1 Introduction

This worksheet is intended to provide the analyses for the TMRC3 project. As of ~ 20211013 we have a shared directory into which to place various results. For the moment I think we will primarily attempt to put csv files. In each directory of that shared tree, we will attempt to put the set of results which are defined by each subdivision.

2 Sample sheet

I think there have been some new/improved annotations in the online sample sheet, so let us go download a fresh copy and see.

samplesheet <- "sample_sheets/tmrc3_samples_20211012.xlsx"
crf_metadata <- "sample_sheets/20210825_EXP_ESPECIAL_TMRC3_VERSION_2.xlsx"

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

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

5 Sample Estimation

5.1 Generate expressionsets

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

5.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 54 rows from the sample metadata because they were blank.
## The sample definitions comprises: 238 rows(samples) and 75 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 205 columns.
## Before removal, there were 21481 genes, now there are 19941.
## There are 19 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 TMRC30126 TMRC30127 TMRC30120 TMRC30128 
##     83.63     88.41     80.29     87.62     84.52     89.49     79.16     82.53 
## TMRC30141 TMRC30131 TMRC30073 
##     89.40     86.82     89.26
levels(pData(hs_expt[["expressionset"]])[["visitnumber"]]) <- list(
    '0'="notapplicable", '1'=1, '2'=2, '3'=3)

5.1.2 Add Clinical metadata

Let us also merge in the clinician’s metadata. I worry a little that this might not be allowed for dbGap data, but if it is a problem I suspect we can just remove the bad columns from it. Also note that I rarely use the join function, but it is somewhat required here because I do not want to risk shuffling the metadata when I add the new metadata, which comes from a spreadsheet sorted by patient, not sample. In doing this I therefore just created a new column ‘join’ which contains the shared information, e.g. the patient ID from the existing metadata and the same ID from the CRF file which has been coerced into lowercase.

hs_pd <- pData(hs_expt)
start <- rownames(hs_pd)
hs_crf <- openxlsx::read.xlsx(crf_metadata)
hs_crf[["join"]] <- tolower(hs_crf[["codigo_paciente"]])
hs_pd[["join"]] <- hs_pd[["tubelabelorigin"]]
test <- plyr::join(hs_pd, hs_crf, by="join")
test[["join"]] <- NULL
rownames(test) <- rownames(hs_pd)
na_idx <- is.na(test)
test[na_idx] <- "undefined"
pData(hs_expt) <- test

This added a bunch of new columns, of which there are a few which Theresa showed are of likely interest:

  • eb_lc_sexo
  • eb_lc_etnia
  • edad eb_lc_tiempo_evolucion
  • eb_lc_num_lc_activas
  • eb_lc_ulcera_area_1
  • eb_lc_ejex_lesion_mm_1
  • eb_lc_lesion_area_1
  • v2_lc_ejex_lesion_mm_1
  • v2_lc_lesion_area_1
  • v2_lc_ejex_ulcera_mm_1
  • v2_lc_ejey_ulcera_mm_1
  • v2_lc_ulcera_area_1
  • v3_lc_ejex_lesion_mm_1
  • v3_lc_ejey_lesion_mm_1
  • v3_lc_lesion_area_1
  • v3_lc_ejex_ulcera_mm_1
  • v3_lc_ejey_ulcera_mm_1
  • v3_lc_ulcera_area_1
  • eb_lc_tto_mcto_prescrito
  • eb_lc_tto_mcto_glucan_dosis
  • v3_lc_num_amp_cap_tto
  • adherencia_tto

5.1.3 Consider lcRNA (currently unused)

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)

5.1.3.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: 182 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

5.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 205, now there are 202 samples.
## valid_write <- sm(write_expt(hs_valid, excel=glue("excel/hs_valid-v{ver}-{rundate}.xlsx")))

5.3 Upload ‘raw’ CPM

The cpm directory in the shared tree has a place to drop the counts for the full dataset along with some subsets by cell type and time. The following block should make that process rather easier.

all_cpm <- hs_valid %>%
  normalize_expt(hs_valid, filter=TRUE, convert="cpm") %>%
  exprs() %>%
  write.csv(file=file=glue::glue("upload/CPM/all_cpm-v{ver}-d{rundate}.csv"))

biopsy_cpm <- hs_valid %>%
  subset_expt(subset="typeofcells=='biopsy'") %>%
  normalize_expt(filter=TRUE, convert="cpm") %>%
  exprs() %>%
  write.csv(file=glue::glue("upload/CPM/Biopsies/biopsy_cpm-v{ver}-d{rundate}.csv"))

eosinophils_cpm <- hs_valid %>%
  subset_expt(subset="typeofcells=='eosinophils'") %>%
  normalize_expt(filter=TRUE, convert="cpm") %>%
  exprs() %>%
  write.csv(file=glue::glue("upload/CPM/Eosinophils/eosinophil_cpm-v{ver}-d{rundate}.csv"))

monocyte_cpm <- hs_valid %>%
  subset_expt(subset="typeofcells=='monocytes'") %>%
  normalize_expt(filter=TRUE, convert="cpm") %>%
  exprs() %>%
  write.csv(file=glue::glue("upload/CPM/Monocytes/monocyte_cpm-v{ver}-d{rundate}.csv"))

neutrophil_cpm <- hs_valid %>%
  subset_expt(subset="typeofcells=='neutrophils'") %>%
  normalize_expt(filter=TRUE, convert="cpm") %>%
  exprs() %>%
  write.csv(file=glue::glue("upload/CPM/Neutrophils/neutrophil_cpm-v{ver}-d{rundate}.csv"))

times <- c("1", "2", "3")
for (time in times) {
  time_subset <- paste0("visitnumber=='", time, "'")
  filename <- glue::glue("upload/CPM/visit{time}-v{ver}-d{rundate}.csv")
  written <- hs_valid %>%
    subset_expt(subset=time_subset) %>%
    exprs() %>%
    write.csv(file=filename)
}

types <- c("neutrophils", "monocytes", "eosinophils", "biopsy")
for (type in types) {
  type_subset <- paste0("typeofcells=='", type, "'")
  for (time in times) {
    time_subset <- paste0("visitnumber=='", time, "'")
    filename <- glue::glue("upload/CPM/{type}_visit{time}-v{ver}-d{rundate}.csv")
    written <- hs_valid %>%
      subset_expt(subset=time_subset) %>%
      subset_expt(subset=type_subset) %>%
      exprs() %>%
      write.csv(file=filename)
  }
}
## Error: <text>:4:22: unexpected '='
## 3:   exprs() %>%
## 4:   write.csv(file=file=
##                         ^

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

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

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

6.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 202, now there are 182 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: null.
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)

6.3.1 Repeat without the biopsy samples

hs_clinical_nobiop <- hs_clinical %>%
  subset_expt(subset="typeofcells!='biopsy'") %>%
  subset_expt(subset="condition=='lost'|condition=='cure'|condition=='failure'")
## subset_expt(): There were 182, now there are 130 samples.
## subset_expt(): There were 130, now there are 128 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)

6.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 5216 low-count genes (14725 remaining).
## batch_counts: Before batch/surrogate estimation, 198077 entries are x==0: 7%.
## batch_counts: Before batch/surrogate estimation, 528392 entries are 0<x<1: 20%.
## Setting 27938 low elements to zero.
## transform_counts: Found 27938 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

6.4 Perform DE of the clinical samples cure vs. fail

individual_celltypes <- subset_expt(hs_clinical_nobiop, subset="condition!='lost'")
## subset_expt(): There were 128, now there are 115 samples.
hs_clinic_de <- sm(all_pairwise(individual_celltypes, model_batch="svaseq", filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
hs_clinic_table <- sm(combine_de_tables(
    hs_clinic_de,
    excel=glue::glue("excel/individual_celltypes_table-v{ver}.xlsx")))
## Error in combine_de_tables(hs_clinic_de, excel = glue::glue("excel/individual_celltypes_table-v{ver}.xlsx")): object 'hs_clinic_de' not found
hs_clinic_sig <- sm(extract_significant_genes(
    hs_clinic_table,
    excel=glue::glue("excel/individual_celltypes_sig-v{ver}.xlsx")))
## Error in extract_significant_genes(hs_clinic_table, excel = glue::glue("excel/individual_celltypes_sig-v{ver}.xlsx")): object 'hs_clinic_table' not found
hs_clinic_sig[["summary_df"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_sig' not found
hs_clinic_de[["comparison"]][["heat"]]
## Error in eval(expr, envir, enclos): object 'hs_clinic_de' not found

6.5 Random aside for my own education

I was just doing some reading about concordance statistics. I want to try something with them.

test_df <- hs_clinic_table[["data"]][["failure_vs_cure"]][, c("deseq_logfc", "edger_logfc")]
## Error in eval(expr, envir, enclos): object 'hs_clinic_table' not found
test_lm <- glm(deseq_logfc ~ edger_logfc, data=test_df)
## Error in is.data.frame(data): object 'test_df' not found
con <- survival::concordance(test_lm)
## Error in survival::concordance(test_lm): object 'test_lm' not found
con
## Error in eval(expr, envir, enclos): object 'con' not found

To calculate the first of these metrics, the area under the concordance curve (AUCC), we ranked genes in both the single-cell and bulk datasets in descending order by the statistical significance of their differential expression. Then, we created lists of the top-ranked genes in each dataset of matching size, up to some maximum size k. For each of these lists (that is, for the top-1 genes, top-2 genes, top-3 genes, and so on), we computed the size of the intersection between the single-cell and bulk DE genes. This procedure yielded a curve relating the number of shared genes between datasets to the number of top-ranked genes considered. The area under this curve was computed by summing the size of all intersections, and normalized to the range [0, 1] by dividing it by its maximum possible value, k × ( k +1) / 2. To evaluate the concordance of DE analysis, we used k =500 except where otherwise noted, but found our results were insensitive to the precise value of k. To compute the second metric, the transcriptome-wide rank correlation, we multiplied the absolute value of the test statistic for each gene by the sign of its log-fold change between conditions, and then computed the Spearman correlation over genes between them.

calculate_aucc <- function(tbl, px="deseq_adjp", py="edger_adjp",
                           lx="deseq_logfc", ly="edger_logfc",
                           topn=0.1) {
  ## If the topn argument is an integer, the just ask for that number.
  ## If it is a floating point 0<x<1, then set topn to that proportion
  ## of the number of genes.
  if (topn <= 0) {
    stop("topn need to be either a float from 0-1 or an interger bigger than 100.")
  } else if (topn > 1 & topn <= 100) {
    stop("topn need to be either a float from 0-1 or an interger bigger than 100.")
  } else if (topn < 1) {
    topn <- ceiling(nrow(tbl) * topn)
  }

  x_df <- tbl[, c(px, lx)]
  y_df <- tbl[, c(py, ly)]
  ## curve (AUCC), we ranked genes in both the single-cell and bulk datasets in
  ## descending order by the statistical significance of their differential expression.
  x_idx <- order(x_df[[1]], decreasing=FALSE)
  x_df <- x_df[x_idx, ]
  y_idx <- order(y_df[[1]], decreasing=FALSE)
  y_df <- y_df[y_idx, ]

  ## Then, we created lists of the top-ranked genes in each dataset of
  ## matching size, up to some maximum size k. For each of these lists
  ## (that is, for the top-1 genes, top-2 genes, top-3 genes, and so
  ## on), we computed the size of the intersection between the
  ## single-cell and bulk DE genes. This procedure yielded a curve
  ## relating the number of shared genes between datasets to the
  ## number of top-ranked genes considered.

  intersections <- rep(0, topn)
  for (i in 1:topn) {
    if (i == 1) {
      x_intersections[i] <- rownames(x_df)[i] == rownames(y_df)[i]
    } else {
      x_set <- rownames(x_df)[1:i]
      y_set <- rownames(y_df)[1:i]
      intersections[i] <- sum(x_set %in% y_set)
    }
  }

  ## The area under this curve was computed by summing the size of all
  ## intersections, and normalized to the range [0, 1] by dividing it
  ## by its maximum possible value, k × ( k +1) / 2. To evaluate the
  ## concordance of DE analysis, we used k =500 except where otherwise
  ## noted, but found our results were insensitive to the
  sumint <- sum(intersections)
  norm <- (topn * (topn + 1)) /2
  aucc <- sumint / norm
  return(aucc)
}

6.5.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…

6.5.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'&condition!='notapplicable'")
## subset_expt(): There were 182, now there are 165 samples.
## Currently (202109), this is not returning any significant hits.
## In previous iterations it did.
lrt_visit_clinical_test <- sm(deseq_lrt(clinical_nolost, transform="vst",
                                        interactor_column="visitnumber",
                                        interest_column="clinicaloutcome"))
summary(lrt_visit_clinical_test[["deseq_table"]])
##      gene              baseMean      log2FoldChange     lfcSE     
##  Length:19941       Min.   :     0   Min.   :-4.5   Min.   :0.0   
##  Class :character   1st Qu.:     6   1st Qu.:-0.1   1st Qu.:0.4   
##  Mode  :character   Median :   186   Median : 0.1   Median :0.6   
##                     Mean   :  1771   Mean   : 0.1   Mean   :1.0   
##                     3rd Qu.:  1107   3rd Qu.: 0.3   3rd Qu.:1.0   
##                     Max.   :355344   Max.   : 8.0   Max.   :7.0   
##                                      NA's   :1624   NA's   :1624  
##       stat          pvalue          padj     
##  Min.   :-1.6   Min.   :0.0    Min.   :0.4   
##  1st Qu.: 0.1   1st Qu.:0.6    1st Qu.:1.0   
##  Median : 0.4   Median :0.8    Median :1.0   
##  Mean   : 0.7   Mean   :0.8    Mean   :1.0   
##  3rd Qu.: 0.9   3rd Qu.:0.9    3rd Qu.:1.0   
##  Max.   :21.6   Max.   :1.0    Max.   :1.0   
##  NA's   :1624   NA's   :1624   NA's   :1625
written <- write_xlsx(data=as.data.frame(lrt_visit_clinical_test[["deseq_table"]]),
                      excel=glue::glue("excel/lrt_clinical_visit-v{ver}.xlsx"))

lrt_celltype_clinical_test <- sm(deseq_lrt(clinical_nolost, transform="vst",
                                           interactor_column="typeofcells",
                                           interest_column="clinicaloutcome"))
## Going to attempt to install: Error in loadNamespace(j <- i[[1L]], c(lib.loc, .libPaths()), versionCheck = vI[[j]]) : 
##   there is no package called 'Cairo'
## 'getOption("repos")' replaces Bioconductor standard repositories, see
## '?repositories' for details
## 
## replacement repositories:
##     CRAN: http://cran.r-project.org
## Bioconductor version 3.13 (BiocManager 1.30.16), R 4.1.0 (2021-05-18)
## Installing package(s) 'Error in loadNamespace(j <- i[[1L]], c(lib.loc,
##   .libPaths()), versionCheck = vI[[j]]) : there is no package called 'Cairo''
## Warning in .inet_warning(msg): package 'Error in loadNamespace(j <- i[[1L]], c(lib.loc, .libPaths()), versionCheck = vI[[j]]) : 
##   there is no package called 'Cairo'' is not available for Bioconductor version '3.13'
## 
## A version of this package for your version of R might be available elsewhere,
## see the ideas at
## https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
## Error in loadNamespace(j <- i[[1L]], c(lib.loc, .libPaths()), versionCheck = vI[[j]]): there is no package called 'Cairo'
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
favorite_lrt_df <- merge(hs_annot, lrt_celltype_clinical_test[["favorite_genes"]], all.y=TRUE,
                     by="row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'y' in selecting a method for function 'merge': object 'lrt_celltype_clinical_test' not found
written <- write_xlsx(data=favorite_lrt_df,
                      excel=glue::glue("excel/lrt_clinical_celltype_favorites-v{ver}.xlsx"))
## Error in write_xlsx(data = favorite_lrt_df, excel = glue::glue("excel/lrt_clinical_celltype_favorites-v{ver}.xlsx")): object 'favorite_lrt_df' not found
deseq_lrt_df <- merge(hs_annot, as.data.frame(lrt_celltype_clinical_test[["deseq_table"]]), all.y=TRUE,
                      by="row.names")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'y' in selecting a method for function 'merge': error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'lrt_celltype_clinical_test' not found
rownames(deseq_lrt_df) <- deseq_lrt_df[["Row.names"]]
## Error in eval(expr, envir, enclos): object 'deseq_lrt_df' not found
deseq_lrt_df[["Row.names"]] <- NULL
## Error in deseq_lrt_df[["Row.names"]] <- NULL: object 'deseq_lrt_df' not found
written <- write_xlsx(data=deseq_lrt_df,
                      excel=glue::glue("excel/lrt_clinical_celltype-v{ver}.xlsx"))
## Error in write_xlsx(data = deseq_lrt_df, excel = glue::glue("excel/lrt_clinical_celltype-v{ver}.xlsx")): object 'deseq_lrt_df' not found
lrt_celltype_clinical_test$cluster_data$plot
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_23_genes_idx <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][["cluster"]] == 23
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_23_genes <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][cluster_23_genes_idx, ]
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_23_genes
## Error in eval(expr, envir, enclos): object 'cluster_23_genes' not found
cluster_24_genes_idx <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][["cluster"]] == 24
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_24_genes <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][cluster_24_genes_idx, ]
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_24_genes
## Error in eval(expr, envir, enclos): object 'cluster_24_genes' not found
cluster_22_genes_idx <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][["cluster"]] == 22
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_22_genes <- lrt_celltype_clinical_test[["cluster_data"]][["df"]][cluster_22_genes_idx, ]
## Error in eval(expr, envir, enclos): object 'lrt_celltype_clinical_test' not found
cluster_22_genes
## Error in eval(expr, envir, enclos): object 'cluster_22_genes' not found

6.5.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))
## Error in extract_significant_genes(hs_clinic_table, n = 100): object 'hs_clinic_table' not found
table <- "failure_vs_cure"
wanted <- rbind(hs_clinic_topn[["deseq"]][["ups"]][[table]],
                hs_clinic_topn[["deseq"]][["downs"]][[table]])
## Error in eval(quote(list(...)), env): object 'hs_clinic_topn' not found
small_expt <- exclude_genes_expt(hs_clinical_nobiop, ids=rownames(wanted), method="keep")
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'wanted' not found
small_norm <- sm(normalize_expt(small_expt, transform="log2", convert="cpm",
                                norm="quant", filter=TRUE))
## Error in normalize_expt(small_expt, transform = "log2", convert = "cpm", : object 'small_expt' not found
plot_pca(small_norm)$plot
## Error in plot_pca(small_norm): object 'small_norm' not found
small_nb <- normalize_expt(small_expt, transform="log2", convert="cpm",
                           batch="svaseq", norm="quant", filter=TRUE)
## Error in normalize_expt(small_expt, transform = "log2", convert = "cpm", : object 'small_expt' not found
plot_pca(small_nb)$plot
## Error in plot_pca(small_nb): object 'small_nb' not found
## DESeq2 MA plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_ma_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'hs_clinic_table' not found
## DESeq2 Volcano plot of failure / cure
hs_clinic_table[["plots"]][["failure_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'hs_clinic_table' not found

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

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

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

6.6 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 <- simple_gsva(individual_celltypes,
                                   signatures="reference/msigdb/c7.all.v7.2.entrez.gmt",
                                   signature_category="c7",
                                   msig_xml="reference/msigdb_v7.2.xml",
                                   cores=10)
## Converting the rownames() of the expressionset to ENTREZID.
## 583 ENSEMBL ID's didn't have a matching ENTEREZ ID. Dropping them now.
## Before conversion, the expressionset has 19941 entries.
## After conversion, the expressionset has 19519 entries.
## Adding annotations from reference/msigdb_v7.2.xml.
## Warning: `xml_nodes()` was deprecated in rvest 1.0.0.
## Please use `html_elements()` instead.
hs_celltype_gsva_c7_sig <- sm(get_sig_gsva_categories(
    hs_celltype_gsva_c7,
    excel="excel/individual_celltypes_gsva_c7.xlsx"))

7 Some queries from 20210816

Upon returning from Maine, I sat with Najib, Theresa, and Maria Adelaida. A whole host of potential ideas were considered; here are a couple of them:

7.1 Visualize variance in the TMRC3 data

My TODO text says: "Variance partition of TMRC3 samples with at least time, cell-type, and cure/fail. I mixed this idea with the visit 1 previously.

vp_factors <- c("condition", "batch", "visitnumber", "eb_lc_ulcera_area_1")

v1_vp <- simple_varpart(hs_clinical, factors=vp_factors, do_fit=TRUE)
## Error in checkModelStatus(fit, showWarnings = showWarnings, colinearityCutoff = colinearityCutoff) : 
##   The variables specified in this model are redundant,
## so the design matrix is not full rank
## Retrying with only condition in the model.
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## The following object is masked from 'package:S4Vectors':
## 
##     expand
## 
## Total:116 s
## 
## Total:52 s
pp(file="images/v1_vp.png", image=v1_vp$partition_plot)

7.2 Visit 1 comparisons

Here is the note from my TODO list: “Using v1, perform cell-type comparisons/signatures as well as a cure/fail differential expression”.

Implicit in this query is the idea that we should do an explicit visualization of the visit 1 samples without the subsequent visits.

## For the moment, let us ignore the lost/NA samples
v1_expt <- subset_expt(hs_clinical, subset="visitnumber=='1'") %>%
  subset_expt(subset="condition=='cure'|condition=='failure'") %>%
  subset_expt(subset="batch!='biopsy'")
## subset_expt(): There were 182, now there are 76 samples.
## subset_expt(): There were 76, now there are 68 samples.
## subset_expt(): There were 68, now there are 42 samples.
v1_norm <- normalize_expt(v1_expt, filter=TRUE, transform="log2", convert="cpm",
                          batch="svaseq")
## Removing 8361 low-count genes (11580 remaining).
## batch_counts: Before batch/surrogate estimation, 8014 entries are x==0: 2%.
## batch_counts: Before batch/surrogate estimation, 75129 entries are 0<x<1: 15%.
## Setting 2645 low elements to zero.
## transform_counts: Found 2645 values equal to 0, adding 1 to the matrix.
plot_pca(v1_norm)$plot

v1_de <- all_pairwise(v1_expt, filter=TRUE, model_batch="svaseq")
## batch_counts: Before batch/surrogate estimation, 8014 entries are x==0: 2%.
## 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 (11580 remaining).
## batch_counts: Before batch/surrogate estimation, 8014 entries are x==0: 2%.
## batch_counts: Before batch/surrogate estimation, 75129 entries are 0<x<1: 15%.
## Setting 2645 low elements to zero.
## transform_counts: Found 2645 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
v1_table <- combine_de_tables(v1_de, excel=glue::glue("excel/v1_tables-v{ver}.xlsx"))
## Error in combine_de_tables(v1_de, excel = glue::glue("excel/v1_tables-v{ver}.xlsx")): object 'v1_de' not found

7.2.1 Visit 1 variance partition

It might be interesting to add ‘parasitemappingrate’ here but I have not filled it in for all samples yet.

samplecollectiondate should be useful too but is not complete.

This is also a great place to pull in some of the clinical information. I need to ask Maria Adelaida for it…

v1_vp <- simple_varpart(v1_expt, do_fit=TRUE)
## 
## Total:107 s
## 
## Total:56 s
v1_vp$partition_plot

## condition is cure/fail batch is cell type.

7.2.2 Visit 1 separated by cell type

v1_eo <- subset_expt(v1_expt, subset="batch=='eosinophils'")
## subset_expt(): There were 42, now there are 10 samples.
v1_mono <- subset_expt(v1_expt, subset="batch=='monocytes'")
## subset_expt(): There were 42, now there are 16 samples.
v1_neut <- subset_expt(v1_expt, subset="batch=='neutrophils'")
## subset_expt(): There were 42, now there are 16 samples.
v1_eo_norm <- normalize_expt(v1_eo, transform="log2", convert="cpm",
                             filter=TRUE, norm="quant")
## Removing 9789 low-count genes (10152 remaining).
## transform_counts: Found 1 values equal to 0, adding 1 to the matrix.
plot_pca(v1_eo_norm)$plot

v1_eo_nb <- normalize_expt(v1_eo, transform="log2", convert="cpm",
                           filter=TRUE, batch="svaseq")
## Removing 9789 low-count genes (10152 remaining).
## batch_counts: Before batch/surrogate estimation, 93 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 3050 entries are 0<x<1: 3%.
## Setting 106 low elements to zero.
## transform_counts: Found 106 values equal to 0, adding 1 to the matrix.
plot_pca(v1_eo_nb)$plot

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

v1_mono_nb <- normalize_expt(v1_mono, transform="log2", convert="cpm",
                             filter=TRUE, batch="svaseq")
## Removing 9329 low-count genes (10612 remaining).
## batch_counts: Before batch/surrogate estimation, 226 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 6672 entries are 0<x<1: 4%.
## Setting 205 low elements to zero.
## transform_counts: Found 205 values equal to 0, adding 1 to the matrix.
plot_pca(v1_mono_nb)$plot

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

v1_neut_nb <- normalize_expt(v1_neut, transform="log2", convert="cpm",
                             filter=TRUE, batch="svaseq")
## Removing 11186 low-count genes (8755 remaining).
## batch_counts: Before batch/surrogate estimation, 138 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 6557 entries are 0<x<1: 5%.
## Setting 167 low elements to zero.
## transform_counts: Found 167 values equal to 0, adding 1 to the matrix.
plot_pca(v1_neut_nb)$plot

8 Compare visits

Compare visits independent of cure/fail

time_expt <- hs_clinical %>%
  set_expt_conditions(fact="visitnumber")
pData(time_expt)[["condition"]] <- paste0("v", pData(time_expt)[["condition"]])

time_norm <- normalize_expt(time_expt, filter=TRUE, norm="quant", convert="cpm",
                            transform="log2")
## Removing 5216 low-count genes (14725 remaining).
## transform_counts: Found 107 values equal to 0, adding 1 to the matrix.
time_nb <- normalize_expt(time_expt, filter=TRUE, batch="svaseq", convert="cpm",
                          transform="log2")
## Removing 5216 low-count genes (14725 remaining).
## batch_counts: Before batch/surrogate estimation, 198077 entries are x==0: 7%.
## batch_counts: Before batch/surrogate estimation, 528392 entries are 0<x<1: 20%.
## Setting 33769 low elements to zero.
## transform_counts: Found 33769 values equal to 0, adding 1 to the matrix.
plot_pca(time_nb)$plot
## plot labels was not set and there are more than 100 samples, disabling it.

time_de <- all_pairwise(time_expt, filter=TRUE, model_batch="svaseq")
## batch_counts: Before batch/surrogate estimation, 198077 entries are x==0: 7%.
## 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 (14725 remaining).
## batch_counts: Before batch/surrogate estimation, 198077 entries are x==0: 7%.
## batch_counts: Before batch/surrogate estimation, 528392 entries are 0<x<1: 20%.
## Setting 33769 low elements to zero.
## transform_counts: Found 33769 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
keepers <- list(
    "v2v1"=c("v2", "v1"),
    "v3v1"=c("v3", "v1"),
    "v3v2"=c("v3", "v2"))
time_tables <- combine_de_tables(time_de, keepers=keepers,
                                 excel=glue::glue("excel/compare_visits-v{ver}.xlsx"))
## Error in combine_de_tables(time_de, keepers = keepers, excel = glue::glue("excel/compare_visits-v{ver}.xlsx")): object 'time_de' not found

8.1 Separate visits by cell type

Now let us consider the 3 visits from the lens of cell type.

time_type_factor <- paste0(pData(time_expt)[["condition"]], "_", pData(time_expt)[["batch"]])
time_type_expt <- set_expt_conditions(time_expt, fact=time_type_factor)

time_type_biopsy <- subset_expt(time_type_expt, subset="batch=='biopsy'")
## subset_expt(): There were 182, now there are 52 samples.
time_type_neutrophil <- subset_expt(time_type_expt, subset="batch=='neutrophils'")
## subset_expt(): There were 182, now there are 50 samples.
time_type_eosinophil <- subset_expt(time_type_expt, subset="batch=='eosinophils'")
## subset_expt(): There were 182, now there are 30 samples.
time_type_monocyte <- subset_expt(time_type_expt, subset="batch=='monocytes'")
## subset_expt(): There were 182, now there are 50 samples.

8.1.1 Biopsy

time_biopsy <- normalize_expt(time_type_biopsy, filter=TRUE, norm="quant", convert="cpm",
                              transform="log2")
## Removing 5738 low-count genes (14203 remaining).
## transform_counts: Found 16 values equal to 0, adding 1 to the matrix.
time_biopsy_nb <- normalize_expt(time_type_biopsy, filter=TRUE, batch="svaseq", convert="cpm",
                                 transform="log2")
## Removing 5738 low-count genes (14203 remaining).
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 44637 entries are 0<x<1: 6%.
## Setting 1749 low elements to zero.
## transform_counts: Found 1749 values equal to 0, adding 1 to the matrix.
plot_pca(time_biopsy)$plot

plot_pca(time_biopsy_nb)$plot

time_biopsy_de <- all_pairwise(time_type_biopsy, model_batch="svaseq", filter=TRUE)
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## 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 (14203 remaining).
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 44637 entries are 0<x<1: 6%.
## Setting 1749 low elements to zero.
## transform_counts: Found 1749 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
keepers <- list(
    "v2v1"=c("v2_biopsy", "v1_biopsy"),
    "v3v1"=c("v3_biopsy", "v1_biopsy"),
    "v3v2"=c("v3_biopsy", "v2_biopsy"))
time_biopsy_tables <- combine_de_tables(
    time_biopsy_de, keepers=keepers,
    excel=glue::glue("excel/time_biopsy_tables-v{ver}.xlsx"))
## Error in combine_de_tables(time_biopsy_de, keepers = keepers, excel = glue::glue("excel/time_biopsy_tables-v{ver}.xlsx")): object 'time_biopsy_de' not found

8.1.2 Neutrophils

time_neutrophil <- normalize_expt(time_type_neutrophil, filter=TRUE, norm="quant", convert="cpm",
                              transform="log2")
## Removing 10599 low-count genes (9342 remaining).
## transform_counts: Found 1 values equal to 0, adding 1 to the matrix.
time_neutrophil_nb <- normalize_expt(time_type_neutrophil, filter=TRUE, batch="svaseq", convert="cpm",
                                 transform="log2")
## Removing 10599 low-count genes (9342 remaining).
## batch_counts: Before batch/surrogate estimation, 1669 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 42558 entries are 0<x<1: 9%.
## Setting 775 low elements to zero.
## transform_counts: Found 775 values equal to 0, adding 1 to the matrix.
plot_pca(time_neutrophil)$plot

plot_pca(time_neutrophil_nb)$plot

time_neutrophil_de <- all_pairwise(time_type_neutrophil, model_batch="svaseq", filter=TRUE)
## batch_counts: Before batch/surrogate estimation, 1669 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 (9342 remaining).
## batch_counts: Before batch/surrogate estimation, 1669 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 42558 entries are 0<x<1: 9%.
## Setting 829 low elements to zero.
## transform_counts: Found 829 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
keepers <- list(
    "v2v1"=c("v2_neutrophils", "v1_neutrophils"),
    "v3v1"=c("v3_neutrophils", "v1_neutrophils"),
    "v3v2"=c("v3_neutrophils", "v2_neutrophils"))
time_neutrophil_tables <- combine_de_tables(
    time_neutrophil_de, keepers=keepers,
    excel=glue::glue("excel/time_neutrophil_tables-v{ver}.xlsx"))
## Error in combine_de_tables(time_neutrophil_de, keepers = keepers, excel = glue::glue("excel/time_neutrophil_tables-v{ver}.xlsx")): object 'time_neutrophil_de' not found

8.1.3 Eosinophils

time_eosinophil <- normalize_expt(time_type_eosinophil, filter=TRUE, norm="quant", convert="cpm",
                              transform="log2")
## Removing 9190 low-count genes (10751 remaining).
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.
time_eosinophil_nb <- normalize_expt(time_type_eosinophil, filter=TRUE, batch="svaseq", convert="cpm",
                                 transform="log2")
## Removing 9190 low-count genes (10751 remaining).
## batch_counts: Before batch/surrogate estimation, 785 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 18837 entries are 0<x<1: 6%.
## Setting 428 low elements to zero.
## transform_counts: Found 428 values equal to 0, adding 1 to the matrix.
plot_pca(time_eosinophil)$plot

plot_pca(time_eosinophil_nb)$plot

time_eosinophil_de <- all_pairwise(time_type_eosinophil, model_batch="svaseq", filter=TRUE)
## batch_counts: Before batch/surrogate estimation, 785 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 (10751 remaining).
## batch_counts: Before batch/surrogate estimation, 785 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 18837 entries are 0<x<1: 6%.
## Setting 428 low elements to zero.
## transform_counts: Found 428 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
keepers <- list(
    "v2v1"=c("v2_eosinophils", "v1_eosinophils"),
    "v3v1"=c("v3_eosinophils", "v1_eosinophils"),
    "v3v2"=c("v3_eosinophils", "v2_eosinophils"))
time_eosinophil_tables <- combine_de_tables(
    time_eosinophil_de, keepers=keepers,
    excel=glue::glue("excel/time_eosinophil_tables-v{ver}.xlsx"))
## Error in combine_de_tables(time_eosinophil_de, keepers = keepers, excel = glue::glue("excel/time_eosinophil_tables-v{ver}.xlsx")): object 'time_eosinophil_de' not found

8.1.4 Monocyte

time_monocyte <- normalize_expt(time_type_monocyte, filter=TRUE, norm="quant", convert="cpm",
                              transform="log2")
## Removing 8776 low-count genes (11165 remaining).
## transform_counts: Found 11 values equal to 0, adding 1 to the matrix.
time_monocyte_nb <- normalize_expt(time_type_monocyte, filter=TRUE, batch="svaseq", convert="cpm",
                                 transform="log2")
## Removing 8776 low-count genes (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 1029 low elements to zero.
## transform_counts: Found 1029 values equal to 0, adding 1 to the matrix.
plot_pca(time_monocyte)$plot

plot_pca(time_monocyte_nb)$plot

time_monocyte_de <- all_pairwise(time_type_monocyte, model_batch="svaseq", filter=TRUE)
## batch_counts: Before batch/surrogate estimation, 2380 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 (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 1029 low elements to zero.
## transform_counts: Found 1029 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
keepers <- list(
    "v2v1"=c("v2_monocytes", "v1_monocytes"),
    "v3v1"=c("v3_monocytes", "v1_monocytes"),
    "v3v2"=c("v3_monocytes", "v2_monocytes"))
time_monocyte_tables <- combine_de_tables(
    time_monocyte_de, keepers=keepers,
    excel=glue::glue("excel/time_monocyte_tables-v{ver}.xlsx"))
## Error in combine_de_tables(time_monocyte_de, keepers = keepers, excel = glue::glue("excel/time_monocyte_tables-v{ver}.xlsx")): object 'time_monocyte_de' not found

8.2 Time and clinicaloutcome

time_cf_factor <- paste0(pData(time_type_biopsy)[["condition"]], "_", pData(time_type_biopsy)[["clinicaloutcome"]])
biopsy_time_cf <- set_expt_conditions(time_type_biopsy, fact=time_cf_factor)

time_cf_biopsy <- normalize_expt(biopsy_time_cf, filter=TRUE, norm="quant", convert="cpm",
                                 transform="log2")
## Removing 5738 low-count genes (14203 remaining).
## transform_counts: Found 16 values equal to 0, adding 1 to the matrix.
time_cf_biopsy_nb <- normalize_expt(biopsy_time_cf, filter=TRUE, batch="svaseq", convert="cpm",
                                    transform="log2")
## Removing 5738 low-count genes (14203 remaining).
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 44637 entries are 0<x<1: 6%.
## Setting 1721 low elements to zero.
## transform_counts: Found 1721 values equal to 0, adding 1 to the matrix.
plot_pca(time_cf_biopsy)$plot

plot_pca(time_cf_biopsy_nb)$plot

biopsy_time_de <- all_pairwise(time_type_biopsy, filter=TRUE, model_batch="svaseq")
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## 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 (14203 remaining).
## batch_counts: Before batch/surrogate estimation, 5504 entries are x==0: 1%.
## batch_counts: Before batch/surrogate estimation, 44637 entries are 0<x<1: 6%.
## Setting 1749 low elements to zero.
## transform_counts: Found 1749 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
biopsy_time_tables <- combine_de_tables(time_type_de, keepers=keepers,
                                        excel=glue::glue("excel/compare_biopsy_visits-v{ver}.xlsx"))
## Error in combine_de_tables(time_type_de, keepers = keepers, excel = glue::glue("excel/compare_biopsy_visits-v{ver}.xlsx")): object 'time_type_de' not found

9 Individual Cell types

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

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

9.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"))

9.2 Monocytes

9.2.1 Evaluate Monocyte samples

mono <- subset_expt(hs_valid, subset="typeofcells=='monocytes'") %>%
  set_expt_conditions(fact="clinicaloutcome") %>%
  set_expt_batches(fact="visitnumber") %>%
  set_expt_colors(colors=chosen_colors)
## subset_expt(): There were 202, now there are 50 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: null.
## 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 8776 low-count genes (11165 remaining).
## transform_counts: Found 11 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 8776 low-count genes (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 1302 low elements to zero.
## transform_counts: Found 1302 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)

9.2.2 DE of Monocyte samples

9.2.2.1 Without sva

mono_de <- sm(all_pairwise(mono, model_batch=FALSE, filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
mono_tables <- sm(combine_de_tables(
    mono_de, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_mono_vall_de_curevsfail_nobatch.xlsx")))
## Error in combine_de_tables(mono_de, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_mono_vall_de_curevsfail_nobatch.xlsx")): object 'mono_de' not found
written <- write_xlsx(data=mono_tables[["data"]][[1]],
                      excel=glue::glue("excel/monocyte_clinical_table-v{ver}.xlsx"))
## Error in write_xlsx(data = mono_tables[["data"]][[1]], excel = glue::glue("excel/monocyte_clinical_table-v{ver}.xlsx")): object 'mono_tables' not found
mono_sig <- sm(extract_significant_genes(mono_tables, according_to="deseq"))
## Error in extract_significant_genes(mono_tables, according_to = "deseq"): object 'mono_tables' not found
written <- write_xlsx(data=mono_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/monocyte_clinical_sigup-v{ver}.xlsx"))
## Error in write_xlsx(data = mono_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/monocyte_clinical_sigup-v{ver}.xlsx")): object 'mono_sig' not found
written <- write_xlsx(data=mono_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/monocyte_clinical_sigdown-v{ver}.xlsx"))
## Error in write_xlsx(data = mono_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/monocyte_clinical_sigdown-v{ver}.xlsx")): object 'mono_sig' not found
mono_pct_sig <- sm(extract_significant_genes(mono_tables, n=200,
                                             lfc=NULL, p=NULL, according_to="deseq"))
## Error in extract_significant_genes(mono_tables, n = 200, lfc = NULL, p = NULL, : object 'mono_tables' not found
written <- write_xlsx(data=mono_pct_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/monocyte_clinical_sigup_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = mono_pct_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/monocyte_clinical_sigup_pct-v{ver}.xlsx")): object 'mono_pct_sig' not found
written <- write_xlsx(data=mono_pct_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/monocyte_clinical_sigdown_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = mono_pct_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/monocyte_clinical_sigdown_pct-v{ver}.xlsx")): object 'mono_pct_sig' not found
mono_sig$summary_df
## Error in eval(expr, envir, enclos): object 'mono_sig' not found
## 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"))

9.2.2.2 With sva

mono_de_sva <- sm(all_pairwise(mono, model_batch="svaseq", filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
mono_sva_tables <- sm(combine_de_tables(
    mono_de_sva, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_mono_vall_de_curevsfail_svabatch.xlsx")))
## Error in combine_de_tables(mono_de_sva, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_mono_vall_de_curevsfail_svabatch.xlsx")): object 'mono_de_sva' not found
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"))
## Error in extract_significant_genes(mono_tables_sva, excel = glue::glue("excel/monocyte_clinical_sig_tables_sva-v{ver}.xlsx"), : object 'mono_tables_sva' not found

9.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
## Error in eval(expr, envir, enclos): object 'mono_tables' not found
## DESeq2 Volcano plot of failure / cure
mono_tables[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'mono_tables' not found
## DESeq2 MA plot of failure / cure with svaseq
mono_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_ma_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'mono_tables_sva' not found
## DESeq2 Volcano plot of failure / cure with svaseq
mono_tables_sva[["plots"]][["fail_vs_cure"]][["deseq_vol_plots"]]$plot
## Error in eval(expr, envir, enclos): object 'mono_tables_sva' not found

9.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())
broad_c7 <- load_gmt_signatures(signatures="reference/msigdb/c7.all.v7.2.entrez.gmt",
                                signature_category="c7")
mono_up_goseq_msig <- goseq_msigdb(sig_genes=ups, signatures=broad_c7,
                                   signature_category="c7", length_db=hs_length)
## Error in rownames(sig_genes): object 'ups' not found
mono_down_goseq_msig <- goseq_msigdb(sig_genes=downs, signatures=broad_c7,
                                     signature_category="c7", length_db=hs_length)
## Error in rownames(sig_genes): object 'downs' not found

9.2.2.6 Plot of similar experiments

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

9.2.3 Evaluate Neutrophil samples

neut <- subset_expt(hs_valid, subset="typeofcells=='neutrophils'") %>%
  set_expt_conditions(fact="clinicaloutcome") %>%
  set_expt_batches(fact="visitnumber") %>%
  set_expt_colors(colors=chosen_colors)
## subset_expt(): There were 202, now there are 50 samples.
## Warning in set_expt_colors(., colors = chosen_colors): Colors for the following
## categories are not being used: null.
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)

9.2.4 DE of Netrophil samples

9.2.4.1 Without sva

neut_de <- sm(all_pairwise(neut, model_batch=FALSE, filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
neut_tables <- sm(combine_de_tables(
    neut_de, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_neut_vall_de_curevsfail_nobatch.xlsx")))
## Error in combine_de_tables(neut_de, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_neut_vall_de_curevsfail_nobatch.xlsx")): object 'neut_de' not found
written <- write_xlsx(data=neut_tables[["data"]][[1]],
                      excel=glue::glue("excel/neutrophil_clinical_table-v{ver}.xlsx"))
## Error in write_xlsx(data = neut_tables[["data"]][[1]], excel = glue::glue("excel/neutrophil_clinical_table-v{ver}.xlsx")): object 'neut_tables' not found
neut_sig <- sm(extract_significant_genes(neut_tables, according_to="deseq"))
## Error in extract_significant_genes(neut_tables, according_to = "deseq"): object 'neut_tables' not found
written <- write_xlsx(data=neut_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/neutrophil_clinical_sigup-v{ver}.xlsx"))
## Error in write_xlsx(data = neut_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/neutrophil_clinical_sigup-v{ver}.xlsx")): object 'neut_sig' not found
written <- write_xlsx(data=neut_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/neutrophil_clinical_sigdown-v{ver}.xlsx"))
## Error in write_xlsx(data = neut_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/neutrophil_clinical_sigdown-v{ver}.xlsx")): object 'neut_sig' not found
neut_pct_sig <- sm(extract_significant_genes(neut_tables, n=200, lfc=NULL,
                                             p=NULL, according_to="deseq"))
## Error in extract_significant_genes(neut_tables, n = 200, lfc = NULL, p = NULL, : object 'neut_tables' not found
written <- write_xlsx(data=neut_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/neutrophil_clinical_sigup_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = neut_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/neutrophil_clinical_sigup_pct-v{ver}.xlsx")): object 'neut_sig' not found
written <- write_xlsx(data=neut_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/neutrophil_clinical_sigdown_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = neut_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/neutrophil_clinical_sigdown_pct-v{ver}.xlsx")): object 'neut_sig' not found
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"))

9.2.4.2 With sva

neut_de_sva <- sm(all_pairwise(neut, model_batch="svaseq", filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
neut_tables_sva <- sm(combine_de_tables(
    neut_de_sva, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_neut_vall_de_curevsfail_svabatch.xlsx")))
## Error in combine_de_tables(neut_de_sva, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_neut_vall_de_curevsfail_svabatch.xlsx")): object 'neut_de_sva' not found
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"))
## Error in extract_significant_genes(neut_tables_sva, excel = glue::glue("excel/neutrophil_clinical_sig_tables_sva-v{ver}.xlsx"), : object 'neut_tables_sva' not found

9.2.4.3 Neutrophil DE plots

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

9.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)
## Error in rownames(sig_genes): object 'ups' not found
neut_down_goseq_msig <- goseq_msigdb(sig_genes=downs, signatures=broad_c7,
                                     signature_category="c7", length_db=hs_length)
## Error in rownames(sig_genes): object 'downs' not found

9.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"]]
## Error in eval(expr, envir, enclos): object 'neut_up_goseq_msig' not found
## Neutrophil genes with increased expression in the cured samples
## share genes with the following experiments
neut_down_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'neut_down_goseq_msig' not found

9.3 Eosinophils

9.3.1 Evaluate Eosinophil samples

eo <- subset_expt(hs_valid, subset="typeofcells=='eosinophils'") %>%
  set_expt_conditions(fact="clinicaloutcome") %>%
  set_expt_batches(fact="visitnumber") %>%
  set_expt_colors(colors=chosen_colors)
## subset_expt(): There were 202, now there are 30 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"))
plt <- plot_pca(eo_nb, plot_labels=FALSE)$plot
plt

9.3.2 DE of Eosinophil samples

9.3.2.1 Withouth sva

eo_de <- sm(all_pairwise(eo, model_batch=FALSE, filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
eo_tables <- sm(combine_de_tables(
    eo_de, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_eo_vall_de_curevsfail_nobatch.xlsx")))
## Error in combine_de_tables(eo_de, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_eo_vall_de_curevsfail_nobatch.xlsx")): object 'eo_de' not found
written <- write_xlsx(data=eo_tables[["data"]][[1]],
                      excel=glue::glue("excel/eosinophil_clinical_table-v{ver}.xlsx"))
## Error in write_xlsx(data = eo_tables[["data"]][[1]], excel = glue::glue("excel/eosinophil_clinical_table-v{ver}.xlsx")): object 'eo_tables' not found
eo_sig <- sm(extract_significant_genes(eo_tables, according_to="deseq"))
## Error in extract_significant_genes(eo_tables, according_to = "deseq"): object 'eo_tables' not found
written <- write_xlsx(data=eo_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/eosinophil_clinical_sigup-v{ver}.xlsx"))
## Error in write_xlsx(data = eo_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/eosinophil_clinical_sigup-v{ver}.xlsx")): object 'eo_sig' not found
written <- write_xlsx(data=eo_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/eosinophil_clinical_sigdown-v{ver}.xlsx"))
## Error in write_xlsx(data = eo_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/eosinophil_clinical_sigdown-v{ver}.xlsx")): object 'eo_sig' not found
eo_pct_sig <- sm(extract_significant_genes(eo_tables, n=200,
                                           lfc=NULL, p=NULL, according_to="deseq"))
## Error in extract_significant_genes(eo_tables, n = 200, lfc = NULL, p = NULL, : object 'eo_tables' not found
written <- write_xlsx(data=eo_pct_sig[["deseq"]][["ups"]][[1]],
                      excel=glue::glue("excel/eosinophil_clinical_sigup_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = eo_pct_sig[["deseq"]][["ups"]][[1]], excel = glue::glue("excel/eosinophil_clinical_sigup_pct-v{ver}.xlsx")): object 'eo_pct_sig' not found
written <- write_xlsx(data=eo_pct_sig[["deseq"]][["downs"]][[1]],
                      excel=glue::glue("excel/eosinophil_clinical_sigdown_pct-v{ver}.xlsx"))
## Error in write_xlsx(data = eo_pct_sig[["deseq"]][["downs"]][[1]], excel = glue::glue("excel/eosinophil_clinical_sigdown_pct-v{ver}.xlsx")): object 'eo_pct_sig' not found
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"))

9.3.2.2 With sva

eo_de_sva <- sm(all_pairwise(eo, model_batch="svaseq", filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
eo_tables_sva <- sm(combine_de_tables(
    eo_de_sva, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_eo_vall_de_curevsfail_svabatch.xlsx")))
## Error in combine_de_tables(eo_de_sva, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_eo_vall_de_curevsfail_svabatch.xlsx")): object 'eo_de_sva' not found
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"))
## Error in extract_significant_genes(eo_tables_sva, excel = glue::glue("excel/eosinophil_clinical_sig_tables_sva-v{ver}.xlsx"), : object 'eo_tables_sva' not found

9.3.2.3 Eosinophil DE plots

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

9.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)
## Error in rownames(sig_genes): object 'ups' not found
eo_down_goseq_msig <- goseq_msigdb(sig_genes=downs, signatures=broad_c7,
                                   signature_category="c7", length_db=hs_length)
## Error in rownames(sig_genes): object 'downs' not found

9.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"]]
## Error in eval(expr, envir, enclos): object 'eo_up_goseq_msig' not found
## Eosinophil genes with increased expression in the cured samples
## share genes with the following experiments
eo_down_goseq_msig[["pvalue_plots"]][["mfp_plot_over"]]
## Error in eval(expr, envir, enclos): object 'eo_down_goseq_msig' not found

9.4 Biopsies

9.4.1 Evaluate Biopsy samples

biop <- subset_expt(hs_valid, subset="typeofcells=='biopsy'") %>%
  set_expt_conditions(fact="clinicaloutcome") %>%
  set_expt_batches(fact="visitnumber") %>%
  set_expt_colors(colors=chosen_colors)
## subset_expt(): There were 202, now there are 52 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 5738 low-count genes (14203 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)

9.4.2 DE of Biopsy samples

9.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("upload/DE_Cure_vs_Fail/{ver}_biopsy_vall_de_curevsfail_nobatch.xlsx")))

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")
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"))
## Error: <text>:4:93: unexpected ')'
## 3:     biop_de, keepers=keepers,
## 4:     excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_biopsy_vall_de_curevsfail_nobatch.xlsx")))
##                                                                                                ^

9.4.2.2 with sva

biop_de_sva <- sm(all_pairwise(biop, model_batch="svaseq", filter=TRUE))
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
biop_tables_sva <- sm(combine_de_tables(
    biop_de_sva, keepers=keepers,
    excel=glue::glue("upload/DE_Cure_vs_Fail/{ver}_biopsy_vall_de_curevsfail_svabatch.xlsx")))
## Error in combine_de_tables(biop_de_sva, keepers = keepers, excel = glue::glue("upload/DE_Cure_vs_Fail/{ver}_biopsy_vall_de_curevsfail_svabatch.xlsx")): object 'biop_de_sva' not found
biop_sig_sva <- sm(extract_significant_genes(
    biop_tables_sva,
    excel=glue::glue("excel/biopsy_clinical_sig_tables_sva-v{ver}.xlsx"),
    according_to="deseq"))
## Error in extract_significant_genes(biop_tables_sva, excel = glue::glue("excel/biopsy_clinical_sig_tables_sva-v{ver}.xlsx"), : object 'biop_tables_sva' not found

9.4.2.3 Biopsy DE plots

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

10 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"]])))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'mono_sig_sva' not found
shared_vector <- Vennerable::Venn(Sets=sig_vectors)
## Error in Vennerable::Venn(Sets = sig_vectors): object 'sig_vectors' not found
Vennerable::plot(shared_vector, doWeights=FALSE)
## Error in h(simpleError(msg, call)): error in evaluating the argument 'x' in selecting a method for function 'plot': object 'shared_vector' not found
shared_ids <- shared_vector@IntersectionSets[["111"]]
## Error in eval(expr, envir, enclos): object 'shared_vector' not found
shared_expt <- exclude_genes_expt(hs_clinical, ids=shared_ids, method="keep")
## Error in exclude_genes_expt(hs_clinical, ids = shared_ids, method = "keep"): object 'shared_ids' not found
shared_written <- write_expt(shared_expt,
                             excel=glue::glue("excel/shared_across_celltypes-v{ver}.xlsx"))
## Error in h(simpleError(msg, call)): error in evaluating the argument 'object' in selecting a method for function 'exprs': object 'shared_expt' not found

11 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 202, now there are 50 samples.
mono_visit_norm <- normalize_expt(mono_visit, filter=TRUE, norm="quant", convert="cpm",
                                  transform="log2")
## Removing 8776 low-count genes (11165 remaining).
## transform_counts: Found 11 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 8776 low-count genes (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 1029 low elements to zero.
## transform_counts: Found 1029 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 notapplicable 
##            19            25             5             1
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, 2380 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 (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 1029 low elements to zero.
## transform_counts: Found 1029 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
mono_visit_tables <- combine_de_tables(
    mono_visit_de,
    keepers=keepers,
    excel=glue::glue("excel/mono_visit_tables-v{ver}.xlsx"))
## Error in combine_de_tables(mono_visit_de, keepers = keepers, excel = glue::glue("excel/mono_visit_tables-v{ver}.xlsx")): object 'mono_visit_de' not found
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, 2380 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 (11165 remaining).
## batch_counts: Before batch/surrogate estimation, 2380 entries are x==0: 0%.
## batch_counts: Before batch/surrogate estimation, 36412 entries are 0<x<1: 7%.
## Setting 936 low elements to zero.
## transform_counts: Found 936 values equal to 0, adding 1 to the matrix.
## Error in checkForRemoteErrors(val): 5 nodes produced errors; first error: c("Error in if (grep(x = eval_name, pattern = \"^([[:digit:]]|[[:punct:]])\")) { : \n  argument is of length zero\n", "basic")
mono_one_vs_tables <- combine_de_tables(
    mono_one_vs_de,
    excel=glue::glue("excel/mono_one_vs_tables-v{ver}.xlsx"))
## Error in combine_de_tables(mono_one_vs_de, excel = glue::glue("excel/mono_one_vs_tables-v{ver}.xlsx")): object 'mono_one_vs_de' not found

12 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 841bed6443e2a8e27851bef94a1a6aacc0bae5cf
## This is hpgltools commit: Fri Oct 29 16:01:32 2021 -0400: 841bed6443e2a8e27851bef94a1a6aacc0bae5cf
## Saving to tmrc3_02sample_estimation_v202110.rda.xz
tmp <- loadme(filename=savefile)
LS0tCnRpdGxlOiAiVE1SQzMgQ29tcHJlaGVuc2l2ZSBEYXRhIEFuYWx5c2lzOiAyMDIxMTAiCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICBjb2xsYXBzZWQ6IGZhbHNlCiAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlPgogIGJvZHkgLm1haW4tY29udGFpbmVyIHsKICAgIG1heC13aWR0aDogMTYwMHB4OwogIH0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCnR0IDwtIHNtKGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICB3aWR0aD0xMjAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGg9MTIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0PTEyLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTIpKQp2ZXIgPC0gIjIwMjExMCIKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0PSIlWSVtJWQiKQoKcm1kX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgidG1yYzNfMDJzYW1wbGVfZXN0aW1hdGlvbl92e3Zlcn0uUm1kIikKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSJcXC5yZGFcXC54eiIsIHg9cm1kX2ZpbGUpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgd29ya3NoZWV0IGlzIGludGVuZGVkIHRvIHByb3ZpZGUgdGhlIGFuYWx5c2VzIGZvciB0aGUgVE1SQzMKcHJvamVjdC4gIEFzIG9mIH4gMjAyMTEwMTMgd2UgaGF2ZSBhIHNoYXJlZCBkaXJlY3RvcnkgaW50byB3aGljaCB0bwpwbGFjZSB2YXJpb3VzIHJlc3VsdHMuICBGb3IgdGhlIG1vbWVudCBJIHRoaW5rIHdlIHdpbGwgcHJpbWFyaWx5CmF0dGVtcHQgdG8gcHV0IGNzdiBmaWxlcy4gIEluIGVhY2ggZGlyZWN0b3J5IG9mIHRoYXQgc2hhcmVkIHRyZWUsIHdlCndpbGwgYXR0ZW1wdCB0byBwdXQgdGhlIHNldCBvZiByZXN1bHRzIHdoaWNoIGFyZSBkZWZpbmVkIGJ5IGVhY2gKc3ViZGl2aXNpb24uCgojIFNhbXBsZSBzaGVldAoKSSB0aGluayB0aGVyZSBoYXZlIGJlZW4gc29tZSBuZXcvaW1wcm92ZWQgYW5ub3RhdGlvbnMgaW4gdGhlIG9ubGluZSBzYW1wbGUgc2hlZXQsCnNvIGxldCB1cyBnbyBkb3dubG9hZCBhIGZyZXNoIGNvcHkgYW5kIHNlZS4KCmBgYHtyIHNhbXBsZXNoZWV0fQpzYW1wbGVzaGVldCA8LSAic2FtcGxlX3NoZWV0cy90bXJjM19zYW1wbGVzXzIwMjExMDEyLnhsc3giCmNyZl9tZXRhZGF0YSA8LSAic2FtcGxlX3NoZWV0cy8yMDIxMDgyNV9FWFBfRVNQRUNJQUxfVE1SQzNfVkVSU0lPTl8yLnhsc3giCmBgYAoKIyBBbm5vdGF0aW9uCgpXZSB0YWtlIHRoZSBhbm5vdGF0aW9uIGRhdGEgZnJvbSBlbnNlbWJsJ3MgYmlvbWFydCBpbnN0YW5jZS4gIFRoZSBnZW5vbWUgd2hpY2gKd2FzIHVzZWQgdG8gbWFwIHRoZSBkYXRhIHdhcyBoZzM4IHJldmlzaW9uIDEwMC4gIE15IGRlZmF1bHQgd2hlbiB1c2luZyBiaW9tYXJ0IGlzCnRvIGxvYWQgdGhlIGRhdGEgZnJvbSAxIHllYXIgYmVmb3JlIHRoZSBjdXJyZW50IGRhdGUuCgpgYGB7ciBoc19hbm5vdH0KaHNfYW5ub3QgPC0gc20obG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHllYXI9IjIwMjAiKSkKaHNfYW5ub3QgPC0gaHNfYW5ub3RbWyJhbm5vdGF0aW9uIl1dCmhzX2Fubm90W1sidHJhbnNjcmlwdCJdXSA8LSBwYXN0ZTAocm93bmFtZXMoaHNfYW5ub3QpLCAiLiIsIGhzX2Fubm90W1sidmVyc2lvbiJdXSkKcm93bmFtZXMoaHNfYW5ub3QpIDwtIG1ha2UubmFtZXMoaHNfYW5ub3RbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZT1UUlVFKQp0eF9nZW5lX21hcCA8LSBoc19hbm5vdFssIGMoInRyYW5zY3JpcHQiLCAiZW5zZW1ibF9nZW5lX2lkIildCgpzdW1tYXJ5KGhzX2Fubm90KQpgYGAKCmBgYHtyIGhzX2dvfQpoc19nbyA8LSBzbShsb2FkX2Jpb21hcnRfZ28oKVtbImdvIl1dKQpoc19sZW5ndGggPC0gaHNfYW5ub3RbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiY2RzX2xlbmd0aCIpXQpjb2xuYW1lcyhoc19sZW5ndGgpIDwtIGMoIklEIiwgImxlbmd0aCIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgaXMgaW50ZW5kZWQgdG8gcHJvdmlkZSBhbiBvdmVydmlldyBvZiBUTVJDMyBzYW1wbGVzIHdoaWNoIGhhdmUKYmVlbiBzZXF1ZW5jZWQuICBJdCBpbmNsdWRlcyBzb21lIHBsb3RzIGFuZCBhbmFseXNlcyBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXBzCmFtb25nIHRoZSBzYW1wbGVzIGFzIHdlbGwgYXMgc29tZSBkaWZmZXJlbnRpYWwgYW5hbHlzZXMgd2hlbiBwb3NzaWJsZS4KCiMgU2FtcGxlIEVzdGltYXRpb24KCiMjIEdlbmVyYXRlIGV4cHJlc3Npb25zZXRzCgpUaGUgc2FtcGxlIHNoZWV0IGlzIGNvcGllZCBmcm9tIG91ciBzaGFyZWQgb25saW5lIHNoZWV0IGFuZCB1cGRhdGVkIHdpdGggZWFjaCByZWxlYXNlCm9mIHNlcXVlbmNpbmcgZGF0YS4KCiMjIyBIaXNhdDIgZXhwcmVzc2lvbnNldHMKClRoZSBmaXJzdCB0aGluZyB0byBub3RlIGlzIHRoZSBsYXJnZSByYW5nZSBpbiBjb3ZlcmFnZS4gIFRoZXJlIGFyZSBtdWx0aXBsZQpzYW1wbGVzIHdpdGggY292ZXJhZ2Ugd2hpY2ggaXMgdG9vIGxvdyB0byB1c2UuICBUaGVzZSB3aWxsIGJlIHJlbW92ZWQgc2hvcnRseS4KCkluIHRoZSBmb2xsb3dpbmcgYmxvY2sgSSBpbW1lZGlhdGVseSBleGNsdWRlIGFueSBub24tY29kaW5nIHJlYWRzIGFzIHdlbGwuCgpgYGB7ciBhbGxfbmV3X2hpc2F0Mn0KIyMgQ3JlYXRlIHRoZSBleHByZXNzaW9uc2V0IGFuZCBpbW1lZGlhdGVseSBwYXNzIGl0IHRvIGEgZmlsdGVyCiMjIHJlbW92aW5nIHRoZSBub24gcHJvdGVpbiBjb2RpbmcgZ2VuZXMuCnNhbml0aXplX2NvbHVtbnMgPC0gYygidmlzaXRudW1iZXIiLCAiY2xpbmljYWxvdXRjb21lIiwgImRvbm9yIiwKICAgICAgICAgICAgICAgICAgICAgICJ0eXBlb2ZjZWxscyIsICJjbGluaWNhbHByZXNlbnRhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAiY29uZGl0aW9uIiwgImJhdGNoIikKaHNfZXhwdCA8LSBjcmVhdGVfZXhwdChzYW1wbGVzaGVldCwKICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbj0iaGczODEwMGhpc2F0ZmlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgc2F2ZWZpbGU9Z2x1ZTo6Z2x1ZSgicmRhL2hzX2V4cHRfYWxsLXZ7dmVyfS5yZGEiKSwKICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm89aHNfYW5ub3QpICU+JQogIGV4Y2x1ZGVfZ2VuZXNfZXhwdChjb2x1bW49ImdlbmVfYmlvdHlwZSIsIG1ldGhvZD0ia2VlcCIsCiAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49InByb3RlaW5fY29kaW5nIiwgbWV0YV9jb2x1bW49Im5jcm5hX2xvc3QiKSAlPiUKICBzYW5pdGl6ZV9leHB0X21ldGFkYXRhKGNvbHVtbnM9c2FuaXRpemVfY29sdW1ucykgJT4lCiAgc2V0X2V4cHRfZmFjdG9ycyhjb2x1bW5zPXNhbml0aXplX2NvbHVtbnMsIGNsYXNzPSJmYWN0b3IiKQoKbGV2ZWxzKHBEYXRhKGhzX2V4cHRbWyJleHByZXNzaW9uc2V0Il1dKVtbInZpc2l0bnVtYmVyIl1dKSA8LSBsaXN0KAogICAgJzAnPSJub3RhcHBsaWNhYmxlIiwgJzEnPTEsICcyJz0yLCAnMyc9MykKYGBgCgojIyMgQWRkIENsaW5pY2FsIG1ldGFkYXRhCgpMZXQgdXMgYWxzbyBtZXJnZSBpbiB0aGUgY2xpbmljaWFuJ3MgbWV0YWRhdGEuICBJIHdvcnJ5IGEgbGl0dGxlIHRoYXQKdGhpcyBtaWdodCBub3QgYmUgYWxsb3dlZCBmb3IgZGJHYXAgZGF0YSwgYnV0IGlmIGl0IGlzIGEgcHJvYmxlbSBJCnN1c3BlY3Qgd2UgY2FuIGp1c3QgcmVtb3ZlIHRoZSBiYWQgY29sdW1ucyBmcm9tIGl0LiAgQWxzbyBub3RlIHRoYXQgSQpyYXJlbHkgdXNlIHRoZSBqb2luIGZ1bmN0aW9uLCBidXQgaXQgaXMgc29tZXdoYXQgcmVxdWlyZWQgaGVyZSBiZWNhdXNlCkkgZG8gbm90IHdhbnQgdG8gcmlzayBzaHVmZmxpbmcgdGhlIG1ldGFkYXRhIHdoZW4gSSBhZGQgdGhlIG5ldwptZXRhZGF0YSwgd2hpY2ggY29tZXMgZnJvbSBhIHNwcmVhZHNoZWV0IHNvcnRlZCBieSBwYXRpZW50LCBub3QKc2FtcGxlLiAgSW4gZG9pbmcgdGhpcyBJIHRoZXJlZm9yZSBqdXN0IGNyZWF0ZWQgYSBuZXcgY29sdW1uICdqb2luJwp3aGljaCBjb250YWlucyB0aGUgc2hhcmVkIGluZm9ybWF0aW9uLCBlLmcuIHRoZSBwYXRpZW50IElECmZyb20gdGhlIGV4aXN0aW5nIG1ldGFkYXRhIGFuZCB0aGUgc2FtZSBJRCBmcm9tIHRoZSBDUkYgZmlsZSB3aGljaCBoYXMKYmVlbiBjb2VyY2VkIGludG8gbG93ZXJjYXNlLgoKYGBge3IgbWVyZ2VfY3JmfQpoc19wZCA8LSBwRGF0YShoc19leHB0KQpzdGFydCA8LSByb3duYW1lcyhoc19wZCkKaHNfY3JmIDwtIG9wZW54bHN4OjpyZWFkLnhsc3goY3JmX21ldGFkYXRhKQpoc19jcmZbWyJqb2luIl1dIDwtIHRvbG93ZXIoaHNfY3JmW1siY29kaWdvX3BhY2llbnRlIl1dKQpoc19wZFtbImpvaW4iXV0gPC0gaHNfcGRbWyJ0dWJlbGFiZWxvcmlnaW4iXV0KdGVzdCA8LSBwbHlyOjpqb2luKGhzX3BkLCBoc19jcmYsIGJ5PSJqb2luIikKdGVzdFtbImpvaW4iXV0gPC0gTlVMTApyb3duYW1lcyh0ZXN0KSA8LSByb3duYW1lcyhoc19wZCkKbmFfaWR4IDwtIGlzLm5hKHRlc3QpCnRlc3RbbmFfaWR4XSA8LSAidW5kZWZpbmVkIgpwRGF0YShoc19leHB0KSA8LSB0ZXN0CmBgYAoKVGhpcyBhZGRlZCBhIGJ1bmNoIG9mIG5ldyBjb2x1bW5zLCBvZiB3aGljaCB0aGVyZSBhcmUgYSBmZXcgd2hpY2gKVGhlcmVzYSBzaG93ZWQgYXJlIG9mIGxpa2VseSBpbnRlcmVzdDoKCiogZWJfbGNfc2V4bwoqIGViX2xjX2V0bmlhCiogZWRhZCBlYl9sY190aWVtcG9fZXZvbHVjaW9uCiogZWJfbGNfbnVtX2xjX2FjdGl2YXMKKiBlYl9sY191bGNlcmFfYXJlYV8xCiogZWJfbGNfZWpleF9sZXNpb25fbW1fMQoqIGViX2xjX2xlc2lvbl9hcmVhXzEKKiB2Ml9sY19lamV4X2xlc2lvbl9tbV8xCiogdjJfbGNfbGVzaW9uX2FyZWFfMQoqIHYyX2xjX2VqZXhfdWxjZXJhX21tXzEKKiB2Ml9sY19lamV5X3VsY2VyYV9tbV8xCiogdjJfbGNfdWxjZXJhX2FyZWFfMQoqIHYzX2xjX2VqZXhfbGVzaW9uX21tXzEKKiB2M19sY19lamV5X2xlc2lvbl9tbV8xCiogdjNfbGNfbGVzaW9uX2FyZWFfMQoqIHYzX2xjX2VqZXhfdWxjZXJhX21tXzEKKiB2M19sY19lamV5X3VsY2VyYV9tbV8xCiogdjNfbGNfdWxjZXJhX2FyZWFfMQoqIGViX2xjX3R0b19tY3RvX3ByZXNjcml0bwoqIGViX2xjX3R0b19tY3RvX2dsdWNhbl9kb3NpcwoqIHYzX2xjX251bV9hbXBfY2FwX3R0bwoqIGFkaGVyZW5jaWFfdHRvCgojIyMgQ29uc2lkZXIgbGNSTkEgKGN1cnJlbnRseSB1bnVzZWQpCgpTcGxpdCB0aGlzIGRhdGEgaW50byBDRFMgYW5kIGxuY1JOQS4gIE9oIGNyYXAgaW4gb3JkZXIgdG8gZG8gdGhhdCBJIG5lZWQgdG8gcmVjb3VudCB0aGUgZGF0YS4KUnVubmluZyBub3cgKDIwMjEwNTE4KQoKYGBge3IgbG5jX2Nkc30KIyMgbG5jX2V4cHQgPC0gY3JlYXRlX2V4cHQoc2FtcGxlc2hlZXQsCiMjICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uPSJoZzM4MTAwbG5jZmlsZSIsCiMjICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1oc19hbm5vdCkKYGBgCgojIyMjIEluaXRpYWwgbWV0cmljcwoKT25jZSB0aGUgZGF0YSB3YXMgbG9hZGVkLCB0aGVyZSBhcmUgYSBjb3VwbGUgb2YgbWV0cmljcyB3aGljaCBtYXkgYmUgcGxvdHRlZCBpbW1lZGlhdGVseS4KCmBgYHtyIGluaXRpYWxfbWV0cmljc30Kbm9uemVybyA8LSBwbG90X25vbnplcm8oaHNfZXhwdCkKbm9uemVybyRwbG90CgpuY3JuYV9sb3N0X2RmIDwtIGFzLmRhdGEuZnJhbWUocERhdGEoaHNfZXhwdClbWyJuY3JuYV9sb3N0Il1dKQpyb3duYW1lcyhuY3JuYV9sb3N0X2RmKSA8LSByb3duYW1lcyhwRGF0YShoc19leHB0KSkKY29sbmFtZXMobmNybmFfbG9zdF9kZikgPC0gIm5jcm5hX2xvc3QiCgp0bXBkZiA8LSBtZXJnZShub256ZXJvJHRhYmxlLCBuY3JuYV9sb3N0X2RmLCBieT0icm93Lm5hbWVzIikKcm93bmFtZXModG1wZGYpIDwtIHRtcGRmW1siUm93Lm5hbWVzIl1dCnRtcGRmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKCmdncGxvdCh0bXBkZiwgYWVzKHg9bmNybmFfbG9zdCwgeT1ub256ZXJvX2dlbmVzKSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoKSArCiAgZ2dwbG90Mjo6Z2d0aXRsZSgiTm9uemVybyBnZW5lcyB3aXRoIHJlc3BlY3QgdG8gcGVyY2VudCBjb3VudHMKbG9zdCB3aGVuIG5jUk5BIHdhcyByZW1vdmVkLiIpCmBgYAoKTmFqaWIgZG9lc24ndCB3YW50IHRoaXMgcGxvdCwgYnV0IEkgYW0gdXNpbmcgaXQgdG8gY2hlY2sgbmV3IHNhbXBsZXMsCnNvIHdpbGwgaGlkZSBpdCBmcm9tIGdlbmVyYWwgdXNlLgoKYGBge3IgbGlic2l6ZX0KbGlic2l6ZSA8LSBwbG90X2xpYnNpemUoaHNfZXhwdCkKbGlic2l6ZSRwbG90CmBgYAoKIyMgTWluaW11bSBjb3ZlcmFnZSBzYW1wbGUgZmlsdGVyaW5nCgpJIGFyYml0cmFyaWx5IGNob3NlIDExLDAwMCBub24temVybyBnZW5lcyBhcyBhIG1pbmltdW0uICBXZSBtYXkKd2FudCB0aGlzIHRvIGJlIGhpZ2hlci4KCmBgYHtyIGhpc2F0Ml93cml0ZSwgZmlnLnNob3c9ImhpZGUifQpoc192YWxpZCA8LSBzdWJzZXRfZXhwdChoc19leHB0LCBub256ZXJvPTExMDAwKQoKIyMgdmFsaWRfd3JpdGUgPC0gc20od3JpdGVfZXhwdChoc192YWxpZCwgZXhjZWw9Z2x1ZSgiZXhjZWwvaHNfdmFsaWQtdnt2ZXJ9LXtydW5kYXRlfS54bHN4IikpKQpgYGAKCiMjIFVwbG9hZCAncmF3JyBDUE0KClRoZSBjcG0gZGlyZWN0b3J5IGluIHRoZSBzaGFyZWQgdHJlZSBoYXMgYSBwbGFjZSB0byBkcm9wIHRoZSBjb3VudHMKZm9yIHRoZSBmdWxsIGRhdGFzZXQgYWxvbmcgd2l0aCBzb21lIHN1YnNldHMgYnkgY2VsbCB0eXBlIGFuZCB0aW1lLgpUaGUgZm9sbG93aW5nIGJsb2NrIHNob3VsZCBtYWtlIHRoYXQgcHJvY2VzcyByYXRoZXIgZWFzaWVyLgoKYGBge3IgY3BtX2NzdiwgcmVzdWx0cz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KYWxsX2NwbSA8LSBoc192YWxpZCAlPiUKICBub3JtYWxpemVfZXhwdChoc192YWxpZCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIpICU+JQogIGV4cHJzKCkgJT4lCiAgd3JpdGUuY3N2KGZpbGU9ZmlsZT1nbHVlOjpnbHVlKCJ1cGxvYWQvQ1BNL2FsbF9jcG0tdnt2ZXJ9LWR7cnVuZGF0ZX0uY3N2IikpCgpiaW9wc3lfY3BtIDwtIGhzX3ZhbGlkICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0idHlwZW9mY2VsbHM9PSdiaW9wc3knIikgJT4lCiAgbm9ybWFsaXplX2V4cHQoZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIpICU+JQogIGV4cHJzKCkgJT4lCiAgd3JpdGUuY3N2KGZpbGU9Z2x1ZTo6Z2x1ZSgidXBsb2FkL0NQTS9CaW9wc2llcy9iaW9wc3lfY3BtLXZ7dmVyfS1ke3J1bmRhdGV9LmNzdiIpKQoKZW9zaW5vcGhpbHNfY3BtIDwtIGhzX3ZhbGlkICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0idHlwZW9mY2VsbHM9PSdlb3Npbm9waGlscyciKSAlPiUKICBub3JtYWxpemVfZXhwdChmaWx0ZXI9VFJVRSwgY29udmVydD0iY3BtIikgJT4lCiAgZXhwcnMoKSAlPiUKICB3cml0ZS5jc3YoZmlsZT1nbHVlOjpnbHVlKCJ1cGxvYWQvQ1BNL0Vvc2lub3BoaWxzL2Vvc2lub3BoaWxfY3BtLXZ7dmVyfS1ke3J1bmRhdGV9LmNzdiIpKQoKbW9ub2N5dGVfY3BtIDwtIGhzX3ZhbGlkICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0idHlwZW9mY2VsbHM9PSdtb25vY3l0ZXMnIikgJT4lCiAgbm9ybWFsaXplX2V4cHQoZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIpICU+JQogIGV4cHJzKCkgJT4lCiAgd3JpdGUuY3N2KGZpbGU9Z2x1ZTo6Z2x1ZSgidXBsb2FkL0NQTS9Nb25vY3l0ZXMvbW9ub2N5dGVfY3BtLXZ7dmVyfS1ke3J1bmRhdGV9LmNzdiIpKQoKbmV1dHJvcGhpbF9jcG0gPC0gaHNfdmFsaWQgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJ0eXBlb2ZjZWxscz09J25ldXRyb3BoaWxzJyIpICU+JQogIG5vcm1hbGl6ZV9leHB0KGZpbHRlcj1UUlVFLCBjb252ZXJ0PSJjcG0iKSAlPiUKICBleHBycygpICU+JQogIHdyaXRlLmNzdihmaWxlPWdsdWU6OmdsdWUoInVwbG9hZC9DUE0vTmV1dHJvcGhpbHMvbmV1dHJvcGhpbF9jcG0tdnt2ZXJ9LWR7cnVuZGF0ZX0uY3N2IikpCgp0aW1lcyA8LSBjKCIxIiwgIjIiLCAiMyIpCmZvciAodGltZSBpbiB0aW1lcykgewogIHRpbWVfc3Vic2V0IDwtIHBhc3RlMCgidmlzaXRudW1iZXI9PSciLCB0aW1lLCAiJyIpCiAgZmlsZW5hbWUgPC0gZ2x1ZTo6Z2x1ZSgidXBsb2FkL0NQTS92aXNpdHt0aW1lfS12e3Zlcn0tZHtydW5kYXRlfS5jc3YiKQogIHdyaXR0ZW4gPC0gaHNfdmFsaWQgJT4lCiAgICBzdWJzZXRfZXhwdChzdWJzZXQ9dGltZV9zdWJzZXQpICU+JQogICAgZXhwcnMoKSAlPiUKICAgIHdyaXRlLmNzdihmaWxlPWZpbGVuYW1lKQp9Cgp0eXBlcyA8LSBjKCJuZXV0cm9waGlscyIsICJtb25vY3l0ZXMiLCAiZW9zaW5vcGhpbHMiLCAiYmlvcHN5IikKZm9yICh0eXBlIGluIHR5cGVzKSB7CiAgdHlwZV9zdWJzZXQgPC0gcGFzdGUwKCJ0eXBlb2ZjZWxscz09JyIsIHR5cGUsICInIikKICBmb3IgKHRpbWUgaW4gdGltZXMpIHsKICAgIHRpbWVfc3Vic2V0IDwtIHBhc3RlMCgidmlzaXRudW1iZXI9PSciLCB0aW1lLCAiJyIpCiAgICBmaWxlbmFtZSA8LSBnbHVlOjpnbHVlKCJ1cGxvYWQvQ1BNL3t0eXBlfV92aXNpdHt0aW1lfS12e3Zlcn0tZHtydW5kYXRlfS5jc3YiKQogICAgd3JpdHRlbiA8LSBoc192YWxpZCAlPiUKICAgICAgc3Vic2V0X2V4cHQoc3Vic2V0PXRpbWVfc3Vic2V0KSAlPiUKICAgICAgc3Vic2V0X2V4cHQoc3Vic2V0PXR5cGVfc3Vic2V0KSAlPiUKICAgICAgZXhwcnMoKSAlPiUKICAgICAgd3JpdGUuY3N2KGZpbGU9ZmlsZW5hbWUpCiAgfQp9CmBgYAoKIyBQcm9qZWN0IEFpbXMKClRoZSBwcm9qZWN0IHNlZWtzIHRvIGRldGVybWluZSB0aGUgcmVsYXRpb25zaGlwIG9mIHRoZSBpbm5hdGUgaW1tdW5lIHJlc3BvbnNlCmFuZCBpbmZsYW1tYXRvcnkgc2lnbmFsaW5nIHRvIHRoZSBjbGluaWNhbCBvdXRjb21lIG9mIGFudGlsZWlzaG1hbmlhbCBkcnVnCnRyZWF0bWVudC4gV2Ugd2lsbCB0ZXN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlIHByb2ZpbGUgb2YgaW5uYXRlIGltbXVuZSBjZWxsCmFjdGl2YXRpb24gYW5kIHRoZWlyIGR5bmFtaWNzIHRocm91Z2ggdGhlIGNvdXJzZSBvZiB0cmVhdG1lbnQgZGlmZmVyIGJldHdlZW4gQ0wKcGF0aWVudHMgd2l0aCBwcm9zcGVjdGl2ZWx5IGRldGVybWluZWQgdGhlcmFwZXV0aWMgY3VyZSBvciBmYWlsdXJlLgoKVGhpcyB3aWxsIGJlIGFjaGlldmVkIHRocm91Z2ggdGhlIGNoYXJhY3Rlcml6YXRpb24gb2YgdGhlIGluIHZpdm8gZHluYW1pY3Mgb2YKYmxvb2QtZGVyaXZlZCBtb25vY3l0ZSwgbmV1dHJvcGhpbCBhbmQgZW9zaW5vcGhpbCB0cmFuc2NyaXB0b21lIGJlZm9yZSwgZHVyaW5nCmFuZCBhdCB0aGUgZW5kIG9mIHRyZWF0bWVudCBpbiBDTCBwYXRpZW50cy4gQ2VsbC10eXBlIHNwZWNpZmljIHRyYW5zY3JpcHRvbWVzLApjb21wb3NpdGUgc2lnbmF0dXJlcyBhbmQgdGltZS1yZXNwb25zZSBleHByZXNzaW9uIHByb2ZpbGVzIHdpbGwgYmUgY29udHJhc3RlZAphbW9uZyBwYXRpZW50cyB3aXRoIHRoZXJhcGV1dGljIGN1cmUgb3IgZmFpbHVyZS4KCiMjIFByZXBhcmF0aW9uCgpUbyBhZGRyZXNzIHRoZXNlLCBJIGFkZGVkIHRvIHRoZSBlbmQgb2YgdGhlIHNhbXBsZSBzaGVldCBjb2x1bW5zIG5hbWVkCidjb25kaXRpb24nLCAnYmF0Y2gnLCAnZG9ub3InLCBhbmQgJ3RpbWUnLiAgVGhlc2UgYXJlIGZpbGxlZCBpbiB3aXRoIHNob3J0aGFuZAp2YWx1ZXMgYWNjb3JkaW5nIHRvIHRoZSBhYm92ZS4KCiMjIEdsb2JhbCB2aWV3CgpCZWZvcmUgYWRkcmVzc2luZyB0aGUgcXVlc3Rpb25zIGV4cGxpY2l0bHkgYnkgc3Vic2V0dGluZyB0aGUgZGF0YSwgSSB3YW50IHRvIGdldAphIGxvb2sgYXQgdGhlIHNhbXBsZXMgYXMgdGhleSBhcmUuCgpgYGB7ciBwcmVfcXVlc3Rpb25zfQpuZXdfbmFtZXMgPC0gcERhdGEoaHNfdmFsaWQpW1sic2FtcGxlbmFtZSJdXQpoc192YWxpZCA8LSBoc192YWxpZCAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9ImNlbGxzc291cmNlIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0PSJ0eXBlb2ZjZWxscyIpICU+JQogIHNldF9leHB0X3NhbXBsZW5hbWVzKG5ld25hbWVzPW5ld19uYW1lcykKCmFsbF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGhzX3ZhbGlkLCB0cmFuc2Zvcm09ImxvZzIiLCBub3JtPSJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFKSkKCmFsbF9wY2EgPC0gcGxvdF9wY2EoYWxsX25vcm0sIHBsb3RfbGFiZWxzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgIHBsb3RfdGl0bGU9IlBDQSAtIENlbGwgdHlwZSIsIHNpemVfY29sdW1uPSJ2aXNpdG51bWJlciIpCnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL3RtcmMzX3BjYV9ub2xhYmVscy12e3Zlcn0ucG5nIiksIGltYWdlPWFsbF9wY2EkcGxvdCkKCndyaXRlLmNzdihhbGxfcGNhJHRhYmxlLCBmaWxlPSJjb29yZHMvaHNfZG9ub3JfcGNhX2Nvb3Jkcy5jc3YiKQpwbG90X2NvcmhlYXQoYWxsX25vcm0sIHBsb3RfdGl0bGU9IkhlaXJhcmNoaWNhbCBjbHVzdGVyaW5nOgogICAgICAgICBjZWxsIHR5cGVzIikkcGxvdApgYGAKCiMjIEV4YW1pbmUgc2FtcGxlcyByZWxldmFudCB0byBjbGluaWNhbCBvdXRjb21lCgpOb3cgbGV0IHVzIGNvbnNpZGVyIG9ubHkgdGhlIHNhbXBsZXMgZm9yIHdoaWNoIHdlIGhhdmUgYSBjbGluaWNhbCBvdXRjb21lLgpUaGVzZSBmYWxsIHByaW1hcmlseSBpbnRvIGVpdGhlciAnY3VyZWQnIG9yICdmYWlsZWQnLCBidXQgc29tZSBwZW9wbGUgaGF2ZSBub3QKeWV0IHJldHVybmVkIHRvIHRoZSBjbGluaWMgYWZ0ZXIgdGhlIGZpcnN0IG9yIHNlY29uZCB2aXNpdC4gIFRoZXNlIGFyZSBkZWVtZWQKJ2xvc3QnLgoKYGBge3IgYWxsX2NsaW5pY2FsfQpoc19jbGluaWNhbCA8LSBoc192YWxpZCAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9ImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdD0idHlwZW9mY2VsbHMiKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9InR5cGVvZmNlbGxzIT0ncGJtY3MnJnR5cGVvZmNlbGxzIT0nbWFjcm9waGFnZXMnIikKCmNob3Nlbl9jb2xvcnMgPC0gYygiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiMxQjlFNzciLCAiI0ZGMDAwMCIsICIjRkYwMDAwIikKbmFtZXMoY2hvc2VuX2NvbG9ycykgPC0gYygiY3VyZSIsICJmYWlsdXJlIiwgImxvc3QiLCAibnVsbCIsICJub3RhcHBsaWNhYmxlIikKaHNfY2xpbmljYWwgPC0gc2V0X2V4cHRfY29sb3JzKGhzX2NsaW5pY2FsLCBjb2xvcnM9Y2hvc2VuX2NvbG9ycykKCm5ld25hbWVzIDwtIG1ha2UubmFtZXMocERhdGEoaHNfY2xpbmljYWwpW1sic2FtcGxlbmFtZSJdXSwgdW5pcXVlPVRSVUUpCmhzX2NsaW5pY2FsIDwtIHNldF9leHB0X3NhbXBsZW5hbWVzKGhzX2NsaW5pY2FsLCBuZXduYW1lcz1uZXduYW1lcykKCmhzX2NsaW5pY2FsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2xpbmljYWwsIGZpbHRlcj1UUlVFLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IikpCmNsaW5pY2FsX3BjYSA8LSBwbG90X3BjYShoc19jbGluaWNhbF9ub3JtLCBwbG90X2xhYmVscz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfY29sdW1uPSJ2aXNpdG51bWJlciIsIGNpcz1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZT0iUENBIC0gY2xpbmljYWwgc2FtcGxlcyIpCnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL2FsbF9jbGluaWNhbF9ub2JhdGNoX3BjYS12e3Zlcn0ucG5nIiksIGltYWdlPWNsaW5pY2FsX3BjYSRwbG90LAogICBoZWlnaHQ9OCwgd2lkdGg9MjApCmBgYAoKIyMjIFJlcGVhdCB3aXRob3V0IHRoZSBiaW9wc3kgc2FtcGxlcwoKYGBge3IgaWJpZF9ub2Jpb3BzeX0KaHNfY2xpbmljYWxfbm9iaW9wIDwtIGhzX2NsaW5pY2FsICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0idHlwZW9mY2VsbHMhPSdiaW9wc3knIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJjb25kaXRpb249PSdsb3N0J3xjb25kaXRpb249PSdjdXJlJ3xjb25kaXRpb249PSdmYWlsdXJlJyIpCgpoc19jbGluaWNhbF9ub2Jpb3Bfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChoc19jbGluaWNhbF9ub2Jpb3AsIGZpbHRlcj1UUlVFLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBub3JtPSJxdWFudCIpKQpjbGluaWNhbF9ub2Jpb3BfcGNhIDwtIHBsb3RfcGNhKGhzX2NsaW5pY2FsX25vYmlvcF9ub3JtLCBwbG90X2xhYmVscz1GQUxTRSwgY2lzPU5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZT0iUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIikKcHAoZmlsZT1nbHVlKCJpbWFnZXMvYWxsX2NsaW5pY2FsX25vYmlvcF9ub2JhdGNoX3BjYS12e3Zlcn0ucG5nIiksCiAgIGltYWdlPWNsaW5pY2FsX25vYmlvcF9wY2EkcGxvdCkKYGBgCgojIyMgQXR0ZW1wdCB0byBjb3JyZWN0IGZvciB0aGUgc3Vycm9nYXRlIHZhcmlhYmxlcwoKQXQgdGhpcyB0aW1lIHdlIGhhdmUgdHdvIHByaW1hcnkgZGF0YSBzdHJ1Y3R1cmVzIG9mIGludGVyZXN0OiBoc19jbGluaWNhbCBhbmQgaHNfY2xpbmljYWxfbm9iaW9wCgpgYGB7ciBjbGluaWNhbF9zdmF9CmhzX2NsaW5pY2FsX25iIDwtIG5vcm1hbGl6ZV9leHB0KGhzX2NsaW5pY2FsLCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIpCmNsaW5pY2FsX2JhdGNoX3BjYSA8LSBwbG90X3BjYShoc19jbGluaWNhbF9uYiwgcGxvdF9sYWJlbHM9RkFMU0UsIGNpcz1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZV9jb2x1bW49InZpc2l0bnVtYmVyIiwgcGxvdF90aXRsZT0iUENBIC0gY2xpbmljYWwgc2FtcGxlcyIpCmNsaW5pY2FsX2JhdGNoX3BjYSRwbG90Cgpoc19jbGluaWNhbF9ub2Jpb3BfbmIgPC0gc20obm9ybWFsaXplX2V4cHQoaHNfY2xpbmljYWxfbm9iaW9wLCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iKSkKY2xpbmljYWxfbm9iaW9wX2JhdGNoX3BjYSA8LSBwbG90X3BjYShoc19jbGluaWNhbF9ub2Jpb3BfbmIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZT0iUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscz1GQUxTRSkKcHAoZmlsZT0iaW1hZ2VzL2NsaW5pY2FsX2JhdGNoLnBuZyIsIGltYWdlPWNsaW5pY2FsX25vYmlvcF9iYXRjaF9wY2EkcGxvdCkKdGVzdCA8LSBwbG90X3BjYShoc19jbGluaWNhbF9ub2Jpb3BfbmIsIHNpemVfY29sdW1uPSJ2aXNpdG51bWJlciIsCiAgICAgICAgICAgICAgICAgcGxvdF90aXRsZT0iUENBIC0gY2xpbmljYWwgc2FtcGxlcyB3aXRob3V0IGJpb3BzaWVzIiwKICAgICAgICAgICAgICAgICBwbG90X2xhYmVscz1GQUxTRSkKdGVzdCRwbG90CgpjbGluaWNhbF9ub2Jpb3BfYmF0Y2hfdHNuZSA8LSBwbG90X3RzbmUoaHNfY2xpbmljYWxfbm9iaW9wX25iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF90aXRsZT0idFNORSAtIGNsaW5pY2FsIHNhbXBsZXMgd2l0aG91dCBiaW9wc2llcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xhYmVscz1GQUxTRSkKY2xpbmljYWxfbm9iaW9wX2JhdGNoX3RzbmUkcGxvdApgYGAKCiMjIFBlcmZvcm0gREUgb2YgdGhlIGNsaW5pY2FsIHNhbXBsZXMgY3VyZSB2cy4gZmFpbAoKYGBge3IgY2xpbmljYWxfZGUsIGZpZy5zaG93PSJoaWRlIn0KaW5kaXZpZHVhbF9jZWxsdHlwZXMgPC0gc3Vic2V0X2V4cHQoaHNfY2xpbmljYWxfbm9iaW9wLCBzdWJzZXQ9ImNvbmRpdGlvbiE9J2xvc3QnIikKaHNfY2xpbmljX2RlIDwtIHNtKGFsbF9wYWlyd2lzZShpbmRpdmlkdWFsX2NlbGx0eXBlcywgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKSkKaHNfY2xpbmljX3RhYmxlIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgaHNfY2xpbmljX2RlLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvaW5kaXZpZHVhbF9jZWxsdHlwZXNfdGFibGUtdnt2ZXJ9Lnhsc3giKSkpCmhzX2NsaW5pY19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGhzX2NsaW5pY190YWJsZSwKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2luZGl2aWR1YWxfY2VsbHR5cGVzX3NpZy12e3Zlcn0ueGxzeCIpKSkKCmhzX2NsaW5pY19zaWdbWyJzdW1tYXJ5X2RmIl1dCmBgYAoKYGBge3IgZGVfaGVhdG1hcH0KaHNfY2xpbmljX2RlW1siY29tcGFyaXNvbiJdXVtbImhlYXQiXV0KYGBgCgojIyBSYW5kb20gYXNpZGUgZm9yIG15IG93biBlZHVjYXRpb24KCkkgd2FzIGp1c3QgZG9pbmcgc29tZSByZWFkaW5nIGFib3V0IGNvbmNvcmRhbmNlIHN0YXRpc3RpY3MuICBJIHdhbnQgdG8gdHJ5IHNvbWV0aGluZyB3aXRoIHRoZW0uCgpgYGB7ciBjb25jb3JkYW5jZV90ZXN0fQp0ZXN0X2RmIDwtIGhzX2NsaW5pY190YWJsZVtbImRhdGEiXV1bWyJmYWlsdXJlX3ZzX2N1cmUiXV1bLCBjKCJkZXNlcV9sb2dmYyIsICJlZGdlcl9sb2dmYyIpXQp0ZXN0X2xtIDwtIGdsbShkZXNlcV9sb2dmYyB+IGVkZ2VyX2xvZ2ZjLCBkYXRhPXRlc3RfZGYpCmNvbiA8LSBzdXJ2aXZhbDo6Y29uY29yZGFuY2UodGVzdF9sbSkKY29uCmBgYAoKVG8gY2FsY3VsYXRlIHRoZSBmaXJzdCBvZiB0aGVzZSBtZXRyaWNzLCB0aGUgYXJlYSB1bmRlciB0aGUgY29uY29yZGFuY2UKY3VydmUgKEFVQ0MpLCB3ZSByYW5rZWQgZ2VuZXMgaW4gYm90aCB0aGUgc2luZ2xlLWNlbGwgYW5kIGJ1bGsgZGF0YXNldHMgaW4KZGVzY2VuZGluZyBvcmRlciBieSB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIG9mIHRoZWlyIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLgpUaGVuLCB3ZSBjcmVhdGVkIGxpc3RzIG9mIHRoZSB0b3AtcmFua2VkIGdlbmVzIGluIGVhY2ggZGF0YXNldCBvZiBtYXRjaGluZyBzaXplLCB1cAp0byBzb21lIG1heGltdW0gc2l6ZSBrLiBGb3IgZWFjaCBvZiB0aGVzZSBsaXN0cyAodGhhdCBpcywgZm9yIHRoZSB0b3AtMSBnZW5lcywgdG9wLTIKZ2VuZXMsIHRvcC0zIGdlbmVzLCBhbmQgc28gb24pLCB3ZSBjb21wdXRlZCB0aGUgc2l6ZSBvZiB0aGUgaW50ZXJzZWN0aW9uIGJldHdlZW4KdGhlIHNpbmdsZS1jZWxsIGFuZCBidWxrIERFIGdlbmVzLiBUaGlzIHByb2NlZHVyZSB5aWVsZGVkIGEgY3VydmUgcmVsYXRpbmcgdGhlCm51bWJlciBvZiBzaGFyZWQgZ2VuZXMgYmV0d2VlbiBkYXRhc2V0cyB0byB0aGUgbnVtYmVyIG9mIHRvcC1yYW5rZWQgZ2VuZXMKY29uc2lkZXJlZC4gVGhlIGFyZWEgdW5kZXIgdGhpcyBjdXJ2ZSB3YXMgY29tcHV0ZWQgYnkgc3VtbWluZyB0aGUgc2l6ZSBvZiBhbGwKaW50ZXJzZWN0aW9ucywgYW5kIG5vcm1hbGl6ZWQgdG8gdGhlIHJhbmdlIFswLCAxXSBieSBkaXZpZGluZyBpdCBieSBpdHMgbWF4aW11bQpwb3NzaWJsZSB2YWx1ZSwgayDDlyAoIGsgKzEpIC8gMi4gVG8gZXZhbHVhdGUgdGhlIGNvbmNvcmRhbmNlIG9mIERFIGFuYWx5c2lzLCB3ZSB1c2VkCmsgPTUwMCBleGNlcHQgd2hlcmUgb3RoZXJ3aXNlIG5vdGVkLCBidXQgZm91bmQgb3VyIHJlc3VsdHMgd2VyZSBpbnNlbnNpdGl2ZSB0byB0aGUKcHJlY2lzZSB2YWx1ZSBvZiBrLiBUbyBjb21wdXRlIHRoZSBzZWNvbmQgbWV0cmljLCB0aGUgdHJhbnNjcmlwdG9tZS13aWRlIHJhbmsKY29ycmVsYXRpb24sIHdlIG11bHRpcGxpZWQgdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSB0ZXN0IHN0YXRpc3RpYyBmb3IgZWFjaCBnZW5lIGJ5IHRoZQpzaWduIG9mIGl0cyBsb2ctZm9sZCBjaGFuZ2UgYmV0d2VlbiBjb25kaXRpb25zLCBhbmQgdGhlbiBjb21wdXRlZCB0aGUgU3BlYXJtYW4KY29ycmVsYXRpb24gb3ZlciBnZW5lcyBiZXR3ZWVuIHRoZW0uCgpgYGB7ciBhdWNjfQpjYWxjdWxhdGVfYXVjYyA8LSBmdW5jdGlvbih0YmwsIHB4PSJkZXNlcV9hZGpwIiwgcHk9ImVkZ2VyX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBseD0iZGVzZXFfbG9nZmMiLCBseT0iZWRnZXJfbG9nZmMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BuPTAuMSkgewogICMjIElmIHRoZSB0b3BuIGFyZ3VtZW50IGlzIGFuIGludGVnZXIsIHRoZSBqdXN0IGFzayBmb3IgdGhhdCBudW1iZXIuCiAgIyMgSWYgaXQgaXMgYSBmbG9hdGluZyBwb2ludCAwPHg8MSwgdGhlbiBzZXQgdG9wbiB0byB0aGF0IHByb3BvcnRpb24KICAjIyBvZiB0aGUgbnVtYmVyIG9mIGdlbmVzLgogIGlmICh0b3BuIDw9IDApIHsKICAgIHN0b3AoInRvcG4gbmVlZCB0byBiZSBlaXRoZXIgYSBmbG9hdCBmcm9tIDAtMSBvciBhbiBpbnRlcmdlciBiaWdnZXIgdGhhbiAxMDAuIikKICB9IGVsc2UgaWYgKHRvcG4gPiAxICYgdG9wbiA8PSAxMDApIHsKICAgIHN0b3AoInRvcG4gbmVlZCB0byBiZSBlaXRoZXIgYSBmbG9hdCBmcm9tIDAtMSBvciBhbiBpbnRlcmdlciBiaWdnZXIgdGhhbiAxMDAuIikKICB9IGVsc2UgaWYgKHRvcG4gPCAxKSB7CiAgICB0b3BuIDwtIGNlaWxpbmcobnJvdyh0YmwpICogdG9wbikKICB9CgogIHhfZGYgPC0gdGJsWywgYyhweCwgbHgpXQogIHlfZGYgPC0gdGJsWywgYyhweSwgbHkpXQogICMjIGN1cnZlIChBVUNDKSwgd2UgcmFua2VkIGdlbmVzIGluIGJvdGggdGhlIHNpbmdsZS1jZWxsIGFuZCBidWxrIGRhdGFzZXRzIGluCiAgIyMgZGVzY2VuZGluZyBvcmRlciBieSB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIG9mIHRoZWlyIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLgogIHhfaWR4IDwtIG9yZGVyKHhfZGZbWzFdXSwgZGVjcmVhc2luZz1GQUxTRSkKICB4X2RmIDwtIHhfZGZbeF9pZHgsIF0KICB5X2lkeCA8LSBvcmRlcih5X2RmW1sxXV0sIGRlY3JlYXNpbmc9RkFMU0UpCiAgeV9kZiA8LSB5X2RmW3lfaWR4LCBdCgogICMjIFRoZW4sIHdlIGNyZWF0ZWQgbGlzdHMgb2YgdGhlIHRvcC1yYW5rZWQgZ2VuZXMgaW4gZWFjaCBkYXRhc2V0IG9mCiAgIyMgbWF0Y2hpbmcgc2l6ZSwgdXAgdG8gc29tZSBtYXhpbXVtIHNpemUgay4gRm9yIGVhY2ggb2YgdGhlc2UgbGlzdHMKICAjIyAodGhhdCBpcywgZm9yIHRoZSB0b3AtMSBnZW5lcywgdG9wLTIgZ2VuZXMsIHRvcC0zIGdlbmVzLCBhbmQgc28KICAjIyBvbiksIHdlIGNvbXB1dGVkIHRoZSBzaXplIG9mIHRoZSBpbnRlcnNlY3Rpb24gYmV0d2VlbiB0aGUKICAjIyBzaW5nbGUtY2VsbCBhbmQgYnVsayBERSBnZW5lcy4gVGhpcyBwcm9jZWR1cmUgeWllbGRlZCBhIGN1cnZlCiAgIyMgcmVsYXRpbmcgdGhlIG51bWJlciBvZiBzaGFyZWQgZ2VuZXMgYmV0d2VlbiBkYXRhc2V0cyB0byB0aGUKICAjIyBudW1iZXIgb2YgdG9wLXJhbmtlZCBnZW5lcyBjb25zaWRlcmVkLgoKICBpbnRlcnNlY3Rpb25zIDwtIHJlcCgwLCB0b3BuKQogIGZvciAoaSBpbiAxOnRvcG4pIHsKICAgIGlmIChpID09IDEpIHsKICAgICAgeF9pbnRlcnNlY3Rpb25zW2ldIDwtIHJvd25hbWVzKHhfZGYpW2ldID09IHJvd25hbWVzKHlfZGYpW2ldCiAgICB9IGVsc2UgewogICAgICB4X3NldCA8LSByb3duYW1lcyh4X2RmKVsxOmldCiAgICAgIHlfc2V0IDwtIHJvd25hbWVzKHlfZGYpWzE6aV0KICAgICAgaW50ZXJzZWN0aW9uc1tpXSA8LSBzdW0oeF9zZXQgJWluJSB5X3NldCkKICAgIH0KICB9CgogICMjIFRoZSBhcmVhIHVuZGVyIHRoaXMgY3VydmUgd2FzIGNvbXB1dGVkIGJ5IHN1bW1pbmcgdGhlIHNpemUgb2YgYWxsCiAgIyMgaW50ZXJzZWN0aW9ucywgYW5kIG5vcm1hbGl6ZWQgdG8gdGhlIHJhbmdlIFswLCAxXSBieSBkaXZpZGluZyBpdAogICMjIGJ5IGl0cyBtYXhpbXVtIHBvc3NpYmxlIHZhbHVlLCBrIMOXICggayArMSkgLyAyLiBUbyBldmFsdWF0ZSB0aGUKICAjIyBjb25jb3JkYW5jZSBvZiBERSBhbmFseXNpcywgd2UgdXNlZCBrID01MDAgZXhjZXB0IHdoZXJlIG90aGVyd2lzZQogICMjIG5vdGVkLCBidXQgZm91bmQgb3VyIHJlc3VsdHMgd2VyZSBpbnNlbnNpdGl2ZSB0byB0aGUKICBzdW1pbnQgPC0gc3VtKGludGVyc2VjdGlvbnMpCiAgbm9ybSA8LSAodG9wbiAqICh0b3BuICsgMSkpIC8yCiAgYXVjYyA8LSBzdW1pbnQgLyBub3JtCiAgcmV0dXJuKGF1Y2MpCn0KYGBgCgoKIyMjIFBlcmZvcm0gTFJUIHdpdGggdGhlIGNsaW5pY2FsIHNhbXBsZXMKCkkgYW0gbm90IHN1cmUgaWYgd2UgaGF2ZSBlbm91Z2ggc2FtcGxlcyBhY3Jvc3MgdGhlIHRocmVlIHZpc2l0IHRvCmNvbXBsZXRlbHkgd29yayBhcyB3ZWxsIGFzIHdlIHdvdWxkIGxpa2UsIGJ1dCB0aGVyZSBpcyBvbmx5IDEgd2F5IHRvCmZpbmQgb3V0ISAgTm93IHRoYXQgSSB0aGluayBhYm91dCBpdCwgb25lIHRoaW5nIHdoaWNoIG1pZ2h0IGJlIGF3ZXNvbWUKaXMgdG8gdXNlIGNlbGwgdHlwZSBhcyBhbiBpbnRlcmFjdGluZyBmYWN0b3IuLi4KCiMjIyMgV2l0aCBiaW9wc3kgc2FtcGxlcwoKSSBmaWd1cmUgdGhpcyBtaWdodCBiZSBhIHBsYWNlIHdoZXJlIHRoZSBiaW9wc3kgc2FtcGxlcyBtaWdodCBwcm92ZSB1c2VmdWwuCgpgYGB7ciBscnRfdGVzdH0KY2xpbmljYWxfbm9sb3N0IDwtIHN1YnNldF9leHB0KGhzX2NsaW5pY2FsLCBzdWJzZXQ9ImNvbmRpdGlvbiE9J2xvc3QnJmNvbmRpdGlvbiE9J25vdGFwcGxpY2FibGUnIikKCiMjIEN1cnJlbnRseSAoMjAyMTA5KSwgdGhpcyBpcyBub3QgcmV0dXJuaW5nIGFueSBzaWduaWZpY2FudCBoaXRzLgojIyBJbiBwcmV2aW91cyBpdGVyYXRpb25zIGl0IGRpZC4KbHJ0X3Zpc2l0X2NsaW5pY2FsX3Rlc3QgPC0gc20oZGVzZXFfbHJ0KGNsaW5pY2FsX25vbG9zdCwgdHJhbnNmb3JtPSJ2c3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rvcl9jb2x1bW49InZpc2l0bnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyZXN0X2NvbHVtbj0iY2xpbmljYWxvdXRjb21lIikpCnN1bW1hcnkobHJ0X3Zpc2l0X2NsaW5pY2FsX3Rlc3RbWyJkZXNlcV90YWJsZSJdXSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9YXMuZGF0YS5mcmFtZShscnRfdmlzaXRfY2xpbmljYWxfdGVzdFtbImRlc2VxX3RhYmxlIl1dKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2xydF9jbGluaWNhbF92aXNpdC12e3Zlcn0ueGxzeCIpKQoKbHJ0X2NlbGx0eXBlX2NsaW5pY2FsX3Rlc3QgPC0gc20oZGVzZXFfbHJ0KGNsaW5pY2FsX25vbG9zdCwgdHJhbnNmb3JtPSJ2c3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rvcl9jb2x1bW49InR5cGVvZmNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyZXN0X2NvbHVtbj0iY2xpbmljYWxvdXRjb21lIikpCnN1bW1hcnkobHJ0X2NlbGx0eXBlX2NsaW5pY2FsX3Rlc3RbWyJmYXZvcml0ZV9nZW5lcyJdXSkKZmF2b3JpdGVfbHJ0X2RmIDwtIG1lcmdlKGhzX2Fubm90LCBscnRfY2VsbHR5cGVfY2xpbmljYWxfdGVzdFtbImZhdm9yaXRlX2dlbmVzIl1dLCBhbGwueT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBieT0icm93Lm5hbWVzIikKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZmF2b3JpdGVfbHJ0X2RmLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbHJ0X2NsaW5pY2FsX2NlbGx0eXBlX2Zhdm9yaXRlcy12e3Zlcn0ueGxzeCIpKQpkZXNlcV9scnRfZGYgPC0gbWVyZ2UoaHNfYW5ub3QsIGFzLmRhdGEuZnJhbWUobHJ0X2NlbGx0eXBlX2NsaW5pY2FsX3Rlc3RbWyJkZXNlcV90YWJsZSJdXSksIGFsbC55PVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBieT0icm93Lm5hbWVzIikKcm93bmFtZXMoZGVzZXFfbHJ0X2RmKSA8LSBkZXNlcV9scnRfZGZbWyJSb3cubmFtZXMiXV0KZGVzZXFfbHJ0X2RmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZGVzZXFfbHJ0X2RmLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbHJ0X2NsaW5pY2FsX2NlbGx0eXBlLXZ7dmVyfS54bHN4IikpCmxydF9jZWxsdHlwZV9jbGluaWNhbF90ZXN0JGNsdXN0ZXJfZGF0YSRwbG90CgpjbHVzdGVyXzIzX2dlbmVzX2lkeCA8LSBscnRfY2VsbHR5cGVfY2xpbmljYWxfdGVzdFtbImNsdXN0ZXJfZGF0YSJdXVtbImRmIl1dW1siY2x1c3RlciJdXSA9PSAyMwpjbHVzdGVyXzIzX2dlbmVzIDwtIGxydF9jZWxsdHlwZV9jbGluaWNhbF90ZXN0W1siY2x1c3Rlcl9kYXRhIl1dW1siZGYiXV1bY2x1c3Rlcl8yM19nZW5lc19pZHgsIF0KY2x1c3Rlcl8yM19nZW5lcwoKY2x1c3Rlcl8yNF9nZW5lc19pZHggPC0gbHJ0X2NlbGx0eXBlX2NsaW5pY2FsX3Rlc3RbWyJjbHVzdGVyX2RhdGEiXV1bWyJkZiJdXVtbImNsdXN0ZXIiXV0gPT0gMjQKY2x1c3Rlcl8yNF9nZW5lcyA8LSBscnRfY2VsbHR5cGVfY2xpbmljYWxfdGVzdFtbImNsdXN0ZXJfZGF0YSJdXVtbImRmIl1dW2NsdXN0ZXJfMjRfZ2VuZXNfaWR4LCBdCmNsdXN0ZXJfMjRfZ2VuZXMKCmNsdXN0ZXJfMjJfZ2VuZXNfaWR4IDwtIGxydF9jZWxsdHlwZV9jbGluaWNhbF90ZXN0W1siY2x1c3Rlcl9kYXRhIl1dW1siZGYiXV1bWyJjbHVzdGVyIl1dID09IDIyCmNsdXN0ZXJfMjJfZ2VuZXMgPC0gbHJ0X2NlbGx0eXBlX2NsaW5pY2FsX3Rlc3RbWyJjbHVzdGVyX2RhdGEiXV1bWyJkZiJdXVtjbHVzdGVyXzIyX2dlbmVzX2lkeCwgXQpjbHVzdGVyXzIyX2dlbmVzCmBgYAoKIyMjIExvb2sgYXQgb25seSB0aGUgZGlmZmVyZW50aWFsIGdlbmVzCgpBIGdvb2Qgc3VnZ2VzdGlvbiBmcm9tIFRoZXJlc2Egd2FzIHRvIGV4YW1pbmUgb25seSB0aGUgbW9zdCB2YXJpYW50CmdlbmVzIGZyb20gZmFpbHVyZSB2cy4gY3VyZSBhbmQgc2VlIGhvdyB0aGV5IGNoYW5nZSB0aGUgY2x1c3RlcmluZy9ldGMKcmVzdWx0cy4gIFRoaXMgaXMgbXkgYXR0ZW1wdCB0byBhZGRyZXNzIHRoaXMgcXVlcnkuCgpgYGB7ciBzbWFsbF9leHBsb3JlfQpoc19jbGluaWNfdG9wbiA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGhzX2NsaW5pY190YWJsZSwgbj0xMDApKQp0YWJsZSA8LSAiZmFpbHVyZV92c19jdXJlIgp3YW50ZWQgPC0gcmJpbmQoaHNfY2xpbmljX3RvcG5bWyJkZXNlcSJdXVtbInVwcyJdXVtbdGFibGVdXSwKICAgICAgICAgICAgICAgIGhzX2NsaW5pY190b3BuW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbdGFibGVdXSkKCnNtYWxsX2V4cHQgPC0gZXhjbHVkZV9nZW5lc19leHB0KGhzX2NsaW5pY2FsX25vYmlvcCwgaWRzPXJvd25hbWVzKHdhbnRlZCksIG1ldGhvZD0ia2VlcCIpCnNtYWxsX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoc21hbGxfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKSkKcGxvdF9wY2Eoc21hbGxfbm9ybSkkcGxvdAoKc21hbGxfbmIgPC0gbm9ybWFsaXplX2V4cHQoc21hbGxfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpCnBsb3RfcGNhKHNtYWxsX25iKSRwbG90CmBgYAoKYGBge3IgY2xpbmljYWxfcGxvdH0KIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKaHNfY2xpbmljX3RhYmxlW1sicGxvdHMiXV1bWyJmYWlsdXJlX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmhzX2NsaW5pY190YWJsZVtbInBsb3RzIl1dW1siZmFpbHVyZV92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMgZzpQcm9maWxlciByZXN1bHRzIHVzaW5nIHRoZSBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcwoKYGBge3IgcGVyZm9ybV9ncHJvZmlsZXJ9CnVwcyA8LSBoc19jbGluaWNfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQpkb3ducyA8LSBoc19jbGluaWNfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dCgpoc19jbGluaWNfZ3Byb2ZpbGVyX3VwcyA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHVwcykKaHNfY2xpbmljX2dwcm9maWxlcl91cHNbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCmhzX2NsaW5pY19ncHJvZmlsZXJfdXBzW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpoc19jbGluaWNfZ3Byb2ZpbGVyX3Vwc1tbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQoKIyNoc190cnkyIDwtIHNpbXBsZV9ncHJvZmlsZXIyKHVwcykKCmhzX2NsaW5pY19ncHJvZmlsZXJfZG93bnMgPC0gc2ltcGxlX2dwcm9maWxlcihkb3ducykKaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KaHNfY2xpbmljX2dwcm9maWxlcl9kb3duc1tbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIFBlcmZvcm0gR1NWQSBvbiB0aGUgY2xpbmljYWwgc2FtcGxlcwoKYGBge3IgZ3N2YSwgZmlnLnNob3c9ImhpZGUifQpoc19jZWxsdHlwZV9nc3ZhX2MyIDwtIHNtKHNpbXBsZV9nc3ZhKGluZGl2aWR1YWxfY2VsbHR5cGVzKSkKaHNfY2VsbHR5cGVfZ3N2YV9jMl9zaWcgPC0gc20oZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICBoc19jZWxsdHlwZV9nc3ZhX2MyLAogICAgZXhjZWw9ImV4Y2VsL2luZGl2aWR1YWxfY2VsbHR5cGVzX2dzdmFfYzIueGxzeCIpKQoKIyMgYnJvYWRfYzcgPC0gR1NFQUJhc2U6OmdldEdtdCgicmVmZXJlbmNlL21zaWdkYi9jNy5hbGwudjcuMi5lbnRyZXouZ210IiwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0aW9uVHlwZT1HU0VBQmFzZTo6QnJvYWRDb2xsZWN0aW9uKGNhdGVnb3J5PSJjNyIpLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVJZFR5cGU9R1NFQUJhc2U6OkVudHJleklkZW50aWZpZXIoKSkKIyMgaHNfY2VsbHR5cGVfZ3N2YV9jNyA8LSBzbShzaW1wbGVfZ3N2YShpbmRpdmlkdWFsX2NlbGx0eXBlcywgc2lnbmF0dXJlcz1icm9hZF9jNywKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2lnX3htbD0icmVmZXJlbmNlL21zaWdkYl92Ny4yLnhtbCIsIGNvcmVzPTEwKSkKaHNfY2VsbHR5cGVfZ3N2YV9jNyA8LSBzaW1wbGVfZ3N2YShpbmRpdmlkdWFsX2NlbGx0eXBlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVzPSJyZWZlcmVuY2UvbXNpZ2RiL2M3LmFsbC52Ny4yLmVudHJlei5nbXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeT0iYzciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zaWdfeG1sPSJyZWZlcmVuY2UvbXNpZ2RiX3Y3LjIueG1sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3Jlcz0xMCkKCmhzX2NlbGx0eXBlX2dzdmFfYzdfc2lnIDwtIHNtKGdldF9zaWdfZ3N2YV9jYXRlZ29yaWVzKAogICAgaHNfY2VsbHR5cGVfZ3N2YV9jNywKICAgIGV4Y2VsPSJleGNlbC9pbmRpdmlkdWFsX2NlbGx0eXBlc19nc3ZhX2M3Lnhsc3giKSkKYGBgCgojIyMgUHJpbnQgc29tZSBwbG90cyBvZiB0aGUgR1NWQSBvdXRwdXRzCgpgYGB7ciBnc3ZhX3Bsb3RzfQojIyBUaGUgcmF3IGhlYXRtYXAgb2YgdGhlIEMyIHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInJhd19wbG90Il1dCiMjIFRoZSAnc2lnbmlmaWNhbmNlJyBzY29yZXMgb2YgdGhlIEMyIHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInNjb3JlX3Bsb3QiXV0KIyMgVGhlIHN1YnNldCBvZiBzY29yZXMgZm9yIGNhdGVnb3JpZXMgZGVlbWVkIHNpZ25pZmljYW50bHkgZGlmZmVyZW50Lgpoc19jZWxsdHlwZV9nc3ZhX2MyX3NpZ1tbInN1YnNldF9wbG90Il1dCgojIyBUaGUgcmF3IGhlYXRtYXAgb2YgdGhlIEM3IHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInJhd19wbG90Il1dCiMjIFRoZSAnc2lnbmlmaWNhbmNlJyBzY29yZXMgb2YgdGhlIEM3IHZhbHVlcwpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInNjb3JlX3Bsb3QiXV0KIyMgVGhlIHN1YnNldCBvZiBzY29yZXMgZm9yIGNhdGVnb3JpZXMgZGVlbWVkIHNpZ25pZmljYW50bHkgZGlmZmVyZW50Lgpoc19jZWxsdHlwZV9nc3ZhX2M3X3NpZ1tbInN1YnNldF9wbG90Il1dCmBgYAoKIyBTb21lIHF1ZXJpZXMgZnJvbSAyMDIxMDgxNgoKVXBvbiByZXR1cm5pbmcgZnJvbSBNYWluZSwgSSBzYXQgd2l0aCBOYWppYiwgVGhlcmVzYSwgYW5kIE1hcmlhCkFkZWxhaWRhLiAgQSB3aG9sZSBob3N0IG9mIHBvdGVudGlhbCBpZGVhcyB3ZXJlIGNvbnNpZGVyZWQ7IGhlcmUgYXJlIGEKY291cGxlIG9mIHRoZW06CgojIyBWaXN1YWxpemUgdmFyaWFuY2UgaW4gdGhlIFRNUkMzIGRhdGEKCk15IFRPRE8gdGV4dCBzYXlzOiAiVmFyaWFuY2UgcGFydGl0aW9uIG9mIFRNUkMzIHNhbXBsZXMgd2l0aCBhdCBsZWFzdAp0aW1lLCBjZWxsLXR5cGUsIGFuZCBjdXJlL2ZhaWwuICBJIG1peGVkIHRoaXMgaWRlYSB3aXRoIHRoZSB2aXNpdCAxIHByZXZpb3VzbHkuCgpgYGB7ciBjbGluaWNhbF92YXJwYXJ0fQp2cF9mYWN0b3JzIDwtIGMoImNvbmRpdGlvbiIsICJiYXRjaCIsICJ2aXNpdG51bWJlciIsICJlYl9sY191bGNlcmFfYXJlYV8xIikKCnYxX3ZwIDwtIHNpbXBsZV92YXJwYXJ0KGhzX2NsaW5pY2FsLCBmYWN0b3JzPXZwX2ZhY3RvcnMsIGRvX2ZpdD1UUlVFKQpwcChmaWxlPSJpbWFnZXMvdjFfdnAucG5nIiwgaW1hZ2U9djFfdnAkcGFydGl0aW9uX3Bsb3QpCmBgYAoKIyMgVmlzaXQgMSBjb21wYXJpc29ucwoKSGVyZSBpcyB0aGUgbm90ZSBmcm9tIG15IFRPRE8gbGlzdDogICJVc2luZyB2MSwgcGVyZm9ybSBjZWxsLXR5cGUKY29tcGFyaXNvbnMvc2lnbmF0dXJlcyBhcyB3ZWxsIGFzIGEgY3VyZS9mYWlsIGRpZmZlcmVudGlhbApleHByZXNzaW9uIi4KCkltcGxpY2l0IGluIHRoaXMgcXVlcnkgaXMgdGhlIGlkZWEgdGhhdCB3ZSBzaG91bGQgZG8gYW4gZXhwbGljaXQKdmlzdWFsaXphdGlvbiBvZiB0aGUgdmlzaXQgMSBzYW1wbGVzIHdpdGhvdXQgdGhlIHN1YnNlcXVlbnQgdmlzaXRzLgoKYGBge3IgdmlzaXQxX3N1YnNldH0KIyMgRm9yIHRoZSBtb21lbnQsIGxldCB1cyBpZ25vcmUgdGhlIGxvc3QvTkEgc2FtcGxlcwp2MV9leHB0IDwtIHN1YnNldF9leHB0KGhzX2NsaW5pY2FsLCBzdWJzZXQ9InZpc2l0bnVtYmVyPT0nMSciKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9ImNvbmRpdGlvbj09J2N1cmUnfGNvbmRpdGlvbj09J2ZhaWx1cmUnIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJiYXRjaCE9J2Jpb3BzeSciKQoKdjFfbm9ybSA8LSBub3JtYWxpemVfZXhwdCh2MV9leHB0LCBmaWx0ZXI9VFJVRSwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaD0ic3Zhc2VxIikKcGxvdF9wY2EodjFfbm9ybSkkcGxvdAoKdjFfZGUgPC0gYWxsX3BhaXJ3aXNlKHYxX2V4cHQsIGZpbHRlcj1UUlVFLCBtb2RlbF9iYXRjaD0ic3Zhc2VxIikKdjFfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXModjFfZGUsIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3YxX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBWaXNpdCAxIHZhcmlhbmNlIHBhcnRpdGlvbgoKSXQgbWlnaHQgYmUgaW50ZXJlc3RpbmcgdG8gYWRkICdwYXJhc2l0ZW1hcHBpbmdyYXRlJyBoZXJlIGJ1dCBJIGhhdmUKbm90IGZpbGxlZCBpdCBpbiBmb3IgYWxsIHNhbXBsZXMgeWV0LgoKc2FtcGxlY29sbGVjdGlvbmRhdGUgc2hvdWxkIGJlIHVzZWZ1bCB0b28gYnV0IGlzIG5vdCBjb21wbGV0ZS4KClRoaXMgaXMgYWxzbyBhIGdyZWF0IHBsYWNlIHRvIHB1bGwgaW4gc29tZSBvZiB0aGUgY2xpbmljYWwKaW5mb3JtYXRpb24uICBJIG5lZWQgdG8gYXNrIE1hcmlhIEFkZWxhaWRhIGZvciBpdC4uLgoKYGBge3IgdmlzaXQxX3ZwfQp2MV92cCA8LSBzaW1wbGVfdmFycGFydCh2MV9leHB0LCBkb19maXQ9VFJVRSkKdjFfdnAkcGFydGl0aW9uX3Bsb3QKIyMgY29uZGl0aW9uIGlzIGN1cmUvZmFpbCBiYXRjaCBpcyBjZWxsIHR5cGUuCmBgYAoKIyMjIFZpc2l0IDEgc2VwYXJhdGVkIGJ5IGNlbGwgdHlwZQoKYGBge3IgdmlzaXQxX2NlbGx0eXBlc30KdjFfZW8gPC0gc3Vic2V0X2V4cHQodjFfZXhwdCwgc3Vic2V0PSJiYXRjaD09J2Vvc2lub3BoaWxzJyIpCnYxX21vbm8gPC0gc3Vic2V0X2V4cHQodjFfZXhwdCwgc3Vic2V0PSJiYXRjaD09J21vbm9jeXRlcyciKQp2MV9uZXV0IDwtIHN1YnNldF9leHB0KHYxX2V4cHQsIHN1YnNldD0iYmF0Y2g9PSduZXV0cm9waGlscyciKQoKdjFfZW9fbm9ybSA8LSBub3JtYWxpemVfZXhwdCh2MV9lbywgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgbm9ybT0icXVhbnQiKQpwbG90X3BjYSh2MV9lb19ub3JtKSRwbG90CnYxX2VvX25iIDwtIG5vcm1hbGl6ZV9leHB0KHYxX2VvLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIpCnBsb3RfcGNhKHYxX2VvX25iKSRwbG90Cgp2MV9tb25vX25vcm0gPC0gbm9ybWFsaXplX2V4cHQodjFfbW9ubywgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIpCnBsb3RfcGNhKHYxX21vbm9fbm9ybSkkcGxvdAp2MV9tb25vX25iIDwtIG5vcm1hbGl6ZV9leHB0KHYxX21vbm8sIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJzdmFzZXEiKQpwbG90X3BjYSh2MV9tb25vX25iKSRwbG90Cgp2MV9uZXV0X25vcm0gPC0gbm9ybWFsaXplX2V4cHQodjFfbmV1dCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIpCnBsb3RfcGNhKHYxX25ldXRfbm9ybSkkcGxvdAp2MV9uZXV0X25iIDwtIG5vcm1hbGl6ZV9leHB0KHYxX25ldXQsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJzdmFzZXEiKQpwbG90X3BjYSh2MV9uZXV0X25iKSRwbG90CmBgYAoKIyBDb21wYXJlIHZpc2l0cwoKQ29tcGFyZSB2aXNpdHMgaW5kZXBlbmRlbnQgb2YgY3VyZS9mYWlsCgpgYGB7ciB2aXNpdHN9CnRpbWVfZXhwdCA8LSBoc19jbGluaWNhbCAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9InZpc2l0bnVtYmVyIikKcERhdGEodGltZV9leHB0KVtbImNvbmRpdGlvbiJdXSA8LSBwYXN0ZTAoInYiLCBwRGF0YSh0aW1lX2V4cHQpW1siY29uZGl0aW9uIl1dKQoKdGltZV9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHRpbWVfZXhwdCwgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnRpbWVfbmIgPC0gbm9ybWFsaXplX2V4cHQodGltZV9leHB0LCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKcGxvdF9wY2EodGltZV9uYikkcGxvdAoKdGltZV9kZSA8LSBhbGxfcGFpcndpc2UodGltZV9leHB0LCBmaWx0ZXI9VFJVRSwgbW9kZWxfYmF0Y2g9InN2YXNlcSIpCmtlZXBlcnMgPC0gbGlzdCgKICAgICJ2MnYxIj1jKCJ2MiIsICJ2MSIpLAogICAgInYzdjEiPWMoInYzIiwgInYxIiksCiAgICAidjN2MiI9YygidjMiLCAidjIiKSkKdGltZV90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXModGltZV9kZSwga2VlcGVycz1rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9jb21wYXJlX3Zpc2l0cy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIFNlcGFyYXRlIHZpc2l0cyBieSBjZWxsIHR5cGUKCk5vdyBsZXQgdXMgY29uc2lkZXIgdGhlIDMgdmlzaXRzIGZyb20gdGhlIGxlbnMgb2YgY2VsbCB0eXBlLgoKYGBge3IgdmlzaXRfY2VsbF90eXBlfQp0aW1lX3R5cGVfZmFjdG9yIDwtIHBhc3RlMChwRGF0YSh0aW1lX2V4cHQpW1siY29uZGl0aW9uIl1dLCAiXyIsIHBEYXRhKHRpbWVfZXhwdClbWyJiYXRjaCJdXSkKdGltZV90eXBlX2V4cHQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyh0aW1lX2V4cHQsIGZhY3Q9dGltZV90eXBlX2ZhY3RvcikKCnRpbWVfdHlwZV9iaW9wc3kgPC0gc3Vic2V0X2V4cHQodGltZV90eXBlX2V4cHQsIHN1YnNldD0iYmF0Y2g9PSdiaW9wc3knIikKdGltZV90eXBlX25ldXRyb3BoaWwgPC0gc3Vic2V0X2V4cHQodGltZV90eXBlX2V4cHQsIHN1YnNldD0iYmF0Y2g9PSduZXV0cm9waGlscyciKQp0aW1lX3R5cGVfZW9zaW5vcGhpbCA8LSBzdWJzZXRfZXhwdCh0aW1lX3R5cGVfZXhwdCwgc3Vic2V0PSJiYXRjaD09J2Vvc2lub3BoaWxzJyIpCnRpbWVfdHlwZV9tb25vY3l0ZSA8LSBzdWJzZXRfZXhwdCh0aW1lX3R5cGVfZXhwdCwgc3Vic2V0PSJiYXRjaD09J21vbm9jeXRlcyciKQpgYGAKCiMjIyBCaW9wc3kKCmBgYHtyIGJpb3BzeV90aW1lX3R5cGV9CnRpbWVfYmlvcHN5IDwtIG5vcm1hbGl6ZV9leHB0KHRpbWVfdHlwZV9iaW9wc3ksIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnRpbWVfYmlvcHN5X25iIDwtIG5vcm1hbGl6ZV9leHB0KHRpbWVfdHlwZV9iaW9wc3ksIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKcGxvdF9wY2EodGltZV9iaW9wc3kpJHBsb3QKcGxvdF9wY2EodGltZV9iaW9wc3lfbmIpJHBsb3QKdGltZV9iaW9wc3lfZGUgPC0gYWxsX3BhaXJ3aXNlKHRpbWVfdHlwZV9iaW9wc3ksIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKa2VlcGVycyA8LSBsaXN0KAogICAgInYydjEiPWMoInYyX2Jpb3BzeSIsICJ2MV9iaW9wc3kiKSwKICAgICJ2M3YxIj1jKCJ2M19iaW9wc3kiLCAidjFfYmlvcHN5IiksCiAgICAidjN2MiI9YygidjNfYmlvcHN5IiwgInYyX2Jpb3BzeSIpKQp0aW1lX2Jpb3BzeV90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0aW1lX2Jpb3BzeV9kZSwga2VlcGVycz1rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvdGltZV9iaW9wc3lfdGFibGVzLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIE5ldXRyb3BoaWxzCgpgYGB7ciBuZXV0cm9waGlsX3RpbWVfdHlwZX0KdGltZV9uZXV0cm9waGlsIDwtIG5vcm1hbGl6ZV9leHB0KHRpbWVfdHlwZV9uZXV0cm9waGlsLCBmaWx0ZXI9VFJVRSwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiKQp0aW1lX25ldXRyb3BoaWxfbmIgPC0gbm9ybWFsaXplX2V4cHQodGltZV90eXBlX25ldXRyb3BoaWwsIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKcGxvdF9wY2EodGltZV9uZXV0cm9waGlsKSRwbG90CnBsb3RfcGNhKHRpbWVfbmV1dHJvcGhpbF9uYikkcGxvdAp0aW1lX25ldXRyb3BoaWxfZGUgPC0gYWxsX3BhaXJ3aXNlKHRpbWVfdHlwZV9uZXV0cm9waGlsLCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCmtlZXBlcnMgPC0gbGlzdCgKICAgICJ2MnYxIj1jKCJ2Ml9uZXV0cm9waGlscyIsICJ2MV9uZXV0cm9waGlscyIpLAogICAgInYzdjEiPWMoInYzX25ldXRyb3BoaWxzIiwgInYxX25ldXRyb3BoaWxzIiksCiAgICAidjN2MiI9YygidjNfbmV1dHJvcGhpbHMiLCAidjJfbmV1dHJvcGhpbHMiKSkKdGltZV9uZXV0cm9waGlsX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIHRpbWVfbmV1dHJvcGhpbF9kZSwga2VlcGVycz1rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvdGltZV9uZXV0cm9waGlsX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBFb3Npbm9waGlscwoKYGBge3IgZW9zaW5vcGhpbF90aW1lX3R5cGV9CnRpbWVfZW9zaW5vcGhpbCA8LSBub3JtYWxpemVfZXhwdCh0aW1lX3R5cGVfZW9zaW5vcGhpbCwgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKdGltZV9lb3Npbm9waGlsX25iIDwtIG5vcm1hbGl6ZV9leHB0KHRpbWVfdHlwZV9lb3Npbm9waGlsLCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKHRpbWVfZW9zaW5vcGhpbCkkcGxvdApwbG90X3BjYSh0aW1lX2Vvc2lub3BoaWxfbmIpJHBsb3QKdGltZV9lb3Npbm9waGlsX2RlIDwtIGFsbF9wYWlyd2lzZSh0aW1lX3R5cGVfZW9zaW5vcGhpbCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQprZWVwZXJzIDwtIGxpc3QoCiAgICAidjJ2MSI9YygidjJfZW9zaW5vcGhpbHMiLCAidjFfZW9zaW5vcGhpbHMiKSwKICAgICJ2M3YxIj1jKCJ2M19lb3Npbm9waGlscyIsICJ2MV9lb3Npbm9waGlscyIpLAogICAgInYzdjIiPWMoInYzX2Vvc2lub3BoaWxzIiwgInYyX2Vvc2lub3BoaWxzIikpCnRpbWVfZW9zaW5vcGhpbF90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0aW1lX2Vvc2lub3BoaWxfZGUsIGtlZXBlcnM9a2VlcGVycywKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3RpbWVfZW9zaW5vcGhpbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMgTW9ub2N5dGUKCmBgYHtyIG1vbm9jeXRlX3RpbWVfdHlwZX0KdGltZV9tb25vY3l0ZSA8LSBub3JtYWxpemVfZXhwdCh0aW1lX3R5cGVfbW9ub2N5dGUsIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnRpbWVfbW9ub2N5dGVfbmIgPC0gbm9ybWFsaXplX2V4cHQodGltZV90eXBlX21vbm9jeXRlLCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKHRpbWVfbW9ub2N5dGUpJHBsb3QKcGxvdF9wY2EodGltZV9tb25vY3l0ZV9uYikkcGxvdAp0aW1lX21vbm9jeXRlX2RlIDwtIGFsbF9wYWlyd2lzZSh0aW1lX3R5cGVfbW9ub2N5dGUsIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKa2VlcGVycyA8LSBsaXN0KAogICAgInYydjEiPWMoInYyX21vbm9jeXRlcyIsICJ2MV9tb25vY3l0ZXMiKSwKICAgICJ2M3YxIj1jKCJ2M19tb25vY3l0ZXMiLCAidjFfbW9ub2N5dGVzIiksCiAgICAidjN2MiI9YygidjNfbW9ub2N5dGVzIiwgInYyX21vbm9jeXRlcyIpKQp0aW1lX21vbm9jeXRlX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIHRpbWVfbW9ub2N5dGVfZGUsIGtlZXBlcnM9a2VlcGVycywKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL3RpbWVfbW9ub2N5dGVfdGFibGVzLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMgVGltZSBhbmQgY2xpbmljYWxvdXRjb21lCgpgYGB7ciB0aW1lX2NsaW5pY2Fsb3V0Y29tZX0KdGltZV9jZl9mYWN0b3IgPC0gcGFzdGUwKHBEYXRhKHRpbWVfdHlwZV9iaW9wc3kpW1siY29uZGl0aW9uIl1dLCAiXyIsIHBEYXRhKHRpbWVfdHlwZV9iaW9wc3kpW1siY2xpbmljYWxvdXRjb21lIl1dKQpiaW9wc3lfdGltZV9jZiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKHRpbWVfdHlwZV9iaW9wc3ksIGZhY3Q9dGltZV9jZl9mYWN0b3IpCgp0aW1lX2NmX2Jpb3BzeSA8LSBub3JtYWxpemVfZXhwdChiaW9wc3lfdGltZV9jZiwgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKdGltZV9jZl9iaW9wc3lfbmIgPC0gbm9ybWFsaXplX2V4cHQoYmlvcHN5X3RpbWVfY2YsIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKcGxvdF9wY2EodGltZV9jZl9iaW9wc3kpJHBsb3QKcGxvdF9wY2EodGltZV9jZl9iaW9wc3lfbmIpJHBsb3QKCmJpb3BzeV90aW1lX2RlIDwtIGFsbF9wYWlyd2lzZSh0aW1lX3R5cGVfYmlvcHN5LCBmaWx0ZXI9VFJVRSwgbW9kZWxfYmF0Y2g9InN2YXNlcSIpCmJpb3BzeV90aW1lX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcyh0aW1lX3R5cGVfZGUsIGtlZXBlcnM9a2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2NvbXBhcmVfYmlvcHN5X3Zpc2l0cy12e3Zlcn0ueGxzeCIpKQoKYGBgCiMgSW5kaXZpZHVhbCBDZWxsIHR5cGVzCgpUaGUgZm9sbG93aW5nIGJsb2NrcyBzcGxpdCB0aGUgc2FtcGxlcyBpbnRvIGEgZmV3IGdyb3VwcyBieSBzYW1wbGUgdHlwZSBhbmQgbG9vawphdCB0aGUgZGlzdHJpYnV0aW9ucyBiZXR3ZWVuIHRoZW0uCgojIyBJbXBsZW1lbnRhdGlvbiBkZXRhaWxzCgpHZXQgdG9wL2JvdHRvbSBuIGdlbmVzIGZvciBlYWNoIGNlbGwgdHlwZSwgdXNpbmcgY2xpbmljYWwgb3V0Y29tZSBhcyB0aGUgZmFjdG9yIG9mIGludGVyZXN0LgpGb3IgdGhlIG1vbWVudCwgdXNlIHN2YSBmb3IgdGhlIERFIGFuYWx5c2lzLgpQcm92aWRlIGNwbXMgZm9yIHRoZSB0b3AvYm90dG9tIG4gZ2VuZXMuCgpTdGFydCB3aXRoIHRvcC9ib3R0b20gMjAwLgpQZXJmb3JtIGRlZmF1bHQgbG9nRkMgYW5kIHAtdmFsdWUgYXMgd2VsbC4KCiMjIyBTaGFyZWQgY29udHJhc3RzCgpIZXJlIGlzIHRoZSBjb250cmFzdCB3ZSB3aWxsIHVzZSB0aHJvdWdocHV0LCBJIGFtIGxlYXZpbmcgb3BlbiB0aGUgb3B0aW9uIHRvIGFkZCBtb3JlLgoKYGBge3Iga2VlcGVyc30Ka2VlcGVycyA8LSBsaXN0KAogICJmYWlsX3ZzX2N1cmUiPWMoImZhaWx1cmUiLCAiY3VyZSIpKQpgYGAKCiMjIE1vbm9jeXRlcwoKIyMjIEV2YWx1YXRlIE1vbm9jeXRlIHNhbXBsZXMKCmBgYHtyIG1vbm9jeXRlc30KbW9ubyA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0PSJ0eXBlb2ZjZWxscz09J21vbm9jeXRlcyciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9ImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdD0idmlzaXRudW1iZXIiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JzPWNob3Nlbl9jb2xvcnMpCiMjIEZJWE1FIHNldF9leHB0X2NvbG9ycyBzaG91bGQgc3BlYWsgdXAgaWYgdGhlcmUgYXJlIG1pc21hdGNoZXMgaGVyZSEhIQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShtb25vLCBmaWxlPSJyZGEvbW9ub2N5dGVfZXhwdC5yZGEiKQptb25vX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW9ubywgY29udmVydD0iY3BtIiwgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiLCBub3JtPSJxdWFudCIpCnBsdCA8LSBwbG90X3BjYShtb25vX25vcm0sIHBsb3RfbGFiZWxzPUZBTFNFKSRwbG90CnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL21vbm9fcGNhX25vcm1hbGl6ZWQtdnt2ZXJ9LnBkZiIpLCBpbWFnZT1wbHQpCgptb25vX25iIDwtIG5vcm1hbGl6ZV9leHB0KG1vbm8sIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJzdmFzZXEiKQpwbHQgPC0gcGxvdF9wY2EobW9ub19uYiwgcGxvdF9sYWJlbHM9RkFMU0UpJHBsb3QKcHAoZmlsZT1nbHVlKCJpbWFnZXMvbW9ub19wY2Ffbm9ybWFsaXplZF9iYXRjaC12e3Zlcn0ucGRmIiksIGltYWdlPXBsdCkKYGBgCgojIyMgREUgb2YgTW9ub2N5dGUgc2FtcGxlcwoKIyMjIyBXaXRob3V0IHN2YQoKYGBge3IgZGVfbW9ub2N5dGUsIGZpZy5zaG93PSJoaWRlIn0KbW9ub19kZSA8LSBzbShhbGxfcGFpcndpc2UobW9ubywgbW9kZWxfYmF0Y2g9RkFMU0UsIGZpbHRlcj1UUlVFKSkKbW9ub190YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBtb25vX2RlLCBrZWVwZXJzPWtlZXBlcnMsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJ1cGxvYWQvREVfQ3VyZV92c19GYWlsL3t2ZXJ9X21vbm9fdmFsbF9kZV9jdXJldnNmYWlsX25vYmF0Y2gueGxzeCIpKSkKCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPW1vbm9fdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfdGFibGUtdnt2ZXJ9Lnhsc3giKSkKbW9ub19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhtb25vX3RhYmxlcywgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1tb25vX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jbGluaWNhbF9zaWd1cC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1tb25vX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKCm1vbm9fcGN0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1vbm9fdGFibGVzLCBuPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGZjPU5VTEwsIHA9TlVMTCwgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1tb25vX3BjdF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY2xpbmljYWxfc2lndXBfcGN0LXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPW1vbm9fcGN0X3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ2Rvd25fcGN0LXZ7dmVyfS54bHN4IikpCm1vbm9fc2lnJHN1bW1hcnlfZGYKCiMjIFByaW50IG91dCBhIHRhYmxlIG9mIHRoZSBjcG0gdmFsdWVzIGZvciBvdGhlciBleHBsb3JhdGlvbnMuCm1vbm9fY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1vbm8sIGNvbnZlcnQ9ImNwbSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1leHBycyhtb25vX2NwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9tb25vY3l0ZV9jcG1fYmVmb3JlX2JhdGNoLXZ7dmVyfS54bHN4IikpCm1vbm9fYmNwbSA8LSBzbShub3JtYWxpemVfZXhwdChtb25vLCBmaWx0ZXI9VFJVRSwgY29udmVydD0iY3BtIiwgYmF0Y2g9InN2YXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1leHBycyhtb25vX2JjcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbW9ub2N5dGVfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBXaXRoIHN2YQoKYGBge3IgZGVfbW9ub19zdmEsIGZpZy5zaG93PSJoaWRlIn0KbW9ub19kZV9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKG1vbm8sIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkpCm1vbm9fc3ZhX3RhYmxlcyA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIG1vbm9fZGVfc3ZhLCBrZWVwZXJzPWtlZXBlcnMsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJ1cGxvYWQvREVfQ3VyZV92c19GYWlsL3t2ZXJ9X21vbm9fdmFsbF9kZV9jdXJldnNmYWlsX3N2YWJhdGNoLnhsc3giKSkpCgptb25vX3NpZ19zdmEgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIG1vbm9fdGFibGVzX3N2YSwKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21vbm9jeXRlX2NsaW5pY2FsX3NpZ190YWJsZXNfc3ZhLXZ7dmVyfS54bHN4IiksCiAgICBhY2NvcmRpbmdfdG89ImRlc2VxIikpCmBgYAoKIyMjIyBNb25vY3l0ZSBERSBwbG90cwoKRmlyc3QgcHJpbnQgb3V0IHRoZSBERSBwbG90cyB3aXRob3V0IGFuZCB0aGVuIHdpdGggc3ZhIGVzdGltYXRlcy4KCmBgYHtyIG1vbm9fZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm1vbm9fdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm1vbm9fdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmFzZXEKbW9ub190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3Zhc2VxCm1vbm9fdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMjIE1vbm9jeXRlIG9udG9sb2d5IHNlYXJjaAoKYGBge3IgbW9ub19ncHJvZmlsZXJ9CnVwcyA8LSBtb25vX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dCmRvd25zIDwtIG1vbm9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXQoKbW9ub191cF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNpZ19nZW5lcz11cHMpCm1vbm9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCm1vbm9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm1vbm9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KCm1vbm9fZG93bl9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNpZ19nZW5lcz1kb3ducykKbW9ub19kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQptb25vX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm1vbm9fZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyMgTW9ub2N5dGUgTVNpZ0RCIHF1ZXJ5CgpgYGB7ciBtc2lnX21vbm9fZ29zZXEsIGZpZy5zaG93PSJoaWRlIn0KIyMgYnJvYWRfYzcgPC0gR1NFQUJhc2U6OmdldEdtdCgicmVmZXJlbmNlL21zaWdkYi9jNy5hbGwudjcuMi5lbnRyZXouZ210IiwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0aW9uVHlwZT1HU0VBQmFzZTo6QnJvYWRDb2xsZWN0aW9uKGNhdGVnb3J5PSJjNyIpLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVJZFR5cGU9R1NFQUJhc2U6OkVudHJleklkZW50aWZpZXIoKSkKYnJvYWRfYzcgPC0gbG9hZF9nbXRfc2lnbmF0dXJlcyhzaWduYXR1cmVzPSJyZWZlcmVuY2UvbXNpZ2RiL2M3LmFsbC52Ny4yLmVudHJlei5nbXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeT0iYzciKQptb25vX3VwX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcz11cHMsIHNpZ25hdHVyZXM9YnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5PSJjNyIsIGxlbmd0aF9kYj1oc19sZW5ndGgpCm1vbm9fZG93bl9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXM9ZG93bnMsIHNpZ25hdHVyZXM9YnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVfY2F0ZWdvcnk9ImM3IiwgbGVuZ3RoX2RiPWhzX2xlbmd0aCkKYGBgCgojIyMjIFBsb3Qgb2Ygc2ltaWxhciBleHBlcmltZW50cwoKYGBge3IgbXNpZ19wbG90c30KIyMgTW9ub2N5dGUgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm1vbm9fdXBfZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCiMjIE1vbm9jeXRlIGdlbmVzIHdpdGggaW5jcmVhc2VkIGV4cHJlc3Npb24gaW4gdGhlIGN1cmVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm1vbm9fZG93bl9nb3NlcV9tc2lnW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyBFdmFsdWF0ZSBOZXV0cm9waGlsIHNhbXBsZXMKCmBgYHtyIG5ldXRyb3BoaWxzfQpuZXV0IDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQ9InR5cGVvZmNlbGxzPT0nbmV1dHJvcGhpbHMnIikgJT4lCiAgc2V0X2V4cHRfY29uZGl0aW9ucyhmYWN0PSJjbGluaWNhbG91dGNvbWUiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9InZpc2l0bnVtYmVyIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9ycz1jaG9zZW5fY29sb3JzKQoKc2F2ZV9yZXN1bHQgPC0gc2F2ZShuZXV0LCBmaWxlPSJyZGEvbmV1dHJvcGhpbF9leHB0LnJkYSIpCgpuZXV0X25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgY29udmVydD0iY3BtIiwgZmlsdGVyPVRSVUUsIHRyYW5zZm9ybT0ibG9nMiIpKQpwbHQgPC0gcGxvdF9wY2EobmV1dF9ub3JtLCBwbG90X2xhYmVscz1GQUxTRSkkcGxvdApwcChmaWxlPWdsdWUoImltYWdlcy9uZXV0X3BjYV9ub3JtYWxpemVkLXZ7dmVyfS5wZGYiKSwgaW1hZ2U9cGx0KQoKbmV1dF9uYiA8LSBzbShub3JtYWxpemVfZXhwdChuZXV0LCBjb252ZXJ0PSJjcG0iLCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiLCBiYXRjaD0ic3Zhc2VxIikpCnBsdCA8LSBwbG90X3BjYShuZXV0X25iLCBwbG90X2xhYmVscz1GQUxTRSkkcGxvdApwcChmaWxlPWdsdWUoImltYWdlcy9uZXV0X3BjYV9ub3JtYWxpemVkX3N2YXNlcS12e3Zlcn0ucGRmIiksIGltYWdlPXBsdCkKYGBgCgojIyMgREUgb2YgTmV0cm9waGlsIHNhbXBsZXMKCiMjIyMgV2l0aG91dCBzdmEKCmBgYHtyIG5ldXRyb3BoaWxfZGUsIGZpZy5zaG93PSJoaWRlIn0KbmV1dF9kZSA8LSBzbShhbGxfcGFpcndpc2UobmV1dCwgbW9kZWxfYmF0Y2g9RkFMU0UsIGZpbHRlcj1UUlVFKSkKbmV1dF90YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBuZXV0X2RlLCBrZWVwZXJzPWtlZXBlcnMsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJ1cGxvYWQvREVfQ3VyZV92c19GYWlsL3t2ZXJ9X25ldXRfdmFsbF9kZV9jdXJldnNmYWlsX25vYmF0Y2gueGxzeCIpKSkKCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPW5ldXRfdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvbmV1dHJvcGhpbF9jbGluaWNhbF90YWJsZS12e3Zlcn0ueGxzeCIpKQpuZXV0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG5ldXRfdGFibGVzLCBhY2NvcmRpbmdfdG89ImRlc2VxIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPW5ldXRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lndXAtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9bmV1dF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKCm5ldXRfcGN0X3NpZyA8LSBzbShleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG5ldXRfdGFibGVzLCBuPTIwMCwgbGZjPU5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHA9TlVMTCwgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1uZXV0X3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9uZXV0cm9waGlsX2NsaW5pY2FsX3NpZ3VwX3BjdC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1uZXV0X3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lnZG93bl9wY3Qtdnt2ZXJ9Lnhsc3giKSkKbmV1dF9jcG0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgY29udmVydD0iY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPWV4cHJzKG5ldXRfY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY3BtX2JlZm9yZV9iYXRjaC12e3Zlcn0ueGxzeCIpKQpuZXV0X2JjcG0gPC0gc20obm9ybWFsaXplX2V4cHQobmV1dCwgZmlsdGVyPVRSVUUsIGJhdGNoPSJzdmFzZXEiLCBjb252ZXJ0PSJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZXhwcnMobmV1dF9iY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBXaXRoIHN2YQoKYGBge3IgZGVfbmV1dF9zdmEsIGZpZy5zaG93PSJoaWRlIn0KbmV1dF9kZV9zdmEgPC0gc20oYWxsX3BhaXJ3aXNlKG5ldXQsIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkpCm5ldXRfdGFibGVzX3N2YSA8LSBzbShjb21iaW5lX2RlX3RhYmxlcygKICAgIG5ldXRfZGVfc3ZhLCBrZWVwZXJzPWtlZXBlcnMsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJ1cGxvYWQvREVfQ3VyZV92c19GYWlsL3t2ZXJ9X25ldXRfdmFsbF9kZV9jdXJldnNmYWlsX3N2YWJhdGNoLnhsc3giKSkpCgpuZXV0X3NpZ19zdmEgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIG5ldXRfdGFibGVzX3N2YSwKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL25ldXRyb3BoaWxfY2xpbmljYWxfc2lnX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSwKICAgIGFjY29yZGluZ190bz0iZGVzZXEiKSkKYGBgCgojIyMjIE5ldXRyb3BoaWwgREUgcGxvdHMKCmBgYHtyIG5ldXRfZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm5ldXRfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCm5ldXRfdGFibGVzW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUgd2l0aCBzdmEKbmV1dF90YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3ZhCm5ldXRfdGFibGVzX3N2YVtbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfdm9sX3Bsb3RzIl1dJHBsb3QKYGBgCgojIyMjIE5ldXRyb3BoaWwgb250b2xvZ3kgc2VhcmNoCgpgYGB7ciBuZXV0X2dwfQp1cHMgPC0gbmV1dF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImZhaWxfdnNfY3VyZSJdXQpkb3ducyA8LSBuZXV0X3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KCm5ldXRfdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9dXBzKQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sibWZwX3Bsb3Rfb3ZlciJdXQpuZXV0X3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCgpuZXV0X2Rvd25fZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihkb3ducykKbmV1dF9kb3duX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siYnBwX3Bsb3Rfb3ZlciJdXQpuZXV0X2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCm5ldXRfZG93bl9ncFtbInB2YWx1ZV9wbG90cyJdXVtbInJlYWN0b21lX3Bsb3Rfb3ZlciJdXQpgYGAKCiMjIyMgTmV1dHJvcGhpbCBHU1ZBIHF1ZXJ5CgpgYGB7ciBtc2lnX25ldXRfZ29zZXEsIGZpZy5zaG93PSJoaWRlIn0KbmV1dF91cF9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXM9dXBzLCBzaWduYXR1cmVzPWJyb2FkX2M3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeT0iYzciLCBsZW5ndGhfZGI9aHNfbGVuZ3RoKQoKbmV1dF9kb3duX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcz1kb3ducywgc2lnbmF0dXJlcz1icm9hZF9jNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeT0iYzciLCBsZW5ndGhfZGI9aHNfbGVuZ3RoKQpgYGAKCiMjIyMgUGxvdCBvZiBzaW1pbGFyIGV4cGVyaW1lbnRzCgpgYGB7ciBtc2lnX3Bsb3RzX25ldXR9CiMjIE5ldXRyb3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCm5ldXRfdXBfZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KCiMjIE5ldXRyb3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgY3VyZWQgc2FtcGxlcwojIyBzaGFyZSBnZW5lcyB3aXRoIHRoZSBmb2xsb3dpbmcgZXhwZXJpbWVudHMKbmV1dF9kb3duX2dvc2VxX21zaWdbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmBgYAoKIyMgRW9zaW5vcGhpbHMKCiMjIyBFdmFsdWF0ZSBFb3Npbm9waGlsIHNhbXBsZXMKCmBgYHtyIGVvc2lub3BoaWxzfQplbyA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0PSJ0eXBlb2ZjZWxscz09J2Vvc2lub3BoaWxzJyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdD0iY2xpbmljYWxvdXRjb21lIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0PSJ2aXNpdG51bWJlciIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnM9Y2hvc2VuX2NvbG9ycykKCnNhdmVfcmVzdWx0IDwtIHNhdmUoZW8sIGZpbGU9InJkYS9lb3Npbm9waGlsX2V4cHQucmRhIikKZW9fbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChlbywgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudCIsIGZpbHRlcj1UUlVFKSkKcGx0IDwtIHBsb3RfcGNhKGVvX25vcm0sIHBsb3RfbGFiZWxzPUZBTFNFKSRwbG90CnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL2VvX3BjYV9ub3JtYWxpemVkLXZ7dmVyfS5wZGYiKSwgaW1hZ2U9cGx0KQoKZW9fbmIgPC0gc20obm9ybWFsaXplX2V4cHQoZW8sIGNvbnZlcnQ9ImNwbSIsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIikpCnBsdCA8LSBwbG90X3BjYShlb19uYiwgcGxvdF9sYWJlbHM9RkFMU0UpJHBsb3QKcGx0CmBgYAoKIyMjIERFIG9mIEVvc2lub3BoaWwgc2FtcGxlcwoKIyMjIyBXaXRob3V0aCBzdmEKCmBgYHtyIGVvc2lub3BoaWxfZGUsIGZpZy5zaG93PSJoaWRlIn0KZW9fZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGVvLCBtb2RlbF9iYXRjaD1GQUxTRSwgZmlsdGVyPVRSVUUpKQplb190YWJsZXMgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBlb19kZSwga2VlcGVycz1rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgidXBsb2FkL0RFX0N1cmVfdnNfRmFpbC97dmVyfV9lb192YWxsX2RlX2N1cmV2c2ZhaWxfbm9iYXRjaC54bHN4IikpKQoKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZW9fdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF90YWJsZS12e3Zlcn0ueGxzeCIpKQplb19zaWcgPC0gc20oZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhlb190YWJsZXMsIGFjY29yZGluZ190bz0iZGVzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZW9fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY2xpbmljYWxfc2lndXAtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZW9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWdkb3duLXZ7dmVyfS54bHN4IikpCgplb19wY3Rfc2lnIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoZW9fdGFibGVzLCBuPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxmYz1OVUxMLCBwPU5VTEwsIGFjY29yZGluZ190bz0iZGVzZXEiKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZW9fcGN0X3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9lb3Npbm9waGlsX2NsaW5pY2FsX3NpZ3VwX3BjdC12e3Zlcn0ueGxzeCIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1lb19wY3Rfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWdkb3duX3BjdC12e3Zlcn0ueGxzeCIpKQoKZW9fY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGVvLCBjb252ZXJ0PSJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZXhwcnMoZW9fY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY3BtX2JlZm9yZV9iYXRjaC12e3Zlcn0ueGxzeCIpKQplb19iY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGVvLCBmaWx0ZXI9VFJVRSwgYmF0Y2g9InN2YXNlcSIsIGNvbnZlcnQ9ImNwbSIpKQp3cml0dGVuIDwtIHdyaXRlX3hsc3goZGF0YT1leHBycyhlb19iY3BtKSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2Vvc2lub3BoaWxfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBXaXRoIHN2YQoKYGBge3IgZGVfZW9fc3ZhLCBmaWcuc2hvdz0iaGlkZSJ9CmVvX2RlX3N2YSA8LSBzbShhbGxfcGFpcndpc2UoZW8sIG1vZGVsX2JhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkpCmVvX3RhYmxlc19zdmEgPC0gc20oY29tYmluZV9kZV90YWJsZXMoCiAgICBlb19kZV9zdmEsIGtlZXBlcnM9a2VlcGVycywKICAgIGV4Y2VsPWdsdWU6OmdsdWUoInVwbG9hZC9ERV9DdXJlX3ZzX0ZhaWwve3Zlcn1fZW9fdmFsbF9kZV9jdXJldnNmYWlsX3N2YWJhdGNoLnhsc3giKSkpCgplb19zaWdfc3ZhIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBlb190YWJsZXNfc3ZhLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvZW9zaW5vcGhpbF9jbGluaWNhbF9zaWdfdGFibGVzX3N2YS12e3Zlcn0ueGxzeCIpLAogICAgYWNjb3JkaW5nX3RvPSJkZXNlcSIpKQpgYGAKCiMjIyMgRW9zaW5vcGhpbCBERSBwbG90cwoKYGBge3IgZW9fZGVfcGxvdHN9CiMjIERFU2VxMiBNQSBwbG90IG9mIGZhaWx1cmUgLyBjdXJlCmVvX3RhYmxlc1tbInBsb3RzIl1dW1siZmFpbF92c19jdXJlIl1dW1siZGVzZXFfbWFfcGxvdHMiXV0kcGxvdAoKIyMgREVTZXEyIFZvbGNhbm8gcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQplb190YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZSB3aXRoIHN2YQplb190YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV9tYV9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgVm9sY2FubyBwbG90IG9mIGZhaWx1cmUgLyBjdXJlIHdpdGggc3ZhCmVvX3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CmBgYAoKIyMjIyBFb3Npbm9waGlsIG9udG9sb2d5IHNlYXJjaAoKYGBge3IgZW9fZ3Byb2ZpbGVyfQp1cHMgPC0gZW9fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0KZG93bnMgPC0gZW9fc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXQoKZW9fdXBfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihzaWdfZ2VuZXM9dXBzKQplb191cF9ncFtbInB2YWx1ZV9wbG90cyJdXVtbImJwcF9wbG90X292ZXIiXV0KZW9fdXBfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmVvX3VwX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1sicmVhY3RvbWVfcGxvdF9vdmVyIl1dCgplb19kb3duX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoZG93bnMpCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJicHBfcGxvdF9vdmVyIl1dCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCmVvX2Rvd25fZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJyZWFjdG9tZV9wbG90X292ZXIiXV0KYGBgCgojIyMjIEVvc2lub3BoaWwgTVNpZ0RCIHF1ZXJ5CgpgYGB7ciBtc2lnX2VvX2dvc2VxLCBmaWcuc2hvdz0iaGlkZSJ9CmVvX3VwX2dvc2VxX21zaWcgPC0gZ29zZXFfbXNpZ2RiKHNpZ19nZW5lcz11cHMsIHNpZ25hdHVyZXM9YnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeT0iYzciLCBsZW5ndGhfZGI9aHNfbGVuZ3RoKQoKZW9fZG93bl9nb3NlcV9tc2lnIDwtIGdvc2VxX21zaWdkYihzaWdfZ2VuZXM9ZG93bnMsIHNpZ25hdHVyZXM9YnJvYWRfYzcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlX2NhdGVnb3J5PSJjNyIsIGxlbmd0aF9kYj1oc19sZW5ndGgpCmBgYAoKIyMjIyBQbG90IG9mIHNpbWlsYXIgZXhwZXJpbWVudHMKCmBgYHtyIG1zaWdfcGxvdHNfZW99CiMjIEVvc2lub3BoaWwgZ2VuZXMgd2l0aCBpbmNyZWFzZWQgZXhwcmVzc2lvbiBpbiB0aGUgZmFpbGVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCmVvX3VwX2dvc2VxX21zaWdbWyJwdmFsdWVfcGxvdHMiXV1bWyJtZnBfcGxvdF9vdmVyIl1dCgojIyBFb3Npbm9waGlsIGdlbmVzIHdpdGggaW5jcmVhc2VkIGV4cHJlc3Npb24gaW4gdGhlIGN1cmVkIHNhbXBsZXMKIyMgc2hhcmUgZ2VuZXMgd2l0aCB0aGUgZm9sbG93aW5nIGV4cGVyaW1lbnRzCmVvX2Rvd25fZ29zZXFfbXNpZ1tbInB2YWx1ZV9wbG90cyJdXVtbIm1mcF9wbG90X292ZXIiXV0KYGBgCgojIyBCaW9wc2llcwoKIyMjIEV2YWx1YXRlIEJpb3BzeSBzYW1wbGVzCgpgYGB7ciBiaW9wc2llc30KYmlvcCA8LSBzdWJzZXRfZXhwdChoc192YWxpZCwgc3Vic2V0PSJ0eXBlb2ZjZWxscz09J2Jpb3BzeSciKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3Q9ImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdD0idmlzaXRudW1iZXIiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JzPWNob3Nlbl9jb2xvcnMpCgpzYXZlX3Jlc3VsdCA8LSBzYXZlKGJpb3AsIGZpbGU9InJkYS9iaW9wc3lfZXhwdC5yZGEiKQpiaW9wX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoYmlvcCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiLCBub3JtPSJxdWFudCIpCnBsdCA8LSBwbG90X3BjYShiaW9wX25vcm0sIHBsb3RfbGFiZWxzPUZBTFNFKSRwbG90CnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL2Jpb3BfcGNhX25vcm1hbGl6ZWQtdnt2ZXJ9LnBkZiIpLCBpbWFnZT1wbHQpCgpiaW9wX25iIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGJpb3AsIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJzdmFzZXEiKSkKcGx0IDwtIHBsb3RfcGNhKGJpb3BfbmIsIHBsb3RfbGFiZWxzPUZBTFNFKSRwbG90CnBwKGZpbGU9Z2x1ZSgiaW1hZ2VzL2Jpb3BfcGNhX25vcm1hbGl6ZWRfc3Zhc2VxLXZ7dmVyfS5wZGYiKSwgaW1hZ2U9cGx0KQpgYGAKCiMjIyBERSBvZiBCaW9wc3kgc2FtcGxlcwoKIyMjIyBXaXRob3V0IHN2YQoKYGBge3IgZGVfYmlvcHN5LCBmaWcuc2hvdz0iaGlkZSJ9CmJpb3BfZGUgPC0gc20oYWxsX3BhaXJ3aXNlKGJpb3AsIG1vZGVsX2JhdGNoPUZBTFNFLCBmaWx0ZXI9VFJVRSkpCmJpb3BfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgYmlvcF9kZSwga2VlcGVycz1rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgidXBsb2FkL0RFX0N1cmVfdnNfRmFpbC97dmVyfV9iaW9wc3lfdmFsbF9kZV9jdXJldnNmYWlsX25vYmF0Y2gueGxzeCIpKSkKCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPWJpb3BfdGFibGVzW1siZGF0YSJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3RhYmxlLXZ7dmVyfS54bHN4IikpCmJpb3Bfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoYmlvcF90YWJsZXMsIGFjY29yZGluZ190bz0iZGVzZXEiKQojI3dyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPWJpb3Bfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKIyMgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3NpZ3VwLXZ7dmVyfS54bHN4IikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPWJpb3Bfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3NpZ2Rvd24tdnt2ZXJ9Lnhsc3giKSkKYmlvcF9wY3Rfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoYmlvcF90YWJsZXMsIG49MjAwLCBsZmM9TlVMTCwgcD1OVUxMLCBhY2NvcmRpbmdfdG89ImRlc2VxIikKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9YmlvcF9wY3Rfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL2Jpb3BzeV9jbGluaWNhbF9zaWd1cF9wY3Qtdnt2ZXJ9Lnhsc3giKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9YmlvcF9wY3Rfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NsaW5pY2FsX3NpZ2Rvd25fcGN0LXZ7dmVyfS54bHN4IikpCgpiaW9wX2NwbSA8LSBzbShub3JtYWxpemVfZXhwdChiaW9wLCBjb252ZXJ0PSJjcG0iKSkKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9ZXhwcnMoYmlvcF9jcG0pLAogICAgICAgICAgICAgICAgICAgICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiZXhjZWwvYmlvcHN5X2NwbV9iZWZvcmVfYmF0Y2gtdnt2ZXJ9Lnhsc3giKSkKYmlvcF9iY3BtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGJpb3AsIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIiwgY29udmVydD0iY3BtIikpCndyaXR0ZW4gPC0gd3JpdGVfeGxzeChkYXRhPWV4cHJzKGJpb3BfYmNwbSksCiAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY3BtX2FmdGVyX2JhdGNoLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyB3aXRoIHN2YQoKYGBge3IgZGVfYmlvcHN5X3N2YSwgZmlnLnNob3c9ImhpZGUifQpiaW9wX2RlX3N2YSA8LSBzbShhbGxfcGFpcndpc2UoYmlvcCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKSkKYmlvcF90YWJsZXNfc3ZhIDwtIHNtKGNvbWJpbmVfZGVfdGFibGVzKAogICAgYmlvcF9kZV9zdmEsIGtlZXBlcnM9a2VlcGVycywKICAgIGV4Y2VsPWdsdWU6OmdsdWUoInVwbG9hZC9ERV9DdXJlX3ZzX0ZhaWwve3Zlcn1fYmlvcHN5X3ZhbGxfZGVfY3VyZXZzZmFpbF9zdmFiYXRjaC54bHN4IikpKQoKYmlvcF9zaWdfc3ZhIDwtIHNtKGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBiaW9wX3RhYmxlc19zdmEsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9iaW9wc3lfY2xpbmljYWxfc2lnX3RhYmxlc19zdmEtdnt2ZXJ9Lnhsc3giKSwKICAgIGFjY29yZGluZ190bz0iZGVzZXEiKSkKYGBgCgojIyMjIEJpb3BzeSBERSBwbG90cwoKYGBge3IgYmlvcF9kZV9wbG90c30KIyMgREVTZXEyIE1BIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKYmlvcF90YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX21hX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBWb2xjYW5vIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKYmlvcF90YWJsZXNbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX3ZvbF9wbG90cyJdXSRwbG90CgojIyBERVNlcTIgTUEgcGxvdCBvZiBmYWlsdXJlIC8gY3VyZQpiaW9wX3RhYmxlc19zdmFbWyJwbG90cyJdXVtbImZhaWxfdnNfY3VyZSJdXVtbImRlc2VxX21hX3Bsb3RzIl1dJHBsb3QKCiMjIERFU2VxMiBWb2xjYW5vIHBsb3Qgb2YgZmFpbHVyZSAvIGN1cmUKYmlvcF90YWJsZXNfc3ZhW1sicGxvdHMiXV1bWyJmYWlsX3ZzX2N1cmUiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV0kcGxvdApgYGAKCiMgTG9vayBmb3Igc2hhcmVkIGdlbmVzIGFtb25nIE1vbm9jeXRlcy9OZXV0cm9waGlscy9Fb3Npbm9waGlscwoKV2UgaGF2ZSB0aHJlZSB2YXJpYWJsZXMgY29udGFpbmluZyB0aGUgJ3NpZ25pZmljYW50JyBERSBnZW5lcyBmb3IgdGhlCnRocmVlIGNlbGwgdHlwZXMuICBGb3IgdGhpcyBJIGFtIGNob29zaW5nIChmb3IgdGhlIG1vbWVudCkgdG8gdXNlIHRoZQpzdmEgZGF0YS4KCmBgYHtyIHNoYXJlZF9ieV90eXBlfQojIyBtb25vX3NpZ19zdmEsIG5ldXRfc2lnX3N2YSwgZW9fc2lnX3N2YQpzaWdfdmVjdG9ycyA8LSBsaXN0KAogICAgIm1vbm9jeXRlcyI9Yyhyb3duYW1lcyhtb25vX3NpZ19zdmFbWyJkZXNlcSJdXVtbInVwcyJdXVtbImZhaWxfdnNfY3VyZSJdXSksCiAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMobW9ub19zaWdfc3ZhW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXSkpLAogICAgIm5ldXRyb3BoaWxzIj1jKHJvd25hbWVzKG5ldXRfc2lnX3N2YVtbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dKSwKICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKG5ldXRfc2lnX3N2YVtbImRlc2VxIl1dW1siZG93bnMiXV1bWyJmYWlsX3ZzX2N1cmUiXV0pKSwKICAgICJlb3Npbm9waGlscyI9IGMocm93bmFtZXMoZW9fc2lnX3N2YVtbImRlc2VxIl1dW1sidXBzIl1dW1siZmFpbF92c19jdXJlIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhlb19zaWdfc3ZhW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbImZhaWxfdnNfY3VyZSJdXSkpKQoKc2hhcmVkX3ZlY3RvciA8LSBWZW5uZXJhYmxlOjpWZW5uKFNldHM9c2lnX3ZlY3RvcnMpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkX3ZlY3RvciwgZG9XZWlnaHRzPUZBTFNFKQoKc2hhcmVkX2lkcyA8LSBzaGFyZWRfdmVjdG9yQEludGVyc2VjdGlvblNldHNbWyIxMTEiXV0Kc2hhcmVkX2V4cHQgPC0gZXhjbHVkZV9nZW5lc19leHB0KGhzX2NsaW5pY2FsLCBpZHM9c2hhcmVkX2lkcywgbWV0aG9kPSJrZWVwIikKc2hhcmVkX3dyaXR0ZW4gPC0gd3JpdGVfZXhwdChzaGFyZWRfZXhwdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9zaGFyZWRfYWNyb3NzX2NlbGx0eXBlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgTW9ub2N5dGVzIGJ5IHZpc2l0CgogMS4gQ2FuIHlvdSBwbGVhc2Ugc2hhcmUgd2l0aCB1cyBhIFBDQSAoU1ZBIGFuZCBub24tU1ZBKSBvZiB0aGUKICAgIG1vbm9jeXRlcyBvZiB0aGUgVE1SQzMgcHJvamVjdCwgYnV0IGxhYmVsaW5nIHRoZW0gYmFzZWQgb24gdGhlIHZpc2l0CiAgICAoVjEsIFYyLCBWMyk/CiAyLiBDYW4geW91IHBsZWFzZSBzaGFyZSBERSBsaXN0cyBvZiBWMSB2cyBWMiwgVjEgdnMgVjMsIFYxIHZzLiBWMitWMwogICAgYW5kIFYyIHZzIFYzPwoKYGBge3IgbW9ub2N5dGVzX2J5X3Zpc2l0fQp2aXNpdF9jb2xvcnMgPC0gY2hvc2VuX2NvbG9ycyA8LSBjKCIjRDk1RjAyIiwgIiM3NTcwQjMiLCAiIzFCOUU3NyIpCm5hbWVzKHZpc2l0X2NvbG9ycykgPC0gYygxLCAyLCAzKQptb25vX3Zpc2l0IDwtIHN1YnNldF9leHB0KGhzX3ZhbGlkLCBzdWJzZXQ9InR5cGVvZmNlbGxzPT0nbW9ub2N5dGVzJyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdD0idmlzaXRudW1iZXIiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3Q9ImNsaW5pY2Fsb3V0Y29tZSIpICU+JQogIHNldF9leHB0X2NvbG9ycyhjb2xvcnM9Y2hvc2VuX2NvbG9ycykKCm1vbm9fdmlzaXRfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtb25vX3Zpc2l0LCBmaWx0ZXI9VFJVRSwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtPSJsb2cyIikKbW9ub192aXNpdF9wY2EgPC0gcGxvdF9wY2EobW9ub192aXNpdF9ub3JtKQpwcChmaWxlPSJpbWFnZXMvbW9ub2N5dGVfYnlfdmlzaXQucG5nIiwgaW1hZ2U9bW9ub192aXNpdF9wY2EkcGxvdCkKCm1vbm9fdmlzaXRfbmIgPC0gbm9ybWFsaXplX2V4cHQobW9ub192aXNpdCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIpCm1vbm9fdmlzaXRfbmJfcGNhIDwtIHBsb3RfcGNhKG1vbm9fdmlzaXRfbmIpCnBwKGZpbGU9ImltYWdlcy9tb25vY3l0ZV9ieV92aXNpdF9uYi5wbmciLCBpbWFnZT1tb25vX3Zpc2l0X25iX3BjYSRwbG90KQoKdGFibGUocERhdGEobW9ub192aXNpdF9ub3JtKSRiYXRjaCkKYGBgCgpgYGB7ciBtb25vX3Zpc2l0X2RlLCBmaWcuc2hvdz0iaGlkZSJ9CmtlZXBlcnMgPC0gbGlzdCgKICAgICJzZWNvbmRfdnNfZmlyc3QiPWMoImMyIiwgImMxIiksCiAgICAidGhpcmRfdnNfc2Vjb25kIj1jKCJjMyIsICJjMiIpLAogICAgInRoaXJkX3ZzX2ZpcnN0Ij1jKCJjMyIsICJjMSIpKQptb25vX3Zpc2l0X2RlIDwtIGFsbF9wYWlyd2lzZShtb25vX3Zpc2l0LCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCgptb25vX3Zpc2l0X3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIG1vbm9fdmlzaXRfZGUsCiAgICBrZWVwZXJzPWtlZXBlcnMsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJleGNlbC9tb25vX3Zpc2l0X3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCmBgYHtyIHYxX3ZzX2FsbH0KbmV3X2ZhY3RvciA8LSBhcy5jaGFyYWN0ZXIocERhdGEobW9ub192aXNpdClbWyJ2aXNpdG51bWJlciJdXSkKbm90X29uZV9pZHggPC0gbmV3X2ZhY3RvciAhPSAxCm5ld19mYWN0b3Jbbm90X29uZV9pZHhdIDwtICJub3RfMSIKbW9ub19vbmVfdnMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtb25vX3Zpc2l0LCBuZXdfZmFjdG9yKQoKbW9ub19vbmVfdnNfZGUgPC0gYWxsX3BhaXJ3aXNlKG1vbm9fb25lX3ZzLCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCgptb25vX29uZV92c190YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBtb25vX29uZV92c19kZSwKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImV4Y2VsL21vbm9fb25lX3ZzX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMgVGVzdCBUU1AKCkluIHdyaXRpbmcgdGhlIGZvbGxvd2luZywgSSBxdWlja2x5IHJlYWxpemVkIHRoYXQgdHNwYWlyIHdhcyBub3QKam9raW5nIHdoZW4gaXQgc2FpZCBpdCBpcyBpbnRlbmRlZCBmb3Igc21hbGwgbnVtYmVycyBvZiBnZW5lcy4gIEZvciBhCmZ1bGwgZXhwcmVzc2lvbnNldCBvZiBodW1hbiBkYXRhIGl0IGlzIHN0cnVnZ2xpbmcuICBJIGxpa2UgdGhlIGlkZWEsCml0IG1heSBwcm92ZSB3b3J0aCB3aGlsZSB0byBzcGVuZCBzb21lIHRpbWUgb3B0aW1pemluZyB0aGUgcGFja2FnZSBzbwp0aGF0IGl0IGlzIG1vcmUgdXNhYmxlLgoKYGBge3IgdHNwLCBldmFsPUZBTFNFfQpleHB0IDwtIGhzX2NsaW5pY2FsX25vYmlvcAoKc2ltcGxlX3RzcCA8LSBmdW5jdGlvbihleHB0LCBjb2x1bW49ImNvbmRpdGlvbiIpIHsKICBmYWN0cyA8LSBsZXZlbHMoYXMuZmFjdG9yKHBEYXRhKGV4cHQpW1tjb2x1bW5dXSkpCiAgcmV0bGlzdCA8LSBsaXN0KCkKICBpZiAobGVuZ3RoKGZhY3RzKSA8IDIpIHsKICAgIHN0b3AoIlRoaXMgcmVxdWlyZXMgZmFjdG9ycyB3aXRoIGF0IGxlYXN0IDIgbGV2ZWxzLiIpCiAgfSBlbHNlIGlmIChsZW5ndGgoZmFjdHMpID09IDIpIHsKICAgIHJldGxpc3QgPC0gc2ltcGxlX3RzcF9wYWlyKGV4cHQsIGNvbHVtbj1jb2x1bW4pCiAgfSBlbHNlIHsKICAgIGZvciAoZmlyc3QgaW4gMToobGVuZ3RoKGZhY3RzKSAtIDEpKSB7CiAgICAgIGZvciAoc2Vjb25kIGluIDI6KGxlbmd0aChmYWN0cykpKSB7CiAgICAgICAgaWYgKGZpcnN0IDwgc2Vjb25kKSB7CiAgICAgICAgICBuYW1lIDwtIGdsdWU6OmdsdWUoIntmYWN0c1tmaXJzdF19X3ZzX3tmYWN0c1tzZWNvbmRdfSIpCiAgICAgICAgICBtZXNzYWdlKCJTdGFydGluZyAiLCBuYW1lLCAiLiIpCiAgICAgICAgICBzdWJzdHJpbmcgPC0gZ2x1ZTo6Z2x1ZSgie2NvbHVtbn09PSd7ZmFjdHNbZmlyc3RdfSd8e2NvbHVtbn09PSd7ZmFjdHNbc2Vjb25kXX0nIikKICAgICAgICAgIHN1YmJ5IDwtIHN1YnNldF9leHB0KGV4cHQsIHN1YnNldD1hcy5jaGFyYWN0ZXIoc3Vic3RyaW5nKSkKICAgICAgICAgIHJldGxpc3RbW25hbWVdXSA8LSBzaW1wbGVfdHNwX3BhaXIoc3ViYnksIGNvbHVtbj1jb2x1bW4pCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQp9CgpzaW1wbGVfdHNwX3BhaXIgPC0gZnVuY3Rpb24oc3ViYnksIGNvbHVtbj0iY29uZGl0aW9uIiwgcmVwZXRpdGlvbnM9NTApIHsKICB0c3BfaW5wdXQgPC0gc3ViYnlbWyJleHByZXNzaW9uc2V0Il1dCiAgdHNwX291dHB1dCA8LSB0c3BjYWxjKHRzcF9pbnB1dCwgY29sdW1uKQogIHRzcF9zY29yZXMgPC0gdHNwc2lnKHRzcF9pbnB1dCwgY29sdW1uLCBCPXJlcGV0aXRpb25zKQp9Cgp0c3AxIDwtIHRzcGNhbGModHNwX2lucHV0LCAiY29uZGl0aW9uIikKCmBgYAoKYGBge3Igc2F2ZW1lfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgc2F2ZWZpbGUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9c2F2ZWZpbGUpKQp9CmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsPUZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lPXNhdmVmaWxlKQpgYGAK