Note to self: I changed the clusterProfiler output list to store the enrichResults in [[xx_data]][[enrich]], or in the case of go: [[go_data]][[BP_enrich]] instead of enrich_results.

1 Set some parameters which will be used later

sample_sheet <- "sample_sheets/20240606_only_umd_sequenced_modified.xlsx"
## LogFC cutoff when working on 'normal' comparisons
lfc_cutoff <- 1.0
## LogFC cutoff when working on the inclusion sets.
filter_lfc_cutoff <- 0.1
## Adjusted p-value cutoff when working with 'normal' contrasts
adjp_cutoff <- 0.05
## Adjusted p-value cutoff when working on the inclusion sets.
filter_adjp_cutoff <- 0.1
## Increase the maximum allowed group size when working with clusterProfiler
## This should bring out some of the more general groups like 'cellbody'
max_groupsize <- 2000
## Allow groups higher up in the tree for clusterProfiler results.
go_level <- 2
## Allow 10 GO categories to be displayed when plotting.
go_categories <- 14
## MA plot point outlines
outline <- FALSE
## Speed up clusterProfiler by choosing the correct keytypes
orgdb_from <- "ENSEMBL"
default_fstring <- "~ 0 + condition"
annotation_columns <- c("ensembl_gene_id", "ensembl_transcript_id",
                        "description", "external_synonym")
label_column <- "symbol"  ## taken from org.Mm.eg.db

2 TODOs

  • Check this for correctness.
  • Reorganize it
  • GSVA (@hanzelmannGSVAGeneSet2013a)
  • Consider embedding some/many/all of the Excel outputs into the html output via xfun::embed_dir(‘excel/’)

3 Meeting with Theresa

Previous papers did not do an explicit subtraction, instead just compared to WT and kept the genes which are > in delta/het vs. wt. There are multiple ways to deal with this and that query has not yet been defined. Later, Theresa came to the conclusion that the subtraction method is not appropriate.

4 A note on transcript-level changes

An interesting question was posed regarding transcript-level changes in the TRAP and bulk data. As a result, I made copies of the notebooks and repeated all analyses at the transcript level; the various images, excel files, etc are all in the same directories with a suffix ’_tx’. A few minor changes were introduced for the labelling of genes.

I made no effort to compare the similarities between the transcript-level changes for the TRAP and bulk data; but did that only at the level of genes.

5 Introduction

In this document I hope to explore the freshly processed samples and perform some comparisons to see that we have the expected similarities and differences from the prior analysis performed by Theresa.

There is one way in which I expect any/all of these analyses to be explicitly different: this should include the changes produced by April’s renaming of some samples.

My intention is to produce a sample sheet which includes one column with non-umi-deduplicated results and one with deduplicated results. With the exception of the previous point, I hope that the first will be identical (or at least very close to identical) to Theresa’s result while the second I expect will be subtly different – but I am hoping subtly enough that it will not significantly change the interpretation but be a little more precise.

Lets see! I need therefore to make a change to my metadata gathering function to include the umi deduplicated result. I am thinking therefore to create a separate specification for umi-barcoded samples because looking through the logs for umi stuff when they are not used will be too much of a pain…

5.1 Small random reminder

I have a couple pictures of RPL22 to help me remember the experimental design:

  • The human ribosome with RPL22 in red: human_rpl22_red
  • The mouse ribosome with RPL22 in green at the center: mouse_rpl22

That second picture came from: (@liMaleGermcellspecificRibosome2022)

6 A note about implementation

I would like to improve this document by comparing/contrasting the methodologies performed by other groups and those performed by me in it. I never fully appreciated the suite of computational methods applied by previous groups when examining TRAP data; I instead simply followed Theresa’s notebook without considering other possibilities.

I therefore spent a little time stepping through her thesis and pulling out the relevant papers in the hopes of learning these various methods. I should therefore be able soon to compare/contrast the various methods employed by other labs in addition to copying Theresa’s logic.

6.1 The following block cannot work in the container

The following block assumes the full tree of preprocessed data with the logs from the trimmer, mapping, umi deduplication, counting, etc. As a result it cannot work in the container which has only the various count tables.

As a result, I am including a copy of this sheet after running the following block in my working tree. I suppose for the moment you will have to trust that it worked. (for right now, when testing out this container, I am just sending the R working directory to my tree for this block, then moving it back.

I will need to manually edit one column though, the symlink column from Theresa has a series of paths which do not work in the container.

umi_spec <- make_rnaseq_spec(umi = TRUE)
iprgc_2022_meta <- gather_preprocessing_metadata("sample_sheets/20240606_only_umd_sequenced.xlsx",
                                                 spec = umi_spec, species = "mm39_112", verbose = FALSE,
                                                 basedir = "preprocessing/umd_sequenced")
colnames(iprgc_2022_meta[["new_meta"]])
head(iprgc_2022_meta[["new_meta"]])
msigdb <- "reference/msigdb_v2024.1.Mm.db"
msig_data <- NULL
make_transparent <- function() {
  ggplot2::theme(
    panel.background = element_rect(fill = 'transparent'),
    plot.background = element_rect(fill = 'transparent', color = NA),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    legend.background = element_rect(fill = 'transparent'),
    legend.box.background = element_rect(fill = 'transparent'))
}

I will figure out if I can leave mSigDB M2 in this image; if not, then any analyses depending on those gene sets will fail a priori.

m2_gsc <- try(load_gmt_signatures(signatures = msigdb,
                                  signature_category = "M2"), silent = TRUE)
## I do not think I have permission to load the msigdb in the container
## So, if this fails, just load it from GSVAData, oh wait no, GSVAdata is human.
if ("try-error" %in% class(m2_gsc)) {
  warning("Unable to load the M2 MsigDB data.")
}

From this point on, I am hoping/intending to pull liberally from Theresa’s notebook with a diversion to compare the three datasets:

  • Pre-April renaming: E.g. Theresa’s current dataset
  • Post renaming: Unless I am mistaken, this should be very similar to the above.
  • Post deduplication: Given what I saw from the extracted logs in the sample sheet, I expect this to be similar but not identical to the previous two.

Lets find out! But first, annotations!

7 Annotation data

I am pulling this from Theresa’s anxontrapR_pipeline.Rmd, primarily because it looks similar to the other documents, but was modified more recently. I will change it slightly, primarily because I grabbed a new mmusculus assembly and therefore I will pull the mmusculus annotations from a specific biomart (@smedleyBioMartBiologicalQueries2009) archive that should match it.

A note from the future: multiple ensembl archive servers have been taken offline since last I ran this. Let us see if Feb. 2023 still works.

7.1 An important note!

In the recent past, ensembl queries have become inconsistent, failing much more often than ever in the past. I do not think this is the fault of ensembl; but I think I need a fallback mechanism for collecting annotation information.

In the case of ensembl, it should be trivial (but less fun) to use a combination of the locally installed orgdb and txdb databases.

This does open a risk that the set of genes with annotations will be different depending on when the container is run due to differences between the orgdb/txdb instance and the Feb 2023 biomart. I am not sure there is much I can do about that except to bundle the set of annotations I downloaded in the container – since load_biomart_annotations() does save a rda copy of its download.

ok, I did both. If you, dear reader, wish to download your own annotations, and ensembl is having troubles, the following should work without a problem; in addition the rda annotations are in /data of the container and should get loaded.

7.1.1 Another stategy

I added a little code to my cyoa package which downloads all the tables at https://ftp.ensembl.org/pub/current/mysql/ for either the biomart database (ensembl_mart_116/ and/or mouse_mart_116) or the species specific database (mus_musculus_core_116_39); I then added some functions to hpgltools to directly query these local SQL databases. This is crazy fast (< 2 seconds vs. ~ 2 minutes) compared to using biomart, but I do not entirely understand the schemas yet and so miss some potentially useful columns of interest. If anyone is interested, I would be happy to pass along more complete instructions; I am thinking it would be nice for the community to make the lives of people at ensembl easier.

7.1.2 My strategy for the container

I decided to load my existing ensembl annotations as the canonical set, then add to it a portion of the mm.eg.db annotations. I then split them to one set for the gene data and another for the transcripts.

Here are the most important label columns:

  1. symbol: The gene symbol (provided by org.Mm.eg.db)
  2. external_transcript_name: Usually the same as symbol, but with a suffix identifying which transcript it refers to. (from biomart)
  3. genename: Long-form name (from org.Mm.eg.db)
  4. description: Often but not always identical to the genename, includes accessions for a couple of other databases. (from biomart)
  5. ensembl_gene_id: The ENSMUSG id, our primary key for genes
  6. ensembl_transcript_id: The ENSMUST, our primary key for transcripts

Due to the way I am merging these, they are pretty redundant, but they will get pared down when merged to the assay data.

tx_gene_map <- data.frame()
mm_annot <- try(load_biomart_annotations(species = "mmusculus", host = "useast.ensembl.org",
                                         archive = FALSE, overwrite = FALSE,
                                         gene_requests = annotation_columns))
## The biomart annotations file already exists, loading from it.
fields <- c("ACCNUM", "ENSEMBL", "ENSEMBLTRANS", "ENTEZID", "GENENAME", "SYMBOL")
orgdb_annot <- load_orgdb_annotations("org.Mm.eg.db", fields = fields)
## Loading required package: AnnotationDbi
## Loading required package: stats4
## Loading required package: BiocGenerics
## Loading required package: generics
## 
## Attaching package: 'generics'
## The following object is masked from 'package:dplyr':
## 
##     explain
## The following objects are masked from 'package:base':
## 
##     as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
##     setequal, union
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:hpgltools':
## 
##     conditions, conditions<-, IQR, mad, sd, var
## The following object is masked from 'package:dplyr':
## 
##     combine
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, is.unsorted, lapply, Map, mapply, match, mget,
##     order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank,
##     rbind, Reduce, rownames, sapply, saveRDS, table, tapply, unique,
##     unsplit, which.max, which.min
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## Attaching package: 'Biobase'
## The following objects are masked from 'package:hpgltools':
## 
##     exprs<-, notes, pData<-, sampleNames<-
## Loading required package: IRanges
## Loading required package: S4Vectors
## 
## Attaching package: 'S4Vectors'
## The following objects are masked from 'package:dplyr':
## 
##     first, rename
## The following object is masked from 'package:utils':
## 
##     findMatches
## The following objects are masked from 'package:base':
## 
##     expand.grid, I, unname
## 
## Attaching package: 'IRanges'
## The following objects are masked from 'package:dplyr':
## 
##     collapse, desc, slice
## 
## Attaching package: 'AnnotationDbi'
## The following object is masked from 'package:dplyr':
## 
##     select
## 
## Unable to find CDSNAME, setting it to GENENAME.
## Unable to find GENE_TYPE, setting it to GENETYPE.
## Unable to find CDSCHROM in the db, removing it.
## Unable to find CDSSTRAND in the db, removing it.
## Unable to find CDSSTART in the db, removing it.
## Unable to find CDSEND in the db, removing it.
## Some requested columns are not available: ENTEZID.
## The following are available: ACCNUM, ALIAS, ENSEMBL, ENSEMBLPROT, ENSEMBLTRANS, ENTREZID, ENZYME, EVIDENCE, EVIDENCEALL, GENENAME, GENETYPE, GO, GOALL, IPI, MGI, ONTOLOGY, ONTOLOGYALL, PATH, PFAM, PMID, PROSITE, REFSEQ, SYMBOL, UNIPROT
## Extracted all gene ids.
## Attempting to select: GENENAME, GENETYPE, ACCNUM, ENSEMBL, ENSEMBLTRANS, GENENAME, SYMBOL
## 'select()' returned 1:many mapping between keys and columns
gene_info <- orgdb_annot[["genes"]]

## Note, there are a bunch of variants of the txdb package one might use.
## I do not think it matters a lot for our purposes, but I suspect that if we used
## a mismatched BSgenome and tried to pull CDS sequences, that might end badly.
pkg <- "TxDb.Mmusculus.UCSC.mm10.knownGene"
tx_annot <- load_txdb_annotations(pkg)
## Loading required package: GenomicFeatures
## Loading required package: Seqinfo
## Loading required package: GenomicRanges
## 'select()' returned 1:many mapping between keys and columns
## 'select()' returned 1:many mapping between keys and columns
## 'select()' returned 1:many mapping between keys and columns
transcripts <- tx_annot[["TX"]]
transcripts[["tx"]] <- gsub(x = transcripts[["TXNAME"]],
                            pattern = "\\.\\d+$", replacement = "")
mm_annot_orgdb <- merge(gene_info, transcripts, by.x = "ensembltrans", by.y = "tx")
rownames(mm_annot_orgdb) <- make.names(mm_annot_orgdb[["ensembl"]], unique = TRUE)

mm_annot_combined <- merge(mm_annot[["annotation"]], mm_annot_orgdb, by.x = "ensembl_transcript_id", by.y = "ensembltrans", all.x = TRUE)

mm_annot_genes <- mm_annot_combined
rownames(mm_annot_genes) <- make.names(mm_annot_genes[["ensembl_gene_id"]], unique = TRUE)

mm_annot_tx <- mm_annot_combined
rownames(mm_annot_tx) <- make.names(mm_annot_tx[["ensembl_transcript_id"]], unique = TRUE)

tx_gene_map <- mm_annot_genes[, c("TXID", "ensembl_gene_id")]

The end result of these various annotation collections is mostly identical, but the column containing the MGI gene names may get changed. This is pretty annoying when it comes to getting the container image to run perfectly in all situations; and so at this time it just loads the local.rda file; if one wishes to play press your luck with ensembl, just delete the annotation rda and re-render the documents.

8 Hisat2 summarizedExperiments

The primary difference between my block and Theresa’s are:

  1. I am pulling the metadata directly from the gather_preprocessing_metadata() above.
  2. I am using the column ‘symlink’ which is just a copy of the existing ‘file’ column with a small change so I can load it from my directory without having to copy everything.
  3. I am using the ensembl genome release 39, version 112 and so pulled a somewhat newer copy of the annotation data.
  4. The original is named ‘v1’, followed by ‘v2’ and ‘v3’ for the other two treatments I performed.

8.1 Color choices and reused parameters

Given that we are excluding a bunch of the older samples, the set of colors I expect to find is different; so I will make explicit here the various colors used to denote location/genotype/time/etc.

April turned me onto this website ‘paletton.com’ for this kind of stuff and I will try and pick out palettes which basically match what I am getting with the original colors.

color_choices <- list(
  "all" = list(
    "p08_het_dlgn" = "#E7298A",
    "p15_het_dlgn" = "#E7298A",
    "p08_het_retina" = "#238B45",
    "p15_het_retina" = "#238B45",
    "p08_het_scn" = "#4292C6",
    "p15_het_scn" = "#4292C6",
    "p08_ko_dlgn" = "#C994C7",
    "p15_ko_dlgn" = "#C994C7",
    "p08_ko_retina" = "#74c476",
    "p15_ko_retina" = "#74c476",
    "p08_ko_scn" = "#9BCAE1",
    "p15_ko_scn" = "#9BCAE1",
    "p08_wt_dlgn" = "#980043",
    "p15_wt_dlgn" = "#980043",
    "p08_wt_retina" = "#004008",
    "p15_wt_retina" = "#004008",
    "p08_wt_scn" = "#08519C",
    "p15_wt_scn" = "#08519C",
    "p60_wt_dlgn" = "#333333",
    "p60_wt_retina" = "#222222",
    "p60_wt_scn" = "#111111"),
  "geno_loc" = list(
    "het_dlgn" = "#E7298A",
    "het_retina" = "#238B45",
    "het_scn" = "#4292C6",
    "ko_dlgn" = "#C994C7",
    "ko_retina" = "#74c476",
    "ko_scn" = "#9BCAE1",
    "wt_dlgn" = "#980043",
    "wt_retina" = "#004008",
    "wt_scn" = "#08519C"),
  "location" = list(
    "retina" = "#004008",
    "dlgn" = "#980043",
    "scn" = "#08519C"),
  "genotype" = list(
    "wt" = "#74c476",
    "het" = "#238B45",
    "ko" = "#006D2C"),
  "time" = list(
    "p08" = "#5E104B",
    "p15" = "#4E9231"))
label_column <- "mgi_symbol" ## Set the column used to extract gene symbols rather than ENSG.....
colors <- color_choices[["geno_loc"]]
time_colors <- list(
  "p08_het_dlgn" = "#E7298A",
  "p15_het_dlgn" = "#8a1852",
  "p08_het_retina" = "#238B45",
  "p15_het_retina" = "#155329",
  "p08_het_scn" = "#4292C6",
  "p15_het_scn" = "#275776",
  "p08_ko_dlgn" = "#C994C7",
  "p15_ko_dlgn" = "#785877",
  "p08_ko_retina" = "#74C476",
  "p15_ko_retina" = "#457546",
  "p08_ko_scn" = "#9BCAE1",
  "p15_ko_scn" = "#5d7987")

There is one noteworthy sample: iprgc_103, it was effectively replaced when April renamed the samples and so exists in the v1 data, but not v2/v3; they instead have the newly named samples which I called iprgc_123 to iprgc_130. As a result, I copied the annotations for iprgc_123 to my column so that there is no discrepency in terms of genotype/location/time.

8.2 The original count tables

At the moment I have not included the original counts in this container because we made some changes to the mapping strategy and also found that a couple samples were mixed up in sequencing; as a result I documented all of the changes in the sample sheets and preprocessing documents and excluded the original files.

This is also why some columns in the sample sheet have suffixes like ‘adh’ and ‘atb’, those denote from whom the relevant metadata columns came from.

mm38_hisat_v1 <- create_se(sample_sheet,
                           gene_info = mm_annot_genes,
                           file_column = "symlink") |>
  set_conditions(fact = "geno_loc_atb") |>
  set_batches(fact = "time_atb") |>
  set_colors(color_choices[["geno_loc"]])
mm38_hisat_v1

8.3 Recounted tables and the deduplicated result

In the following I make two more versions of the data, one remapped with the changes to the sample identities, and one with deduplication applied.

mm38_hisat_v2 <- create_se(sample_sheet, gene_info = mm_annot_genes,
                           file_column = "hisat_count_table") |>
  set_conditions(fact = "geno_loc_atb") |>
  set_batches(fact = "time_atb") |>
  set_colors(color_choices[["geno_loc"]])
## Reading the sample metadata.
## Checking the state of the condition column.
## Checking the state of the batch column.
## Checking the condition factor.
## The sample definitions comprises: 69 rows(samples) and 59 columns(metadata fields).
## Warning in create_se(sample_sheet, gene_info = mm_annot_genes, file_column =
## "hisat_count_table"): Some samples were removed when cross referencing the
## samples against the count data.
## Matched 25405 annotations and counts.
## Some annotations were lost in merging, setting them to 'undefined'.
## The final summarized experiment has 25425 rows and 59 columns.
## The numbers of samples by condition are:
## 
##   het_dlgn het_retina    het_scn    ko_dlgn  ko_retina     ko_scn    wt_dlgn 
##          7          7          7          6          6          6         11 
##  wt_retina     wt_scn 
##         11          7
## Setting colors with no pre-defined colors, using the Dark2 palette.
## The number of samples by batch are:
## 
## p08 p15 p60 
##  31  34   3
mm38_hisat_v2
## class: SummarizedExperiment 
## dim: 25425 68 
## metadata(7): notes title ... study researcher
## assays(1): ''
## rownames(25425): ENSMUSG00000000001 ENSMUSG00000000003 ...
##   ENSMUSG00001074846 ENSMUSG00002076083
## rowData names(23): ensembl_transcript_id ensembl_gene_id ... TXSTART
##   TXEND
## colnames(68): iprgc_62 iprgc_63 ... iprgc_129 iprgc_130
## colData names(60): rownames sampleid ... umi_dedup_max_umi_per_pos
##   color
mm38_hisat_v3 <- create_se(sample_sheet, gene_info = mm_annot_genes,
                           file_column = "umi_dedup_output_count") |>
  set_conditions(fact = "geno_loc_atb") |>
  set_batches(fact = "time_atb") |>
  set_colors(color_choices[["geno_loc"]])
## Reading the sample metadata.
## Checking the state of the condition column.
## Checking the state of the batch column.
## Checking the condition factor.
## The sample definitions comprises: 69 rows(samples) and 59 columns(metadata fields).
## Warning in create_se(sample_sheet, gene_info = mm_annot_genes, file_column =
## "umi_dedup_output_count"): Some samples were removed when cross referencing the
## samples against the count data.
## Matched 25405 annotations and counts.
## Some annotations were lost in merging, setting them to 'undefined'.
## The final summarized experiment has 25425 rows and 59 columns.
## The numbers of samples by condition are:
## 
##   het_dlgn het_retina    het_scn    ko_dlgn  ko_retina     ko_scn    wt_dlgn 
##          7          7          7          6          6          6         11 
##  wt_retina     wt_scn 
##         11          7
## Setting colors with no pre-defined colors, using the Dark2 palette.
## The number of samples by batch are:
## 
## p08 p15 p60 
##  31  34   3
mm38_hisat_v3
## class: SummarizedExperiment 
## dim: 25425 68 
## metadata(7): notes title ... study researcher
## assays(1): ''
## rownames(25425): ENSMUSG00000000001 ENSMUSG00000000003 ...
##   ENSMUSG00001074846 ENSMUSG00002076083
## rowData names(23): ensembl_transcript_id ensembl_gene_id ... TXSTART
##   TXEND
## colnames(68): iprgc_62 iprgc_63 ... iprgc_129 iprgc_130
## colData names(60): rownames sampleid ... umi_dedup_max_umi_per_pos
##   color
all_fact <- paste0(colData(mm38_hisat_v3)[["time_atb"]], "_",
                   colData(mm38_hisat_v3)[["geno_loc_atb"]])
colData(mm38_hisat_v3)[["time_geno_loc"]] <- all_fact

9 Use the Summarized Experiment to prune the gene annotations

mm_annot_genes <- as.data.frame(rowData(mm38_hisat_v3))

9.1 Archive count tables for the singularity container

The following is what I did to make an archive of the transcript count tables following deduplication. It creates a tar archive of all the filenames provided in the ‘column’ argument.

mrna_tables <- tar_meta_column(mm38_hisat_v3, column = "umi_dedup_mrna_count")

Note the end of the previous block, I created a factor out of the combination of time, genotype, and location. In a future invocation of this notebook, I will change the pairwise comparisons to add each of these three factors to the statistical model instead of this. The code to do that is not quite ready yet.

10 Non-zero Counts per Sample

Let’s look at the number of non-zero genes for all samples versus the coverage.

As above, this does not get run because I did not copy the count tables.

v1_nonzero <- plot_nonzero(mm38_hisat_v1)
v1_nonzero

But these do!

plot_legend(mm38_hisat_v2)
## The colors used in the expressionset are: 1, 2, 3, 4, 5, 6, 7, 8, 9.

v2_nonzero  <- plot_nonzero(mm38_hisat_v2, y_intercept = 0.65)
## The following samples have less than 16526.25 features.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68" 
##  [7] "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74"  "iprgc_75" 
## [13] "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83" 
## [19] "iprgc_84"  "iprgc_85"  "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89" 
## [25] "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95" 
## [31] "iprgc_96"  "iprgc_97"  "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104"
## [37] "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111"
## [43] "iprgc_112" "iprgc_113" "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118"
## [49] "iprgc_121" "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127"
## [55] "iprgc_128" "iprgc_129" "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the hpgltools package.
##   Please report the issue to the authors.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
v2_nonzero
## A non-zero genes plot of 68 samples.
## These samples have an average 13.70186 CPM coverage and 15744 genes observed, ranging from 13692 to
## 17083.

pp(file = "01diagnostic_images/nonzero_v2_unfiltered.pdf")
v2_nonzero[["plot"]]
plotted <- dev.off()

v3_nonzero  <- plot_nonzero(mm38_hisat_v3, y_intercept = 0.65)
## The following samples have less than 16526.25 features.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68" 
##  [7] "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74"  "iprgc_75" 
## [13] "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83" 
## [19] "iprgc_84"  "iprgc_85"  "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89" 
## [25] "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95" 
## [31] "iprgc_96"  "iprgc_97"  "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104"
## [37] "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111"
## [43] "iprgc_112" "iprgc_113" "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118"
## [49] "iprgc_119" "iprgc_121" "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126"
## [55] "iprgc_127" "iprgc_128" "iprgc_129" "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
v3_nonzero
## A non-zero genes plot of 68 samples.
## These samples have an average 4.803034 CPM coverage and 15787 genes observed, ranging from 13868 to
## 17101.

pp(file = "01diagnostic_images/nonzero_v3_unfiltered.pdf")
v3_nonzero[["plot"]]
plotted <- dev.off()

Oh wow, I did not expect such a profound effect on the cpm values on the more saturated libraries. I guess in retrospect I should have?

Also note to self, we are not messing with p60.

10.1 Exclude p60

mm38_hisat_v2 <- subset_se(mm38_hisat_v2, subset = "time_atb!='p60'")
mm38_hisat_v3 <- subset_se(mm38_hisat_v3, subset = "time_atb!='p60'")

10.2 Replot the nonzero gene plots

v2_nonzero_filt <- plot_nonzero(mm38_hisat_v2, plot_labels = FALSE)
## The following samples have less than 16526.25 features.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68" 
##  [7] "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74"  "iprgc_75" 
## [13] "iprgc_77"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85" 
## [19] "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91" 
## [25] "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95"  "iprgc_96"  "iprgc_97" 
## [31] "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106"
## [37] "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113"
## [43] "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_121" "iprgc_123"
## [49] "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127" "iprgc_128" "iprgc_129"
## [55] "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
## Not putting labels on the plot.
pp(file = "01diagnostic_images/nonzero_v2_filt.pdf", image = v2_nonzero_filt[["plot"]])

v3_nonzero_filt <- plot_nonzero(mm38_hisat_v3, plot_labels = FALSE)
## The following samples have less than 16526.25 features.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68" 
##  [7] "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74"  "iprgc_75" 
## [13] "iprgc_77"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85" 
## [19] "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91" 
## [25] "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95"  "iprgc_96"  "iprgc_97" 
## [31] "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106"
## [37] "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113"
## [43] "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_119" "iprgc_121"
## [49] "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127" "iprgc_128"
## [55] "iprgc_129" "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
## Not putting labels on the plot.
pp(file = "01diagnostic_images/nonzero_v3_filt.pdf", image = v3_nonzero_filt[["plot"]])

Once again, I do not want to lose the previous code, so here is the v1 invocation

mm38_hisat_v1 <- subset_se(mm38_hisat_v1, subset = "time_atb!='p60'")

11 Quick PCA, then return to Theresa’s document

v2_norm <- normalize(mm38_hisat_v2, transform = "log2", convert = "cpm",
                     norm = "quant", filter = TRUE)
## Removing 10298 low-count genes (15127 remaining).
## transform_counts: Found 8465 values equal to 0, adding 1 to the matrix.
v2_norm_pca <- plot_pca(v2_norm)
v2_norm_pca
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by het_dlgn, het_retina, het_scn, ko_dlgn, ko_retina, ko_scn, wt_dlgn, wt_retina, wt_scn
## Shapes are defined by p08, p15.

pp(file = "01diagnostic_images/v2_norm_pca.pdf", image = v2_norm_pca[["plot"]])

v3_norm <- normalize(mm38_hisat_v3, transform = "log2", convert = "cpm",
                     norm = "quant", filter = TRUE)
## Removing 10156 low-count genes (15269 remaining).
## transform_counts: Found 9347 values equal to 0, adding 1 to the matrix.
v3_norm_pca <- plot_pca(v3_norm)
pp(file = "01diagnostic_images/v3_norm_pca.pdf", image = v3_norm_pca[["plot"]])

Ibid.

v1_norm <- normalize(mm38_hisat_v1, transform = "log2", convert = "cpm",
                     norm = "quant", filter = TRUE)
plot_pca(v1_norm)

To my eyes it looks like we just have 1 weirdo p15 sample? Deduplication had a minor but significant effect on the PCA.

With that in mind, let us look at Theresa’s WORKING document and see what we can recapitulate.

Theresa’s document: The TRAP protocol has some variability which is introduced at different stpdf including homogenization, antibody labeling, pulldown efficiency/specificity, sample handling during cleanup, and library prep/sequencing. We know from Rashmi’s QC that there is variability at the level of pulldown efficiency (amount of RNA isolated). She is doing a good job of keeping track of this for all her samples and we have validated her P8 results (attached supplementary figure 3D). We consistently see clear differences between control and cre samples for the retina, which makes sense because the cell bodies are in the retina. The target tissue differences are smaller, which also makes sense for axon-TRAP. We think that some of her P15 samples are not good based on low amounts of isolated RNA from cre(+) retina samples. We plan to drop these samples and not perform additional isolations at this time point. Based on this (and the general lack of large developmental effects), we were planning to focus on presenting the P8 data only in the paper. Interested to hear your thoughts in this…

My notes: Theresa’s first operations in this notebook were to:

  1. Set location as condition, genotype as batch.
  2. Perform PCA before/after sva.
v3_loc_geno <- set_conditions(mm38_hisat_v3, fact = "location_atb",
                              colors = color_choices[["location"]]) |>
  set_batches(fact = "genotype_atb")
## The numbers of samples by condition are:
## 
##   dlgn retina    scn 
##     23     23     19
## The number of samples by batch are:
## 
## het  ko  wt 
##  21  18  26

11.1 The associated PCA

At different times, it appears to me that Theresa has preferred slightly different normalization methods, primarily a mix of TMM and quantile.

Thus I will use different suffix letters to denote various normalizations employed, and if they turn out the same I will pick one arbitrarily.

loc_geno_nq <- normalize(v3_loc_geno, transform = "log2", convert = "cpm",
                         filter = TRUE, norm = "quant")
## Removing 10156 low-count genes (15269 remaining).
## transform_counts: Found 9347 values equal to 0, adding 1 to the matrix.
location_genotype_pca <- plot_pca(loc_geno_nq)
pp(file = "01diagnostic_images/location_genotype_norm_pca.pdf",
   image = location_genotype_pca[["plot"]])

## ok, I have two weirdo samples which look very much like they are actually dlgn.
## These are sample IDs iprgc_66 and iprgc_130

loc_geno_nt <- normalize(v3_loc_geno, transform = "log2", convert = "cpm",
                         filter = TRUE, norm = "tmm")
## Removing 10156 low-count genes (15269 remaining).
## transform_counts: Found 42869 values equal to 0, adding 1 to the matrix.
location_genotype_tmm_pca <- plot_pca(loc_geno_nt)
pp(file = "01diagnostic_images/location_genotype_tmm_pca.pdf",
   image = location_genotype_tmm_pca[["plot"]])
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure

A random thought about these PCA plots, it might be worth while to add a panel below the legend with the sample numbers per condition/batch.

Of course, the same information is provided in a more fun fashion via my silly sankey function:

sample_sankey <- plot_meta_sankey(v3_loc_geno, color_choices = color_choices,
                                  factors = c("genotype_atb", "location_atb", "time_atb"))
## Warning: attributes are not identical across measure variables; they will be
## dropped
## Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## ℹ The deprecated feature was likely used in the ggsankey package.
##   Please report the issue at
##   <https://github.com/davidsjoberg/ggsankey/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
pp(file = "01diagnostic_images/design_sankey.pdf", image = sample_sankey[["plot"]])

12 A Short conversation with Rashmi

Rashmi came by and we discussed the samples a little. She suggested that is likely that we will need to exclude the 202205 samples, these may be identified by a few ways, most easily I think via the ‘project_ah’ column, they are the 021_1 samples.

My sense was that she concurred with my interpretation of the umi deduplication, so I will continue using the deduplicated results exclusively, at least for now.

13 Melanopsin Sanity Check

One of Theresa’s first checks was wisely for melanopsin. Let us repeat a version of this:

opn4_exprs <- data.frame(combined = colData(loc_geno_nt)[["geno_loc_atb"]],
                         location = colData(loc_geno_nt)[["location_atb"]],
                         genotype = colData(loc_geno_nt)[["genotype_atb"]],
                         opn = assay(loc_geno_nt)["ENSMUSG00000021799", ])

groupedstats::grouped_summary(opn4_exprs, location, opn)
## # A tibble: 3 × 16
##   location skim_type skim_variable missing complete   mean    sd   min   p25
##   <fct>    <chr>     <chr>           <int>    <dbl>  <dbl> <dbl> <dbl> <dbl>
## 1 dlgn     numeric   opn                 0        1 0.0849 0.195     0  0   
## 2 retina   numeric   opn                 0        1 2.82   2.10      0  1.59
## 3 scn      numeric   opn                 0        1 0.0450 0.142     0  0   
## # ℹ 7 more variables: median <dbl>, p75 <dbl>, max <dbl>, n <int>,
## #   std.error <dbl>, mean.conf.low <dbl>, mean.conf.high <dbl>
opn4_location <- ggstatsplot::ggbetweenstats(data = opn4_exprs, x = location, y = opn)
## loading tbb library '/lab/singularity/iprgcv2/data/renv/library/linux-debian-forky/R-4.5/x86_64-pc-linux-gnu/RcppParallel/lib/libtbb.so.2'
## loading tbb library '/lab/singularity/iprgcv2/data/renv/library/linux-debian-forky/R-4.5/x86_64-pc-linux-gnu/RcppParallel/lib/libtbbmalloc.so.2'
pp(file = "images/ggbetween_location.pdf", image = opn4_location)

opn4_genotype <- ggstatsplot::ggbetweenstats(data = opn4_exprs, x = genotype, y = opn)
pp(file = "images/ggbetween_location.pdf", image = opn4_genotype)

opn4_combined <- ggstatsplot::ggbetweenstats(data = opn4_exprs, x = combined, y = opn)
pp(file = "images/ggbetween_combined.pdf", image = opn4_combined)

ok, so I plotted the question a bit differently, but got the same answer.

Here is the text of Theresa’s notebook following this analysis:

“Ugh oh, looks like there is at least one retina KO sample that has some melanopsin expression in it. Turns out ipRGC_07 is a bad egg which is supposed to be a KO but has melanopsin expression. It’s friends which were pooled from the same mice are iprgc_06 and iprgc_08, so we need to exclude all these samples.”

I am also seeing some knockout expression with some caveats: I do not have the affected samples in my dataset (iprgc_07) and the levels I am seeing are quite low – I will look in IGV to double check, but I strongly suspect that these are some piddly reads near the UTRs.

Onward!

14 PCA plots

14.1 PCA of all genes by location

Theresa’s first pca was of log2 cpm values. I might add quantile/tmm to this?

v3_location <- set_conditions(mm38_hisat_v3, fact = "location_atb") |>
  set_batches(fact = "genotype_atb") |>
  set_colors(color_choices[["location"]])
## The numbers of samples by condition are:
## 
##   dlgn retina    scn 
##     23     23     19
## Setting colors with no pre-defined colors, using the Dark2 palette.
## The number of samples by batch are:
## 
## het  ko  wt 
##  21  18  26
v3_location_norm <- normalize(v3_location, filter = TRUE, norm = "quant",
                                   transform = "log2", convert = "cpm")
## Removing 10156 low-count genes (15269 remaining).
## transform_counts: Found 9347 values equal to 0, adding 1 to the matrix.
v3_location_pca <- plot_pca(v3_location_norm)
pp(file = "01diagnostic_images/v3_location_norm_pca.pdf", image = v3_location_pca)

Once again we see that samples iprgc_66 and iprgc_130 are likely actually DLGN and not SCN. I am therefore going to add a column to the sample sheet noting this, and remove them from the expressionset.

I will thus replot the data after removing those two. If we want to see what it looks like with the re-attributed locations, we can do so.

Theresa has a nice change to the PCA plotter in which she sets the alpha channel as an additional visual queue for a metadata factor…

mm38_hisat_v3 <- subset_se(mm38_hisat_v3, subset="sampleid!='iprgc_130'") |>
  subset_se(subset="sampleid!='iprgc_66'")
v3_location <- set_conditions(mm38_hisat_v3, fact = "location_atb") |>
  set_batches(fact = "genotype_atb") |>
  set_colors(color_choices[["location"]])
## The numbers of samples by condition are:
## 
##   dlgn retina    scn 
##     23     23     17
## Setting colors with no pre-defined colors, using the Dark2 palette.
## The number of samples by batch are:
## 
## het  ko  wt 
##  20  18  25
v3_location_norm <- normalize(v3_location, filter = TRUE, norm = "quant",
                                   transform = "log2", convert = "cpm")
## Removing 10162 low-count genes (15263 remaining).
## transform_counts: Found 8867 values equal to 0, adding 1 to the matrix.
filtered_location_pca <- plot_pca(v3_location_norm)
pp(file = "02filtered_images/filtered_location_pca.pdf", image = filtered_location_pca)

removed_sankey <- plot_meta_sankey(v3_location, color_choices = color_choices,
                                   factors = c("genotype_atb", "location_atb", "time_atb"))
## Warning: attributes are not identical across measure variables; they will be
## dropped
pp(file = "02filtered_images/filtered_sankey.pdf", image = removed_sankey[["plot"]])

Here is Theresa’s text, recall once again that I do not have some of these older samples (iprgc_62):

PC1 vs PC2 identifies retina vs axon is still the main component of variation. We do see though that in the PC2 direction, we see with the new samples added, we don’t see separation based on axonal targets (dLGN vs SCN). In the PC1 vs PC3 plot, we see that it’s PC3 where we start to see variation correlated with axonal compartment. Let’s look at PC1 vs PC2 colored by batch (when they were processed/sequenced) to see if that is what is contributing so much variation in PC2.

Side note: ipRGC 62 seems like an odd ball. This seems to me like it should have been a dLGN P08 sample. Is there any possibility this got mislabeled early on? I went back and double checked to see if all my processing is correct and it indeed was labeled an SCN P15 from the time I got the samples, and it is indeed.

15 DE

I now switched to Theresa’s document ‘WORKING_axonTRAP…’ and will start pulling sections from it. I am reasonably certain I have reasonably similar sample distributions, so I presume I can invoke similar/identical calls for DESeq and friends.

15.1 p8 retinas

In the block immediately before the DE analyses, Theresa created a subset expressionset of only p08 retinas. Thus this initial DE I assume will be used to subtract for the SCN/DLGN analyses that follow. (I guess I could read ahead and find out, but no! I want to be a blank slate)

Theresa’s primary workflow makes heavy use of DESeq2 (@loveModeratedEstimationFold2014) and sva (@leekSVAPackageRemoving2012). In some(most?) of Theresa’s invocations of the all_pairwise() function, she excludes the other methods that it performs. In this workbook, I left those methods on, thus we can evaluate the relative performance DESeq2 vs. some (all? I may have disabled EBSeq/dream because they were taking too long) of the following:

  • limma: (@ritchieLimmaPowersDifferential2015) (among other references) originally written for microarrays.
  • EdgeR: (@robinsonEdgeRBioconductorPackage2010), which shares many assumptions with DESeq2.
  • EBSeq: (@lengEBSeqEmpiricalBayes2013), because I have a soft spot for any Bayesian method.
  • Noiseq: (@tarazonaNOIseqRNAseqDifferential2011), which seeks to directly model variance in an RNASeq dataset and use that to improve the sensitivity of the result, much like:
  • Dream: (@hoffmanDreamPowerfulDifferential2020), written by the same authors (and uses very similar logic) as one of my favorite tools, variancePartition(@hoffmanVariancePartitionInterpretingDrivers2016).
mm38_p8_retina <- subset_se(mm38_hisat_v3, subset = "time_atb=='p08' & location_atb=='retina'")
mm_normal_p8_ret_de <- all_pairwise(mm38_p8_retina, model_svs = "svaseq",
                                    model_fstring = "~ 0 + condition", filter = TRUE)
## het_retina  ko_retina  wt_retina 
##          3          3          5
## Removing 12001 low-count genes (13424 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 2593 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## het_retina  ko_retina  wt_retina 
##          3          3          5
## conditions
## het_retina  ko_retina  wt_retina 
##          3          3          5
## conditions
## het_retina  ko_retina  wt_retina 
##          3          3          5

mm_normal_p8_ret_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 3 comparisons.

There seems to be a discrepency with previous iterations of this. Let us simplify to just doing deseq and find what is causing it. In my previous iteration, I got 3632 genes in the unique(c()) or het+ko.

deseq_only <- deseq_pairwise(mm38_p8_retina, model_svs = "svaseq",
                             model_fstring = default_fstring, filter = TRUE)
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
deseq_hetkeeper_genes <- deseq_only$all_tables$wt_retina_vs_het_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_kokeeper_genes <- deseq_only$all_tables$wt_retina_vs_ko_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_keepergenes <- unique(c(rownames(deseq_hetkeeper_genes),
                        rownames(deseq_kokeeper_genes)))
length(deseq_keepergenes)
## [1] 3632
deseq_pair_hetkeeper_genes <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_het_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_pair_kokeeper_genes <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_ko_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_pair_keepergenes <- unique(c(rownames(deseq_pair_hetkeeper_genes),
                        rownames(deseq_pair_kokeeper_genes)))
length(deseq_pair_keepergenes)
## [1] 3632

The following invocation performed by Theresa filters the wt/het comparison for only those genes which increased by at least 0.25 logFC with a significant adjusted p-value. I assume that this is to use the wt samples as a translational control for the ket/ko comparisons; I am therefore thinking that for my purposes, I will therefore separate the contrasts from all_pairwise do this in a stepwise fashion…

The block of code immediately following Theresa’s all_pairwise() invocation is a little confusing for me and warrants some explanation by me to me in the hopes that I do not misunderstand what is happening and the goals therein.

I think I can safely assume that the goal here is to pull out the IDs which increased in het with respect to wild type; even if by a small margin, as long as it is statistically significant vis a vis the adjusted p-value.

I am going to perform what I think is the same thing in a slightly different fashion so that I can share a copy of the results with whomever is interested. I will also repeat Theresa’s invocation and prove to myself that I understood and got the same answer.

wt_het_keeper <- list("het_vs_wt" = c("het_retina", "wt_retina"))
het_wt_table <- combine_de_tables(
  mm_normal_p8_ret_de, keepers = wt_het_keeper, label_column = label_column,
  excel = "03theresa_comparison_excel/het_retina_control.xlsx")
## Deleting the file 03theresa_comparison_excel/het_retina_control.xlsx before writing the tables.
## Looking for subscript invalid names, end of extract_keepers.
het_wt_table
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1 wt_retina_vs_het_retina-inverted         889           630         910
##   edger_sigdown limma_sigup limma_sigdown
## 1           650         828           583
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the UpSetR package.
##   Please report the issue at <https://github.com/hms-dbmi/UpSetR/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## ℹ The deprecated feature was likely used in the UpSetR package.
##   Please report the issue at <https://github.com/hms-dbmi/UpSetR/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Plot describing unique/shared genes in a differential expression table.

wanted_sig <- extract_significant_genes(
  het_wt_table, lfc = 0.25, according_to = "deseq",
  excel = "03theresa_comparison_excel/het_retina_control-sig.xlsx")
## Deleting the file 03theresa_comparison_excel/het_retina_control-sig.xlsx before writing the tables.
wanted_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 0.25 adj P cutoff: 0.05
##           deseq_up deseq_down
## het_vs_wt     2640       2311

wanted_het_increased <- wanted_sig[["deseq"]][["ups"]][["het_vs_wt"]]
increased_het_genes <- rownames(wanted_het_increased)

Here are Theresa’s next lines:

mm_de_normal_p8_ret <- mm_normal_p8_ret_de
hetkeeper_genes <- mm_de_normal_p8_ret$deseq$all_tables$wt_retina_vs_het_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
kokeeper_genes <- mm_de_normal_p8_ret$deseq$all_tables$wt_retina_vs_ko_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
keepergenes <- unique(c(rownames(hetkeeper_genes),
                        rownames(kokeeper_genes)))
## We know a priori that Opn4 is ENSMUSG00000021799
## I do not expect to see it in this set, it should be higher in wt
## retina vs ko retina by a significant margin.
"ENSMUSG00000021799" %in% keepergenes
## [1] TRUE
## Oooohhh but it _is_ higher in het vs. wt, as we saw in
## the violin plot earlier.

I think Rashmi made a compelling point which illustrates why we likely should expect the expression of Opn4 to significantly higher in the heterozygotes vs wild-type:

  1. Recall that the assay is using the immunopurification to extract the RNAs.
  2. The wt samples do not have the cre recombinase and therefore no HA and therefore everything we observe is due to non-specific binding.
  3. The set of genes observed due to non-specific binding is different than het/ko (presumably a larger number of relatively small values), therefore the divisor performed in the cpm is likely relativly large resulting in normalized values getting shifted down to some degree.
  4. On the other hand, the set of genes observed in het/ko are more likely to be only the specific binders and therefore smaller (I can test this) resulting in a smaller divisor and slight shifting up in the cpm values.

This makes me wonder if any normalization methods exist which do something like multiply the values by some value related to the proportion of observed genes; and/or if this is a good/bad/indifferent idea.

Also, just a note for me to remember: RPL22, not RPS22, for some reason I keep thinking the small subunit.

15.2 Prove I understood

hetkeeper_genes <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_het_retina |>
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)
testthat::expect_true(nrow(hetkeeper_genes) == length(increased_het_genes))
taa_keepers <- sort(rownames(hetkeeper_genes))
atb_keepers <- sort(increased_het_genes)
testthat::expect_equal(taa_keepers, atb_keepers)

Yay! I can read! Now let us repeat for the KO vs wt

wt_ko_keeper <- list("ko_vs_wt" = c("ko_retina", "wt_retina"))
ko_wt_table <- combine_de_tables(
  mm_normal_p8_ret_de, keepers = wt_ko_keeper, label_column = label_column,
  excel = "03theresa_comparison_excel/ko_retina_control.xlsx")
## Deleting the file 03theresa_comparison_excel/ko_retina_control.xlsx before writing the tables.
## Looking for subscript invalid names, end of extract_keepers.
ko_wt_table
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1 wt_retina_vs_ko_retina-inverted         985           528         985
##   edger_sigdown limma_sigup limma_sigdown
## 1           568         942           517
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

wanted_sig <- extract_significant_genes(
  ko_wt_table, lfc = 0.25, according_to = "deseq",
  excel = "03theresa_comparison_excel/ko_retina_control-sig.xlsx")
## Deleting the file 03theresa_comparison_excel/ko_retina_control-sig.xlsx before writing the tables.
wanted_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 0.25 adj P cutoff: 0.05
##          deseq_up deseq_down
## ko_vs_wt     2875       2667

wanted_ko_increased <- wanted_sig[["deseq"]][["ups"]][["ko_vs_wt"]]
increased_ko_genes <- rownames(wanted_ko_increased)
length(increased_ko_genes)
## [1] 2875

The next thing performed in Theresa’s document is a unique(concatenation of these two gene groups), thus sucking up every gene which was significantly higher in either the knockout or heterzyous samples with respect to wild-type.

This was followed by a couple of merge operations of a little bit of the annotation data; I am not sure I understand the goal yet…

Here is her code. I copied the annotation ‘mgi_symbol’ column to ‘external_synonym’ so that I need not change any of her code. I am assuming this is the appropriate column of interest, I do not know this for certain, but it seems quite likely.

While I am at it, here is the set_sig_limma() function from Theresa’s helpers.R

set_sig_limma <- function(limma_tbl, factors = NULL) {
  if (is.null(factors)) {
    #set significance for plotting colors
    limma_tbl$Significance <- NA
    limma_tbl[abs(limma_tbl$logFC) <= 1.0 | limma_tbl$adj.P.Val > 0.05, "Significance"] <- "Not \nEnriched"
    limma_tbl[limma_tbl$logFC >= 1.0  & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- "Disease \nUpregulated"
    limma_tbl[limma_tbl$logFC <= -1.0  & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- "Disease \nDownregulated"
    limma_tbl$Significance <- factor(limma_tbl$Significance, levels = c("Upregulated", "Downregulated",  "Not \nEnriched"))
  } else {
    limma_tbl$Significance <- NA
    limma_tbl[abs(limma_tbl$logFC) <= 1.0 | limma_tbl$adj.P.Val >= 0.05, "Significance"] <- "Not \nEnriched"
    if(nrow(limma_tbl[limma_tbl$logFC >= 1.0  & limma_tbl$adj.P.Val <= 0.05, ]) != 0) {
      limma_tbl[limma_tbl$logFC >= 1.0  & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- factors[1]
    }
    if (nrow(limma_tbl[limma_tbl$logFC <= -1.0  & limma_tbl$adj.P.Val <= 0.05, ]) != 0) {
      limma_tbl[limma_tbl$logFC <= -1.0  & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- factors[2]
    }
    limma_tbl$Significance <- factor(limma_tbl$Significance, levels = c(factors,  "Not \nEnriched"))
  }
  return(limma_tbl)
}

15.2.1 Combining het/wt and ko/wt

keepergenes <- unique(c(rownames(hetkeeper_genes), rownames(kokeeper_genes)))
length(keepergenes)
## [1] 3632
annots_to_merge <- mm_annot_genes |>
  dplyr::select(ensembl_gene_id, ensembl_transcript_id, symbol) |>
  filter(ensembl_gene_id %in%
           rownames(mm_de_normal_p8_ret$deseq$all_tables$ko_retina_vs_het_retina)) |>
  distinct()
mm_de_normal_p8_ret$deseq$all_tables$ko_retina_vs_het_retina <- merge(
  mm_de_normal_p8_ret$deseq$all_tables$ko_retina_vs_het_retina, annots_to_merge,
  by.x = "row.names", by.y = "ensembl_gene_id", all.x = TRUE)
df <- mm_de_normal_p8_ret$deseq$all_tables$ko_retina_vs_het_retina |>
  dplyr::mutate(logFC = -logFC) |>
  set_sig_limma(factors = c("Het Enriched", "KO Enriched"))
rownames(df) <- df[["Row.names"]]
df[["Row.names"]] <- NULL

My version of the above task makes use of the excludes option of combine_de_tabes. Given the set of unique gene IDs increased in the het/ko, I can ask to exlude anything not in that set. I could also have more parsimoniously directly excluded any gene ID increased in the wt samples. But, Theresa already provided the code to do the former, so it will be less typing/opportunity for silly mistakes to just do that.

both_increased_genes <- unique(c(increased_het_genes, increased_ko_genes))
## arbitrairly grab all genes from one of my data structures.
all_genes <- rownames(exprs(mm38_hisat_v3))
exclude_idx <- all_genes %in% both_increased_genes
summary(exclude_idx)
##    Mode   FALSE    TRUE 
## logical   21793    3632

My April 2025 version of this shows 21,793 and 3,632 genes in this set. Is that still true? (As of 20260311, it is!)

exclude_increased_genes <- all_genes[exclude_idx]
retina_keepers <- list(
  "het_vs_wt" = c("het_retina", "wt_retina"),
  "ko_vs_wt" = c("ko_retina", "wt_retina"),
  "ko_vs_het" = c("ko_retina", "het_retina"))
## A reminder to myself: there is also a parameter 'wanted_genes'
## which does effectively the same thing as excludes in this context;
## excludes was originally written to allow flexible, keyword-based
## exclusion.
p8_retina_tables <- combine_de_tables(
  mm_normal_p8_ret_de, keepers = retina_keepers,
  wanted_genes = both_increased_genes, label_column = label_column,
  excel = glue("03theresa_comparison_excel/p8_retina_kept_genes_increased_in_wt_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
p8_retina_tables
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1 wt_retina_vs_het_retina-inverted         889             2         888
## 2  wt_retina_vs_ko_retina-inverted         985             1         977
## 3          ko_retina_vs_het_retina          21            69          22
##   edger_sigdown limma_sigup limma_sigdown
## 1             2         821             0
## 2             1         933             0
## 3            77           1             1
## Plot describing unique/shared genes in a differential expression table.

p8_retina_sig <- extract_significant_genes(
  p8_retina_tables, according_to = "deseq",
  excel = glue("03theresa_comparison_excel/p8_retina_kept_genes_increased_in_wt_sig-v{ver}.xlsx"))
p8_retina_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## het_vs_wt      889          2
## ko_vs_wt       985          1
## ko_vs_het       21         69

opposite_p8_retina_tables <- combine_de_tables(
  mm_normal_p8_ret_de, keepers = retina_keepers,
  excludes = both_increased_genes, label_column = label_column,
  excel = glue("03theresa_comparison_excel/p8_retina_removed_genes_increased_in_wt_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
opposite_p8_retina_tables
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1 wt_retina_vs_het_retina-inverted           0           628          22
## 2  wt_retina_vs_ko_retina-inverted           0           527           8
## 3          ko_retina_vs_het_retina          67            68          81
##   edger_sigdown limma_sigup limma_sigdown
## 1           648           7           583
## 2           567           9           517
## 3            93           0             0
## Plot describing unique/shared genes in a differential expression table.

opposite_p8_retina_sig <- extract_significant_genes(
  p8_retina_tables, according_to = "deseq",
  excel = glue("03theresa_comparison_excel/p8_retina_removed_genes_increased_in_wt_sig-v{ver}.xlsx"))
opposite_p8_retina_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## het_vs_wt      889          2
## ko_vs_wt       985          1
## ko_vs_het       21         69

16 SCN Het vs KO

It is only now that I realized we are splitting the data by location for each set of comparisons. I think that, left to my own devices, I would prefer to keep the input data structure intact, perform the somewhat larger number of contrasts, and then split up the results. Ideally this will slightly improve the fidelity of the results returned by DESeq2 and friends. But, I will run the state of Theresa’s notebook with as few changes as possible first, then add this.

16.1 PCA

I am going to skip this PCA plot for a couple of reasons: I already did a superset of it, and the subset Theresa performed is not valid given the set of samples included in my sample sheet, and figuring out the actually corresponding subset will take me forever… In addition, I want to use my mm38_hisat_v3 for everything…

mm38_subset <- subset_se(
  mm38_hisat,
  subset = "(batch == '4' | batch == '5' | batch == '6') & time == 'p08' & location == 'scn' | sampleid == 'iprgc_03'")
mm38_norm <- normalize(mm38_subset, filter = TRUE, convert = "cpm",
                            transform = "log2", batch = "svaseq")
mm38_norm <- set_batches(mm38_norm, fact = "location")
mm38_norm <- set_conditions(mm38_norm, fact = "genotype")
pca_norm <- plot_pca(mm38_norm, max_overlaps = 70)
pca_norm$plot

Instead I will simplify the subset and see what happens…

scn_samples <- subset_se(mm38_hisat_v3,
                           subset = "location_atb == 'scn'") |>
  set_batches(fact = "location_atb") |>
  set_conditions(fact = "genotype_atb", colors = color_choices[["genotype"]])
## The number of samples by batch are:
## 
## scn 
##  17
## The numbers of samples by condition are:
## 
## het  ko  wt 
##   6   6   5
scn_norm <- normalize(scn_samples, filter = TRUE, convert = "cpm",
                           transform = "log2", batch = "svaseq")
## Removing 11109 low-count genes (14316 remaining).
## transform_counts: Found 919 values less than 0.
## transform_counts: Found 919 values equal to 0, adding 1 to the matrix.
scn_norm_pca <- plot_pca(scn_norm)
scn_norm_pca
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by het, ko, wt
## Shapes are defined by scn.

17 Filtering out non-specific genes and examining the results

The following is a copy/paste from Theresa containing the remaining tasks she performed and will provide the template for implementation of the final tasks.

This picks up with the lines from her notebook immediately following the invocation of ‘set_sig_limma(factors = c(“Het Enriched” …’.

For all of the remaining blocks I will copy in her code, turn off its evaluation, run the blocks manually, compare them to her notebook output, then enable each block as I ensure I understand it.

I will likely therefore introduce some small formatting changes and add some additional GSEA/enrichment tasks once the non-specific filtering is complete.

17.1 Important 202608 note

IMy problems with ensembl have resulted in me loading the transcript IDs rather than the MGI symbols. I hope to resolve this as soon as possible. For the moment I just want to make certain that all of the data points match previous revisions of the analysis.

head(df)
##                    baseMean    logFC   lfcSE    stat P.Value adj.P.Val
## ENSMUSG00000000001   377.00  0.33610 0.14370 -2.3390 0.01936   0.09630
## ENSMUSG00000000028    16.77  0.04385 0.40800 -0.1075 0.91440   1.00000
## ENSMUSG00000000037    26.56 -0.25690 0.38940  0.6596 0.50950   0.68910
## ENSMUSG00000000056   928.60  0.11350 0.09364 -1.2120 0.22550   0.43180
## ENSMUSG00000000058    55.20  0.95970 0.40190 -2.3880 0.01694   0.08867
## ENSMUSG00000000078   247.70  0.11840 0.17030 -0.6952 0.48690   0.67140
##                    deseq_num deseq_den ensembl_transcript_id    symbol
## ENSMUSG00000000001  8.435105  8.771179    ENSMUST00000000001     Gnai3
## ENSMUSG00000000028  4.017544  4.061396    ENSMUST00000000028 undefined
## ENSMUSG00000000037  4.378935  4.122052    ENSMUST00000019101 undefined
## ENSMUSG00000000056  9.972203 10.085705    ENSMUST00000103015      Narf
## ENSMUSG00000000058  5.749838  6.709501    ENSMUST00000000058      Cav2
## ENSMUSG00000000078  7.889756  8.008128    ENSMUST00000000080      Klf6
##                      Significance
## ENSMUSG00000000001 Not \nEnriched
## ENSMUSG00000000028 Not \nEnriched
## ENSMUSG00000000037 Not \nEnriched
## ENSMUSG00000000056 Not \nEnriched
## ENSMUSG00000000058 Not \nEnriched
## ENSMUSG00000000078 Not \nEnriched
df <- df |>
  filter(rownames(df) %in% keepergenes)
labels_ups <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) >= 1.0) |>
  arrange(logFC) |>
  head(n = 9)
labels_downs <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) >= 1.0) |>
  arrange(-logFC) |>
  head(n = 11)
labels <- rbind(labels_ups, labels_downs)
res_tbl <- df
DEplot <- ggplot(res_tbl, aes(x = logFC, y = -log10(adj.P.Val), label = symbol)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1, 1)) +
  geom_hline(yintercept = -log10(0.05)) +
  theme_classic(base_size = 20) +
  xlab("log2(FC)") +
  ylab("-log10(p-value)") +
  theme(legend.position = "right") +
  scale_color_manual(values = c("#F8766D", "#00BFC4", "Grey")) +
  ## nudge_x = -0.5,
  ## nudge_y = 3, max.overlaps = 15) +
  xlim(c(-3, 6))

pp(file = "03theresa_comparison_images/p08_retina_DE_1312024.pdf",
   image = DEplot)
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).

write_xlsx(df, excel = "excel/retinahet_vs_retinako_WTfiltered.xlsx")
## Deleting the file excel/retinahet_vs_retinako_WTfiltered.xlsx before writing the tables.
## write_xlsx() wrote excel/retinahet_vs_retinako_WTfiltered.xlsx.
## The cursor is on sheet first, row: 3635 column: 13.

17.2 How many ups/downs

ko_enriched <- df |>
  filter(Significance == "KO Enriched")
nrow(ko_enriched)
## [1] 21
het_enriched <-  df |>
  filter(Significance == "Het Enriched")
nrow(het_enriched)
## [1] 69

17.3 category enrichment/GSEA

res_tbl[["gene_id"]] <- rownames(res_tbl)
regulated_genes <- res_tbl |>
  dplyr::filter(adj.P.Val <= 0.05) |>
  arrange(logFC) |>
  dplyr::select(gene_id, logFC, adj.P.Val, symbol, Significance) |>
  dplyr::filter(abs(logFC) >= 1.0)
## gsea_result_ko <- gost(query = ko_genes$external_synonym,
##                        organism = "mmusculus",
##                        evcodes = TRUE,
##                        ordered_query = TRUE)
gsea_result_het <- gost(query = het_enriched$symbol,
                        organism = "mmusculus",
                        evcodes = TRUE,
                        ordered_query = TRUE)
##gsea_result_alldysregulated <- gost(query = alldysregulated_genes$external_synonym,
##                                    organism = "mmusculus",
##                                    evcodes = TRUE,
##                                    ordered_query = TRUE)
summary(gsea_result_het)
##        Length Class      Mode
## result 16     data.frame list
## meta    5     -none-     list

I have a function in my package which seeks to make gProfiler queries a bit more complete and easy. Let us see how similar the result is…

rownames(alldysregulated_genes) <- alldysregulated_genes[["Row.names"]]
alldysregulated_genes[["Row.names"]] <- NULL

het_gp <- simple_gprofiler(rownames(alldysregulated_genes),
                           species = "mmusculus",
                           excel = glue("excel/het_gprofiler-v{ver}.xlsx"))
het_gp
enrichplot::dotplot(het_gp[["BP_enrich"]])
gp_pair <- enrichplot::pairwise_termsim(het_gp[["BP_enrich"]])
enrichplot::emapplot(gp_pair)
enrichplot::ssplot(gp_pair)
enrichplot::treeplot(gp_pair)
upsetplot(het_gp[["BP_enrich"]])

enrichplot::dotplot(het_gp[["REAC_enrich"]])
gp_pair <- enrichplot::pairwise_termsim(het_gp[["REAC_enrich"]])
enrichplot::emapplot(gp_pair)
enrichplot::ssplot(gp_pair)
enrichplot::treeplot(gp_pair)
upsetplot(het_gp[["REAC_enrich"]])

I make a somewhat arbitrary distinction between the concepts of over-enrichment analyses and GSEA: the former (as performed by gprofiler) (@raudvereProfilerWebServer2019) seeks to find groups of genes overrepresented in GO/reactome/etc. These groups of genes are taken exclusively from the top-n/bottom-n genes with respect to fold-change between conditions of interest; in this case most different than wt in the p08 retina ko or het samples.

With that in mind, I can invoke a similar function using the full table of DE results to get what I call the GSEA result using clusterProfiler (@yuIntroductionBiomedicalKnowledge). In the following block I will use the ‘all_cprofiler’ function on the data structures named ‘p8_retina_tables’ and ‘opposite_p8_retina_tables’ in order to get these GSEA results for each contrast performed (het/wt, ko/wt, het/ko). I will follow that up with ‘all_gprofiler’ which does the same, but uses gProfiler’s enrichment analyses (it will therefore include what we just looked at).

p08_retina_all_cp <- all_cprofiler(
  p8_retina_sig, p8_retina_tables, orgdb = "org.Mm.eg.db", orgdb_from = orgdb_from,
  excel = "03theresa_comparison_excel/cprofiler_p08_retina.xlsx")

enrichplot::dotplot(p08_retina_all_cp[["ko_vs_het_up"]][["go_data"]][["MF_enrich"]],
                    showCategory = go_categories)

p08_topn_gsea <- plot_topn_gsea(p08_retina_all_cp)
## Starting: het_vs_wt_up.
## Starting: het_vs_wt_down.
## Starting: ko_vs_wt_up.
## Starting: ko_vs_wt_down.
## Starting: ko_vs_het_up.
## Starting: ko_vs_het_down.
pp(file = "03theresa_comparison_images/gsea_p08_retina_ko_vs_het_top_hit.pdf",
   image = print(p08_topn_gsea[["GO_ko_vs_het_up"]][[1]]))

p08_topn_gsea[["GO_ko_vs_het_up"]][[2]]

p08_topn_gsea[["GO_ko_vs_het_up"]][[3]]

p08_topn_gsea[["GO_ko_vs_het_up"]][[4]]

p08_topn_gsea[["GO_ko_vs_het_up"]][[5]]

pp(file = "03theresa_comparison_images/gsea_p08_retina_het_vs_wt_top_hit.pdf",
   image = print(p08_topn_gsea[["GO_het_vs_wt_up"]][[1]]))

#gsea_ko <-  gsea_result_ko[["result"]] |>
#    select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
#    arrange(desc(recall)) |>
#    head(n = 10)
#  gsea_plots_ko <- ggplot(gsea_ko, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
#  geom_bar(stat = "identity")+
#  scale_fill_continuous(low = "blue", high = "red") +
#  theme_bw()+
#  ylab("") +
#  xlab("GSEA Score")
gsea_het <-  gsea_result_het[["result"]] |>
  dplyr::select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 10)
gsea_plots_het <- ggplot(gsea_het, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over Representation Score")
pp(file = "03theresa_comparison_images/GSEA_p08_axontrap_retinahet_upregulated_vs_retinako.pdf")
gsea_plots_het
plotted <- dev.off()
gsea_plots_het

gsea_all <-  gsea_result_alldysregulated[["result"]] |>
  dplyr::select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 10)
gsea_plots_all <- ggplot(gsea_all, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over Representation Score")

pp(file = "images/GSEA_p08_retina_axontrap_alldysregulatedgenes.pdf")
gsea_plots_all
plotted <- dev.off()

18 Library sizes post-deduplication

Theresa’s next operation was to perform libsize/nonzero plots. I already did the pre/post deduplication nonzero, here is the analagous libsize.

v2 is pre-deduplication and v3 is post.

plot_libsize(mm38_hisat_v2)
## Library sizes of 65 samples, 
## ranging from 3,717,242 to 24,538,069.

post_filter_nonzero <- plot_libsize(mm38_hisat_v3, text = FALSE)
pp(file = "01diagnostic_images/post_all_filteres_nonzero.pdf")
post_filter_nonzero[["plot"]]
plotted <- dev.off()
post_filter_nonzero
## Library sizes of 63 samples, 
## ranging from 1,264,475 to 10,979,038.

I am a bit concerned about some of these library sizes post-deduplication.

Let us look at the relationship between reads and duplication, which I assume will be relatively linear.

dedup_query <- colData(mm38_hisat_v3)[, c("hisat_genome_single_all", "umi_dedup_pct_reads")]
test_plot <- plot_linear_scatter(dedup_query, loess = TRUE)
## Warning in plot_linear_scatter(dedup_query, loess = TRUE): Model type robust
## failed, falling back to a default lm.
pp(file = "01diagnostic_images/deduplication_vs_hisat_scatter.pdf", image = test_plot[["scatter"]])
## `geom_smooth()` using formula = 'y ~ x'
## Warning: The following aesthetics were dropped during statistical transformation:
## label.
## ℹ This can happen when ggplot fails to infer the correct grouping structure
##   in the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?
## `geom_smooth()` using formula = 'y ~ x'
## Warning: The following aesthetics were dropped during statistical transformation:
## label.
## ℹ This can happen when ggplot fails to infer the correct grouping structure
##   in the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?

Theresa also produced a density/sample plot, that might prove quite useful for these due to their significantly larger variance across samples (due to deduplication).

pp(file = "01diagnostic_images/sample_density.pdf")
mm38_density <- plot_density(loc_geno_nt)
mm38_density[["plot"]] +
  theme(legend.position = "none")
plot_boxplot(loc_geno_nt)
## Plot describing the gene distribution from a dataset.
dev.off()
## png 
##   2
mm38_density[["plot"]] +
  theme(legend.position = "none")

box <- plot_boxplot(loc_geno_nt)
pp(file = "01diagnostic_images/sample_boxplot.pdf", image = box)

There is some difference across sample densities, but it is not too crazytown.

19 Diverging a little

At this point in the document I read ahead a bit and came to the conclusion that it repeats the above logic of taking the union of wt comparisons to remove genes from the appropriate het/ko or p15/p08 or location comparisons. This seems quite reasonable to me, but I would prefer to not separate all the data, so I will attempt to duplicate and slightly streamline this logic on the full dataset. Thus I am going to skip down to the end and attempt to implement this.

19.1 DE

Note: The following few blocks are all copy/pasted directly from Theresa’s notebook and are not evaluated because they are performed almost identically later but with slightly different logic/orders.

mm_de_normal_p8_scn <- all_pairwise(mm38_subset, model_batch = "svaseq",
                                    parallel = FALSE, do_ebseq = FALSE, do_basic = FALSE,
                                    do_dream = FALSE, do_noiseq = FALSE, do_edger = FALSE,
                                    filter = TRUE)
annots_to_merge <- mm_annot |>
  select(ensembl_gene_id, external_synonym) |>
  filter(ensembl_gene_id %in% rownames(mm_de_normal_p8_scn$deseq$all_tables$ko_scn_vs_het_scn)) |>
  distinct()
mm_de_normal_p8_scn$deseq$all_tables$ko_scn_vs_het_scn <- merge(
  mm_de_normal_p8_scn$deseq$all_tables$ko_scn_vs_het_scn,
  annots_to_merge, by.x = 0, by.y = "ensembl_gene_id", all.x = TRUE)
hetkeeper_genes <- mm_de_normal_p8_scn$deseq$all_tables$wt_scn_vs_het_scn |>
  filter(logFC <= -0.1 & adj.P.Val <= 0.05)
kokeeper_genes <- mm_de_normal_p8_scn$deseq$all_tables$wt_scn_vs_ko_scn |>
  filter(logFC <= -0.1 & adj.P.Val <= 0.05)
keepergenes <- unique(c(rownames(hetkeeper_genes), rownames(kokeeper_genes)))
df <- mm_de_normal_p8_scn$deseq$all_tables$koscn_vs_hetscn |>
  dplyr::mutate(logFC = -logFC) |>
  set_sig_limma(factors = c("Het Enriched",
                            "KO Enriched"))
df <- df |>
  filter(Row.names %in% keepergenes)
labels_ups <- df |>
  filter(abs(logFC) > 1) |>
  arrange(logFC) |>
  head(n = 1)
labels_downs <- df |>
  filter(abs(logFC) > 1) |>
  arrange(-logFC) |>
  head(n = 1)
labels <- rbind(labels_ups, labels_downs)
res_tbl <- df
DEplot <- ggplot(res_tbl, aes(x = logFC, y = -log10(adj.P.Val), label = external_synonym)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1, 1)) +
  geom_hline(yintercept = -log10(0.05)) +
  theme_classic(base_size = 20) +
  xlab("log2(FC)") +
  ylab("-log10(p-value)") +
  ## ggtitle(title, subtitle = subtitle) +
  theme(legend.position="right") +
  scale_color_manual(values=c("Het Enriched" = "#F8766D",
                              "KO Enriched" = "#00BFC4",
                              "Not\n Enriched" = "Grey")) +
  geom_label_repel(data=filter(df,
                               ## c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
                               external_synonym %in% labels$external_synonym),
                   ## nudge_x = -0.5,
                   nudge_y = 3, max.overlaps = 15) +
  ggtitle("SCN Het vs KO Translatome")

pp(file = "images/p08_scn_DE_1312024.pdf")
DEplot
plotted <- dev.off()

write_xlsx(df, excel = "excel/scnhet_vs_scnko_WTfiltered.xlsx")

19.2 How many ups/downs

ko_enriched <- df |>
  filter(Significance == "KO Enriched")

het_enriched <- df |>
  filter(Significance == "Het Enriched")

19.3 GSEA

ko_genes <- res_tbl |>
  filter(adj.P.Val <= 0.05) |>
  arrange(-abs(logFC)) |>
  select(Row.names, logFC, adj.P.Val, external_synonym, Significance) |>
  filter(logFC <= -1)

het_genes <- res_tbl |>
  filter(adj.P.Val <= 0.05) |>
  arrange(-abs(logFC)) |>
  select(Row.names, logFC, adj.P.Val, external_synonym, Significance) |>
  filter(logFC >= 1)

alldysregulated_genes <- res_tbl |>
  filter(adj.P.Val <= 0.05) |>
  arrange(logFC) |>
  select(Row.names, logFC, adj.P.Val, external_synonym, Significance) |>
  filter(abs(logFC) >= 1)

gsea_result_ko <- gost(query = ko_genes$external_synonym,
                       organism = "mmusculus",
                       evcodes = TRUE,
                       ordered_query = TRUE)

gsea_result_het <- gost(query = het_genes$external_synonym,
                        organism = "mmusculus",
                        evcodes = TRUE,
                        ordered_query = TRUE)

gsea_result_alldysregulated <- gost(query = alldysregulated_genes$external_synonym,
                                    organism = "mmusculus",
                                    evcodes = TRUE,
                                    ordered_query = TRUE)
gsea_ko <-  gsea_result_ko[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 10)
gsea_plots_ko <- ggplot(gsea_ko, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over enrichment Score")

gsea_het <-  gsea_result_het[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 10)
gsea_plots_het <- ggplot(gsea_het, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over enrichment Score")

gsea_all <-  gsea_result_alldysregulated[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 10)
gsea_plots_all <- ggplot(gsea_all, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over enrichment Score")

pp(file = "images/GSEA_p08_retina_axontrap_alldysregulatedgenes.pdf")
gsea_plots_all
plotted <- dev.off()

20 Het Retina vs Het SCN

mm38_subset2 <- subset_se(
  mm38_hisat,
  subset = "(batch == '4' | batch == '5' | batch == '6') & time == 'p08' & genotype != 'ko' & location != 'dlgn' | sampleid == 'iprgc_03'")

mm38_subset2 <- subset_se(mm38_subset2, subset = "sampleid != 'iprgc_89'")
mm38_subset2$design |>
  select(genotype, location) |>
  table()
mm38_norm2 <- normalize(mm38_subset2, filter=TRUE,
                             convert="cpm",
                             transform="log2", batch = "svaseq")

20.1 PCA

mm38_norm2 <- set_batches(mm38_norm2, fact = "location")
mm38_norm2 <- set_conditions(mm38_norm2, fact = "genotype")
pca_norm2 <- plot_pca(mm38_norm2, max_overlaps = 70)
pca_norm2$plot

20.2 DE

mm_de_subset2 <- all_pairwise(mm38_subset2,
                              model_batch="svaseq",
                              parallel=FALSE, do_ebseq=FALSE,
                              do_basic = FALSE, do_dream = FALSE,
                              do_noiseq = FALSE, do_edger = FALSE,
                              filter = TRUE)
retinakeeper_genes <- mm_de_subset2$deseq$all_tables$wt_retina_vs_het_retina |>
  filter(logFC <= -0.1 & adj.P.Val <= 0.05)

scnkeeper_genes <- mm_de_subset2$deseq$all_tables$wt_scn_vs_het_scn |>
  filter(logFC <= -0.1 & adj.P.Val <= 0.05)

keepergenes <- unique(c(rownames(retinakeeper_genes), rownames(scnkeeper_genes)))

annots_to_merge <- mm_annot |>
  select(ensembl_gene_id, external_synonym) |>
  filter(ensembl_gene_id %in% rownames(mm_de_subset2$deseq$all_tables$het_scn_vs_het_retina)) |>
  distinct()

mm_de_subset2$deseq$all_tables$het_scn_vs_het_retina <- merge(
  mm_de_subset2$deseq$all_tables$het_scn_vs_het_retina,
  annots_to_merge, by.x = 0,
  by.y = "ensembl_gene_id", all.x = TRUE)

df <- mm_de_subset2$deseq$all_tables$het_scn_vs_het_retina |>
  mutate(Significance = case_when(logFC <= -1.0 ~ "Retina Enriched",
                                  logFC >= 1.0 ~ "SCN Enriched",
                                  logFC > -1.0 & logFC < 1.0 ~ "Not\n Enriched"))

df <- df |>
  filter(Row.names %in% keepergenes)

scn_enriched <- df |>
  filter(adj.P.Val <= 0.05 & logFC >= 1.0) |>
  arrange(-logFC) |>
  select(Row.names, external_synonym, logFC, adj.P.Val) |>
  mutate(Significance = "SCN Enriched") |>
  filter(Row.names %in% rownames(scnkeeper_genes))

retina_enriched <- df |>
  filter(adj.P.Val <= 0.05 & logFC <= -1.0) |>
  arrange(logFC)  |>
  select(Row.names, external_synonym, logFC, adj.P.Val) |>
  mutate(Significance = "Retina Enriched") |>
  filter(Row.names %in% rownames(retinakeeper_genes))

notenriched <- df |>
  select(Row.names, external_synonym, logFC, adj.P.Val, Significance) |>
  filter(Row.names %in% c(rownames(retinakeeper_genes),
                          rownames(scnkeeper_genes))[duplicated(c(rownames(retinakeeper_genes),
                                                                  rownames(scnkeeper_genes)))]) |>
  filter(Significance == "Not\n Enriched")

df <- rbind(scn_enriched, retina_enriched, notenriched)
df <- df |>
  distinct()

## writexl::write_xlsx(df, path = "axonTRAP_DE_results_20240202/retinahet_vs_scn_het_WTfiltered.xlsx")
labels_ups <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1.0) |>
  arrange(logFC) |>
  head(n = 10)

labels_downs <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1.0) |>
  arrange(-logFC) |>
  head(n = 10)

labels <- rbind(labels_ups, labels_downs)

labels_requested <- c("Cdh10","Cdh12","Cdh13","Cdh18",
                      "Cdh7","Cdh8","Cdh9","Cntn3",
                      "Cntn4","Cntn5","Cntn6","Kirrel3",
                      "Nrxn1","Nrxn3","Sema3c","Sema6d",
                      "Tenm1","Tenm2","Tenm4")
res_tbl <- df
DEplot <- ggplot(res_tbl, aes(x = logFC, y = -log10(adj.P.Val), label = external_synonym)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1, 1)) +
  geom_hline(yintercept = -log10(0.05)) +
  theme_classic(base_size = 20) +
  xlab("log2(FC)") +
  ylab("-log10(p-value)") +
  ## ggtitle(title, subtitle = subtitle) +
  theme(legend.position="right") +
  scale_color_manual(values=c("Grey", "#F8766D", "#00BFC4")) +
  geom_label_repel(data=filter(df,
                               external_synonym %in% labels_requested),
                   ## c(labels$external_synonym, "Opn4")), #c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
                   ## nudge_x = -0.5,
                   nudge_y = 15, max.overlaps = 25)

#pp(file = "axonTRAP_Volcanoplots_20240202/p08_retinavsscnhet_DE_requested_genelabels_02052024.pdf")
DEplot
#dev.off()

20.3 How many ups/downs

scn_enriched <- df |>
  filter(adj.P.Val <= 0.05 & logFC >= 1.0) |>
  arrange(-logFC) |>
  select(Row.names, external_synonym, logFC, adj.P.Val, Significance)

retina_enriched <- df |>
  filter(adj.P.Val <= 0.05 & logFC <= -1.0) |>
  arrange(logFC)  |>
  select(Row.names, external_synonym, logFC, adj.P.Val, Significance)

scn_enriched
retina_enriched

df |>
  filter(Significance == "Not\n Enriched")

20.4 GSEA

gsea_result_scn <- gost(query = scn_enriched$external_synonym,
                        organism = "mmusculus", evcodes = TRUE,
                        ordered_query = TRUE, source = c("GO"))

gsea_result_ret <- gost(query = retina_enriched$external_synonym,
                        organism = "mmusculus", evcodes = TRUE,
                        ordered_query = TRUE, source = c("GO"))
gsea_scn <-  gsea_result_scn[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 20)
gsea_plots_scn <- ggplot(gsea_scn, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over enrichment Score")

pp(file = "images/GSEA_SCNhet_vs_retina_enriched_P08.pdf")
gsea_plots_scn
plotted <- dev.off()

gsea_ret <-  gsea_result_ret[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 20)
gsea_plots_ret <- ggplot(gsea_ret, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("Over enrichment Score")

pp(file = "images/GSEA_Retinahet_vs_SCN_enriched_P08.pdf")
gsea_plots_ret
plotted <- dev.off()

21 KO Retina vs KO SCN

mm38_subset3 <- subset_se(
  mm38_hisat,
  subset = "(batch == '4' | batch == '5' | batch == '6') & time == 'p08'  & genotype != 'het' & location != 'dlgn' | sampleid == 'iprgc_03'")

mm38_subset3 <- subset_se(mm38_subset3, subset = "sampleid != 'iprgc_86'")
mm38_subset3$design |>
  select(genotype, location) |>
  table()
mm38_norm3 <- normalize(mm38_subset3, filter=TRUE,
                             convert="cpm", transform="log2", batch = "svaseq")

21.1 PCA

mm38_norm3 <- set_batches(mm38_norm3, fact = "location")
mm38_norm3 <- set_conditions(mm38_norm3, fact = "genotype")
pca_norm3 <- plot_pca(mm38_norm3, max_overlaps = 70)
pca_norm3$plot

21.2 DE

mm_de_subset3 <- all_pairwise(mm38_subset3,
                              model_batch="svaseq",
                              parallel=FALSE, do_ebseq=FALSE,
                              do_basic = FALSE, do_dream = FALSE,
                              do_noiseq = FALSE, do_edger = FALSE,
                              filter = TRUE)

retinakeeper_genes <- mm_de_subset3$deseq$all_tables$wtretina_vs_koretina |>
  filter(logFC <= -1.0 & adj.P.Val <= 0.05)

scnkeeper_genes <- mm_de_subset3$deseq$all_tables$wtscn_vs_koscn |>
  filter(logFC <= -1.0 & adj.P.Val <= 0.05)

keepergenes <- unique(c(rownames(retinakeeper_genes), rownames(scnkeeper_genes)))

annots_to_merge <- mm_annot |>
  select(ensembl_gene_id, external_synonym) |>
  filter(ensembl_gene_id %in% rownames(mm_de_subset3$deseq$all_tables$ko_scn_vs_ko_retina)) |>
  distinct()

mm_de_subset3$deseq$all_tables$ko_scn_vs_ko_retina <- merge(
  mm_de_subset3$deseq$all_tables$ko_scn_vs_ko_retina,
  annots_to_merge, by.x = 0,
  by.y = "ensembl_gene_id", all.x = TRUE)

df <- mm_de_subset3$deseq$all_tables$ko_scn_vs_ko_retina |>
  mutate(Significance = case_when(logFC <= -1 ~ "Retina Enriched",
                                  logFC >= 1 ~ "SCN Enriched",
                                  logFC > -1 & logFC < 1 ~ "Not\n Enriched"))

df <- df |>
  filter(Row.names %in% keepergenes)

scn_enriched <- df |>
  filter(adj.P.Val <= 0.05 & logFC >= 1) |>
  arrange(-logFC) |>
  select(Row.names, external_synonym, logFC, adj.P.Val) |>
  mutate(Significance = "SCN Enriched") |>
  filter(Row.names %in% rownames(scnkeeper_genes))

df |>
  filter(adj.P.Val <= 0.05 & logFC <= -1) |>
  arrange(logFC)  |>
  select(Row.names, external_synonym, logFC, adj.P.Val) |>
  mutate(Significance = "Retina Enriched") |>
  filter(Row.names %in% rownames(retinakeeper_genes)) -> retina_enriched

notenriched <- df |>
  select(Row.names, external_synonym, logFC, adj.P.Val, Significance) |>
  filter(Row.names %in% c(rownames(retinakeeper_genes),
                          rownames(scnkeeper_genes))[duplicated(c(rownames(retinakeeper_genes),
                                                                  rownames(scnkeeper_genes)))])

df <- rbind(scn_enriched, retina_enriched, notenriched)
labels_ups <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1) |>
  arrange(logFC) |>
  head(n = 10)

labels_downs <- df |>
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1) |>
  arrange(-logFC) |>
  head(n = 10)

labels <- rbind(labels_ups, labels_downs)
## wanted_column <- "Significance"

res_tbl <- df
DEplot <- ggplot(res_tbl, aes(x = logFC, y = -log10(adj.P.Val), label = external_synonym)) +
  geom_point(aes(colour = Significance), size = 4) +
  ## geom_point(aes(colour = !!sym(wanted_column)), size = 4) +
  geom_vline(xintercept = c(-1, 1)) +
  geom_hline(yintercept = -log10(0.05)) +
  theme_classic(base_size = 20) +
  xlab("log2(FC)") +
  ylab("-log10(p-value)") +
  ## ggtitle(title, subtitle = subtitle) +
  theme(legend.position = "right") +
  scale_color_manual(values = c("Grey", "#F8766D", "#00BFC4")) +
  geom_label_repel(data = filter(
    df, external_synonym %in% c(labels$external_synonym, "Opn4")),
    ## c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
    ## nudge_x = -0.5,
    nudge_y = 10, max.overlaps = 25)

pp(file = "images/p08_retinavsscnko_DE_1312024.pdf")
DEplot
plotted <- dev.off()

21.3 How many ups/downs

scn_enriched
retina_enriched
notenriched |>
  filter(Significance == "Not\n Enriched")

21.4 GSEA

gsea_result_scn <- gost(query = scn_enriched$external_synonym,
                        organism = "mmusculus",
                        evcodes = TRUE,
                        ordered_query = TRUE,
                        source = c("GO"))

gsea_result_ret <- gost(query = retina_enriched$external_synonym,
                        organism = "mmusculus",
                        evcodes = TRUE,
                        ordered_query = TRUE,
                        source = c("GO"))
gsea_scn <-  gsea_result_scn[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 20)
gsea_plots_scn <- ggplot(gsea_scn, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("GSEA Score")

pp(file = "images/GSEA_SCNko_enriched_vs_retina_P08.pdf")
gsea_plots_scn
plotted <- dev.off()

gsea_ret <-  gsea_result_ret[["result"]] |>
  select(term_name, p_value, term_size, intersection_size, recall, source, intersection) |>
  arrange(desc(recall)) |>
  head(n = 20)
gsea_plots_ret <- ggplot(gsea_ret, aes(x = recall, y = reorder(term_name, recall), fill = p_value)) +
  geom_bar(stat = "identity") +
  scale_fill_continuous(low = "blue", high = "red") +
  theme_bw() +
  ylab("") +
  xlab("GSEA Score")

pp(file = "images/GSEA_Retinako_enriched_vs_SCN_P08.pdf")
gsea_plots_ret
plotted <- dev.off()

22 My version of the global analysis

I want to have an invocation of all_pairwise() which uses all samples, in the following block I will set that up using a set of ‘keepers’ which will be named by time, location, then 2 letters for the numerator/denominator: w for WT, h for het, d for delta; thus “p08_retina_hw” is comparing the het/wt for the p08 retina samples.

If they are of interest, I will have a separate set which follows the same convention with names like “p08_ko_sr” to compare p08 deltas with SCN as the numerator and retina as the denominator.

22.1 Set up the exclusion dataset

The most peculiar aspect of this analysis resides in the choices around choosing which genes to consider when comparing the genotypes/locations/times. The general idea is pretty clear: find the genes which are non-specifically being pulled down in the WT samples and either exclude or discount them. The various potential methods for performing this are confusing:

  1. Which set of comparisons of wt/ko wt/het do we use to exclude/discount genes?
    1. Should it be a combination of all samples wt vs. x?
    2. Should it be only the ‘relevant’ comparison, e.g. if we are comparing p08_dlgn_het vs. p08_scn_het; do we remove genes observed in (p08_dlgn_het/wt && p08_scn_het/wt)
  2. Do we instead attempt to use this x/wt information to normalize the expression values in the other conditions and keep those genes?

Theresa’s current worksheet implements a version of 1b in which she separated the various input gene sets to define the exclusion genes. I am going to repeat this, but leave the starting data structure intact.

In this first iteration, I will do that by creating a simplified model of the data which combines the time/genotype/location and using sva. In my next iteration I will use a full statistical model containing each of those factors (and probably also using sva).

Note: my color choices are kind of garbage.

In addition, the exclusion dataset is the same as the analysis dataset, it is really only the contrasts which will be different.

v3_pairwise_input <- set_conditions(mm38_hisat_v3, fact = "time_geno_loc",
                                    colors = color_choices[["all"]])
## The numbers of samples by condition are:
## 
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in set_colors(meta, colors = colors, color_column = color_column, :
## This list does not match the samples nor conditions.
## This function is intended to set the colors of a dataset.
## It was passed an object of type data.frame and does not know what to do.

22.2 A heatmap of specific genes across all conditions

all_cond_gene_heatmap_start <- normalize(v3_pairwise_input, filter = "simple",
                                         length_column = "cds_length",
                                         convert = "rpkm", transform = "log2")
## Removing 5517 low-count genes (19908 remaining).
## About to perform a RPKM conversion where NA lengths are set to: 1000.
## There appear to be 1430 genes without a length.
## Setting the elements with NA length to 1000.
## transform_counts: Found 261240 values equal to 0, adding 1 to the matrix.
all_cond_gene_heatmap_input <- median_by_factor(all_cond_gene_heatmap_start)
## The factor p08_het_dlgn has 3 rows.
## The factor p08_het_retina has 3 rows.
## The factor p08_het_scn has 3 rows.
## The factor p08_ko_dlgn has 3 rows.
## The factor p08_ko_retina has 3 rows.
## The factor p08_ko_scn has 3 rows.
## The factor p08_wt_dlgn has 5 rows.
## The factor p08_wt_retina has 5 rows.
## The factor p08_wt_scn has 3 rows.
## The factor p15_het_dlgn has 4 rows.
## The factor p15_het_retina has 4 rows.
## The factor p15_het_scn has 3 rows.
## The factor p15_ko_dlgn has 3 rows.
## The factor p15_ko_retina has 3 rows.
## The factor p15_ko_scn has 3 rows.
## The factor p15_wt_dlgn has 5 rows.
## The factor p15_wt_retina has 5 rows.
## The factor p15_wt_scn has 2 rows.
all_cond_mtrx <- all_cond_gene_heatmap_input[["medians"]]
color_order <- colnames(all_cond_mtrx)
na_idx <- is.na(all_cond_mtrx)
all_cond_mtrx[na_idx] <- 0
variances <- matrixStats::rowVars(as.matrix(all_cond_mtrx))
variant_genes <- variances > 6.2
input_mtrx <- all_cond_mtrx[variant_genes, ]
cond_colors <- get_colors_by_condition(v3_pairwise_input, levels = color_order)
dim(input_mtrx)
## [1] 135  18
input_heatmap <- gplots::heatmap.2(as.matrix(input_mtrx), scale = "none", trace = "none",
                                   ColSideColors = cond_colors)

pp(file = "04inclusion_comparisons/top_104_variant_rpkm_genes_heatmap.pdf")
input_heatmap <- gplots::heatmap.2(as.matrix(input_mtrx), scale = "none", trace = "none",
                                   ColSideColors = cond_colors)
dev.off()
## png 
##   2

23 TODO: Change the above to subtract wt

Rashmi suggested we should do the above plot after subtracting the wt counts. This is a good idea, but it will have to wait until we finish the current set.

23.1 Set up the contrasts

In the following few blocks I will set up the various comparisons of interest. Starting with the set of genes to exclude because they were observed to bind non-specifically in the wt samples.

23.1.1 Inclusion contrasts

In each exclusion I will have the contrast first followed by the pair of contrasts which will be used to define the gene set to exclude.

  • p15_het_dlgn/p08_het_dlgn: p15_wt_dlgn/p15_het_dlgn, p08_wt_dlgn/p08_het_dlgn; remove the genes increased in wt.
  • p15_ko_scn/p08_ko_scn: p15_wt_scn/p15_ko_scn, p08_wt_scn/p15_ko_scn
  • p15_het_retina/p08_het_retina: I think you get it, wt/het for both p15 retinas and p08 retinas…

Put slightly differently, for every term of interest I will create a contrast with the wt as numerator and the desired term as denominator, then pull out the genes increased in wt.

23.1.2 Potential text describing filtering

This dataset includes wild-type mice for each condition; this provided an opportunity to filter out the most likely false positive genes/transcripts. When the samples were processed and the tagged large ribosomal subunits were pulled down, it was assumed that at least some other transcripts were likely to bind to the column and therefore end up in the sequencing libraries. If one assumes that this distribution is consistent over time, genotype, and location; then a likely strategy would be to take the mean value of all observed wild-type samples and exclude any genes/transcripts for which the heterozygous and/or knockout samples have lower observed abundance than this mean. We therefore performed the comparisons of the wild-type samples by time and location and observed significant variance; thus we chose instead to exclude genes/transcripts which are lower in the heterzygous and knock-out samples than any of the comitant wild-type conditions. As an example, if the desired contrast is to compare heterzygous retina / knockout retina at p08; then the set of observed abundances was first compared against the p08 wt retina samples and filtered to include only those which were deemed higher when comparing the (p08 heterozygous retina / p08 wild-type retina) and (p08 knockout retina / p08 wild-type retina) via DESeq2, with a less stringent definition of significant (adjusted p-value <= 0.1 and logFC >= 0.1). Two versions of this filter were applied, one which required either the numerator or denominator to be higher than the corresponding wild-type samples; and one which required both to be higher than the wild-type samples. The mean normalized expression values were reported with each of these comparisons so that one may perform other filters as desired.

I will put this slightly differently, copy-pasting the observed set of genes increased in the non-wt condition to show the result:

LFC cutoff: 0.1 adj P cutoff: 0.1 deseq_up p15_het_dlgn 2067 p08_het_dlgn 180 p15_ko_dlgn 2544 p08_ko_dlgn 397 p15_het_retina 402 p08_het_retina 976 p15_ko_retina 347 p08_ko_retina 1551 p15_het_scn 15 p08_het_scn 225 p15_ko_scn 8 p08_ko_scn 112

When comparing against the dLGN wild-types, there are between 180 and 2,544 genes which pass the filter. The retina filter passes between 347 and 1,551 genes. The SCN filter passes far fewer genes, ranging from 8 to 225.

If we filter based on the intersection of genes which pass these, then any contrast which includes SCN samples will have ~ 0 genes of interest by definition. Thus, we chose to allow genes which pass the union of either the numerator or denominator filter. In this instance, we retain a significant number of genes as long as we are not restricted to only SCN samples.

inclusions <- list(
  ## I like alphabetizing things, start with dlgn
  "p15_het_dlgn" = c("p15_het_dlgn", "p15_wt_dlgn"),
  "p08_het_dlgn" = c("p08_het_dlgn", "p08_wt_dlgn"),
  "p15_ko_dlgn" = c("p15_ko_dlgn", "p15_wt_dlgn"),
  "p08_ko_dlgn" = c("p08_ko_dlgn", "p08_wt_dlgn"),
  ## Then retinas
  "p15_het_retina" = c("p15_het_retina", "p15_wt_retina"),
  "p08_het_retina" = c("p08_het_retina", "p08_wt_retina"),
  "p15_ko_retina" = c("p15_ko_retina", "p15_wt_retina"),
  "p08_ko_retina" = c("p08_ko_retina", "p08_wt_retina"),
  ## Then scn
  "p15_het_scn" = c("p15_het_scn", "p15_wt_scn"),
  "p08_het_scn" = c("p08_het_scn", "p08_wt_scn"),
  "p15_ko_scn" = c("p15_ko_scn", "p15_wt_scn"),
  "p08_ko_scn" = c("p08_ko_scn", "p08_wt_scn"))

23.1.3 Time contrasts

For each location/genotype of interest, let us compare p15/p08

time_keepers <- list(
  ## DLGN
  "t_het_dlgn" = c("p15_het_dlgn", "p08_het_dlgn"),
  "t_ko_dlgn" = c("p15_ko_dlgn", "p08_ko_dlgn"),
  ## Retina
  "t_het_retina" = c("p15_het_retina", "p08_het_retina"),
  "t_ko_retina" = c("p15_ko_retina", "p08_ko_retina"),
  ## SCN
  "t_het_scn" = c("p15_het_scn", "p08_het_scn"),
  "t_ko_scn" = c("p15_ko_scn", "p08_ko_scn"))

23.1.4 Location contrasts

Compare locations and keep time/genotype consistent. I will use the location initials to define numerator/denominator.

location_keepers <- list(
  ## dlgn/retina
  "dr_p08_het" = c("p08_het_dlgn", "p08_het_retina"),
  "dr_p15_het" = c("p15_het_dlgn", "p15_het_retina"),
  "dr_p08_ko" = c("p08_ko_dlgn", "p08_ko_retina"),
  "dr_p15_ko" = c("p15_ko_dlgn", "p15_ko_retina"),
  ## scn/retina
  "sr_p08_het" = c("p08_het_scn", "p08_het_retina"),
  "sr_p15_het" = c("p15_het_scn", "p15_het_retina"),
  "sr_p08_ko" = c("p08_ko_scn", "p08_ko_retina"),
  "sr_p15_ko" = c("p15_ko_scn", "p15_ko_retina"),
  ## dlgn/scn
  "ds_p08_het" = c("p08_het_dlgn", "p08_het_scn"),
  "ds_p15_het" = c("p15_het_dlgn", "p15_het_scn"),
  "ds_p08_ko" = c("p08_ko_dlgn", "p08_ko_scn"),
  "ds_p15_ko" = c("p15_ko_dlgn", "p15_ko_scn"))

23.1.5 Genotype contrasts

Compare ko/het while keeping time/location constant. Similarly, use the initials to denote numerator/denominator, which will always be kh.

genotype_keepers <- list(
  ## DLGN
  "kh_p08_dlgn" = c("p08_ko_dlgn", "p08_het_dlgn"),
  "kh_p15_dlgn" = c("p15_ko_dlgn", "p15_het_dlgn"),
  ## Retina
  "kh_p08_retina" = c("p08_ko_retina", "p08_het_retina"),
  "kh_p15_retina" = c("p15_ko_retina", "p15_het_retina"),
  ## SCN
  "kh_p08_scn" = c("p08_ko_scn", "p08_het_scn"),
  "kh_p15_scn" = c("p15_ko_scn", "p15_het_scn"))

23.2 Perform the exclusion comparison

My all_pairwise() function now has a parameter which allows me to choose which contrasts to perform instead of literally doing every possible comparison. That is well suited for these operations.

inclusion_de <- all_pairwise(
  v3_pairwise_input, filter = "simple", model_fstring = default_fstring,
  keepers = inclusions, model_svs = "svaseq")
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 5517 low-count genes (19908 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 394442 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 2 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2

inclusion_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 12 comparisons.
inclusion_tables <- combine_de_tables(
  inclusion_de, keepers = inclusions, label_column = label_column,
  excel = glue("04inclusion_comparisons/inclusion_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
inclusion_tables
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1      p15_het_dlgn_vs_p15_wt_dlgn         536           971         668
## 2      p08_het_dlgn_vs_p08_wt_dlgn          15            79          57
## 3       p15_ko_dlgn_vs_p15_wt_dlgn         903          1333        1029
## 4       p08_ko_dlgn_vs_p08_wt_dlgn         117           282         133
## 5  p15_het_retina_vs_p15_wt_retina         151            58         193
## 6  p08_het_retina_vs_p08_wt_retina         432           110         464
## 7   p15_ko_retina_vs_p15_wt_retina         107            34         178
## 8   p08_ko_retina_vs_p08_wt_retina         533           155         551
## 9        p15_het_scn_vs_p15_wt_scn          11             8          39
## 10       p08_het_scn_vs_p08_wt_scn          48             8          57
## 11        p15_ko_scn_vs_p15_wt_scn           7             5          28
## 12        p08_ko_scn_vs_p08_wt_scn          31            26          83
##    edger_sigdown limma_sigup limma_sigdown
## 1           1013         582           833
## 2            107          40            46
## 3           1346         837          1045
## 4            297         186           356
## 5            114         119            57
## 6            162         315            88
## 7             62          39            25
## 8            224         404           144
## 9             28          19            34
## 10            45          42            20
## 11            30          39            39
## 12            54          65            55
## Plot describing unique/shared genes in a differential expression table.

## 202603: I successfully recapitulated previous non-container result.
## 202608: Recapitulated against the 202603 results!

inclusion_sig <- extract_significant_genes(
  inclusion_tables, lfc = filter_lfc_cutoff, p = filter_adjp_cutoff, according_to = "deseq",
  excel = glue("04inclusion_comparisons/inclusion_sig-v{ver}.xlsx"))
inclusion_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 0.1 adj P cutoff: 0.1
##                deseq_up deseq_down
## p15_het_dlgn       2067       2381
## p08_het_dlgn        180        349
## p15_ko_dlgn        2544       2633
## p08_ko_dlgn         397        572
## p15_het_retina      402        223
## p08_het_retina      976        380
## p15_ko_retina       347         93
## p08_ko_retina      1551        859
## p15_het_scn          15          9
## p08_het_scn         225         55
## p15_ko_scn            8          6
## p08_ko_scn          112        116

202608: I am seeing a tiny shift in p-values/logFC across all contrasts and methods; it is so small that normally I would not see it. In addition, if one looks at the metadata tab in the output pairwise xlsx file (inclusion_tables-v20250515.xlsx compared to inclusion_tables-v20260820.xlsx for example), they include the mean values and surrogate variables from sva – these are exactly identical to the number of digits available in excel/R. We can go one step further and observe that the various metrics of beasmean and such.

““” 1. When we start the DESeq to generate the set of included genes: a. The input data is exactly identical between 202503 and today – I can see that in a few places, when comparing the xlsx outputs the easiest are the % variance in the PCA plots on sheet #1 and the basemean values in all the following sheets. They are identical for every gene on every sheet I checked (~10 genes on 3 sheets each ranging across the top and bottom 500 most expressed genes). b. The first step of the DE analysis is to invoke sva and calculate the additions to the model. These get printed to the metadata sheet of the xlsx file and are exactly identical.

So, I know for certain that the input to all methods is the same from 202503 to now. I also know for certain that every model got the same surrogates.

  1. The logFC values for every method have shifted by between 0 and 0.01, including my basic method.
  2. The p-values have shifted by between 0 and 0.0001 for every method.
  3. The adjusted p-values have shifted by between 0 and 0.001 for every method.

I have gone through every line which performs the differential expression and I do not see any changes between 2025 and now.

The end result is that the set of ‘significant’ genes for every contrast in every comparison is exactly the same. However, we are extracting genes which are insignificantly higher in the condition vs. wt and this set of genes has decreased by between 0 and 10 genes across the comparisons which in the case of the SCN samples which already have very few results in a noticeable difference.

““”

Let us try a very slightly different filter when invoking DESeq2? Damnit I don’t know. The following is the invocation produced by all_pairwise()

test_diff <- deseq2_pairwise(v3_pairwise_input, filter = "simple",
                             model_fstring = default_fstring, keepers = inclusions,
                             model_svs = "svaseq", null_fstring = "~", extra_contrasts = NULL,
                             annot_df = NULL, force = FALSE, deseq_method = "long",
                             fittype = "parametric", num_surrogates = "be", keep_underscore = TRUE)
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 2 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.

I am running that under the debugger, I am now at the step which produces the method-specific surrogate variables; when run under all_pairwise, it produces the SVs for all methods at the same time and passes them along. SV3 is the most sensitive to differences, so I will check the first few entries for SV2 and SV3. Sample iprgc_86 in the 202503 xlsx file has SV3 as -0.1657932. In my R session I see exactly that. I went on to check SVs 1,2,3 for the first 18 samples, they are all identical.

One weird little change I did notice, I have some logic to check if the input is filtered; one term was backward and I fixed it. I do not think that matters; but one test I will apply is to repeat the DE analysis with the pre and post filtered inputs.

ok, I completed the DESeq run under the debugger and recapitulated the differences observed between 202503 and today. The baseMean (column AK in the xlsx file) values are identical, but the SE/stat/FC/p/adjp are slightly different for most genes.

Let us now rerun with the pre-filtered set as input and leave the SVs with their current values (which are identical to the 202503 run)?

Note to self, when I finish this: there is a hard-coded number of significant digits when I print out the table of results (4), don’t do that – set an option for that.

Ok, this unfiltered run results in a set of results which now has 25,425 rows, so it definitely did not filter. In addition, the adjusted p-values have shifted by ~ 1e-5, but the logFC and p-values are identical to the 202608 run.

So that is not the answer but at least I was not wrong that it has an effect, I guess. Let us try the opposite filter – switch to CBCB filtering which was the default some time ago? Filtering really is the only thing I can think of which would change results across every method by such a small amount. Same result.

ok, I checked the result; same. I changed the betaprior, the deseq normalization, and significant digits. No change.

Random thought: I set the number of significant digits to 9 and tried again. Aaaannnndddd I hate everything - that is the answer. I think I need to make certain that options(digits = x) where x is consistent.

202505: A strange thing happened here in this iteration: the plot of the significant genes is the exact same as the previous iteration; but the table of numbers of genes looks different.

For example, the previous table showed: p15_het_dlgn with 2067 up and 2381 down. The plot shows exactly that; but the new table shows 607 up and 1229 down. Let us check the actual data structure and see what is up?

I think I get it: when we do the extract_significant_genes above, we explicitly set a non-standard p-value and logFC because we are explicitly attempting to use a very loose definition of the set of genes which are in greater abundance than their most similar wild-type. However, when I create the barplot of significant genes; those values are explicitly set to 0,1,2 logFCs and p-value 0.05. Therefore, what I need to do, in order to check consistency, is to repeat this call but with the default FC/p values and see what the numbers look like.

test_inclusion <- extract_significant_genes(
  inclusion_tables, according_to = "deseq", excel = "excel/default_inclusion_sig.xlsx")
## Deleting the file excel/default_inclusion_sig.xlsx before writing the tables.
test_inclusion
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##                deseq_up deseq_down
## p15_het_dlgn        536        971
## p08_het_dlgn         15         79
## p15_ko_dlgn         903       1333
## p08_ko_dlgn         117        282
## p15_het_retina      151         58
## p08_het_retina      432        110
## p15_ko_retina       107         34
## p08_ko_retina       533        155
## p15_het_scn          11          8
## p08_het_scn          48          8
## p15_ko_scn            7          5
## p08_ko_scn           31         26

Yeah, I think this makes sense; what I need to do: change the significant bar plot so that it uses the lfc cutoff argument as the second of its 3 cutoffs. That should ensure that these numbers are consistent across analyses and parameters provided.

dim(inclusion_sig$deseq$ups$p15_het_dlgn)
## [1] 2067   83
test_all_up <- inclusion_tables$data$p15_het_dlgn[["deseq_logfc"]] >= 0.1 &
  inclusion_tables$data$p15_het_dlgn[["deseq_adjp"]] <= 0.1
summary(test_all_up)
##    Mode   FALSE    TRUE 
## logical   17841    2067

Ohh, I get it, when I was testing this out manually, I set the logFC to 1.0 instead of the very minimal 0.1 we have been using for this!

24 MA/Volcano plots of x vs wt

Rashmi asked to see the comparisons against wt; I will name each file xw to show that it is x vs wt. for whatever other parameters are being examined. It is likely that some colors will be wrong because this is my first time creating these plots and we are doing them manually.

24.1 p15_het_dlgn

allc <- color_choices[["all"]]
table_name <- "p15_het_dlgn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_het_dlgn"
denom <- "p15_wt_dlgn"
hw_p15_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)

pp(file = "05inclusion_volcano_ma/hw_p15_dlgn_volcano.pdf", width = 9, height = 9,
   image = hw_p15_dlgn_volcano[["plot"]])

hw_p15_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p15_dlgn_ma.pdf", width = 9, height = 9,
   image = hw_p15_dlgn_ma[["plot"]])

24.2 p08_het_dlgn

table_name <- "p08_het_dlgn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_het_dlgn"
denom <- "p08_wt_dlgn"
hw_p08_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/hw_p08_dlgn_volcano.pdf", width = 9, height = 9,
   image = hw_p08_dlgn_volcano[["plot"]])

hw_p08_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p08_dlgn_ma.pdf", width = 9, height = 9)
hw_p08_dlgn_ma[["plot"]]
plotted <- dev.off()
hw_p08_dlgn_ma[["plot"]]

24.3 p15_ko_dlgn

table_name <- "p15_ko_dlgn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_ko_dlgn"
denom <- "p15_wt_dlgn"
kw_p15_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p15_dlgn_volcano.pdf", width = 9, height = 9,
   image = kw_p15_dlgn_volcano[["plot"]])

kw_p15_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/kw_p15_dlgn_ma.pdf", width = 9, height = 9,
   image = kw_p15_dlgn_ma[["plot"]])

24.4 p08_ko_dlgn

table_name <- "p08_ko_dlgn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_ko_dlgn"
denom <- "p08_wt_dlgn"
kw_p08_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p08_dlgn_volcano.pdf", width = 9, height = 9,
   image = kw_p08_dlgn_volcano[["plot"]])

kw_p08_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/kw_p08_dlgn_ma.pdf", width = 9, height = 9,
   image = kw_p08_dlgn_ma[["plot"]])

24.5 p15_het_retina

table_name <- "p15_het_retina"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_het_retina"
denom <- "p15_wt_retina"
hw_p15_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/hw_p15_retina_volcano.pdf", width = 9, height = 9,
   image = hw_p15_retina_volcano[["plot"]])

hw_p15_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p15_retina_ma.pdf", width = 9, height = 9,
   image = hw_p15_retina_ma[["plot"]])

24.6 p08_het_retina

table_name <- "p08_het_retina"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_het_retina"
denom <- "p08_wt_retina"
hw_p08_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/hw_p08_retina_volcano.pdf", width = 9, height = 9,
   image = hw_p08_retina_volcano[["plot"]])

hw_p08_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p08_retina_ma.pdf", width = 9, height = 9,
   image = hw_p08_retina_ma[["plot"]])

24.7 p15_ko_retina

table_name <- "p15_ko_retina"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_ko_retina"
denom <- "p15_wt_retina"
kw_p15_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p15_retina_volcano.pdf", width = 9, height = 9,
   image = kw_p15_retina_volcano[["plot"]])

kw_p15_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/kw_p15_retina_ma.pdf", width = 9, height = 9,
   image = kw_p15_retina_ma[["plot"]])

24.8 p08_ko_retina

table_name <- "p08_ko_retina"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_ko_retina"
denom <- "p08_wt_retina"
kw_p08_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p08_retina_volcano.pdf", width = 9, height = 9,
   kw_p08_retina_volcano[["plot"]])

kw_p08_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma_p08_retina_ma.pdf", width = 9, height = 9,
   image = kw_p08_retina_ma[["plot"]])

24.9 p15_het_scn

table_name <- "p15_het_scn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_het_scn"
denom <- "p15_wt_scn"
hw_p15_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/hw_p15_scn_volcano.pdf", width = 9, height = 9,
   image = hw_p15_scn_volcano[["plot"]])

hw_p15_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p15_scn_ma.pdf", width = 9, height = 9,
   image = hw_p15_scn_ma[["plot"]])

24.10 p08_het_scn

table_name <- "p08_het_scn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_het_scn"
denom <- "p08_wt_scn"
hw_p08_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/hw_p08_scn_volcano.pdf", width = 9, height = 9,
   image = hw_p08_scn_volcano[["plot"]])

hw_p08_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/hw_p08_scn_ma.pdf", width = 9, height = 9,
   image = hw_p08_scn_ma[["plot"]])

24.11 p15_ko_scn

table_name <- "p15_ko_scn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p15_ko_scn"
denom <- "p15_wt_scn"
kw_p15_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p15_scn_volcano.pdf", width = 9, height = 9,
   kw_p15_scn_volcano[["plot"]])

kw_p15_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/kw_p15_scn_ma.pdf", width = 9, height = 9,
   image = kw_p15_scn_ma[["plot"]])

24.12 p08_ko_scn

table_name <- "p08_ko_scn"
table <- inclusion_tables[["data"]][[table_name]]
num <- "p08_ko_scn"
denom <- "p08_wt_scn"
kw_p08_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = allc[[denom]], color_high = allc[[num]],
  label_column = label_column, label = 10, alpha = 1.0,
  size = 4)
pp(file = "05inclusion_volcano_ma/kw_p08_scn_volcano.pdf", width = 9, height = 9,
   image = kw_p08_scn_volcano[["plot"]])

kw_p08_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = allc[[denom]], color_high = allc[[num]],
  p_col = "deseq_adjp", label_column = label_column, outline = outline,
  label = 10)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "05inclusion_volcano_ma/kw_p08_scn_ma.pdf", width = 9, height = 9,
   image = kw_p08_scn_ma[["plot"]])

There is something different here compared to the 202503 results. Two of the dots have moved; but every other plot looks exactly the same.

See the shared/unique genes in these sets.

inclusion_upsets <- upsetr_sig(inclusion_sig)
inclusion_intersects <- write_upset_groups(
  inclusion_upsets, excel = "04inclusion_comparison/inclusion_gene_groups.xlsx")
## Deleting the file 04inclusion_comparison/inclusion_gene_groups.xlsx before writing the tables.

24.12.1 Extract genes included for each set of contrasts

Now, using that function, pull out the gene IDs of genes we do not trust because they were too high in wt for every contrast we are likely to perform.

The following was a modified version of the inclusion function which is somewhat more restrictive.

extract_inclusions_strict <- function(inclusion_sig, inclusion_tables, inclusions, keepers,
                                      all_genes, according_to = "deseq", which = "ups") {
  retlist <- list()
  table_names <- names(inclusion_sig[[according_to]][[which]])
  for (c_num in seq_along(keepers)) {
    contrast <- names(keepers)[c_num]
    numerator_name <- keepers[[c_num]][1]
    denominator_name <- keepers[[c_num]][2]
    ## In my new branch I cleaned up the sanitizer function for contrasts so this is not needed.
    ## The following two lines are no longer needed because of the cleanups I performed.
    ##numerator_name <- gsub(x = numerator_name, pattern = "(het|ko|wt)", replacement = "_\\1_")
    ##denominator_name <- gsub(x = denominator_name, pattern = "(het|ko|wt)", replacement = "_\\1_")
    numerator_table <- inclusion_sig[[according_to]][[which]][[numerator_name]]
    numerator_genes <- rownames(numerator_table)
    denominator_table <- inclusion_sig[[according_to]][[which]][[denominator_name]]
    denominator_genes <- rownames(denominator_table)
    df_columns <- paste0("deseq_", c("logfc", "adjp", "den"))
    included_num <- inclusion_tables[["data"]][[numerator_name]][, df_columns]
    colnames(included_num) <- c("numerator_vs_wt_logfc", "numerator_vs_wt_adjp", "num_wt_mean_exprs")
    included_den <- inclusion_tables[["data"]][[denominator_name]][, df_columns]
    colnames(included_den) <- c("denominator_vs_wt_logfc", "denominator_vs_wt_adjp", "den_wt_mean_exprs")
    ## I think this is where things went wrong,
    ## compare this modified line to the original to prove it.
    included_df <- merge(included_num, included_den, by = "row.names")
    ## Previously, I did not specify the merge action, all = FALSE by default.
    ## This then will result in a difference in the rows observed
    ## included_df <- merge(included_num, included_den, by = "row.names", all = FALSE)
    rownames(included_df) <- included_df[["Row.names"]]
    included_df[["Row.names"]] <- NULL
    concatenated_genes <- c(numerator_genes, denominator_genes)
    both_gene_idx <- duplicated(concatenated_genes)
    genes_in_both <- concatenated_genes[both_gene_idx]
    message("The set of unique genes higher in ", numerator_name,
            " vs. wt is ", length(numerator_genes), ".")
    message("The set of unique genes higher in ", denominator_name,
            " vs. wt is ", length(denominator_genes), ".")
    message("The intersection of them is ", length(genes_in_both), " genes.")
    include_name <- paste0("inc_", contrast)
    include_idx <- all_genes %in% genes_in_both
    include_genes <- all_genes[include_idx]
    df_name <- paste0("df_", contrast)
    retlist[[df_name]] <- included_df
    written_inclusion <- write_xlsx(
      data = included_df,
      excel = glue("07included_strict_genes_excel/{include_name}-v{ver}.xlsx"))
    retlist[[include_name]] <- include_genes
    retlist[[contrast]] <- include_genes
  }
  return(retlist)
}

This is the pre-202505 version of this function.

extract_inclusions <- function(inclusion_sig, inclusion_tables, inclusions, keepers, all_genes,
                               according_to = "deseq", which = "ups") {
  retlist <- list()
  table_names <- names(inclusion_sig[[according_to]][[which]])
  for (c_num in seq_along(keepers)) {
    contrast <- names(keepers)[c_num]
    numerator_name <- keepers[[c_num]][1]
    denominator_name <- keepers[[c_num]][2]
    ## In my new branch I cleaned up the sanitizer function for contrasts so this is not needed.
    ## The following two lines are no longer needed because of the cleanups I performed.
    ##numerator_name <- gsub(x = numerator_name, pattern = "(het|ko|wt)", replacement = "_\\1_")
    ##denominator_name <- gsub(x = denominator_name, pattern = "(het|ko|wt)", replacement = "_\\1_")
    numerator_table <- inclusion_sig[[according_to]][[which]][[numerator_name]]
    numerator_genes <- rownames(numerator_table)
    denominator_table <- inclusion_sig[[according_to]][[which]][[denominator_name]]
    denominator_genes <- rownames(denominator_table)
    df_columns <- paste0("deseq_", c("logfc", "adjp", "den"))
    included_num <- inclusion_tables[["data"]][[numerator_name]][, df_columns]
    colnames(included_num) <- c("numerator_vs_wt_logfc", "numerator_vs_wt_adjp", "num_wt_mean_exprs")
    included_den <- inclusion_tables[["data"]][[denominator_name]][, df_columns]
    colnames(included_den) <- c("denominator_vs_wt_logfc", "denominator_vs_wt_adjp", "den_wt_mean_exprs")
    included_df <- merge(included_num, included_den, by = "row.names")
    rownames(included_df) <- included_df[["Row.names"]]
    included_df[["Row.names"]] <- NULL
    include_genes <- unique(c(numerator_genes, denominator_genes))
    message("The set of unique genes higher in ", numerator_name,
            " vs. wt is ", length(numerator_genes), ".")
    message("The set of unique genes higher in ", denominator_name,
            " vs. wt is ", length(denominator_genes), ".")
    message("The unique union of them is ", length(include_genes), " genes.")
    include_name <- paste0("inc_", contrast)
    include_idx <- all_genes %in% include_genes
    include_genes <- all_genes[include_idx]
    df_name <- paste0("df_", contrast)
    retlist[[df_name]] <- included_df
    written_inclusion <- write_xlsx(data = included_df,
                                    excel = glue("07included_genes/{include_name}-v{ver}.xlsx"))
    retlist[[include_name]] <- include_genes
    retlist[[contrast]] <- include_genes
  }
  return(retlist)
}

25 ‘Normal’ Inclusion extraction

Here is the full set of gene IDs

all_genes <- rownames(assay(v3_pairwise_input))

In the following blocks I am including the union of genes observed higher than wt in either of the numerator or denominator for each contrast.

25.1 Time

time_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                      time_keepers, all_genes)
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The unique union of them is 2113 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The unique union of them is 2716 genes.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1086 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1664 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 238 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The unique union of them is 120 genes.

25.2 Location

location_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                          location_keepers, all_genes)
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1134 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 2361 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1883 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The unique union of them is 2843 genes.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1188 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 417 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1624 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The unique union of them is 355 genes.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 402 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The unique union of them is 2080 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The unique union of them is 493 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The unique union of them is 2550 genes.

25.3 Genotype

genotype_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                          genotype_keepers, all_genes)
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The unique union of them is 501 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The unique union of them is 2773 genes.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1760 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 571 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 312 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The unique union of them is 18 genes.

26 The strict ‘inclusion’ set

26.1 Time

time_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
                                                    time_keepers, all_genes)
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The intersection of them is 134 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The intersection of them is 225 genes.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The intersection of them is 292 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The intersection of them is 234 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The intersection of them is 2 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The intersection of them is 0 genes.

26.2 Location

location_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
                                                        location_keepers, all_genes)
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The intersection of them is 22 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The intersection of them is 108 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The intersection of them is 65 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The intersection of them is 48 genes.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The intersection of them is 13 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The intersection of them is 0 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The intersection of them is 39 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The intersection of them is 0 genes.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The intersection of them is 3 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The intersection of them is 2 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The intersection of them is 16 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The intersection of them is 2 genes.

26.3 Genotype

genotype_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
                                                        genotype_keepers, all_genes)
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The intersection of them is 76 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The intersection of them is 1838 genes.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The intersection of them is 767 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The intersection of them is 178 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The intersection of them is 25 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The intersection of them is 5 genes.

26.3.1 Check vs Theresa’s filter

Up above Theresa performed a 0.25 log2FC and 0.05 adjp filter which provided a set of 2,640 genes observed higher in the p08 het retinas vs. wt retinas. I should see that in this inclusion_sig data structure.

There is an important caveat though: in Theresa’s filter above, she did a DE of only the retina samples but I did all samples. I expected that this would result in basically the same result (I actually assumed I would get a few more genes), but instead it appears to have retrieved a significantly smaller number of genes (about 1/2, happily they pretty much all appear in the previous filter). As a result, I am going to try relaxing my constraints slightly to see if I can recapitulate her filter (which would match Theresa’s later filter, though I guess that in turn will lead to a smaller set of genes compared to her later, relaxed 0.1 filter).

comparison <- inclusion_sig[["deseq"]][["ups"]][["p08_het_retina"]]
comp <- list(
  "taa" = taa_keepers,
  "new" = rownames(comparison))
test_comparison <- Vennerable::Venn(comp)
Vennerable::plot(test_comparison)

I want to have a little function which, given a contrast of interest, will extract the gene sets which should be included/excluded given the above.

write_all_cp <- function(all_cp, prefix = "12", suffix = "") {
  all_written <- list()
  for (g in seq_len(length(all_cp))) {
    name <- names(all_cp)[g]
    datum <- all_cp[[name]]
    filename <- glue("{prefix}enrichment_excel/{name}_cprofiler{suffix}-v{ver}.xlsx")
    written <- sm(write_cp_data(datum, excel = filename))
    all_written[[g]] <- written
  }
  return(all_written)
}
write_all_gp <- function(all_gp, prefix = "13", suffix = "") {
  all_written <- list()
  for (g in seq_len(length(all_gp))) {
    name <- names(all_gp)[g]
    datum <- all_gp[[name]]
    filename <- glue("{prefix}enrichment_excel/{name}_gprofiler{suffix}-v{ver}.xlsx")
    written <- sm(write_gprofiler_data(datum, excel = filename))
    all_written[[g]] <- written
  }
  return(all_written)
}
write_all_en <- function(all_en, prefix = "14", suffix = "") {
  all_written <- list()
  for (e in seq_len(length(all_en))) {
    name <- names(all_en)[e]
    datum <- all_en[[name]]
    filename <- glue("{prefix}enrichment_excel/{name}_enricher{suffix}-v{ver}.xlsx")
    written <- sm(write_enricher_data(datum, excel = filename))
    all_written[[e]] <- written
  }
  return(all_written)
}

26.3.2 Extract genes included for each set of contrasts

Now, using that function, pull out the gene IDs of genes we do not trust because they were too high in wt for every contrast we are likely to perform.

all_genes <- rownames(assay(v3_pairwise_input))
time_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                      time_keepers, all_genes)
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The unique union of them is 2113 genes.
## Deleting the file 07included_genes/inc_t_het_dlgn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The unique union of them is 2716 genes.
## Deleting the file 07included_genes/inc_t_ko_dlgn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1086 genes.
## Deleting the file 07included_genes/inc_t_het_retina-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1664 genes.
## Deleting the file 07included_genes/inc_t_ko_retina-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 238 genes.
## Deleting the file 07included_genes/inc_t_het_scn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The unique union of them is 120 genes.
## Deleting the file 07included_genes/inc_t_ko_scn-v20260828.xlsx before writing the tables.
location_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                          location_keepers, all_genes)
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1134 genes.
## Deleting the file 07included_genes/inc_dr_p08_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 2361 genes.
## Deleting the file 07included_genes/inc_dr_p15_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1883 genes.
## Deleting the file 07included_genes/inc_dr_p08_ko-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The unique union of them is 2843 genes.
## Deleting the file 07included_genes/inc_dr_p15_ko-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1188 genes.
## Deleting the file 07included_genes/inc_sr_p08_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 417 genes.
## Deleting the file 07included_genes/inc_sr_p15_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The unique union of them is 1624 genes.
## Deleting the file 07included_genes/inc_sr_p08_ko-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The unique union of them is 355 genes.
## Deleting the file 07included_genes/inc_sr_p15_ko-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 402 genes.
## Deleting the file 07included_genes/inc_ds_p08_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The unique union of them is 2080 genes.
## Deleting the file 07included_genes/inc_ds_p15_het-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The unique union of them is 493 genes.
## Deleting the file 07included_genes/inc_ds_p08_ko-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The unique union of them is 2550 genes.
## Deleting the file 07included_genes/inc_ds_p15_ko-v20260828.xlsx before writing the tables.
genotype_inclusions <- extract_inclusions(inclusion_sig, inclusion_tables, inclusions,
                                          genotype_keepers, all_genes)
## The set of unique genes higher in p08_ko_dlgn vs. wt is 397.
## The set of unique genes higher in p08_het_dlgn vs. wt is 180.
## The unique union of them is 501 genes.
## Deleting the file 07included_genes/inc_kh_p08_dlgn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2544.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2067.
## The unique union of them is 2773 genes.
## Deleting the file 07included_genes/inc_kh_p15_dlgn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_ko_retina vs. wt is 1551.
## The set of unique genes higher in p08_het_retina vs. wt is 976.
## The unique union of them is 1760 genes.
## Deleting the file 07included_genes/inc_kh_p08_retina-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_retina vs. wt is 347.
## The set of unique genes higher in p15_het_retina vs. wt is 402.
## The unique union of them is 571 genes.
## Deleting the file 07included_genes/inc_kh_p15_retina-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p08_ko_scn vs. wt is 112.
## The set of unique genes higher in p08_het_scn vs. wt is 225.
## The unique union of them is 312 genes.
## Deleting the file 07included_genes/inc_kh_p08_scn-v20260828.xlsx before writing the tables.
## The set of unique genes higher in p15_ko_scn vs. wt is 8.
## The set of unique genes higher in p15_het_scn vs. wt is 15.
## The unique union of them is 18 genes.
## Deleting the file 07included_genes/inc_kh_p15_scn-v20260828.xlsx before writing the tables.

26.4 Perform the DE analyses and exclude the target genes

26.4.1 Genotype

genotype_de <- all_pairwise(v3_pairwise_input, filter = TRUE, model_fstring = default_fstring,
                            keepers = genotype_keepers, model_svs = "svaseq")
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 109425 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2

genotype_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 6 comparisons.

26.4.2 Location

location_de <- all_pairwise(v3_pairwise_input, filter = TRUE, model_fstring = default_fstring,
                            keepers = location_keepers, model_svs = "svaseq")
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 109425 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2

location_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 12 comparisons.

26.4.3 Time

time_de <- all_pairwise(v3_pairwise_input, filter = TRUE, model_fstring = default_fstring,
                        keepers = time_keepers, model_svs = "svaseq")
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 109425 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2

time_de
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 6 comparisons.

It is near here when the computer sometimes fails with no more tempfiles. In another window I am messing with tempfile() in R to try to understand where it is going off the rails…

26.5 Extract the relevant tables and include genes lower in wt

26.5.1 Genotype contrasts

I will start with the tables and no inclusions so I can check my work.

In this first block I will explain a little more thoroughly what is going on:

  1. Dump the full table of the contrasts I defined above comparing the 3 genotypes across time/location.
  2. Iterate over each of those contrasts and do the following:
    1. Extract the name of the contrast, ‘kh_p08_dlgn’ for example
    2. Yank out that specific entry from the keeper list and its name
    3. Yank out the corresponding set of genes to include from the inclusions data structure.
    4. Create a filename given the name in (a) above and the logFC cutoff chosen for the inclusions (I am assuming we may change this)
    5. Given (b), (c), and (d), extract the corresponding table from the differential expression analysis and include the appropriate genes.
    FIXME: my gprofiler function just assumes human and so if passed mmusculus will incorrectly attempt to connect to non-existant databases. Let us fix that now.
genotype_tables_full <- combine_de_tables(
  genotype_de, keepers = genotype_keepers, label_column = label_column,
  fancy = TRUE,
  excel = glue("08full_contrasts_excel/genotype_full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
genotype_tables_full
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1     p08_ko_dlgn_vs_p08_het_dlgn          24             2          42
## 2     p15_ko_dlgn_vs_p15_het_dlgn          50             2          81
## 3 p08_ko_retina_vs_p08_het_retina           6             2           9
## 4 p15_ko_retina_vs_p15_het_retina           9             5           6
## 5       p08_ko_scn_vs_p08_het_scn          54           135          80
## 6       p15_ko_scn_vs_p15_het_scn           0            16           3
##   edger_sigdown limma_sigup limma_sigdown
## 1             1          41             3
## 2             3           0             0
## 3             2           3             1
## 4             4           0             3
## 5           139          32            28
## 6            29           0             1
## Plot describing unique/shared genes in a differential expression table.

genotype_sig_full <- extract_significant_genes(
  genotype_tables_full, according_to = "deseq",
  excel = glue("08full_contrasts_excel/genotype_full_sig-v{ver}.xlsx"))
genotype_sig_full
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##               deseq_up deseq_down
## kh_p08_dlgn         24          2
## kh_p15_dlgn         50          2
## kh_p08_retina        6          2
## kh_p15_retina        9          5
## kh_p08_scn          54        135
## kh_p15_scn           0         16

26.5.2 Search Enrichment of these sets

In this run, we will search the full set of genes, next we will only do the inclusions.

genotype_full_gp <- all_gprofiler(genotype_sig_full, species = "mmusculus",
                                  excel = "09full_contrasts_enrich/genotype_full_gprofiler.xlsx")
genotype_full_cp <- all_cprofiler(genotype_sig_full, genotype_tables_full,
                                  orgdb = "org.Mm.eg.db", go_level = go_level, organism = "mouse",
                                  orgdb_from = orgdb_from, max_groupsize = max_groupsize,
                                  excel = "09full_contrasts_enrich/genotype_full_cprofiler.xlsx")
genotype_full_upset <- upsetr_sig(genotype_sig_full)
genotype_full_intersects <- write_upset_groups(genotype_full_upset,
                                               excel = "09full_contrasts_intersections/genotype_full_gene_groups.xlsx")
## Deleting the file 09full_contrasts_intersections/genotype_full_gene_groups.xlsx before writing the tables.

Now separate the various genotype tables and perform the inclusions of the genes with relatively low wt values.

26.5.2.1 Extract filtered genes and pass to gprofiler2/clusterprofiler

genotype_tables <- list()
genotype_sig <- list()
genotype_gp <- list()
genotype_cp <- list()
genotype_en <- list()
for (k in seq_along(genotype_keepers)) {
  name <- names(genotype_keepers)[k]
  message("Examining ", name)
  keeper <- genotype_keepers[name]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- genotype_inclusions[[include_df_name]]
  includes <- genotype_inclusions[[include_name]]
  summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  include_filename <- glue("10genotype_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("10genotype_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  genotype_tables[[name]] <- combine_de_tables(
    genotype_de, extra_annot = include_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes)
  print(genotype_tables[[name]])
  genotype_sig[[name]] <- extract_significant_genes(
    genotype_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(genotype_sig[[name]])
  num_rows <- nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows >= 10) {
    message("Performing gprofiler/clusterProfiler.")
    genotype_gp[[name]] <- all_gprofiler(genotype_sig[[name]], species = "mmusculus")
    genotype_cp[[name]] <- all_cprofiler(
      genotype_sig[[name]], genotype_tables[[name]],
      orgdb = "org.Mm.eg.db", orgdb_from = orgdb_from,
      go_level = go_level, max_groupsize = max_groupsize, organism = "mouse")
    #genotype_cp_test[[name]] <- all_cprofiler(
    #  genotype_sig[[name]], genotype_tables[[name]],
    #  orgdb = "org.Mm.eg.db", orgdb_from = orgdb_from, organism = "mouse")
    gp_written <- write_all_gp(genotype_gp[[name]], prefix = "11")
    cp_written <- write_all_cp(genotype_cp[[name]], prefix = "11")
    #en_written <- write_all_en(genotype_en[[name]])
  } else {
    warning("There are less than 10 genes up and down in the ", name, " comparison.")
    message("There are less than 10 genes up and down in the ", name, " comparison.")
  }
}
## Examining kh_p08_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_het_dlgn          23             1          30
##   edger_sigdown limma_sigup limma_sigdown
## 1             0          26             0
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## kh_p08_dlgn       23          1

## There are 24 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining kh_p15_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p15_het_dlgn          44             0          73
##   edger_sigdown limma_sigup limma_sigdown
## 1             1           0             0
## Only kh_p15_dlgn_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## kh_p15_dlgn       44          0

## There are 44 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining kh_p08_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_retina_vs_p08_het_retina           3             1           3
##   edger_sigdown limma_sigup limma_sigdown
## 1             1           2             1
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##               deseq_up deseq_down
## kh_p08_retina        3          1

## There are 4 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_retina
## comparison.
## There are less than 10 genes up and down in the kh_p08_retina comparison.
## Examining kh_p15_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_retina_vs_p15_het_retina           6             4           4
##   edger_sigdown limma_sigup limma_sigdown
## 1             3           0             3
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##               deseq_up deseq_down
## kh_p15_retina        6          4

## There are 10 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining kh_p08_scn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p08_ko_scn_vs_p08_het_scn           9            45           9            45
##   limma_sigup limma_sigdown
## 1           6            14
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## kh_p08_scn        9         45

## There are 54 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining kh_p15_scn
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 16.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p15_ko_scn_vs_p15_het_scn           0             5           0             5
##   limma_sigup limma_sigdown
## 1           0             0
## Only kh_p15_scn_down has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## kh_p15_scn        0          5

## There are 5 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_scn comparison.
## There are less than 10 genes up and down in the kh_p15_scn comparison.

Plot the results separately.

for (k in seq_along(genotype_keepers)) {
  name <- names(genotype_keepers)[k]
  message("Examining ", name)
  keeper <- genotype_keepers[name]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- genotype_inclusions[[include_df_name]]
  includes <- genotype_inclusions[[include_name]]
  summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  num_rows <- nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
  nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]])
  nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  ## #1 is up and #2 is down, avoiding typeos here.
  num_objects <- length(genotype_cp[[name]])
  if (num_objects == 0) {
    warning("Something went wrong in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(genotype_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(genotype_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- genotype_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- genotype_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- genotype_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig)
      mf_tree_up_filename <- glue("12clusterProfiler_plots/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("12clusterProfiler_plots/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("12clusterProfiler_plots/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("12clusterProfiler_plots/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("12clusterProfiler_plots/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("12clusterProfiler_plots/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- genotype_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- genotype_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- genotype_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("12clusterProfiler_plots/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("12clusterProfiler_plots/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_down_filename <- glue("12clusterProfiler_plots/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("12clusterProfiler_plots/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("12clusterProfiler_plots/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, cateogories = go_categories)
      bp_bar_down_filename <- glue("12clusterProfiler_plots/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining kh_p08_dlgn
## There are 24 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## dimensionality reduction failed with provided drfun; falling back to stats::cmdscale.
## NULL
## There are insufficient significant results to plot.
## NULL
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## NULL
## Examining kh_p15_dlgn
## There are 44 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining kh_p08_retina
## There are 4 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_retina
## There are 10 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## NULL
## Examining kh_p08_scn
## There are 54 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## NULL
## Examining kh_p15_scn
## There are 5 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.

A few specific plots of interest: Colenso asked to label a few genes for the knockout/het p08_retinas, p08_scn, and p08_dlgn: either the top-15 or all significant. I am pretty sure if I tell it 15 and there are not that many, it will just do the significant? Let us find out!

26.5.2.2 ko/het for p08 retinas

table_name <- "kh_p08_retina"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting <- c("Opn4", "Gm9008", "Lrr1", "Cnbd1")
kh_p08_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = colors[["het_retina"]], color_high = colors[["ko_retina"]],
  label_column = "mgi_symbol", label = interesting, alpha = 1.0,
  outline = outline, size = 4)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p08_retina_volcano.pdf", width = 9, height = 9)
kh_p08_retina_volcano[["plot"]]
plotted <- dev.off()
kh_p08_retina_volcano[["plot"]]

kh_p08_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", outline = outline,
  label = interesting)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p08_retina_ma.pdf", width = 9, height = 9)
kh_p08_retina_ma[["plot"]]
plotted <- dev.off()
kh_p08_retina_ma[["plot"]]

26.5.2.3 ko/het p08 SCN

I am going to make an executive decision for this plot, 15 is too many and makes it crazy cluttered.

26.5.3 Repeat this with two sets of genes

table_name <- "kh_p08_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Fign", "Nrn1", "Dpysl2", "Actb", "Fgf9", "Otx2", "Sec23",
                       "Ncam1", "Map4", "Sec22b", "Nlgn3", "Marcks", "Cd47",
                       "Dpysl3", "Lin7c", "Cadm1", "Snx12", "Rhoa", "Inpp5f",
                       "Atg12", "Set", "Gsk3b", "Pdcd4", "Gabra2", "Tmco1", "Anapc16")
kh_p08_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq
_adjp",
  label_column = "mgi_symbol", label = interesting_genes, size = 4, alpha = 1.0,
  outline = outline, color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]])
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq
## _adjp is not in the table.
pp(file = "13genotype_ma_volcano/kh_p08_scn_volcano.pdf", width = 9, height = 9)
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
plotted <- dev.off()
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  outline = outline, p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p08_scn_ma.pdf", width = 9, height = 9)
kh_p08_scn_ma[["plot"]]
plotted <- dev.off()
kh_p08_scn_ma[["plot"]]

26.5.3.1 Same plot but a different set of labeled genes

table_name <- "kh_p08_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c(
  "Anapc16", "Gabra2", "Tmco1", "Sod2", "Fgf9", "Pdcd4", "Rhoa", "Gsk3b", "Foxp1",
  "Ncam1", "Marcks", "Fign", "Dpysl3", "Inpp5f", "Cadm1", "Map4", "Ugcg", "Elovl4",
  "Elavl1", "Cfl2", "Tnnt1", "Gnb1", "Impact", "Nrn1", "Nlgn3", "Actb", "Cd47",
  "Sec22b", "Slc17a7", "Vglut1", "Actb", "B4galt5", "Foxp1", "Otx2", "Lin7c",
  "Snx12", "Atg12", "Set")
kh_p08_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  outline = outline, label_column = "mgi_symbol", label = interesting_genes, size = 4, alpha = 1.0)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p08_scn_volcano_v2.pdf", width = 9, height = 9)
kh_p08_scn_volcano[["plot"]]
plotted <- dev.off()
kh_p08_scn_volcano[["plot"]]

## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  outline = outline, p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p08_scn_ma_v2.pdf", width = 9, height = 9)
kh_p08_scn_ma[["plot"]]
plotted <- dev.off()
kh_p08_scn_ma[["plot"]]

26.5.3.2 ko/het p08 dLGN

table_name <- "kh_p08_dlgn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
kh_p08_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
  outline = outline, label_column = "mgi_symbol", label = 10, size = 4, alpha = 1.0)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p08_dlgn_volcano.pdf", width = 9, height = 9)
kh_p08_dlgn_volcano[["plot"]]
plotted <- dev.off()
kh_p08_dlgn_volcano[["plot"]]

## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = 10, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p08_dlgn_ma.pdf", width = 9, height = 9)
kh_p08_dlgn_ma[["plot"]]
plotted <- dev.off()
kh_p08_dlgn_ma[["plot"]]

26.5.3.3 ko/het for p15 retinas

When last I ran this manually, it did not double-label, hopefully that remains true in the container.

table_name <- "kh_p15_retina"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting <- c("Opn4", "Gm9008", "Lrr1", "Cnbd1")
kh_p15_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
  color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
  label_column = "mgi_symbol", label = interesting, alpha = 1.0,
  outline = outline, size = 4)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p15_retina_volcano.pdf", width = 9, height = 9)
kh_p15_retina_volcano[["plot"]]
plotted <- dev.off()
kh_p15_retina_volcano[["plot"]]

## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p15_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p15_retina_ma.pdf", width = 9, height = 9)
kh_p15_retina_ma[["plot"]]
plotted <- dev.off()
kh_p15_retina_ma[["plot"]]

26.5.3.4 ko/het p15 SCN

26.5.4 Repeat this with two sets of genes

table_name <- "kh_p15_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Fign", "Nrn1", "Dpysl2", "Actb", "Fgf9", "Otx2", "Sec23",
                       "Ncam1", "Map4", "Sec22b", "Nlgn3", "Marcks", "Cd47",
                       "Dpysl3", "Lin7c", "Cadm1", "Snx12", "Rhoa", "Inpp5f",
                       "Atg12", "Set", "Gsk3b", "Pdcd4", "Gabra2", "Tmco1", "Anapc16")
kh_p15_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  label_column = "mgi_symbol", size = 4, alpha = 1.0,
  outline = outline, color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]])
pp(file = "13genotype_ma_volcano/kh_p15_scn_volcano.pdf", width = 9, height = 9)
kh_p15_scn_volcano[["plot"]]
plotted <- dev.off()
kh_p15_scn_volcano[["plot"]]

kh_p15_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p15_scn_ma.pdf", width = 9, height = 9)
kh_p15_scn_ma[["plot"]]
plotted <- dev.off()
kh_p15_scn_ma[["plot"]]

Round 2 with a separate gene set.

table_name <- "kh_p15_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c(
  "Anapc16", "Gabra2", "Tmco1", "Sod2", "Fgf9", "Pdcd4", "Rhoa", "Gsk3b", "Foxp1",
  "Ncam1", "Marcks", "Fign", "Dpysl3", "Inpp5f", "Cadm1", "Map4", "Ugcg", "Elovl4",
  "Elavl1", "Cfl2", "Tnnt1", "Gnb1", "Impact", "Nrn1", "Nlgn3", "Actb", "Cd47",
  "Sec22b", "Slc17a7", "Vglut1", "Actb", "B4galt5", "Foxp1", "Otx2", "Lin7c",
  "Snx12", "Atg12", "Set")
kh_p15_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  outline = outline, label_column = "mgi_symbol", label = interesting_genes, size = 4, alpha = 1.0)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p15_scn_volcano_v2.pdf", width = 9, height = 9)
kh_p15_scn_volcano[["plot"]]
plotted <- dev.off()
kh_p15_scn_volcano[["plot"]]

kh_p15_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p15_scn_ma_v2.pdf", width = 9, height = 9)
kh_p15_scn_ma[["plot"]]
plotted <- dev.off()
kh_p15_scn_ma[["plot"]]

26.5.4.1 ko/het p15 dLGN

table_name <- "kh_p15_dlgn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
kh_p15_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
  outline = outline, label_column = "mgi_symbol", label = 10, size = 4, alpha = 1.0)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano/kh_p15_dlgn_volcano.pdf", width = 9, height = 9)
kh_p15_dlgn_volcano[["plot"]]
plotted <- dev.off()
kh_p15_dlgn_volcano[["plot"]]

## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p15_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = 10, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "13genotype_ma_volcano/kh_p15_dlgn_ma.pdf", width = 9, height = 9)
kh_p15_dlgn_ma[["plot"]]
plotted <- dev.off()
kh_p15_dlgn_ma[["plot"]]

A query from Rashmi:

“I was discussing with Dr. Speer about the dLGN data and we found mostly retinal genes in dLGN Het/KO or time point comparison. Please check if those are not retina samples.”

I checked the samples etc and everything looks ok to me; perhaps I can use the results to look at this question in another way:

I will therefore load the p08_het_dlgn/p08_ko_dlgn table and compare it to the p08_het_retina/p08_ko_retina table directly. I think that if these turn out to be identical, then the hypothesis suggested by this query is correct.

Note, in order to do this, I must use the full tables, not the post-inclusion tables because I cannot guarantee that they will have identical gene IDs.

retina_table <- genotype_tables_full[["data"]][["kh_p08_retina"]]
dlgn_table <- genotype_tables_full[["data"]][["kh_p08_dlgn"]]
retina_subset <- retina_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(retina_subset) <- c("ID", "retina_logfc")
dlgn_subset <- dlgn_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(dlgn_subset) <- c("ID", "dlgn_logfc")
merged <- merge(retina_subset, dlgn_subset, by = "ID")
rownames(merged) <- make.names(merged[["ID"]], unique = TRUE)
merged[["ID"]] <- NULL
plotted <- plot_linear_scatter(merged)
## Warning in plot_linear_scatter(merged): Model type robust failed, falling back
## to a default lm.
pp(file = "images/kh_p08_retina_vs_dlgn_deseq_logfc_values.png")
plotted[["scatter"]]
dev.off()
## png 
##   2
plotted[["scatter"]]

Rashmi asked if we could also do the p15 for this comparison:

retina_table <- genotype_tables_full[["data"]][["kh_p15_retina"]]
dlgn_table <- genotype_tables_full[["data"]][["kh_p15_dlgn"]]
retina_subset <- retina_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(retina_subset) <- c("ID", "retina_logfc")
dlgn_subset <- dlgn_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(dlgn_subset) <- c("ID", "dlgn_logfc")
merged <- merge(retina_subset, dlgn_subset, by = "ID")
rownames(merged) <- make.names(merged[["ID"]], unique = TRUE)
merged[["ID"]] <- NULL
plotted <- plot_linear_scatter(merged)
## Warning in plot_linear_scatter(merged): Model type robust failed, falling back
## to a default lm.
pp(file = "images/kh_p15_retina_vs_dlgn_deseq_logfc_values.png")
plotted[["scatter"]]
dev.off()
## png 
##   2
plotted[["scatter"]]

26.5.4.2 Repeat with the strict filter

genotype_strict_tables <- list()
genotype_strict_sig <- list()
genotype_strict_gp <- list()
genotype_strict_cp <- list()
genotype_strict_en <- list()
for (k in seq_along(genotype_keepers)) {
  name <- names(genotype_keepers)[k]
  message("Examining ", name)
  keeper <- genotype_keepers[name]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_strict_df <- genotype_inclusions_strict[[include_df_name]]
  includes_strict <- genotype_inclusions_strict[[include_name]]
  summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes_strict)
  include_filename <- glue("14genotype_strict_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("14genotype_strict_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  genotype_strict_tables[[name]] <- combine_de_tables(
    genotype_de, extra_annot = include_strict_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes_strict)
  print(genotype_strict_tables[[name]])
  genotype_strict_sig[[name]] <- extract_significant_genes(
    genotype_strict_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(genotype_strict_sig[[name]])
  num_rows <- nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows >= 10) {
    message("Performing gprofiler/clusterProfiler.")
    genotype_strict_gp[[name]] <- all_gprofiler(genotype_strict_sig[[name]], species = "mmusculus")
    genotype_strict_cp[[name]] <- all_cprofiler(
      genotype_strict_sig[[name]], genotype_strict_tables[[name]],
      orgdb = "org.Mm.eg.db", go_level = go_level,
      orgdb_from = orgdb_from, max_groupsize = max_groupsize, organism = "mouse")
    #if (!is.null(get0("m2_gsc"))) {
    #  genotype_strict_en[[name]] <- all_enricher(genotype_strict_sig[[name]], gsc = m2_gsc,
    #                                      orgdb = "org.Mm.eg.db", from = "ENSEMBL", to = "SYMBOL")
    #}
    gp_written <- write_all_gp(genotype_strict_gp[[name]], prefix = "15", suffix = "strict")
    cp_written <- write_all_cp(genotype_strict_cp[[name]], prefix = "15", suffix = "strict")
    #en_written <- write_all_en(genotype_strict_en[[name]])
  } else {
    warning("There are less than 10 genes up and down in the ", name, " comparison.")
    message("There are less than 10 genes up and down in the ", name, " comparison.")
  }
}
## Examining kh_p08_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_het_dlgn           1             0           1
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           1             0
## Only kh_p08_dlgn_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## kh_p08_dlgn        1          0

## There are 1 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_dlgn
## comparison.
## There are less than 10 genes up and down in the kh_p08_dlgn comparison.
## Examining kh_p15_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p15_het_dlgn           0             0           0
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           0             0
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## kh_p15_dlgn        0          0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_dlgn
## comparison.
## There are less than 10 genes up and down in the kh_p15_dlgn comparison.
## Examining kh_p08_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_retina_vs_p08_het_retina           0             0           0
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           0             0
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##               deseq_up deseq_down
## kh_p08_retina        0          0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_retina
## comparison.
## There are less than 10 genes up and down in the kh_p08_retina comparison.
## Examining kh_p15_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_retina_vs_p15_het_retina           0             0           0
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           0             2
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##               deseq_up deseq_down
## kh_p15_retina        0          0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_retina
## comparison.
## There are less than 10 genes up and down in the kh_p15_retina comparison.
## Examining kh_p08_scn
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 25.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p08_ko_scn_vs_p08_het_scn           0             0           0             0
##   limma_sigup limma_sigdown
## 1           0             0
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## kh_p08_scn        0          0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_scn comparison.
## There are less than 10 genes up and down in the kh_p08_scn comparison.
## Examining kh_p15_scn
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 3.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p15_ko_scn_vs_p15_het_scn           0             0           0             0
##   limma_sigup limma_sigdown
## 1           0             0
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## kh_p15_scn        0          0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_scn comparison.
## There are less than 10 genes up and down in the kh_p15_scn comparison.

27 Genotype Strict plots

for (k in seq_along(genotype_keepers)) {
  name <- names(genotype_keepers)[k]
  message("Examining ", name)
  keeper <- genotype_keepers[name]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_strict_df <- genotype_inclusions_strict[[include_df_name]]
  includes_strict <- genotype_inclusions_strict[[include_name]]
  summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes_strict)
  num_rows <- nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]])
  nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  ## #1 is up and #2 is down, avoiding typeos here.
  num_objects <- length(genotype_strict_cp[[name]])
  if (num_objects == 0) {
    warning("Something went wrong in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(genotype_strict_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(genotype_strict_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_up_filename <- glue("16clusterProfiler_plots/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("16clusterProfiler_plots/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("16clusterProfiler_plots/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("16clusterProfiler_plots/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("16clusterProfiler_plots/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("16clusterProfiler_plots/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("16clusterProfiler_plots/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("16clusterProfiler_plots/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_down_filename <- glue("16clusterProfiler_plots/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("16clusterProfiler_plots/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("16clusterProfiler_plots/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, cateogories = go_categories)
      bp_bar_down_filename <- glue("16clusterProfiler_plots/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining kh_p08_dlgn
## There are 1 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_dlgn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_retina
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_retina
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_scn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_scn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.

Given this stricter filter, I think no genes pass in the genome comparisons.

27.0.1 Location contrasts with genes removed/kept

We will now repeat the above tasks seeking location differences instead of genotype; essentially I copy/pasted the above with s/genotype/location/g.

location_tables_full <- combine_de_tables(
  location_de, keepers = location_keepers, label_column = label_column,
  excel = glue("17full_location_contrasts/location_full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
location_tables_full
## A set of combined differential expression results.
##                             table deseq_sigup deseq_sigdown edger_sigup
## 1  p08_het_dlgn_vs_p08_het_retina        2165          1562        2212
## 2  p15_het_dlgn_vs_p15_het_retina        2437          3369        2587
## 3    p08_ko_dlgn_vs_p08_ko_retina        2180          1868        2144
## 4    p15_ko_dlgn_vs_p15_ko_retina        2715          3942        2934
## 5   p08_het_scn_vs_p08_het_retina        2634          1707        2586
## 6   p15_het_scn_vs_p15_het_retina        2841          2395        2716
## 7     p08_ko_scn_vs_p08_ko_retina        2728          1705        2644
## 8     p15_ko_scn_vs_p15_ko_retina        2613          3005        2612
## 9     p08_het_dlgn_vs_p08_het_scn         648           788         751
## 10    p15_het_dlgn_vs_p15_het_scn        1708          2796        1984
## 11      p08_ko_dlgn_vs_p08_ko_scn        1002          1342        1115
## 12      p15_ko_dlgn_vs_p15_ko_scn        1829          2529        2158
##    edger_sigdown limma_sigup limma_sigdown
## 1           1632        1886          1660
## 2           3339        2748          2639
## 3           2077        2104          1963
## 4           3847        3236          2962
## 5           1882        2226          1889
## 6           2616        2730          2366
## 7           1922        2386          2160
## 8           3143        2812          2623
## 9            780         647           766
## 10          2623        1979          2034
## 11          1439        1169          1317
## 12          2396        1878          2000
## Plot describing unique/shared genes in a differential expression table.

location_sig_full <- extract_significant_genes(
  location_tables_full, according_to = "deseq",
  excel = glue("17full_location_contrasts/location_full_sig-v{ver}.xlsx"))
location_sig_full
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## dr_p08_het     2165       1562
## dr_p15_het     2437       3369
## dr_p08_ko      2180       1868
## dr_p15_ko      2715       3942
## sr_p08_het     2634       1707
## sr_p15_het     2841       2395
## sr_p08_ko      2728       1705
## sr_p15_ko      2613       3005
## ds_p08_het      648        788
## ds_p15_het     1708       2796
## ds_p08_ko      1002       1342
## ds_p15_ko      1829       2529

location_full_upset <- upsetr_sig(location_sig_full)
location_full_intersects <- write_upset_groups(
  location_full_upset,
  excel = "excel/17full_location_contrasts/location_full_gene_groups.xlsx")
## Deleting the file excel/17full_location_contrasts/location_full_gene_groups.xlsx before writing the tables.
location_tables <- list()
location_sig <- list()
location_gp <- list()
location_cp <- list()
for (k in seq_along(location_keepers)) {
  name <- names(location_keepers)[k]
  message("Examining ", name)
  keeper <- location_keepers[name]
  includes <- location_inclusions[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- location_inclusions[[include_df_name]]
  includes <- location_inclusions[[include_name]]
  summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  include_filename <- glue("18location_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("18location_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  location_tables[[name]] <- combine_de_tables(
    location_de, extra_annot = include_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes)
  print(location_tables[[name]])
  location_sig[[name]] <- extract_significant_genes(
    location_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(location_sig[[name]])
  num_rows <- nrow(location_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows > 10) {
    location_gp[[name]] <- all_gprofiler(location_sig[[name]], species = "mmusculus")
    location_cp[[name]] <- all_cprofiler(
      location_sig[[name]], location_tables[[name]],
      orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
      max_groupsize = max_groupsize, organism = "mouse")
    cp_written <- write_all_cp(location_cp[[name]], prefix = "19")
    gp_written <- write_all_gp(location_gp[[name]], prefix = "19")
  }
}
## Examining dr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_retina         259            81         259
##   edger_sigdown limma_sigup limma_sigdown
## 1            85         240            81
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## dr_p08_het      259         81

## There are 340 significant up and down genes.
## Examining dr_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_het_retina         699           133         745
##   edger_sigdown limma_sigup limma_sigdown
## 1           119         687           119
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## dr_p15_het      699        133

## There are 832 significant up and down genes.
## Examining dr_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_ko_retina         584           116         566
##   edger_sigdown limma_sigup limma_sigdown
## 1           122         525           122
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## dr_p08_ko      584        116

## There are 700 significant up and down genes.
## Examining dr_p15_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p15_ko_retina         946           354        1002
##   edger_sigdown limma_sigup limma_sigdown
## 1           337        1048           310
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## dr_p15_ko      946        354

## There are 1300 significant up and down genes.
## Examining sr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                           table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_scn_vs_p08_het_retina         298           111         289
##   edger_sigdown limma_sigup limma_sigdown
## 1           115         249           119
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## sr_p08_het      298        111

## There are 409 significant up and down genes.
## Examining sr_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                           table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_scn_vs_p15_het_retina          84            86          82
##   edger_sigdown limma_sigup limma_sigdown
## 1            92          79            86
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## sr_p15_het       84         86

## There are 170 significant up and down genes.
## Examining sr_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_scn_vs_p08_ko_retina         409           126         384
##   edger_sigdown limma_sigup limma_sigdown
## 1           131         392           139
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## sr_p08_ko      409        126

## There are 535 significant up and down genes.
## Examining sr_p15_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_scn_vs_p15_ko_retina          83            86          83
##   edger_sigdown limma_sigup limma_sigdown
## 1            89          98            82
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## sr_p15_ko       83         86

## There are 169 significant up and down genes.
## Examining ds_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_scn          38            43          43
##   edger_sigdown limma_sigup limma_sigdown
## 1            39          35            29
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## ds_p08_het       38         43

## There are 81 significant up and down genes.
## Examining ds_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_het_scn         888             3        1006
##   edger_sigdown limma_sigup limma_sigdown
## 1             3         897             3
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## ds_p15_het      888          3

## There are 891 significant up and down genes.
## Examining ds_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p08_ko_dlgn_vs_p08_ko_scn         129            21         142            21
##   limma_sigup limma_sigdown
## 1         118            21
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## ds_p08_ko      129         21

## There are 150 significant up and down genes.
## Examining ds_p15_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p15_ko_dlgn_vs_p15_ko_scn         939            13        1082             9
##   limma_sigup limma_sigdown
## 1         831            10
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## ds_p15_ko      939         13

## There are 952 significant up and down genes.

Print out all the plots in a separate block.

for (k in seq_along(location_keepers)) {
  name <- names(location_keepers)[k]
  message("Examining ", name)
  keeper <- location_keepers[name]
  includes <- location_inclusions[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- location_inclusions[[include_df_name]]
  includes <- location_inclusions[[include_name]]
  summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  num_rows <- nrow(location_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
  nrow(location_sig[[name]][["deseq"]][["ups"]][[name]])
  nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  num_objects <- length(location_cp[[name]])
  if (num_objects == 0) {
    warning("Something went wrong in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(location_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(location_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- location_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- location_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- location_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_up_filename <- glue("19clusterProfiler_plots/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("19clusterProfiler_plots/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("19clusterProfiler_plots/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("19clusterProfiler_plots/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("19clusterProfiler_plots/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("19clusterProfiler_plots/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- location_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- location_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- location_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("19clusterProfiler_plots/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("19clusterProfiler_plots/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = 12)
      cc_tree_down_filename <- glue("19clusterProfiler_plots/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("19clusterProfiler_plots/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("19clusterProfiler_plots/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_down_filename <- glue("19clusterProfiler_plots/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining dr_p08_het
## There are 340 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining dr_p15_het
## There are 832 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining dr_p08_ko
## There are 700 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining dr_p15_ko
## There are 1300 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p08_het
## There are 409 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p15_het
## There are 170 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p08_ko
## There are 535 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p15_ko
## There are 169 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining ds_p08_het
## There are 81 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining ds_p15_het
## There are 891 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining ds_p08_ko
## There are 150 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining ds_p15_ko
## There are 952 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?

Colenso sent a specific query of interest, comparing SCN vs. Retinas at p08 in the heterozygotes including a set of genes of particular interest. Perhaps I can use some of these as markers to quality control my work in the future?

Here are the genes:

Opn4, Eomes, Trpc7, Oprm1, Nr4a3, Tbx20, Irx6, AW551984, Pcdh19, Adcyap1, Baiap3, Chl1, Grin3a, Igf1, Gria1, Grin2d, Grin3a, Chrna6, Chrna3, Htr5a, Htr2a, Htr7, Irx4, PlxnC1, Sema6d, Sema4f, Sema4a, Sema6b, Lrrc4b, Lrrc58, Lrrc3b, Wnt4, Wnt9b, Ctxn3, Tenm1, Gna14, Rgs4, Rgs6, Rgs5

table_input <- location_tables[["sr_p08_het"]]
table_name <- "sr_p08_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
                       "Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
                       "Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
                       "Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
                       "PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
                       "Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
                       "Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p08_het_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4)
pp(file = "20location_ma_volcano/sr_p08_het_volcano.pdf", width = 9, height = 9)
sr_p08_het_volcano[["plot"]]
plotted <- dev.off()
sr_p08_het_volcano[["plot"]]

sr_p08_het_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "20location_ma_volcano/sr_p08_het_ma.pdf", width = 9, height = 9)
sr_p08_het_ma[["plot"]]
plotted <- dev.off()
sr_p08_het_ma[["plot"]]

27.0.2 Also the ko

table_input <- location_tables[["sr_p08_ko"]]
table_name <- "sr_p08_ko"
table <- table_input[["data"]][[table_name]]
sr_p08_ko_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4)
pp(file = "20location_ma_volcano/sr_p08_ko_volcano.pdf", width = 9, height = 9)
sr_p08_ko_volcano[["plot"]]
plotted <- dev.off()
sr_p08_ko_volcano[["plot"]]

sr_p08_ko_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "20location_ma_volcano/sr_p08_ko_ma.pdf", width = 9, height = 9)
sr_p08_ko_ma[["plot"]]
plotted <- dev.off()
sr_p08_ko_ma[["plot"]]

table_input <- location_tables[["sr_p15_het"]]
table_name <- "sr_p15_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
                       "Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
                       "Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
                       "Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
                       "PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
                       "Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
                       "Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p15_het_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4)
pp(file = "20location_ma_volcano/sr_p15_het_volcano.pdf", width = 9, height = 9)
sr_p15_het_volcano[["plot"]]
plotted <- dev.off()
sr_p15_het_volcano[["plot"]]

sr_p15_het_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "20location_ma_volcano/sr_p15_het_ma.pdf", width = 9, height = 9)
sr_p15_het_ma[["plot"]]
plotted <- dev.off()
sr_p15_het_ma[["plot"]]

27.0.3 Also the ko

table_input <- location_tables[["sr_p15_ko"]]
table_name <- "sr_p15_ko"
table <- table_input[["data"]][[table_name]]
sr_p15_ko_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "20location_ma_volcano/sr_p15_ko_volcano.pdf", width = 12, height = 12)
sr_p15_ko_volcano[["plot"]]
plotted <- dev.off()
sr_p15_ko_volcano[["plot"]]

sr_p15_ko_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "20location_ma_volcano/sr_p15_ko_ma.pdf", width = 9, height = 9)
sr_p15_ko_ma[["plot"]]
plotted <- dev.off()
sr_p15_ko_ma[["plot"]]

27.0.3.1 Test a specific location query for duplicated IDs

Let us see if any Ensembl gene IDs and/or MGI IDs are shared in the worksheet location_sr_p08_ko_including_wt_0.1_decreased_sig up/down.

test_table_up <- location_sig[["sr_p08_ko"]][["deseq"]][["ups"]][[1]]
test_table_down <- location_sig[["sr_p08_ko"]][["deseq"]][["downs"]][[1]]

query <- list("up" = rownames(test_table_up),
              "down" = rownames(test_table_down))
query_upset <- UpSetR::fromList(query)
UpSetR::upset(query_upset)
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?

query <- list("up" = test_table_up[["mgi_symbol"]],
              "down" = test_table_down[["mgi_symbol"]])
query_upset <- UpSetR::fromList(query)
UpSetR::upset(query_upset)
## Error in `start_col:end_col`:
## ! argument of length 0
## ok, good.

27.0.3.2 Repeat with the strict filter

location_strict_tables <- list()
location_strict_sig <- list()
location_strict_gp <- list()
location_strict_cp <- list()
for (k in seq_along(location_keepers)) {
  name <- names(location_keepers)[k]
  message("Examining ", name)
  keeper <- location_keepers[name]
  includes <- location_inclusions_strict[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- location_inclusions_strict[[include_df_name]]
  includes <- location_inclusions_strict[[include_name]]
  found_includes <- rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes
  summary(found_includes)
  if (sum(found_includes) == 0) {
    next
  }
  include_filename <- glue("21location_strict_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("21location_strict_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  location_strict_tables[[name]] <- combine_de_tables(
    location_de, extra_annot = include_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes)
  print(location_strict_tables[[name]])
  location_strict_sig[[name]] <- extract_significant_genes(
    location_strict_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(location_strict_sig[[name]])
  num_rows <- nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows > 10) {
    location_strict_gp[[name]] <- all_gprofiler(location_strict_sig[[name]], species = "mmusculus")
    location_strict_cp[[name]] <- all_cprofiler(
      location_strict_sig[[name]], location_strict_tables[[name]],
      orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
      max_groupsize = max_groupsize, organism = "mouse")
    cp_written <- write_all_cp(location_strict_cp[[name]], prefix = "22", suffix = "strict")
    gp_written <- write_all_gp(location_strict_gp[[name]], prefix = "22", suffix = "strict")
  }
}
## Examining dr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 22.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_retina           7             0           8
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           5             0
## Only dr_p08_het_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## dr_p08_het        7          0

## There are 7 significant up and down genes.
## Examining dr_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_het_retina          65             5          65
##   edger_sigdown limma_sigup limma_sigdown
## 1             5          57             4
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## dr_p15_het       65          5

## There are 70 significant up and down genes.
## Examining dr_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_ko_retina          40             1          39
##   edger_sigdown limma_sigup limma_sigdown
## 1             1          32             0
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## dr_p08_ko       40          1

## There are 41 significant up and down genes.
## Examining dr_p15_ko
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 48.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p15_ko_retina          25             6          25
##   edger_sigdown limma_sigup limma_sigdown
## 1             5          27             5
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## dr_p15_ko       25          6

## There are 31 significant up and down genes.
## Examining sr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 13.
## A set of combined differential expression results.
##                           table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_scn_vs_p08_het_retina           6             0           6
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           3             1
## Only sr_p08_het_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## sr_p08_het        6          0

## There are 6 significant up and down genes.
## Examining sr_p15_het
## Examining sr_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 39.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_scn_vs_p08_ko_retina          12             0          11
##   edger_sigdown limma_sigup limma_sigdown
## 1             0          12             0
## Only sr_p08_ko_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## sr_p08_ko       12          0

## There are 12 significant up and down genes.
## Examining sr_p15_ko
## Examining ds_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 3.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_scn           2             0           2
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           2             0
## Only ds_p08_het_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## ds_p08_het        2          0

## There are 2 significant up and down genes.
## Examining ds_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 2.
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_het_scn           1             0           1
##   edger_sigdown limma_sigup limma_sigdown
## 1             0           1             0
## Only ds_p15_het_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## ds_p15_het        1          0

## There are 1 significant up and down genes.
## Examining ds_p08_ko
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 16.
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p08_ko_dlgn_vs_p08_ko_scn           2             2           3             2
##   limma_sigup limma_sigdown
## 1           1             2
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## ds_p08_ko        2          2

## There are 4 significant up and down genes.
## Examining ds_p15_ko

Print out all the plots in a separate block.

for (k in seq_along(location_keepers)) {
  name <- names(location_keepers)[k]
  message("Examining ", name)
  keeper <- location_keepers[name]
  includes <- location_inclusions_strict[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- location_inclusions_strict[[include_df_name]]
  includes <- location_inclusions_strict[[include_name]]
  summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  num_rows <- nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]])
  nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  num_objects <- length(location_strict_cp[[name]])
  if (num_objects == 0) {
    warning("Something went wrong in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(location_strict_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(location_strict_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_up_filename <- glue("23clusterProfiler_plots/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("23clusterProfiler_plots/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("23clusterProfiler_plots/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("23clusterProfiler_plots/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("23clusterProfiler_plots/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("23clusterProfiler_plots/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("23clusterProfiler_plots/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("23clusterProfiler_plots/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = 12)
      cc_tree_down_filename <- glue("23clusterProfiler_plots/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("23clusterProfiler_plots/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("23clusterProfiler_plots/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_down_filename <- glue("23clusterProfiler_plots/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining dr_p08_het
## There are 7 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining dr_p15_het
## There are 70 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining dr_p08_ko
## There are 41 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## NULL
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining dr_p15_ko
## There are 31 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p08_het
## There are 6 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p15_het
## There are  significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p08_ko
## There are 12 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining sr_p15_ko
## There are  significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_het
## There are 2 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_het
## There are 1 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_ko
## There are 4 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_ko
## There are  significant up and down genes.
## Warning: Something went wrong in all_cprofiler.

Colenso sent a specific query of interest, comparing SCN vs. Retinas at p08 in the heterozygotes including a set of genes of particular interest. Perhaps I can use some of these as markers to quality control my work in the future?

Here are the genes:

Opn4, Eomes, Trpc7, Oprm1, Nr4a3, Tbx20, Irx6, AW551984, Pcdh19, Adcyap1, Baiap3, Chl1, Grin3a, Igf1, Gria1, Grin2d, Grin3a, Chrna6, Chrna3, Htr5a, Htr2a, Htr7, Irx4, PlxnC1, Sema6d, Sema4f, Sema4a, Sema6b, Lrrc4b, Lrrc58, Lrrc3b, Wnt4, Wnt9b, Ctxn3, Tenm1, Gna14, Rgs4, Rgs6, Rgs5

table_input <- location_strict_tables[["sr_p08_het"]]
table_name <- "sr_p08_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
                       "Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
                       "Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
                       "Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
                       "PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
                       "Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
                       "Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p08_het_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4)
pp(file = "24location_ma_volcano_strict/sr_p08_het_volcano.pdf", width = 9, height = 9)
sr_p08_het_volcano[["plot"]]
plotted <- dev.off()
sr_p08_het_volcano[["plot"]]

sr_p08_het_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "24location_ma_volcano_strict/sr_p08_het_ma.pdf", width = 9, height = 9)
sr_p08_het_ma[["plot"]]
plotted <- dev.off()
sr_p08_het_ma[["plot"]]

27.0.4 Also the ko

table_input <- location_strict_tables[["sr_p08_ko"]]
table_name <- "sr_p08_ko"
table <- table_input[["data"]][[table_name]]
sr_p08_ko_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4)
pp(file = "24location_ma_volcano_strict/sr_p08_ko_volcano.pdf", width = 9, height = 9)
sr_p08_ko_volcano[["plot"]]
plotted <- dev.off()
sr_p08_ko_volcano[["plot"]]

sr_p08_ko_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "24location_ma_volcano_strict/sr_p08_ko_ma.pdf", width = 9, height = 9)
sr_p08_ko_ma[["plot"]]
plotted <- dev.off()
sr_p08_ko_ma[["plot"]]

27.0.5 Also the ko

table_input <- location_tables[["sr_p15_ko"]]
table_name <- "sr_p15_ko"
table <- table_input[["data"]][[table_name]]
sr_p15_ko_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "24location_ma_volcano_strict/sr_p15_ko_volcano.pdf", width = 12, height = 12)
sr_p15_ko_volcano[["plot"]]
plotted <- dev.off()
sr_p15_ko_volcano[["plot"]]

sr_p15_ko_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "24location_ma_volcano_strict/sr_p15_ko_ma.pdf", width = 9, height = 9)
sr_p15_ko_ma[["plot"]]
plotted <- dev.off()
sr_p15_ko_ma[["plot"]]

27.0.6 And time

time_tables_full <- combine_de_tables(
  time_de, keepers = time_keepers,
  label_column = label_column,
  excel = glue("25full_contrasts_time/full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
time_sig_full <- extract_significant_genes(
  time_tables_full, according_to = "deseq",
  excel = glue("25full_contrasts_time/full_sig-v{ver}.xlsx"))
time_tables <- list()
time_sig <- list()
time_gp <- list()
time_cp <- list()
for (k in seq_along(time_keepers)) {
  name <- names(time_keepers)[k]
  message("Examining ", name)
  keeper <- time_keepers[name]
  includes <- time_inclusions[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- time_inclusions[[include_df_name]]
  includes <- time_inclusions[[include_name]]
  summary(rownames(time_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
  include_filename <- glue("26time_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("26time_contrasts/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  time_tables[[name]] <- combine_de_tables(
    time_de, extra_annot = include_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes)
  print(time_tables[[name]])
  time_sig[[name]] <- extract_significant_genes(
    time_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(time_sig[[name]])
  num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows > 10) {
    time_gp[[name]] <- all_gprofiler(time_sig[[name]], species = "mmusculus")
    gp_written <- write_all_gp(time_gp[[name]])
    time_cp[[name]] <- all_cprofiler(
      time_sig[[name]], time_tables[[name]], orgdb = "org.Mm.eg.db", organism = "mouse",
      orgdb_from = orgdb_from, go_level = go_level, max_groupsize = max_groupsize)
    cp_written <- write_all_cp(time_cp[[name]], prefix = "27")
    gp_written <- write_all_gp(time_gp[[name]], prefix = "27")
  }
}
## Examining t_het_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p08_het_dlgn         397            14         431
##   edger_sigdown limma_sigup limma_sigdown
## 1            14         359            13
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## t_het_dlgn      397         14

## There are 411 significant up and down genes.
## Examining t_ko_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p08_ko_dlgn         670            90         777
##   edger_sigdown limma_sigup limma_sigdown
## 1            77         572            77
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## t_ko_dlgn      670         90

## There are 760 significant up and down genes.
## Examining t_het_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_retina_vs_p08_het_retina          49           122          49
##   edger_sigdown limma_sigup limma_sigdown
## 1           127          41           160
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##              deseq_up deseq_down
## t_het_retina       49        122

## There are 171 significant up and down genes.
## Examining t_ko_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_retina_vs_p08_ko_retina          71           244          75
##   edger_sigdown limma_sigup limma_sigdown
## 1           253          61           370
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## t_ko_retina       71        244

## There are 315 significant up and down genes.
## Examining t_het_scn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_scn_vs_p08_het_scn           1             2           1
##   edger_sigdown limma_sigup limma_sigdown
## 1             2           0             2
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## t_het_scn        1          2

## There are 3 significant up and down genes.
## Examining t_ko_scn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                      table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p15_ko_scn_vs_p08_ko_scn           0            22           0            20
##   limma_sigup limma_sigdown
## 1           1            24
## Only t_ko_scn_down has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##          deseq_up deseq_down
## t_ko_scn        0         22

## There are 22 significant up and down genes.

Send the plots separately.

for (k in seq_along(time_keepers)) {
  name <- names(time_keepers)[k]
  message("Examining ", name)
  keeper <- time_keepers[name]
  includes <- time_inclusions[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- time_inclusions[[include_df_name]]
  includes <- time_inclusions[[include_name]]
  num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  num_objects <- length(time_cp[[name]])
  if (num_objects == 0) {
    warning("Something failed in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(time_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(time_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- time_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- time_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- time_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_up_filename <- glue("28clusterProfiler_plots/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("28clusterProfiler_plots/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("28clusterProfiler_plots/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("28clusterProfiler_plots/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("28clusterProfiler_plots/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("28clusterProfiler_plots/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- time_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- time_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- time_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("28clusterProfiler_plots/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("28clusterProfiler_plots/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_down_filename <- glue("28clusterProfiler_plots/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("28clusterProfiler_plots/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("28clusterProfiler_plots/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_down_filename <- glue("28clusterProfiler_plots/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining t_het_dlgn
## There are 411 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_ko_dlgn
## There are 760 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in max(idx1, idx2): no non-missing arguments to max; returning -Inf
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## no non-missing arguments to max; returning -Inf
## Examining t_het_retina
## There are 171 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_ko_retina
## There are 315 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_het_scn
## There are 3 significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_ko_scn
## There are 22 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?

27.1 Volcano plots by time

27.1.1 t_het_dlgn

table_name <- "t_het_dlgn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_het_dlgn_volcano.pdf", width = 12, height = 12)
t_het_dlgn_volcano[["plot"]]
plotted <- dev.off()
t_het_dlgn_volcano[["plot"]]

t_het_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_het_dlgn_ma.pdf", width = 9, height = 9)
t_het_dlgn_ma[["plot"]]
plotted <- dev.off()
t_het_dlgn_ma[["plot"]]

27.1.2 t_ko_dlgn

table_name <- "t_ko_dlgn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_dlgn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_ko_dlgn_volcano.pdf", width = 12, height = 12)
t_ko_dlgn_volcano[["plot"]]
plotted <- dev.off()
t_ko_dlgn_volcano[["plot"]]

t_ko_dlgn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_ko_dlgn_ma.pdf", width = 9, height = 9)
t_ko_dlgn_ma[["plot"]]
plotted <- dev.off()
t_ko_dlgn_ma[["plot"]]

27.1.3 t_het_retina

table_name <- "t_het_retina"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_retina"]], color_high = time_colors[["p15_het_retina"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_het_retina_volcano.pdf", width = 12, height = 12)
t_het_retina_volcano[["plot"]]
plotted <- dev.off()
t_het_retina_volcano[["plot"]]

t_het_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_retina"]], color_high = time_colors[["p15_het_retina"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_het_retina_ma.pdf", width = 9, height = 9)
t_het_retina_ma[["plot"]]
plotted <- dev.off()
t_het_retina_ma[["plot"]]

27.1.4 t_ko_retina

table_name <- "t_ko_retina"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_retina_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_ko_retina_volcano.pdf", width = 12, height = 12)
t_ko_retina_volcano[["plot"]]
plotted <- dev.off()
t_ko_retina_volcano[["plot"]]

t_ko_retina_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_ko_retina_ma.pdf", width = 9, height = 9)
t_ko_retina_ma[["plot"]]
plotted <- dev.off()
t_ko_retina_ma[["plot"]]

27.2 t_het_scn

table_name <- "t_het_scn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_het_scn_volcano.pdf", width = 12, height = 12)
t_het_scn_volcano[["plot"]]
plotted <- dev.off()
t_het_scn_volcano[["plot"]]

t_het_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_het_scn_ma.pdf", width = 9, height = 9)
t_het_scn_ma[["plot"]]
plotted <- dev.off()
t_het_scn_ma[["plot"]]

27.3 t_ko_scn

table_name <- "t_ko_scn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_scn_volcano <- plot_volcano_condition_de(
  table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  label_column = "mgi_symbol", label = interesting_genes, alpha = 1.0,
  size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano/t_ko_scn_volcano.pdf", width = 12, height = 12)
t_ko_scn_volcano[["plot"]]
plotted <- dev.off()
t_ko_scn_volcano[["plot"]]

t_ko_scn_ma <- plot_ma_condition_de(
  table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
  color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
  p_col = "deseq_adjp", label_column = "mgi_symbol", label = interesting_genes, outline = outline)
## The column: mgi_symbol is not in the data, using rownames.
pp(file = "29time_ma_volcano/t_ko_scn_ma.pdf", width = 9, height = 9)
t_ko_scn_ma[["plot"]]
plotted <- dev.off()
t_ko_scn_ma[["plot"]]

27.3.0.1 Repeat with the strict filter

time_strict_tables <- list()
time_strict_sig <- list()
time_strict_gp <- list()
time_strict_cp <- list()
time_strict_en <- list()
for (k in seq_along(time_keepers)) {
  name <- names(time_keepers)[k]
  message("Examining ", name)
  keeper <- time_keepers[name]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- time_inclusions_strict[[include_df_name]]
  includes <- time_inclusions_strict[[include_name]]
  found_includes <- rownames(time_sig_full[["deseq"]][["ups"]][[name]]) %in% includes
  summary(found_includes)
  if (sum(found_includes) == 0) {
    next
  }
  include_filename <- glue("30time_strict_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("30time_strict_contrasts_excel/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
  time_strict_tables[[name]] <- combine_de_tables(
    time_de, extra_annot = include_df,
    keepers = keeper, label_column = label_column,
    excel = include_filename, wanted_genes = includes)
  print(time_strict_tables[[name]])
  time_strict_sig[[name]] <- extract_significant_genes(
    time_strict_tables[[name]], according_to = "deseq",
    excel = include_sig_filename)
  print(time_strict_sig[[name]])
  num_rows <- nrow(time_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(time_strict_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  if (num_rows >= 10) {
    message("Performing gprofiler/clusterProfiler.")
    time_strict_gp[[name]] <- all_gprofiler(time_strict_sig[[name]], species = "mmusculus")
    time_strict_cp[[name]] <- all_cprofiler(
      time_strict_sig[[name]], time_strict_tables[[name]],
      orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
      max_groupsize = max_groupsize, organism = "mouse")
    #if (!is.null(get0("m2_gsc"))) {
    #  time_strict_en[[name]] <- all_enricher(time_strict_sig[[name]], gsc = m2_gsc,
    #                                      orgdb = "org.Mm.eg.db", from = "ENSEMBL", to = "SYMBOL")
    #}
    gp_written <- write_all_gp(time_strict_gp[[name]], prefix = "31", suffix = "strict")
    cp_written <- write_all_cp(time_strict_cp[[name]], prefix = "31", suffix = "strict")
    #en_written <- write_all_en(time_strict_en[[name]])
  } else {
    warning("There are less than 10 genes up and down in the ", name, " comparison.")
    message("There are less than 10 genes up and down in the ", name, " comparison.")
  }
}
## Examining t_het_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p08_het_dlgn          19             2          20
##   edger_sigdown limma_sigup limma_sigdown
## 1             2          12             3
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##            deseq_up deseq_down
## t_het_dlgn       19          2

## There are 21 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining t_ko_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p08_ko_dlgn           8            12           9
##   edger_sigdown limma_sigup limma_sigdown
## 1             9           7             9
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##           deseq_up deseq_down
## t_ko_dlgn        8         12

## There are 20 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining t_het_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                              table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_retina_vs_p08_het_retina          13            15          13
##   edger_sigdown limma_sigup limma_sigdown
## 1            17          11            25
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##              deseq_up deseq_down
## t_het_retina       13         15

## There are 28 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining t_ko_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
##                            table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_retina_vs_p08_ko_retina           9            20          10
##   edger_sigdown limma_sigup limma_sigdown
## 1            20           8            48
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
##             deseq_up deseq_down
## t_ko_retina        9         20

## There are 29 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Examining t_het_scn
## Examining t_ko_scn

Send the plots separately.

for (k in seq_along(time_keepers)) {
  name <- names(time_keepers)[k]
  message("Examining ", name)
  keeper <- time_keepers[name]
  includes <- time_inclusions[[name]]
  include_name <- paste0("inc_", name)
  include_df_name <- paste0("df_", name)
  include_df <- time_inclusions[[include_df_name]]
  includes <- time_inclusions[[include_name]]
  num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
  message("There are ", num_rows, " significant up and down genes.")
  num_objects <- length(time_cp[[name]])
  if (num_objects == 0) {
    warning("Something failed in all_cprofiler.")
  } else {
    upp <- which(grepl(x = names(time_cp[[name]]), pattern = "_up$"))
    downp <- which(grepl(x = names(time_cp[[name]]), pattern = "_down$"))
    if (length(upp) > 0) {
      mf_sig <- time_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
      cc_sig <- time_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
      bp_sig <- time_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
      mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_up_filename <- glue("32cp_trees/{name}_up_mf_sig_tree.pdf")
      pp(file = mf_tree_up_filename)
      try(print(mf_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_up_filename <- glue("32cp_bar/{name}_up_mf_sig_bar.pdf")
      pp(file = mf_bar_up_filename)
      try(print(mf_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_up_filename <- glue("32cp_trees/{name}_up_cc_sig_tree.pdf")
      pp(file = cc_tree_up_filename)
      try(print(cc_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_up_filename <- glue("32cp_bar/{name}_up_cc_sig_bar.pdf")
      pp(file = cc_bar_up_filename)
      try(print(cc_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_up_filename <- glue("32cp_trees/{name}_up_bp_sig_tree.pdf")
      pp(file = bp_tree_up_filename)
      try(print(bp_plots_up[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_up_filename <- glue("32cp_bar/{name}_up_bp_sig_bar.pdf")
      pp(file = bp_bar_up_filename)
      try(print(bp_plots_up[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
    if (length(downp) > 0) {
      mf_sig <- time_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
      cc_sig <- time_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
      bp_sig <- time_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
      mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
      mf_tree_down_filename <- glue("32cp_trees/{name}_down_mf_sig_tree.pdf")
      pp(file = mf_tree_down_filename)
      try(print(mf_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      mf_bar_down_filename <- glue("32cp_bar/{name}_down_mf_sig_bar.pdf")
      pp(file = mf_bar_down_filename)
      try(print(mf_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
      cc_tree_down_filename <- glue("32cp_trees/{name}_down_cc_sig_tree.pdf")
      pp(file = cc_tree_down_filename)
      try(print(cc_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      cc_bar_down_filename <- glue("32cp_bar/{name}_down_cc_sig_bar.pdf")
      pp(file = cc_bar_down_filename)
      try(print(cc_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_tree_down_filename <- glue("32cp_trees/{name}_down_bp_sig_tree.pdf")
      pp(file = bp_tree_down_filename)
      try(print(bp_plots_down[["tree"]]), silent = TRUE)
      plotted <- dev.off()
      bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
      bp_bar_down_filename <- glue("32cp_bar/{name}_down_bp_sig_bar.pdf")
      pp(file = bp_bar_down_filename)
      try(print(bp_plots_down[["dot"]]), silent = TRUE)
      plotted <- dev.off()
    }
  }
}
## Examining t_het_dlgn
## There are 411 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_ko_dlgn
## There are 760 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in max(idx1, idx2): no non-missing arguments to max; returning -Inf
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## no non-missing arguments to max; returning -Inf
## Examining t_het_retina
## There are 171 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_ko_retina
## There are 315 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Examining t_het_scn
## There are 3 significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_ko_scn
## There are 22 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
## Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?

28 Translatome queries

In conversation with Colenso, he spoke about a series of contrasts which would be interesting to attempt in order to query the changes across both locations and genotypes and/or both locations and time, thus:

(p08_het_scn / p08_het_retina) / (p08_ko_scn / p08_ko_retina)

as an example. We can definitely do these, but they do not work for all methods employed (I think they work best with limma and edgeR).

Lets find out!

28.1 Two scn/retina comparisons

  • (p08_het_scn / p08_het_retina) / (p08_ko_scn / p08_ko_retina)
  • (p15_het_scn / p15_het_retina) / (p15_ko_scn / p15_ko_retina)
scn_extra <- glue("\\
  p08het = (conditionp08_het_scn - conditionp08_het_retina), \\
  p08ko = (conditionp08_ko_scn - conditionp08_ko_retina), \\
  p08het_vs_p08ko = (conditionp08_het_scn - conditionp08_het_retina) - (conditionp08_ko_scn - conditionp08_ko_retina), \\
  p15het = (conditionp15_het_scn - conditionp15_het_retina), \\
  p15ko = (conditionp15_ko_scn - conditionp15_ko_retina), \\
  p15het_vs_p15ko = (conditionp15_het_scn - conditionp15_het_retina) - (conditionp15_ko_scn - conditionp15_ko_retina)")
scn_translatome_de_keepers <- list(
  "p08het" = c("p08_het_scn", "p08_het_retina"),
  "p08ko" = c("p08_ko_scn", "p08_ko_retina"),
  "p15het" = c("p15_het_scn", "p15_het_retina"),
  "p15ko" = c("p15_ko_scn", "p15_ko_retina"))
scn_translatome_keepers <- list(
  "p08het" = c("p08_het_scn", "p08_het_retina"),
  "p08ko" = c("p08_ko_scn", "p08_ko_retina"),
  "p08_scn_translatome" = c("p08het", "p08ko"),
  "p15het" = c("p15_het_scn", "p15_het_retina"),
  "p15ko" = c("p15_ko_scn", "p15_ko_retina"),
  "p15_scn_translatome" = c("p15het", "p15ko"))
filt <- normalize(v3_pairwise_input, filter = TRUE)
## Removing 10162 low-count genes (15263 remaining).
limma_test <- limma_pairwise(filt,
                             keepers = scn_translatome_de_keepers,
                             model_fstring = "~ 0 + condition",
                             model_svs = FALSE, extra_contrastrs = scn_extra)
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
edger_test <- edger_pairwise(filt,
                             keepers = scn_translatome_de_keepers,
                             model_fstring = "~ 0 + condition",
                             model_svs = FALSE, extra_contrasts = scn_extra)
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
scn_translatome_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                   keepers = scn_translatome_de_keepers,
                                   model_svs = FALSE,
                                   model_fstring = "~ 0 + condition",
                                   do_basic = FALSE, do_dream = FALSE,
                                   do_noiseq = FALSE, do_ebseq = FALSE,
                                   extra_contrasts = scn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## scn_translatome_de_keepers, : This will likely fail because of how the keepers
## and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p15ko_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

scn_combined_test <- combine_de_tables(
  scn_translatome_de, keepers = scn_translatome_keepers,
  excel = glue("33translatome_xlsx/test_scn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## coefficient edger did not find conditionp15ko or conditionp15het.
## coefficient limma did not find p15ko or p15het.
## Looking for subscript invalid names, end of extract_keepers.
scn_translatome_de_sva <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                       keepers = scn_translatome_de_keepers,
                                       model_svs = "svaseq",
                                       model_fstring = "~ 0 + condition",
                                       do_basic = FALSE, do_dream = FALSE,
                                       do_noiseq = FALSE, do_ebseq = FALSE,
                                       extra_contrasts = scn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## scn_translatome_de_keepers, : This will likely fail because of how the keepers
## and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p15ko_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

scn_combined_test_sva <- combine_de_tables(
  scn_translatome_de_sva, keepers = scn_translatome_keepers,
  excel = glue("33translatome_xlsx/test_scn_translatome_unfiltered_sva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## coefficient edger did not find conditionp15ko or conditionp15het.
## coefficient limma did not find p15ko or p15het.
## Looking for subscript invalid names, end of extract_keepers.

28.1.1 Subtracting DESeq2 results: p08 scn het vs ko

p08_scn_combined_deseq <- subtract_de_results(
  first_table = scn_combined_test[["data"]][["p08het"]],
  second_table = scn_combined_test[["data"]][["p08ko"]],
  first_lfc = "deseq_logfc", second_lfc = "deseq_logfc",
  first_p = "deseq_adjp", second_p = "deseq_adjp",
  first_name = "het", second_name = "ko",
  excel = glue("33translatome_xlsx/translatome_p08_scn_combined_deseq-v{ver}.xlsx"))

28.1.2 Subtracting DESeq2 results: p15 scn het vs ko

p15_scn_combined_deseq <- subtract_de_results(
  first_table = scn_combined_test[["data"]][["p15het"]],
  second_table = scn_combined_test[["data"]][["p15ko"]],
  first_lfc = "deseq_logfc", second_lfc = "deseq_logfc",
  first_p = "deseq_adjp", second_p = "deseq_adjp",
  first_name = "het", second_name = "ko",
  excel = glue("34translatome_deseqsub_xlsx/translatome_p15_scn_combined_deseq-v{ver}.xlsx"))

28.2 One dlgn/retina comparison

  • (p08_het_dlgn / p08_het_retina) / (p08_ko_dlgn / p08_ko_retina)
p08_dlgn_extra <- "p08het_vs_p08ko = (conditionp08_het_dlgn - conditionp08_het_retina) - (conditionp08_ko_dlgn - conditionp08_ko_retina)"
p08_dlgn_translatome_de_keepers <- list(
  "p08het" = c("p08_het_dlgn", "p08_het_retina"),
  "p08ko" = c("p08_ko_dlgn", "p08_ko_retina"))
p08_dlgn_translatome_keepers <- list(
  "p08_het_dlgn_vs_retina" = c("p08_het_dlgn", "p08_het_retina"),
  "p08_ko_dlgn_vs_retina" = c("p08_ko_dlgn", "p08_ko_retina"),
  "p08_dlgn_translatome" = c("p08het", "p08ko"))
p08_dlgn_translatome_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                        keepers = p08_dlgn_translatome_de_keepers,
                                        model_svs = FALSE,
                                        model_fstring = "~ 0 + condition",
                                        do_basic = FALSE, do_dream = FALSE,
                                        do_noiseq = FALSE, do_ebseq = FALSE,
                                        extra_contrasts = p08_dlgn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## p08_dlgn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.
p08_dlgn_combined_test <- combine_de_tables(
  p08_dlgn_translatome_de, keepers = p08_dlgn_translatome_keepers,
  label_column = label_column,
  excel = glue("33translatome_xlsx/test_p08_dlgn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.
p08_dlgn_translatome_de_sva <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                            keepers = p08_dlgn_translatome_de_keepers,
                                            model_svs = "svaseq",
                                            model_fstring = "~ 0 + condition",
                                            do_basic = FALSE, do_dream = FALSE,
                                            do_noiseq = FALSE, do_ebseq = FALSE,
                                            extra_contrasts = p08_dlgn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## p08_dlgn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.
p08_dlgn_combined_test_sva <- combine_de_tables(
  p08_dlgn_translatome_de_sva, keepers = p08_dlgn_translatome_keepers,
  label_column = label_column,
  excel = glue("33translatome_xlsx/test_p08_dlgn_translatome_unfiltered_sva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.

28.2.1 Subtracting the DESeq2 results

28.3 Two scn/retina comparisons (p15/p08 across het/ko)

  • (p15_het_scn / p15_het_retina) / (p08_het_scn / p08_het_retina)
  • (p15_ko_scn / p15_ko_retina) / (p08_ko_scn / p08_ko_retina)
time_scn_extra <- glue("\\
  p15het = (conditionp15_het_scn - conditionp15_het_retina), \\
  p08het = (conditionp08_het_scn - conditionp08_het_retina), \\
  p15het_vs_p08het = (conditionp15_het_scn - conditionp15_het_retina) - (conditionp08_het_scn - conditionp08_het_retina),
  p15ko = (conditionp15_ko_scn - conditionp15_ko_retina), \\
  p08ko = (conditionp08_ko_scn - conditionp08_ko_retina), \\
  p15ko_vs_p08ko = (conditionp15_ko_scn - conditionp15_ko_retina) - (conditionp08_ko_scn - conditionp08_ko_retina)")
time_scn_translatome_de_keepers <- list(
  "p15het" = c("p15_het_scn", "p15_het_retina"),
  "p08het" = c("p08_het_scn", "p08_het_retina"),
  "p15ko" = c("p15_ko_scn", "p15_ko_retina"),
  "p08ko" = c("p08_ko_scn", "p08_ko_retina"))
time_scn_translatome_keepers <- list(
  "p15het" = c("p15_het_scn", "p15_het_retina"),
  "p08het" = c("p08_het_scn", "p08_het_retina"),
  "p15ko" = c("p15_ko_scn", "p15_ko_retina"),
  "p08ko" = c("p08_ko_scn", "p08_ko_retina"),
  "p15_het_sc_vs_retina" = c("p15_het_scn", "p15_het_retina"),
  "p08_het_sc_vs_retina" = c("p08_het_scn", "p08_het_retina"),
  "scn_het_translatome" = c("p15het", "p08het"),
  "scn_ko_translatome" = c("p15ko", "p08ko"))
time_scn_translatome_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                        keepers = time_scn_translatome_de_keepers,
                                        model_svs = FALSE,
                                        model_fstring = "~ 0 + condition",
                                        do_basic = FALSE, do_dream = FALSE,
                                        do_noiseq = FALSE, do_ebseq = FALSE,
                                        extra_contrasts = time_scn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## time_scn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08het_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

time_scn_translatome_test <- combine_de_tables(
  time_scn_translatome_de,
  keepers = time_scn_translatome_keepers,
  label_column = label_column,
  excel = glue("33translatome_xlsx/test_time_scn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08het or conditionp15het.
## coefficient limma did not find p08het or p15het.
## coefficient edger did not find conditionp08ko or conditionp15ko.
## coefficient limma did not find p08ko or p15ko.
## Looking for subscript invalid names, end of extract_keepers.
time_scn_translatome_de_sva <- all_pairwise(v3_pairwise_input, filter = TRUE,
                                            keepers = time_scn_translatome_de_keepers,
                                            model_svs = "svaseq",
                                            model_fstring = "~ 0 + condition",
                                            do_basic = FALSE, do_dream = FALSE,
                                            do_noiseq = FALSE, do_ebseq = FALSE,
                                            extra_contrasts = time_scn_extra)
## Warning in all_pairwise(v3_pairwise_input, filter = TRUE, keepers =
## time_scn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Removing 10162 low-count genes (15263 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08het_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## conditions
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina 
##              3              3              3              3              3 
##     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn   p15_het_dlgn 
##              3              5              5              3              4 
## p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn 
##              4              3              3              3              3 
##    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              5              5              2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

time_scn_translatome_test_sva <- combine_de_tables(
  time_scn_translatome_de_sva,
  keepers = time_scn_translatome_keepers,
  label_column = label_column,
  excel = glue("33translatome_xlsx/test_time_scn_translatome_unfiltered_sva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08het or conditionp15het.
## coefficient limma did not find p08het or p15het.
## coefficient edger did not find conditionp08ko or conditionp15ko.
## coefficient limma did not find p08ko or p15ko.
## Looking for subscript invalid names, end of extract_keepers.

Next step: Perform the retina filter; need to think about the proper union/intersection of the retina/x expression values

In the previous block, we are making 2 global comparisons, here is one of them:

(p15hetscn/p15hetret)/(p08hetscn/p08hetret)

I therefore want to extract the most logical set of genes higher in some/all of these conditions with respect to the corresponding wt conditions. Previously, in section ‘Extract genes included for each set of contrasts’, I attempted to perform this operation for 2 specific wt conditions. When this was performed, it took the unique(union) of the two sets. Thus it stands to reason that I want to take the unique(union) of all 4 in this instance? e.g.:

(p15hetscn > p15wtscn) | (p15hetret > p15wtret) | (p08hetscn > p08wtscn) | (p08hetret > p08wtret)

I kind of think it should be:

((p15hetscn > p15wtscn) | (p15hetret > p15wtret)) & ((p08hetscn > p08wtscn) | (p08hetret > p08wtret))

gross, perhaps I should just do this manually, given that there are only a few putative translatomes to query?

29 Quick and dirty DESeq2 contrast of contrasts

In a fashion similar to how Hector handled the effect of phagocytosis with Laura and Najib a long time ago, I propose to do a simple subtraction of the results of our two contrasts which comprise the translatome query (I was thinking about this last week, thus the inclusion of them in the de tables above). Similarly to the phagocytosis effect, I will simply take the worst posible adjusted p-value. I will repeat this with limma/EdgeR and see how similar the final results are to what those methods provide in the (a/b)/(c/d) comparisons. I am reasonably certain that DESeq2’s results() function has the ability to perform these odd contrasts, but I have never figured out how; perhaps I will use this as a chance to revisit that…

Let us test this idea with the p08 dlgn query, which seeks to compare:

(p08_het_dlgn / p08_het_retina) / (p08_ko_dlgn / p08_ko_retina)

These are maintained in the de_table with the names ‘p08_het_dlgn_vs_retina’ and ‘p08_ko_dlgn_vs_retina’

29.1 p08 dlgn het vs ko

p08_dlgn_combined_deseq <- subtract_de_results(
  first_table = p08_dlgn_combined_test[["data"]][["p08_het_dlgn_vs_retina"]],
  second_table = p08_dlgn_combined_test[["data"]][["p08_ko_dlgn_vs_retina"]],
  first_lfc = "deseq_logfc", second_lfc = "deseq_logfc",
  first_p = "deseq_adjp", second_p = "deseq_adjp",
  first_name = "het", second_name = "ko",
  excel = glue("34translatome_deseqsub_xlsx/translatome_p08_dlgn_combined_deseq-v{ver}.xlsx"))

See how similar these results are to those obtained from limma/edger.

test_columns <- c("edger_logfc", "limma_logfc", "edger_adjp", "limma_adjp")
test_df <- p08_dlgn_combined_test[["data"]][["p08_dlgn_translatome"]][, test_columns]
test_df <- merge(test_df, p08_dlgn_combined_deseq, by = "row.names")
rownames(test_df) <- test_df[["Row.names"]]
test_df[["Row.names"]] <- NULL
cor.test(test_df[["limma_logfc"]], test_df[["het_vs_ko_logfc"]])
## 
##  Pearson's product-moment correlation
## 
## data:  test_df[["limma_logfc"]] and test_df[["het_vs_ko_logfc"]]
## t = 200.91, df = 15261, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.8474337 0.8561405
## sample estimates:
##       cor 
## 0.8518459
cor.test(test_df[["edger_logfc"]], test_df[["het_vs_ko_logfc"]])
## 
##  Pearson's product-moment correlation
## 
## data:  test_df[["edger_logfc"]] and test_df[["het_vs_ko_logfc"]]
## t = 239.37, df = 15261, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.8852492 0.8919242
## sample estimates:
##       cor 
## 0.8886338
tt <- plot_linear_scatter(test_df[, c("limma_logfc", "het_vs_ko_logfc")])
## Warning in plot_linear_scatter(test_df[, c("limma_logfc", "het_vs_ko_logfc")]):
## Model type robust failed, falling back to a default lm.
tt[["scatter"]]

tt <- plot_linear_scatter(test_df[, c("edger_adjp", "het_vs_ko_p")])
## Warning in plot_linear_scatter(test_df[, c("edger_adjp", "het_vs_ko_p")]):
## Model type robust failed, falling back to a default lm.
tt[["scatter"]]

## So, using the maximum p-value is a complete failure; but the extreme similarities
## between this and edgeR suggest to me that it is likely possible to use the results
## from edgeR without concern (or limma for that matter, it was also extremely similar)
## Or I can spend a little time and collect the numbers on each side of the division
## and calculate a t statistic myself.

30 Non-Specific filtering of the translatome data

I have on hand

  • p08het_vs_p08ko : (p08_het_scn - p08_het_retina) - (p08_ko_scn - p08_ko_retina)
  • p15het_vs_p15ko : (p15_het_scn - p15_het_retina) - (p15_ko_scn - p15_ko_retina)
  • p08het_vs_p08ko : (p08_het_dlgn - p08_het_retina) - (p08_ko_dlgn - p08_ko_retina)
  • p15het_vs_p08het : (p15_het_scn - p15_het_retina) - (p08_het_scn - p08_het_retina)
  • p15ko_vs_p08ko : (p15_ko_scn - p15_ko_retina) - (p08_ko_scn - p08_ko_retina)

I have gene sets up above which define the genes suitable for each of these pieces. There are only 5 comparisons, let us step through them.

30.1 SCN translatome het/ko at p08

The data for this contrast resides in scn_combined_test\(data\)p08_scn_translatome or the same slot of scn_combined_test_sva

  • p08_het_scn - p08_het_retina) - (p08_ko_scn - p08_ko_retina)

Thus, the inclusion_sig portions to extract are found in: inclusion_sig[[“deseq”]][[“ups”]], and are named exactly as written above!

p08_het_vs_ko_translatome_unfilt <- scn_combined_test[["data"]][["p08_scn_translatome"]]
num_union <- unique(c(rownames(inclusion_sig[["deseq"]][["ups"]][["p08_het_scn"]]),
                      rownames(inclusion_sig[["deseq"]][["ups"]][["p08_het_retina"]])))
length(num_union)
## [1] 1188
den_union <- unique(c(rownames(inclusion_sig[["deseq"]][["ups"]][["p08_ko_scn"]]),
                      rownames(inclusion_sig[["deseq"]][["ups"]][["p08_ko_retina"]])))
length(den_union)
## [1] 1624
both_union <- unique(c(num_union, den_union))
length(both_union)
## [1] 2005
both_inter_idx <- num_union %in% den_union
both_inter <- num_union[both_inter_idx]
length(both_inter)
## [1] 807
keeper <- list("p08_scn_translatome" = c("p08het", "p08ko"))
p08_scn_translatome_union_filtered <- combine_de_tables(
  scn_translatome_de, keepers = keeper,
  label_column = label_column,
  excel = glue("35translatome_union/p08_scn_translatome_union_filtered_nosva-v{ver}.xlsx"),
  wanted_genes = both_union)
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.
p08_scn_translatome_inter_filtered <- combine_de_tables(
  scn_translatome_de, keepers = keeper,
  label_column = label_column,
  excel = glue("35translatome_union/p08_scn_translatome_intersect_filtered_nosva-v{ver}.xlsx"),
  wanted_genes = both_inter)
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.
p08_scn_translatome_union_filtered_sva <- combine_de_tables(
  scn_translatome_de_sva, keepers = keeper,
  label_column = label_column,
  excel = glue("35translatome_union/p08_scn_translatome_union_filtered_sva-v{ver}.xlsx"),
  wanted_genes = both_union)
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.
p08_scn_translatome_union_filtered <- combine_de_tables(
  scn_translatome_de, keepers = keeper,
  label_column = label_column,
  excel = glue("35translatome_union/p08_scn_translatome_intersect_filtered_sva-v{ver}.xlsx"),
  wanted_genes = both_inter)
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## Looking for subscript invalid names, end of extract_keepers.

31 Venn/UpSet of Retina, SCN, and dLGN DE Genes

Here is a snippet from Rashmi which expresses nicely the DE-result comparisons she is most interested:

Since, I want to know the number of DEG expressed in Retina, SCN and dLGN with respect to genotype, Location and time. I prepared the venn diagram for these comparison:

  • Genotype: P8 Ret Het vs KO, P15 Ret Het vs KO, P8 SCN Het vs KO, P15 SCN Het vs KO, P8 dLGN Het vs KO, P15 dLGN Het vs KO
  • Location: P8_het Ret vs SCN, P8_KO Ret vs SCN, P15_het Ret vs SCN, P15_KO Ret vs SCN, P8_het Ret vs dLGN, P8_KO Ret vs dLGN, P15_het Ret vs dLGN, P15_KO Ret vs dLGN, P8_het SCN vs dLGN, P8_KO SCN vs dLGN, P15_het SCN vs dLGN, P15_KO SCN vs dLGN.

Since I was interested in understanding the change in local translatome according to Location for different developmental time points for Het and KO. Hence, I tried to generate a venn diagram for Location (Ret and SCN) at developmental time points P8 and P15 for genotype het and KO. So the venn diagram / upset plot will be for location where some genes will be shared/unique for P8_Ret_het, P8_SCN_Het, P15_Ret_HET, P15_SCN_HET. We can prepare an upset plot for P8_Ret_KO, P8_SCN_KO, P15_Ret_KO and P15_SCN_KO also. Or can generate an upset plot by combining both P8_Ret_het, P8_SCN_Het, P15_Ret_HET and P15_SCN_HET and P8_Ret_KO, P8_SCN_KO, P15_Ret_KO and P15_SCN_KO.

Ok, let us see if I can implement this, starting with the genotype query

  • Genotype: P8 Ret Het vs KO, P15 Ret Het vs KO, P8 SCN Het vs KO, P15 SCN Het vs KO, P8 dLGN Het vs KO, P15 dLGN Het vs KO

31.1 ko vs het; all locations and times

## The appropriate data structure is 'genotype_tables',
## and the tables of interest are:
table_names <- c("kh_p08_retina", "kh_p15_retina", "kh_p08_scn",
                 "kh_p15_scn", "kh_p08_dlgn", "kh_p15_dlgn")
table_names %in% names(genotype_sig)
## [1] TRUE TRUE TRUE TRUE TRUE TRUE
newsig <- genotype_sig[[1]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- genotype_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- genotype_sig[[name]][["deseq"]][["downs"]][[name]]
}
genotype_upsetr <- upsetr_sig(newsig)
genotype_upset_written <- write_upset_groups(genotype_upsetr, excel = "36upset_genotype/genotype_upset_groups.xlsx")
## Deleting the file 36upset_genotype/genotype_upset_groups.xlsx before writing the tables.
genotype_upsetr[["all_plot"]]

pp(file = "36upset_genotype/test_genotype_upset.pdf")
print(genotype_upsetr[["all_plot"]])
plotted <- dev.off()

Now let us try the location-specific comparisons

31.2 scn vs retina, p08

## The appropriate data structure is 'genotype_tables',
## and the tables of interest are:
table_names <- c("sr_p08_het", "sr_p08_ko")
table_names %in% names(location_sig)
## [1] TRUE TRUE
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
location_upset_written <- write_upset_groups(location_upsetr, excel = "36upset_genotype/sr_p08_hetko_upset_groups.xlsx")
## Deleting the file 36upset_genotype/sr_p08_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

pp(file = "36upset_genotype/test_location_sr_p08_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

I am reasonably certain that Rashmi would like a table of the genes shared among increased scn ko and het in the above plot along with the increased retina (e.g. the 269 and 103 gene sets).

31.3 scn vs retina, p15

table_names <- c("sr_p15_het", "sr_p15_ko")
table_names %in% names(location_sig)
## [1] TRUE TRUE
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
location_upset_written <- write_upset_groups(location_upsetr, excel = "36upset_genotype/sr_p15_hetko_upset_groups.xlsx")
## Deleting the file 36upset_genotype/sr_p15_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

print(scn_retina_p15_upset_result)
## Error:
## ! object 'scn_retina_p15_upset_result' not found
pp(file = "36upset_genotype/test_location_sr_p15_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

31.4 dlgn vs retina, p08

## The appropriate data structure is 'genotype_tables',
## and the tables of interest are:
table_names <- c("dr_p08_het", "dr_p08_ko")
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
location_upset_written <- write_upset_groups(location_upsetr, excel = "3upset_genotype/dr_p08_hetko_upset_groups.xlsx")
## Deleting the file 3upset_genotype/dr_p08_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

pp(file = "36upset_genotype/test_location_dr_p08_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

31.5 dlgn vs retina, p15

## The appropriate data structure is 'genotype_tables',
## and the tables of interest are:
table_names <- c("dr_p15_het", "dr_p15_ko")
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
location_upset_written <- write_upset_groups(location_upsetr, excel = "37upset_location/dr_p15_hetko_upset_groups.xlsx")
## Deleting the file 37upset_location/dr_p15_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

pp(file = "37upset_location/test_location_dr_p15_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

31.6 dlgn vs scn, p08

table_names <- c("ds_p08_het", "ds_p08_ko")
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
location_upset_written <- write_upset_groups(location_upsetr, excel = "37upset_location/ds_p08_hetko_upset_groups.xlsx")
## Deleting the file 37upset_location/ds_p08_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

pp(file = "37upset_location/test_location_ds_p08_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

31.7 dlgn vs scn, p15

table_names <- c("ds_p15_het", "ds_p15_ko")
location_upset_input <- list()
first_table <- table_names[1]
newsig <- location_sig[[first_table]]
for (sig in 2:length(table_names)) {
  name <- table_names[sig]
  newsig[["deseq"]][["ups"]][[name]] <- location_sig[[name]][["deseq"]][["ups"]][[name]]
  newsig[["deseq"]][["downs"]][[name]] <- location_sig[[name]][["deseq"]][["downs"]][[name]]
}
location_upsetr <- upsetr_sig(newsig)
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
location_upset_written <- write_upset_groups(location_upsetr, excel = "37upset_location/ds_p15_hetko_upset_groups.xlsx")
## Deleting the file 37upset_location/ds_p15_hetko_upset_groups.xlsx before writing the tables.
location_upsetr[["all_plot"]]

pp(file = "37upset_location/test_location_ds_p15_hetko_upset.pdf")
print(location_upsetr[["all_plot"]])
plotted <- dev.off()

32 Shared and unique gene sets across x/wt

In this block I want to find the unique and shared genes between:

  1. scn p8 het/wt and retina p8 het/wt: hwp08scninc, hwp08retinc, hwp08scndec, hwp08retdec
  2. scn p15 het/wt and retina p15 het/wt: hwp15scninc, hwp15retinc, hwp15scndec, hwp15retdec
  3. #1 and #2 together: 8 catgories above
  4. scn p8 ko/wt and retina p8 ko/wt
  5. scn p15 ko/wt and retina p15 ko/wt
  6. #4 and #5 together

The comparisons of het/wt are found in the ‘inclusion_sig’ dataset; because they are providing our cutoffs for nonspecific binding.

32.1 Number 1 above: p08_het vs wt for scn and retina.

table_names <- c("p08_het_scn", "p08_het_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p08_het_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p08_het_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p08_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

32.2 Number 2 above: p15_het vs wt for scn and retina.

table_names <- c("p15_het_scn", "p15_het_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p15_het_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p15_het_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p15_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

32.3 Number 3 above: combination of #1 and #2

table_names <- c("p08_het_scn", "p08_het_retina", "p15_het_scn", "p15_het_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p08p15_het_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p08p15_het_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p08p15_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

32.4 Number 4 above p08_ko vs wt for scn and retina.

table_names <- c("p08_ko_scn", "p08_ko_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p08_ko_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p08_ko_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p08_ko_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

32.5 Number 5 above p15_ko vs wt for scn and retina.

table_names <- c("p15_ko_scn", "p15_ko_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p15_ko_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p15_ko_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p15_ko_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

32.6 Number 6 above: Combining #4 and #5

table_names <- c("p08_ko_scn", "p08_ko_retina", "p15_ko_scn", "p15_ko_retina")
inclusion_upsetr <- upsetr_sig(inclusion_sig, contrasts = table_names)
inclusion_upset_written <- write_upset_groups(inclusion_upsetr, excel = "37upset_locations/rs_p08p15_ko_inclusion_upset_groups.xlsx")
## Deleting the file 37upset_locations/rs_p08p15_ko_inclusion_upset_groups.xlsx before writing the tables.
inclusion_upsetr[["all_plot"]]

pp(file = "37upset_locations/inclusion_sr_p08p15_ko_upset.pdf")
print(inclusion_upsetr[["all_plot"]])
plotted <- dev.off()

33 GSVA

msigdb <- "reference/msigdb_v2024.1.Mm.db"
if (file.exists(msigdb)) {
  v3_h_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "mh",
                           signatures = msigdb, id_source = "fdata",
                           required_id = "mgi_symbol")
  v3_h_gsva

  v3_h_gsva_sig <- get_sig_gsva_categories(
    v3_h_gsva, excel = "38msigdb/gsva_sig_hallmark_categories.xlsx")
  v3_h_gsva_sig

  v3_m1_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "m1",
                            signatures = msigdb, id_source = "fdata",
                            required_id = "mgi_symbol")
  v3_m1_gsva
  v3_m1_gsva_sig <- get_sig_gsva_categories(
    v3_m1_gsva, excel = "38msigdb/gsva_sig_positional_categories.xlsx")
  v3_m1_gsva_sig

  v3_m2_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "m2",
                            signatures = msigdb, id_source = "fdata",
                            required_id = "mgi_symbol")
  v3_m2_gsva
  v3_m2_gsva_sig <- get_sig_gsva_categories(
    v3_m2_gsva, excel = "38msigdb/gsva_sig_curated_categories.xlsx")
  v3_m2_gsva_sig

  v3_m3_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "m3",
                            signatures = msigdb, id_source = "fdata",
                            required_id = "mgi_symbol")
  v3_m3_gsva
  v3_m3_gsva_sig <- get_sig_gsva_categories(
    v3_m3_gsva, excel = "38msigdb/gsva_sig_regulatory_categories.xlsx")
  v3_m3_gsva_sig

  v3_m5_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "m5",
                            signatures = msigdb, id_source = "fdata",
                            required_id = "mgi_symbol")
  v3_m5_gsva
  v3_m5_gsva_sig <- get_sig_gsva_categories(
    v3_m5_gsva, excel = "38msigdb/gsva_sig_ontology_categories.xlsx")
  v3_m5_gsva_sig

  v3_m8_gsva <- simple_gsva(v3_pairwise_input, orgdb = "org.Mm.eg.db", signature_category = "m8",
                            signatures = msigdb, id_source = "fdata",
                            required_id = "mgi_symbol")
  v3_m8_gsva
  v3_m8_gsva_sig <- get_sig_gsva_categories(
    v3_m8_gsva, excel = "38msigdb/gsva_sig_celltype_categories.xlsx")
  v3_m8_gsva_sig
}
## gsva requires the annotation field to be filled in. Setting it to orgdb given.
## Converting the rownames() of the SummarizedExperiment to mgi_symbol.
## Error in `simple_gsva()`:
## ! I do not understand this ID source.

34 GSEA images

Up above I created a fairly large set of enrichment/GSEA analyses. Let us pull some of the most interesting results here and look at them.

Here are the specific queries from Rashmi:

  • Genotype (het vs ko):
    • P8 het and ko for Ret
    • SCN (P8 het vs KO SCN
    • P8 het vs KO Ret)
    • P15 het and ko for Ret
  • Location (somal vs axonal):
    • SR_P08_KO
    • SR_P08_Het
    • SR_P15_KO
    • SR_P15_Het
  • Time(p8vs p15):
    • t_het_Ret_ po8-p15
    • t_KO_Ret_C po8-p15
    • t_het_SCN_po8-p15
    • t_KO_SCN_po8-p15

34.1 Genotype

Let us take a moment and see for which contrasts I acquired results:

I need to make a little summary for clusterprofiler too so that I can easily see how many hits there are for each contrast.

summary(genotype_full_gp)
##                 Length Class                       Mode
## kh_p08_dlgn_up  20     hpgltools::simple_gprofiler list
## kh_p15_dlgn_up  27     hpgltools::simple_gprofiler list
## kh_p08_scn_up   20     hpgltools::simple_gprofiler list
## kh_p08_scn_down 24     hpgltools::simple_gprofiler list
## kh_p15_scn_down 25     hpgltools::simple_gprofiler list
for (i in names(genotype_full_gp)) {
  print(i)
  print(genotype_full_gp[[i]][["num_hits"]])
}
## [1] "kh_p08_dlgn_up"
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##     0     0     0     0     0     0     0     0     0 
## [1] "kh_p15_dlgn_up"
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##    61    29     0   111     1    17     6     3     0 
## [1] "kh_p08_scn_up"
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##     0     0     0     0     0     0     0     0     0 
## [1] "kh_p08_scn_down"
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##    37    12     0     0     0     4     0   105     0 
## [1] "kh_p15_scn_down"
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##    42    10     0     0     2     5     0     1     0
summary(genotype_full_cp)
##                    Length Class                             Mode
## kh_p08_dlgn_up     20     hpgltools::simple_clusterprofiler list
## kh_p08_dlgn_down   20     hpgltools::simple_clusterprofiler list
## kh_p15_dlgn_up     20     hpgltools::simple_clusterprofiler list
## kh_p15_dlgn_down   20     hpgltools::simple_clusterprofiler list
## kh_p08_retina_up   20     hpgltools::simple_clusterprofiler list
## kh_p08_retina_down 20     hpgltools::simple_clusterprofiler list
## kh_p15_retina_up   20     hpgltools::simple_clusterprofiler list
## kh_p15_retina_down 20     hpgltools::simple_clusterprofiler list
## kh_p08_scn_up      20     hpgltools::simple_clusterprofiler list
## kh_p08_scn_down    20     hpgltools::simple_clusterprofiler list
## kh_p15_scn_down    20     hpgltools::simple_clusterprofiler list
for (i in names(genotype_full_cp)) {
  print(i)
  print(nrow(genotype_full_cp[[i]][["gse_go"]]))
}
## [1] "kh_p08_dlgn_up"
## NULL
## [1] "kh_p08_dlgn_down"
## NULL
## [1] "kh_p15_dlgn_up"
## NULL
## [1] "kh_p15_dlgn_down"
## NULL
## [1] "kh_p08_retina_up"
## NULL
## [1] "kh_p08_retina_down"
## NULL
## [1] "kh_p15_retina_up"
## NULL
## [1] "kh_p15_retina_down"
## NULL
## [1] "kh_p08_scn_up"
## NULL
## [1] "kh_p08_scn_down"
## NULL
## [1] "kh_p15_scn_down"
## NULL

34.1.1 p8 het/ko for retina:

This contrast, even before filtering away the high-wt genes, only has 8 genes in the set of up and down genes combined. As a result, my function which performs gProfiler/clusterProfiler skips it, and also skips the p15 het/ko for retina samples.

34.1.2 p8 het/ko for scn:

This has a bunch more genes: 51 up and 128 down. Unfortunately, gProfiler sees no significant over-representation in the up category of genes. The down category has

The up/down sets from clusterProfiler have enrich_go, gse_go, and go_data to look at.

genotype_full_gp$kh_p08_scn_up$num_hits
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##     0     0     0     0     0     0     0     0     0
genotype_full_gp$kh_p08_scn_down$num_hits
##    BP    CC CORUM    HP  KEGG    MF  REAC    TF    WP 
##    37    12     0     0     0     4     0   105     0
plots <- plot_enrichresult(genotype_full_gp$kh_p08_scn_down[["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots[["tree"]]

Perhaps I should just ask the question: for which categories did I get results back?

summary(genotype_full_gp)
##                 Length Class                       Mode
## kh_p08_dlgn_up  20     hpgltools::simple_gprofiler list
## kh_p15_dlgn_up  27     hpgltools::simple_gprofiler list
## kh_p08_scn_up   20     hpgltools::simple_gprofiler list
## kh_p08_scn_down 24     hpgltools::simple_gprofiler list
## kh_p15_scn_down 25     hpgltools::simple_gprofiler list

kh_p08_dlgn_up: No significant gProfiler results. kh_p15_dlgn_up: Significant BP, HP, KEGG, MF, REAC, TF kh_p08_scn_up: No significant gProfiler results. kh_p08_scn_down: Significant BP, MiRNA, MF, TF kh_p15_scn_down: Significant BP, MF

plots <- plot_enrichresult(genotype_full_gp[["kh_p15_dlgn_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.2 Location

34.2.1 Scn vs retina ko, p08

plots <- plot_enrichresult(location_gp[["sr_p08_ko"]][["sr_p08_ko_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(location_gp[["sr_p08_ko"]][["sr_p08_ko_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.2.2 scn vs retina, het, p08

Enriched groups: BP, KEGG, MF, TF, CC

summary(location_gp[["sr_p08_het"]][["sr_p08_het_up"]])
##                   Length Class             Mode     
## BP                16     data.frame        list     
## CC                16     data.frame        list     
## CORUM              0     data.frame        list     
## HP                 0     data.frame        list     
## KEGG              16     data.frame        list     
## MF                16     data.frame        list     
## REAC               0     data.frame        list     
## TF                16     data.frame        list     
## WP                 0     data.frame        list     
## input             89     data.frame        list     
## BP_enrich          1     enrichResult      S4       
## CC_enrich          1     enrichResult      S4       
## KEGG_enrich        1     enrichResult      S4       
## MF_enrich          1     enrichResult      S4       
## TF_enrich          1     enrichResult      S4       
## num_genes          1     -none-            numeric  
## interactive_plots  5     -none-            list     
## num_hits           9     -none-            numeric  
## gost_plots         5     -none-            list     
## gost_links         5     -none-            list     
## significant        5     -none-            list     
## excel              1     written_gprofiler numeric  
## pvalue_plots       2     -none-            list     
## species            1     -none-            character
## threshold          1     -none-            numeric
plots <- plot_enrichresult(location_gp[["sr_p08_het"]][["sr_p08_het_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(location_gp[["sr_p08_het"]][["sr_p08_het_up"]][["CC_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(location_gp[["sr_p08_het"]][["sr_p08_het_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

sr_p08_het_topn_gsea <- plot_topn_gsea(location_cp[[""]])
## Error in `if (nrow(gse) < topn) ...`:
## ! argument is of length zero

34.2.3 Scn vs retina ko, p15

plots <- plot_enrichresult(location_gp[["sr_p15_ko"]][["sr_p15_ko_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(location_gp[["sr_p15_ko"]][["sr_p15_ko_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.2.4 scn vs retina, het, p15

plots <- plot_enrichresult(location_gp[["sr_p15_het"]][["sr_p15_het_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(location_gp[["sr_p15_het"]][["sr_p15_het_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.3 Time

34.3.1 het retina

Ups: significant results for BP, MF, TF Downs: BP, MF, REAC, TF, WP

plots <- plot_enrichresult(time_gp[["t_het_retina"]][["t_het_retina_up"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

plots <- plot_enrichresult(time_gp[["t_het_retina"]][["t_het_retina_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.3.2 ko retina

Up: BP, MiRNA, MF Down: BP, MF, REAC, TF

plots <- plot_enrichresult(time_gp[["t_ko_retina"]][["t_ko_retina_up"]][["BP_enrich"]])
## There are insufficient significant results to plot.
plots[["dot"]]
## NULL
plots <- plot_enrichresult(time_gp[["t_ko_retina"]][["t_ko_retina_down"]][["BP_enrich"]])
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## ✖ Problematic argument:
## • by = "Count"
## ℹ Did you misspell an argument name?
plots[["dot"]]

34.3.3 het scn

Neither of the SCN gProfiler queries provided any results.

35 Compare the bulk and TRAP data

There are a few variables from the bulk analyses which we may use to compare to the TRAP data:

mm_de_dlgn_sva, mm_de_ret_sva, mm_de_scn_sva, mm_de_dlgn, mm_de_ret, mm_de_scn.

Those are location-specific contrasts.

genoloc_de_sva/genoloc_table_sva provide all contrasts that I thought might be fun.

The following is all pre-wt filtering. Next I will repeat everything post-filtering.

## The bulk tables
genoloc_table_sva[["table_names"]]
## Error:
## ! object 'genoloc_table_sva' not found
## The TRAP tables
location_tables_full[["table_names"]]
## $dr_p08_het
## p08_het_dlgn_vs_p08_het_retina
## 
## $dr_p15_het
## p15_het_dlgn_vs_p15_het_retina
## 
## $dr_p08_ko
## p08_ko_dlgn_vs_p08_ko_retina
## 
## $dr_p15_ko
## p15_ko_dlgn_vs_p15_ko_retina
## 
## $sr_p08_het
## p08_het_scn_vs_p08_het_retina
## 
## $sr_p15_het
## p15_het_scn_vs_p15_het_retina
## 
## $sr_p08_ko
## p08_ko_scn_vs_p08_ko_retina
## 
## $sr_p15_ko
## p15_ko_scn_vs_p15_ko_retina
## 
## $ds_p08_het
## p08_het_dlgn_vs_p08_het_scn
## 
## $ds_p15_het
## p15_het_dlgn_vs_p15_het_scn
## 
## $ds_p08_ko
## p08_ko_dlgn_vs_p08_ko_scn
## 
## $ds_p15_ko
## p15_ko_dlgn_vs_p15_ko_scn
genotype_tables_full[["table_names"]]
## $kh_p08_dlgn
## p08_ko_dlgn_vs_p08_het_dlgn
## 
## $kh_p15_dlgn
## p15_ko_dlgn_vs_p15_het_dlgn
## 
## $kh_p08_retina
## p08_ko_retina_vs_p08_het_retina
## 
## $kh_p15_retina
## p15_ko_retina_vs_p15_het_retina
## 
## $kh_p08_scn
## p08_ko_scn_vs_p08_het_scn
## 
## $kh_p15_scn
## p15_ko_scn_vs_p15_het_scn
time_tables_full[["table_names"]]
## $t_het_dlgn
## p15_het_dlgn_vs_p08_het_dlgn
## 
## $t_ko_dlgn
## p15_ko_dlgn_vs_p08_ko_dlgn
## 
## $t_het_retina
## p15_het_retina_vs_p08_het_retina
## 
## $t_ko_retina
## p15_ko_retina_vs_p08_ko_retina
## 
## $t_het_scn
## p15_het_scn_vs_p08_het_scn
## 
## $t_ko_scn
## p15_ko_scn_vs_p08_ko_scn
## Retina het vs Retina wt
bulk_table <- genoloc_table_sva[["data"]][["Retina_ko_vs_Retina_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_retina"]]
retina_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
retina_ko_het_aucc
## Error:
## ! object 'retina_ko_het_aucc' not found
retina_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
retina_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'retina_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["Retina_ko_vs_Retina_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_retina"]]
retina_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
retina_ko_het_aucc
## Error:
## ! object 'retina_ko_het_aucc' not found
retina_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
retina_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'retina_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["SCN_ko_vs_SCN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_scn"]]
scn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
scn_ko_het_aucc
## Error:
## ! object 'scn_ko_het_aucc' not found
scn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
scn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'scn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["SCN_ko_vs_SCN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_scn"]]
scn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
scn_ko_het_aucc
## Error:
## ! object 'scn_ko_het_aucc' not found
scn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
scn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'scn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["dLGN_ko_vs_dLGN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_dlgn"]]
dlgn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
dlgn_ko_het_aucc
## Error:
## ! object 'dlgn_ko_het_aucc' not found
dlgn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
dlgn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'dlgn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["dLGN_ko_vs_dLGN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_dlgn"]]
dlgn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
dlgn_ko_het_aucc
## Error:
## ! object 'dlgn_ko_het_aucc' not found
dlgn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
dlgn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'dlgn_ko_het_ros' not found
## The bulk tables
genoloc_table_sva[["table_names"]]
## Error:
## ! object 'genoloc_table_sva' not found
## The TRAP tables
location_tables[["table_names"]]
## NULL
genotype_tables[["table_names"]]
## NULL
time_tables[["table_names"]]
## NULL
## Retina het vs Retina wt
bulk_table <- genoloc_table_sva[["data"]][["Retina_ko_vs_Retina_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_retina"]]
retina_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
retina_ko_het_aucc
## Error:
## ! object 'retina_ko_het_aucc' not found
retina_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
retina_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'retina_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["Retina_ko_vs_Retina_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_retina"]]
retina_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
retina_ko_het_aucc
## Error:
## ! object 'retina_ko_het_aucc' not found
retina_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
retina_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'retina_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["SCN_ko_vs_SCN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_scn"]]
scn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
scn_ko_het_aucc
## Error:
## ! object 'scn_ko_het_aucc' not found
scn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
scn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'scn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["SCN_ko_vs_SCN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_scn"]]
scn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
scn_ko_het_aucc
## Error:
## ! object 'scn_ko_het_aucc' not found
scn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
scn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'scn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["dLGN_ko_vs_dLGN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p08_dlgn"]]
dlgn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
dlgn_ko_het_aucc
## Error:
## ! object 'dlgn_ko_het_aucc' not found
dlgn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
dlgn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'dlgn_ko_het_ros' not found
bulk_table <- genoloc_table_sva[["data"]][["dLGN_ko_vs_dLGN_het"]]
## Error:
## ! object 'genoloc_table_sva' not found
trap_table <- genotype_tables_full[["data"]][["kh_p15_dlgn"]]
dlgn_ko_het_aucc <- calculate_aucc(bulk_table, trap_table,
                                     px = "deseq_adjp", py = "deseq_adjp",
                                     lx = "deseq_logfc", ly = "deseq_logfc")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'nrow': object 'bulk_table' not found
dlgn_ko_het_aucc
## Error:
## ! object 'dlgn_ko_het_aucc' not found
dlgn_ko_het_ros <- rank_order_scatter(bulk_table, trap_table)
## Error:
## ! object 'bulk_table' not found
dlgn_ko_het_ros[["lfc_scatter"]]
## Error:
## ! object 'dlgn_ko_het_ros' not found

36 Bibliography

pander::pander(sessionInfo())
message(paste0("This is hpgltools commit: ", get_git_commit()))
message(paste0("Saving to ", savefile))
tmp <- sm(saveme(filename = savefile))
tmp <- loadme(filename = savefile)
LS0tCnRpdGxlOiAiQW5hbHlzZXMgb2YgdGhlIElQUkdDIHJlLXByb2Nlc3NlZCBzYW1wbGVzLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgICAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgICAgIGRmX3ByaW50OiBwYWdlZAogICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgZmlnX2hlaWdodDogNwogICAgICAgIGZpZ193aWR0aDogNwogICAgICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgICAgIHdpZHRoOiAzMDAKICAgICAgICBrZWVwX21kOiBmYWxzZQogICAgICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgICAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgICBmaWdfaGVpZ2h0OiA3CiAgICAgICAgICBmaWdfd2lkdGg6IDcKICAgICAgICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgICAgICAga2VlcF9tZDogZmFsc2UKICAgICAgICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICBmb250LXNpemU6IDE2cHg7Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTZweDsKfQpwcmUgewogIGZvbnQtc2l6ZTogMTZweAp9CmJvZHkgLm1haW4tY29udGFpbmVyIHsKICBtYXgtd2lkdGg6IDE2MDBweDsKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShocGdsdG9vbHMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZ3Byb2ZpbGVyMikKdHQgPC0gdHJ5KGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKSkKa25pdHI6Om9wdHNfa25pdCRzZXQoCiAgcHJvZ3Jlc3MgPSBUUlVFLCB2ZXJib3NlID0gVFJVRSwgd2lkdGggPSA5MCwgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlcnJvciA9IFRSVUUsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4LCBmaWcucmV0aW5hID0gMiwKICBvdXQud2lkdGggPSAiMTAwJSIsIGRldiA9ICJwbmciLAogIGRldi5hcmdzID0gbGlzdChwbmcgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpKQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSkKdmVyIDwtICIyMDI0MDgiCnByZXZpb3VzX2ZpbGUgPC0gIiIKdmVyIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCAiJVklbSVkIikKCiMjdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKQpybWRfZmlsZSA8LSAiaXByZ2NfYW5hbHlzZXNfMjAyNDA4LlJtZCIKc2F2ZWZpbGUgPC0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcm1kX2ZpbGUpCiMjIE5vIG9uZSB3aWxsIGV2ZXIgcmVhZCB0aGlzIEkgc3VzcGVjdCwgYnV0IHRoZXJlIHdpbGwgX25ldmVyXyBiZSBhIHdvcmQgcHJvZHVjZWQKIyMgYnkgYW4gTExNIGluIGEgZG9jdW1lbnQgd3JpdHRlbiBieSBtZS4KYGBgCgpOb3RlIHRvIHNlbGY6IEkgY2hhbmdlZCB0aGUgY2x1c3RlclByb2ZpbGVyIG91dHB1dCBsaXN0IHRvIHN0b3JlIHRoZQplbnJpY2hSZXN1bHRzIGluIFtbeHhfZGF0YV1dW1tlbnJpY2hdXSwgb3IgaW4gdGhlIGNhc2Ugb2YgZ286CltbZ29fZGF0YV1dW1tCUF9lbnJpY2hdXSBpbnN0ZWFkIG9mIGVucmljaF9yZXN1bHRzLgoKIyBTZXQgc29tZSBwYXJhbWV0ZXJzIHdoaWNoIHdpbGwgYmUgdXNlZCBsYXRlcgoKYGBge3J9CnNhbXBsZV9zaGVldCA8LSAic2FtcGxlX3NoZWV0cy8yMDI0MDYwNl9vbmx5X3VtZF9zZXF1ZW5jZWRfbW9kaWZpZWQueGxzeCIKIyMgTG9nRkMgY3V0b2ZmIHdoZW4gd29ya2luZyBvbiAnbm9ybWFsJyBjb21wYXJpc29ucwpsZmNfY3V0b2ZmIDwtIDEuMAojIyBMb2dGQyBjdXRvZmYgd2hlbiB3b3JraW5nIG9uIHRoZSBpbmNsdXNpb24gc2V0cy4KZmlsdGVyX2xmY19jdXRvZmYgPC0gMC4xCiMjIEFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmIHdoZW4gd29ya2luZyB3aXRoICdub3JtYWwnIGNvbnRyYXN0cwphZGpwX2N1dG9mZiA8LSAwLjA1CiMjIEFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmIHdoZW4gd29ya2luZyBvbiB0aGUgaW5jbHVzaW9uIHNldHMuCmZpbHRlcl9hZGpwX2N1dG9mZiA8LSAwLjEKIyMgSW5jcmVhc2UgdGhlIG1heGltdW0gYWxsb3dlZCBncm91cCBzaXplIHdoZW4gd29ya2luZyB3aXRoIGNsdXN0ZXJQcm9maWxlcgojIyBUaGlzIHNob3VsZCBicmluZyBvdXQgc29tZSBvZiB0aGUgbW9yZSBnZW5lcmFsIGdyb3VwcyBsaWtlICdjZWxsYm9keScKbWF4X2dyb3Vwc2l6ZSA8LSAyMDAwCiMjIEFsbG93IGdyb3VwcyBoaWdoZXIgdXAgaW4gdGhlIHRyZWUgZm9yIGNsdXN0ZXJQcm9maWxlciByZXN1bHRzLgpnb19sZXZlbCA8LSAyCiMjIEFsbG93IDEwIEdPIGNhdGVnb3JpZXMgdG8gYmUgZGlzcGxheWVkIHdoZW4gcGxvdHRpbmcuCmdvX2NhdGVnb3JpZXMgPC0gMTQKIyMgTUEgcGxvdCBwb2ludCBvdXRsaW5lcwpvdXRsaW5lIDwtIEZBTFNFCiMjIFNwZWVkIHVwIGNsdXN0ZXJQcm9maWxlciBieSBjaG9vc2luZyB0aGUgY29ycmVjdCBrZXl0eXBlcwpvcmdkYl9mcm9tIDwtICJFTlNFTUJMIgpkZWZhdWx0X2ZzdHJpbmcgPC0gIn4gMCArIGNvbmRpdGlvbiIKYW5ub3RhdGlvbl9jb2x1bW5zIDwtIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAiZGVzY3JpcHRpb24iLCAiZXh0ZXJuYWxfc3lub255bSIpCmxhYmVsX2NvbHVtbiA8LSAic3ltYm9sIiAgIyMgdGFrZW4gZnJvbSBvcmcuTW0uZWcuZGIKYGBgCgojIFRPRE9zCgoqIENoZWNrIHRoaXMgZm9yIGNvcnJlY3RuZXNzLgoqIFJlb3JnYW5pemUgaXQKKiBHU1ZBIChAaGFuemVsbWFubkdTVkFHZW5lU2V0MjAxM2EpCiogQ29uc2lkZXIgZW1iZWRkaW5nIHNvbWUvbWFueS9hbGwgb2YgdGhlIEV4Y2VsIG91dHB1dHMgaW50byB0aGUgaHRtbAogIG91dHB1dCB2aWEgeGZ1bjo6ZW1iZWRfZGlyKCdleGNlbC8nKQoKIyBNZWV0aW5nIHdpdGggVGhlcmVzYQoKUHJldmlvdXMgcGFwZXJzIGRpZCBub3QgZG8gYW4gZXhwbGljaXQgc3VidHJhY3Rpb24sIGluc3RlYWQganVzdApjb21wYXJlZCB0byBXVCBhbmQga2VwdCB0aGUgZ2VuZXMgd2hpY2ggYXJlID4gaW4gZGVsdGEvaGV0IHZzLiB3dC4KVGhlcmUgYXJlIG11bHRpcGxlIHdheXMgdG8gZGVhbCB3aXRoIHRoaXMgYW5kIHRoYXQgcXVlcnkgaGFzIG5vdCB5ZXQKYmVlbiBkZWZpbmVkLiAgTGF0ZXIsIFRoZXJlc2EgY2FtZSB0byB0aGUgY29uY2x1c2lvbiB0aGF0IHRoZQpzdWJ0cmFjdGlvbiBtZXRob2QgaXMgbm90IGFwcHJvcHJpYXRlLgoKIyBBIG5vdGUgb24gdHJhbnNjcmlwdC1sZXZlbCBjaGFuZ2VzCgpBbiBpbnRlcmVzdGluZyBxdWVzdGlvbiB3YXMgcG9zZWQgcmVnYXJkaW5nIHRyYW5zY3JpcHQtbGV2ZWwgY2hhbmdlcwppbiB0aGUgVFJBUCBhbmQgYnVsayBkYXRhLiAgQXMgYSByZXN1bHQsIEkgbWFkZSBjb3BpZXMgb2YgdGhlCm5vdGVib29rcyBhbmQgcmVwZWF0ZWQgYWxsIGFuYWx5c2VzIGF0IHRoZSB0cmFuc2NyaXB0IGxldmVsOyB0aGUKdmFyaW91cyBpbWFnZXMsIGV4Y2VsIGZpbGVzLCBldGMgYXJlIGFsbCBpbiB0aGUgc2FtZSBkaXJlY3RvcmllcyB3aXRoCmEgc3VmZml4ICdfdHgnLiAgQSBmZXcgbWlub3IgY2hhbmdlcyB3ZXJlIGludHJvZHVjZWQgZm9yIHRoZSBsYWJlbGxpbmcKb2YgZ2VuZXMuCgpJIG1hZGUgbm8gZWZmb3J0IHRvIGNvbXBhcmUgdGhlIHNpbWlsYXJpdGllcyBiZXR3ZWVuIHRoZQp0cmFuc2NyaXB0LWxldmVsIGNoYW5nZXMgZm9yIHRoZSBUUkFQIGFuZCBidWxrIGRhdGE7IGJ1dCBkaWQgdGhhdCBvbmx5CmF0IHRoZSBsZXZlbCBvZiBnZW5lcy4KCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIGRvY3VtZW50IEkgaG9wZSB0byBleHBsb3JlIHRoZSBmcmVzaGx5IHByb2Nlc3NlZCBzYW1wbGVzIGFuZApwZXJmb3JtIHNvbWUgY29tcGFyaXNvbnMgdG8gc2VlIHRoYXQgd2UgaGF2ZSB0aGUgZXhwZWN0ZWQgc2ltaWxhcml0aWVzCmFuZCBkaWZmZXJlbmNlcyBmcm9tIHRoZSBwcmlvciBhbmFseXNpcyBwZXJmb3JtZWQgYnkgVGhlcmVzYS4KClRoZXJlIGlzIG9uZSB3YXkgaW4gd2hpY2ggSSBleHBlY3QgYW55L2FsbCBvZiB0aGVzZSBhbmFseXNlcyB0byBiZQpleHBsaWNpdGx5IGRpZmZlcmVudDogdGhpcyBzaG91bGQgaW5jbHVkZSB0aGUgY2hhbmdlcyBwcm9kdWNlZCBieQpBcHJpbCdzIHJlbmFtaW5nIG9mIHNvbWUgc2FtcGxlcy4KCk15IGludGVudGlvbiBpcyB0byBwcm9kdWNlIGEgc2FtcGxlIHNoZWV0IHdoaWNoIGluY2x1ZGVzIG9uZSBjb2x1bW4Kd2l0aCBub24tdW1pLWRlZHVwbGljYXRlZCByZXN1bHRzIGFuZCBvbmUgd2l0aCBkZWR1cGxpY2F0ZWQgcmVzdWx0cy4KV2l0aCB0aGUgZXhjZXB0aW9uIG9mIHRoZSBwcmV2aW91cyBwb2ludCwgSSBob3BlIHRoYXQgdGhlIGZpcnN0IHdpbGwKYmUgaWRlbnRpY2FsIChvciBhdCBsZWFzdCB2ZXJ5IGNsb3NlIHRvIGlkZW50aWNhbCkgdG8gVGhlcmVzYSdzIHJlc3VsdAp3aGlsZSB0aGUgc2Vjb25kIEkgZXhwZWN0IHdpbGwgYmUgc3VidGx5IGRpZmZlcmVudCAtLSBidXQgSSBhbSBob3BpbmcKc3VidGx5IGVub3VnaCB0aGF0IGl0IHdpbGwgbm90IHNpZ25pZmljYW50bHkgY2hhbmdlIHRoZSBpbnRlcnByZXRhdGlvbgpidXQgYmUgYSBsaXR0bGUgbW9yZSBwcmVjaXNlLgoKTGV0cyBzZWUhICBJIG5lZWQgdGhlcmVmb3JlIHRvIG1ha2UgYSBjaGFuZ2UgdG8gbXkgbWV0YWRhdGEgZ2F0aGVyaW5nCmZ1bmN0aW9uIHRvIGluY2x1ZGUgdGhlIHVtaSBkZWR1cGxpY2F0ZWQgcmVzdWx0LiAgSSBhbSB0aGlua2luZwp0aGVyZWZvcmUgdG8gY3JlYXRlIGEgc2VwYXJhdGUgc3BlY2lmaWNhdGlvbiBmb3IgdW1pLWJhcmNvZGVkIHNhbXBsZXMKYmVjYXVzZSBsb29raW5nIHRocm91Z2ggdGhlIGxvZ3MgZm9yIHVtaSBzdHVmZiB3aGVuIHRoZXkgYXJlIG5vdCB1c2VkCndpbGwgYmUgdG9vIG11Y2ggb2YgYSBwYWluLi4uCgojIyBTbWFsbCByYW5kb20gcmVtaW5kZXIKCkkgaGF2ZSBhIGNvdXBsZSBwaWN0dXJlcyBvZiBSUEwyMiB0byBoZWxwIG1lIHJlbWVtYmVyIHRoZSBleHBlcmltZW50YWwKZGVzaWduOgoKKiBUaGUgaHVtYW4gcmlib3NvbWUgd2l0aCBSUEwyMiBpbiByZWQ6ICFbaHVtYW5fcnBsMjJfcmVkXShodW1hbl9yaWJvc29tZV9MMjJfcmVkLnBuZykKKiBUaGUgbW91c2Ugcmlib3NvbWUgd2l0aCBSUEwyMiBpbiBncmVlbiBhdCB0aGUgY2VudGVyOgohW21vdXNlX3JwbDIyXShtbXVzY3VsdXNfUlBMMjJfZ3JlZW5fY2VudGVyLnBuZykKClRoYXQgc2Vjb25kIHBpY3R1cmUgY2FtZSBmcm9tOiAoQGxpTWFsZUdlcm1jZWxsc3BlY2lmaWNSaWJvc29tZTIwMjIpCgojIEEgbm90ZSBhYm91dCBpbXBsZW1lbnRhdGlvbgoKSSB3b3VsZCBsaWtlIHRvIGltcHJvdmUgdGhpcyBkb2N1bWVudCBieSBjb21wYXJpbmcvY29udHJhc3RpbmcgdGhlCm1ldGhvZG9sb2dpZXMgcGVyZm9ybWVkIGJ5IG90aGVyIGdyb3VwcyBhbmQgdGhvc2UgcGVyZm9ybWVkIGJ5IG1lIGluCml0LiAgSSBuZXZlciBmdWxseSBhcHByZWNpYXRlZCB0aGUgc3VpdGUgb2YgY29tcHV0YXRpb25hbCBtZXRob2RzCmFwcGxpZWQgYnkgcHJldmlvdXMgZ3JvdXBzIHdoZW4gZXhhbWluaW5nIFRSQVAgZGF0YTsgSSBpbnN0ZWFkIHNpbXBseQpmb2xsb3dlZCBUaGVyZXNhJ3Mgbm90ZWJvb2sgd2l0aG91dCBjb25zaWRlcmluZyBvdGhlciBwb3NzaWJpbGl0aWVzLgoKSSB0aGVyZWZvcmUgc3BlbnQgYSBsaXR0bGUgdGltZSBzdGVwcGluZyB0aHJvdWdoIGhlciB0aGVzaXMgYW5kCnB1bGxpbmcgb3V0IHRoZSByZWxldmFudCBwYXBlcnMgaW4gdGhlIGhvcGVzIG9mIGxlYXJuaW5nIHRoZXNlIHZhcmlvdXMKbWV0aG9kcy4gIEkgc2hvdWxkIHRoZXJlZm9yZSBiZSBhYmxlIHNvb24gdG8gY29tcGFyZS9jb250cmFzdCB0aGUKdmFyaW91cyBtZXRob2RzIGVtcGxveWVkIGJ5IG90aGVyIGxhYnMgaW4gYWRkaXRpb24gdG8gY29weWluZwpUaGVyZXNhJ3MgbG9naWMuCgojIyBUaGUgZm9sbG93aW5nIGJsb2NrIGNhbm5vdCB3b3JrIGluIHRoZSBjb250YWluZXIKClRoZSBmb2xsb3dpbmcgYmxvY2sgYXNzdW1lcyB0aGUgZnVsbCB0cmVlIG9mIHByZXByb2Nlc3NlZCBkYXRhIHdpdGgKdGhlIGxvZ3MgZnJvbSB0aGUgdHJpbW1lciwgbWFwcGluZywgdW1pIGRlZHVwbGljYXRpb24sIGNvdW50aW5nLCBldGMuCkFzIGEgcmVzdWx0IGl0IGNhbm5vdCB3b3JrIGluIHRoZSBjb250YWluZXIgd2hpY2ggaGFzIG9ubHkgdGhlIHZhcmlvdXMKY291bnQgdGFibGVzLgoKQXMgYSByZXN1bHQsIEkgYW0gaW5jbHVkaW5nIGEgY29weSBvZiB0aGlzIHNoZWV0IGFmdGVyIHJ1bm5pbmcgdGhlCmZvbGxvd2luZyBibG9jayBpbiBteSB3b3JraW5nIHRyZWUuICBJIHN1cHBvc2UgZm9yIHRoZSBtb21lbnQgeW91IHdpbGwKaGF2ZSB0byB0cnVzdCB0aGF0IGl0IHdvcmtlZC4gIChmb3IgcmlnaHQgbm93LCB3aGVuIHRlc3Rpbmcgb3V0IHRoaXMKY29udGFpbmVyLCBJIGFtIGp1c3Qgc2VuZGluZyB0aGUgUiB3b3JraW5nIGRpcmVjdG9yeSB0byBteSB0cmVlIGZvcgp0aGlzIGJsb2NrLCB0aGVuIG1vdmluZyBpdCBiYWNrLgoKSSB3aWxsIG5lZWQgdG8gbWFudWFsbHkgZWRpdCBvbmUgY29sdW1uIHRob3VnaCwgdGhlIHN5bWxpbmsgY29sdW1uCmZyb20gVGhlcmVzYSBoYXMgYSBzZXJpZXMgb2YgcGF0aHMgd2hpY2ggZG8gbm90IHdvcmsgaW4gdGhlIGNvbnRhaW5lci4KCgpgYGB7ciwgZXZhbD1GQUxTRX0KdW1pX3NwZWMgPC0gbWFrZV9ybmFzZXFfc3BlYyh1bWkgPSBUUlVFKQppcHJnY18yMDIyX21ldGEgPC0gZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoInNhbXBsZV9zaGVldHMvMjAyNDA2MDZfb25seV91bWRfc2VxdWVuY2VkLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlYyA9IHVtaV9zcGVjLCBzcGVjaWVzID0gIm1tMzlfMTEyIiwgdmVyYm9zZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZWRpciA9ICJwcmVwcm9jZXNzaW5nL3VtZF9zZXF1ZW5jZWQiKQpjb2xuYW1lcyhpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSkKaGVhZChpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSkKYGBgCgpgYGB7cn0KbXNpZ2RiIDwtICJyZWZlcmVuY2UvbXNpZ2RiX3YyMDI0LjEuTW0uZGIiCm1zaWdfZGF0YSA8LSBOVUxMCm1ha2VfdHJhbnNwYXJlbnQgPC0gZnVuY3Rpb24oKSB7CiAgZ2dwbG90Mjo6dGhlbWUoCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnKSwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3RyYW5zcGFyZW50JywgY29sb3IgPSBOQSksCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAndHJhbnNwYXJlbnQnKSwKICAgIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3RyYW5zcGFyZW50JykpCn0KYGBgCgpJIHdpbGwgZmlndXJlIG91dCBpZiBJIGNhbiBsZWF2ZSBtU2lnREIgTTIgaW4gdGhpcyBpbWFnZTsgaWYgbm90LCB0aGVuCmFueSBhbmFseXNlcyBkZXBlbmRpbmcgb24gdGhvc2UgZ2VuZSBzZXRzIHdpbGwgZmFpbCBhIHByaW9yaS4KCmBgYHtyfQptMl9nc2MgPC0gdHJ5KGxvYWRfZ210X3NpZ25hdHVyZXMoc2lnbmF0dXJlcyA9IG1zaWdkYiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJNMiIpLCBzaWxlbnQgPSBUUlVFKQojIyBJIGRvIG5vdCB0aGluayBJIGhhdmUgcGVybWlzc2lvbiB0byBsb2FkIHRoZSBtc2lnZGIgaW4gdGhlIGNvbnRhaW5lcgojIyBTbywgaWYgdGhpcyBmYWlscywganVzdCBsb2FkIGl0IGZyb20gR1NWQURhdGEsIG9oIHdhaXQgbm8sIEdTVkFkYXRhIGlzIGh1bWFuLgppZiAoInRyeS1lcnJvciIgJWluJSBjbGFzcyhtMl9nc2MpKSB7CiAgd2FybmluZygiVW5hYmxlIHRvIGxvYWQgdGhlIE0yIE1zaWdEQiBkYXRhLiIpCn0KYGBgCgpGcm9tIHRoaXMgcG9pbnQgb24sIEkgYW0gaG9waW5nL2ludGVuZGluZyB0byBwdWxsIGxpYmVyYWxseSBmcm9tClRoZXJlc2EncyBub3RlYm9vayB3aXRoIGEgZGl2ZXJzaW9uIHRvIGNvbXBhcmUgdGhlIHRocmVlIGRhdGFzZXRzOgoKKiBQcmUtQXByaWwgcmVuYW1pbmc6IEUuZy4gVGhlcmVzYSdzIGN1cnJlbnQgZGF0YXNldAoqIFBvc3QgcmVuYW1pbmc6IFVubGVzcyBJIGFtIG1pc3Rha2VuLCB0aGlzIHNob3VsZCBiZSB2ZXJ5IHNpbWlsYXIgdG8KICB0aGUgYWJvdmUuCiogUG9zdCBkZWR1cGxpY2F0aW9uOiBHaXZlbiB3aGF0IEkgc2F3IGZyb20gdGhlIGV4dHJhY3RlZCBsb2dzIGluIHRoZQogIHNhbXBsZSBzaGVldCwgSSBleHBlY3QgdGhpcyB0byBiZSBzaW1pbGFyIGJ1dCBub3QgaWRlbnRpY2FsIHRvIHRoZQogIHByZXZpb3VzIHR3by4KCkxldHMgZmluZCBvdXQhICAgQnV0IGZpcnN0LCBhbm5vdGF0aW9ucyEKCiMgQW5ub3RhdGlvbiBkYXRhCgpJIGFtIHB1bGxpbmcgdGhpcyBmcm9tIFRoZXJlc2EncyBhbnhvbnRyYXBSX3BpcGVsaW5lLlJtZCwgcHJpbWFyaWx5CmJlY2F1c2UgaXQgbG9va3Mgc2ltaWxhciB0byB0aGUgb3RoZXIgZG9jdW1lbnRzLCBidXQgd2FzIG1vZGlmaWVkIG1vcmUKcmVjZW50bHkuICBJIHdpbGwgY2hhbmdlIGl0IHNsaWdodGx5LCBwcmltYXJpbHkgYmVjYXVzZSBJIGdyYWJiZWQgYQpuZXcgbW11c2N1bHVzIGFzc2VtYmx5IGFuZCB0aGVyZWZvcmUgSSB3aWxsIHB1bGwgdGhlIG1tdXNjdWx1cwphbm5vdGF0aW9ucyBmcm9tIGEgc3BlY2lmaWMgYmlvbWFydAooQHNtZWRsZXlCaW9NYXJ0QmlvbG9naWNhbFF1ZXJpZXMyMDA5KSBhcmNoaXZlIHRoYXQgc2hvdWxkIG1hdGNoIGl0LgoKQSBub3RlIGZyb20gdGhlIGZ1dHVyZTogbXVsdGlwbGUgZW5zZW1ibCBhcmNoaXZlIHNlcnZlcnMgaGF2ZSBiZWVuCnRha2VuIG9mZmxpbmUgc2luY2UgbGFzdCBJIHJhbiB0aGlzLiAgTGV0IHVzIHNlZSBpZiBGZWIuIDIwMjMgc3RpbGwKd29ya3MuCgojIyBBbiBpbXBvcnRhbnQgbm90ZSEKCkluIHRoZSByZWNlbnQgcGFzdCwgZW5zZW1ibCBxdWVyaWVzIGhhdmUgYmVjb21lIGluY29uc2lzdGVudCwgZmFpbGluZwptdWNoIG1vcmUgb2Z0ZW4gdGhhbiBldmVyIGluIHRoZSBwYXN0LiAgSSBkbyBub3QgdGhpbmsgdGhpcyBpcyB0aGUKZmF1bHQgb2YgZW5zZW1ibDsgYnV0IEkgdGhpbmsgSSBuZWVkIGEgZmFsbGJhY2sgbWVjaGFuaXNtIGZvcgpjb2xsZWN0aW5nIGFubm90YXRpb24gaW5mb3JtYXRpb24uCgpJbiB0aGUgY2FzZSBvZiBlbnNlbWJsLCBpdCBzaG91bGQgYmUgdHJpdmlhbCAoYnV0IGxlc3MgZnVuKSB0byB1c2UgYQpjb21iaW5hdGlvbiBvZiB0aGUgbG9jYWxseSBpbnN0YWxsZWQgb3JnZGIgYW5kIHR4ZGIgZGF0YWJhc2VzLgoKVGhpcyBkb2VzIG9wZW4gYSByaXNrIHRoYXQgdGhlIHNldCBvZiBnZW5lcyB3aXRoIGFubm90YXRpb25zIHdpbGwgYmUKZGlmZmVyZW50IGRlcGVuZGluZyBvbiB3aGVuIHRoZSBjb250YWluZXIgaXMgcnVuIGR1ZSB0byBkaWZmZXJlbmNlcwpiZXR3ZWVuIHRoZSBvcmdkYi90eGRiIGluc3RhbmNlIGFuZCB0aGUgRmViIDIwMjMgYmlvbWFydC4gIEkgYW0gbm90CnN1cmUgdGhlcmUgaXMgbXVjaCBJIGNhbiBkbyBhYm91dCB0aGF0IGV4Y2VwdCB0byBidW5kbGUgdGhlIHNldCBvZgphbm5vdGF0aW9ucyBJIGRvd25sb2FkZWQgaW4gdGhlIGNvbnRhaW5lciAtLSBzaW5jZQpsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoKSBkb2VzIHNhdmUgYSByZGEgY29weSBvZiBpdHMgZG93bmxvYWQuCgpvaywgSSBkaWQgYm90aC4gIElmIHlvdSwgZGVhciByZWFkZXIsIHdpc2ggdG8gZG93bmxvYWQgeW91ciBvd24KYW5ub3RhdGlvbnMsIGFuZCBlbnNlbWJsIGlzIGhhdmluZyB0cm91YmxlcywgdGhlIGZvbGxvd2luZyBzaG91bGQgd29yawp3aXRob3V0IGEgcHJvYmxlbTsgaW4gYWRkaXRpb24gdGhlIHJkYSBhbm5vdGF0aW9ucyBhcmUgaW4gL2RhdGEgb2YgdGhlCmNvbnRhaW5lciBhbmQgc2hvdWxkIGdldCBsb2FkZWQuCgojIyMgQW5vdGhlciBzdGF0ZWd5CgpJIGFkZGVkIGEgbGl0dGxlIGNvZGUgdG8gbXkgY3lvYSBwYWNrYWdlIHdoaWNoIGRvd25sb2FkcyBhbGwgdGhlCnRhYmxlcyBhdCBodHRwczovL2Z0cC5lbnNlbWJsLm9yZy9wdWIvY3VycmVudC9teXNxbC8gZm9yIGVpdGhlciB0aGUKYmlvbWFydCBkYXRhYmFzZSAoZW5zZW1ibF9tYXJ0XzExNi8gYW5kL29yIG1vdXNlX21hcnRfMTE2KSBvciB0aGUKc3BlY2llcyBzcGVjaWZpYyBkYXRhYmFzZSAobXVzX211c2N1bHVzX2NvcmVfMTE2XzM5KTsgSSB0aGVuIGFkZGVkCnNvbWUgZnVuY3Rpb25zIHRvIGhwZ2x0b29scyB0byBkaXJlY3RseSBxdWVyeSB0aGVzZSBsb2NhbCBTUUwKZGF0YWJhc2VzLiAgVGhpcyBpcyBjcmF6eSBmYXN0ICg8IDIgc2Vjb25kcyB2cy4gfiAyIG1pbnV0ZXMpIGNvbXBhcmVkCnRvIHVzaW5nIGJpb21hcnQsIGJ1dCBJIGRvIG5vdCBlbnRpcmVseSB1bmRlcnN0YW5kIHRoZSBzY2hlbWFzIHlldCBhbmQKc28gbWlzcyBzb21lIHBvdGVudGlhbGx5IHVzZWZ1bCBjb2x1bW5zIG9mIGludGVyZXN0LiAgSWYgYW55b25lIGlzCmludGVyZXN0ZWQsIEkgd291bGQgYmUgaGFwcHkgdG8gcGFzcyBhbG9uZyBtb3JlIGNvbXBsZXRlIGluc3RydWN0aW9uczsKSSBhbSB0aGlua2luZyBpdCB3b3VsZCBiZSBuaWNlIGZvciB0aGUgY29tbXVuaXR5IHRvIG1ha2UgdGhlIGxpdmVzIG9mCnBlb3BsZSBhdCBlbnNlbWJsIGVhc2llci4KCiMjIyBNeSBzdHJhdGVneSBmb3IgdGhlIGNvbnRhaW5lcgoKSSBkZWNpZGVkIHRvIGxvYWQgbXkgZXhpc3RpbmcgZW5zZW1ibCBhbm5vdGF0aW9ucyBhcyB0aGUgY2Fub25pY2FsCnNldCwgdGhlbiBhZGQgdG8gaXQgYSBwb3J0aW9uIG9mIHRoZSBtbS5lZy5kYiBhbm5vdGF0aW9ucy4gIEkgdGhlbgpzcGxpdCB0aGVtIHRvIG9uZSBzZXQgZm9yIHRoZSBnZW5lIGRhdGEgYW5kIGFub3RoZXIgZm9yIHRoZQp0cmFuc2NyaXB0cy4KCkhlcmUgYXJlIHRoZSBtb3N0IGltcG9ydGFudCBsYWJlbCBjb2x1bW5zOgoKMS4gIHN5bWJvbDogVGhlIGdlbmUgc3ltYm9sIChwcm92aWRlZCBieSBvcmcuTW0uZWcuZGIpCjIuICBleHRlcm5hbF90cmFuc2NyaXB0X25hbWU6IFVzdWFsbHkgdGhlIHNhbWUgYXMgc3ltYm9sLCBidXQgd2l0aCBhCiAgICBzdWZmaXggaWRlbnRpZnlpbmcgd2hpY2ggdHJhbnNjcmlwdCBpdCByZWZlcnMgdG8uIChmcm9tIGJpb21hcnQpCjMuICBnZW5lbmFtZTogTG9uZy1mb3JtIG5hbWUgKGZyb20gb3JnLk1tLmVnLmRiKQo0LiAgZGVzY3JpcHRpb246IE9mdGVuIGJ1dCBub3QgYWx3YXlzIGlkZW50aWNhbCB0byB0aGUgZ2VuZW5hbWUsCiAgICBpbmNsdWRlcyBhY2Nlc3Npb25zIGZvciBhIGNvdXBsZSBvZiBvdGhlciBkYXRhYmFzZXMuIChmcm9tCiAgICBiaW9tYXJ0KQo1LiAgZW5zZW1ibF9nZW5lX2lkOiBUaGUgRU5TTVVTRyBpZCwgb3VyIHByaW1hcnkga2V5IGZvciBnZW5lcwo2LiAgZW5zZW1ibF90cmFuc2NyaXB0X2lkOiBUaGUgRU5TTVVTVCwgb3VyIHByaW1hcnkga2V5IGZvciB0cmFuc2NyaXB0cwoKRHVlIHRvIHRoZSB3YXkgSSBhbSBtZXJnaW5nIHRoZXNlLCB0aGV5IGFyZSBwcmV0dHkgcmVkdW5kYW50LCBidXQgdGhleQp3aWxsIGdldCBwYXJlZCBkb3duIHdoZW4gbWVyZ2VkIHRvIHRoZSBhc3NheSBkYXRhLgoKYGBge3J9CnR4X2dlbmVfbWFwIDwtIGRhdGEuZnJhbWUoKQptbV9hbm5vdCA8LSB0cnkobG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHNwZWNpZXMgPSAibW11c2N1bHVzIiwgaG9zdCA9ICJ1c2Vhc3QuZW5zZW1ibC5vcmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyY2hpdmUgPSBGQUxTRSwgb3ZlcndyaXRlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9yZXF1ZXN0cyA9IGFubm90YXRpb25fY29sdW1ucykpCmZpZWxkcyA8LSBjKCJBQ0NOVU0iLCAiRU5TRU1CTCIsICJFTlNFTUJMVFJBTlMiLCAiRU5URVpJRCIsICJHRU5FTkFNRSIsICJTWU1CT0wiKQpvcmdkYl9hbm5vdCA8LSBsb2FkX29yZ2RiX2Fubm90YXRpb25zKCJvcmcuTW0uZWcuZGIiLCBmaWVsZHMgPSBmaWVsZHMpCmdlbmVfaW5mbyA8LSBvcmdkYl9hbm5vdFtbImdlbmVzIl1dCgojIyBOb3RlLCB0aGVyZSBhcmUgYSBidW5jaCBvZiB2YXJpYW50cyBvZiB0aGUgdHhkYiBwYWNrYWdlIG9uZSBtaWdodCB1c2UuCiMjIEkgZG8gbm90IHRoaW5rIGl0IG1hdHRlcnMgYSBsb3QgZm9yIG91ciBwdXJwb3NlcywgYnV0IEkgc3VzcGVjdCB0aGF0IGlmIHdlIHVzZWQKIyMgYSBtaXNtYXRjaGVkIEJTZ2Vub21lIGFuZCB0cmllZCB0byBwdWxsIENEUyBzZXF1ZW5jZXMsIHRoYXQgbWlnaHQgZW5kIGJhZGx5Lgpwa2cgPC0gIlR4RGIuTW11c2N1bHVzLlVDU0MubW0xMC5rbm93bkdlbmUiCnR4X2Fubm90IDwtIGxvYWRfdHhkYl9hbm5vdGF0aW9ucyhwa2cpCnRyYW5zY3JpcHRzIDwtIHR4X2Fubm90W1siVFgiXV0KdHJhbnNjcmlwdHNbWyJ0eCJdXSA8LSBnc3ViKHggPSB0cmFuc2NyaXB0c1tbIlRYTkFNRSJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiXFwuXFxkKyQiLCByZXBsYWNlbWVudCA9ICIiKQptbV9hbm5vdF9vcmdkYiA8LSBtZXJnZShnZW5lX2luZm8sIHRyYW5zY3JpcHRzLCBieS54ID0gImVuc2VtYmx0cmFucyIsIGJ5LnkgPSAidHgiKQpyb3duYW1lcyhtbV9hbm5vdF9vcmdkYikgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdF9vcmdkYltbImVuc2VtYmwiXV0sIHVuaXF1ZSA9IFRSVUUpCgptbV9hbm5vdF9jb21iaW5lZCA8LSBtZXJnZShtbV9hbm5vdFtbImFubm90YXRpb24iXV0sIG1tX2Fubm90X29yZ2RiLCBieS54ID0gImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsIGJ5LnkgPSAiZW5zZW1ibHRyYW5zIiwgYWxsLnggPSBUUlVFKQoKbW1fYW5ub3RfZ2VuZXMgPC0gbW1fYW5ub3RfY29tYmluZWQKcm93bmFtZXMobW1fYW5ub3RfZ2VuZXMpIDwtIG1ha2UubmFtZXMobW1fYW5ub3RfZ2VuZXNbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZSA9IFRSVUUpCgptbV9hbm5vdF90eCA8LSBtbV9hbm5vdF9jb21iaW5lZApyb3duYW1lcyhtbV9hbm5vdF90eCkgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdF90eFtbImVuc2VtYmxfdHJhbnNjcmlwdF9pZCJdXSwgdW5pcXVlID0gVFJVRSkKCnR4X2dlbmVfbWFwIDwtIG1tX2Fubm90X2dlbmVzWywgYygiVFhJRCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KYGBgCgpUaGUgZW5kIHJlc3VsdCBvZiB0aGVzZSB2YXJpb3VzIGFubm90YXRpb24gY29sbGVjdGlvbnMgaXMgbW9zdGx5CmlkZW50aWNhbCwgYnV0IHRoZSBjb2x1bW4gY29udGFpbmluZyB0aGUgTUdJIGdlbmUgbmFtZXMgbWF5IGdldApjaGFuZ2VkLiAgVGhpcyBpcyBwcmV0dHkgYW5ub3lpbmcgd2hlbiBpdCBjb21lcyB0byBnZXR0aW5nIHRoZQpjb250YWluZXIgaW1hZ2UgdG8gcnVuIHBlcmZlY3RseSBpbiBhbGwgc2l0dWF0aW9uczsgYW5kIHNvIGF0IHRoaXMKdGltZSBpdCBqdXN0IGxvYWRzIHRoZSBsb2NhbC5yZGEgZmlsZTsgaWYgb25lIHdpc2hlcyB0byBwbGF5IHByZXNzCnlvdXIgbHVjayB3aXRoIGVuc2VtYmwsIGp1c3QgZGVsZXRlIHRoZSBhbm5vdGF0aW9uIHJkYSBhbmQgcmUtcmVuZGVyCnRoZSBkb2N1bWVudHMuCgojIEhpc2F0MiBzdW1tYXJpemVkRXhwZXJpbWVudHMKClRoZSBwcmltYXJ5IGRpZmZlcmVuY2UgYmV0d2VlbiBteSBibG9jayBhbmQgVGhlcmVzYSdzIGFyZToKCjEuICBJIGFtIHB1bGxpbmcgdGhlIG1ldGFkYXRhIGRpcmVjdGx5IGZyb20gdGhlCiAgICBnYXRoZXJfcHJlcHJvY2Vzc2luZ19tZXRhZGF0YSgpIGFib3ZlLgoyLiAgSSBhbSB1c2luZyB0aGUgY29sdW1uICdzeW1saW5rJyB3aGljaCBpcyBqdXN0IGEgY29weSBvZiB0aGUKICAgIGV4aXN0aW5nICdmaWxlJyBjb2x1bW4gd2l0aCBhIHNtYWxsIGNoYW5nZSBzbyBJIGNhbiBsb2FkIGl0IGZyb20KICAgIG15IGRpcmVjdG9yeSB3aXRob3V0IGhhdmluZyB0byBjb3B5IGV2ZXJ5dGhpbmcuCjMuICBJIGFtIHVzaW5nIHRoZSBlbnNlbWJsIGdlbm9tZSByZWxlYXNlIDM5LCB2ZXJzaW9uIDExMiBhbmQgc28KICAgIHB1bGxlZCBhIHNvbWV3aGF0IG5ld2VyIGNvcHkgb2YgdGhlIGFubm90YXRpb24gZGF0YS4KNC4gIFRoZSBvcmlnaW5hbCBpcyBuYW1lZCAndjEnLCBmb2xsb3dlZCBieSAndjInIGFuZCAndjMnIGZvciB0aGUKICAgIG90aGVyIHR3byB0cmVhdG1lbnRzIEkgcGVyZm9ybWVkLgoKIyMgQ29sb3IgY2hvaWNlcyBhbmQgcmV1c2VkIHBhcmFtZXRlcnMKCkdpdmVuIHRoYXQgd2UgYXJlIGV4Y2x1ZGluZyBhIGJ1bmNoIG9mIHRoZSBvbGRlciBzYW1wbGVzLCB0aGUgc2V0IG9mCmNvbG9ycyBJIGV4cGVjdCB0byBmaW5kIGlzIGRpZmZlcmVudDsgc28gSSB3aWxsIG1ha2UgZXhwbGljaXQgaGVyZSB0aGUKdmFyaW91cyBjb2xvcnMgdXNlZCB0byBkZW5vdGUgbG9jYXRpb24vZ2Vub3R5cGUvdGltZS9ldGMuCgpBcHJpbCB0dXJuZWQgbWUgb250byB0aGlzIHdlYnNpdGUgJ3BhbGV0dG9uLmNvbScgZm9yIHRoaXMga2luZCBvZgpzdHVmZiBhbmQgSSB3aWxsIHRyeSBhbmQgcGljayBvdXQgcGFsZXR0ZXMgd2hpY2ggYmFzaWNhbGx5IG1hdGNoIHdoYXQKSSBhbSBnZXR0aW5nIHdpdGggdGhlIG9yaWdpbmFsIGNvbG9ycy4KCmBgYHtyfQpjb2xvcl9jaG9pY2VzIDwtIGxpc3QoCiAgImFsbCIgPSBsaXN0KAogICAgInAwOF9oZXRfZGxnbiIgPSAiI0U3Mjk4QSIsCiAgICAicDE1X2hldF9kbGduIiA9ICIjRTcyOThBIiwKICAgICJwMDhfaGV0X3JldGluYSIgPSAiIzIzOEI0NSIsCiAgICAicDE1X2hldF9yZXRpbmEiID0gIiMyMzhCNDUiLAogICAgInAwOF9oZXRfc2NuIiA9ICIjNDI5MkM2IiwKICAgICJwMTVfaGV0X3NjbiIgPSAiIzQyOTJDNiIsCiAgICAicDA4X2tvX2RsZ24iID0gIiNDOTk0QzciLAogICAgInAxNV9rb19kbGduIiA9ICIjQzk5NEM3IiwKICAgICJwMDhfa29fcmV0aW5hIiA9ICIjNzRjNDc2IiwKICAgICJwMTVfa29fcmV0aW5hIiA9ICIjNzRjNDc2IiwKICAgICJwMDhfa29fc2NuIiA9ICIjOUJDQUUxIiwKICAgICJwMTVfa29fc2NuIiA9ICIjOUJDQUUxIiwKICAgICJwMDhfd3RfZGxnbiIgPSAiIzk4MDA0MyIsCiAgICAicDE1X3d0X2RsZ24iID0gIiM5ODAwNDMiLAogICAgInAwOF93dF9yZXRpbmEiID0gIiMwMDQwMDgiLAogICAgInAxNV93dF9yZXRpbmEiID0gIiMwMDQwMDgiLAogICAgInAwOF93dF9zY24iID0gIiMwODUxOUMiLAogICAgInAxNV93dF9zY24iID0gIiMwODUxOUMiLAogICAgInA2MF93dF9kbGduIiA9ICIjMzMzMzMzIiwKICAgICJwNjBfd3RfcmV0aW5hIiA9ICIjMjIyMjIyIiwKICAgICJwNjBfd3Rfc2NuIiA9ICIjMTExMTExIiksCiAgImdlbm9fbG9jIiA9IGxpc3QoCiAgICAiaGV0X2RsZ24iID0gIiNFNzI5OEEiLAogICAgImhldF9yZXRpbmEiID0gIiMyMzhCNDUiLAogICAgImhldF9zY24iID0gIiM0MjkyQzYiLAogICAgImtvX2RsZ24iID0gIiNDOTk0QzciLAogICAgImtvX3JldGluYSIgPSAiIzc0YzQ3NiIsCiAgICAia29fc2NuIiA9ICIjOUJDQUUxIiwKICAgICJ3dF9kbGduIiA9ICIjOTgwMDQzIiwKICAgICJ3dF9yZXRpbmEiID0gIiMwMDQwMDgiLAogICAgInd0X3NjbiIgPSAiIzA4NTE5QyIpLAogICJsb2NhdGlvbiIgPSBsaXN0KAogICAgInJldGluYSIgPSAiIzAwNDAwOCIsCiAgICAiZGxnbiIgPSAiIzk4MDA0MyIsCiAgICAic2NuIiA9ICIjMDg1MTlDIiksCiAgImdlbm90eXBlIiA9IGxpc3QoCiAgICAid3QiID0gIiM3NGM0NzYiLAogICAgImhldCIgPSAiIzIzOEI0NSIsCiAgICAia28iID0gIiMwMDZEMkMiKSwKICAidGltZSIgPSBsaXN0KAogICAgInAwOCIgPSAiIzVFMTA0QiIsCiAgICAicDE1IiA9ICIjNEU5MjMxIikpCmxhYmVsX2NvbHVtbiA8LSAibWdpX3N5bWJvbCIgIyMgU2V0IHRoZSBjb2x1bW4gdXNlZCB0byBleHRyYWN0IGdlbmUgc3ltYm9scyByYXRoZXIgdGhhbiBFTlNHLi4uLi4KY29sb3JzIDwtIGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXQp0aW1lX2NvbG9ycyA8LSBsaXN0KAogICJwMDhfaGV0X2RsZ24iID0gIiNFNzI5OEEiLAogICJwMTVfaGV0X2RsZ24iID0gIiM4YTE4NTIiLAogICJwMDhfaGV0X3JldGluYSIgPSAiIzIzOEI0NSIsCiAgInAxNV9oZXRfcmV0aW5hIiA9ICIjMTU1MzI5IiwKICAicDA4X2hldF9zY24iID0gIiM0MjkyQzYiLAogICJwMTVfaGV0X3NjbiIgPSAiIzI3NTc3NiIsCiAgInAwOF9rb19kbGduIiA9ICIjQzk5NEM3IiwKICAicDE1X2tvX2RsZ24iID0gIiM3ODU4NzciLAogICJwMDhfa29fcmV0aW5hIiA9ICIjNzRDNDc2IiwKICAicDE1X2tvX3JldGluYSIgPSAiIzQ1NzU0NiIsCiAgInAwOF9rb19zY24iID0gIiM5QkNBRTEiLAogICJwMTVfa29fc2NuIiA9ICIjNWQ3OTg3IikKYGBgCgpUaGVyZSBpcyBvbmUgbm90ZXdvcnRoeSBzYW1wbGU6IGlwcmdjXzEwMywgaXQgd2FzIGVmZmVjdGl2ZWx5IHJlcGxhY2VkCndoZW4gQXByaWwgcmVuYW1lZCB0aGUgc2FtcGxlcyBhbmQgc28gZXhpc3RzIGluIHRoZSB2MSBkYXRhLCBidXQgbm90CnYyL3YzOyB0aGV5IGluc3RlYWQgaGF2ZSB0aGUgbmV3bHkgbmFtZWQgc2FtcGxlcyB3aGljaCBJIGNhbGxlZAppcHJnY18xMjMgdG8gaXByZ2NfMTMwLiAgQXMgYSByZXN1bHQsIEkgY29waWVkIHRoZSBhbm5vdGF0aW9ucyBmb3IKaXByZ2NfMTIzIHRvIG15IGNvbHVtbiBzbyB0aGF0IHRoZXJlIGlzIG5vIGRpc2NyZXBlbmN5IGluIHRlcm1zIG9mCmdlbm90eXBlL2xvY2F0aW9uL3RpbWUuCgojIyBUaGUgb3JpZ2luYWwgY291bnQgdGFibGVzCgpBdCB0aGUgbW9tZW50IEkgaGF2ZSBub3QgaW5jbHVkZWQgdGhlIG9yaWdpbmFsIGNvdW50cyBpbiB0aGlzCmNvbnRhaW5lciBiZWNhdXNlIHdlIG1hZGUgc29tZSBjaGFuZ2VzIHRvIHRoZSBtYXBwaW5nIHN0cmF0ZWd5IGFuZAphbHNvIGZvdW5kIHRoYXQgYSBjb3VwbGUgc2FtcGxlcyB3ZXJlIG1peGVkIHVwIGluIHNlcXVlbmNpbmc7IGFzIGEKcmVzdWx0IEkgZG9jdW1lbnRlZCBhbGwgb2YgdGhlIGNoYW5nZXMgaW4gdGhlIHNhbXBsZSBzaGVldHMgYW5kCnByZXByb2Nlc3NpbmcgZG9jdW1lbnRzIGFuZCBleGNsdWRlZCB0aGUgb3JpZ2luYWwgZmlsZXMuCgpUaGlzIGlzIGFsc28gd2h5IHNvbWUgY29sdW1ucyBpbiB0aGUgc2FtcGxlIHNoZWV0IGhhdmUgc3VmZml4ZXMgbGlrZQonYWRoJyBhbmQgJ2F0YicsIHRob3NlIGRlbm90ZSBmcm9tIHdob20gdGhlIHJlbGV2YW50IG1ldGFkYXRhIGNvbHVtbnMKY2FtZSBmcm9tLgoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tMzhfaGlzYXRfdjEgPC0gY3JlYXRlX3NlKHNhbXBsZV9zaGVldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9pbmZvID0gbW1fYW5ub3RfZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gInN5bWxpbmsiKSB8PgogIHNldF9jb25kaXRpb25zKGZhY3QgPSAiZ2Vub19sb2NfYXRiIikgfD4KICBzZXRfYmF0Y2hlcyhmYWN0ID0gInRpbWVfYXRiIikgfD4KICBzZXRfY29sb3JzKGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXSkKbW0zOF9oaXNhdF92MQpgYGAKCiMjIFJlY291bnRlZCB0YWJsZXMgYW5kIHRoZSBkZWR1cGxpY2F0ZWQgcmVzdWx0CgpJbiB0aGUgZm9sbG93aW5nIEkgbWFrZSB0d28gbW9yZSB2ZXJzaW9ucyBvZiB0aGUgZGF0YSwgb25lIHJlbWFwcGVkCndpdGggdGhlIGNoYW5nZXMgdG8gdGhlIHNhbXBsZSBpZGVudGl0aWVzLCBhbmQgb25lIHdpdGggZGVkdXBsaWNhdGlvbgphcHBsaWVkLgoKYGBge3J9Cm1tMzhfaGlzYXRfdjIgPC0gY3JlYXRlX3NlKHNhbXBsZV9zaGVldCwgZ2VuZV9pbmZvID0gbW1fYW5ub3RfZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gImhpc2F0X2NvdW50X3RhYmxlIikgfD4KICBzZXRfY29uZGl0aW9ucyhmYWN0ID0gImdlbm9fbG9jX2F0YiIpIHw+CiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJ0aW1lX2F0YiIpIHw+CiAgc2V0X2NvbG9ycyhjb2xvcl9jaG9pY2VzW1siZ2Vub19sb2MiXV0pCm1tMzhfaGlzYXRfdjIKbW0zOF9oaXNhdF92MyA8LSBjcmVhdGVfc2Uoc2FtcGxlX3NoZWV0LCBnZW5lX2luZm8gPSBtbV9hbm5vdF9nZW5lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidW1pX2RlZHVwX291dHB1dF9jb3VudCIpIHw+CiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vX2xvY19hdGIiKSB8PgogIHNldF9iYXRjaGVzKGZhY3QgPSAidGltZV9hdGIiKSB8PgogIHNldF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImdlbm9fbG9jIl1dKQptbTM4X2hpc2F0X3YzCgphbGxfZmFjdCA8LSBwYXN0ZTAoY29sRGF0YShtbTM4X2hpc2F0X3YzKVtbInRpbWVfYXRiIl1dLCAiXyIsCiAgICAgICAgICAgICAgICAgICBjb2xEYXRhKG1tMzhfaGlzYXRfdjMpW1siZ2Vub19sb2NfYXRiIl1dKQpjb2xEYXRhKG1tMzhfaGlzYXRfdjMpW1sidGltZV9nZW5vX2xvYyJdXSA8LSBhbGxfZmFjdApgYGAKCiMgVXNlIHRoZSBTdW1tYXJpemVkIEV4cGVyaW1lbnQgdG8gcHJ1bmUgdGhlIGdlbmUgYW5ub3RhdGlvbnMKCmBgYHtyfQptbV9hbm5vdF9nZW5lcyA8LSBhcy5kYXRhLmZyYW1lKHJvd0RhdGEobW0zOF9oaXNhdF92MykpCmBgYAoKIyMgQXJjaGl2ZSBjb3VudCB0YWJsZXMgZm9yIHRoZSBzaW5ndWxhcml0eSBjb250YWluZXIKClRoZSBmb2xsb3dpbmcgaXMgd2hhdCBJIGRpZCB0byBtYWtlIGFuIGFyY2hpdmUgb2YgdGhlIHRyYW5zY3JpcHQgY291bnQKdGFibGVzIGZvbGxvd2luZyBkZWR1cGxpY2F0aW9uLiAgSXQgY3JlYXRlcyBhIHRhciBhcmNoaXZlIG9mIGFsbCB0aGUKZmlsZW5hbWVzIHByb3ZpZGVkIGluIHRoZSAnY29sdW1uJyBhcmd1bWVudC4KCmBgYHtyLCBldmFsPUZBTFNFfQptcm5hX3RhYmxlcyA8LSB0YXJfbWV0YV9jb2x1bW4obW0zOF9oaXNhdF92MywgY29sdW1uID0gInVtaV9kZWR1cF9tcm5hX2NvdW50IikKYGBgCgpOb3RlIHRoZSBlbmQgb2YgdGhlIHByZXZpb3VzIGJsb2NrLCBJIGNyZWF0ZWQgYSBmYWN0b3Igb3V0IG9mIHRoZQpjb21iaW5hdGlvbiBvZiB0aW1lLCBnZW5vdHlwZSwgYW5kIGxvY2F0aW9uLiAgSW4gYSBmdXR1cmUgaW52b2NhdGlvbgpvZiB0aGlzIG5vdGVib29rLCBJIHdpbGwgY2hhbmdlIHRoZSBwYWlyd2lzZSBjb21wYXJpc29ucyB0byBhZGQgZWFjaApvZiB0aGVzZSB0aHJlZSBmYWN0b3JzIHRvIHRoZSBzdGF0aXN0aWNhbCBtb2RlbCBpbnN0ZWFkIG9mIHRoaXMuICBUaGUKY29kZSB0byBkbyB0aGF0IGlzIG5vdCBfcXVpdGVfIHJlYWR5IHlldC4KCiMgTm9uLXplcm8gQ291bnRzIHBlciBTYW1wbGUKCkxldCdzIGxvb2sgYXQgdGhlIG51bWJlciBvZiBub24temVybyBnZW5lcyBmb3IgYWxsIHNhbXBsZXMgdmVyc3VzIHRoZQpjb3ZlcmFnZS4KCkFzIGFib3ZlLCB0aGlzIGRvZXMgbm90IGdldCBydW4gYmVjYXVzZSBJIGRpZCBub3QgY29weSB0aGUgY291bnQgdGFibGVzLgoKYGBge3IgZXZhbD1GQUxTRX0KdjFfbm9uemVybyA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF92MSkKdjFfbm9uemVybwpgYGAKCkJ1dCB0aGVzZSBkbyEKCmBgYHtyfQpwbG90X2xlZ2VuZChtbTM4X2hpc2F0X3YyKQp2Ml9ub256ZXJvICA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF92MiwgeV9pbnRlcmNlcHQgPSAwLjY1KQp2Ml9ub256ZXJvCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlcy9ub256ZXJvX3YyX3VuZmlsdGVyZWQucGRmIikKdjJfbm9uemVyb1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKCnYzX25vbnplcm8gIDwtIHBsb3Rfbm9uemVybyhtbTM4X2hpc2F0X3YzLCB5X2ludGVyY2VwdCA9IDAuNjUpCnYzX25vbnplcm8KcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL25vbnplcm9fdjNfdW5maWx0ZXJlZC5wZGYiKQp2M19ub256ZXJvW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCk9oIHdvdywgSSBkaWQgbm90IGV4cGVjdCBzdWNoIGEgcHJvZm91bmQgZWZmZWN0IG9uIHRoZSBjcG0gdmFsdWVzIG9uCnRoZSBtb3JlIHNhdHVyYXRlZCBsaWJyYXJpZXMuICBJIGd1ZXNzIGluIHJldHJvc3BlY3QgSSBzaG91bGQgaGF2ZT8KCkFsc28gbm90ZSB0byBzZWxmLCB3ZSBhcmUgbm90IG1lc3Npbmcgd2l0aCBwNjAuCgojIyBFeGNsdWRlIHA2MAoKYGBge3J9Cm1tMzhfaGlzYXRfdjIgPC0gc3Vic2V0X3NlKG1tMzhfaGlzYXRfdjIsIHN1YnNldCA9ICJ0aW1lX2F0YiE9J3A2MCciKQptbTM4X2hpc2F0X3YzIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3YzLCBzdWJzZXQgPSAidGltZV9hdGIhPSdwNjAnIikKYGBgCgojIyBSZXBsb3QgdGhlIG5vbnplcm8gZ2VuZSBwbG90cwoKYGBge3J9CnYyX25vbnplcm9fZmlsdCA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF92MiwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL25vbnplcm9fdjJfZmlsdC5wZGYiLCBpbWFnZSA9IHYyX25vbnplcm9fZmlsdFtbInBsb3QiXV0pCgp2M19ub256ZXJvX2ZpbHQgPC0gcGxvdF9ub256ZXJvKG1tMzhfaGlzYXRfdjMsIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlcy9ub256ZXJvX3YzX2ZpbHQucGRmIiwgaW1hZ2UgPSB2M19ub256ZXJvX2ZpbHRbWyJwbG90Il1dKQpgYGAKCk9uY2UgYWdhaW4sIEkgZG8gbm90IHdhbnQgdG8gbG9zZSB0aGUgcHJldmlvdXMgY29kZSwgc28gaGVyZSBpcyB0aGUgdjEgaW52b2NhdGlvbgoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tMzhfaGlzYXRfdjEgPC0gc3Vic2V0X3NlKG1tMzhfaGlzYXRfdjEsIHN1YnNldCA9ICJ0aW1lX2F0YiE9J3A2MCciKQpgYGAKCiMgUXVpY2sgUENBLCB0aGVuIHJldHVybiB0byBUaGVyZXNhJ3MgZG9jdW1lbnQKCmBgYHtyfQp2Ml9ub3JtIDwtIG5vcm1hbGl6ZShtbTM4X2hpc2F0X3YyLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnYyX25vcm1fcGNhIDwtIHBsb3RfcGNhKHYyX25vcm0pCnYyX25vcm1fcGNhCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlcy92Ml9ub3JtX3BjYS5wZGYiLCBpbWFnZSA9IHYyX25vcm1fcGNhW1sicGxvdCJdXSkKCnYzX25vcm0gPC0gbm9ybWFsaXplKG1tMzhfaGlzYXRfdjMsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSkKdjNfbm9ybV9wY2EgPC0gcGxvdF9wY2EodjNfbm9ybSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL3YzX25vcm1fcGNhLnBkZiIsIGltYWdlID0gdjNfbm9ybV9wY2FbWyJwbG90Il1dKQpgYGAKCkliaWQuCgpgYGB7ciwgZXZhbD1GQUxTRX0KdjFfbm9ybSA8LSBub3JtYWxpemUobW0zOF9oaXNhdF92MSwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCBmaWx0ZXIgPSBUUlVFKQpwbG90X3BjYSh2MV9ub3JtKQpgYGAKClRvIG15IGV5ZXMgaXQgbG9va3MgbGlrZSB3ZSBqdXN0IGhhdmUgMSB3ZWlyZG8gcDE1IHNhbXBsZT8KRGVkdXBsaWNhdGlvbiBoYWQgYSBtaW5vciBidXQgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBQQ0EuCgpXaXRoIHRoYXQgaW4gbWluZCwgbGV0IHVzIGxvb2sgYXQgVGhlcmVzYSdzIFdPUktJTkcgZG9jdW1lbnQgYW5kIHNlZQp3aGF0IHdlIGNhbiByZWNhcGl0dWxhdGUuCgpUaGVyZXNhJ3MgZG9jdW1lbnQ6IFRoZSBUUkFQIHByb3RvY29sIGhhcyBzb21lIHZhcmlhYmlsaXR5IHdoaWNoIGlzCmludHJvZHVjZWQgYXQgZGlmZmVyZW50IHN0cGRmIGluY2x1ZGluZyBob21vZ2VuaXphdGlvbiwgYW50aWJvZHkKbGFiZWxpbmcsIHB1bGxkb3duIGVmZmljaWVuY3kvc3BlY2lmaWNpdHksIHNhbXBsZSBoYW5kbGluZyBkdXJpbmcKY2xlYW51cCwgYW5kIGxpYnJhcnkgcHJlcC9zZXF1ZW5jaW5nLiBXZSBrbm93IGZyb20gUmFzaG1pJ3MgUUMKdGhhdCB0aGVyZSBpcyB2YXJpYWJpbGl0eSBhdCB0aGUgbGV2ZWwgb2YgcHVsbGRvd24gZWZmaWNpZW5jeSAoYW1vdW50Cm9mIFJOQSBpc29sYXRlZCkuIFNoZSBpcyBkb2luZyBhIGdvb2Qgam9iIG9mIGtlZXBpbmcgdHJhY2sgb2YgdGhpcyBmb3IKYWxsIGhlciBzYW1wbGVzIGFuZCB3ZSBoYXZlIHZhbGlkYXRlZCBoZXIgUDggcmVzdWx0cyAoYXR0YWNoZWQKc3VwcGxlbWVudGFyeSBmaWd1cmUgM0QpLiBXZSBjb25zaXN0ZW50bHkgc2VlIGNsZWFyIGRpZmZlcmVuY2VzCmJldHdlZW4gY29udHJvbCBhbmQgY3JlIHNhbXBsZXMgZm9yIHRoZSByZXRpbmEsIHdoaWNoIG1ha2VzIHNlbnNlCmJlY2F1c2UgdGhlIGNlbGwgYm9kaWVzIGFyZSBpbiB0aGUgcmV0aW5hLiBUaGUgdGFyZ2V0IHRpc3N1ZQpkaWZmZXJlbmNlcyBhcmUgc21hbGxlciwgd2hpY2ggYWxzbyBtYWtlcyBzZW5zZSBmb3IgYXhvbi1UUkFQLiBXZQp0aGluayB0aGF0IHNvbWUgb2YgaGVyIFAxNSBzYW1wbGVzIGFyZSBub3QgZ29vZCBiYXNlZCBvbiBsb3cgYW1vdW50cwpvZiBpc29sYXRlZCBSTkEgZnJvbSBjcmUoKykgcmV0aW5hIHNhbXBsZXMuIFdlIHBsYW4gdG8gZHJvcCB0aGVzZQpzYW1wbGVzIGFuZCBub3QgcGVyZm9ybSBhZGRpdGlvbmFsIGlzb2xhdGlvbnMgYXQgdGhpcyB0aW1lCnBvaW50LiBCYXNlZCBvbiB0aGlzIChhbmQgdGhlIGdlbmVyYWwgbGFjayBvZiBsYXJnZSBkZXZlbG9wbWVudGFsCmVmZmVjdHMpLCB3ZSB3ZXJlIHBsYW5uaW5nIHRvIGZvY3VzIG9uIHByZXNlbnRpbmcgdGhlIFA4IGRhdGEgb25seSBpbgp0aGUgcGFwZXIuIEludGVyZXN0ZWQgdG8gaGVhciB5b3VyIHRob3VnaHRzIGluIHRoaXMuLi4KCk15IG5vdGVzOiBUaGVyZXNhJ3MgZmlyc3Qgb3BlcmF0aW9ucyBpbiB0aGlzIG5vdGVib29rIHdlcmUgdG86CgoxLiAgU2V0IGxvY2F0aW9uIGFzIGNvbmRpdGlvbiwgZ2Vub3R5cGUgYXMgYmF0Y2guCjIuICBQZXJmb3JtIFBDQSBiZWZvcmUvYWZ0ZXIgc3ZhLgoKYGBge3J9CnYzX2xvY19nZW5vIDwtIHNldF9jb25kaXRpb25zKG1tMzhfaGlzYXRfdjMsIGZhY3QgPSAibG9jYXRpb25fYXRiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKSB8PgogIHNldF9iYXRjaGVzKGZhY3QgPSAiZ2Vub3R5cGVfYXRiIikKYGBgCgojIyBUaGUgYXNzb2NpYXRlZCBQQ0EKCkF0IGRpZmZlcmVudCB0aW1lcywgaXQgYXBwZWFycyB0byBtZSB0aGF0IFRoZXJlc2EgaGFzIHByZWZlcnJlZApzbGlnaHRseSBkaWZmZXJlbnQgbm9ybWFsaXphdGlvbiBtZXRob2RzLCBwcmltYXJpbHkgYSBtaXggb2YgVE1NIGFuZApxdWFudGlsZS4KClRodXMgSSB3aWxsIHVzZSBkaWZmZXJlbnQgc3VmZml4IGxldHRlcnMgdG8gZGVub3RlIHZhcmlvdXMKbm9ybWFsaXphdGlvbnMgZW1wbG95ZWQsIGFuZCBpZiB0aGV5IHR1cm4gb3V0IHRoZSBzYW1lIEkgd2lsbCBwaWNrIG9uZSBhcmJpdHJhcmlseS4KCmBgYHtyfQpsb2NfZ2Vub19ucSA8LSBub3JtYWxpemUodjNfbG9jX2dlbm8sIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCmxvY2F0aW9uX2dlbm90eXBlX3BjYSA8LSBwbG90X3BjYShsb2NfZ2Vub19ucSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL2xvY2F0aW9uX2dlbm90eXBlX25vcm1fcGNhLnBkZiIsCiAgIGltYWdlID0gbG9jYXRpb25fZ2Vub3R5cGVfcGNhW1sicGxvdCJdXSkKIyMgb2ssIEkgaGF2ZSB0d28gd2VpcmRvIHNhbXBsZXMgd2hpY2ggbG9vayB2ZXJ5IG11Y2ggbGlrZSB0aGV5IGFyZSBhY3R1YWxseSBkbGduLgojIyBUaGVzZSBhcmUgc2FtcGxlIElEcyBpcHJnY182NiBhbmQgaXByZ2NfMTMwCgpsb2NfZ2Vub19udCA8LSBub3JtYWxpemUodjNfbG9jX2dlbm8sIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJ0bW0iKQpsb2NhdGlvbl9nZW5vdHlwZV90bW1fcGNhIDwtIHBsb3RfcGNhKGxvY19nZW5vX250KQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXMvbG9jYXRpb25fZ2Vub3R5cGVfdG1tX3BjYS5wZGYiLAogICBpbWFnZSA9IGxvY2F0aW9uX2dlbm90eXBlX3RtbV9wY2FbWyJwbG90Il1dKQpgYGAKCkEgcmFuZG9tIHRob3VnaHQgYWJvdXQgdGhlc2UgUENBIHBsb3RzLCBpdCBtaWdodCBiZSB3b3J0aCB3aGlsZSB0byBhZGQKYSBwYW5lbCBiZWxvdyB0aGUgbGVnZW5kIHdpdGggdGhlIHNhbXBsZSBudW1iZXJzIHBlciBjb25kaXRpb24vYmF0Y2guCgpPZiBjb3Vyc2UsIHRoZSBzYW1lIGluZm9ybWF0aW9uIGlzIHByb3ZpZGVkIGluIGEgbW9yZSBmdW4gZmFzaGlvbiB2aWEKbXkgc2lsbHkgc2Fua2V5IGZ1bmN0aW9uOgoKYGBge3J9CnNhbXBsZV9zYW5rZXkgPC0gcGxvdF9tZXRhX3NhbmtleSh2M19sb2NfZ2VubywgY29sb3JfY2hvaWNlcyA9IGNvbG9yX2Nob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JzID0gYygiZ2Vub3R5cGVfYXRiIiwgImxvY2F0aW9uX2F0YiIsICJ0aW1lX2F0YiIpKQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXMvZGVzaWduX3NhbmtleS5wZGYiLCBpbWFnZSA9IHNhbXBsZV9zYW5rZXlbWyJwbG90Il1dKQpgYGAKCiMgQSBTaG9ydCBjb252ZXJzYXRpb24gd2l0aCBSYXNobWkKClJhc2htaSBjYW1lIGJ5IGFuZCB3ZSBkaXNjdXNzZWQgdGhlIHNhbXBsZXMgYSBsaXR0bGUuICBTaGUgc3VnZ2VzdGVkCnRoYXQgaXMgbGlrZWx5IHRoYXQgd2Ugd2lsbCBuZWVkIHRvIGV4Y2x1ZGUgdGhlIDIwMjIwNSBzYW1wbGVzLCB0aGVzZQptYXkgYmUgaWRlbnRpZmllZCBieSBhIGZldyB3YXlzLCBtb3N0IGVhc2lseSBJIHRoaW5rIHZpYSB0aGUKJ3Byb2plY3RfYWgnIGNvbHVtbiwgdGhleSBhcmUgdGhlIDAyMV8xIHNhbXBsZXMuCgpNeSBzZW5zZSB3YXMgdGhhdCBzaGUgY29uY3VycmVkIHdpdGggbXkgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHVtaQpkZWR1cGxpY2F0aW9uLCBzbyBJIHdpbGwgY29udGludWUgdXNpbmcgdGhlIGRlZHVwbGljYXRlZCByZXN1bHRzCmV4Y2x1c2l2ZWx5LCBhdCBsZWFzdCBmb3Igbm93LgoKIyBNZWxhbm9wc2luIFNhbml0eSBDaGVjawoKT25lIG9mIFRoZXJlc2EncyBmaXJzdCBjaGVja3Mgd2FzIHdpc2VseSBmb3IgbWVsYW5vcHNpbi4gIExldCB1cwpyZXBlYXQgYSB2ZXJzaW9uIG9mIHRoaXM6CgpgYGB7cn0Kb3BuNF9leHBycyA8LSBkYXRhLmZyYW1lKGNvbWJpbmVkID0gY29sRGF0YShsb2NfZ2Vub19udClbWyJnZW5vX2xvY19hdGIiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbiA9IGNvbERhdGEobG9jX2dlbm9fbnQpW1sibG9jYXRpb25fYXRiIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgZ2Vub3R5cGUgPSBjb2xEYXRhKGxvY19nZW5vX250KVtbImdlbm90eXBlX2F0YiJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wbiA9IGFzc2F5KGxvY19nZW5vX250KVsiRU5TTVVTRzAwMDAwMDIxNzk5IiwgXSkKCmdyb3VwZWRzdGF0czo6Z3JvdXBlZF9zdW1tYXJ5KG9wbjRfZXhwcnMsIGxvY2F0aW9uLCBvcG4pCm9wbjRfbG9jYXRpb24gPC0gZ2dzdGF0c3Bsb3Q6OmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gbG9jYXRpb24sIHkgPSBvcG4pCnBwKGZpbGUgPSAiaW1hZ2VzL2dnYmV0d2Vlbl9sb2NhdGlvbi5wZGYiLCBpbWFnZSA9IG9wbjRfbG9jYXRpb24pCm9wbjRfZ2Vub3R5cGUgPC0gZ2dzdGF0c3Bsb3Q6OmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gZ2Vub3R5cGUsIHkgPSBvcG4pCnBwKGZpbGUgPSAiaW1hZ2VzL2dnYmV0d2Vlbl9sb2NhdGlvbi5wZGYiLCBpbWFnZSA9IG9wbjRfZ2Vub3R5cGUpCm9wbjRfY29tYmluZWQgPC0gZ2dzdGF0c3Bsb3Q6OmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gY29tYmluZWQsIHkgPSBvcG4pCnBwKGZpbGUgPSAiaW1hZ2VzL2dnYmV0d2Vlbl9jb21iaW5lZC5wZGYiLCBpbWFnZSA9IG9wbjRfY29tYmluZWQpCmBgYAoKb2ssIHNvIEkgcGxvdHRlZCB0aGUgcXVlc3Rpb24gYSBiaXQgZGlmZmVyZW50bHksIGJ1dCBnb3QgdGhlIHNhbWUKYW5zd2VyLgoKSGVyZSBpcyB0aGUgdGV4dCBvZiBUaGVyZXNhJ3Mgbm90ZWJvb2sgZm9sbG93aW5nIHRoaXMgYW5hbHlzaXM6CgoiVWdoIG9oLCBsb29rcyBsaWtlIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSByZXRpbmEgS08gc2FtcGxlIHRoYXQgaGFzCnNvbWUgbWVsYW5vcHNpbiBleHByZXNzaW9uIGluIGl0LiBUdXJucyBvdXQgaXBSR0NfMDcgaXMgYSBiYWQgZWdnCndoaWNoIGlzIHN1cHBvc2VkIHRvIGJlIGEgS08gYnV0IGhhcyBtZWxhbm9wc2luIGV4cHJlc3Npb24uIEl04oCZcwpmcmllbmRzIHdoaWNoIHdlcmUgcG9vbGVkIGZyb20gdGhlIHNhbWUgbWljZSBhcmUgaXByZ2NfMDYgYW5kCmlwcmdjXzA4LCBzbyB3ZSBuZWVkIHRvIGV4Y2x1ZGUgYWxsIHRoZXNlIHNhbXBsZXMuIgoKSSBhbSBhbHNvIHNlZWluZyBzb21lIGtub2Nrb3V0IGV4cHJlc3Npb24gd2l0aCBzb21lIGNhdmVhdHM6IEkgZG8gbm90CmhhdmUgdGhlIGFmZmVjdGVkIHNhbXBsZXMgaW4gbXkgZGF0YXNldCAoaXByZ2NfMDcpIGFuZCB0aGUgbGV2ZWxzIEkgYW0Kc2VlaW5nIGFyZSBxdWl0ZSBsb3cgLS0gSSB3aWxsIGxvb2sgaW4gSUdWIHRvIGRvdWJsZSBjaGVjaywgYnV0IEkKc3Ryb25nbHkgc3VzcGVjdCB0aGF0IHRoZXNlIGFyZSBzb21lIHBpZGRseSByZWFkcyBuZWFyIHRoZSBVVFJzLgoKT253YXJkIQoKIyBQQ0EgcGxvdHMKCiMjIFBDQSBvZiBhbGwgZ2VuZXMgYnkgbG9jYXRpb24KClRoZXJlc2EncyBmaXJzdCBwY2Egd2FzIG9mIGxvZzIgY3BtIHZhbHVlcy4gIEkgbWlnaHQgYWRkIHF1YW50aWxlL3RtbQp0byB0aGlzPwoKYGBge3J9CnYzX2xvY2F0aW9uIDwtIHNldF9jb25kaXRpb25zKG1tMzhfaGlzYXRfdjMsIGZhY3QgPSAibG9jYXRpb25fYXRiIikgfD4KICBzZXRfYmF0Y2hlcyhmYWN0ID0gImdlbm90eXBlX2F0YiIpIHw+CiAgc2V0X2NvbG9ycyhjb2xvcl9jaG9pY2VzW1sibG9jYXRpb24iXV0pCnYzX2xvY2F0aW9uX25vcm0gPC0gbm9ybWFsaXplKHYzX2xvY2F0aW9uLCBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIikKdjNfbG9jYXRpb25fcGNhIDwtIHBsb3RfcGNhKHYzX2xvY2F0aW9uX25vcm0pCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlcy92M19sb2NhdGlvbl9ub3JtX3BjYS5wZGYiLCBpbWFnZSA9IHYzX2xvY2F0aW9uX3BjYSkKYGBgCgpPbmNlIGFnYWluIHdlIHNlZSB0aGF0IHNhbXBsZXMgaXByZ2NfNjYgYW5kIGlwcmdjXzEzMCBhcmUgbGlrZWx5CmFjdHVhbGx5IERMR04gYW5kIG5vdCBTQ04uICBJIGFtIHRoZXJlZm9yZSBnb2luZyB0byBhZGQgYSBjb2x1bW4gdG8KdGhlIHNhbXBsZSBzaGVldCBub3RpbmcgdGhpcywgYW5kIHJlbW92ZSB0aGVtIGZyb20gdGhlIGV4cHJlc3Npb25zZXQuCgpJIHdpbGwgdGh1cyByZXBsb3QgdGhlIGRhdGEgYWZ0ZXIgcmVtb3ZpbmcgdGhvc2UgdHdvLiAgSWYgd2Ugd2FudCB0bwpzZWUgd2hhdCBpdCBsb29rcyBsaWtlIHdpdGggdGhlIHJlLWF0dHJpYnV0ZWQgbG9jYXRpb25zLCB3ZSBjYW4gZG8gc28uCgpUaGVyZXNhIGhhcyBhIG5pY2UgY2hhbmdlIHRvIHRoZSBQQ0EgcGxvdHRlciBpbiB3aGljaCBzaGUgc2V0cyB0aGUKYWxwaGEgY2hhbm5lbCBhcyBhbiBhZGRpdGlvbmFsIHZpc3VhbCBxdWV1ZSBmb3IgYSBtZXRhZGF0YSBmYWN0b3IuLi4KCmBgYHtyfQptbTM4X2hpc2F0X3YzIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3YzLCBzdWJzZXQ9InNhbXBsZWlkIT0naXByZ2NfMTMwJyIpIHw+CiAgc3Vic2V0X3NlKHN1YnNldD0ic2FtcGxlaWQhPSdpcHJnY182NiciKQp2M19sb2NhdGlvbiA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3YzLCBmYWN0ID0gImxvY2F0aW9uX2F0YiIpIHw+CiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJnZW5vdHlwZV9hdGIiKSB8PgogIHNldF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKQoKdjNfbG9jYXRpb25fbm9ybSA8LSBub3JtYWxpemUodjNfbG9jYXRpb24sIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iKQpmaWx0ZXJlZF9sb2NhdGlvbl9wY2EgPC0gcGxvdF9wY2EodjNfbG9jYXRpb25fbm9ybSkKcHAoZmlsZSA9ICIwMmZpbHRlcmVkX2ltYWdlcy9maWx0ZXJlZF9sb2NhdGlvbl9wY2EucGRmIiwgaW1hZ2UgPSBmaWx0ZXJlZF9sb2NhdGlvbl9wY2EpCgpyZW1vdmVkX3NhbmtleSA8LSBwbG90X21ldGFfc2Fua2V5KHYzX2xvY2F0aW9uLCBjb2xvcl9jaG9pY2VzID0gY29sb3JfY2hvaWNlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JzID0gYygiZ2Vub3R5cGVfYXRiIiwgImxvY2F0aW9uX2F0YiIsICJ0aW1lX2F0YiIpKQpwcChmaWxlID0gIjAyZmlsdGVyZWRfaW1hZ2VzL2ZpbHRlcmVkX3NhbmtleS5wZGYiLCBpbWFnZSA9IHJlbW92ZWRfc2Fua2V5W1sicGxvdCJdXSkKYGBgCgpIZXJlIGlzIFRoZXJlc2EncyB0ZXh0LCByZWNhbGwgb25jZSBhZ2FpbiB0aGF0IEkgZG8gbm90IGhhdmUgc29tZSBvZgp0aGVzZSBvbGRlciBzYW1wbGVzIChpcHJnY182Mik6CgpQQzEgdnMgUEMyIGlkZW50aWZpZXMgcmV0aW5hIHZzIGF4b24gaXMgc3RpbGwgdGhlIG1haW4gY29tcG9uZW50IG9mCnZhcmlhdGlvbi4gV2UgZG8gc2VlIHRob3VnaCB0aGF0IGluIHRoZSBQQzIgZGlyZWN0aW9uLCB3ZSBzZWUgd2l0aCB0aGUKbmV3IHNhbXBsZXMgYWRkZWQsIHdlIGRvbuKAmXQgc2VlIHNlcGFyYXRpb24gYmFzZWQgb24gYXhvbmFsIHRhcmdldHMKKGRMR04gdnMgU0NOKS4gSW4gdGhlIFBDMSB2cyBQQzMgcGxvdCwgd2Ugc2VlIHRoYXQgaXTigJlzIFBDMyB3aGVyZSB3ZQpzdGFydCB0byBzZWUgdmFyaWF0aW9uIGNvcnJlbGF0ZWQgd2l0aCBheG9uYWwgY29tcGFydG1lbnQuIExldOKAmXMgbG9vawphdCBQQzEgdnMgUEMyIGNvbG9yZWQgYnkgYmF0Y2ggKHdoZW4gdGhleSB3ZXJlIHByb2Nlc3NlZC9zZXF1ZW5jZWQpIHRvCnNlZSBpZiB0aGF0IGlzIHdoYXQgaXMgY29udHJpYnV0aW5nIHNvIG11Y2ggdmFyaWF0aW9uIGluIFBDMi4KClNpZGUgbm90ZTogaXBSR0MgNjIgc2VlbXMgbGlrZSBhbiBvZGQgYmFsbC4gVGhpcyBzZWVtcyB0byBtZSBsaWtlIGl0CnNob3VsZCBoYXZlIGJlZW4gYSBkTEdOIFAwOCBzYW1wbGUuIElzIHRoZXJlIGFueSBwb3NzaWJpbGl0eSB0aGlzIGdvdAptaXNsYWJlbGVkIGVhcmx5IG9uPyBJIHdlbnQgYmFjayBhbmQgZG91YmxlIGNoZWNrZWQgdG8gc2VlIGlmIGFsbCBteQpwcm9jZXNzaW5nIGlzIGNvcnJlY3QgYW5kIGl0IGluZGVlZCB3YXMgbGFiZWxlZCBhbiBTQ04gUDE1IGZyb20gdGhlCnRpbWUgSSBnb3QgdGhlIHNhbXBsZXMsIGFuZCBpdCBpcyBpbmRlZWQuCgojIERFCgpJIG5vdyBzd2l0Y2hlZCB0byBUaGVyZXNhJ3MgZG9jdW1lbnQgJ1dPUktJTkdfYXhvblRSQVAuLi4nIGFuZCB3aWxsCnN0YXJ0IHB1bGxpbmcgc2VjdGlvbnMgZnJvbSBpdC4gIEkgYW0gcmVhc29uYWJseSBjZXJ0YWluIEkgaGF2ZQpyZWFzb25hYmx5IHNpbWlsYXIgc2FtcGxlIGRpc3RyaWJ1dGlvbnMsIHNvIEkgcHJlc3VtZSBJIGNhbiBpbnZva2UKc2ltaWxhci9pZGVudGljYWwgY2FsbHMgZm9yIERFU2VxIGFuZCBmcmllbmRzLgoKIyMgcDggcmV0aW5hcwoKSW4gdGhlIGJsb2NrIGltbWVkaWF0ZWx5IGJlZm9yZSB0aGUgREUgYW5hbHlzZXMsIFRoZXJlc2EgY3JlYXRlZCBhCnN1YnNldCBleHByZXNzaW9uc2V0IG9mIG9ubHkgcDA4IHJldGluYXMuICBUaHVzIHRoaXMgaW5pdGlhbCBERSBJCmFzc3VtZSB3aWxsIGJlIHVzZWQgdG8gc3VidHJhY3QgZm9yIHRoZSBTQ04vRExHTiBhbmFseXNlcyB0aGF0IGZvbGxvdy4KKEkgZ3Vlc3MgSSBjb3VsZCByZWFkIGFoZWFkIGFuZCBmaW5kIG91dCwgYnV0IG5vISBJIHdhbnQgdG8gYmUgYQpibGFuayBzbGF0ZSkKClRoZXJlc2EncyBwcmltYXJ5IHdvcmtmbG93IG1ha2VzIGhlYXZ5IHVzZSBvZiBERVNlcTIKKEBsb3ZlTW9kZXJhdGVkRXN0aW1hdGlvbkZvbGQyMDE0KSBhbmQgc3ZhCihAbGVla1NWQVBhY2thZ2VSZW1vdmluZzIwMTIpLiAgSW4gc29tZShtb3N0Pykgb2YgVGhlcmVzYSdzCmludm9jYXRpb25zIG9mIHRoZSBhbGxfcGFpcndpc2UoKSBmdW5jdGlvbiwgc2hlIGV4Y2x1ZGVzIHRoZSBvdGhlcgptZXRob2RzIHRoYXQgaXQgcGVyZm9ybXMuICBJbiB0aGlzIHdvcmtib29rLCBJIGxlZnQgdGhvc2UgbWV0aG9kcyBvbiwKdGh1cyB3ZSBjYW4gZXZhbHVhdGUgdGhlIHJlbGF0aXZlIHBlcmZvcm1hbmNlIERFU2VxMiB2cy4gc29tZSAoYWxsPyBJCm1heSBoYXZlIGRpc2FibGVkIEVCU2VxL2RyZWFtIGJlY2F1c2UgdGhleSB3ZXJlIHRha2luZyB0b28gbG9uZykKb2YgdGhlIGZvbGxvd2luZzoKCiogbGltbWE6IChAcml0Y2hpZUxpbW1hUG93ZXJzRGlmZmVyZW50aWFsMjAxNSkgKGFtb25nIG90aGVyCiAgcmVmZXJlbmNlcykgb3JpZ2luYWxseSB3cml0dGVuIGZvciBtaWNyb2FycmF5cy4KKiBFZGdlUjogKEByb2JpbnNvbkVkZ2VSQmlvY29uZHVjdG9yUGFja2FnZTIwMTApLCB3aGljaCBzaGFyZXMgbWFueQogIGFzc3VtcHRpb25zIHdpdGggREVTZXEyLgoqIEVCU2VxOiAoQGxlbmdFQlNlcUVtcGlyaWNhbEJheWVzMjAxMyksIGJlY2F1c2UgSSBoYXZlIGEgc29mdCBzcG90CiAgZm9yIGFueSBCYXllc2lhbiBtZXRob2QuCiogTm9pc2VxOiAoQHRhcmF6b25hTk9Jc2VxUk5Bc2VxRGlmZmVyZW50aWFsMjAxMSksIHdoaWNoIHNlZWtzIHRvCiAgZGlyZWN0bHkgbW9kZWwgdmFyaWFuY2UgaW4gYW4gUk5BU2VxIGRhdGFzZXQgYW5kIHVzZSB0aGF0IHRvIGltcHJvdmUKICB0aGUgc2Vuc2l0aXZpdHkgb2YgdGhlIHJlc3VsdCwgbXVjaCBsaWtlOgoqIERyZWFtOiAoQGhvZmZtYW5EcmVhbVBvd2VyZnVsRGlmZmVyZW50aWFsMjAyMCksIHdyaXR0ZW4gYnkgdGhlIHNhbWUKICBhdXRob3JzIChhbmQgdXNlcyB2ZXJ5IHNpbWlsYXIgbG9naWMpIGFzIG9uZSBvZiBteSBmYXZvcml0ZSB0b29scywKICB2YXJpYW5jZVBhcnRpdGlvbihAaG9mZm1hblZhcmlhbmNlUGFydGl0aW9uSW50ZXJwcmV0aW5nRHJpdmVyczIwMTYpLgoKYGBge3J9Cm1tMzhfcDhfcmV0aW5hIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3YzLCBzdWJzZXQgPSAidGltZV9hdGI9PSdwMDgnICYgbG9jYXRpb25fYXRiPT0ncmV0aW5hJyIpCm1tX25vcm1hbF9wOF9yZXRfZGUgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfcDhfcmV0aW5hLCBtb2RlbF9zdnMgPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLCBmaWx0ZXIgPSBUUlVFKQptbV9ub3JtYWxfcDhfcmV0X2RlCmBgYAoKVGhlcmUgc2VlbXMgdG8gYmUgYSBkaXNjcmVwZW5jeSB3aXRoIHByZXZpb3VzIGl0ZXJhdGlvbnMgb2YgdGhpcy4KTGV0IHVzIHNpbXBsaWZ5IHRvIGp1c3QgZG9pbmcgZGVzZXEgYW5kIGZpbmQgd2hhdCBpcyBjYXVzaW5nIGl0LgpJbiBteSBwcmV2aW91cyBpdGVyYXRpb24sIEkgZ290IDM2MzIgZ2VuZXMgaW4gdGhlIHVuaXF1ZShjKCkpIG9yIGhldCtrby4KCmBgYHtyfQpkZXNlcV9vbmx5IDwtIGRlc2VxX3BhaXJ3aXNlKG1tMzhfcDhfcmV0aW5hLCBtb2RlbF9zdnMgPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gZGVmYXVsdF9mc3RyaW5nLCBmaWx0ZXIgPSBUUlVFKQpkZXNlcV9oZXRrZWVwZXJfZ2VuZXMgPC0gZGVzZXFfb25seSRhbGxfdGFibGVzJHd0X3JldGluYV92c19oZXRfcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCmRlc2VxX2tva2VlcGVyX2dlbmVzIDwtIGRlc2VxX29ubHkkYWxsX3RhYmxlcyR3dF9yZXRpbmFfdnNfa29fcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCmRlc2VxX2tlZXBlcmdlbmVzIDwtIHVuaXF1ZShjKHJvd25hbWVzKGRlc2VxX2hldGtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKGRlc2VxX2tva2VlcGVyX2dlbmVzKSkpCmxlbmd0aChkZXNlcV9rZWVwZXJnZW5lcykKCmRlc2VxX3BhaXJfaGV0a2VlcGVyX2dlbmVzIDwtIG1tX25vcm1hbF9wOF9yZXRfZGUkZGVzZXEkYWxsX3RhYmxlcyR3dF9yZXRpbmFfdnNfaGV0X3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4yNSAmIGFkai5QLlZhbCA8PSAwLjA1KQpkZXNlcV9wYWlyX2tva2VlcGVyX2dlbmVzIDwtIG1tX25vcm1hbF9wOF9yZXRfZGUkZGVzZXEkYWxsX3RhYmxlcyR3dF9yZXRpbmFfdnNfa29fcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCmRlc2VxX3BhaXJfa2VlcGVyZ2VuZXMgPC0gdW5pcXVlKGMocm93bmFtZXMoZGVzZXFfcGFpcl9oZXRrZWVwZXJfZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhkZXNlcV9wYWlyX2tva2VlcGVyX2dlbmVzKSkpCmxlbmd0aChkZXNlcV9wYWlyX2tlZXBlcmdlbmVzKQpgYGAKClRoZSBmb2xsb3dpbmcgaW52b2NhdGlvbiBwZXJmb3JtZWQgYnkgVGhlcmVzYSBmaWx0ZXJzIHRoZSB3dC9oZXQKY29tcGFyaXNvbiBmb3Igb25seSB0aG9zZSBnZW5lcyB3aGljaCBpbmNyZWFzZWQgYnkgYXQgbGVhc3QgMC4yNSBsb2dGQwp3aXRoIGEgc2lnbmlmaWNhbnQgYWRqdXN0ZWQgcC12YWx1ZS4gIEkgYXNzdW1lIHRoYXQgdGhpcyBpcyB0byB1c2UgdGhlCnd0IHNhbXBsZXMgYXMgYSB0cmFuc2xhdGlvbmFsIGNvbnRyb2wgZm9yIHRoZSBrZXQva28gY29tcGFyaXNvbnM7IEkgYW0KdGhlcmVmb3JlIHRoaW5raW5nIHRoYXQgZm9yIG15IHB1cnBvc2VzLCBJIHdpbGwgdGhlcmVmb3JlIHNlcGFyYXRlIHRoZQpjb250cmFzdHMgZnJvbSBhbGxfcGFpcndpc2UgZG8gdGhpcyBpbiBhIHN0ZXB3aXNlIGZhc2hpb24uLi4KClRoZSBibG9jayBvZiBjb2RlIGltbWVkaWF0ZWx5IGZvbGxvd2luZyBUaGVyZXNhJ3MgYWxsX3BhaXJ3aXNlKCkKaW52b2NhdGlvbiBpcyBhIGxpdHRsZSBjb25mdXNpbmcgZm9yIG1lIGFuZCB3YXJyYW50cyBzb21lIGV4cGxhbmF0aW9uCmJ5IG1lIHRvIG1lIGluIHRoZSBob3BlcyB0aGF0IEkgZG8gbm90IG1pc3VuZGVyc3RhbmQgd2hhdCBpcyBoYXBwZW5pbmcKYW5kIHRoZSBnb2FscyB0aGVyZWluLgoKSSB0aGluayBJIGNhbiBzYWZlbHkgYXNzdW1lIHRoYXQgdGhlIGdvYWwgaGVyZSBpcyB0byBwdWxsIG91dCB0aGUgSURzCndoaWNoIGluY3JlYXNlZCBpbiBoZXQgd2l0aCByZXNwZWN0IHRvIHdpbGQgdHlwZTsgZXZlbiBpZiBieSBhIHNtYWxsCm1hcmdpbiwgYXMgbG9uZyBhcyBpdCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHZpcyBhIHZpcyB0aGUKYWRqdXN0ZWQgcC12YWx1ZS4KCkkgYW0gZ29pbmcgdG8gcGVyZm9ybSB3aGF0IEkgdGhpbmsgaXMgdGhlIHNhbWUgdGhpbmcgaW4gYSBzbGlnaHRseQpkaWZmZXJlbnQgZmFzaGlvbiBzbyB0aGF0IEkgY2FuIHNoYXJlIGEgY29weSBvZiB0aGUgcmVzdWx0cyB3aXRoCndob21ldmVyIGlzIGludGVyZXN0ZWQuICBJIHdpbGwgYWxzbyByZXBlYXQgVGhlcmVzYSdzIGludm9jYXRpb24gYW5kCnByb3ZlIHRvIG15c2VsZiB0aGF0IEkgdW5kZXJzdG9vZCBhbmQgZ290IHRoZSBzYW1lIGFuc3dlci4KCmBgYHtyfQp3dF9oZXRfa2VlcGVyIDwtIGxpc3QoImhldF92c193dCIgPSBjKCJoZXRfcmV0aW5hIiwgInd0X3JldGluYSIpKQpoZXRfd3RfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgbW1fbm9ybWFsX3A4X3JldF9kZSwga2VlcGVycyA9IHd0X2hldF9rZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbC9oZXRfcmV0aW5hX2NvbnRyb2wueGxzeCIpCmhldF93dF90YWJsZQoKd2FudGVkX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGhldF93dF90YWJsZSwgbGZjID0gMC4yNSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbC9oZXRfcmV0aW5hX2NvbnRyb2wtc2lnLnhsc3giKQp3YW50ZWRfc2lnCgp3YW50ZWRfaGV0X2luY3JlYXNlZCA8LSB3YW50ZWRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJoZXRfdnNfd3QiXV0KaW5jcmVhc2VkX2hldF9nZW5lcyA8LSByb3duYW1lcyh3YW50ZWRfaGV0X2luY3JlYXNlZCkKYGBgCgpIZXJlIGFyZSBUaGVyZXNhJ3MgbmV4dCBsaW5lczoKCmBgYHtyfQptbV9kZV9ub3JtYWxfcDhfcmV0IDwtIG1tX25vcm1hbF9wOF9yZXRfZGUKaGV0a2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyR3dF9yZXRpbmFfdnNfaGV0X3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4yNSAmIGFkai5QLlZhbCA8PSAwLjA1KQprb2tlZXBlcl9nZW5lcyA8LSBtbV9kZV9ub3JtYWxfcDhfcmV0JGRlc2VxJGFsbF90YWJsZXMkd3RfcmV0aW5hX3ZzX2tvX3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4yNSAmIGFkai5QLlZhbCA8PSAwLjA1KQprZWVwZXJnZW5lcyA8LSB1bmlxdWUoYyhyb3duYW1lcyhoZXRrZWVwZXJfZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhrb2tlZXBlcl9nZW5lcykpKQojIyBXZSBrbm93IGEgcHJpb3JpIHRoYXQgT3BuNCBpcyBFTlNNVVNHMDAwMDAwMjE3OTkKIyMgSSBkbyBub3QgZXhwZWN0IHRvIHNlZSBpdCBpbiB0aGlzIHNldCwgaXQgc2hvdWxkIGJlIGhpZ2hlciBpbiB3dAojIyByZXRpbmEgdnMga28gcmV0aW5hIGJ5IGEgc2lnbmlmaWNhbnQgbWFyZ2luLgoiRU5TTVVTRzAwMDAwMDIxNzk5IiAlaW4lIGtlZXBlcmdlbmVzCiMjIE9vb29oaGggYnV0IGl0IF9pc18gaGlnaGVyIGluIGhldCB2cy4gd3QsIGFzIHdlIHNhdyBpbgojIyB0aGUgdmlvbGluIHBsb3QgZWFybGllci4KYGBgCgpJIHRoaW5rIFJhc2htaSBtYWRlIGEgY29tcGVsbGluZyBwb2ludCB3aGljaCBpbGx1c3RyYXRlcyB3aHkgd2UgbGlrZWx5CnNob3VsZCBleHBlY3QgdGhlIGV4cHJlc3Npb24gb2YgT3BuNCB0byBzaWduaWZpY2FudGx5IGhpZ2hlciBpbiB0aGUKaGV0ZXJvenlnb3RlcyB2cyB3aWxkLXR5cGU6CgoxLiAgUmVjYWxsIHRoYXQgdGhlIGFzc2F5IGlzIHVzaW5nIHRoZSBpbW11bm9wdXJpZmljYXRpb24gdG8gZXh0cmFjdAogICAgdGhlIFJOQXMuCjIuICBUaGUgd3Qgc2FtcGxlcyBkbyBub3QgaGF2ZSB0aGUgY3JlIHJlY29tYmluYXNlIGFuZCB0aGVyZWZvcmUgbm8gSEEKICAgIGFuZCB0aGVyZWZvcmUgZXZlcnl0aGluZyB3ZSBvYnNlcnZlIGlzIGR1ZSB0byBub24tc3BlY2lmaWMKICAgIGJpbmRpbmcuCjMuICBUaGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGR1ZSB0byBub24tc3BlY2lmaWMgYmluZGluZyBpcyBkaWZmZXJlbnQKICAgIHRoYW4gaGV0L2tvIChwcmVzdW1hYmx5IGEgbGFyZ2VyIG51bWJlciBvZiByZWxhdGl2ZWx5IHNtYWxsCiAgICB2YWx1ZXMpLCB0aGVyZWZvcmUgdGhlIGRpdmlzb3IgcGVyZm9ybWVkIGluIHRoZSBjcG0gaXMgbGlrZWx5CiAgICByZWxhdGl2bHkgbGFyZ2UgcmVzdWx0aW5nIGluIG5vcm1hbGl6ZWQgdmFsdWVzIGdldHRpbmcgc2hpZnRlZAogICAgZG93biB0byBzb21lIGRlZ3JlZS4KNC4gIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGluIGhldC9rbyBhcmUgbW9yZQogICAgbGlrZWx5IHRvIGJlIG9ubHkgdGhlIHNwZWNpZmljIGJpbmRlcnMgYW5kIHRoZXJlZm9yZSBzbWFsbGVyIChJCiAgICBjYW4gdGVzdCB0aGlzKSByZXN1bHRpbmcgaW4gYSBzbWFsbGVyIGRpdmlzb3IgYW5kIHNsaWdodCBzaGlmdGluZwogICAgdXAgaW4gdGhlIGNwbSB2YWx1ZXMuCgpUaGlzIG1ha2VzIG1lIHdvbmRlciBpZiBhbnkgbm9ybWFsaXphdGlvbiBtZXRob2RzIGV4aXN0IHdoaWNoIGRvCnNvbWV0aGluZyBsaWtlIG11bHRpcGx5IHRoZSB2YWx1ZXMgYnkgc29tZSB2YWx1ZSByZWxhdGVkIHRvIHRoZQpwcm9wb3J0aW9uIG9mIG9ic2VydmVkIGdlbmVzOyBhbmQvb3IgaWYgdGhpcyBpcyBhIGdvb2QvYmFkL2luZGlmZmVyZW50CmlkZWEuCgpBbHNvLCBqdXN0IGEgbm90ZSBmb3IgbWUgdG8gcmVtZW1iZXI6IFJQTDIyLCBub3QgUlBTMjIsIGZvciBzb21lCnJlYXNvbiBJIGtlZXAgdGhpbmtpbmcgdGhlIHNtYWxsIHN1YnVuaXQuCgojIyBQcm92ZSBJIHVuZGVyc3Rvb2QKCmBgYHtyfQpoZXRrZWVwZXJfZ2VuZXMgPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0X3JldGluYV92c19oZXRfcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCnRlc3R0aGF0OjpleHBlY3RfdHJ1ZShucm93KGhldGtlZXBlcl9nZW5lcykgPT0gbGVuZ3RoKGluY3JlYXNlZF9oZXRfZ2VuZXMpKQp0YWFfa2VlcGVycyA8LSBzb3J0KHJvd25hbWVzKGhldGtlZXBlcl9nZW5lcykpCmF0Yl9rZWVwZXJzIDwtIHNvcnQoaW5jcmVhc2VkX2hldF9nZW5lcykKdGVzdHRoYXQ6OmV4cGVjdF9lcXVhbCh0YWFfa2VlcGVycywgYXRiX2tlZXBlcnMpCmBgYAoKWWF5ISBJIGNhbiByZWFkISAgTm93IGxldCB1cyByZXBlYXQgZm9yIHRoZSBLTyB2cyB3dAoKYGBge3J9Cnd0X2tvX2tlZXBlciA8LSBsaXN0KCJrb192c193dCIgPSBjKCJrb19yZXRpbmEiLCAid3RfcmV0aW5hIikpCmtvX3d0X3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX25vcm1hbF9wOF9yZXRfZGUsIGtlZXBlcnMgPSB3dF9rb19rZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbC9rb19yZXRpbmFfY29udHJvbC54bHN4IikKa29fd3RfdGFibGUKCndhbnRlZF9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBrb193dF90YWJsZSwgbGZjID0gMC4yNSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbC9rb19yZXRpbmFfY29udHJvbC1zaWcueGxzeCIpCndhbnRlZF9zaWcKCndhbnRlZF9rb19pbmNyZWFzZWQgPC0gd2FudGVkX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sia29fdnNfd3QiXV0KaW5jcmVhc2VkX2tvX2dlbmVzIDwtIHJvd25hbWVzKHdhbnRlZF9rb19pbmNyZWFzZWQpCmxlbmd0aChpbmNyZWFzZWRfa29fZ2VuZXMpCmBgYAoKVGhlIG5leHQgdGhpbmcgcGVyZm9ybWVkIGluIFRoZXJlc2EncyBkb2N1bWVudCBpcyBhIHVuaXF1ZShjb25jYXRlbmF0aW9uIG9mCnRoZXNlIHR3byBnZW5lIGdyb3VwcyksIHRodXMgc3Vja2luZyB1cCBldmVyeSBnZW5lIHdoaWNoIHdhcwpzaWduaWZpY2FudGx5IGhpZ2hlciBpbiBlaXRoZXIgdGhlIGtub2Nrb3V0IF9vcl8gaGV0ZXJ6eW91cyBzYW1wbGVzCndpdGggcmVzcGVjdCB0byB3aWxkLXR5cGUuCgpUaGlzIHdhcyBmb2xsb3dlZCBieSBhIGNvdXBsZSBvZiBtZXJnZSBvcGVyYXRpb25zIG9mIGEgbGl0dGxlIGJpdCBvZgp0aGUgYW5ub3RhdGlvbiBkYXRhOyBJIGFtIG5vdCBzdXJlIEkgdW5kZXJzdGFuZCB0aGUgZ29hbCB5ZXQuLi4KCkhlcmUgaXMgaGVyIGNvZGUuIEkgY29waWVkIHRoZSBhbm5vdGF0aW9uICdtZ2lfc3ltYm9sJyBjb2x1bW4gdG8KJ2V4dGVybmFsX3N5bm9ueW0nIHNvIHRoYXQgSSBuZWVkIG5vdCBjaGFuZ2UgYW55IG9mIGhlciBjb2RlLiAgSSBhbQphc3N1bWluZyB0aGlzIGlzIHRoZSBhcHByb3ByaWF0ZSBjb2x1bW4gb2YgaW50ZXJlc3QsIEkgZG8gbm90IGtub3cKdGhpcyBmb3IgY2VydGFpbiwgYnV0IGl0IHNlZW1zIHF1aXRlIGxpa2VseS4KCldoaWxlIEkgYW0gYXQgaXQsIGhlcmUgaXMgdGhlIHNldF9zaWdfbGltbWEoKSBmdW5jdGlvbiBmcm9tIFRoZXJlc2EncyBoZWxwZXJzLlIKCmBgYHtyfQpzZXRfc2lnX2xpbW1hIDwtIGZ1bmN0aW9uKGxpbW1hX3RibCwgZmFjdG9ycyA9IE5VTEwpIHsKICBpZiAoaXMubnVsbChmYWN0b3JzKSkgewogICAgI3NldCBzaWduaWZpY2FuY2UgZm9yIHBsb3R0aW5nIGNvbG9ycwogICAgbGltbWFfdGJsJFNpZ25pZmljYW5jZSA8LSBOQQogICAgbGltbWFfdGJsW2FicyhsaW1tYV90YmwkbG9nRkMpIDw9IDEuMCB8IGxpbW1hX3RibCRhZGouUC5WYWwgPiAwLjA1LCAiU2lnbmlmaWNhbmNlIl0gPC0gIk5vdCBcbkVucmljaGVkIgogICAgbGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA+PSAxLjAgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuVXByZWd1bGF0ZWQiCiAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDIDw9IC0xLjAgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuRG93bnJlZ3VsYXRlZCIKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gZmFjdG9yKGxpbW1hX3RibCRTaWduaWZpY2FuY2UsIGxldmVscyA9IGMoIlVwcmVndWxhdGVkIiwgIkRvd25yZWd1bGF0ZWQiLCAgIk5vdCBcbkVucmljaGVkIikpCiAgfSBlbHNlIHsKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gTkEKICAgIGxpbW1hX3RibFthYnMobGltbWFfdGJsJGxvZ0ZDKSA8PSAxLjAgfCBsaW1tYV90YmwkYWRqLlAuVmFsID49IDAuMDUsICJTaWduaWZpY2FuY2UiXSA8LSAiTm90IFxuRW5yaWNoZWQiCiAgICBpZihucm93KGxpbW1hX3RibFtsaW1tYV90YmwkbG9nRkMgPj0gMS4wICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gMC4wNSwgXSkgIT0gMCkgewogICAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDID49IDEuMCAgJiBsaW1tYV90YmwkYWRqLlAuVmFsIDw9IDAuMDUsIF1bWyJTaWduaWZpY2FuY2UiXV0gPC0gZmFjdG9yc1sxXQogICAgfQogICAgaWYgKG5yb3cobGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA8PSAtMS4wICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gMC4wNSwgXSkgIT0gMCkgewogICAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDIDw9IC0xLjAgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtIGZhY3RvcnNbMl0KICAgIH0KICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gZmFjdG9yKGxpbW1hX3RibCRTaWduaWZpY2FuY2UsIGxldmVscyA9IGMoZmFjdG9ycywgICJOb3QgXG5FbnJpY2hlZCIpKQogIH0KICByZXR1cm4obGltbWFfdGJsKQp9CmBgYAoKIyMjIENvbWJpbmluZyBoZXQvd3QgYW5kIGtvL3d0CgpgYGB7cn0Ka2VlcGVyZ2VuZXMgPC0gdW5pcXVlKGMocm93bmFtZXMoaGV0a2VlcGVyX2dlbmVzKSwgcm93bmFtZXMoa29rZWVwZXJfZ2VuZXMpKSkKbGVuZ3RoKGtlZXBlcmdlbmVzKQoKYW5ub3RzX3RvX21lcmdlIDwtIG1tX2Fubm90X2dlbmVzIHw+CiAgZHBseXI6OnNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGVuc2VtYmxfdHJhbnNjcmlwdF9pZCwgc3ltYm9sKSB8PgogIGZpbHRlcihlbnNlbWJsX2dlbmVfaWQgJWluJQogICAgICAgICAgIHJvd25hbWVzKG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyRrb19yZXRpbmFfdnNfaGV0X3JldGluYSkpIHw+CiAgZGlzdGluY3QoKQptbV9kZV9ub3JtYWxfcDhfcmV0JGRlc2VxJGFsbF90YWJsZXMka29fcmV0aW5hX3ZzX2hldF9yZXRpbmEgPC0gbWVyZ2UoCiAgbW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvX3JldGluYV92c19oZXRfcmV0aW5hLCBhbm5vdHNfdG9fbWVyZ2UsCiAgYnkueCA9ICJyb3cubmFtZXMiLCBieS55ID0gImVuc2VtYmxfZ2VuZV9pZCIsIGFsbC54ID0gVFJVRSkKZGYgPC0gbW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvX3JldGluYV92c19oZXRfcmV0aW5hIHw+CiAgZHBseXI6Om11dGF0ZShsb2dGQyA9IC1sb2dGQykgfD4KICBzZXRfc2lnX2xpbW1hKGZhY3RvcnMgPSBjKCJIZXQgRW5yaWNoZWQiLCAiS08gRW5yaWNoZWQiKSkKcm93bmFtZXMoZGYpIDwtIGRmW1siUm93Lm5hbWVzIl1dCmRmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKYGBgCgpNeSB2ZXJzaW9uIG9mIHRoZSBhYm92ZSB0YXNrIG1ha2VzIHVzZSBvZiB0aGUgZXhjbHVkZXMgb3B0aW9uIG9mCmNvbWJpbmVfZGVfdGFiZXMuICBHaXZlbiB0aGUgc2V0IG9mIHVuaXF1ZSBnZW5lIElEcyBpbmNyZWFzZWQgaW4gdGhlCmhldC9rbywgSSBjYW4gYXNrIHRvIGV4bHVkZSBhbnl0aGluZyBub3QgaW4gdGhhdCBzZXQuICBJIGNvdWxkIGFsc28KaGF2ZSBtb3JlIHBhcnNpbW9uaW91c2x5IGRpcmVjdGx5IGV4Y2x1ZGVkIGFueSBnZW5lIElEIGluY3JlYXNlZCBpbgp0aGUgd3Qgc2FtcGxlcy4gIEJ1dCwgVGhlcmVzYSBhbHJlYWR5IHByb3ZpZGVkIHRoZSBjb2RlIHRvIGRvIHRoZQpmb3JtZXIsIHNvIGl0IHdpbGwgYmUgbGVzcyB0eXBpbmcvb3Bwb3J0dW5pdHkgZm9yIHNpbGx5IG1pc3Rha2VzIHRvCmp1c3QgZG8gdGhhdC4KCmBgYHtyfQpib3RoX2luY3JlYXNlZF9nZW5lcyA8LSB1bmlxdWUoYyhpbmNyZWFzZWRfaGV0X2dlbmVzLCBpbmNyZWFzZWRfa29fZ2VuZXMpKQojIyBhcmJpdHJhaXJseSBncmFiIGFsbCBnZW5lcyBmcm9tIG9uZSBvZiBteSBkYXRhIHN0cnVjdHVyZXMuCmFsbF9nZW5lcyA8LSByb3duYW1lcyhleHBycyhtbTM4X2hpc2F0X3YzKSkKZXhjbHVkZV9pZHggPC0gYWxsX2dlbmVzICVpbiUgYm90aF9pbmNyZWFzZWRfZ2VuZXMKc3VtbWFyeShleGNsdWRlX2lkeCkKYGBgCgpNeSBBcHJpbCAyMDI1IHZlcnNpb24gb2YgdGhpcyBzaG93cyAyMSw3OTMgYW5kIDMsNjMyIGdlbmVzIGluIHRoaXMKc2V0LiAgSXMgdGhhdCBzdGlsbCB0cnVlPyAgKEFzIG9mIDIwMjYwMzExLCBpdCBpcyEpCgpgYGB7cn0KZXhjbHVkZV9pbmNyZWFzZWRfZ2VuZXMgPC0gYWxsX2dlbmVzW2V4Y2x1ZGVfaWR4XQpyZXRpbmFfa2VlcGVycyA8LSBsaXN0KAogICJoZXRfdnNfd3QiID0gYygiaGV0X3JldGluYSIsICJ3dF9yZXRpbmEiKSwKICAia29fdnNfd3QiID0gYygia29fcmV0aW5hIiwgInd0X3JldGluYSIpLAogICJrb192c19oZXQiID0gYygia29fcmV0aW5hIiwgImhldF9yZXRpbmEiKSkKIyMgQSByZW1pbmRlciB0byBteXNlbGY6IHRoZXJlIGlzIGFsc28gYSBwYXJhbWV0ZXIgJ3dhbnRlZF9nZW5lcycKIyMgd2hpY2ggZG9lcyBlZmZlY3RpdmVseSB0aGUgc2FtZSB0aGluZyBhcyBleGNsdWRlcyBpbiB0aGlzIGNvbnRleHQ7CiMjIGV4Y2x1ZGVzIHdhcyBvcmlnaW5hbGx5IHdyaXR0ZW4gdG8gYWxsb3cgZmxleGlibGUsIGtleXdvcmQtYmFzZWQKIyMgZXhjbHVzaW9uLgpwOF9yZXRpbmFfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX25vcm1hbF9wOF9yZXRfZGUsIGtlZXBlcnMgPSByZXRpbmFfa2VlcGVycywKICB3YW50ZWRfZ2VuZXMgPSBib3RoX2luY3JlYXNlZF9nZW5lcywgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMDN0aGVyZXNhX2NvbXBhcmlzb25fZXhjZWwvcDhfcmV0aW5hX2tlcHRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpwOF9yZXRpbmFfdGFibGVzCgpwOF9yZXRpbmFfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgcDhfcmV0aW5hX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoIjAzdGhlcmVzYV9jb21wYXJpc29uX2V4Y2VsL3A4X3JldGluYV9rZXB0X2dlbmVzX2luY3JlYXNlZF9pbl93dF9zaWctdnt2ZXJ9Lnhsc3giKSkKcDhfcmV0aW5hX3NpZwoKb3Bwb3NpdGVfcDhfcmV0aW5hX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gcmV0aW5hX2tlZXBlcnMsCiAgZXhjbHVkZXMgPSBib3RoX2luY3JlYXNlZF9nZW5lcywgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMDN0aGVyZXNhX2NvbXBhcmlzb25fZXhjZWwvcDhfcmV0aW5hX3JlbW92ZWRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpvcHBvc2l0ZV9wOF9yZXRpbmFfdGFibGVzCgpvcHBvc2l0ZV9wOF9yZXRpbmFfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgcDhfcmV0aW5hX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoIjAzdGhlcmVzYV9jb21wYXJpc29uX2V4Y2VsL3A4X3JldGluYV9yZW1vdmVkX2dlbmVzX2luY3JlYXNlZF9pbl93dF9zaWctdnt2ZXJ9Lnhsc3giKSkKb3Bwb3NpdGVfcDhfcmV0aW5hX3NpZwpgYGAKCiMgU0NOIEhldCB2cyBLTwoKSXQgaXMgb25seSBub3cgdGhhdCBJIHJlYWxpemVkIHdlIGFyZSBzcGxpdHRpbmcgdGhlIGRhdGEgYnkgbG9jYXRpb24KZm9yIGVhY2ggc2V0IG9mIGNvbXBhcmlzb25zLiAgSSB0aGluayB0aGF0LCBsZWZ0IHRvIG15IG93biBkZXZpY2VzLCBJCndvdWxkIHByZWZlciB0byBrZWVwIHRoZSBpbnB1dCBkYXRhIHN0cnVjdHVyZSBpbnRhY3QsIHBlcmZvcm0gdGhlCnNvbWV3aGF0IGxhcmdlciBudW1iZXIgb2YgY29udHJhc3RzLCBhbmQgdGhlbiBzcGxpdCB1cCB0aGUgcmVzdWx0cy4KSWRlYWxseSB0aGlzIHdpbGwgc2xpZ2h0bHkgaW1wcm92ZSB0aGUgZmlkZWxpdHkgb2YgdGhlIHJlc3VsdHMKcmV0dXJuZWQgYnkgREVTZXEyIGFuZCBmcmllbmRzLiAgQnV0LCBJIHdpbGwgcnVuIHRoZSBzdGF0ZSBvZgpUaGVyZXNhJ3Mgbm90ZWJvb2sgd2l0aCBhcyBmZXcgY2hhbmdlcyBhcyBwb3NzaWJsZSBmaXJzdCwgdGhlbiBhZGQKdGhpcy4KCiMjIFBDQQoKSSBhbSBnb2luZyB0byBza2lwIHRoaXMgUENBIHBsb3QgZm9yIGEgY291cGxlIG9mIHJlYXNvbnM6IEkgYWxyZWFkeQpkaWQgYSBzdXBlcnNldCBvZiBpdCwgYW5kIHRoZSBzdWJzZXQgVGhlcmVzYSBwZXJmb3JtZWQgaXMgbm90IHZhbGlkCmdpdmVuIHRoZSBzZXQgb2Ygc2FtcGxlcyBpbmNsdWRlZCBpbiBteSBzYW1wbGUgc2hlZXQsIGFuZCBmaWd1cmluZyBvdXQKdGhlIGFjdHVhbGx5IGNvcnJlc3BvbmRpbmcgc3Vic2V0IHdpbGwgdGFrZSBtZSBmb3JldmVyLi4uICBJbgphZGRpdGlvbiwgSSB3YW50IHRvIHVzZSBteSBtbTM4X2hpc2F0X3YzIGZvciBldmVyeXRoaW5nLi4uCgpgYGB7ciwgZXZhbD1GQUxTRX0KbW0zOF9zdWJzZXQgPC0gc3Vic2V0X3NlKAogIG1tMzhfaGlzYXQsCiAgc3Vic2V0ID0gIihiYXRjaCA9PSAnNCcgfCBiYXRjaCA9PSAnNScgfCBiYXRjaCA9PSAnNicpICYgdGltZSA9PSAncDA4JyAmIGxvY2F0aW9uID09ICdzY24nIHwgc2FtcGxlaWQgPT0gJ2lwcmdjXzAzJyIpCm1tMzhfbm9ybSA8LSBub3JtYWxpemUobW0zOF9zdWJzZXQsIGZpbHRlciA9IFRSVUUsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKbW0zOF9ub3JtIDwtIHNldF9iYXRjaGVzKG1tMzhfbm9ybSwgZmFjdCA9ICJsb2NhdGlvbiIpCm1tMzhfbm9ybSA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X25vcm0sIGZhY3QgPSAiZ2Vub3R5cGUiKQpwY2Ffbm9ybSA8LSBwbG90X3BjYShtbTM4X25vcm0sIG1heF9vdmVybGFwcyA9IDcwKQpwY2Ffbm9ybSRwbG90CmBgYAoKSW5zdGVhZCBJIHdpbGwgc2ltcGxpZnkgdGhlIHN1YnNldCBhbmQgc2VlIHdoYXQgaGFwcGVucy4uLgoKYGBge3J9CnNjbl9zYW1wbGVzIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3YzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQgPSAibG9jYXRpb25fYXRiID09ICdzY24nIikgfD4KICBzZXRfYmF0Y2hlcyhmYWN0ID0gImxvY2F0aW9uX2F0YiIpIHw+CiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vdHlwZV9hdGIiLCBjb2xvcnMgPSBjb2xvcl9jaG9pY2VzW1siZ2Vub3R5cGUiXV0pCnNjbl9ub3JtIDwtIG5vcm1hbGl6ZShzY25fc2FtcGxlcywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCnNjbl9ub3JtX3BjYSA8LSBwbG90X3BjYShzY25fbm9ybSkKc2NuX25vcm1fcGNhCmBgYAoKIyBGaWx0ZXJpbmcgb3V0IG5vbi1zcGVjaWZpYyBnZW5lcyBhbmQgZXhhbWluaW5nIHRoZSByZXN1bHRzCgpUaGUgZm9sbG93aW5nIGlzIGEgY29weS9wYXN0ZSBmcm9tIFRoZXJlc2EgY29udGFpbmluZyB0aGUgcmVtYWluaW5nCnRhc2tzIHNoZSBwZXJmb3JtZWQgYW5kIHdpbGwgcHJvdmlkZSB0aGUgdGVtcGxhdGUgZm9yIGltcGxlbWVudGF0aW9uCm9mIHRoZSBmaW5hbCB0YXNrcy4KClRoaXMgcGlja3MgdXAgd2l0aCB0aGUgbGluZXMgZnJvbSBoZXIgbm90ZWJvb2sgaW1tZWRpYXRlbHkgZm9sbG93aW5nCnRoZSBpbnZvY2F0aW9uIG9mICdzZXRfc2lnX2xpbW1hKGZhY3RvcnMgPSBjKCJIZXQgRW5yaWNoZWQiIC4uLicuCgpGb3IgYWxsIG9mIHRoZSByZW1haW5pbmcgYmxvY2tzIEkgd2lsbCBjb3B5IGluIGhlciBjb2RlLCB0dXJuIG9mZiBpdHMKZXZhbHVhdGlvbiwgcnVuIHRoZSBibG9ja3MgbWFudWFsbHksIGNvbXBhcmUgdGhlbSB0byBoZXIgbm90ZWJvb2sKb3V0cHV0LCB0aGVuIGVuYWJsZSBlYWNoIGJsb2NrIGFzIEkgZW5zdXJlIEkgdW5kZXJzdGFuZCBpdC4KCkkgd2lsbCBsaWtlbHkgdGhlcmVmb3JlIGludHJvZHVjZSBzb21lIHNtYWxsIGZvcm1hdHRpbmcgY2hhbmdlcyBhbmQKYWRkIHNvbWUgYWRkaXRpb25hbCBHU0VBL2VucmljaG1lbnQgdGFza3Mgb25jZSB0aGUgbm9uLXNwZWNpZmljCmZpbHRlcmluZyBpcyBjb21wbGV0ZS4KCiMjIEltcG9ydGFudCAyMDI2MDggbm90ZQoKSU15IHByb2JsZW1zIHdpdGggZW5zZW1ibCBoYXZlIHJlc3VsdGVkIGluIG1lIGxvYWRpbmcgdGhlIHRyYW5zY3JpcHQKSURzIHJhdGhlciB0aGFuIHRoZSBNR0kgc3ltYm9scy4gIEkgaG9wZSB0byByZXNvbHZlIHRoaXMgYXMgc29vbiBhcwpwb3NzaWJsZS4gIEZvciB0aGUgbW9tZW50IEkganVzdCB3YW50IHRvIG1ha2UgY2VydGFpbiB0aGF0IGFsbCBvZiB0aGUKZGF0YSBwb2ludHMgbWF0Y2ggcHJldmlvdXMgcmV2aXNpb25zIG9mIHRoZSBhbmFseXNpcy4KCmBgYHtyfQpoZWFkKGRmKQoKZGYgPC0gZGYgfD4KICBmaWx0ZXIocm93bmFtZXMoZGYpICVpbiUga2VlcGVyZ2VuZXMpCmxhYmVsc191cHMgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBhYnMobG9nRkMpID49IDEuMCkgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIGhlYWQobiA9IDkpCmxhYmVsc19kb3ducyA8LSBkZiB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPj0gMS4wKSB8PgogIGFycmFuZ2UoLWxvZ0ZDKSB8PgogIGhlYWQobiA9IDExKQpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQpyZXNfdGJsIDwtIGRmCkRFcGxvdCA8LSBnZ3Bsb3QocmVzX3RibCwgYWVzKHggPSBsb2dGQywgeSA9IC1sb2cxMChhZGouUC5WYWwpLCBsYWJlbCA9IHN5bWJvbCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTaWduaWZpY2FuY2UpLCBzaXplID0gNCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLTEsIDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMDUpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAyMCkgKwogIHhsYWIoImxvZzIoRkMpIikgKwogIHlsYWIoIi1sb2cxMChwLXZhbHVlKSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNGODc2NkQiLCAiIzAwQkZDNCIsICJHcmV5IikpICsKICAjIyBudWRnZV94ID0gLTAuNSwKICAjIyBudWRnZV95ID0gMywgbWF4Lm92ZXJsYXBzID0gMTUpICsKICB4bGltKGMoLTMsIDYpKQoKcHAoZmlsZSA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9pbWFnZXMvcDA4X3JldGluYV9ERV8xMzEyMDI0LnBkZiIsCiAgIGltYWdlID0gREVwbG90KQp3cml0ZV94bHN4KGRmLCBleGNlbCA9ICJleGNlbC9yZXRpbmFoZXRfdnNfcmV0aW5ha29fV1RmaWx0ZXJlZC54bHN4IikKYGBgCgojIyBIb3cgbWFueSB1cHMvZG93bnMKCmBgYHtyfQprb19lbnJpY2hlZCA8LSBkZiB8PgogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIktPIEVucmljaGVkIikKbnJvdyhrb19lbnJpY2hlZCkKaGV0X2VucmljaGVkIDwtICBkZiB8PgogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIkhldCBFbnJpY2hlZCIpCm5yb3coaGV0X2VucmljaGVkKQpgYGAKCiMjIGNhdGVnb3J5IGVucmljaG1lbnQvR1NFQQoKYGBge3J9CnJlc190YmxbWyJnZW5lX2lkIl1dIDwtIHJvd25hbWVzKHJlc190YmwpCnJlZ3VsYXRlZF9nZW5lcyA8LSByZXNfdGJsIHw+CiAgZHBseXI6OmZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIGRwbHlyOjpzZWxlY3QoZ2VuZV9pZCwgbG9nRkMsIGFkai5QLlZhbCwgc3ltYm9sLCBTaWduaWZpY2FuY2UpIHw+CiAgZHBseXI6OmZpbHRlcihhYnMobG9nRkMpID49IDEuMCkKIyMgZ3NlYV9yZXN1bHRfa28gPC0gZ29zdChxdWVyeSA9IGtvX2dlbmVzJGV4dGVybmFsX3N5bm9ueW0sCiMjICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKIyMgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKIyMgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKZ3NlYV9yZXN1bHRfaGV0IDwtIGdvc3QocXVlcnkgPSBoZXRfZW5yaWNoZWQkc3ltYm9sLAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAogICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUpCiMjZ3NlYV9yZXN1bHRfYWxsZHlzcmVndWxhdGVkIDwtIGdvc3QocXVlcnkgPSBhbGxkeXNyZWd1bGF0ZWRfZ2VuZXMkZXh0ZXJuYWxfc3lub255bSwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQpzdW1tYXJ5KGdzZWFfcmVzdWx0X2hldCkKYGBgCgpJIGhhdmUgYSBmdW5jdGlvbiBpbiBteSBwYWNrYWdlIHdoaWNoIHNlZWtzIHRvIG1ha2UgZ1Byb2ZpbGVyIHF1ZXJpZXMKYSBiaXQgbW9yZSBjb21wbGV0ZSBhbmQgZWFzeS4gIExldCB1cyBzZWUgaG93IHNpbWlsYXIgdGhlIHJlc3VsdCBpcy4uLgoKYGBge3IsIGV2YWw9RkFMU0V9CnJvd25hbWVzKGFsbGR5c3JlZ3VsYXRlZF9nZW5lcykgPC0gYWxsZHlzcmVndWxhdGVkX2dlbmVzW1siUm93Lm5hbWVzIl1dCmFsbGR5c3JlZ3VsYXRlZF9nZW5lc1tbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCgpoZXRfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihyb3duYW1lcyhhbGxkeXNyZWd1bGF0ZWRfZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZSgiZXhjZWwvaGV0X2dwcm9maWxlci12e3Zlcn0ueGxzeCIpKQpoZXRfZ3AKZW5yaWNocGxvdDo6ZG90cGxvdChoZXRfZ3BbWyJCUF9lbnJpY2giXV0pCmdwX3BhaXIgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbShoZXRfZ3BbWyJCUF9lbnJpY2giXV0pCmVucmljaHBsb3Q6OmVtYXBwbG90KGdwX3BhaXIpCmVucmljaHBsb3Q6OnNzcGxvdChncF9wYWlyKQplbnJpY2hwbG90Ojp0cmVlcGxvdChncF9wYWlyKQp1cHNldHBsb3QoaGV0X2dwW1siQlBfZW5yaWNoIl1dKQoKZW5yaWNocGxvdDo6ZG90cGxvdChoZXRfZ3BbWyJSRUFDX2VucmljaCJdXSkKZ3BfcGFpciA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKGhldF9ncFtbIlJFQUNfZW5yaWNoIl1dKQplbnJpY2hwbG90OjplbWFwcGxvdChncF9wYWlyKQplbnJpY2hwbG90Ojpzc3Bsb3QoZ3BfcGFpcikKZW5yaWNocGxvdDo6dHJlZXBsb3QoZ3BfcGFpcikKdXBzZXRwbG90KGhldF9ncFtbIlJFQUNfZW5yaWNoIl1dKQpgYGAKCkkgbWFrZSBhIHNvbWV3aGF0IGFyYml0cmFyeSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZSBjb25jZXB0cyBvZgpvdmVyLWVucmljaG1lbnQgYW5hbHlzZXMgYW5kIEdTRUE6IHRoZSBmb3JtZXIgKGFzIHBlcmZvcm1lZCBieQpncHJvZmlsZXIpIChAcmF1ZHZlcmVQcm9maWxlcldlYlNlcnZlcjIwMTkpIHNlZWtzIHRvIGZpbmQgZ3JvdXBzIG9mCmdlbmVzIG92ZXJyZXByZXNlbnRlZCBpbiBHTy9yZWFjdG9tZS9ldGMuICBUaGVzZSBncm91cHMgb2YgZ2VuZXMgYXJlCnRha2VuIGV4Y2x1c2l2ZWx5IGZyb20gdGhlIHRvcC1uL2JvdHRvbS1uIGdlbmVzIHdpdGggcmVzcGVjdCB0bwpmb2xkLWNoYW5nZSBiZXR3ZWVuIGNvbmRpdGlvbnMgb2YgaW50ZXJlc3Q7IGluIHRoaXMgY2FzZSBtb3N0CmRpZmZlcmVudCB0aGFuIHd0IGluIHRoZSBwMDggcmV0aW5hIGtvIG9yIGhldCBzYW1wbGVzLgoKV2l0aCB0aGF0IGluIG1pbmQsIEkgY2FuIGludm9rZSBhIHNpbWlsYXIgZnVuY3Rpb24gdXNpbmcgdGhlIGZ1bGwKdGFibGUgb2YgREUgcmVzdWx0cyB0byBnZXQgd2hhdCBJIGNhbGwgdGhlIEdTRUEgcmVzdWx0IHVzaW5nCmNsdXN0ZXJQcm9maWxlciAoQHl1SW50cm9kdWN0aW9uQmlvbWVkaWNhbEtub3dsZWRnZSkuICBJbiB0aGUKZm9sbG93aW5nIGJsb2NrIEkgd2lsbCB1c2UgdGhlICdhbGxfY3Byb2ZpbGVyJyBmdW5jdGlvbiBvbiB0aGUgZGF0YQpzdHJ1Y3R1cmVzIG5hbWVkICdwOF9yZXRpbmFfdGFibGVzJyBhbmQgJ29wcG9zaXRlX3A4X3JldGluYV90YWJsZXMnIGluCm9yZGVyIHRvIGdldCB0aGVzZSBHU0VBIHJlc3VsdHMgZm9yIGVhY2ggY29udHJhc3QgcGVyZm9ybWVkIChoZXQvd3QsCmtvL3d0LCBoZXQva28pLiAgSSB3aWxsIGZvbGxvdyB0aGF0IHVwIHdpdGggJ2FsbF9ncHJvZmlsZXInIHdoaWNoIGRvZXMKdGhlIHNhbWUsIGJ1dCB1c2VzIGdQcm9maWxlcidzIGVucmljaG1lbnQgYW5hbHlzZXMgKGl0IHdpbGwgdGhlcmVmb3JlCmluY2x1ZGUgd2hhdCB3ZSBqdXN0IGxvb2tlZCBhdCkuCgpgYGB7cn0KcDA4X3JldGluYV9hbGxfY3AgPC0gYWxsX2Nwcm9maWxlcigKICBwOF9yZXRpbmFfc2lnLCBwOF9yZXRpbmFfdGFibGVzLCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbC9jcHJvZmlsZXJfcDA4X3JldGluYS54bHN4IikKCmVucmljaHBsb3Q6OmRvdHBsb3QocDA4X3JldGluYV9hbGxfY3BbWyJrb192c19oZXRfdXAiXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dLAogICAgICAgICAgICAgICAgICAgIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCnAwOF90b3BuX2dzZWEgPC0gcGxvdF90b3BuX2dzZWEocDA4X3JldGluYV9hbGxfY3ApCgpwcChmaWxlID0gIjAzdGhlcmVzYV9jb21wYXJpc29uX2ltYWdlcy9nc2VhX3AwOF9yZXRpbmFfa29fdnNfaGV0X3RvcF9oaXQucGRmIiwKICAgaW1hZ2UgPSBwcmludChwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1sxXV0pKQoKcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbMl1dCnAwOF90b3BuX2dzZWFbWyJHT19rb192c19oZXRfdXAiXV1bWzNdXQpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1s0XV0KcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbNV1dCgpwcChmaWxlID0gIjAzdGhlcmVzYV9jb21wYXJpc29uX2ltYWdlcy9nc2VhX3AwOF9yZXRpbmFfaGV0X3ZzX3d0X3RvcF9oaXQucGRmIiwKICAgaW1hZ2UgPSBwcmludChwMDhfdG9wbl9nc2VhW1siR09faGV0X3ZzX3d0X3VwIl1dW1sxXV0pKQpgYGAKCmBgYHtyfQojZ3NlYV9rbyA8LSAgZ3NlYV9yZXN1bHRfa29bWyJyZXN1bHQiXV0gfD4KIyAgICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSB8PgojICAgIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSB8PgojICAgIGhlYWQobiA9IDEwKQojICBnc2VhX3Bsb3RzX2tvIDwtIGdncGxvdChnc2VhX2tvLCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKIyAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKwojICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKIyAgdGhlbWVfYncoKSsKIyAgeWxhYigiIikgKwojICB4bGFiKCJHU0VBIFNjb3JlIikKZ3NlYV9oZXQgPC0gIGdzZWFfcmVzdWx0X2hldFtbInJlc3VsdCJdXSB8PgogIGRwbHlyOjpzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSB8PgogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSB8PgogIGhlYWQobiA9IDEwKQpnc2VhX3Bsb3RzX2hldCA8LSBnZ3Bsb3QoZ3NlYV9oZXQsIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIk92ZXIgUmVwcmVzZW50YXRpb24gU2NvcmUiKQpwcChmaWxlID0gIjAzdGhlcmVzYV9jb21wYXJpc29uX2ltYWdlcy9HU0VBX3AwOF9heG9udHJhcF9yZXRpbmFoZXRfdXByZWd1bGF0ZWRfdnNfcmV0aW5ha28ucGRmIikKZ3NlYV9wbG90c19oZXQKcGxvdHRlZCA8LSBkZXYub2ZmKCkKZ3NlYV9wbG90c19oZXQKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9hbGwgPC0gIGdzZWFfcmVzdWx0X2FsbGR5c3JlZ3VsYXRlZFtbInJlc3VsdCJdXSB8PgogIGRwbHlyOjpzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSB8PgogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSB8PgogIGhlYWQobiA9IDEwKQpnc2VhX3Bsb3RzX2FsbCA8LSBnZ3Bsb3QoZ3NlYV9hbGwsIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIk92ZXIgUmVwcmVzZW50YXRpb24gU2NvcmUiKQoKcHAoZmlsZSA9ICJpbWFnZXMvR1NFQV9wMDhfcmV0aW5hX2F4b250cmFwX2FsbGR5c3JlZ3VsYXRlZGdlbmVzLnBkZiIpCmdzZWFfcGxvdHNfYWxsCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyBMaWJyYXJ5IHNpemVzIHBvc3QtZGVkdXBsaWNhdGlvbgoKVGhlcmVzYSdzIG5leHQgb3BlcmF0aW9uIHdhcyB0byBwZXJmb3JtIGxpYnNpemUvbm9uemVybyBwbG90cy4gIEkKYWxyZWFkeSBkaWQgdGhlIHByZS9wb3N0IGRlZHVwbGljYXRpb24gbm9uemVybywgaGVyZSBpcyB0aGUgYW5hbGFnb3VzCmxpYnNpemUuCgp2MiBpcyBwcmUtZGVkdXBsaWNhdGlvbiBhbmQgdjMgaXMgcG9zdC4KCmBgYHtyfQpwbG90X2xpYnNpemUobW0zOF9oaXNhdF92MikKcG9zdF9maWx0ZXJfbm9uemVybyA8LSBwbG90X2xpYnNpemUobW0zOF9oaXNhdF92MywgdGV4dCA9IEZBTFNFKQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXMvcG9zdF9hbGxfZmlsdGVyZXNfbm9uemVyby5wZGYiKQpwb3N0X2ZpbHRlcl9ub256ZXJvW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpwb3N0X2ZpbHRlcl9ub256ZXJvCmBgYAoKSSBhbSBhIGJpdCBjb25jZXJuZWQgYWJvdXQgc29tZSBvZiB0aGVzZSBsaWJyYXJ5IHNpemVzCnBvc3QtZGVkdXBsaWNhdGlvbi4KCkxldCB1cyBsb29rIGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiByZWFkcyBhbmQgZHVwbGljYXRpb24sIHdoaWNoIEkKYXNzdW1lIHdpbGwgYmUgcmVsYXRpdmVseSBsaW5lYXIuCgpgYGB7cn0KZGVkdXBfcXVlcnkgPC0gY29sRGF0YShtbTM4X2hpc2F0X3YzKVssIGMoImhpc2F0X2dlbm9tZV9zaW5nbGVfYWxsIiwgInVtaV9kZWR1cF9wY3RfcmVhZHMiKV0KdGVzdF9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoZGVkdXBfcXVlcnksIGxvZXNzID0gVFJVRSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL2RlZHVwbGljYXRpb25fdnNfaGlzYXRfc2NhdHRlci5wZGYiLCBpbWFnZSA9IHRlc3RfcGxvdFtbInNjYXR0ZXIiXV0pCmBgYAoKVGhlcmVzYSBhbHNvIHByb2R1Y2VkIGEgZGVuc2l0eS9zYW1wbGUgcGxvdCwgdGhhdCBtaWdodCBwcm92ZSBxdWl0ZQp1c2VmdWwgZm9yIHRoZXNlIGR1ZSB0byB0aGVpciBzaWduaWZpY2FudGx5IGxhcmdlciB2YXJpYW5jZSBhY3Jvc3MKc2FtcGxlcyAoZHVlIHRvIGRlZHVwbGljYXRpb24pLgoKYGBge3J9CnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlcy9zYW1wbGVfZGVuc2l0eS5wZGYiKQptbTM4X2RlbnNpdHkgPC0gcGxvdF9kZW5zaXR5KGxvY19nZW5vX250KQptbTM4X2RlbnNpdHlbWyJwbG90Il1dICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBsb3RfYm94cGxvdChsb2NfZ2Vub19udCkKZGV2Lm9mZigpCm1tMzhfZGVuc2l0eVtbInBsb3QiXV0gKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYm94IDwtIHBsb3RfYm94cGxvdChsb2NfZ2Vub19udCkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzL3NhbXBsZV9ib3hwbG90LnBkZiIsIGltYWdlID0gYm94KQpgYGAKClRoZXJlIGlzIHNvbWUgZGlmZmVyZW5jZSBhY3Jvc3Mgc2FtcGxlIGRlbnNpdGllcywgYnV0IGl0IGlzIG5vdCB0b28KY3Jhenl0b3duLgoKIyBEaXZlcmdpbmcgYSBsaXR0bGUKCkF0IHRoaXMgcG9pbnQgaW4gdGhlIGRvY3VtZW50IEkgcmVhZCBhaGVhZCBhIGJpdCBhbmQgY2FtZSB0byB0aGUKY29uY2x1c2lvbiB0aGF0IGl0IHJlcGVhdHMgdGhlIGFib3ZlIGxvZ2ljIG9mIHRha2luZyB0aGUgdW5pb24gb2Ygd3QKY29tcGFyaXNvbnMgdG8gcmVtb3ZlIGdlbmVzIGZyb20gdGhlIGFwcHJvcHJpYXRlIGhldC9rbyBvciBwMTUvcDA4IG9yCmxvY2F0aW9uIGNvbXBhcmlzb25zLiAgVGhpcyBzZWVtcyBxdWl0ZSByZWFzb25hYmxlIHRvIG1lLCBidXQgSSB3b3VsZApwcmVmZXIgdG8gbm90IHNlcGFyYXRlIGFsbCB0aGUgZGF0YSwgc28gSSB3aWxsIGF0dGVtcHQgdG8gZHVwbGljYXRlCmFuZCBzbGlnaHRseSBzdHJlYW1saW5lIHRoaXMgbG9naWMgb24gdGhlIGZ1bGwgZGF0YXNldC4gIFRodXMgSSBhbQpnb2luZyB0byBza2lwIGRvd24gdG8gdGhlIGVuZCBhbmQgYXR0ZW1wdCB0byBpbXBsZW1lbnQgdGhpcy4KCiMjIERFCgpOb3RlOiBUaGUgZm9sbG93aW5nIGZldyBibG9ja3MgYXJlIGFsbCBjb3B5L3Bhc3RlZCBkaXJlY3RseSBmcm9tClRoZXJlc2EncyBub3RlYm9vayBhbmQgYXJlIG5vdCBldmFsdWF0ZWQgYmVjYXVzZSB0aGV5IGFyZSBwZXJmb3JtZWQKYWxtb3N0IGlkZW50aWNhbGx5IGxhdGVyIGJ1dCB3aXRoIHNsaWdodGx5IGRpZmZlcmVudCBsb2dpYy9vcmRlcnMuCgpgYGB7ciwgZXZhbD1GQUxTRX0KbW1fZGVfbm9ybWFsX3A4X3NjbiA8LSBhbGxfcGFpcndpc2UobW0zOF9zdWJzZXQsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsIGRvX2Jhc2ljID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2RyZWFtID0gRkFMU0UsIGRvX25vaXNlcSA9IEZBTFNFLCBkb19lZGdlciA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFKQphbm5vdHNfdG9fbWVyZ2UgPC0gbW1fYW5ub3QgfD4KICBzZWxlY3QoZW5zZW1ibF9nZW5lX2lkLCBleHRlcm5hbF9zeW5vbnltKSB8PgogIGZpbHRlcihlbnNlbWJsX2dlbmVfaWQgJWluJSByb3duYW1lcyhtbV9kZV9ub3JtYWxfcDhfc2NuJGRlc2VxJGFsbF90YWJsZXMka29fc2NuX3ZzX2hldF9zY24pKSB8PgogIGRpc3RpbmN0KCkKbW1fZGVfbm9ybWFsX3A4X3NjbiRkZXNlcSRhbGxfdGFibGVzJGtvX3Njbl92c19oZXRfc2NuIDwtIG1lcmdlKAogIG1tX2RlX25vcm1hbF9wOF9zY24kZGVzZXEkYWxsX3RhYmxlcyRrb19zY25fdnNfaGV0X3NjbiwKICBhbm5vdHNfdG9fbWVyZ2UsIGJ5LnggPSAwLCBieS55ID0gImVuc2VtYmxfZ2VuZV9pZCIsIGFsbC54ID0gVFJVRSkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KaGV0a2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9zY24kZGVzZXEkYWxsX3RhYmxlcyR3dF9zY25fdnNfaGV0X3NjbiB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4xICYgYWRqLlAuVmFsIDw9IDAuMDUpCmtva2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9zY24kZGVzZXEkYWxsX3RhYmxlcyR3dF9zY25fdnNfa29fc2NuIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjEgJiBhZGouUC5WYWwgPD0gMC4wNSkKa2VlcGVyZ2VuZXMgPC0gdW5pcXVlKGMocm93bmFtZXMoaGV0a2VlcGVyX2dlbmVzKSwgcm93bmFtZXMoa29rZWVwZXJfZ2VuZXMpKSkKZGYgPC0gbW1fZGVfbm9ybWFsX3A4X3NjbiRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2hldHNjbiB8PgogIGRwbHlyOjptdXRhdGUobG9nRkMgPSAtbG9nRkMpIHw+CiAgc2V0X3NpZ19saW1tYShmYWN0b3JzID0gYygiSGV0IEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLTyBFbnJpY2hlZCIpKQpkZiA8LSBkZiB8PgogIGZpbHRlcihSb3cubmFtZXMgJWluJSBrZWVwZXJnZW5lcykKbGFiZWxzX3VwcyA8LSBkZiB8PgogIGZpbHRlcihhYnMobG9nRkMpID4gMSkgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIGhlYWQobiA9IDEpCmxhYmVsc19kb3ducyA8LSBkZiB8PgogIGZpbHRlcihhYnMobG9nRkMpID4gMSkgfD4KICBhcnJhbmdlKC1sb2dGQykgfD4KICBoZWFkKG4gPSAxKQpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQpyZXNfdGJsIDwtIGRmCkRFcGxvdCA8LSBnZ3Bsb3QocmVzX3RibCwgYWVzKHggPSBsb2dGQywgeSA9IC1sb2cxMChhZGouUC5WYWwpLCBsYWJlbCA9IGV4dGVybmFsX3N5bm9ueW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU2lnbmlmaWNhbmNlKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB4bGFiKCJsb2cyKEZDKSIpICsKICB5bGFiKCItbG9nMTAocC12YWx1ZSkiKSArCiAgIyMgZ2d0aXRsZSh0aXRsZSwgc3VidGl0bGUgPSBzdWJ0aXRsZSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJIZXQgRW5yaWNoZWQiID0gIiNGODc2NkQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS08gRW5yaWNoZWQiID0gIiMwMEJGQzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm90XG4gRW5yaWNoZWQiID0gIkdyZXkiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIoZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIyBjKCdzNV9oZXRfZGxnbicsICdzNV9oZXRfcmV0JywgJ3M1X2hldF9zY24nKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRlcm5hbF9zeW5vbnltICVpbiUgbGFiZWxzJGV4dGVybmFsX3N5bm9ueW0pLAogICAgICAgICAgICAgICAgICAgIyMgbnVkZ2VfeCA9IC0wLjUsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMywgbWF4Lm92ZXJsYXBzID0gMTUpICsKICBnZ3RpdGxlKCJTQ04gSGV0IHZzIEtPIFRyYW5zbGF0b21lIikKCnBwKGZpbGUgPSAiaW1hZ2VzL3AwOF9zY25fREVfMTMxMjAyNC5wZGYiKQpERXBsb3QKcGxvdHRlZCA8LSBkZXYub2ZmKCkKCndyaXRlX3hsc3goZGYsIGV4Y2VsID0gImV4Y2VsL3NjbmhldF92c19zY25rb19XVGZpbHRlcmVkLnhsc3giKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3IsIGV2YWw9RkFMU0V9CmtvX2VucmljaGVkIDwtIGRmIHw+CiAgZmlsdGVyKFNpZ25pZmljYW5jZSA9PSAiS08gRW5yaWNoZWQiKQoKaGV0X2VucmljaGVkIDwtIGRmIHw+CiAgZmlsdGVyKFNpZ25pZmljYW5jZSA9PSAiSGV0IEVucmljaGVkIikKYGBgCgojIyBHU0VBCgpgYGB7ciwgZXZhbD1GQUxTRX0Ka29fZ2VuZXMgPC0gcmVzX3RibCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBhcnJhbmdlKC1hYnMobG9nRkMpKSB8PgogIHNlbGVjdChSb3cubmFtZXMsIGxvZ0ZDLCBhZGouUC5WYWwsIGV4dGVybmFsX3N5bm9ueW0sIFNpZ25pZmljYW5jZSkgfD4KICBmaWx0ZXIobG9nRkMgPD0gLTEpCgpoZXRfZ2VuZXMgPC0gcmVzX3RibCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBhcnJhbmdlKC1hYnMobG9nRkMpKSB8PgogIHNlbGVjdChSb3cubmFtZXMsIGxvZ0ZDLCBhZGouUC5WYWwsIGV4dGVybmFsX3N5bm9ueW0sIFNpZ25pZmljYW5jZSkgfD4KICBmaWx0ZXIobG9nRkMgPj0gMSkKCmFsbGR5c3JlZ3VsYXRlZF9nZW5lcyA8LSByZXNfdGJsIHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgc2VsZWN0KFJvdy5uYW1lcywgbG9nRkMsIGFkai5QLlZhbCwgZXh0ZXJuYWxfc3lub255bSwgU2lnbmlmaWNhbmNlKSB8PgogIGZpbHRlcihhYnMobG9nRkMpID49IDEpCgpnc2VhX3Jlc3VsdF9rbyA8LSBnb3N0KHF1ZXJ5ID0ga29fZ2VuZXMkZXh0ZXJuYWxfc3lub255bSwKICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAogICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQoKZ3NlYV9yZXN1bHRfaGV0IDwtIGdvc3QocXVlcnkgPSBoZXRfZ2VuZXMkZXh0ZXJuYWxfc3lub255bSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQoKZ3NlYV9yZXN1bHRfYWxsZHlzcmVndWxhdGVkIDwtIGdvc3QocXVlcnkgPSBhbGxkeXNyZWd1bGF0ZWRfZ2VuZXMkZXh0ZXJuYWxfc3lub255bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpnc2VhX2tvIDwtICBnc2VhX3Jlc3VsdF9rb1tbInJlc3VsdCJdXSB8PgogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pIHw+CiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpIHw+CiAgaGVhZChuID0gMTApCmdzZWFfcGxvdHNfa28gPC0gZ2dwbG90KGdzZWFfa28sIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIk92ZXIgZW5yaWNobWVudCBTY29yZSIpCgpnc2VhX2hldCA8LSAgZ3NlYV9yZXN1bHRfaGV0W1sicmVzdWx0Il1dIHw+CiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgfD4KICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgfD4KICBoZWFkKG4gPSAxMCkKZ3NlYV9wbG90c19oZXQgPC0gZ2dwbG90KGdzZWFfaGV0LCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIiIpICsKICB4bGFiKCJPdmVyIGVucmljaG1lbnQgU2NvcmUiKQoKZ3NlYV9hbGwgPC0gIGdzZWFfcmVzdWx0X2FsbGR5c3JlZ3VsYXRlZFtbInJlc3VsdCJdXSB8PgogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pIHw+CiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpIHw+CiAgaGVhZChuID0gMTApCmdzZWFfcGxvdHNfYWxsIDwtIGdncGxvdChnc2VhX2FsbCwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiT3ZlciBlbnJpY2htZW50IFNjb3JlIikKCnBwKGZpbGUgPSAiaW1hZ2VzL0dTRUFfcDA4X3JldGluYV9heG9udHJhcF9hbGxkeXNyZWd1bGF0ZWRnZW5lcy5wZGYiKQpnc2VhX3Bsb3RzX2FsbApwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMgSGV0IFJldGluYSB2cyBIZXQgU0NOCgpgYGB7ciwgZXZhbD1GQUxTRX0KbW0zOF9zdWJzZXQyIDwtIHN1YnNldF9zZSgKICBtbTM4X2hpc2F0LAogIHN1YnNldCA9ICIoYmF0Y2ggPT0gJzQnIHwgYmF0Y2ggPT0gJzUnIHwgYmF0Y2ggPT0gJzYnKSAmIHRpbWUgPT0gJ3AwOCcgJiBnZW5vdHlwZSAhPSAna28nICYgbG9jYXRpb24gIT0gJ2RsZ24nIHwgc2FtcGxlaWQgPT0gJ2lwcmdjXzAzJyIpCgptbTM4X3N1YnNldDIgPC0gc3Vic2V0X3NlKG1tMzhfc3Vic2V0Miwgc3Vic2V0ID0gInNhbXBsZWlkICE9ICdpcHJnY184OSciKQptbTM4X3N1YnNldDIkZGVzaWduIHw+CiAgc2VsZWN0KGdlbm90eXBlLCBsb2NhdGlvbikgfD4KICB0YWJsZSgpCm1tMzhfbm9ybTIgPC0gbm9ybWFsaXplKG1tMzhfc3Vic2V0MiwgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm09ImxvZzIiLCBiYXRjaCA9ICJzdmFzZXEiKQpgYGAKCiMjIFBDQQoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tMzhfbm9ybTIgPC0gc2V0X2JhdGNoZXMobW0zOF9ub3JtMiwgZmFjdCA9ICJsb2NhdGlvbiIpCm1tMzhfbm9ybTIgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9ub3JtMiwgZmFjdCA9ICJnZW5vdHlwZSIpCnBjYV9ub3JtMiA8LSBwbG90X3BjYShtbTM4X25vcm0yLCBtYXhfb3ZlcmxhcHMgPSA3MCkKcGNhX25vcm0yJHBsb3QKYGBgCgojIyBERQoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tX2RlX3N1YnNldDIgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfc3Vic2V0MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFLCBkb19lYnNlcT1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fYmFzaWMgPSBGQUxTRSwgZG9fZHJlYW0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2VkZ2VyID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnJldGluYWtlZXBlcl9nZW5lcyA8LSBtbV9kZV9zdWJzZXQyJGRlc2VxJGFsbF90YWJsZXMkd3RfcmV0aW5hX3ZzX2hldF9yZXRpbmEgfD4KICBmaWx0ZXIobG9nRkMgPD0gLTAuMSAmIGFkai5QLlZhbCA8PSAwLjA1KQoKc2Nua2VlcGVyX2dlbmVzIDwtIG1tX2RlX3N1YnNldDIkZGVzZXEkYWxsX3RhYmxlcyR3dF9zY25fdnNfaGV0X3NjbiB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4xICYgYWRqLlAuVmFsIDw9IDAuMDUpCgprZWVwZXJnZW5lcyA8LSB1bmlxdWUoYyhyb3duYW1lcyhyZXRpbmFrZWVwZXJfZ2VuZXMpLCByb3duYW1lcyhzY25rZWVwZXJfZ2VuZXMpKSkKCmFubm90c190b19tZXJnZSA8LSBtbV9hbm5vdCB8PgogIHNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGV4dGVybmFsX3N5bm9ueW0pIHw+CiAgZmlsdGVyKGVuc2VtYmxfZ2VuZV9pZCAlaW4lIHJvd25hbWVzKG1tX2RlX3N1YnNldDIkZGVzZXEkYWxsX3RhYmxlcyRoZXRfc2NuX3ZzX2hldF9yZXRpbmEpKSB8PgogIGRpc3RpbmN0KCkKCm1tX2RlX3N1YnNldDIkZGVzZXEkYWxsX3RhYmxlcyRoZXRfc2NuX3ZzX2hldF9yZXRpbmEgPC0gbWVyZ2UoCiAgbW1fZGVfc3Vic2V0MiRkZXNlcSRhbGxfdGFibGVzJGhldF9zY25fdnNfaGV0X3JldGluYSwKICBhbm5vdHNfdG9fbWVyZ2UsIGJ5LnggPSAwLAogIGJ5LnkgPSAiZW5zZW1ibF9nZW5lX2lkIiwgYWxsLnggPSBUUlVFKQoKZGYgPC0gbW1fZGVfc3Vic2V0MiRkZXNlcSRhbGxfdGFibGVzJGhldF9zY25fdnNfaGV0X3JldGluYSB8PgogIG11dGF0ZShTaWduaWZpY2FuY2UgPSBjYXNlX3doZW4obG9nRkMgPD0gLTEuMCB+ICJSZXRpbmEgRW5yaWNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nRkMgPj0gMS4wIH4gIlNDTiBFbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dGQyA+IC0xLjAgJiBsb2dGQyA8IDEuMCB+ICJOb3RcbiBFbnJpY2hlZCIpKQoKZGYgPC0gZGYgfD4KICBmaWx0ZXIoUm93Lm5hbWVzICVpbiUga2VlcGVyZ2VuZXMpCgpzY25fZW5yaWNoZWQgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA+PSAxLjApIHw+CiAgYXJyYW5nZSgtbG9nRkMpIHw+CiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfc3lub255bSwgbG9nRkMsIGFkai5QLlZhbCkgfD4KICBtdXRhdGUoU2lnbmlmaWNhbmNlID0gIlNDTiBFbnJpY2hlZCIpIHw+CiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIHJvd25hbWVzKHNjbmtlZXBlcl9nZW5lcykpCgpyZXRpbmFfZW5yaWNoZWQgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA8PSAtMS4wKSB8PgogIGFycmFuZ2UobG9nRkMpICB8PgogIHNlbGVjdChSb3cubmFtZXMsIGV4dGVybmFsX3N5bm9ueW0sIGxvZ0ZDLCBhZGouUC5WYWwpIHw+CiAgbXV0YXRlKFNpZ25pZmljYW5jZSA9ICJSZXRpbmEgRW5yaWNoZWQiKSB8PgogIGZpbHRlcihSb3cubmFtZXMgJWluJSByb3duYW1lcyhyZXRpbmFrZWVwZXJfZ2VuZXMpKQoKbm90ZW5yaWNoZWQgPC0gZGYgfD4KICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9zeW5vbnltLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpIHw+CiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIGMocm93bmFtZXMocmV0aW5ha2VlcGVyX2dlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhzY25rZWVwZXJfZ2VuZXMpKVtkdXBsaWNhdGVkKGMocm93bmFtZXMocmV0aW5ha2VlcGVyX2dlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSkpXSkgfD4KICBmaWx0ZXIoU2lnbmlmaWNhbmNlID09ICJOb3RcbiBFbnJpY2hlZCIpCgpkZiA8LSByYmluZChzY25fZW5yaWNoZWQsIHJldGluYV9lbnJpY2hlZCwgbm90ZW5yaWNoZWQpCmRmIDwtIGRmIHw+CiAgZGlzdGluY3QoKQoKIyMgd3JpdGV4bDo6d3JpdGVfeGxzeChkZiwgcGF0aCA9ICJheG9uVFJBUF9ERV9yZXN1bHRzXzIwMjQwMjAyL3JldGluYWhldF92c19zY25faGV0X1dUZmlsdGVyZWQueGxzeCIpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CmxhYmVsc191cHMgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBhYnMobG9nRkMpID4gMS4wKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgaGVhZChuID0gMTApCgpsYWJlbHNfZG93bnMgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBhYnMobG9nRkMpID4gMS4wKSB8PgogIGFycmFuZ2UoLWxvZ0ZDKSB8PgogIGhlYWQobiA9IDEwKQoKbGFiZWxzIDwtIHJiaW5kKGxhYmVsc191cHMsIGxhYmVsc19kb3ducykKCmxhYmVsc19yZXF1ZXN0ZWQgPC0gYygiQ2RoMTAiLCJDZGgxMiIsIkNkaDEzIiwiQ2RoMTgiLAogICAgICAgICAgICAgICAgICAgICAgIkNkaDciLCJDZGg4IiwiQ2RoOSIsIkNudG4zIiwKICAgICAgICAgICAgICAgICAgICAgICJDbnRuNCIsIkNudG41IiwiQ250bjYiLCJLaXJyZWwzIiwKICAgICAgICAgICAgICAgICAgICAgICJOcnhuMSIsIk5yeG4zIiwiU2VtYTNjIiwiU2VtYTZkIiwKICAgICAgICAgICAgICAgICAgICAgICJUZW5tMSIsIlRlbm0yIiwiVGVubTQiKQpyZXNfdGJsIDwtIGRmCkRFcGxvdCA8LSBnZ3Bsb3QocmVzX3RibCwgYWVzKHggPSBsb2dGQywgeSA9IC1sb2cxMChhZGouUC5WYWwpLCBsYWJlbCA9IGV4dGVybmFsX3N5bm9ueW0pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU2lnbmlmaWNhbmNlKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB4bGFiKCJsb2cyKEZDKSIpICsKICB5bGFiKCItbG9nMTAocC12YWx1ZSkiKSArCiAgIyMgZ2d0aXRsZSh0aXRsZSwgc3VidGl0bGUgPSBzdWJ0aXRsZSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJHcmV5IiwgIiNGODc2NkQiLCAiIzAwQkZDNCIpKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihkZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dGVybmFsX3N5bm9ueW0gJWluJSBsYWJlbHNfcmVxdWVzdGVkKSwKICAgICAgICAgICAgICAgICAgICMjIGMobGFiZWxzJGV4dGVybmFsX3N5bm9ueW0sICJPcG40IikpLCAjYygnczVfaGV0X2RsZ24nLCAnczVfaGV0X3JldCcsICdzNV9oZXRfc2NuJykpLAogICAgICAgICAgICAgICAgICAgIyMgbnVkZ2VfeCA9IC0wLjUsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMTUsIG1heC5vdmVybGFwcyA9IDI1KQoKI3BwKGZpbGUgPSAiYXhvblRSQVBfVm9sY2Fub3Bsb3RzXzIwMjQwMjAyL3AwOF9yZXRpbmF2c3NjbmhldF9ERV9yZXF1ZXN0ZWRfZ2VuZWxhYmVsc18wMjA1MjAyNC5wZGYiKQpERXBsb3QKI2Rldi5vZmYoKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3IsIGV2YWw9RkFMU0V9CnNjbl9lbnJpY2hlZCA8LSBkZiB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGxvZ0ZDID49IDEuMCkgfD4KICBhcnJhbmdlKC1sb2dGQykgfD4KICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9zeW5vbnltLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpCgpyZXRpbmFfZW5yaWNoZWQgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA8PSAtMS4wKSB8PgogIGFycmFuZ2UobG9nRkMpICB8PgogIHNlbGVjdChSb3cubmFtZXMsIGV4dGVybmFsX3N5bm9ueW0sIGxvZ0ZDLCBhZGouUC5WYWwsIFNpZ25pZmljYW5jZSkKCnNjbl9lbnJpY2hlZApyZXRpbmFfZW5yaWNoZWQKCmRmIHw+CiAgZmlsdGVyKFNpZ25pZmljYW5jZSA9PSAiTm90XG4gRW5yaWNoZWQiKQpgYGAKCiMjIEdTRUEKCmBgYHtyLCBldmFsPUZBTFNFfQpnc2VhX3Jlc3VsdF9zY24gPC0gZ29zdChxdWVyeSA9IHNjbl9lbnJpY2hlZCRleHRlcm5hbF9zeW5vbnltLAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLCBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUsIHNvdXJjZSA9IGMoIkdPIikpCgpnc2VhX3Jlc3VsdF9yZXQgPC0gZ29zdChxdWVyeSA9IHJldGluYV9lbnJpY2hlZCRleHRlcm5hbF9zeW5vbnltLAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLCBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUsIHNvdXJjZSA9IGMoIkdPIikpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CmdzZWFfc2NuIDwtICBnc2VhX3Jlc3VsdF9zY25bWyJyZXN1bHQiXV0gfD4KICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSB8PgogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSB8PgogIGhlYWQobiA9IDIwKQpnc2VhX3Bsb3RzX3NjbiA8LSBnZ3Bsb3QoZ3NlYV9zY24sIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIk92ZXIgZW5yaWNobWVudCBTY29yZSIpCgpwcChmaWxlID0gImltYWdlcy9HU0VBX1NDTmhldF92c19yZXRpbmFfZW5yaWNoZWRfUDA4LnBkZiIpCmdzZWFfcGxvdHNfc2NuCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCgpnc2VhX3JldCA8LSAgZ3NlYV9yZXN1bHRfcmV0W1sicmVzdWx0Il1dIHw+CiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgfD4KICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgfD4KICBoZWFkKG4gPSAyMCkKZ3NlYV9wbG90c19yZXQgPC0gZ2dwbG90KGdzZWFfcmV0LCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIiIpICsKICB4bGFiKCJPdmVyIGVucmljaG1lbnQgU2NvcmUiKQoKcHAoZmlsZSA9ICJpbWFnZXMvR1NFQV9SZXRpbmFoZXRfdnNfU0NOX2VucmljaGVkX1AwOC5wZGYiKQpnc2VhX3Bsb3RzX3JldApwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMgS08gUmV0aW5hIHZzIEtPIFNDTgoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tMzhfc3Vic2V0MyA8LSBzdWJzZXRfc2UoCiAgbW0zOF9oaXNhdCwKICBzdWJzZXQgPSAiKGJhdGNoID09ICc0JyB8IGJhdGNoID09ICc1JyB8IGJhdGNoID09ICc2JykgJiB0aW1lID09ICdwMDgnICAmIGdlbm90eXBlICE9ICdoZXQnICYgbG9jYXRpb24gIT0gJ2RsZ24nIHwgc2FtcGxlaWQgPT0gJ2lwcmdjXzAzJyIpCgptbTM4X3N1YnNldDMgPC0gc3Vic2V0X3NlKG1tMzhfc3Vic2V0Mywgc3Vic2V0ID0gInNhbXBsZWlkICE9ICdpcHJnY184NiciKQptbTM4X3N1YnNldDMkZGVzaWduIHw+CiAgc2VsZWN0KGdlbm90eXBlLCBsb2NhdGlvbikgfD4KICB0YWJsZSgpCm1tMzhfbm9ybTMgPC0gbm9ybWFsaXplKG1tMzhfc3Vic2V0MywgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKYGBgCgojIyBQQ0EKCmBgYHtyLCBldmFsPUZBTFNFfQptbTM4X25vcm0zIDwtIHNldF9iYXRjaGVzKG1tMzhfbm9ybTMsIGZhY3QgPSAibG9jYXRpb24iKQptbTM4X25vcm0zIDwtIHNldF9jb25kaXRpb25zKG1tMzhfbm9ybTMsIGZhY3QgPSAiZ2Vub3R5cGUiKQpwY2Ffbm9ybTMgPC0gcGxvdF9wY2EobW0zOF9ub3JtMywgbWF4X292ZXJsYXBzID0gNzApCnBjYV9ub3JtMyRwbG90CmBgYAoKIyMgREUKCmBgYHtyLCBldmFsPUZBTFNFfQptbV9kZV9zdWJzZXQzIDwtIGFsbF9wYWlyd2lzZShtbTM4X3N1YnNldDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2JhdGNoPSJzdmFzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSwgZG9fZWJzZXE9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2Jhc2ljID0gRkFMU0UsIGRvX2RyZWFtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX25vaXNlcSA9IEZBTFNFLCBkb19lZGdlciA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFKQoKcmV0aW5ha2VlcGVyX2dlbmVzIDwtIG1tX2RlX3N1YnNldDMkZGVzZXEkYWxsX3RhYmxlcyR3dHJldGluYV92c19rb3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMS4wICYgYWRqLlAuVmFsIDw9IDAuMDUpCgpzY25rZWVwZXJfZ2VuZXMgPC0gbW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJHd0c2NuX3ZzX2tvc2NuIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0xLjAgJiBhZGouUC5WYWwgPD0gMC4wNSkKCmtlZXBlcmdlbmVzIDwtIHVuaXF1ZShjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksIHJvd25hbWVzKHNjbmtlZXBlcl9nZW5lcykpKQoKYW5ub3RzX3RvX21lcmdlIDwtIG1tX2Fubm90IHw+CiAgc2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgZXh0ZXJuYWxfc3lub255bSkgfD4KICBmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXMobW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJGtvX3Njbl92c19rb19yZXRpbmEpKSB8PgogIGRpc3RpbmN0KCkKCm1tX2RlX3N1YnNldDMkZGVzZXEkYWxsX3RhYmxlcyRrb19zY25fdnNfa29fcmV0aW5hIDwtIG1lcmdlKAogIG1tX2RlX3N1YnNldDMkZGVzZXEkYWxsX3RhYmxlcyRrb19zY25fdnNfa29fcmV0aW5hLAogIGFubm90c190b19tZXJnZSwgYnkueCA9IDAsCiAgYnkueSA9ICJlbnNlbWJsX2dlbmVfaWQiLCBhbGwueCA9IFRSVUUpCgpkZiA8LSBtbV9kZV9zdWJzZXQzJGRlc2VxJGFsbF90YWJsZXMka29fc2NuX3ZzX2tvX3JldGluYSB8PgogIG11dGF0ZShTaWduaWZpY2FuY2UgPSBjYXNlX3doZW4obG9nRkMgPD0gLTEgfiAiUmV0aW5hIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID49IDEgfiAiU0NOIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID4gLTEgJiBsb2dGQyA8IDEgfiAiTm90XG4gRW5yaWNoZWQiKSkKCmRmIDwtIGRmIHw+CiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIGtlZXBlcmdlbmVzKQoKc2NuX2VucmljaGVkIDwtIGRmIHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgbG9nRkMgPj0gMSkgfD4KICBhcnJhbmdlKC1sb2dGQykgfD4KICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9zeW5vbnltLCBsb2dGQywgYWRqLlAuVmFsKSB8PgogIG11dGF0ZShTaWduaWZpY2FuY2UgPSAiU0NOIEVucmljaGVkIikgfD4KICBmaWx0ZXIoUm93Lm5hbWVzICVpbiUgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSkKCmRmIHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgbG9nRkMgPD0gLTEpIHw+CiAgYXJyYW5nZShsb2dGQykgIHw+CiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfc3lub255bSwgbG9nRkMsIGFkai5QLlZhbCkgfD4KICBtdXRhdGUoU2lnbmlmaWNhbmNlID0gIlJldGluYSBFbnJpY2hlZCIpIHw+CiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcykpIC0+IHJldGluYV9lbnJpY2hlZAoKbm90ZW5yaWNoZWQgPC0gZGYgfD4KICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9zeW5vbnltLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpIHw+CiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIGMocm93bmFtZXMocmV0aW5ha2VlcGVyX2dlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhzY25rZWVwZXJfZ2VuZXMpKVtkdXBsaWNhdGVkKGMocm93bmFtZXMocmV0aW5ha2VlcGVyX2dlbmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSkpXSkKCmRmIDwtIHJiaW5kKHNjbl9lbnJpY2hlZCwgcmV0aW5hX2VucmljaGVkLCBub3RlbnJpY2hlZCkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGFiZWxzX3VwcyA8LSBkZiB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPiAxKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgaGVhZChuID0gMTApCgpsYWJlbHNfZG93bnMgPC0gZGYgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBhYnMobG9nRkMpID4gMSkgfD4KICBhcnJhbmdlKC1sb2dGQykgfD4KICBoZWFkKG4gPSAxMCkKCmxhYmVscyA8LSByYmluZChsYWJlbHNfdXBzLCBsYWJlbHNfZG93bnMpCiMjIHdhbnRlZF9jb2x1bW4gPC0gIlNpZ25pZmljYW5jZSIKCnJlc190YmwgPC0gZGYKREVwbG90IDwtIGdncGxvdChyZXNfdGJsLCBhZXMoeCA9IGxvZ0ZDLCB5ID0gLWxvZzEwKGFkai5QLlZhbCksIGxhYmVsID0gZXh0ZXJuYWxfc3lub255bSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTaWduaWZpY2FuY2UpLCBzaXplID0gNCkgKwogICMjIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9ICEhc3ltKHdhbnRlZF9jb2x1bW4pKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB4bGFiKCJsb2cyKEZDKSIpICsKICB5bGFiKCItbG9nMTAocC12YWx1ZSkiKSArCiAgIyMgZ2d0aXRsZSh0aXRsZSwgc3VidGl0bGUgPSBzdWJ0aXRsZSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiR3JleSIsICIjRjg3NjZEIiwgIiMwMEJGQzQiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGZpbHRlcigKICAgIGRmLCBleHRlcm5hbF9zeW5vbnltICVpbiUgYyhsYWJlbHMkZXh0ZXJuYWxfc3lub255bSwgIk9wbjQiKSksCiAgICAjIyBjKCdzNV9oZXRfZGxnbicsICdzNV9oZXRfcmV0JywgJ3M1X2hldF9zY24nKSksCiAgICAjIyBudWRnZV94ID0gLTAuNSwKICAgIG51ZGdlX3kgPSAxMCwgbWF4Lm92ZXJsYXBzID0gMjUpCgpwcChmaWxlID0gImltYWdlcy9wMDhfcmV0aW5hdnNzY25rb19ERV8xMzEyMDI0LnBkZiIpCkRFcGxvdApwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3IsIGV2YWw9RkFMU0V9CnNjbl9lbnJpY2hlZApyZXRpbmFfZW5yaWNoZWQKbm90ZW5yaWNoZWQgfD4KICBmaWx0ZXIoU2lnbmlmaWNhbmNlID09ICJOb3RcbiBFbnJpY2hlZCIpCmBgYAoKIyMgR1NFQQoKYGBge3IsIGV2YWw9RkFMU0V9CmdzZWFfcmVzdWx0X3NjbiA8LSBnb3N0KHF1ZXJ5ID0gc2NuX2VucmljaGVkJGV4dGVybmFsX3N5bm9ueW0sCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlID0gYygiR08iKSkKCmdzZWFfcmVzdWx0X3JldCA8LSBnb3N0KHF1ZXJ5ID0gcmV0aW5hX2VucmljaGVkJGV4dGVybmFsX3N5bm9ueW0sCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlID0gYygiR08iKSkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9zY24gPC0gIGdzZWFfcmVzdWx0X3NjbltbInJlc3VsdCJdXSB8PgogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pIHw+CiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpIHw+CiAgaGVhZChuID0gMjApCmdzZWFfcGxvdHNfc2NuIDwtIGdncGxvdChnc2VhX3NjbiwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpwcChmaWxlID0gImltYWdlcy9HU0VBX1NDTmtvX2VucmljaGVkX3ZzX3JldGluYV9QMDgucGRmIikKZ3NlYV9wbG90c19zY24KcGxvdHRlZCA8LSBkZXYub2ZmKCkKCmdzZWFfcmV0IDwtICBnc2VhX3Jlc3VsdF9yZXRbWyJyZXN1bHQiXV0gfD4KICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSB8PgogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSB8PgogIGhlYWQobiA9IDIwKQpnc2VhX3Bsb3RzX3JldCA8LSBnZ3Bsb3QoZ3NlYV9yZXQsIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIkdTRUEgU2NvcmUiKQoKcHAoZmlsZSA9ICJpbWFnZXMvR1NFQV9SZXRpbmFrb19lbnJpY2hlZF92c19TQ05fUDA4LnBkZiIpCmdzZWFfcGxvdHNfcmV0CnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyBNeSB2ZXJzaW9uIG9mIHRoZSBnbG9iYWwgYW5hbHlzaXMKCkkgd2FudCB0byBoYXZlIGFuIGludm9jYXRpb24gb2YgYWxsX3BhaXJ3aXNlKCkgd2hpY2ggdXNlcyBhbGwgc2FtcGxlcywKaW4gdGhlIGZvbGxvd2luZyBibG9jayBJIHdpbGwgc2V0IHRoYXQgdXAgdXNpbmcgYSBzZXQgb2YgJ2tlZXBlcnMnCndoaWNoIHdpbGwgYmUgbmFtZWQgYnkgdGltZSwgbG9jYXRpb24sIHRoZW4gMiBsZXR0ZXJzIGZvciB0aGUKbnVtZXJhdG9yL2Rlbm9taW5hdG9yOiB3IGZvciBXVCwgaCBmb3IgaGV0LCBkIGZvciBkZWx0YTsgdGh1cwoicDA4X3JldGluYV9odyIgaXMgY29tcGFyaW5nIHRoZSBoZXQvd3QgZm9yIHRoZSBwMDggcmV0aW5hIHNhbXBsZXMuCgpJZiB0aGV5IGFyZSBvZiBpbnRlcmVzdCwgSSB3aWxsIGhhdmUgYSBzZXBhcmF0ZSBzZXQgd2hpY2ggZm9sbG93cyB0aGUKc2FtZSBjb252ZW50aW9uIHdpdGggbmFtZXMgbGlrZSAicDA4X2tvX3NyIiB0byBjb21wYXJlIHAwOCBkZWx0YXMgd2l0aApTQ04gYXMgdGhlIG51bWVyYXRvciBhbmQgcmV0aW5hIGFzIHRoZSBkZW5vbWluYXRvci4KCiMjIFNldCB1cCB0aGUgZXhjbHVzaW9uIGRhdGFzZXQKClRoZSBtb3N0IHBlY3VsaWFyIGFzcGVjdCBvZiB0aGlzIGFuYWx5c2lzIHJlc2lkZXMgaW4gdGhlIGNob2ljZXMKYXJvdW5kIGNob29zaW5nIHdoaWNoIGdlbmVzIHRvIGNvbnNpZGVyIHdoZW4gY29tcGFyaW5nIHRoZQpnZW5vdHlwZXMvbG9jYXRpb25zL3RpbWVzLiAgVGhlIGdlbmVyYWwgaWRlYSBpcyBwcmV0dHkgY2xlYXI6IGZpbmQgdGhlCmdlbmVzIHdoaWNoIGFyZSBub24tc3BlY2lmaWNhbGx5IGJlaW5nIHB1bGxlZCBkb3duIGluIHRoZSBXVCBzYW1wbGVzCmFuZCBlaXRoZXIgZXhjbHVkZSBvciBkaXNjb3VudCB0aGVtLiAgVGhlIHZhcmlvdXMgcG90ZW50aWFsIG1ldGhvZHMKZm9yIHBlcmZvcm1pbmcgdGhpcyBhcmUgY29uZnVzaW5nOgoKMS4gIFdoaWNoIHNldCBvZiBjb21wYXJpc29ucyBvZiB3dC9rbyB3dC9oZXQgZG8gd2UgdXNlIHRvCiAgICBleGNsdWRlL2Rpc2NvdW50IGdlbmVzPwogICAgYS4gIFNob3VsZCBpdCBiZSBhIGNvbWJpbmF0aW9uIG9mIGFsbCBzYW1wbGVzIHd0IHZzLiB4PwogICAgYi4gIFNob3VsZCBpdCBiZSBvbmx5IHRoZSAncmVsZXZhbnQnIGNvbXBhcmlzb24sIGUuZy4gaWYgd2UgYXJlCiAgICBjb21wYXJpbmcgcDA4X2RsZ25faGV0IHZzLiBwMDhfc2NuX2hldDsgZG8gd2UgcmVtb3ZlIGdlbmVzCiAgICBvYnNlcnZlZCBpbiAocDA4X2RsZ25faGV0L3d0ICYmIHAwOF9zY25faGV0L3d0KQoyLiAgRG8gd2UgaW5zdGVhZCBhdHRlbXB0IHRvIHVzZSB0aGlzIHgvd3QgaW5mb3JtYXRpb24gdG8gbm9ybWFsaXplCiAgICB0aGUgZXhwcmVzc2lvbiB2YWx1ZXMgaW4gdGhlIG90aGVyIGNvbmRpdGlvbnMgYW5kIGtlZXAgdGhvc2UKICAgIGdlbmVzPwoKVGhlcmVzYSdzIGN1cnJlbnQgd29ya3NoZWV0IGltcGxlbWVudHMgYSB2ZXJzaW9uIG9mIDFiIGluIHdoaWNoIHNoZQpzZXBhcmF0ZWQgdGhlIHZhcmlvdXMgaW5wdXQgZ2VuZSBzZXRzIHRvIGRlZmluZSB0aGUgZXhjbHVzaW9uIGdlbmVzLgpJIGFtIGdvaW5nIHRvIHJlcGVhdCB0aGlzLCBidXQgbGVhdmUgdGhlIHN0YXJ0aW5nIGRhdGEgc3RydWN0dXJlCmludGFjdC4KCkluIHRoaXMgZmlyc3QgaXRlcmF0aW9uLCBJIHdpbGwgZG8gdGhhdCBieSBjcmVhdGluZyBhIHNpbXBsaWZpZWQgbW9kZWwKb2YgdGhlIGRhdGEgd2hpY2ggY29tYmluZXMgdGhlIHRpbWUvZ2Vub3R5cGUvbG9jYXRpb24gYW5kIHVzaW5nIHN2YS4KSW4gbXkgbmV4dCBpdGVyYXRpb24gSSB3aWxsIHVzZSBhIGZ1bGwgc3RhdGlzdGljYWwgbW9kZWwgY29udGFpbmluZwplYWNoIG9mIHRob3NlIGZhY3RvcnMgKGFuZCBwcm9iYWJseSBhbHNvIHVzaW5nIHN2YSkuCgpOb3RlOiBteSBjb2xvciBjaG9pY2VzIGFyZSBraW5kIG9mIGdhcmJhZ2UuCgpJbiBhZGRpdGlvbiwgdGhlIGV4Y2x1c2lvbiBkYXRhc2V0IGlzIHRoZSBzYW1lIGFzIHRoZSBhbmFseXNpcwpkYXRhc2V0LCBpdCBpcyByZWFsbHkgb25seSB0aGUgY29udHJhc3RzIHdoaWNoIHdpbGwgYmUgZGlmZmVyZW50LgoKYGBge3J9CnYzX3BhaXJ3aXNlX2lucHV0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfaGlzYXRfdjMsIGZhY3QgPSAidGltZV9nZW5vX2xvYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX2Nob2ljZXNbWyJhbGwiXV0pCmBgYAoKIyMgQSBoZWF0bWFwIG9mIHNwZWNpZmljIGdlbmVzIGFjcm9zcyBhbGwgY29uZGl0aW9ucwoKYGBge3J9CmFsbF9jb25kX2dlbmVfaGVhdG1hcF9zdGFydCA8LSBub3JtYWxpemUodjNfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9ICJzaW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aF9jb2x1bW4gPSAiY2RzX2xlbmd0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydCA9ICJycGttIiwgdHJhbnNmb3JtID0gImxvZzIiKQphbGxfY29uZF9nZW5lX2hlYXRtYXBfaW5wdXQgPC0gbWVkaWFuX2J5X2ZhY3RvcihhbGxfY29uZF9nZW5lX2hlYXRtYXBfc3RhcnQpCmFsbF9jb25kX210cnggPC0gYWxsX2NvbmRfZ2VuZV9oZWF0bWFwX2lucHV0W1sibWVkaWFucyJdXQpjb2xvcl9vcmRlciA8LSBjb2xuYW1lcyhhbGxfY29uZF9tdHJ4KQpuYV9pZHggPC0gaXMubmEoYWxsX2NvbmRfbXRyeCkKYWxsX2NvbmRfbXRyeFtuYV9pZHhdIDwtIDAKdmFyaWFuY2VzIDwtIG1hdHJpeFN0YXRzOjpyb3dWYXJzKGFzLm1hdHJpeChhbGxfY29uZF9tdHJ4KSkKdmFyaWFudF9nZW5lcyA8LSB2YXJpYW5jZXMgPiA2LjIKaW5wdXRfbXRyeCA8LSBhbGxfY29uZF9tdHJ4W3ZhcmlhbnRfZ2VuZXMsIF0KY29uZF9jb2xvcnMgPC0gZ2V0X2NvbG9yc19ieV9jb25kaXRpb24odjNfcGFpcndpc2VfaW5wdXQsIGxldmVscyA9IGNvbG9yX29yZGVyKQpkaW0oaW5wdXRfbXRyeCkKCmlucHV0X2hlYXRtYXAgPC0gZ3Bsb3RzOjpoZWF0bWFwLjIoYXMubWF0cml4KGlucHV0X210cngpLCBzY2FsZSA9ICJub25lIiwgdHJhY2UgPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29sU2lkZUNvbG9ycyA9IGNvbmRfY29sb3JzKQpwcChmaWxlID0gIjA0aW5jbHVzaW9uX2NvbXBhcmlzb25zL3RvcF8xMDRfdmFyaWFudF9ycGttX2dlbmVzX2hlYXRtYXAucGRmIikKaW5wdXRfaGVhdG1hcCA8LSBncGxvdHM6OmhlYXRtYXAuMihhcy5tYXRyaXgoaW5wdXRfbXRyeCksIHNjYWxlID0gIm5vbmUiLCB0cmFjZSA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2xTaWRlQ29sb3JzID0gY29uZF9jb2xvcnMpCmRldi5vZmYoKQpgYGAKCiMgVE9ETzogQ2hhbmdlIHRoZSBhYm92ZSB0byBzdWJ0cmFjdCB3dAoKUmFzaG1pIHN1Z2dlc3RlZCB3ZSBzaG91bGQgZG8gdGhlIGFib3ZlIHBsb3QgYWZ0ZXIgc3VidHJhY3RpbmcgdGhlIHd0CmNvdW50cy4gIFRoaXMgaXMgYSBnb29kIGlkZWEsIGJ1dCBpdCB3aWxsIGhhdmUgdG8gd2FpdCB1bnRpbCB3ZSBmaW5pc2gKdGhlIGN1cnJlbnQgc2V0LgoKIyMgU2V0IHVwIHRoZSBjb250cmFzdHMKCkluIHRoZSBmb2xsb3dpbmcgZmV3IGJsb2NrcyBJIHdpbGwgc2V0IHVwIHRoZSB2YXJpb3VzIGNvbXBhcmlzb25zIG9mCmludGVyZXN0LiAgU3RhcnRpbmcgd2l0aCB0aGUgc2V0IG9mIGdlbmVzIHRvIGV4Y2x1ZGUgYmVjYXVzZSB0aGV5IHdlcmUKb2JzZXJ2ZWQgdG8gYmluZCBub24tc3BlY2lmaWNhbGx5IGluIHRoZSB3dCBzYW1wbGVzLgoKIyMjIEluY2x1c2lvbiBjb250cmFzdHMKCkluIGVhY2ggZXhjbHVzaW9uIEkgd2lsbCBoYXZlIHRoZSBjb250cmFzdCBmaXJzdCBmb2xsb3dlZCBieSB0aGUgcGFpcgpvZiBjb250cmFzdHMgd2hpY2ggd2lsbCBiZSB1c2VkIHRvIGRlZmluZSB0aGUgZ2VuZSBzZXQgdG8gZXhjbHVkZS4KCiogcDE1X2hldF9kbGduL3AwOF9oZXRfZGxnbjogcDE1X3d0X2RsZ24vcDE1X2hldF9kbGduLAogIHAwOF93dF9kbGduL3AwOF9oZXRfZGxnbjsgcmVtb3ZlIHRoZSBnZW5lcyBpbmNyZWFzZWQgaW4gd3QuCiogcDE1X2tvX3Njbi9wMDhfa29fc2NuOiBwMTVfd3Rfc2NuL3AxNV9rb19zY24sIHAwOF93dF9zY24vcDE1X2tvX3NjbgoqIHAxNV9oZXRfcmV0aW5hL3AwOF9oZXRfcmV0aW5hOiBJIHRoaW5rIHlvdSBnZXQgaXQsIHd0L2hldCBmb3IgYm90aAogIHAxNSByZXRpbmFzIGFuZCBwMDggcmV0aW5hcy4uLgoKUHV0IHNsaWdodGx5IGRpZmZlcmVudGx5LCBmb3IgZXZlcnkgdGVybSBvZiBpbnRlcmVzdCBJIHdpbGwgY3JlYXRlIGEKY29udHJhc3Qgd2l0aCB0aGUgd3QgYXMgbnVtZXJhdG9yIGFuZCB0aGUgZGVzaXJlZCB0ZXJtIGFzIGRlbm9taW5hdG9yLAp0aGVuIHB1bGwgb3V0IHRoZSBnZW5lcyBpbmNyZWFzZWQgaW4gd3QuCgojIyMgUG90ZW50aWFsIHRleHQgZGVzY3JpYmluZyBmaWx0ZXJpbmcKClRoaXMgZGF0YXNldCBpbmNsdWRlcyB3aWxkLXR5cGUgbWljZSBmb3IgZWFjaCBjb25kaXRpb247IHRoaXMgcHJvdmlkZWQKYW4gb3Bwb3J0dW5pdHkgdG8gZmlsdGVyIG91dCB0aGUgbW9zdCBsaWtlbHkgZmFsc2UgcG9zaXRpdmUKZ2VuZXMvdHJhbnNjcmlwdHMuICBXaGVuIHRoZSBzYW1wbGVzIHdlcmUgcHJvY2Vzc2VkIGFuZCB0aGUgdGFnZ2VkCmxhcmdlIHJpYm9zb21hbCBzdWJ1bml0cyB3ZXJlIHB1bGxlZCBkb3duLCBpdCB3YXMgYXNzdW1lZCB0aGF0IGF0CmxlYXN0IHNvbWUgb3RoZXIgdHJhbnNjcmlwdHMgd2VyZSBsaWtlbHkgdG8gYmluZCB0byB0aGUgY29sdW1uIGFuZAp0aGVyZWZvcmUgZW5kIHVwIGluIHRoZSBzZXF1ZW5jaW5nIGxpYnJhcmllcy4gIElmIG9uZSBhc3N1bWVzIHRoYXQKdGhpcyBkaXN0cmlidXRpb24gaXMgY29uc2lzdGVudCBvdmVyIHRpbWUsIGdlbm90eXBlLCBhbmQgbG9jYXRpb247CnRoZW4gYSBsaWtlbHkgc3RyYXRlZ3kgd291bGQgYmUgdG8gdGFrZSB0aGUgbWVhbiB2YWx1ZSBvZiBhbGwgb2JzZXJ2ZWQKd2lsZC10eXBlIHNhbXBsZXMgYW5kIGV4Y2x1ZGUgYW55IGdlbmVzL3RyYW5zY3JpcHRzIGZvciB3aGljaCB0aGUKaGV0ZXJvenlnb3VzIGFuZC9vciBrbm9ja291dCBzYW1wbGVzIGhhdmUgbG93ZXIgb2JzZXJ2ZWQgYWJ1bmRhbmNlCnRoYW4gdGhpcyBtZWFuLiAgV2UgdGhlcmVmb3JlIHBlcmZvcm1lZCB0aGUgY29tcGFyaXNvbnMgb2YgdGhlCndpbGQtdHlwZSBzYW1wbGVzIGJ5IHRpbWUgYW5kIGxvY2F0aW9uIGFuZCBvYnNlcnZlZCBzaWduaWZpY2FudAp2YXJpYW5jZTsgdGh1cyB3ZSBjaG9zZSBpbnN0ZWFkIHRvIGV4Y2x1ZGUgZ2VuZXMvdHJhbnNjcmlwdHMgd2hpY2ggYXJlCmxvd2VyIGluIHRoZSBoZXRlcnp5Z291cyBhbmQga25vY2stb3V0IHNhbXBsZXMgdGhhbiBhbnkgb2YgdGhlIGNvbWl0YW50CndpbGQtdHlwZSBjb25kaXRpb25zLiAgQXMgYW4gZXhhbXBsZSwgaWYgdGhlIGRlc2lyZWQgY29udHJhc3QgaXMgdG8KY29tcGFyZSBoZXRlcnp5Z291cyByZXRpbmEgLyBrbm9ja291dCByZXRpbmEgYXQgcDA4OyB0aGVuIHRoZSBzZXQgb2YKb2JzZXJ2ZWQgYWJ1bmRhbmNlcyB3YXMgZmlyc3QgY29tcGFyZWQgYWdhaW5zdCB0aGUgcDA4IHd0IHJldGluYQpzYW1wbGVzIGFuZCBmaWx0ZXJlZCB0byBpbmNsdWRlIG9ubHkgdGhvc2Ugd2hpY2ggd2VyZSBkZWVtZWQgaGlnaGVyCndoZW4gY29tcGFyaW5nIHRoZSAocDA4IGhldGVyb3p5Z291cyByZXRpbmEgLyBwMDggd2lsZC10eXBlIHJldGluYSkKYW5kIChwMDgga25vY2tvdXQgcmV0aW5hIC8gcDA4IHdpbGQtdHlwZSByZXRpbmEpIHZpYSBERVNlcTIsIHdpdGggYQpsZXNzIHN0cmluZ2VudCBkZWZpbml0aW9uIG9mIHNpZ25pZmljYW50IChhZGp1c3RlZCBwLXZhbHVlIDw9IDAuMSBhbmQKbG9nRkMgPj0gMC4xKS4gIFR3byB2ZXJzaW9ucyBvZiB0aGlzIGZpbHRlciB3ZXJlIGFwcGxpZWQsIG9uZSB3aGljaApyZXF1aXJlZCBlaXRoZXIgdGhlIG51bWVyYXRvciBvciBkZW5vbWluYXRvciB0byBiZSBoaWdoZXIgdGhhbiB0aGUKY29ycmVzcG9uZGluZyB3aWxkLXR5cGUgc2FtcGxlczsgYW5kIG9uZSB3aGljaCByZXF1aXJlZCBib3RoIHRvIGJlCmhpZ2hlciB0aGFuIHRoZSB3aWxkLXR5cGUgc2FtcGxlcy4gIFRoZSBtZWFuIG5vcm1hbGl6ZWQgZXhwcmVzc2lvbgp2YWx1ZXMgd2VyZSByZXBvcnRlZCB3aXRoIGVhY2ggb2YgdGhlc2UgY29tcGFyaXNvbnMgc28gdGhhdCBvbmUgbWF5CnBlcmZvcm0gb3RoZXIgZmlsdGVycyBhcyBkZXNpcmVkLgoKSSB3aWxsIHB1dCB0aGlzIHNsaWdodGx5IGRpZmZlcmVudGx5LCBjb3B5LXBhc3RpbmcgdGhlIG9ic2VydmVkIHNldCBvZgpnZW5lcyBpbmNyZWFzZWQgaW4gdGhlIG5vbi13dCBjb25kaXRpb24gdG8gc2hvdyB0aGUgcmVzdWx0OgoKTEZDIGN1dG9mZjogMC4xIGFkaiBQIGN1dG9mZjogMC4xCiAgICAgICAgICAgICAgIGRlc2VxX3VwCnAxNV9oZXRfZGxnbiAgICAgICAyMDY3CnAwOF9oZXRfZGxnbiAgICAgICAgMTgwCnAxNV9rb19kbGduICAgICAgICAyNTQ0CnAwOF9rb19kbGduICAgICAgICAgMzk3CnAxNV9oZXRfcmV0aW5hICAgICAgNDAyCnAwOF9oZXRfcmV0aW5hICAgICAgOTc2CnAxNV9rb19yZXRpbmEgICAgICAgMzQ3CnAwOF9rb19yZXRpbmEgICAgICAxNTUxCnAxNV9oZXRfc2NuICAgICAgICAgIDE1CnAwOF9oZXRfc2NuICAgICAgICAgMjI1CnAxNV9rb19zY24gICAgICAgICAgICA4CnAwOF9rb19zY24gICAgICAgICAgMTEyCgpXaGVuIGNvbXBhcmluZyBhZ2FpbnN0IHRoZSBkTEdOIHdpbGQtdHlwZXMsIHRoZXJlIGFyZSBiZXR3ZWVuIDE4MCBhbmQKMiw1NDQgZ2VuZXMgd2hpY2ggcGFzcyB0aGUgZmlsdGVyLiAgVGhlIHJldGluYSBmaWx0ZXIgcGFzc2VzIGJldHdlZW4KMzQ3IGFuZCAxLDU1MSBnZW5lcy4gIFRoZSBTQ04gZmlsdGVyIHBhc3NlcyBmYXIgZmV3ZXIgZ2VuZXMsIHJhbmdpbmcKZnJvbSA4IHRvIDIyNS4KCklmIHdlIGZpbHRlciBiYXNlZCBvbiB0aGUgaW50ZXJzZWN0aW9uIG9mIGdlbmVzIHdoaWNoIHBhc3MgdGhlc2UsIHRoZW4KYW55IGNvbnRyYXN0IHdoaWNoIGluY2x1ZGVzIFNDTiBzYW1wbGVzIHdpbGwgaGF2ZSB+IDAgZ2VuZXMgb2YKaW50ZXJlc3QgYnkgZGVmaW5pdGlvbi4gIFRodXMsIHdlIGNob3NlIHRvIGFsbG93IGdlbmVzIHdoaWNoIHBhc3MgdGhlCnVuaW9uIG9mIGVpdGhlciB0aGUgbnVtZXJhdG9yIG9yIGRlbm9taW5hdG9yIGZpbHRlci4gIEluIHRoaXMgaW5zdGFuY2UsCndlIHJldGFpbiBhIHNpZ25pZmljYW50IG51bWJlciBvZiBnZW5lcyBhcyBsb25nIGFzIHdlIGFyZSBub3QKcmVzdHJpY3RlZCB0byBvbmx5IFNDTiBzYW1wbGVzLgoKYGBge3J9CmluY2x1c2lvbnMgPC0gbGlzdCgKICAjIyBJIGxpa2UgYWxwaGFiZXRpemluZyB0aGluZ3MsIHN0YXJ0IHdpdGggZGxnbgogICJwMTVfaGV0X2RsZ24iID0gYygicDE1X2hldF9kbGduIiwgInAxNV93dF9kbGduIiksCiAgInAwOF9oZXRfZGxnbiIgPSBjKCJwMDhfaGV0X2RsZ24iLCAicDA4X3d0X2RsZ24iKSwKICAicDE1X2tvX2RsZ24iID0gYygicDE1X2tvX2RsZ24iLCAicDE1X3d0X2RsZ24iKSwKICAicDA4X2tvX2RsZ24iID0gYygicDA4X2tvX2RsZ24iLCAicDA4X3d0X2RsZ24iKSwKICAjIyBUaGVuIHJldGluYXMKICAicDE1X2hldF9yZXRpbmEiID0gYygicDE1X2hldF9yZXRpbmEiLCAicDE1X3d0X3JldGluYSIpLAogICJwMDhfaGV0X3JldGluYSIgPSBjKCJwMDhfaGV0X3JldGluYSIsICJwMDhfd3RfcmV0aW5hIiksCiAgInAxNV9rb19yZXRpbmEiID0gYygicDE1X2tvX3JldGluYSIsICJwMTVfd3RfcmV0aW5hIiksCiAgInAwOF9rb19yZXRpbmEiID0gYygicDA4X2tvX3JldGluYSIsICJwMDhfd3RfcmV0aW5hIiksCiAgIyMgVGhlbiBzY24KICAicDE1X2hldF9zY24iID0gYygicDE1X2hldF9zY24iLCAicDE1X3d0X3NjbiIpLAogICJwMDhfaGV0X3NjbiIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfd3Rfc2NuIiksCiAgInAxNV9rb19zY24iID0gYygicDE1X2tvX3NjbiIsICJwMTVfd3Rfc2NuIiksCiAgInAwOF9rb19zY24iID0gYygicDA4X2tvX3NjbiIsICJwMDhfd3Rfc2NuIikpCmBgYAoKIyMjIFRpbWUgY29udHJhc3RzCgpGb3IgZWFjaCBsb2NhdGlvbi9nZW5vdHlwZSBvZiBpbnRlcmVzdCwgbGV0IHVzIGNvbXBhcmUgcDE1L3AwOAoKYGBge3J9CnRpbWVfa2VlcGVycyA8LSBsaXN0KAogICMjIERMR04KICAidF9oZXRfZGxnbiIgPSBjKCJwMTVfaGV0X2RsZ24iLCAicDA4X2hldF9kbGduIiksCiAgInRfa29fZGxnbiIgPSBjKCJwMTVfa29fZGxnbiIsICJwMDhfa29fZGxnbiIpLAogICMjIFJldGluYQogICJ0X2hldF9yZXRpbmEiID0gYygicDE1X2hldF9yZXRpbmEiLCAicDA4X2hldF9yZXRpbmEiKSwKICAidF9rb19yZXRpbmEiID0gYygicDE1X2tvX3JldGluYSIsICJwMDhfa29fcmV0aW5hIiksCiAgIyMgU0NOCiAgInRfaGV0X3NjbiIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMDhfaGV0X3NjbiIpLAogICJ0X2tvX3NjbiIgPSBjKCJwMTVfa29fc2NuIiwgInAwOF9rb19zY24iKSkKYGBgCgojIyMgTG9jYXRpb24gY29udHJhc3RzCgpDb21wYXJlIGxvY2F0aW9ucyBhbmQga2VlcCB0aW1lL2dlbm90eXBlIGNvbnNpc3RlbnQuICBJIHdpbGwgdXNlIHRoZQpsb2NhdGlvbiBpbml0aWFscyB0byBkZWZpbmUgbnVtZXJhdG9yL2Rlbm9taW5hdG9yLgoKYGBge3J9CmxvY2F0aW9uX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBkbGduL3JldGluYQogICJkcl9wMDhfaGV0IiA9IGMoInAwOF9oZXRfZGxnbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJkcl9wMTVfaGV0IiA9IGMoInAxNV9oZXRfZGxnbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJkcl9wMDhfa28iID0gYygicDA4X2tvX2RsZ24iLCAicDA4X2tvX3JldGluYSIpLAogICJkcl9wMTVfa28iID0gYygicDE1X2tvX2RsZ24iLCAicDE1X2tvX3JldGluYSIpLAogICMjIHNjbi9yZXRpbmEKICAic3JfcDA4X2hldCIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJzcl9wMTVfaGV0IiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInNyX3AwOF9rbyIgPSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiKSwKICAic3JfcDE1X2tvIiA9IGMoInAxNV9rb19zY24iLCAicDE1X2tvX3JldGluYSIpLAogICMjIGRsZ24vc2NuCiAgImRzX3AwOF9oZXQiID0gYygicDA4X2hldF9kbGduIiwgInAwOF9oZXRfc2NuIiksCiAgImRzX3AxNV9oZXQiID0gYygicDE1X2hldF9kbGduIiwgInAxNV9oZXRfc2NuIiksCiAgImRzX3AwOF9rbyIgPSBjKCJwMDhfa29fZGxnbiIsICJwMDhfa29fc2NuIiksCiAgImRzX3AxNV9rbyIgPSBjKCJwMTVfa29fZGxnbiIsICJwMTVfa29fc2NuIikpCmBgYAoKIyMjIEdlbm90eXBlIGNvbnRyYXN0cwoKQ29tcGFyZSBrby9oZXQgd2hpbGUga2VlcGluZyB0aW1lL2xvY2F0aW9uIGNvbnN0YW50LiAgU2ltaWxhcmx5LCB1c2UKdGhlIGluaXRpYWxzIHRvIGRlbm90ZSBudW1lcmF0b3IvZGVub21pbmF0b3IsIHdoaWNoIHdpbGwgYWx3YXlzIGJlIGtoLgoKYGBge3J9Cmdlbm90eXBlX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBETEdOCiAgImtoX3AwOF9kbGduIiA9IGMoInAwOF9rb19kbGduIiwgInAwOF9oZXRfZGxnbiIpLAogICJraF9wMTVfZGxnbiIgPSBjKCJwMTVfa29fZGxnbiIsICJwMTVfaGV0X2RsZ24iKSwKICAjIyBSZXRpbmEKICAia2hfcDA4X3JldGluYSIgPSBjKCJwMDhfa29fcmV0aW5hIiwgInAwOF9oZXRfcmV0aW5hIiksCiAgImtoX3AxNV9yZXRpbmEiID0gYygicDE1X2tvX3JldGluYSIsICJwMTVfaGV0X3JldGluYSIpLAogICMjIFNDTgogICJraF9wMDhfc2NuIiA9IGMoInAwOF9rb19zY24iLCAicDA4X2hldF9zY24iKSwKICAia2hfcDE1X3NjbiIgPSBjKCJwMTVfa29fc2NuIiwgInAxNV9oZXRfc2NuIikpCmBgYAoKIyMgUGVyZm9ybSB0aGUgZXhjbHVzaW9uIGNvbXBhcmlzb24KCk15IGFsbF9wYWlyd2lzZSgpIGZ1bmN0aW9uIG5vdyBoYXMgYSBwYXJhbWV0ZXIgd2hpY2ggYWxsb3dzIG1lIHRvCmNob29zZSB3aGljaCBjb250cmFzdHMgdG8gcGVyZm9ybSBpbnN0ZWFkIG9mIGxpdGVyYWxseSBkb2luZyBldmVyeQpwb3NzaWJsZSBjb21wYXJpc29uLiAgVGhhdCBpcyB3ZWxsIHN1aXRlZCBmb3IgdGhlc2Ugb3BlcmF0aW9ucy4KCmBgYHtyfQppbmNsdXNpb25fZGUgPC0gYWxsX3BhaXJ3aXNlKAogIHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSAic2ltcGxlIiwgbW9kZWxfZnN0cmluZyA9IGRlZmF1bHRfZnN0cmluZywKICBrZWVwZXJzID0gaW5jbHVzaW9ucywgbW9kZWxfc3ZzID0gInN2YXNlcSIpCmluY2x1c2lvbl9kZQoKaW5jbHVzaW9uX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBpbmNsdXNpb25fZGUsIGtlZXBlcnMgPSBpbmNsdXNpb25zLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIwNGluY2x1c2lvbl9jb21wYXJpc29ucy9pbmNsdXNpb25fdGFibGVzLXZ7dmVyfS54bHN4IikpCmluY2x1c2lvbl90YWJsZXMKIyMgMjAyNjAzOiBJIHN1Y2Nlc3NmdWxseSByZWNhcGl0dWxhdGVkIHByZXZpb3VzIG5vbi1jb250YWluZXIgcmVzdWx0LgojIyAyMDI2MDg6IFJlY2FwaXR1bGF0ZWQgYWdhaW5zdCB0aGUgMjAyNjAzIHJlc3VsdHMhCgppbmNsdXNpb25fc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaW5jbHVzaW9uX3RhYmxlcywgbGZjID0gZmlsdGVyX2xmY19jdXRvZmYsIHAgPSBmaWx0ZXJfYWRqcF9jdXRvZmYsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCIwNGluY2x1c2lvbl9jb21wYXJpc29ucy9pbmNsdXNpb25fc2lnLXZ7dmVyfS54bHN4IikpCmluY2x1c2lvbl9zaWcKYGBgCgoyMDI2MDg6IEkgYW0gc2VlaW5nIGEgdGlueSBzaGlmdCBpbiBwLXZhbHVlcy9sb2dGQyBhY3Jvc3MgYWxsIGNvbnRyYXN0cyBhbmQKbWV0aG9kczsgaXQgaXMgc28gc21hbGwgdGhhdCBub3JtYWxseSBJIHdvdWxkIG5vdCBzZWUgaXQuICBJbgphZGRpdGlvbiwgaWYgb25lIGxvb2tzIGF0IHRoZSBtZXRhZGF0YSB0YWIgaW4gdGhlIG91dHB1dCBwYWlyd2lzZSB4bHN4CmZpbGUgKGluY2x1c2lvbl90YWJsZXMtdjIwMjUwNTE1Lnhsc3ggY29tcGFyZWQgdG8KaW5jbHVzaW9uX3RhYmxlcy12MjAyNjA4MjAueGxzeCBmb3IgZXhhbXBsZSksIHRoZXkgaW5jbHVkZSB0aGUgbWVhbgp2YWx1ZXMgYW5kIHN1cnJvZ2F0ZSB2YXJpYWJsZXMgZnJvbSBzdmEgLS0gdGhlc2UgYXJlIGV4YWN0bHkgaWRlbnRpY2FsCnRvIHRoZSBudW1iZXIgb2YgZGlnaXRzIGF2YWlsYWJsZSBpbiBleGNlbC9SLiAgV2UgY2FuIGdvIG9uZSBzdGVwCmZ1cnRoZXIgYW5kIG9ic2VydmUgdGhhdCB0aGUgdmFyaW91cyBtZXRyaWNzIG9mIGJlYXNtZWFuIGFuZCBzdWNoLgoKIiIiCjEuICBXaGVuIHdlIHN0YXJ0IHRoZSBERVNlcSB0byBnZW5lcmF0ZSB0aGUgc2V0IG9mIGluY2x1ZGVkIGdlbmVzOgogIGEuICBUaGUgaW5wdXQgZGF0YSBpcyBleGFjdGx5IGlkZW50aWNhbCBiZXR3ZWVuIDIwMjUwMyBhbmQgdG9kYXkgLS0KICBJIGNhbiBzZWUgdGhhdCBpbiBhIGZldyBwbGFjZXMsIHdoZW4gY29tcGFyaW5nIHRoZSB4bHN4IG91dHB1dHMgdGhlCiAgZWFzaWVzdCBhcmUgdGhlICUgdmFyaWFuY2UgaW4gdGhlIFBDQSBwbG90cyBvbiBzaGVldCAjMSBhbmQgdGhlCiAgYmFzZW1lYW4gdmFsdWVzIGluIGFsbCB0aGUgZm9sbG93aW5nIHNoZWV0cy4gIFRoZXkgYXJlIGlkZW50aWNhbCBmb3IKICBldmVyeSBnZW5lIG9uIGV2ZXJ5IHNoZWV0IEkgY2hlY2tlZCAofjEwIGdlbmVzIG9uIDMgc2hlZXRzIGVhY2gKICByYW5naW5nIGFjcm9zcyB0aGUgdG9wIGFuZCBib3R0b20gNTAwIG1vc3QgZXhwcmVzc2VkIGdlbmVzKS4KICBiLiAgVGhlIGZpcnN0IHN0ZXAgb2YgdGhlIERFIGFuYWx5c2lzIGlzIHRvIGludm9rZSBzdmEgYW5kIGNhbGN1bGF0ZQogIHRoZSBhZGRpdGlvbnMgdG8gdGhlIG1vZGVsLiAgVGhlc2UgZ2V0IHByaW50ZWQgdG8gdGhlIG1ldGFkYXRhIHNoZWV0CiAgb2YgdGhlIHhsc3ggZmlsZSBhbmQgYXJlIGV4YWN0bHkgaWRlbnRpY2FsLgoKICBTbywgSSBrbm93IGZvciBjZXJ0YWluIHRoYXQgdGhlIGlucHV0IHRvIGFsbCBtZXRob2RzIGlzIHRoZSBzYW1lCiAgZnJvbSAyMDI1MDMgdG8gbm93LiAgSSBhbHNvIGtub3cgZm9yIGNlcnRhaW4gdGhhdCBldmVyeSBtb2RlbCBnb3QKICB0aGUgc2FtZSBzdXJyb2dhdGVzLgoKMi4gIFRoZSBsb2dGQyB2YWx1ZXMgZm9yIGV2ZXJ5IG1ldGhvZCBoYXZlIHNoaWZ0ZWQgYnkgYmV0d2VlbiAwIGFuZAogICAgMC4wMSwgaW5jbHVkaW5nIG15IGJhc2ljIG1ldGhvZC4KMy4gIFRoZSBwLXZhbHVlcyBoYXZlIHNoaWZ0ZWQgYnkgYmV0d2VlbiAwIGFuZCAwLjAwMDEgZm9yIGV2ZXJ5IG1ldGhvZC4KNC4gIFRoZSBhZGp1c3RlZCBwLXZhbHVlcyBoYXZlIHNoaWZ0ZWQgYnkgYmV0d2VlbiAwIGFuZCAwLjAwMSBmb3IgZXZlcnkgbWV0aG9kLgoKSSBoYXZlIGdvbmUgdGhyb3VnaCBldmVyeSBsaW5lIHdoaWNoIHBlcmZvcm1zIHRoZSBkaWZmZXJlbnRpYWwKZXhwcmVzc2lvbiBhbmQgSSBkbyBub3Qgc2VlIGFueSBjaGFuZ2VzIGJldHdlZW4gMjAyNSBhbmQgbm93LgoKVGhlIGVuZCByZXN1bHQgaXMgdGhhdCB0aGUgc2V0IG9mICdzaWduaWZpY2FudCcgZ2VuZXMgZm9yIGV2ZXJ5CmNvbnRyYXN0IGluIGV2ZXJ5IGNvbXBhcmlzb24gaXMgZXhhY3RseSB0aGUgc2FtZS4gIEhvd2V2ZXIsIHdlIGFyZQpleHRyYWN0aW5nIGdlbmVzIHdoaWNoIGFyZSBfaW5zaWduaWZpY2FudGx5XyBoaWdoZXIgaW4gdGhlIGNvbmRpdGlvbgp2cy4gd3QgYW5kIHRoaXMgc2V0IG9mIGdlbmVzIGhhcyBkZWNyZWFzZWQgYnkgYmV0d2VlbiAwIGFuZCAxMCBnZW5lcwphY3Jvc3MgdGhlIGNvbXBhcmlzb25zIHdoaWNoIGluIHRoZSBjYXNlIG9mIHRoZSBTQ04gc2FtcGxlcyB3aGljaAphbHJlYWR5IGhhdmUgdmVyeSBmZXcgcmVzdWx0cyBpbiBhIG5vdGljZWFibGUgZGlmZmVyZW5jZS4KCiIiIgoKTGV0IHVzIHRyeSBhIHZlcnkgc2xpZ2h0bHkgZGlmZmVyZW50IGZpbHRlciB3aGVuIGludm9raW5nIERFU2VxMj8KRGFtbml0IEkgZG9uJ3Qga25vdy4gIFRoZSBmb2xsb3dpbmcgaXMgdGhlIGludm9jYXRpb24gcHJvZHVjZWQgYnkKYWxsX3BhaXJ3aXNlKCkKCmBgYHtyfQp0ZXN0X2RpZmYgPC0gZGVzZXEyX3BhaXJ3aXNlKHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSAic2ltcGxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gZGVmYXVsdF9mc3RyaW5nLCBrZWVwZXJzID0gaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwgbnVsbF9mc3RyaW5nID0gIn4iLCBleHRyYV9jb250cmFzdHMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90X2RmID0gTlVMTCwgZm9yY2UgPSBGQUxTRSwgZGVzZXFfbWV0aG9kID0gImxvbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdHR5cGUgPSAicGFyYW1ldHJpYyIsIG51bV9zdXJyb2dhdGVzID0gImJlIiwga2VlcF91bmRlcnNjb3JlID0gVFJVRSkKYGBgCgpJIGFtIHJ1bm5pbmcgdGhhdCB1bmRlciB0aGUgZGVidWdnZXIsIEkgYW0gbm93IGF0IHRoZSBzdGVwIHdoaWNoCnByb2R1Y2VzIHRoZSBtZXRob2Qtc3BlY2lmaWMgc3Vycm9nYXRlIHZhcmlhYmxlczsgd2hlbiBydW4gdW5kZXIKYWxsX3BhaXJ3aXNlLCBpdCBwcm9kdWNlcyB0aGUgU1ZzIGZvciBhbGwgbWV0aG9kcyBhdCB0aGUgc2FtZSB0aW1lIGFuZApwYXNzZXMgdGhlbSBhbG9uZy4gIFNWMyBpcyB0aGUgbW9zdCBzZW5zaXRpdmUgdG8gZGlmZmVyZW5jZXMsIHNvIEkKd2lsbCBjaGVjayB0aGUgZmlyc3QgZmV3IGVudHJpZXMgZm9yIFNWMiBhbmQgU1YzLiAgU2FtcGxlIGlwcmdjXzg2IGluCnRoZSAyMDI1MDMgeGxzeCBmaWxlIGhhcyBTVjMgYXMgLTAuMTY1NzkzMi4gIEluIG15IFIgc2Vzc2lvbiBJIHNlZQpleGFjdGx5IHRoYXQuICBJIHdlbnQgb24gdG8gY2hlY2sgU1ZzIDEsMiwzIGZvciB0aGUgZmlyc3QgMTggc2FtcGxlcywKdGhleSBhcmUgYWxsIGlkZW50aWNhbC4KCk9uZSB3ZWlyZCBsaXR0bGUgY2hhbmdlIEkgZGlkIG5vdGljZSwgSSBoYXZlIHNvbWUgbG9naWMgdG8gY2hlY2sgaWYKdGhlIGlucHV0IGlzIGZpbHRlcmVkOyBvbmUgdGVybSB3YXMgYmFja3dhcmQgYW5kIEkgZml4ZWQgaXQuICBJIGRvIG5vdAp0aGluayB0aGF0IG1hdHRlcnM7IGJ1dCBvbmUgdGVzdCBJIHdpbGwgYXBwbHkgaXMgdG8gcmVwZWF0IHRoZSBERQphbmFseXNpcyB3aXRoIHRoZSBwcmUgYW5kIHBvc3QgZmlsdGVyZWQgaW5wdXRzLgoKb2ssIEkgY29tcGxldGVkIHRoZSBERVNlcSBydW4gdW5kZXIgdGhlIGRlYnVnZ2VyIGFuZCByZWNhcGl0dWxhdGVkIHRoZQpkaWZmZXJlbmNlcyBvYnNlcnZlZCBiZXR3ZWVuIDIwMjUwMyBhbmQgdG9kYXkuICBUaGUgYmFzZU1lYW4gKGNvbHVtbgpBSyBpbiB0aGUgeGxzeCBmaWxlKSB2YWx1ZXMgYXJlIGlkZW50aWNhbCwgYnV0IHRoZSBTRS9zdGF0L0ZDL3AvYWRqcAphcmUgc2xpZ2h0bHkgZGlmZmVyZW50IGZvciBtb3N0IGdlbmVzLgoKTGV0IHVzIG5vdyByZXJ1biB3aXRoIHRoZSBwcmUtZmlsdGVyZWQgc2V0IGFzIGlucHV0IGFuZCBsZWF2ZSB0aGUgU1ZzCndpdGggdGhlaXIgY3VycmVudCB2YWx1ZXMgKHdoaWNoIGFyZSBpZGVudGljYWwgdG8gdGhlIDIwMjUwMyBydW4pPwoKTm90ZSB0byBzZWxmLCB3aGVuIEkgZmluaXNoIHRoaXM6IHRoZXJlIGlzIGEgaGFyZC1jb2RlZCBudW1iZXIgb2YKc2lnbmlmaWNhbnQgZGlnaXRzIHdoZW4gSSBwcmludCBvdXQgdGhlIHRhYmxlIG9mIHJlc3VsdHMgKDQpLCBkb24ndCBkbwp0aGF0IC0tIHNldCBhbiBvcHRpb24gZm9yIHRoYXQuCgpPaywgdGhpcyB1bmZpbHRlcmVkIHJ1biByZXN1bHRzIGluIGEgc2V0IG9mIHJlc3VsdHMgd2hpY2ggbm93IGhhcwoyNSw0MjUgcm93cywgc28gaXQgZGVmaW5pdGVseSBkaWQgbm90IGZpbHRlci4gIEluIGFkZGl0aW9uLCB0aGUKYWRqdXN0ZWQgcC12YWx1ZXMgaGF2ZSBzaGlmdGVkIGJ5IH4gMWUtNSwgYnV0IHRoZSBsb2dGQyBhbmQgcC12YWx1ZXMgYXJlCmlkZW50aWNhbCB0byB0aGUgMjAyNjA4IHJ1bi4KClNvIHRoYXQgaXMgbm90IHRoZSBhbnN3ZXIgYnV0IGF0IGxlYXN0IEkgd2FzIG5vdCB3cm9uZyB0aGF0IGl0IGhhcyBhbgplZmZlY3QsIEkgZ3Vlc3MuICBMZXQgdXMgdHJ5IHRoZSBvcHBvc2l0ZSBmaWx0ZXIgLS0gc3dpdGNoIHRvIENCQ0IKZmlsdGVyaW5nIHdoaWNoIHdhcyB0aGUgZGVmYXVsdCBzb21lIHRpbWUgYWdvPyAgRmlsdGVyaW5nIHJlYWxseSBpcwp0aGUgb25seSB0aGluZyBJIGNhbiB0aGluayBvZiB3aGljaCB3b3VsZCBjaGFuZ2UgcmVzdWx0cyBhY3Jvc3MKX2V2ZXJ5XyBtZXRob2QgYnkgc3VjaCBhIHNtYWxsIGFtb3VudC4gIFNhbWUgcmVzdWx0LgoKb2ssIEkgY2hlY2tlZCB0aGUgcmVzdWx0OyBzYW1lLiAgSSBjaGFuZ2VkIHRoZSBiZXRhcHJpb3IsIHRoZSBkZXNlcQpub3JtYWxpemF0aW9uLCBhbmQgc2lnbmlmaWNhbnQgZGlnaXRzLiAgTm8gY2hhbmdlLgoKUmFuZG9tIHRob3VnaHQ6IEkgc2V0IHRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIHRvIDkgYW5kIHRyaWVkCmFnYWluLiAgQWFhYW5ubm5kZGRkIEkgaGF0ZSBldmVyeXRoaW5nIC0gdGhhdCBpcyB0aGUgYW5zd2VyLiAgSSB0aGluawpJIG5lZWQgdG8gbWFrZSBjZXJ0YWluIHRoYXQgb3B0aW9ucyhkaWdpdHMgPSB4KSB3aGVyZSB4IGlzIGNvbnNpc3RlbnQuCgoKMjAyNTA1OiBBIHN0cmFuZ2UgdGhpbmcgaGFwcGVuZWQgaGVyZSBpbiB0aGlzIGl0ZXJhdGlvbjogdGhlIHBsb3Qgb2YKdGhlIHNpZ25pZmljYW50IGdlbmVzIGlzIHRoZSBleGFjdCBzYW1lIGFzIHRoZSBwcmV2aW91cyBpdGVyYXRpb247IGJ1dAp0aGUgdGFibGUgb2YgbnVtYmVycyBvZiBnZW5lcyBsb29rcyBkaWZmZXJlbnQuCgpGb3IgZXhhbXBsZSwgdGhlIHByZXZpb3VzIHRhYmxlIHNob3dlZDogcDE1X2hldF9kbGduIHdpdGggMjA2NyB1cCBhbmQKMjM4MSBkb3duLiAgVGhlIHBsb3Qgc2hvd3MgZXhhY3RseSB0aGF0OyBidXQgdGhlIG5ldyB0YWJsZSBzaG93cyA2MDcKdXAgYW5kIDEyMjkgZG93bi4gIExldCB1cyBjaGVjayB0aGUgYWN0dWFsIGRhdGEgc3RydWN0dXJlIGFuZCBzZWUgd2hhdAppcyB1cD8KCkkgdGhpbmsgSSBnZXQgaXQ6IHdoZW4gd2UgZG8gdGhlIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMgYWJvdmUsIHdlCmV4cGxpY2l0bHkgc2V0IGEgbm9uLXN0YW5kYXJkIHAtdmFsdWUgYW5kIGxvZ0ZDIGJlY2F1c2Ugd2UgYXJlCmV4cGxpY2l0bHkgYXR0ZW1wdGluZyB0byB1c2UgYSB2ZXJ5IGxvb3NlIGRlZmluaXRpb24gb2YgdGhlIHNldCBvZgpnZW5lcyB3aGljaCBhcmUgaW4gZ3JlYXRlciBhYnVuZGFuY2UgdGhhbiB0aGVpciBtb3N0IHNpbWlsYXIKd2lsZC10eXBlLiBIb3dldmVyLCB3aGVuIEkgY3JlYXRlIHRoZSBiYXJwbG90IG9mIHNpZ25pZmljYW50IGdlbmVzOwp0aG9zZSB2YWx1ZXMgYXJlIGV4cGxpY2l0bHkgc2V0IHRvIDAsMSwyIGxvZ0ZDcyBhbmQgcC12YWx1ZSAwLjA1LgpUaGVyZWZvcmUsIHdoYXQgSSBuZWVkIHRvIGRvLCBpbiBvcmRlciB0byBjaGVjayBjb25zaXN0ZW5jeSwgaXMgdG8KcmVwZWF0IHRoaXMgY2FsbCBidXQgd2l0aCB0aGUgZGVmYXVsdCBGQy9wIHZhbHVlcyBhbmQgc2VlIHdoYXQgdGhlCm51bWJlcnMgbG9vayBsaWtlLgoKYGBge3J9CnRlc3RfaW5jbHVzaW9uIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaW5jbHVzaW9uX3RhYmxlcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwgZXhjZWwgPSAiZXhjZWwvZGVmYXVsdF9pbmNsdXNpb25fc2lnLnhsc3giKQp0ZXN0X2luY2x1c2lvbgpgYGAKClllYWgsIEkgdGhpbmsgdGhpcyBtYWtlcyBzZW5zZTsgd2hhdCBJIG5lZWQgdG8gZG86IGNoYW5nZSB0aGUKc2lnbmlmaWNhbnQgYmFyIHBsb3Qgc28gdGhhdCBpdCB1c2VzIHRoZSBsZmMgY3V0b2ZmIGFyZ3VtZW50IGFzIHRoZQpzZWNvbmQgb2YgaXRzIDMgY3V0b2Zmcy4gIFRoYXQgc2hvdWxkIGVuc3VyZSB0aGF0IHRoZXNlIG51bWJlcnMgYXJlCmNvbnNpc3RlbnQgYWNyb3NzIGFuYWx5c2VzIGFuZCBwYXJhbWV0ZXJzIHByb3ZpZGVkLgoKYGBge3J9CmRpbShpbmNsdXNpb25fc2lnJGRlc2VxJHVwcyRwMTVfaGV0X2RsZ24pCnRlc3RfYWxsX3VwIDwtIGluY2x1c2lvbl90YWJsZXMkZGF0YSRwMTVfaGV0X2RsZ25bWyJkZXNlcV9sb2dmYyJdXSA+PSAwLjEgJgogIGluY2x1c2lvbl90YWJsZXMkZGF0YSRwMTVfaGV0X2RsZ25bWyJkZXNlcV9hZGpwIl1dIDw9IDAuMQpzdW1tYXJ5KHRlc3RfYWxsX3VwKQpgYGAKCk9oaCwgSSBnZXQgaXQsIHdoZW4gSSB3YXMgdGVzdGluZyB0aGlzIG91dCBtYW51YWxseSwgSSBzZXQgdGhlIGxvZ0ZDCnRvIDEuMCBpbnN0ZWFkIG9mIHRoZSB2ZXJ5IG1pbmltYWwgMC4xIHdlIGhhdmUgYmVlbiB1c2luZyBmb3IgdGhpcyEKCiMgTUEvVm9sY2FubyBwbG90cyBvZiB4IHZzIHd0CgpSYXNobWkgYXNrZWQgdG8gc2VlIHRoZSBjb21wYXJpc29ucyBhZ2FpbnN0IHd0OyBJIHdpbGwgbmFtZSBlYWNoIGZpbGUKeHcgdG8gc2hvdyB0aGF0IGl0IGlzIHggdnMgd3QuIGZvciB3aGF0ZXZlciBvdGhlciBwYXJhbWV0ZXJzIGFyZSBiZWluZwpleGFtaW5lZC4gIEl0IGlzIGxpa2VseSB0aGF0IHNvbWUgY29sb3JzIHdpbGwgYmUgd3JvbmcgYmVjYXVzZSB0aGlzIGlzCm15IGZpcnN0IHRpbWUgY3JlYXRpbmcgdGhlc2UgcGxvdHMgYW5kIHdlIGFyZSBkb2luZyB0aGVtIG1hbnVhbGx5LgoKIyMgcDE1X2hldF9kbGduCgpgYGB7cn0KYWxsYyA8LSBjb2xvcl9jaG9pY2VzW1siYWxsIl1dCnRhYmxlX25hbWUgPC0gInAxNV9oZXRfZGxnbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9oZXRfZGxnbiIKZGVub20gPC0gInAxNV93dF9kbGduIgpod19wMTVfZGxnbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9od19wMTVfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBod19wMTVfZGxnbl92b2xjYW5vW1sicGxvdCJdXSkKCmh3X3AxNV9kbGduX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCgpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEvaHdfcDE1X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGh3X3AxNV9kbGduX21hW1sicGxvdCJdXSkKYGBgCgojIyBwMDhfaGV0X2RsZ24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMDhfaGV0X2RsZ24iCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfaGV0X2RsZ24iCmRlbm9tIDwtICJwMDhfd3RfZGxnbiIKaHdfcDA4X2RsZ25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9od19wMDhfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBod19wMDhfZGxnbl92b2xjYW5vW1sicGxvdCJdXSkKCmh3X3AwOF9kbGduX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9od19wMDhfZGxnbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AwOF9kbGduX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpod19wMDhfZGxnbl9tYVtbInBsb3QiXV0KYGBgCgojIyBwMTVfa29fZGxnbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAxNV9rb19kbGduIgp0YWJsZSA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCm51bSA8LSAicDE1X2tvX2RsZ24iCmRlbm9tIDwtICJwMTVfd3RfZGxnbiIKa3dfcDE1X2RsZ25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9rd19wMTVfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBrd19wMTVfZGxnbl92b2xjYW5vW1sicGxvdCJdXSkKCmt3X3AxNV9kbGduX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9rd19wMTVfZGxnbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0ga3dfcDE1X2RsZ25fbWFbWyJwbG90Il1dKQpgYGAKCiMjIHAwOF9rb19kbGduCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAicDA4X2tvX2RsZ24iCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfa29fZGxnbiIKZGVub20gPC0gInAwOF93dF9kbGduIgprd19wMDhfZGxnbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2t3X3AwOF9kbGduX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGt3X3AwOF9kbGduX3ZvbGNhbm9bWyJwbG90Il1dKQoKa3dfcDA4X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgb3V0bGluZSA9IG91dGxpbmUsCiAgbGFiZWwgPSAxMCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2t3X3AwOF9kbGduX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBrd19wMDhfZGxnbl9tYVtbInBsb3QiXV0pCmBgYAoKIyMgcDE1X2hldF9yZXRpbmEKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMTVfaGV0X3JldGluYSIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9oZXRfcmV0aW5hIgpkZW5vbSA8LSAicDE1X3d0X3JldGluYSIKaHdfcDE1X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2h3X3AxNV9yZXRpbmFfdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0gaHdfcDE1X3JldGluYV92b2xjYW5vW1sicGxvdCJdXSkKCmh3X3AxNV9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgb3V0bGluZSA9IG91dGxpbmUsCiAgbGFiZWwgPSAxMCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2h3X3AxNV9yZXRpbmFfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGh3X3AxNV9yZXRpbmFfbWFbWyJwbG90Il1dKQpgYGAKCiMjIHAwOF9oZXRfcmV0aW5hCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAicDA4X2hldF9yZXRpbmEiCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfaGV0X3JldGluYSIKZGVub20gPC0gInAwOF93dF9yZXRpbmEiCmh3X3AwOF9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9od19wMDhfcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGh3X3AwOF9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0pCgpod19wMDhfcmV0aW5hX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9od19wMDhfcmV0aW5hX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBod19wMDhfcmV0aW5hX21hW1sicGxvdCJdXSkKYGBgCgojIyBwMTVfa29fcmV0aW5hCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAicDE1X2tvX3JldGluYSIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9rb19yZXRpbmEiCmRlbm9tIDwtICJwMTVfd3RfcmV0aW5hIgprd19wMTVfcmV0aW5hX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEva3dfcDE1X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBrd19wMTVfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dKQoKa3dfcDE1X3JldGluYV9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEva3dfcDE1X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0ga3dfcDE1X3JldGluYV9tYVtbInBsb3QiXV0pCmBgYAoKIyMgcDA4X2tvX3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAwOF9rb19yZXRpbmEiCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfa29fcmV0aW5hIgpkZW5vbSA8LSAicDA4X3d0X3JldGluYSIKa3dfcDA4X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2t3X3AwOF9yZXRpbmFfdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGt3X3AwOF9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0pCgprd19wMDhfcmV0aW5hX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYV9wMDhfcmV0aW5hX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBrd19wMDhfcmV0aW5hX21hW1sicGxvdCJdXSkKYGBgCgojIyBwMTVfaGV0X3NjbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAxNV9oZXRfc2NuIgp0YWJsZSA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCm51bSA8LSAicDE1X2hldF9zY24iCmRlbm9tIDwtICJwMTVfd3Rfc2NuIgpod19wMTVfc2NuX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEvaHdfcDE1X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSwKICAgaW1hZ2UgPSBod19wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dKQoKaHdfcDE1X3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEvaHdfcDE1X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0gaHdfcDE1X3Njbl9tYVtbInBsb3QiXV0pCmBgYAoKIyMgcDA4X2hldF9zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMDhfaGV0X3NjbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAwOF9oZXRfc2NuIgpkZW5vbSA8LSAicDA4X3d0X3NjbiIKaHdfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2h3X3AwOF9zY25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0gaHdfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXSkKCmh3X3AwOF9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgb3V0bGluZSA9IG91dGxpbmUsCiAgbGFiZWwgPSAxMCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2h3X3AwOF9zY25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGh3X3AwOF9zY25fbWFbWyJwbG90Il1dKQpgYGAKCiMjIHAxNV9rb19zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMTVfa29fc2NuIgp0YWJsZSA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCm51bSA8LSAicDE1X2tvX3NjbiIKZGVub20gPC0gInAxNV93dF9zY24iCmt3X3AxNV9zY25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gYWxsY1tbZGVub21dXSwgY29sb3JfaGlnaCA9IGFsbGNbW251bV1dLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYS9rd19wMTVfc2NuX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBrd19wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dKQoKa3dfcDE1X3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWEva3dfcDE1X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0ga3dfcDE1X3Njbl9tYVtbInBsb3QiXV0pCmBgYAoKIyMgcDA4X2tvX3NjbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAwOF9rb19zY24iCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfa29fc2NuIgpkZW5vbSA8LSAicDA4X3d0X3NjbiIKa3dfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLCBsYWJlbCA9IDEwLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2t3X3AwOF9zY25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDksCiAgIGltYWdlID0ga3dfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXSkKCmt3X3AwOF9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwgb3V0bGluZSA9IG91dGxpbmUsCiAgbGFiZWwgPSAxMCkKcHAoZmlsZSA9ICIwNWluY2x1c2lvbl92b2xjYW5vX21hL2t3X3AwOF9zY25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5LAogICBpbWFnZSA9IGt3X3AwOF9zY25fbWFbWyJwbG90Il1dKQpgYGAKClRoZXJlIGlzIHNvbWV0aGluZyBkaWZmZXJlbnQgaGVyZSBjb21wYXJlZCB0byB0aGUgMjAyNTAzIHJlc3VsdHMuICBUd28Kb2YgdGhlIGRvdHMgaGF2ZSBtb3ZlZDsgYnV0IGV2ZXJ5IG90aGVyIHBsb3QgbG9va3MgZXhhY3RseSB0aGUgc2FtZS4KClNlZSB0aGUgc2hhcmVkL3VuaXF1ZSBnZW5lcyBpbiB0aGVzZSBzZXRzLgoKYGBge3J9CmluY2x1c2lvbl91cHNldHMgPC0gdXBzZXRyX3NpZyhpbmNsdXNpb25fc2lnKQppbmNsdXNpb25faW50ZXJzZWN0cyA8LSB3cml0ZV91cHNldF9ncm91cHMoCiAgaW5jbHVzaW9uX3Vwc2V0cywgZXhjZWwgPSAiMDRpbmNsdXNpb25fY29tcGFyaXNvbi9pbmNsdXNpb25fZ2VuZV9ncm91cHMueGxzeCIpCgpgYGAKCiMjIyBFeHRyYWN0IGdlbmVzIGluY2x1ZGVkIGZvciBlYWNoIHNldCBvZiBjb250cmFzdHMKCk5vdywgdXNpbmcgdGhhdCBmdW5jdGlvbiwgcHVsbCBvdXQgdGhlIGdlbmUgSURzIG9mIGdlbmVzIHdlIGRvIG5vdAp0cnVzdCBiZWNhdXNlIHRoZXkgd2VyZSB0b28gaGlnaCBpbiB3dCBmb3IgZXZlcnkgY29udHJhc3Qgd2UgYXJlCmxpa2VseSB0byBwZXJmb3JtLgoKVGhlIGZvbGxvd2luZyB3YXMgYSBtb2RpZmllZCB2ZXJzaW9uIG9mIHRoZSBpbmNsdXNpb24gZnVuY3Rpb24gd2hpY2ggaXMgc29tZXdoYXQgbW9yZSByZXN0cmljdGl2ZS4KCmBgYHtyfQpleHRyYWN0X2luY2x1c2lvbnNfc3RyaWN0IDwtIGZ1bmN0aW9uKGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsIGtlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsX2dlbmVzLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLCB3aGljaCA9ICJ1cHMiKSB7CiAgcmV0bGlzdCA8LSBsaXN0KCkKICB0YWJsZV9uYW1lcyA8LSBuYW1lcyhpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXSkKICBmb3IgKGNfbnVtIGluIHNlcV9hbG9uZyhrZWVwZXJzKSkgewogICAgY29udHJhc3QgPC0gbmFtZXMoa2VlcGVycylbY19udW1dCiAgICBudW1lcmF0b3JfbmFtZSA8LSBrZWVwZXJzW1tjX251bV1dWzFdCiAgICBkZW5vbWluYXRvcl9uYW1lIDwtIGtlZXBlcnNbW2NfbnVtXV1bMl0KICAgICMjIEluIG15IG5ldyBicmFuY2ggSSBjbGVhbmVkIHVwIHRoZSBzYW5pdGl6ZXIgZnVuY3Rpb24gZm9yIGNvbnRyYXN0cyBzbyB0aGlzIGlzIG5vdCBuZWVkZWQuCiAgICAjIyBUaGUgZm9sbG93aW5nIHR3byBsaW5lcyBhcmUgbm8gbG9uZ2VyIG5lZWRlZCBiZWNhdXNlIG9mIHRoZSBjbGVhbnVwcyBJIHBlcmZvcm1lZC4KICAgICMjbnVtZXJhdG9yX25hbWUgPC0gZ3N1Yih4ID0gbnVtZXJhdG9yX25hbWUsIHBhdHRlcm4gPSAiKGhldHxrb3x3dCkiLCByZXBsYWNlbWVudCA9ICJfXFwxXyIpCiAgICAjI2Rlbm9taW5hdG9yX25hbWUgPC0gZ3N1Yih4ID0gZGVub21pbmF0b3JfbmFtZSwgcGF0dGVybiA9ICIoaGV0fGtvfHd0KSIsIHJlcGxhY2VtZW50ID0gIl9cXDFfIikKICAgIG51bWVyYXRvcl90YWJsZSA8LSBpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXVtbbnVtZXJhdG9yX25hbWVdXQogICAgbnVtZXJhdG9yX2dlbmVzIDwtIHJvd25hbWVzKG51bWVyYXRvcl90YWJsZSkKICAgIGRlbm9taW5hdG9yX3RhYmxlIDwtIGluY2x1c2lvbl9zaWdbW2FjY29yZGluZ190b11dW1t3aGljaF1dW1tkZW5vbWluYXRvcl9uYW1lXV0KICAgIGRlbm9taW5hdG9yX2dlbmVzIDwtIHJvd25hbWVzKGRlbm9taW5hdG9yX3RhYmxlKQogICAgZGZfY29sdW1ucyA8LSBwYXN0ZTAoImRlc2VxXyIsIGMoImxvZ2ZjIiwgImFkanAiLCAiZGVuIikpCiAgICBpbmNsdWRlZF9udW0gPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW251bWVyYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfbnVtKSA8LSBjKCJudW1lcmF0b3JfdnNfd3RfbG9nZmMiLCAibnVtZXJhdG9yX3ZzX3d0X2FkanAiLCAibnVtX3d0X21lYW5fZXhwcnMiKQogICAgaW5jbHVkZWRfZGVuIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1tkZW5vbWluYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfZGVuKSA8LSBjKCJkZW5vbWluYXRvcl92c193dF9sb2dmYyIsICJkZW5vbWluYXRvcl92c193dF9hZGpwIiwgImRlbl93dF9tZWFuX2V4cHJzIikKICAgICMjIEkgdGhpbmsgdGhpcyBpcyB3aGVyZSB0aGluZ3Mgd2VudCB3cm9uZywKICAgICMjIGNvbXBhcmUgdGhpcyBtb2RpZmllZCBsaW5lIHRvIHRoZSBvcmlnaW5hbCB0byBwcm92ZSBpdC4KICAgIGluY2x1ZGVkX2RmIDwtIG1lcmdlKGluY2x1ZGVkX251bSwgaW5jbHVkZWRfZGVuLCBieSA9ICJyb3cubmFtZXMiKQogICAgIyMgUHJldmlvdXNseSwgSSBkaWQgbm90IHNwZWNpZnkgdGhlIG1lcmdlIGFjdGlvbiwgYWxsID0gRkFMU0UgYnkgZGVmYXVsdC4KICAgICMjIFRoaXMgdGhlbiB3aWxsIHJlc3VsdCBpbiBhIGRpZmZlcmVuY2UgaW4gdGhlIHJvd3Mgb2JzZXJ2ZWQKICAgICMjIGluY2x1ZGVkX2RmIDwtIG1lcmdlKGluY2x1ZGVkX251bSwgaW5jbHVkZWRfZGVuLCBieSA9ICJyb3cubmFtZXMiLCBhbGwgPSBGQUxTRSkKICAgIHJvd25hbWVzKGluY2x1ZGVkX2RmKSA8LSBpbmNsdWRlZF9kZltbIlJvdy5uYW1lcyJdXQogICAgaW5jbHVkZWRfZGZbWyJSb3cubmFtZXMiXV0gPC0gTlVMTAogICAgY29uY2F0ZW5hdGVkX2dlbmVzIDwtIGMobnVtZXJhdG9yX2dlbmVzLCBkZW5vbWluYXRvcl9nZW5lcykKICAgIGJvdGhfZ2VuZV9pZHggPC0gZHVwbGljYXRlZChjb25jYXRlbmF0ZWRfZ2VuZXMpCiAgICBnZW5lc19pbl9ib3RoIDwtIGNvbmNhdGVuYXRlZF9nZW5lc1tib3RoX2dlbmVfaWR4XQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIG51bWVyYXRvcl9uYW1lLAogICAgICAgICAgICAiIHZzLiB3dCBpcyAiLCBsZW5ndGgobnVtZXJhdG9yX2dlbmVzKSwgIi4iKQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIGRlbm9taW5hdG9yX25hbWUsCiAgICAgICAgICAgICIgdnMuIHd0IGlzICIsIGxlbmd0aChkZW5vbWluYXRvcl9nZW5lcyksICIuIikKICAgIG1lc3NhZ2UoIlRoZSBpbnRlcnNlY3Rpb24gb2YgdGhlbSBpcyAiLCBsZW5ndGgoZ2VuZXNfaW5fYm90aCksICIgZ2VuZXMuIikKICAgIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBjb250cmFzdCkKICAgIGluY2x1ZGVfaWR4IDwtIGFsbF9nZW5lcyAlaW4lIGdlbmVzX2luX2JvdGgKICAgIGluY2x1ZGVfZ2VuZXMgPC0gYWxsX2dlbmVzW2luY2x1ZGVfaWR4XQogICAgZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIGNvbnRyYXN0KQogICAgcmV0bGlzdFtbZGZfbmFtZV1dIDwtIGluY2x1ZGVkX2RmCiAgICB3cml0dGVuX2luY2x1c2lvbiA8LSB3cml0ZV94bHN4KAogICAgICBkYXRhID0gaW5jbHVkZWRfZGYsCiAgICAgIGV4Y2VsID0gZ2x1ZSgiMDdpbmNsdWRlZF9zdHJpY3RfZ2VuZXNfZXhjZWwve2luY2x1ZGVfbmFtZX0tdnt2ZXJ9Lnhsc3giKSkKICAgIHJldGxpc3RbW2luY2x1ZGVfbmFtZV1dIDwtIGluY2x1ZGVfZ2VuZXMKICAgIHJldGxpc3RbW2NvbnRyYXN0XV0gPC0gaW5jbHVkZV9nZW5lcwogIH0KICByZXR1cm4ocmV0bGlzdCkKfQpgYGAKClRoaXMgaXMgdGhlIHByZS0yMDI1MDUgdmVyc2lvbiBvZiB0aGlzIGZ1bmN0aW9uLgoKYGBge3J9CmV4dHJhY3RfaW5jbHVzaW9ucyA8LSBmdW5jdGlvbihpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLCBrZWVwZXJzLCBhbGxfZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLCB3aGljaCA9ICJ1cHMiKSB7CiAgcmV0bGlzdCA8LSBsaXN0KCkKICB0YWJsZV9uYW1lcyA8LSBuYW1lcyhpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXSkKICBmb3IgKGNfbnVtIGluIHNlcV9hbG9uZyhrZWVwZXJzKSkgewogICAgY29udHJhc3QgPC0gbmFtZXMoa2VlcGVycylbY19udW1dCiAgICBudW1lcmF0b3JfbmFtZSA8LSBrZWVwZXJzW1tjX251bV1dWzFdCiAgICBkZW5vbWluYXRvcl9uYW1lIDwtIGtlZXBlcnNbW2NfbnVtXV1bMl0KICAgICMjIEluIG15IG5ldyBicmFuY2ggSSBjbGVhbmVkIHVwIHRoZSBzYW5pdGl6ZXIgZnVuY3Rpb24gZm9yIGNvbnRyYXN0cyBzbyB0aGlzIGlzIG5vdCBuZWVkZWQuCiAgICAjIyBUaGUgZm9sbG93aW5nIHR3byBsaW5lcyBhcmUgbm8gbG9uZ2VyIG5lZWRlZCBiZWNhdXNlIG9mIHRoZSBjbGVhbnVwcyBJIHBlcmZvcm1lZC4KICAgICMjbnVtZXJhdG9yX25hbWUgPC0gZ3N1Yih4ID0gbnVtZXJhdG9yX25hbWUsIHBhdHRlcm4gPSAiKGhldHxrb3x3dCkiLCByZXBsYWNlbWVudCA9ICJfXFwxXyIpCiAgICAjI2Rlbm9taW5hdG9yX25hbWUgPC0gZ3N1Yih4ID0gZGVub21pbmF0b3JfbmFtZSwgcGF0dGVybiA9ICIoaGV0fGtvfHd0KSIsIHJlcGxhY2VtZW50ID0gIl9cXDFfIikKICAgIG51bWVyYXRvcl90YWJsZSA8LSBpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXVtbbnVtZXJhdG9yX25hbWVdXQogICAgbnVtZXJhdG9yX2dlbmVzIDwtIHJvd25hbWVzKG51bWVyYXRvcl90YWJsZSkKICAgIGRlbm9taW5hdG9yX3RhYmxlIDwtIGluY2x1c2lvbl9zaWdbW2FjY29yZGluZ190b11dW1t3aGljaF1dW1tkZW5vbWluYXRvcl9uYW1lXV0KICAgIGRlbm9taW5hdG9yX2dlbmVzIDwtIHJvd25hbWVzKGRlbm9taW5hdG9yX3RhYmxlKQogICAgZGZfY29sdW1ucyA8LSBwYXN0ZTAoImRlc2VxXyIsIGMoImxvZ2ZjIiwgImFkanAiLCAiZGVuIikpCiAgICBpbmNsdWRlZF9udW0gPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW251bWVyYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfbnVtKSA8LSBjKCJudW1lcmF0b3JfdnNfd3RfbG9nZmMiLCAibnVtZXJhdG9yX3ZzX3d0X2FkanAiLCAibnVtX3d0X21lYW5fZXhwcnMiKQogICAgaW5jbHVkZWRfZGVuIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1tkZW5vbWluYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfZGVuKSA8LSBjKCJkZW5vbWluYXRvcl92c193dF9sb2dmYyIsICJkZW5vbWluYXRvcl92c193dF9hZGpwIiwgImRlbl93dF9tZWFuX2V4cHJzIikKICAgIGluY2x1ZGVkX2RmIDwtIG1lcmdlKGluY2x1ZGVkX251bSwgaW5jbHVkZWRfZGVuLCBieSA9ICJyb3cubmFtZXMiKQogICAgcm93bmFtZXMoaW5jbHVkZWRfZGYpIDwtIGluY2x1ZGVkX2RmW1siUm93Lm5hbWVzIl1dCiAgICBpbmNsdWRlZF9kZltbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCiAgICBpbmNsdWRlX2dlbmVzIDwtIHVuaXF1ZShjKG51bWVyYXRvcl9nZW5lcywgZGVub21pbmF0b3JfZ2VuZXMpKQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIG51bWVyYXRvcl9uYW1lLAogICAgICAgICAgICAiIHZzLiB3dCBpcyAiLCBsZW5ndGgobnVtZXJhdG9yX2dlbmVzKSwgIi4iKQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIGRlbm9taW5hdG9yX25hbWUsCiAgICAgICAgICAgICIgdnMuIHd0IGlzICIsIGxlbmd0aChkZW5vbWluYXRvcl9nZW5lcyksICIuIikKICAgIG1lc3NhZ2UoIlRoZSB1bmlxdWUgdW5pb24gb2YgdGhlbSBpcyAiLCBsZW5ndGgoaW5jbHVkZV9nZW5lcyksICIgZ2VuZXMuIikKICAgIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBjb250cmFzdCkKICAgIGluY2x1ZGVfaWR4IDwtIGFsbF9nZW5lcyAlaW4lIGluY2x1ZGVfZ2VuZXMKICAgIGluY2x1ZGVfZ2VuZXMgPC0gYWxsX2dlbmVzW2luY2x1ZGVfaWR4XQogICAgZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIGNvbnRyYXN0KQogICAgcmV0bGlzdFtbZGZfbmFtZV1dIDwtIGluY2x1ZGVkX2RmCiAgICB3cml0dGVuX2luY2x1c2lvbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBpbmNsdWRlZF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlKCIwN2luY2x1ZGVkX2dlbmVzL3tpbmNsdWRlX25hbWV9LXZ7dmVyfS54bHN4IikpCiAgICByZXRsaXN0W1tpbmNsdWRlX25hbWVdXSA8LSBpbmNsdWRlX2dlbmVzCiAgICByZXRsaXN0W1tjb250cmFzdF1dIDwtIGluY2x1ZGVfZ2VuZXMKICB9CiAgcmV0dXJuKHJldGxpc3QpCn0KYGBgCgojICdOb3JtYWwnIEluY2x1c2lvbiBleHRyYWN0aW9uCgpIZXJlIGlzIHRoZSBmdWxsIHNldCBvZiBnZW5lIElEcwoKYGBge3J9CmFsbF9nZW5lcyA8LSByb3duYW1lcyhhc3NheSh2M19wYWlyd2lzZV9pbnB1dCkpCmBgYAoKSW4gdGhlIGZvbGxvd2luZyBibG9ja3MgSSBhbSBpbmNsdWRpbmcgdGhlIHVuaW9uIG9mIGdlbmVzIG9ic2VydmVkCmhpZ2hlciB0aGFuIHd0IGluIGVpdGhlciBvZiB0aGUgbnVtZXJhdG9yIG9yIGRlbm9taW5hdG9yIGZvciBlYWNoCmNvbnRyYXN0LgoKIyMgVGltZQoKYGBge3J9CnRpbWVfaW5jbHVzaW9ucyA8LSBleHRyYWN0X2luY2x1c2lvbnMoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIyBMb2NhdGlvbgoKYGBge3J9CmxvY2F0aW9uX2luY2x1c2lvbnMgPC0gZXh0cmFjdF9pbmNsdXNpb25zKGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIyBHZW5vdHlwZQoKYGBge3J9Cmdlbm90eXBlX2luY2x1c2lvbnMgPC0gZXh0cmFjdF9pbmNsdXNpb25zKGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbm90eXBlX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIFRoZSBzdHJpY3QgJ2luY2x1c2lvbicgc2V0CgojIyBUaW1lCgpgYGB7cn0KdGltZV9pbmNsdXNpb25zX3N0cmljdCA8LSBleHRyYWN0X2luY2x1c2lvbnNfc3RyaWN0KGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIyBMb2NhdGlvbgoKYGBge3J9CmxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0IDwtIGV4dHJhY3RfaW5jbHVzaW9uc19zdHJpY3QoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbl9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyMgR2Vub3R5cGUKCmBgYHtyfQpnZW5vdHlwZV9pbmNsdXNpb25zX3N0cmljdCA8LSBleHRyYWN0X2luY2x1c2lvbnNfc3RyaWN0KGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2Vub3R5cGVfa2VlcGVycywgYWxsX2dlbmVzKQpgYGAKCiMjIyBDaGVjayB2cyBUaGVyZXNhJ3MgZmlsdGVyCgpVcCBhYm92ZSBUaGVyZXNhIHBlcmZvcm1lZCBhIDAuMjUgbG9nMkZDIGFuZCAwLjA1IGFkanAgZmlsdGVyIHdoaWNoCnByb3ZpZGVkIGEgc2V0IG9mIDIsNjQwIGdlbmVzIG9ic2VydmVkIGhpZ2hlciBpbiB0aGUgcDA4IGhldCByZXRpbmFzCnZzLiB3dCByZXRpbmFzLiAgSSBzaG91bGQgc2VlIHRoYXQgaW4gdGhpcyBpbmNsdXNpb25fc2lnIGRhdGEgc3RydWN0dXJlLgoKVGhlcmUgaXMgYW4gaW1wb3J0YW50IGNhdmVhdCB0aG91Z2g6IGluIFRoZXJlc2EncyBmaWx0ZXIgYWJvdmUsIHNoZQpkaWQgYSBERSBvZiBfb25seV8gdGhlIHJldGluYSBzYW1wbGVzIGJ1dCBJIGRpZCBhbGwgc2FtcGxlcy4gIEkKZXhwZWN0ZWQgdGhhdCB0aGlzIHdvdWxkIHJlc3VsdCBpbiBiYXNpY2FsbHkgdGhlIHNhbWUgcmVzdWx0IChJCmFjdHVhbGx5IGFzc3VtZWQgSSB3b3VsZCBnZXQgYSBmZXcgbW9yZSBnZW5lcyksIGJ1dCBpbnN0ZWFkIGl0IGFwcGVhcnMKdG8gaGF2ZSByZXRyaWV2ZWQgYSBzaWduaWZpY2FudGx5IHNtYWxsZXIgbnVtYmVyIG9mIGdlbmVzIChhYm91dCAxLzIsCmhhcHBpbHkgdGhleSBwcmV0dHkgbXVjaCBhbGwgYXBwZWFyIGluIHRoZSBwcmV2aW91cyBmaWx0ZXIpLiAgQXMgYQpyZXN1bHQsIEkgYW0gZ29pbmcgdG8gdHJ5IHJlbGF4aW5nIG15IGNvbnN0cmFpbnRzIHNsaWdodGx5IHRvIHNlZSBpZiBJCmNhbiByZWNhcGl0dWxhdGUgaGVyIGZpbHRlciAod2hpY2ggd291bGQgbWF0Y2ggVGhlcmVzYSdzIGxhdGVyIGZpbHRlciwKdGhvdWdoIEkgZ3Vlc3MgdGhhdCBpbiB0dXJuIHdpbGwgbGVhZCB0byBhIHNtYWxsZXIgc2V0IG9mIGdlbmVzCmNvbXBhcmVkIHRvIGhlciBsYXRlciwgcmVsYXhlZCAwLjEgZmlsdGVyKS4KCmBgYHtyfQpjb21wYXJpc29uIDwtIGluY2x1c2lvbl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInAwOF9oZXRfcmV0aW5hIl1dCmNvbXAgPC0gbGlzdCgKICAidGFhIiA9IHRhYV9rZWVwZXJzLAogICJuZXciID0gcm93bmFtZXMoY29tcGFyaXNvbikpCnRlc3RfY29tcGFyaXNvbiA8LSBWZW5uZXJhYmxlOjpWZW5uKGNvbXApClZlbm5lcmFibGU6OnBsb3QodGVzdF9jb21wYXJpc29uKQpgYGAKCkkgd2FudCB0byBoYXZlIGEgbGl0dGxlIGZ1bmN0aW9uIHdoaWNoLCBnaXZlbiBhIGNvbnRyYXN0IG9mIGludGVyZXN0LAp3aWxsIGV4dHJhY3QgdGhlIGdlbmUgc2V0cyB3aGljaCBzaG91bGQgYmUgaW5jbHVkZWQvZXhjbHVkZWQgZ2l2ZW4gdGhlCmFib3ZlLgoKYGBge3J9CndyaXRlX2FsbF9jcCA8LSBmdW5jdGlvbihhbGxfY3AsIHByZWZpeCA9ICIxMiIsIHN1ZmZpeCA9ICIiKSB7CiAgYWxsX3dyaXR0ZW4gPC0gbGlzdCgpCiAgZm9yIChnIGluIHNlcV9sZW4obGVuZ3RoKGFsbF9jcCkpKSB7CiAgICBuYW1lIDwtIG5hbWVzKGFsbF9jcClbZ10KICAgIGRhdHVtIDwtIGFsbF9jcFtbbmFtZV1dCiAgICBmaWxlbmFtZSA8LSBnbHVlKCJ7cHJlZml4fWVucmljaG1lbnRfZXhjZWwve25hbWV9X2Nwcm9maWxlcntzdWZmaXh9LXZ7dmVyfS54bHN4IikKICAgIHdyaXR0ZW4gPC0gc20od3JpdGVfY3BfZGF0YShkYXR1bSwgZXhjZWwgPSBmaWxlbmFtZSkpCiAgICBhbGxfd3JpdHRlbltbZ11dIDwtIHdyaXR0ZW4KICB9CiAgcmV0dXJuKGFsbF93cml0dGVuKQp9CndyaXRlX2FsbF9ncCA8LSBmdW5jdGlvbihhbGxfZ3AsIHByZWZpeCA9ICIxMyIsIHN1ZmZpeCA9ICIiKSB7CiAgYWxsX3dyaXR0ZW4gPC0gbGlzdCgpCiAgZm9yIChnIGluIHNlcV9sZW4obGVuZ3RoKGFsbF9ncCkpKSB7CiAgICBuYW1lIDwtIG5hbWVzKGFsbF9ncClbZ10KICAgIGRhdHVtIDwtIGFsbF9ncFtbbmFtZV1dCiAgICBmaWxlbmFtZSA8LSBnbHVlKCJ7cHJlZml4fWVucmljaG1lbnRfZXhjZWwve25hbWV9X2dwcm9maWxlcntzdWZmaXh9LXZ7dmVyfS54bHN4IikKICAgIHdyaXR0ZW4gPC0gc20od3JpdGVfZ3Byb2ZpbGVyX2RhdGEoZGF0dW0sIGV4Y2VsID0gZmlsZW5hbWUpKQogICAgYWxsX3dyaXR0ZW5bW2ddXSA8LSB3cml0dGVuCiAgfQogIHJldHVybihhbGxfd3JpdHRlbikKfQp3cml0ZV9hbGxfZW4gPC0gZnVuY3Rpb24oYWxsX2VuLCBwcmVmaXggPSAiMTQiLCBzdWZmaXggPSAiIikgewogIGFsbF93cml0dGVuIDwtIGxpc3QoKQogIGZvciAoZSBpbiBzZXFfbGVuKGxlbmd0aChhbGxfZW4pKSkgewogICAgbmFtZSA8LSBuYW1lcyhhbGxfZW4pW2VdCiAgICBkYXR1bSA8LSBhbGxfZW5bW25hbWVdXQogICAgZmlsZW5hbWUgPC0gZ2x1ZSgie3ByZWZpeH1lbnJpY2htZW50X2V4Y2VsL3tuYW1lfV9lbnJpY2hlcntzdWZmaXh9LXZ7dmVyfS54bHN4IikKICAgIHdyaXR0ZW4gPC0gc20od3JpdGVfZW5yaWNoZXJfZGF0YShkYXR1bSwgZXhjZWwgPSBmaWxlbmFtZSkpCiAgICBhbGxfd3JpdHRlbltbZV1dIDwtIHdyaXR0ZW4KICB9CiAgcmV0dXJuKGFsbF93cml0dGVuKQp9CmBgYAoKIyMjIEV4dHJhY3QgZ2VuZXMgaW5jbHVkZWQgZm9yIGVhY2ggc2V0IG9mIGNvbnRyYXN0cwoKTm93LCB1c2luZyB0aGF0IGZ1bmN0aW9uLCBwdWxsIG91dCB0aGUgZ2VuZSBJRHMgb2YgZ2VuZXMgd2UgZG8gbm90CnRydXN0IGJlY2F1c2UgdGhleSB3ZXJlIHRvbyBoaWdoIGluIHd0IGZvciBldmVyeSBjb250cmFzdCB3ZSBhcmUKbGlrZWx5IHRvIHBlcmZvcm0uCgpgYGB7cn0KYWxsX2dlbmVzIDwtIHJvd25hbWVzKGFzc2F5KHYzX3BhaXJ3aXNlX2lucHV0KSkKdGltZV9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfa2VlcGVycywgYWxsX2dlbmVzKQpsb2NhdGlvbl9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbl9rZWVwZXJzLCBhbGxfZ2VuZXMpCmdlbm90eXBlX2luY2x1c2lvbnMgPC0gZXh0cmFjdF9pbmNsdXNpb25zKGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbm90eXBlX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIyBQZXJmb3JtIHRoZSBERSBhbmFseXNlcyBhbmQgZXhjbHVkZSB0aGUgdGFyZ2V0IGdlbmVzCgoKIyMjIEdlbm90eXBlCgpgYGB7cn0KZ2Vub3R5cGVfZGUgPC0gYWxsX3BhaXJ3aXNlKHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9mc3RyaW5nID0gZGVmYXVsdF9mc3RyaW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IGdlbm90eXBlX2tlZXBlcnMsIG1vZGVsX3N2cyA9ICJzdmFzZXEiKQpnZW5vdHlwZV9kZQpgYGAKCiMjIyBMb2NhdGlvbgoKYGBge3J9CmxvY2F0aW9uX2RlIDwtIGFsbF9wYWlyd2lzZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfZnN0cmluZyA9IGRlZmF1bHRfZnN0cmluZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBsb2NhdGlvbl9rZWVwZXJzLCBtb2RlbF9zdnMgPSAic3Zhc2VxIikKbG9jYXRpb25fZGUKYGBgCgojIyMgVGltZQoKYGBge3J9CnRpbWVfZGUgPC0gYWxsX3BhaXJ3aXNlKHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9mc3RyaW5nID0gZGVmYXVsdF9mc3RyaW5nLAogICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gdGltZV9rZWVwZXJzLCBtb2RlbF9zdnMgPSAic3Zhc2VxIikKdGltZV9kZQpgYGAKCkl0IGlzIG5lYXIgaGVyZSB3aGVuIHRoZSBjb21wdXRlciBzb21ldGltZXMgZmFpbHMgd2l0aCBubyBtb3JlCnRlbXBmaWxlcy4gIEluIGFub3RoZXIgd2luZG93IEkgYW0gbWVzc2luZyB3aXRoIHRlbXBmaWxlKCkgaW4gUiB0byB0cnkKdG8gdW5kZXJzdGFuZCB3aGVyZSBpdCBpcyBnb2luZyBvZmYgdGhlIHJhaWxzLi4uCgojIyBFeHRyYWN0IHRoZSByZWxldmFudCB0YWJsZXMgYW5kIGluY2x1ZGUgZ2VuZXMgbG93ZXIgaW4gd3QKCiMjIyBHZW5vdHlwZSBjb250cmFzdHMKCkkgd2lsbCBzdGFydCB3aXRoIHRoZSB0YWJsZXMgYW5kIG5vIGluY2x1c2lvbnMgc28gSSBjYW4gY2hlY2sgbXkgd29yay4KCkluIHRoaXMgZmlyc3QgYmxvY2sgSSB3aWxsIGV4cGxhaW4gYSBsaXR0bGUgbW9yZSB0aG9yb3VnaGx5IHdoYXQgaXMKZ29pbmcgb246CgoxLiAgRHVtcCB0aGUgZnVsbCB0YWJsZSBvZiB0aGUgY29udHJhc3RzIEkgZGVmaW5lZCBhYm92ZSBjb21wYXJpbmcgdGhlCiAgICAzIGdlbm90eXBlcyBhY3Jvc3MgdGltZS9sb2NhdGlvbi4KMi4gIEl0ZXJhdGUgb3ZlciBlYWNoIG9mIHRob3NlIGNvbnRyYXN0cyBhbmQgZG8gdGhlIGZvbGxvd2luZzoKICAgIGEuICBFeHRyYWN0IHRoZSBuYW1lIG9mIHRoZSBjb250cmFzdCwgJ2toX3AwOF9kbGduJyBmb3IgZXhhbXBsZQogICAgYi4gIFlhbmsgb3V0IHRoYXQgc3BlY2lmaWMgZW50cnkgZnJvbSB0aGUga2VlcGVyIGxpc3QgYW5kIGl0cyBuYW1lCiAgICBjLiAgWWFuayBvdXQgdGhlIGNvcnJlc3BvbmRpbmcgc2V0IG9mIGdlbmVzIHRvIGluY2x1ZGUgZnJvbSB0aGUKICAgICAgICBpbmNsdXNpb25zIGRhdGEgc3RydWN0dXJlLgogICAgZC4gIENyZWF0ZSBhIGZpbGVuYW1lIGdpdmVuIHRoZSBuYW1lIGluIChhKSBhYm92ZSBhbmQgdGhlIGxvZ0ZDCiAgICAgICAgY3V0b2ZmIGNob3NlbiBmb3IgdGhlIGluY2x1c2lvbnMgKEkgYW0gYXNzdW1pbmcgd2UgbWF5IGNoYW5nZQogICAgICAgIHRoaXMpCiAgICBlLiAgR2l2ZW4gKGIpLCAoYyksIGFuZCAoZCksIGV4dHJhY3QgdGhlIGNvcnJlc3BvbmRpbmcgdGFibGUgZnJvbQogICAgICAgIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBhbmQgaW5jbHVkZSB0aGUgYXBwcm9wcmlhdGUKICAgICAgICBnZW5lcy4KCiAgICBGSVhNRTogbXkgZ3Byb2ZpbGVyIGZ1bmN0aW9uIGp1c3QgYXNzdW1lcyBodW1hbiBhbmQgc28gaWYgcGFzc2VkIG1tdXNjdWx1cyB3aWxsIGluY29ycmVjdGx5CiAgICBhdHRlbXB0IHRvIGNvbm5lY3QgdG8gbm9uLWV4aXN0YW50IGRhdGFiYXNlcy4gIExldCB1cyBmaXggdGhhdCBub3cuCgpgYGB7cn0KZ2Vub3R5cGVfdGFibGVzX2Z1bGwgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgZ2Vub3R5cGVfZGUsIGtlZXBlcnMgPSBnZW5vdHlwZV9rZWVwZXJzLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZmFuY3kgPSBUUlVFLAogIGV4Y2VsID0gZ2x1ZSgiMDhmdWxsX2NvbnRyYXN0c19leGNlbC9nZW5vdHlwZV9mdWxsX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpnZW5vdHlwZV90YWJsZXNfZnVsbAoKZ2Vub3R5cGVfc2lnX2Z1bGwgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBnZW5vdHlwZV90YWJsZXNfZnVsbCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoIjA4ZnVsbF9jb250cmFzdHNfZXhjZWwvZ2Vub3R5cGVfZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKZ2Vub3R5cGVfc2lnX2Z1bGwKYGBgCgojIyMgU2VhcmNoIEVucmljaG1lbnQgb2YgdGhlc2Ugc2V0cwoKSW4gdGhpcyBydW4sIHdlIHdpbGwgc2VhcmNoIHRoZSBmdWxsIHNldCBvZiBnZW5lcywgbmV4dCB3ZSB3aWxsIG9ubHkKZG8gdGhlIGluY2x1c2lvbnMuCgpgYGB7cn0KZ2Vub3R5cGVfZnVsbF9ncCA8LSBhbGxfZ3Byb2ZpbGVyKGdlbm90eXBlX3NpZ19mdWxsLCBzcGVjaWVzID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIwOWZ1bGxfY29udHJhc3RzX2VucmljaC9nZW5vdHlwZV9mdWxsX2dwcm9maWxlci54bHN4IikKZ2Vub3R5cGVfZnVsbF9jcCA8LSBhbGxfY3Byb2ZpbGVyKGdlbm90eXBlX3NpZ19mdWxsLCBnZW5vdHlwZV90YWJsZXNfZnVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGdvX2xldmVsID0gZ29fbGV2ZWwsIG9yZ2FuaXNtID0gIm1vdXNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLCBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjA5ZnVsbF9jb250cmFzdHNfZW5yaWNoL2dlbm90eXBlX2Z1bGxfY3Byb2ZpbGVyLnhsc3giKQpnZW5vdHlwZV9mdWxsX3Vwc2V0IDwtIHVwc2V0cl9zaWcoZ2Vub3R5cGVfc2lnX2Z1bGwpCmdlbm90eXBlX2Z1bGxfaW50ZXJzZWN0cyA8LSB3cml0ZV91cHNldF9ncm91cHMoZ2Vub3R5cGVfZnVsbF91cHNldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIwOWZ1bGxfY29udHJhc3RzX2ludGVyc2VjdGlvbnMvZ2Vub3R5cGVfZnVsbF9nZW5lX2dyb3Vwcy54bHN4IikKYGBgCgpOb3cgc2VwYXJhdGUgdGhlIHZhcmlvdXMgZ2Vub3R5cGUgdGFibGVzIGFuZCBwZXJmb3JtIHRoZSBpbmNsdXNpb25zIG9mCnRoZSBnZW5lcyB3aXRoIHJlbGF0aXZlbHkgbG93IHd0IHZhbHVlcy4KCiMjIyMgRXh0cmFjdCBmaWx0ZXJlZCBnZW5lcyBhbmQgcGFzcyB0byBncHJvZmlsZXIyL2NsdXN0ZXJwcm9maWxlcgoKYGBge3J9Cmdlbm90eXBlX3RhYmxlcyA8LSBsaXN0KCkKZ2Vub3R5cGVfc2lnIDwtIGxpc3QoKQpnZW5vdHlwZV9ncCA8LSBsaXN0KCkKZ2Vub3R5cGVfY3AgPC0gbGlzdCgpCmdlbm90eXBlX2VuIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKGdlbm90eXBlX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhnZW5vdHlwZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBnZW5vdHlwZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjEwZ2Vub3R5cGVfY29udHJhc3RzX2V4Y2VsL3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiMTBnZW5vdHlwZV9jb250cmFzdHNfZXhjZWwve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgZ2Vub3R5cGVfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBnZW5vdHlwZV9kZSwgZXh0cmFfYW5ub3QgPSBpbmNsdWRlX2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlcykKICBwcmludChnZW5vdHlwZV90YWJsZXNbW25hbWVdXSkKICBnZW5vdHlwZV9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgZ2Vub3R5cGVfdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KGdlbm90eXBlX3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3coZ2Vub3R5cGVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+PSAxMCkgewogICAgbWVzc2FnZSgiUGVyZm9ybWluZyBncHJvZmlsZXIvY2x1c3RlclByb2ZpbGVyLiIpCiAgICBnZW5vdHlwZV9ncFtbbmFtZV1dIDwtIGFsbF9ncHJvZmlsZXIoZ2Vub3R5cGVfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGdlbm90eXBlX2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgZ2Vub3R5cGVfc2lnW1tuYW1lXV0sIGdlbm90eXBlX3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICAgICAgZ29fbGV2ZWwgPSBnb19sZXZlbCwgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgICNnZW5vdHlwZV9jcF90ZXN0W1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICMgIGdlbm90eXBlX3NpZ1tbbmFtZV1dLCBnZW5vdHlwZV90YWJsZXNbW25hbWVdXSwKICAgICMgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLCBvcmdhbmlzbSA9ICJtb3VzZSIpCiAgICBncF93cml0dGVuIDwtIHdyaXRlX2FsbF9ncChnZW5vdHlwZV9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMTEiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AoZ2Vub3R5cGVfY3BbW25hbWVdXSwgcHJlZml4ID0gIjExIikKICAgICNlbl93cml0dGVuIDwtIHdyaXRlX2FsbF9lbihnZW5vdHlwZV9lbltbbmFtZV1dKQogIH0gZWxzZSB7CiAgICB3YXJuaW5nKCJUaGVyZSBhcmUgbGVzcyB0aGFuIDEwIGdlbmVzIHVwIGFuZCBkb3duIGluIHRoZSAiLCBuYW1lLCAiIGNvbXBhcmlzb24uIikKICAgIG1lc3NhZ2UoIlRoZXJlIGFyZSBsZXNzIHRoYW4gMTAgZ2VuZXMgdXAgYW5kIGRvd24gaW4gdGhlICIsIG5hbWUsICIgY29tcGFyaXNvbi4iKQogIH0KfQpgYGAKClBsb3QgdGhlIHJlc3VsdHMgc2VwYXJhdGVseS4KCmBgYHtyfQpmb3IgKGsgaW4gc2VxX2Fsb25nKGdlbm90eXBlX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhnZW5vdHlwZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBnZW5vdHlwZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBudW1fcm93cyA8LSBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhnZW5vdHlwZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogICMjICMxIGlzIHVwIGFuZCAjMiBpcyBkb3duLCBhdm9pZGluZyB0eXBlb3MgaGVyZS4KICBudW1fb2JqZWN0cyA8LSBsZW5ndGgoZ2Vub3R5cGVfY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIHdlbnQgd3JvbmcgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKGdlbm90eXBlX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhnZW5vdHlwZV9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfZG93biQiKSkKICAgIGlmIChsZW5ndGgodXBwKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIGdlbm90eXBlX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBnZW5vdHlwZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnKQogICAgICBtZl90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfbWZfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGNjX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9jY19zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfYnBfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogICAgaWYgKGxlbmd0aChkb3ducCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBnZW5vdHlwZV9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIGdlbm90eXBlX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fbWZfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGNjX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fZG93bl9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fZG93bl9jY19zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBjYXRlb2dvcmllcyA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKQSBmZXcgc3BlY2lmaWMgcGxvdHMgb2YgaW50ZXJlc3Q6IENvbGVuc28gYXNrZWQgdG8gbGFiZWwgYSBmZXcgZ2VuZXMKZm9yIHRoZSBrbm9ja291dC9oZXQgcDA4X3JldGluYXMsIHAwOF9zY24sIGFuZCBwMDhfZGxnbjogZWl0aGVyIHRoZQp0b3AtMTUgb3IgYWxsIHNpZ25pZmljYW50LiAgSSBhbSBwcmV0dHkgc3VyZSBpZiBJIHRlbGwgaXQgMTUgYW5kIHRoZXJlCmFyZSBub3QgdGhhdCBtYW55LCBpdCB3aWxsIGp1c3QgZG8gdGhlIHNpZ25pZmljYW50PyAgTGV0IHVzIGZpbmQgb3V0IQoKIyMjIyBrby9oZXQgZm9yIHAwOCByZXRpbmFzCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDA4X3JldGluYSIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmcgPC0gYygiT3BuNCIsICJHbTkwMDgiLCAiTHJyMSIsICJDbmJkMSIpCmtoX3AwOF9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmcsIGFscGhhID0gMS4wLAogIG91dGxpbmUgPSBvdXRsaW5lLCBzaXplID0gNCkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmtoX3AwOF9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gaW50ZXJlc3RpbmcpCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vL2toX3AwOF9yZXRpbmFfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMDhfcmV0aW5hX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfcmV0aW5hX21hW1sicGxvdCJdXQpgYGAKCiMjIyMga28vaGV0IHAwOCBTQ04KCkkgYW0gZ29pbmcgdG8gbWFrZSBhbiBleGVjdXRpdmUgZGVjaXNpb24gZm9yIHRoaXMgcGxvdCwgMTUgaXMgdG9vIG1hbnkKYW5kIG1ha2VzIGl0IGNyYXp5IGNsdXR0ZXJlZC4KCiMjIyBSZXBlYXQgdGhpcyB3aXRoIHR3byBzZXRzIG9mIGdlbmVzCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDA4X3NjbiIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmdfZ2VuZXMgPC0gYygiRmlnbiIsICJOcm4xIiwgIkRweXNsMiIsICJBY3RiIiwgIkZnZjkiLCAiT3R4MiIsICJTZWMyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIk5jYW0xIiwgIk1hcDQiLCAiU2VjMjJiIiwgIk5sZ24zIiwgIk1hcmNrcyIsICJDZDQ3IiwKICAgICAgICAgICAgICAgICAgICAgICAiRHB5c2wzIiwgIkxpbjdjIiwgIkNhZG0xIiwgIlNueDEyIiwgIlJob2EiLCAiSW5wcDVmIiwKICAgICAgICAgICAgICAgICAgICAgICAiQXRnMTIiLCAiU2V0IiwgIkdzazNiIiwgIlBkY2Q0IiwgIkdhYnJhMiIsICJUbWNvMSIsICJBbmFwYzE2IikKa2hfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxCl9hZGpwIiwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCwKICBvdXRsaW5lID0gb3V0bGluZSwgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCiMjIHdoeSBpbiB0aGUgY3JhcCBpcyBpdCBkb3VibGUtbGFiZWxsaW5nIT8KIyMgTXkgTUEgcGxvdHRlciBpc24ndCBhcyBzbWFydCBhcyB0aGUgdm9sY2FubyBwbG90dGVyLCB0aGUgZ2VuZXMgYXJlOgpraF9wMDhfc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBvdXRsaW5lID0gb3V0bGluZSwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcykKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBTYW1lIHBsb3QgYnV0IGEgZGlmZmVyZW50IHNldCBvZiBsYWJlbGVkIGdlbmVzCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDA4X3NjbiIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmdfZ2VuZXMgPC0gYygKICAiQW5hcGMxNiIsICJHYWJyYTIiLCAiVG1jbzEiLCAiU29kMiIsICJGZ2Y5IiwgIlBkY2Q0IiwgIlJob2EiLCAiR3NrM2IiLCAiRm94cDEiLAogICJOY2FtMSIsICJNYXJja3MiLCAiRmlnbiIsICJEcHlzbDMiLCAiSW5wcDVmIiwgIkNhZG0xIiwgIk1hcDQiLCAiVWdjZyIsICJFbG92bDQiLAogICJFbGF2bDEiLCAiQ2ZsMiIsICJUbm50MSIsICJHbmIxIiwgIkltcGFjdCIsICJOcm4xIiwgIk5sZ24zIiwgIkFjdGIiLCAiQ2Q0NyIsCiAgIlNlYzIyYiIsICJTbGMxN2E3IiwgIlZnbHV0MSIsICJBY3RiIiwgIkI0Z2FsdDUiLCAiRm94cDEiLCAiT3R4MiIsICJMaW43YyIsCiAgIlNueDEyIiwgIkF0ZzEyIiwgIlNldCIpCmtoX3AwOF9zY25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19zY24iXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfc2NuIl1dLAogIG91dGxpbmUgPSBvdXRsaW5lLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X3Njbl92b2xjYW5vX3YyLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCiMjIHdoeSBpbiB0aGUgY3JhcCBpcyBpdCBkb3VibGUtbGFiZWxsaW5nIT8KIyMgTXkgTUEgcGxvdHRlciBpc24ndCBhcyBzbWFydCBhcyB0aGUgdm9sY2FubyBwbG90dGVyLCB0aGUgZ2VuZXMgYXJlOgpraF9wMDhfc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBvdXRsaW5lID0gb3V0bGluZSwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcykKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X3Njbl9tYV92Mi5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBrby9oZXQgcDA4IGRMR04KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMDhfZGxnbiIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0Ka2hfcDA4X2RsZ25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19kbGduIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X2RsZ24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSAxMCwgc2l6ZSA9IDQsIGFscGhhID0gMS4wKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fuby9raF9wMDhfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KIyMgTXkgTUEgcGxvdHRlciBpc24ndCBhcyBzbWFydCBhcyB0aGUgdm9sY2FubyBwbG90dGVyLCB0aGUgZ2VuZXMgYXJlOgpraF9wMDhfZGxnbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfZGxnbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IDEwLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDA4X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMDhfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDA4X2RsZ25fbWFbWyJwbG90Il1dCgpgYGAKCiMjIyMga28vaGV0IGZvciBwMTUgcmV0aW5hcwoKV2hlbiBsYXN0IEkgcmFuIHRoaXMgbWFudWFsbHksIGl0IGRpZCBub3QgZG91YmxlLWxhYmVsLCBob3BlZnVsbHkgdGhhdApyZW1haW5zIHRydWUgaW4gdGhlIGNvbnRhaW5lci4KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMTVfcmV0aW5hIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZyA8LSBjKCJPcG40IiwgIkdtOTAwOCIsICJMcnIxIiwgIkNuYmQxIikKa2hfcDE1X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZywgYWxwaGEgPSAxLjAsCiAgb3V0bGluZSA9IG91dGxpbmUsIHNpemUgPSA0KQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fuby9raF9wMTVfcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0KIyMgd2h5IGluIHRoZSBjcmFwIGlzIGl0IGRvdWJsZS1sYWJlbGxpbmchPwojIyBNeSBNQSBwbG90dGVyIGlzbid0IGFzIHNtYXJ0IGFzIHRoZSB2b2xjYW5vIHBsb3R0ZXIsIHRoZSBnZW5lcyBhcmU6CmtoX3AxNV9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmcsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fuby9raF9wMTVfcmV0aW5hX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X3JldGluYV9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3JldGluYV9tYVtbInBsb3QiXV0KYGBgCgojIyMjIGtvL2hldCBwMTUgU0NOCgojIyMgUmVwZWF0IHRoaXMgd2l0aCB0d28gc2V0cyBvZiBnZW5lcwoKYGBge3J9CnRhYmxlX25hbWUgPC0gImtoX3AxNV9zY24iCnRhYmxlX2lucHV0IDwtIGdlbm90eXBlX3RhYmxlc1tbdGFibGVfbmFtZV1dCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCmludGVyZXN0aW5nX2dlbmVzIDwtIGMoIkZpZ24iLCAiTnJuMSIsICJEcHlzbDIiLCAiQWN0YiIsICJGZ2Y5IiwgIk90eDIiLCAiU2VjMjMiLAogICAgICAgICAgICAgICAgICAgICAgICJOY2FtMSIsICJNYXA0IiwgIlNlYzIyYiIsICJObGduMyIsICJNYXJja3MiLCAiQ2Q0NyIsCiAgICAgICAgICAgICAgICAgICAgICAgIkRweXNsMyIsICJMaW43YyIsICJDYWRtMSIsICJTbngxMiIsICJSaG9hIiwgIklucHA1ZiIsCiAgICAgICAgICAgICAgICAgICAgICAgIkF0ZzEyIiwgIlNldCIsICJHc2szYiIsICJQZGNkNCIsICJHYWJyYTIiLCAiVG1jbzEiLCAiQW5hcGMxNiIpCmtoX3AxNV9zY25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCwKICBvdXRsaW5lID0gb3V0bGluZSwgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDE1X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCmtoX3AxNV9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19zY24iXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfc2NuIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fuby9raF9wMTVfc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KYGBgCgpSb3VuZCAyIHdpdGggYSBzZXBhcmF0ZSBnZW5lIHNldC4KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMTVfc2NuIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKAogICJBbmFwYzE2IiwgIkdhYnJhMiIsICJUbWNvMSIsICJTb2QyIiwgIkZnZjkiLCAiUGRjZDQiLCAiUmhvYSIsICJHc2szYiIsICJGb3hwMSIsCiAgIk5jYW0xIiwgIk1hcmNrcyIsICJGaWduIiwgIkRweXNsMyIsICJJbnBwNWYiLCAiQ2FkbTEiLCAiTWFwNCIsICJVZ2NnIiwgIkVsb3ZsNCIsCiAgIkVsYXZsMSIsICJDZmwyIiwgIlRubnQxIiwgIkduYjEiLCAiSW1wYWN0IiwgIk5ybjEiLCAiTmxnbjMiLCAiQWN0YiIsICJDZDQ3IiwKICAiU2VjMjJiIiwgIlNsYzE3YTciLCAiVmdsdXQxIiwgIkFjdGIiLCAiQjRnYWx0NSIsICJGb3hwMSIsICJPdHgyIiwgIkxpbjdjIiwKICAiU254MTIiLCAiQXRnMTIiLCAiU2V0IikKa2hfcDE1X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgc2l6ZSA9IDQsIGFscGhhID0gMS4wKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fuby9raF9wMTVfc2NuX3ZvbGNhbm9fdjIucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9zY25fdm9sY2Fub1tbInBsb3QiXV0Ka2hfcDE1X3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vL2toX3AxNV9zY25fbWFfdjIucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfc2NuX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMTVfc2NuX21hW1sicGxvdCJdXQpgYGAKCiMjIyMga28vaGV0IHAxNSBkTEdOCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDE1X2RsZ24iCnRhYmxlX2lucHV0IDwtIGdlbm90eXBlX3RhYmxlc1tbdGFibGVfbmFtZV1dCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCmtoX3AxNV9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fZGxnbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9kbGduIl1dLAogIG91dGxpbmUgPSBvdXRsaW5lLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gMTAsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm8va2hfcDE1X2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCiMjIE15IE1BIHBsb3R0ZXIgaXNuJ3QgYXMgc21hcnQgYXMgdGhlIHZvbGNhbm8gcGxvdHRlciwgdGhlIGdlbmVzIGFyZToKa2hfcDE1X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19kbGduIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X2RsZ24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSAxMCwgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vL2toX3AxNV9kbGduX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X2RsZ25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9kbGduX21hW1sicGxvdCJdXQpgYGAKCkEgcXVlcnkgZnJvbSBSYXNobWk6CgoiSSB3YXMgZGlzY3Vzc2luZyB3aXRoIERyLiBTcGVlciBhYm91dCB0aGUgZExHTiBkYXRhIGFuZCB3ZSBmb3VuZCBtb3N0bHkKcmV0aW5hbCBnZW5lcyBpbiBkTEdOIEhldC9LTyBvciB0aW1lIHBvaW50IGNvbXBhcmlzb24uIFBsZWFzZSBjaGVjayBpZgp0aG9zZSBhcmUgbm90IHJldGluYSBzYW1wbGVzLiIKCkkgY2hlY2tlZCB0aGUgc2FtcGxlcyBldGMgYW5kIGV2ZXJ5dGhpbmcgbG9va3Mgb2sgdG8gbWU7IHBlcmhhcHMgSSBjYW4KdXNlIHRoZSByZXN1bHRzIHRvIGxvb2sgYXQgdGhpcyBxdWVzdGlvbiBpbiBhbm90aGVyIHdheToKCkkgd2lsbCB0aGVyZWZvcmUgbG9hZCB0aGUgcDA4X2hldF9kbGduL3AwOF9rb19kbGduIHRhYmxlIGFuZCBjb21wYXJlCml0IHRvIHRoZSBwMDhfaGV0X3JldGluYS9wMDhfa29fcmV0aW5hIHRhYmxlIGRpcmVjdGx5LiAgSSB0aGluayB0aGF0CmlmIHRoZXNlIHR1cm4gb3V0IHRvIGJlIGlkZW50aWNhbCwgdGhlbiB0aGUgaHlwb3RoZXNpcyBzdWdnZXN0ZWQgYnkKdGhpcyBxdWVyeSBpcyBjb3JyZWN0LgoKTm90ZSwgaW4gb3JkZXIgdG8gZG8gdGhpcywgSSBtdXN0IHVzZSB0aGUgZnVsbCB0YWJsZXMsIG5vdCB0aGUKcG9zdC1pbmNsdXNpb24gdGFibGVzIGJlY2F1c2UgSSBjYW5ub3QgZ3VhcmFudGVlIHRoYXQgdGhleSB3aWxsIGhhdmUKaWRlbnRpY2FsIGdlbmUgSURzLgoKYGBge3J9CnJldGluYV90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMDhfcmV0aW5hIl1dCmRsZ25fdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDA4X2RsZ24iXV0KcmV0aW5hX3N1YnNldCA8LSByZXRpbmFfdGFibGVbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiZGVzZXFfbG9nZmMiKV0KY29sbmFtZXMocmV0aW5hX3N1YnNldCkgPC0gYygiSUQiLCAicmV0aW5hX2xvZ2ZjIikKZGxnbl9zdWJzZXQgPC0gZGxnbl90YWJsZVssIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJkZXNlcV9sb2dmYyIpXQpjb2xuYW1lcyhkbGduX3N1YnNldCkgPC0gYygiSUQiLCAiZGxnbl9sb2dmYyIpCm1lcmdlZCA8LSBtZXJnZShyZXRpbmFfc3Vic2V0LCBkbGduX3N1YnNldCwgYnkgPSAiSUQiKQpyb3duYW1lcyhtZXJnZWQpIDwtIG1ha2UubmFtZXMobWVyZ2VkW1siSUQiXV0sIHVuaXF1ZSA9IFRSVUUpCm1lcmdlZFtbIklEIl1dIDwtIE5VTEwKcGxvdHRlZCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKG1lcmdlZCkKcHAoZmlsZSA9ICJpbWFnZXMva2hfcDA4X3JldGluYV92c19kbGduX2Rlc2VxX2xvZ2ZjX3ZhbHVlcy5wbmciKQpwbG90dGVkW1sic2NhdHRlciJdXQpkZXYub2ZmKCkKcGxvdHRlZFtbInNjYXR0ZXIiXV0KYGBgCgpSYXNobWkgYXNrZWQgaWYgd2UgY291bGQgYWxzbyBkbyB0aGUgcDE1IGZvciB0aGlzIGNvbXBhcmlzb246CgpgYGB7cn0KcmV0aW5hX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AxNV9yZXRpbmEiXV0KZGxnbl90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMTVfZGxnbiJdXQpyZXRpbmFfc3Vic2V0IDwtIHJldGluYV90YWJsZVssIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJkZXNlcV9sb2dmYyIpXQpjb2xuYW1lcyhyZXRpbmFfc3Vic2V0KSA8LSBjKCJJRCIsICJyZXRpbmFfbG9nZmMiKQpkbGduX3N1YnNldCA8LSBkbGduX3RhYmxlWywgYygiZW5zZW1ibF9nZW5lX2lkIiwgImRlc2VxX2xvZ2ZjIildCmNvbG5hbWVzKGRsZ25fc3Vic2V0KSA8LSBjKCJJRCIsICJkbGduX2xvZ2ZjIikKbWVyZ2VkIDwtIG1lcmdlKHJldGluYV9zdWJzZXQsIGRsZ25fc3Vic2V0LCBieSA9ICJJRCIpCnJvd25hbWVzKG1lcmdlZCkgPC0gbWFrZS5uYW1lcyhtZXJnZWRbWyJJRCJdXSwgdW5pcXVlID0gVFJVRSkKbWVyZ2VkW1siSUQiXV0gPC0gTlVMTApwbG90dGVkIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIobWVyZ2VkKQpwcChmaWxlID0gImltYWdlcy9raF9wMTVfcmV0aW5hX3ZzX2RsZ25fZGVzZXFfbG9nZmNfdmFsdWVzLnBuZyIpCnBsb3R0ZWRbWyJzY2F0dGVyIl1dCmRldi5vZmYoKQpwbG90dGVkW1sic2NhdHRlciJdXQpgYGAKCiMjIyMgUmVwZWF0IHdpdGggdGhlIHN0cmljdCBmaWx0ZXIKCmBgYHtyfQpnZW5vdHlwZV9zdHJpY3RfdGFibGVzIDwtIGxpc3QoKQpnZW5vdHlwZV9zdHJpY3Rfc2lnIDwtIGxpc3QoKQpnZW5vdHlwZV9zdHJpY3RfZ3AgPC0gbGlzdCgpCmdlbm90eXBlX3N0cmljdF9jcCA8LSBsaXN0KCkKZ2Vub3R5cGVfc3RyaWN0X2VuIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKGdlbm90eXBlX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhnZW5vdHlwZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBnZW5vdHlwZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX3N0cmljdF9kZiA8LSBnZW5vdHlwZV9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlc19zdHJpY3QgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyhnZW5vdHlwZV9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXNfc3RyaWN0KQogIGluY2x1ZGVfZmlsZW5hbWUgPC0gZ2x1ZSgiMTRnZW5vdHlwZV9zdHJpY3RfY29udHJhc3RzX2V4Y2VsL3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiMTRnZW5vdHlwZV9zdHJpY3RfY29udHJhc3RzX2V4Y2VsL3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIGdlbm90eXBlX3N0cmljdF90YWJsZXNbW25hbWVdXSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIGdlbm90eXBlX2RlLCBleHRyYV9hbm5vdCA9IGluY2x1ZGVfc3RyaWN0X2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlc19zdHJpY3QpCiAgcHJpbnQoZ2Vub3R5cGVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dKQogIGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgZ2Vub3R5cGVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludChnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV0pCiAgbnVtX3Jvd3MgPC0gbnJvdyhnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBpZiAobnVtX3Jvd3MgPj0gMTApIHsKICAgIG1lc3NhZ2UoIlBlcmZvcm1pbmcgZ3Byb2ZpbGVyL2NsdXN0ZXJQcm9maWxlci4iKQogICAgZ2Vub3R5cGVfc3RyaWN0X2dwW1tuYW1lXV0gPC0gYWxsX2dwcm9maWxlcihnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dIDwtIGFsbF9jcHJvZmlsZXIoCiAgICAgIGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXSwgZ2Vub3R5cGVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBnb19sZXZlbCA9IGdvX2xldmVsLAogICAgICBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgICNpZiAoIWlzLm51bGwoZ2V0MCgibTJfZ3NjIikpKSB7CiAgICAjICBnZW5vdHlwZV9zdHJpY3RfZW5bW25hbWVdXSA8LSBhbGxfZW5yaWNoZXIoZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dLCBnc2MgPSBtMl9nc2MsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBmcm9tID0gIkVOU0VNQkwiLCB0byA9ICJTWU1CT0wiKQogICAgI30KICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKGdlbm90eXBlX3N0cmljdF9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMTUiLCBzdWZmaXggPSAic3RyaWN0IikKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dLCBwcmVmaXggPSAiMTUiLCBzdWZmaXggPSAic3RyaWN0IikKICAgICNlbl93cml0dGVuIDwtIHdyaXRlX2FsbF9lbihnZW5vdHlwZV9zdHJpY3RfZW5bW25hbWVdXSkKICB9IGVsc2UgewogICAgd2FybmluZygiVGhlcmUgYXJlIGxlc3MgdGhhbiAxMCBnZW5lcyB1cCBhbmQgZG93biBpbiB0aGUgIiwgbmFtZSwgIiBjb21wYXJpc29uLiIpCiAgICBtZXNzYWdlKCJUaGVyZSBhcmUgbGVzcyB0aGFuIDEwIGdlbmVzIHVwIGFuZCBkb3duIGluIHRoZSAiLCBuYW1lLCAiIGNvbXBhcmlzb24uIikKICB9Cn0KYGBgCgojIEdlbm90eXBlIFN0cmljdCBwbG90cwoKYGBge3J9CmZvciAoayBpbiBzZXFfYWxvbmcoZ2Vub3R5cGVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGdlbm90eXBlX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGdlbm90eXBlX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfc3RyaWN0X2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzX3N0cmljdCA8LSBnZW5vdHlwZV9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlc19zdHJpY3QpCiAgbnVtX3Jvd3MgPC0gbnJvdyhnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbnJvdyhnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgIyMgIzEgaXMgdXAgYW5kICMyIGlzIGRvd24sIGF2b2lkaW5nIHR5cGVvcyBoZXJlLgogIG51bV9vYmplY3RzIDwtIGxlbmd0aChnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIHdlbnQgd3JvbmcgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfdXAkIikpCiAgICBkb3ducCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXMoZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl9kb3duJCIpKQogICAgaWYgKGxlbmd0aCh1cHApID4gMCkgewogICAgICBtZl9zaWcgPC0gZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkNDX2VucmljaCJdXQogICAgICBicF9zaWcgPC0gZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9tZl9zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2NjX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9icF9zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgICBpZiAobGVuZ3RoKGRvd25wKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fZG93bl9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fZG93bl9tZl9zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIGNhdGVvZ29yaWVzID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fYnBfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICB9Cn0KYGBgCgpHaXZlbiB0aGlzIHN0cmljdGVyIGZpbHRlciwgSSB0aGluayBubyBnZW5lcyBwYXNzIGluIHRoZSBnZW5vbWUKY29tcGFyaXNvbnMuCgojIyMgTG9jYXRpb24gY29udHJhc3RzIHdpdGggZ2VuZXMgcmVtb3ZlZC9rZXB0CgpXZSB3aWxsIG5vdyByZXBlYXQgdGhlIGFib3ZlIHRhc2tzIHNlZWtpbmcgbG9jYXRpb24gZGlmZmVyZW5jZXMKaW5zdGVhZCBvZiBnZW5vdHlwZTsgZXNzZW50aWFsbHkgSSBjb3B5L3Bhc3RlZCB0aGUgYWJvdmUgd2l0aApzL2dlbm90eXBlL2xvY2F0aW9uL2cuCgpgYGB7cn0KbG9jYXRpb25fdGFibGVzX2Z1bGwgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgbG9jYXRpb25fZGUsIGtlZXBlcnMgPSBsb2NhdGlvbl9rZWVwZXJzLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIxN2Z1bGxfbG9jYXRpb25fY29udHJhc3RzL2xvY2F0aW9uX2Z1bGxfdGFibGVzLXZ7dmVyfS54bHN4IikpCmxvY2F0aW9uX3RhYmxlc19mdWxsCmxvY2F0aW9uX3NpZ19mdWxsIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgbG9jYXRpb25fdGFibGVzX2Z1bGwsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCIxN2Z1bGxfbG9jYXRpb25fY29udHJhc3RzL2xvY2F0aW9uX2Z1bGxfc2lnLXZ7dmVyfS54bHN4IikpCmxvY2F0aW9uX3NpZ19mdWxsCmxvY2F0aW9uX2Z1bGxfdXBzZXQgPC0gdXBzZXRyX3NpZyhsb2NhdGlvbl9zaWdfZnVsbCkKbG9jYXRpb25fZnVsbF9pbnRlcnNlY3RzIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcygKICBsb2NhdGlvbl9mdWxsX3Vwc2V0LAogIGV4Y2VsID0gImV4Y2VsLzE3ZnVsbF9sb2NhdGlvbl9jb250cmFzdHMvbG9jYXRpb25fZnVsbF9nZW5lX2dyb3Vwcy54bHN4IikKYGBgCgpgYGB7cn0KbG9jYXRpb25fdGFibGVzIDwtIGxpc3QoKQpsb2NhdGlvbl9zaWcgPC0gbGlzdCgpCmxvY2F0aW9uX2dwIDwtIGxpc3QoKQpsb2NhdGlvbl9jcCA8LSBsaXN0KCkKZm9yIChrIGluIHNlcV9hbG9uZyhsb2NhdGlvbl9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXMobG9jYXRpb25fa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gbG9jYXRpb25fa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNbW25hbWVdXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyhsb2NhdGlvbl9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXMpCiAgaW5jbHVkZV9maWxlbmFtZSA8LSBnbHVlKCIxOGxvY2F0aW9uX2NvbnRyYXN0cy97bmFtZX1faW5jbHVkaW5nX3d0X3tsZmNfY3V0b2ZmfV9kZWNyZWFzZWRfdGFibGUtdnt2ZXJ9Lnhsc3giKQogIGluY2x1ZGVfc2lnX2ZpbGVuYW1lIDwtIGdsdWUoIjE4bG9jYXRpb25fY29udHJhc3RzL3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIGxvY2F0aW9uX3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbG9jYXRpb25fZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9kZiwKICAgIGtlZXBlcnMgPSBrZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSwgd2FudGVkX2dlbmVzID0gaW5jbHVkZXMpCiAgcHJpbnQobG9jYXRpb25fdGFibGVzW1tuYW1lXV0pCiAgbG9jYXRpb25fc2lnW1tuYW1lXV0gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGxvY2F0aW9uX3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludChsb2NhdGlvbl9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBpZiAobnVtX3Jvd3MgPiAxMCkgewogICAgbG9jYXRpb25fZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKGxvY2F0aW9uX3NpZ1tbbmFtZV1dLCBzcGVjaWVzID0gIm1tdXNjdWx1cyIpCiAgICBsb2NhdGlvbl9jcFtbbmFtZV1dIDwtIGFsbF9jcHJvZmlsZXIoCiAgICAgIGxvY2F0aW9uX3NpZ1tbbmFtZV1dLCBsb2NhdGlvbl90YWJsZXNbW25hbWVdXSwKICAgICAgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgZ29fbGV2ZWwgPSBnb19sZXZlbCwgb3JnZGJfZnJvbSA9IG9yZ2RiX2Zyb20sCiAgICAgIG1heF9ncm91cHNpemUgPSBtYXhfZ3JvdXBzaXplLCBvcmdhbmlzbSA9ICJtb3VzZSIpCiAgICBjcF93cml0dGVuIDwtIHdyaXRlX2FsbF9jcChsb2NhdGlvbl9jcFtbbmFtZV1dLCBwcmVmaXggPSAiMTkiKQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AobG9jYXRpb25fZ3BbW25hbWVdXSwgcHJlZml4ID0gIjE5IikKICB9Cn0KYGBgCgpQcmludCBvdXQgYWxsIHRoZSBwbG90cyBpbiBhIHNlcGFyYXRlIGJsb2NrLgoKYGBge3J9CmZvciAoayBpbiBzZXFfYWxvbmcobG9jYXRpb25fa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGxvY2F0aW9uX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGxvY2F0aW9uX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tuYW1lXV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gbG9jYXRpb25faW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tpbmNsdWRlX25hbWVdXQogIHN1bW1hcnkocm93bmFtZXMobG9jYXRpb25fc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzKQogIG51bV9yb3dzIDwtIG5yb3cobG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG5yb3cobG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKQogIG5yb3cobG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgbnVtX29iamVjdHMgPC0gbGVuZ3RoKGxvY2F0aW9uX2NwW1tuYW1lXV0pCiAgaWYgKG51bV9vYmplY3RzID09IDApIHsKICAgIHdhcm5pbmcoIlNvbWV0aGluZyB3ZW50IHdyb25nIGluIGFsbF9jcHJvZmlsZXIuIikKICB9IGVsc2UgewogICAgdXBwIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhsb2NhdGlvbl9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfdXAkIikpCiAgICBkb3ducCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXMobG9jYXRpb25fY3BbW25hbWVdXSksIHBhdHRlcm4gPSAiX2Rvd24kIikpCiAgICBpZiAobGVuZ3RoKHVwcCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBsb2NhdGlvbl9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIGxvY2F0aW9uX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkNDX2VucmljaCJdXQogICAgICBicF9zaWcgPC0gbG9jYXRpb25fY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfY2Nfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICAgIGlmIChsZW5ndGgoZG93bnApID4gMCkgewogICAgICBtZl9zaWcgPC0gbG9jYXRpb25fY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIGxvY2F0aW9uX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBsb2NhdGlvbl9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSAxMikKICAgICAgY2NfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKQ29sZW5zbyBzZW50IGEgc3BlY2lmaWMgcXVlcnkgb2YgaW50ZXJlc3QsIGNvbXBhcmluZyBTQ04gdnMuIFJldGluYXMKYXQgcDA4IGluIHRoZSBoZXRlcm96eWdvdGVzIGluY2x1ZGluZyBhIHNldCBvZiBnZW5lcyBvZiBwYXJ0aWN1bGFyCmludGVyZXN0LiAgUGVyaGFwcyBJIGNhbiB1c2Ugc29tZSBvZiB0aGVzZSBhcyBtYXJrZXJzIHRvIHF1YWxpdHkKY29udHJvbCBteSB3b3JrIGluIHRoZSBmdXR1cmU/CgpIZXJlIGFyZSB0aGUgZ2VuZXM6CgpPcG40LCBFb21lcywgVHJwYzcsIE9wcm0xLCBOcjRhMywgVGJ4MjAsIElyeDYsIEFXNTUxOTg0LCBQY2RoMTksCkFkY3lhcDEsIEJhaWFwMywgQ2hsMSwgR3JpbjNhLCBJZ2YxLCBHcmlhMSwgR3JpbjJkLCBHcmluM2EsIENocm5hNiwKQ2hybmEzLCBIdHI1YSwgSHRyMmEsIEh0cjcsIElyeDQsIFBseG5DMSwgU2VtYTZkLCBTZW1hNGYsIFNlbWE0YSwKU2VtYTZiLCBMcnJjNGIsIExycmM1OCwgTHJyYzNiLCBXbnQ0LCBXbnQ5YiwgQ3R4bjMsIFRlbm0xLCBHbmExNCwKUmdzNCwgUmdzNiwgUmdzNQoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3RhYmxlc1tbInNyX3AwOF9oZXQiXV0KdGFibGVfbmFtZSA8LSAic3JfcDA4X2hldCIKdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmdfZ2VuZXMgPC0gYygiT3BuNCIsICJFb21lcyIsICJUcnBjNyIsICJPcHJtMSIsICJOcjRhMyIsICJUYngyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgIklyeDYiLCAiQVc1NTE5ODQiLCAiUGNkaDE5IiwgIkFkY3lhcDFyMSIsICJCYWlhcDMiLAogICAgICAgICAgICAgICAgICAgICAgICJDaGwxIiwgIkdyaW4zYSIsICJJZ2YxIiwgIkdyaWExIiwgIkdyaW4yZCIsICJHcmluM2EiLAogICAgICAgICAgICAgICAgICAgICAgICJDaHJuYTYiLCAiQ2hybmEzIiwgIkh0cjVhIiwgIkh0cjJhIiwgIkh0cjciLCAiSXJ4NCIsCiAgICAgICAgICAgICAgICAgICAgICAgIlBseG5DMSIsICJTZW1hNmQiLCAiU2VtYTRmIiwgIlNlbWE0YSIsICJTZW1hNmIiLCAiTHJyYzRiIiwKICAgICAgICAgICAgICAgICAgICAgICAiTHJyYzU4IiwgIkxycmMzYiIsICJXbnQ0IiwgIldudDliIiwgIkN0eG4zIiwgIlRlbm0xIiwgIkduYTE0IiwKICAgICAgICAgICAgICAgICAgICAgICAiUmdzNCIsICJSZ3M2IiwgIlJnczUiLCAiUG91NGYyIiwgIkNocm5iMyIsICJCY2FuIikKc3JfcDA4X2hldF92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImhldF9yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfc2NuIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMjBsb2NhdGlvbl9tYV92b2xjYW5vL3NyX3AwOF9oZXRfdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AwOF9oZXRfdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDA4X2hldF92b2xjYW5vW1sicGxvdCJdXQpzcl9wMDhfaGV0X21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjBsb2NhdGlvbl9tYV92b2xjYW5vL3NyX3AwOF9oZXRfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpgYGAKCiMjIyBBbHNvIHRoZSBrbwoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3RhYmxlc1tbInNyX3AwOF9rbyJdXQp0YWJsZV9uYW1lIDwtICJzcl9wMDhfa28iCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCnNyX3AwOF9rb192b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3NjbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjIwbG9jYXRpb25fbWFfdm9sY2Fuby9zcl9wMDhfa29fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AwOF9rb192b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfa29fdm9sY2Fub1tbInBsb3QiXV0Kc3JfcDA4X2tvX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1sia29fc2NuIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjIwbG9jYXRpb25fbWFfdm9sY2Fuby9zcl9wMDhfa29fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfa29fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AwOF9rb19tYVtbInBsb3QiXV0KYGBgCgpgYGB7cn0KdGFibGVfaW5wdXQgPC0gbG9jYXRpb25fdGFibGVzW1sic3JfcDE1X2hldCJdXQp0YWJsZV9uYW1lIDwtICJzcl9wMTVfaGV0Igp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKCJPcG40IiwgIkVvbWVzIiwgIlRycGM3IiwgIk9wcm0xIiwgIk5yNGEzIiwgIlRieDIwIiwKICAgICAgICAgICAgICAgICAgICAgICAiSXJ4NiIsICJBVzU1MTk4NCIsICJQY2RoMTkiLCAiQWRjeWFwMXIxIiwgIkJhaWFwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNobDEiLCAiR3JpbjNhIiwgIklnZjEiLCAiR3JpYTEiLCAiR3JpbjJkIiwgIkdyaW4zYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNocm5hNiIsICJDaHJuYTMiLCAiSHRyNWEiLCAiSHRyMmEiLCAiSHRyNyIsICJJcng0IiwKICAgICAgICAgICAgICAgICAgICAgICAiUGx4bkMxIiwgIlNlbWE2ZCIsICJTZW1hNGYiLCAiU2VtYTRhIiwgIlNlbWE2YiIsICJMcnJjNGIiLAogICAgICAgICAgICAgICAgICAgICAgICJMcnJjNTgiLCAiTHJyYzNiIiwgIldudDQiLCAiV250OWIiLCAiQ3R4bjMiLCAiVGVubTEiLCAiR25hMTQiLAogICAgICAgICAgICAgICAgICAgICAgICJSZ3M0IiwgIlJnczYiLCAiUmdzNSIsICJQb3U0ZjIiLCAiQ2hybmIzIiwgIkJjYW4iKQpzcl9wMTVfaGV0X3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm8vc3JfcDE1X2hldF92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDE1X2hldF92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMTVfaGV0X3ZvbGNhbm9bWyJwbG90Il1dCnNyX3AxNV9oZXRfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm8vc3JfcDE1X2hldF9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AxNV9oZXRfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AxNV9oZXRfbWFbWyJwbG90Il1dCmBgYAoKIyMjIEFsc28gdGhlIGtvCgpgYGB7cn0KdGFibGVfaW5wdXQgPC0gbG9jYXRpb25fdGFibGVzW1sic3JfcDE1X2tvIl1dCnRhYmxlX25hbWUgPC0gInNyX3AxNV9rbyIKdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0Kc3JfcDE1X2tvX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1sia29fc2NuIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHBvaW50LnBhZGRpbmcgPSAwLjIpCnBwKGZpbGUgPSAiMjBsb2NhdGlvbl9tYV92b2xjYW5vL3NyX3AxNV9rb192b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQpzcl9wMTVfa29fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDE1X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnNyX3AxNV9rb19tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm8vc3JfcDE1X2tvX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDE1X2tvX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMTVfa29fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBUZXN0IGEgc3BlY2lmaWMgbG9jYXRpb24gcXVlcnkgZm9yIGR1cGxpY2F0ZWQgSURzCgpMZXQgdXMgc2VlIGlmIGFueSBFbnNlbWJsIGdlbmUgSURzIGFuZC9vciBNR0kgSURzIGFyZSBzaGFyZWQgaW4gdGhlCndvcmtzaGVldCBsb2NhdGlvbl9zcl9wMDhfa29faW5jbHVkaW5nX3d0XzAuMV9kZWNyZWFzZWRfc2lnIHVwL2Rvd24uCgpgYGB7cn0KdGVzdF90YWJsZV91cCA8LSBsb2NhdGlvbl9zaWdbWyJzcl9wMDhfa28iXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dCnRlc3RfdGFibGVfZG93biA8LSBsb2NhdGlvbl9zaWdbWyJzcl9wMDhfa28iXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0KCnF1ZXJ5IDwtIGxpc3QoInVwIiA9IHJvd25hbWVzKHRlc3RfdGFibGVfdXApLAogICAgICAgICAgICAgICJkb3duIiA9IHJvd25hbWVzKHRlc3RfdGFibGVfZG93bikpCnF1ZXJ5X3Vwc2V0IDwtIFVwU2V0Ujo6ZnJvbUxpc3QocXVlcnkpClVwU2V0Ujo6dXBzZXQocXVlcnlfdXBzZXQpCgpxdWVyeSA8LSBsaXN0KCJ1cCIgPSB0ZXN0X3RhYmxlX3VwW1sibWdpX3N5bWJvbCJdXSwKICAgICAgICAgICAgICAiZG93biIgPSB0ZXN0X3RhYmxlX2Rvd25bWyJtZ2lfc3ltYm9sIl1dKQpxdWVyeV91cHNldCA8LSBVcFNldFI6OmZyb21MaXN0KHF1ZXJ5KQpVcFNldFI6OnVwc2V0KHF1ZXJ5X3Vwc2V0KQojIyBvaywgZ29vZC4KYGBgCgojIyMjIFJlcGVhdCB3aXRoIHRoZSBzdHJpY3QgZmlsdGVyCgpgYGB7cn0KbG9jYXRpb25fc3RyaWN0X3RhYmxlcyA8LSBsaXN0KCkKbG9jYXRpb25fc3RyaWN0X3NpZyA8LSBsaXN0KCkKbG9jYXRpb25fc3RyaWN0X2dwIDwtIGxpc3QoKQpsb2NhdGlvbl9zdHJpY3RfY3AgPC0gbGlzdCgpCmZvciAoayBpbiBzZXFfYWxvbmcobG9jYXRpb25fa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGxvY2F0aW9uX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGxvY2F0aW9uX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zX3N0cmljdFtbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX25hbWVdXQogIGZvdW5kX2luY2x1ZGVzIDwtIHJvd25hbWVzKGxvY2F0aW9uX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcwogIHN1bW1hcnkoZm91bmRfaW5jbHVkZXMpCiAgaWYgKHN1bShmb3VuZF9pbmNsdWRlcykgPT0gMCkgewogICAgbmV4dAogIH0KICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjIxbG9jYXRpb25fc3RyaWN0X2NvbnRyYXN0cy97bmFtZX1faW5jbHVkaW5nX3d0X3tsZmNfY3V0b2ZmfV9kZWNyZWFzZWRfdGFibGUtdnt2ZXJ9Lnhsc3giKQogIGluY2x1ZGVfc2lnX2ZpbGVuYW1lIDwtIGdsdWUoIjIxbG9jYXRpb25fc3RyaWN0X2NvbnRyYXN0cy97bmFtZX1faW5jbHVkaW5nX3d0X3tsZmNfY3V0b2ZmfV9kZWNyZWFzZWRfc2lnLXZ7dmVyfS54bHN4IikKICBsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBsb2NhdGlvbl9kZSwgZXh0cmFfYW5ub3QgPSBpbmNsdWRlX2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlcykKICBwcmludChsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1tuYW1lXV0pCiAgbG9jYXRpb25fc3RyaWN0X3NpZ1tbbmFtZV1dIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3cobG9jYXRpb25fc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+IDEwKSB7CiAgICBsb2NhdGlvbl9zdHJpY3RfZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXSwgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQogICAgbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgbG9jYXRpb25fc3RyaWN0X3NpZ1tbbmFtZV1dLCBsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1tuYW1lXV0sCiAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGdvX2xldmVsID0gZ29fbGV2ZWwsIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLAogICAgICBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSwgb3JnYW5pc20gPSAibW91c2UiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AobG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV0sIHByZWZpeCA9ICIyMiIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AobG9jYXRpb25fc3RyaWN0X2dwW1tuYW1lXV0sIHByZWZpeCA9ICIyMiIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogIH0KfQpgYGAKClByaW50IG91dCBhbGwgdGhlIHBsb3RzIGluIGEgc2VwYXJhdGUgYmxvY2suCgpgYGB7cn0KZm9yIChrIGluIHNlcV9hbG9uZyhsb2NhdGlvbl9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXMobG9jYXRpb25fa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gbG9jYXRpb25fa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0W1tuYW1lXV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gbG9jYXRpb25faW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gbG9jYXRpb25faW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyhsb2NhdGlvbl9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXMpCiAgbnVtX3Jvd3MgPC0gbnJvdyhsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBucm93KGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbnJvdyhsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgbnVtX29iamVjdHMgPC0gbGVuZ3RoKGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dKQogIGlmIChudW1fb2JqZWN0cyA9PSAwKSB7CiAgICB3YXJuaW5nKCJTb21ldGhpbmcgd2VudCB3cm9uZyBpbiBhbGxfY3Byb2ZpbGVyLiIpCiAgfSBlbHNlIHsKICAgIHVwcCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXMobG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXSksIHBhdHRlcm4gPSAiX2Rvd24kIikpCiAgICBpZiAobGVuZ3RoKHVwcCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSBsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfY2Nfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICAgIGlmIChsZW5ndGgoZG93bnApID4gMCkgewogICAgICBtZl9zaWcgPC0gbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSBsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSAxMikKICAgICAgY2NfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2NjX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKQ29sZW5zbyBzZW50IGEgc3BlY2lmaWMgcXVlcnkgb2YgaW50ZXJlc3QsIGNvbXBhcmluZyBTQ04gdnMuIFJldGluYXMKYXQgcDA4IGluIHRoZSBoZXRlcm96eWdvdGVzIGluY2x1ZGluZyBhIHNldCBvZiBnZW5lcyBvZiBwYXJ0aWN1bGFyCmludGVyZXN0LiAgUGVyaGFwcyBJIGNhbiB1c2Ugc29tZSBvZiB0aGVzZSBhcyBtYXJrZXJzIHRvIHF1YWxpdHkKY29udHJvbCBteSB3b3JrIGluIHRoZSBmdXR1cmU/CgpIZXJlIGFyZSB0aGUgZ2VuZXM6CgpPcG40LCBFb21lcywgVHJwYzcsIE9wcm0xLCBOcjRhMywgVGJ4MjAsIElyeDYsIEFXNTUxOTg0LCBQY2RoMTksCkFkY3lhcDEsIEJhaWFwMywgQ2hsMSwgR3JpbjNhLCBJZ2YxLCBHcmlhMSwgR3JpbjJkLCBHcmluM2EsIENocm5hNiwKQ2hybmEzLCBIdHI1YSwgSHRyMmEsIEh0cjcsIElyeDQsIFBseG5DMSwgU2VtYTZkLCBTZW1hNGYsIFNlbWE0YSwKU2VtYTZiLCBMcnJjNGIsIExycmM1OCwgTHJyYzNiLCBXbnQ0LCBXbnQ5YiwgQ3R4bjMsIFRlbm0xLCBHbmExNCwKUmdzNCwgUmdzNiwgUmdzNQoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3N0cmljdF90YWJsZXNbWyJzcl9wMDhfaGV0Il1dCnRhYmxlX25hbWUgPC0gInNyX3AwOF9oZXQiCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCmludGVyZXN0aW5nX2dlbmVzIDwtIGMoIk9wbjQiLCAiRW9tZXMiLCAiVHJwYzciLCAiT3BybTEiLCAiTnI0YTMiLCAiVGJ4MjAiLAogICAgICAgICAgICAgICAgICAgICAgICJJcng2IiwgIkFXNTUxOTg0IiwgIlBjZGgxOSIsICJBZGN5YXAxcjEiLCAiQmFpYXAzIiwKICAgICAgICAgICAgICAgICAgICAgICAiQ2hsMSIsICJHcmluM2EiLCAiSWdmMSIsICJHcmlhMSIsICJHcmluMmQiLCAiR3JpbjNhIiwKICAgICAgICAgICAgICAgICAgICAgICAiQ2hybmE2IiwgIkNocm5hMyIsICJIdHI1YSIsICJIdHIyYSIsICJIdHI3IiwgIklyeDQiLAogICAgICAgICAgICAgICAgICAgICAgICJQbHhuQzEiLCAiU2VtYTZkIiwgIlNlbWE0ZiIsICJTZW1hNGEiLCAiU2VtYTZiIiwgIkxycmM0YiIsCiAgICAgICAgICAgICAgICAgICAgICAgIkxycmM1OCIsICJMcnJjM2IiLCAiV250NCIsICJXbnQ5YiIsICJDdHhuMyIsICJUZW5tMSIsICJHbmExNCIsCiAgICAgICAgICAgICAgICAgICAgICAgIlJnczQiLCAiUmdzNiIsICJSZ3M1IiwgIlBvdTRmMiIsICJDaHJuYjMiLCAiQmNhbiIpCnNyX3AwOF9oZXRfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjI0bG9jYXRpb25fbWFfdm9sY2Fub19zdHJpY3Qvc3JfcDA4X2hldF92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2hldF92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfaGV0X3ZvbGNhbm9bWyJwbG90Il1dCnNyX3AwOF9oZXRfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyNGxvY2F0aW9uX21hX3ZvbGNhbm9fc3RyaWN0L3NyX3AwOF9oZXRfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpgYGAKCiMjIyBBbHNvIHRoZSBrbwoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3N0cmljdF90YWJsZXNbWyJzcl9wMDhfa28iXV0KdGFibGVfbmFtZSA8LSAic3JfcDA4X2tvIgp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpzcl9wMDhfa29fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIyNGxvY2F0aW9uX21hX3ZvbGNhbm9fc3RyaWN0L3NyX3AwOF9rb192b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AwOF9rb192b2xjYW5vW1sicGxvdCJdXQpzcl9wMDhfa29fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjRsb2NhdGlvbl9tYV92b2xjYW5vX3N0cmljdC9zcl9wMDhfa29fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfa29fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AwOF9rb19tYVtbInBsb3QiXV0KYGBgCgojIyMgQWxzbyB0aGUga28KCmBgYHtyfQp0YWJsZV9pbnB1dCA8LSBsb2NhdGlvbl90YWJsZXNbWyJzcl9wMTVfa28iXV0KdGFibGVfbmFtZSA8LSAic3JfcDE1X2tvIgp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpzcl9wMTVfa29fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCwgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgcG9pbnQucGFkZGluZyA9IDAuMikKcHAoZmlsZSA9ICIyNGxvY2F0aW9uX21hX3ZvbGNhbm9fc3RyaWN0L3NyX3AxNV9rb192b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQpzcl9wMTVfa29fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDE1X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnNyX3AxNV9rb19tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyNGxvY2F0aW9uX21hX3ZvbGNhbm9fc3RyaWN0L3NyX3AxNV9rb19tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AxNV9rb19tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDE1X2tvX21hW1sicGxvdCJdXQpgYGAKCiMjIyBBbmQgdGltZQoKYGBge3J9CnRpbWVfdGFibGVzX2Z1bGwgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgdGltZV9kZSwga2VlcGVycyA9IHRpbWVfa2VlcGVycywKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIyNWZ1bGxfY29udHJhc3RzX3RpbWUvZnVsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKdGltZV9zaWdfZnVsbCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIHRpbWVfdGFibGVzX2Z1bGwsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCIyNWZ1bGxfY29udHJhc3RzX3RpbWUvZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKYGBgCgpgYGB7cn0KdGltZV90YWJsZXMgPC0gbGlzdCgpCnRpbWVfc2lnIDwtIGxpc3QoKQp0aW1lX2dwIDwtIGxpc3QoKQp0aW1lX2NwIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKHRpbWVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKHRpbWVfa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gdGltZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZXMgPC0gdGltZV9pbmNsdXNpb25zW1tuYW1lXV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gdGltZV9pbmNsdXNpb25zW1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKHRpbWVfc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzKQogIGluY2x1ZGVfZmlsZW5hbWUgPC0gZ2x1ZSgiMjZ0aW1lX2NvbnRyYXN0cy97bmFtZX1faW5jbHVkaW5nX3d0X3tsZmNfY3V0b2ZmfV9kZWNyZWFzZWRfdGFibGUtdnt2ZXJ9Lnhsc3giKQogIGluY2x1ZGVfc2lnX2ZpbGVuYW1lIDwtIGdsdWUoIjI2dGltZV9jb250cmFzdHMve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgdGltZV90YWJsZXNbW25hbWVdXSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIHRpbWVfZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9kZiwKICAgIGtlZXBlcnMgPSBrZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSwgd2FudGVkX2dlbmVzID0gaW5jbHVkZXMpCiAgcHJpbnQodGltZV90YWJsZXNbW25hbWVdXSkKICB0aW1lX3NpZ1tbbmFtZV1dIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICB0aW1lX3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludCh0aW1lX3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBpZiAobnVtX3Jvd3MgPiAxMCkgewogICAgdGltZV9ncFtbbmFtZV1dIDwtIGFsbF9ncHJvZmlsZXIodGltZV9zaWdbW25hbWVdXSwgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AodGltZV9ncFtbbmFtZV1dKQogICAgdGltZV9jcFtbbmFtZV1dIDwtIGFsbF9jcHJvZmlsZXIoCiAgICAgIHRpbWVfc2lnW1tuYW1lXV0sIHRpbWVfdGFibGVzW1tuYW1lXV0sIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIG9yZ2FuaXNtID0gIm1vdXNlIiwKICAgICAgb3JnZGJfZnJvbSA9IG9yZ2RiX2Zyb20sIGdvX2xldmVsID0gZ29fbGV2ZWwsIG1heF9ncm91cHNpemUgPSBtYXhfZ3JvdXBzaXplKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AodGltZV9jcFtbbmFtZV1dLCBwcmVmaXggPSAiMjciKQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AodGltZV9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMjciKQogIH0KfQpgYGAKClNlbmQgdGhlIHBsb3RzIHNlcGFyYXRlbHkuCgpgYGB7cn0KZm9yIChrIGluIHNlcV9hbG9uZyh0aW1lX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyh0aW1lX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIHRpbWVfa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc1tbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIHRpbWVfaW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSB0aW1lX2luY2x1c2lvbnNbW2luY2x1ZGVfbmFtZV1dCiAgbnVtX3Jvd3MgPC0gbnJvdyh0aW1lX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyh0aW1lX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIG51bV9vYmplY3RzIDwtIGxlbmd0aCh0aW1lX2NwW1tuYW1lXV0pCiAgaWYgKG51bV9vYmplY3RzID09IDApIHsKICAgIHdhcm5pbmcoIlNvbWV0aGluZyBmYWlsZWQgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKHRpbWVfY3BbW25hbWVdXSksIHBhdHRlcm4gPSAiX3VwJCIpKQogICAgZG93bnAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKHRpbWVfY3BbW25hbWVdXSksIHBhdHRlcm4gPSAiX2Rvd24kIikpCiAgICBpZiAobGVuZ3RoKHVwcCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV91cF9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fdXBfY2Nfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X3VwX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICAgIGlmIChsZW5ndGgoZG93bnApID4gMCkgewogICAgICBtZl9zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIkNDX2VucmljaCJdXQogICAgICBicF9zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzL3tuYW1lfV9kb3duX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fY2Nfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90cy97bmFtZX1fZG93bl9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHMve25hbWV9X2Rvd25fYnBfc2lnX2Jhci5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICB9Cn0KYGBgCgojIyBWb2xjYW5vIHBsb3RzIGJ5IHRpbWUKCiMjIyB0X2hldF9kbGduCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAidF9oZXRfZGxnbiIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2hldF9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3RfaGV0X2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKdF9oZXRfZGxnbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnRfaGV0X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3RfaGV0X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQp0X2hldF9kbGduX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9kbGduX21hW1sicGxvdCJdXQpgYGAKCiMjIyB0X2tvX2RsZ24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJ0X2tvX2RsZ24iCnRhYmxlX2lucHV0IDwtIHRpbWVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KdF9rb19kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3Rfa29fZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQp0X2tvX2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKdF9rb19kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnRfa29fZGxnbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm8vdF9rb19kbGduX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9rb19kbGduX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2tvX2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIHRfaGV0X3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfaGV0X3JldGluYSIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2hldF9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X3JldGluYSJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3RfaGV0X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQp0X2hldF9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKdF9oZXRfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnRfaGV0X3JldGluYV9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfcmV0aW5hIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3RfaGV0X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnRfaGV0X3JldGluYV9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKdF9oZXRfcmV0aW5hX21hW1sicGxvdCJdXQpgYGAKCiMjIyB0X2tvX3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfa29fcmV0aW5hIgp0YWJsZV9pbnB1dCA8LSB0aW1lX3RhYmxlc1tbdGFibGVfbmFtZV1dCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCnRfa29fcmV0aW5hX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3Rfa29fcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIpCnRfa29fcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnRfa29fcmV0aW5hX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyOXRpbWVfbWFfdm9sY2Fuby90X2tvX3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnRfa29fcmV0aW5hX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2tvX3JldGluYV9tYVtbInBsb3QiXV0KYGBgCgojIyB0X2hldF9zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJ0X2hldF9zY24iCnRhYmxlX2lucHV0IDwtIHRpbWVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KdF9oZXRfc2NuX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAibWdpX3N5bWJvbCIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vL3RfaGV0X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQp0X2hldF9zY25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKdF9oZXRfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCnRfaGV0X3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm8vdF9oZXRfc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9oZXRfc2NuX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMgdF9rb19zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJ0X2tvX3NjbiIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2tvX3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgbGFiZWxfY29sdW1uID0gIm1naV9zeW1ib2wiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCwgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgcG9pbnQucGFkZGluZyA9IDAuMikKcHAoZmlsZSA9ICIyOXRpbWVfbWFfdm9sY2Fuby90X2tvX3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyKQp0X2tvX3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2tvX3Njbl92b2xjYW5vW1sicGxvdCJdXQp0X2tvX3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJtZ2lfc3ltYm9sIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm8vdF9rb19zY25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQp0X2tvX3Njbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKdF9rb19zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBSZXBlYXQgd2l0aCB0aGUgc3RyaWN0IGZpbHRlcgoKYGBge3J9CnRpbWVfc3RyaWN0X3RhYmxlcyA8LSBsaXN0KCkKdGltZV9zdHJpY3Rfc2lnIDwtIGxpc3QoKQp0aW1lX3N0cmljdF9ncCA8LSBsaXN0KCkKdGltZV9zdHJpY3RfY3AgPC0gbGlzdCgpCnRpbWVfc3RyaWN0X2VuIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKHRpbWVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKHRpbWVfa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gdGltZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIHRpbWVfaW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gdGltZV9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9uYW1lXV0KICBmb3VuZF9pbmNsdWRlcyA8LSByb3duYW1lcyh0aW1lX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcwogIHN1bW1hcnkoZm91bmRfaW5jbHVkZXMpCiAgaWYgKHN1bShmb3VuZF9pbmNsdWRlcykgPT0gMCkgewogICAgbmV4dAogIH0KICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjMwdGltZV9zdHJpY3RfY29udHJhc3RzX2V4Y2VsL3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiMzB0aW1lX3N0cmljdF9jb250cmFzdHNfZXhjZWwve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgdGltZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0aW1lX2RlLCBleHRyYV9hbm5vdCA9IGluY2x1ZGVfZGYsCiAgICBrZWVwZXJzID0ga2VlcGVyLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgICBleGNlbCA9IGluY2x1ZGVfZmlsZW5hbWUsIHdhbnRlZF9nZW5lcyA9IGluY2x1ZGVzKQogIHByaW50KHRpbWVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dKQogIHRpbWVfc3RyaWN0X3NpZ1tbbmFtZV1dIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICB0aW1lX3N0cmljdF90YWJsZXNbW25hbWVdXSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICAgIGV4Y2VsID0gaW5jbHVkZV9zaWdfZmlsZW5hbWUpCiAgcHJpbnQodGltZV9zdHJpY3Rfc2lnW1tuYW1lXV0pCiAgbnVtX3Jvd3MgPC0gbnJvdyh0aW1lX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3codGltZV9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgaWYgKG51bV9yb3dzID49IDEwKSB7CiAgICBtZXNzYWdlKCJQZXJmb3JtaW5nIGdwcm9maWxlci9jbHVzdGVyUHJvZmlsZXIuIikKICAgIHRpbWVfc3RyaWN0X2dwW1tuYW1lXV0gPC0gYWxsX2dwcm9maWxlcih0aW1lX3N0cmljdF9zaWdbW25hbWVdXSwgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQogICAgdGltZV9zdHJpY3RfY3BbW25hbWVdXSA8LSBhbGxfY3Byb2ZpbGVyKAogICAgICB0aW1lX3N0cmljdF9zaWdbW25hbWVdXSwgdGltZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0sCiAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGdvX2xldmVsID0gZ29fbGV2ZWwsIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLAogICAgICBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSwgb3JnYW5pc20gPSAibW91c2UiKQogICAgI2lmICghaXMubnVsbChnZXQwKCJtMl9nc2MiKSkpIHsKICAgICMgIHRpbWVfc3RyaWN0X2VuW1tuYW1lXV0gPC0gYWxsX2VucmljaGVyKHRpbWVfc3RyaWN0X3NpZ1tbbmFtZV1dLCBnc2MgPSBtMl9nc2MsCiAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBmcm9tID0gIkVOU0VNQkwiLCB0byA9ICJTWU1CT0wiKQogICAgI30KICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKHRpbWVfc3RyaWN0X2dwW1tuYW1lXV0sIHByZWZpeCA9ICIzMSIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AodGltZV9zdHJpY3RfY3BbW25hbWVdXSwgcHJlZml4ID0gIjMxIiwgc3VmZml4ID0gInN0cmljdCIpCiAgICAjZW5fd3JpdHRlbiA8LSB3cml0ZV9hbGxfZW4odGltZV9zdHJpY3RfZW5bW25hbWVdXSkKICB9IGVsc2UgewogICAgd2FybmluZygiVGhlcmUgYXJlIGxlc3MgdGhhbiAxMCBnZW5lcyB1cCBhbmQgZG93biBpbiB0aGUgIiwgbmFtZSwgIiBjb21wYXJpc29uLiIpCiAgICBtZXNzYWdlKCJUaGVyZSBhcmUgbGVzcyB0aGFuIDEwIGdlbmVzIHVwIGFuZCBkb3duIGluIHRoZSAiLCBuYW1lLCAiIGNvbXBhcmlzb24uIikKICB9Cn0KYGBgCgpTZW5kIHRoZSBwbG90cyBzZXBhcmF0ZWx5LgoKYGBge3J9CmZvciAoayBpbiBzZXFfYWxvbmcodGltZV9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXModGltZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSB0aW1lX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSB0aW1lX2luY2x1c2lvbnNbW25hbWVdXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSB0aW1lX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gdGltZV9pbmNsdXNpb25zW1tpbmNsdWRlX25hbWVdXQogIG51bV9yb3dzIDwtIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBudW1fb2JqZWN0cyA8LSBsZW5ndGgodGltZV9jcFtbbmFtZV1dKQogIGlmIChudW1fb2JqZWN0cyA9PSAwKSB7CiAgICB3YXJuaW5nKCJTb21ldGhpbmcgZmFpbGVkIGluIGFsbF9jcHJvZmlsZXIuIikKICB9IGVsc2UgewogICAgdXBwIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyh0aW1lX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyh0aW1lX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl9kb3duJCIpKQogICAgaWYgKGxlbmd0aCh1cHApID4gMCkgewogICAgICBtZl9zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF90cmVlcy97bmFtZX1fdXBfbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF9iYXIve25hbWV9X3VwX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfdHJlZXMve25hbWV9X3VwX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfYmFyL3tuYW1lfV91cF9jY19zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX3RyZWVzL3tuYW1lfV91cF9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfYmFyL3tuYW1lfV91cF9icF9zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgICBpZiAobGVuZ3RoKGRvd25wKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX3RyZWVzL3tuYW1lfV9kb3duX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfYmFyL3tuYW1lfV9kb3duX21mX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF90cmVlcy97bmFtZX1fZG93bl9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX2Jhci97bmFtZX1fZG93bl9jY19zaWdfYmFyLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfdHJlZXMve25hbWV9X2Rvd25fYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfYmFyL3tuYW1lfV9kb3duX2JwX3NpZ19iYXIucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKIyBUcmFuc2xhdG9tZSBxdWVyaWVzCgpJbiBjb252ZXJzYXRpb24gd2l0aCBDb2xlbnNvLCBoZSBzcG9rZSBhYm91dCBhIHNlcmllcyBvZiBjb250cmFzdHMKd2hpY2ggd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gYXR0ZW1wdCBpbiBvcmRlciB0byBxdWVyeSB0aGUgY2hhbmdlcwphY3Jvc3MgYm90aCBsb2NhdGlvbnMgYW5kIGdlbm90eXBlcyBhbmQvb3IgYm90aCBsb2NhdGlvbnMgYW5kIHRpbWUsCnRodXM6CgoocDA4X2hldF9zY24gLyBwMDhfaGV0X3JldGluYSkgLyAocDA4X2tvX3NjbiAvIHAwOF9rb19yZXRpbmEpCgphcyBhbiBleGFtcGxlLiAgV2UgY2FuIGRlZmluaXRlbHkgZG8gdGhlc2UsIGJ1dCB0aGV5IGRvIG5vdCB3b3JrIGZvcgphbGwgbWV0aG9kcyBlbXBsb3llZCAoSSB0aGluayB0aGV5IHdvcmsgYmVzdCB3aXRoIGxpbW1hIGFuZCBlZGdlUikuCgpMZXRzIGZpbmQgb3V0IQoKIyMgVHdvIHNjbi9yZXRpbmEgY29tcGFyaXNvbnMKCiogKHAwOF9oZXRfc2NuIC8gcDA4X2hldF9yZXRpbmEpIC8gKHAwOF9rb19zY24gLyBwMDhfa29fcmV0aW5hKQoqIChwMTVfaGV0X3NjbiAvIHAxNV9oZXRfcmV0aW5hKSAvIChwMTVfa29fc2NuIC8gcDE1X2tvX3JldGluYSkKCmBgYHtyfQpzY25fZXh0cmEgPC0gZ2x1ZSgiXFwKICBwMDhoZXQgPSAoY29uZGl0aW9ucDA4X2hldF9zY24gLSBjb25kaXRpb25wMDhfaGV0X3JldGluYSksIFxcCiAgcDA4a28gPSAoY29uZGl0aW9ucDA4X2tvX3NjbiAtIGNvbmRpdGlvbnAwOF9rb19yZXRpbmEpLCBcXAogIHAwOGhldF92c19wMDhrbyA9IChjb25kaXRpb25wMDhfaGV0X3NjbiAtIGNvbmRpdGlvbnAwOF9oZXRfcmV0aW5hKSAtIChjb25kaXRpb25wMDhfa29fc2NuIC0gY29uZGl0aW9ucDA4X2tvX3JldGluYSksIFxcCiAgcDE1aGV0ID0gKGNvbmRpdGlvbnAxNV9oZXRfc2NuIC0gY29uZGl0aW9ucDE1X2hldF9yZXRpbmEpLCBcXAogIHAxNWtvID0gKGNvbmRpdGlvbnAxNV9rb19zY24gLSBjb25kaXRpb25wMTVfa29fcmV0aW5hKSwgXFwKICBwMTVoZXRfdnNfcDE1a28gPSAoY29uZGl0aW9ucDE1X2hldF9zY24gLSBjb25kaXRpb25wMTVfaGV0X3JldGluYSkgLSAoY29uZGl0aW9ucDE1X2tvX3NjbiAtIGNvbmRpdGlvbnAxNV9rb19yZXRpbmEpIikKc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMgPC0gbGlzdCgKICAicDA4aGV0IiA9IGMoInAwOF9oZXRfc2NuIiwgInAwOF9oZXRfcmV0aW5hIiksCiAgInAwOGtvIiA9IGMoInAwOF9rb19zY24iLCAicDA4X2tvX3JldGluYSIpLAogICJwMTVoZXQiID0gYygicDE1X2hldF9zY24iLCAicDE1X2hldF9yZXRpbmEiKSwKICAicDE1a28iID0gYygicDE1X2tvX3NjbiIsICJwMTVfa29fcmV0aW5hIikpCnNjbl90cmFuc2xhdG9tZV9rZWVwZXJzIDwtIGxpc3QoCiAgInAwOGhldCIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhrbyIgPSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiKSwKICAicDA4X3Njbl90cmFuc2xhdG9tZSIgPSBjKCJwMDhoZXQiLCAicDA4a28iKSwKICAicDE1aGV0IiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAxNWtvIiA9IGMoInAxNV9rb19zY24iLCAicDE1X2tvX3JldGluYSIpLAogICJwMTVfc2NuX3RyYW5zbGF0b21lIiA9IGMoInAxNWhldCIsICJwMTVrbyIpKQpmaWx0IDwtIG5vcm1hbGl6ZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSkKbGltbWFfdGVzdCA8LSBsaW1tYV9wYWlyd2lzZShmaWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBzY25fdHJhbnNsYXRvbWVfZGVfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gRkFMU0UsIGV4dHJhX2NvbnRyYXN0cnMgPSBzY25fZXh0cmEpCmVkZ2VyX3Rlc3QgPC0gZWRnZXJfcGFpcndpc2UoZmlsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9IEZBTFNFLCBleHRyYV9jb250cmFzdHMgPSBzY25fZXh0cmEpCnNjbl90cmFuc2xhdG9tZV9kZSA8LSBhbGxfcGFpcndpc2UodjNfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHNjbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX25vaXNlcSA9IEZBTFNFLCBkb19lYnNlcSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IHNjbl9leHRyYSkKc2NuX2NvbWJpbmVkX3Rlc3QgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgc2NuX3RyYW5zbGF0b21lX2RlLCBrZWVwZXJzID0gc2NuX3RyYW5zbGF0b21lX2tlZXBlcnMsCiAgZXhjZWwgPSBnbHVlKCIzM3RyYW5zbGF0b21lX3hsc3gvdGVzdF9zY25fdHJhbnNsYXRvbWVfdW5maWx0ZXJlZF9ub3N2YS12e3Zlcn0ueGxzeCIpKQpzY25fdHJhbnNsYXRvbWVfZGVfc3ZhIDwtIGFsbF9wYWlyd2lzZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHNjbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0cmFfY29udHJhc3RzID0gc2NuX2V4dHJhKQpzY25fY29tYmluZWRfdGVzdF9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgc2NuX3RyYW5zbGF0b21lX2RlX3N2YSwga2VlcGVycyA9IHNjbl90cmFuc2xhdG9tZV9rZWVwZXJzLAogIGV4Y2VsID0gZ2x1ZSgiMzN0cmFuc2xhdG9tZV94bHN4L3Rlc3Rfc2NuX3RyYW5zbGF0b21lX3VuZmlsdGVyZWRfc3ZhLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIFN1YnRyYWN0aW5nIERFU2VxMiByZXN1bHRzOiBwMDggc2NuIGhldCB2cyBrbwoKYGBge3J9CnAwOF9zY25fY29tYmluZWRfZGVzZXEgPC0gc3VidHJhY3RfZGVfcmVzdWx0cygKICBmaXJzdF90YWJsZSA9IHNjbl9jb21iaW5lZF90ZXN0W1siZGF0YSJdXVtbInAwOGhldCJdXSwKICBzZWNvbmRfdGFibGUgPSBzY25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhrbyJdXSwKICBmaXJzdF9sZmMgPSAiZGVzZXFfbG9nZmMiLCBzZWNvbmRfbGZjID0gImRlc2VxX2xvZ2ZjIiwKICBmaXJzdF9wID0gImRlc2VxX2FkanAiLCBzZWNvbmRfcCA9ICJkZXNlcV9hZGpwIiwKICBmaXJzdF9uYW1lID0gImhldCIsIHNlY29uZF9uYW1lID0gImtvIiwKICBleGNlbCA9IGdsdWUoIjMzdHJhbnNsYXRvbWVfeGxzeC90cmFuc2xhdG9tZV9wMDhfc2NuX2NvbWJpbmVkX2Rlc2VxLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIFN1YnRyYWN0aW5nIERFU2VxMiByZXN1bHRzOiBwMTUgc2NuIGhldCB2cyBrbwoKYGBge3J9CnAxNV9zY25fY29tYmluZWRfZGVzZXEgPC0gc3VidHJhY3RfZGVfcmVzdWx0cygKICBmaXJzdF90YWJsZSA9IHNjbl9jb21iaW5lZF90ZXN0W1siZGF0YSJdXVtbInAxNWhldCJdXSwKICBzZWNvbmRfdGFibGUgPSBzY25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMTVrbyJdXSwKICBmaXJzdF9sZmMgPSAiZGVzZXFfbG9nZmMiLCBzZWNvbmRfbGZjID0gImRlc2VxX2xvZ2ZjIiwKICBmaXJzdF9wID0gImRlc2VxX2FkanAiLCBzZWNvbmRfcCA9ICJkZXNlcV9hZGpwIiwKICBmaXJzdF9uYW1lID0gImhldCIsIHNlY29uZF9uYW1lID0gImtvIiwKICBleGNlbCA9IGdsdWUoIjM0dHJhbnNsYXRvbWVfZGVzZXFzdWJfeGxzeC90cmFuc2xhdG9tZV9wMTVfc2NuX2NvbWJpbmVkX2Rlc2VxLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMgT25lIGRsZ24vcmV0aW5hIGNvbXBhcmlzb24KCiogKHAwOF9oZXRfZGxnbiAvIHAwOF9oZXRfcmV0aW5hKSAvIChwMDhfa29fZGxnbiAvIHAwOF9rb19yZXRpbmEpCgpgYGB7cn0KcDA4X2RsZ25fZXh0cmEgPC0gInAwOGhldF92c19wMDhrbyA9IChjb25kaXRpb25wMDhfaGV0X2RsZ24gLSBjb25kaXRpb25wMDhfaGV0X3JldGluYSkgLSAoY29uZGl0aW9ucDA4X2tvX2RsZ24gLSBjb25kaXRpb25wMDhfa29fcmV0aW5hKSIKcDA4X2RsZ25fdHJhbnNsYXRvbWVfZGVfa2VlcGVycyA8LSBsaXN0KAogICJwMDhoZXQiID0gYygicDA4X2hldF9kbGduIiwgInAwOF9oZXRfcmV0aW5hIiksCiAgInAwOGtvIiA9IGMoInAwOF9rb19kbGduIiwgInAwOF9rb19yZXRpbmEiKSkKcDA4X2RsZ25fdHJhbnNsYXRvbWVfa2VlcGVycyA8LSBsaXN0KAogICJwMDhfaGV0X2RsZ25fdnNfcmV0aW5hIiA9IGMoInAwOF9oZXRfZGxnbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhfa29fZGxnbl92c19yZXRpbmEiID0gYygicDA4X2tvX2RsZ24iLCAicDA4X2tvX3JldGluYSIpLAogICJwMDhfZGxnbl90cmFuc2xhdG9tZSIgPSBjKCJwMDhoZXQiLCAicDA4a28iKSkKcDA4X2RsZ25fdHJhbnNsYXRvbWVfZGUgPC0gYWxsX3BhaXJ3aXNlKHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHAwOF9kbGduX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2Jhc2ljID0gRkFMU0UsIGRvX2RyZWFtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IHAwOF9kbGduX2V4dHJhKQpwMDhfZGxnbl9jb21iaW5lZF90ZXN0IDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHAwOF9kbGduX3RyYW5zbGF0b21lX2RlLCBrZWVwZXJzID0gcDA4X2RsZ25fdHJhbnNsYXRvbWVfa2VlcGVycywKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzM3RyYW5zbGF0b21lX3hsc3gvdGVzdF9wMDhfZGxnbl90cmFuc2xhdG9tZV91bmZpbHRlcmVkX25vc3ZhLXZ7dmVyfS54bHN4IikpCnAwOF9kbGduX3RyYW5zbGF0b21lX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UodjNfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHAwOF9kbGduX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2Jhc2ljID0gRkFMU0UsIGRvX2RyZWFtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0cmFfY29udHJhc3RzID0gcDA4X2RsZ25fZXh0cmEpCnAwOF9kbGduX2NvbWJpbmVkX3Rlc3Rfc3ZhIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHAwOF9kbGduX3RyYW5zbGF0b21lX2RlX3N2YSwga2VlcGVycyA9IHAwOF9kbGduX3RyYW5zbGF0b21lX2tlZXBlcnMsCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMzN0cmFuc2xhdG9tZV94bHN4L3Rlc3RfcDA4X2RsZ25fdHJhbnNsYXRvbWVfdW5maWx0ZXJlZF9zdmEtdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIyMgU3VidHJhY3RpbmcgdGhlIERFU2VxMiByZXN1bHRzCgojIyBUd28gc2NuL3JldGluYSBjb21wYXJpc29ucyAocDE1L3AwOCBhY3Jvc3MgaGV0L2tvKQoKKiAocDE1X2hldF9zY24gLyBwMTVfaGV0X3JldGluYSkgLyAocDA4X2hldF9zY24gLyBwMDhfaGV0X3JldGluYSkKKiAocDE1X2tvX3NjbiAvIHAxNV9rb19yZXRpbmEpIC8gKHAwOF9rb19zY24gLyBwMDhfa29fcmV0aW5hKQoKYGBge3J9CnRpbWVfc2NuX2V4dHJhIDwtIGdsdWUoIlxcCiAgcDE1aGV0ID0gKGNvbmRpdGlvbnAxNV9oZXRfc2NuIC0gY29uZGl0aW9ucDE1X2hldF9yZXRpbmEpLCBcXAogIHAwOGhldCA9IChjb25kaXRpb25wMDhfaGV0X3NjbiAtIGNvbmRpdGlvbnAwOF9oZXRfcmV0aW5hKSwgXFwKICBwMTVoZXRfdnNfcDA4aGV0ID0gKGNvbmRpdGlvbnAxNV9oZXRfc2NuIC0gY29uZGl0aW9ucDE1X2hldF9yZXRpbmEpIC0gKGNvbmRpdGlvbnAwOF9oZXRfc2NuIC0gY29uZGl0aW9ucDA4X2hldF9yZXRpbmEpLAogIHAxNWtvID0gKGNvbmRpdGlvbnAxNV9rb19zY24gLSBjb25kaXRpb25wMTVfa29fcmV0aW5hKSwgXFwKICBwMDhrbyA9IChjb25kaXRpb25wMDhfa29fc2NuIC0gY29uZGl0aW9ucDA4X2tvX3JldGluYSksIFxcCiAgcDE1a29fdnNfcDA4a28gPSAoY29uZGl0aW9ucDE1X2tvX3NjbiAtIGNvbmRpdGlvbnAxNV9rb19yZXRpbmEpIC0gKGNvbmRpdGlvbnAwOF9rb19zY24gLSBjb25kaXRpb25wMDhfa29fcmV0aW5hKSIpCnRpbWVfc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMgPC0gbGlzdCgKICAicDE1aGV0IiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAwOGhldCIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMTVrbyIgPSBjKCJwMTVfa29fc2NuIiwgInAxNV9rb19yZXRpbmEiKSwKICAicDA4a28iID0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIikpCnRpbWVfc2NuX3RyYW5zbGF0b21lX2tlZXBlcnMgPC0gbGlzdCgKICAicDE1aGV0IiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAwOGhldCIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMTVrbyIgPSBjKCJwMTVfa29fc2NuIiwgInAxNV9rb19yZXRpbmEiKSwKICAicDA4a28iID0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIiksCiAgInAxNV9oZXRfc2NfdnNfcmV0aW5hIiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAwOF9oZXRfc2NfdnNfcmV0aW5hIiA9IGMoInAwOF9oZXRfc2NuIiwgInAwOF9oZXRfcmV0aW5hIiksCiAgInNjbl9oZXRfdHJhbnNsYXRvbWUiID0gYygicDE1aGV0IiwgInAwOGhldCIpLAogICJzY25fa29fdHJhbnNsYXRvbWUiID0gYygicDE1a28iLCAicDA4a28iKSkKdGltZV9zY25fdHJhbnNsYXRvbWVfZGUgPC0gYWxsX3BhaXJ3aXNlKHYzX3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHRpbWVfc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2Jhc2ljID0gRkFMU0UsIGRvX2RyZWFtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IHRpbWVfc2NuX2V4dHJhKQp0aW1lX3Njbl90cmFuc2xhdG9tZV90ZXN0IDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHRpbWVfc2NuX3RyYW5zbGF0b21lX2RlLAogIGtlZXBlcnMgPSB0aW1lX3Njbl90cmFuc2xhdG9tZV9rZWVwZXJzLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjMzdHJhbnNsYXRvbWVfeGxzeC90ZXN0X3RpbWVfc2NuX3RyYW5zbGF0b21lX3VuZmlsdGVyZWRfbm9zdmEtdnt2ZXJ9Lnhsc3giKSkKdGltZV9zY25fdHJhbnNsYXRvbWVfZGVfc3ZhIDwtIGFsbF9wYWlyd2lzZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gdGltZV9zY25fdHJhbnNsYXRvbWVfZGVfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fYmFzaWMgPSBGQUxTRSwgZG9fZHJlYW0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9jb250cmFzdHMgPSB0aW1lX3Njbl9leHRyYSkKdGltZV9zY25fdHJhbnNsYXRvbWVfdGVzdF9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgdGltZV9zY25fdHJhbnNsYXRvbWVfZGVfc3ZhLAogIGtlZXBlcnMgPSB0aW1lX3Njbl90cmFuc2xhdG9tZV9rZWVwZXJzLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjMzdHJhbnNsYXRvbWVfeGxzeC90ZXN0X3RpbWVfc2NuX3RyYW5zbGF0b21lX3VuZmlsdGVyZWRfc3ZhLXZ7dmVyfS54bHN4IikpCmBgYAoKTmV4dCBzdGVwOiBQZXJmb3JtIHRoZSByZXRpbmEgZmlsdGVyOyBuZWVkIHRvIHRoaW5rIGFib3V0IHRoZSBwcm9wZXIKdW5pb24vaW50ZXJzZWN0aW9uIG9mIHRoZSByZXRpbmEveCBleHByZXNzaW9uIHZhbHVlcwoKSW4gdGhlIHByZXZpb3VzIGJsb2NrLCB3ZSBhcmUgbWFraW5nIDIgZ2xvYmFsIGNvbXBhcmlzb25zLCBoZXJlIGlzIG9uZQpvZiB0aGVtOgoKKHAxNWhldHNjbi9wMTVoZXRyZXQpLyhwMDhoZXRzY24vcDA4aGV0cmV0KQoKSSB0aGVyZWZvcmUgd2FudCB0byBleHRyYWN0IHRoZSBtb3N0IGxvZ2ljYWwgc2V0IG9mIGdlbmVzIGhpZ2hlciBpbgpzb21lL2FsbCBvZiB0aGVzZSBjb25kaXRpb25zIHdpdGggcmVzcGVjdCB0byB0aGUgY29ycmVzcG9uZGluZyB3dApjb25kaXRpb25zLiAgUHJldmlvdXNseSwgaW4gc2VjdGlvbiAnRXh0cmFjdCBnZW5lcyBpbmNsdWRlZCBmb3IgZWFjaApzZXQgb2YgY29udHJhc3RzJywgSSBhdHRlbXB0ZWQgdG8gcGVyZm9ybSB0aGlzIG9wZXJhdGlvbiBmb3IgMgpzcGVjaWZpYyB3dCBjb25kaXRpb25zLiAgV2hlbiB0aGlzIHdhcyBwZXJmb3JtZWQsIGl0IHRvb2sgdGhlCnVuaXF1ZSh1bmlvbikgb2YgdGhlIHR3byBzZXRzLiAgVGh1cyBpdCBzdGFuZHMgdG8gcmVhc29uIHRoYXQgSSB3YW50CnRvIHRha2UgdGhlIHVuaXF1ZSh1bmlvbikgb2YgYWxsIDQgaW4gdGhpcyBpbnN0YW5jZT8gIGUuZy46CgoocDE1aGV0c2NuID4gcDE1d3RzY24pIHwgKHAxNWhldHJldCA+IHAxNXd0cmV0KSB8CiAgKHAwOGhldHNjbiA+IHAwOHd0c2NuKSB8IChwMDhoZXRyZXQgPiBwMDh3dHJldCkKCkkga2luZCBvZiB0aGluayBpdCBzaG91bGQgYmU6CgooKHAxNWhldHNjbiA+IHAxNXd0c2NuKSB8IChwMTVoZXRyZXQgPiBwMTV3dHJldCkpICYKICAoKHAwOGhldHNjbiA+IHAwOHd0c2NuKSB8IChwMDhoZXRyZXQgPiBwMDh3dHJldCkpCgpncm9zcywgcGVyaGFwcyBJIHNob3VsZCBqdXN0IGRvIHRoaXMgbWFudWFsbHksIGdpdmVuIHRoYXQgdGhlcmUgYXJlCm9ubHkgYSBmZXcgcHV0YXRpdmUgdHJhbnNsYXRvbWVzIHRvIHF1ZXJ5PwoKIyBRdWljayBhbmQgZGlydHkgREVTZXEyIGNvbnRyYXN0IG9mIGNvbnRyYXN0cwoKSW4gYSBmYXNoaW9uIHNpbWlsYXIgdG8gaG93IEhlY3RvciBoYW5kbGVkIHRoZSBlZmZlY3Qgb2YgcGhhZ29jeXRvc2lzCndpdGggTGF1cmEgYW5kIE5hamliIGEgbG9uZyB0aW1lIGFnbywgSSBwcm9wb3NlIHRvIGRvIGEgc2ltcGxlCnN1YnRyYWN0aW9uIG9mIHRoZSByZXN1bHRzIG9mIG91ciB0d28gY29udHJhc3RzIHdoaWNoIGNvbXByaXNlIHRoZQp0cmFuc2xhdG9tZSBxdWVyeSAoSSB3YXMgdGhpbmtpbmcgYWJvdXQgdGhpcyBsYXN0IHdlZWssIHRodXMgdGhlCmluY2x1c2lvbiBvZiB0aGVtIGluIHRoZSBkZSB0YWJsZXMgYWJvdmUpLiAgU2ltaWxhcmx5IHRvIHRoZQpwaGFnb2N5dG9zaXMgZWZmZWN0LCBJIHdpbGwgc2ltcGx5IHRha2UgdGhlIHdvcnN0IHBvc2libGUgYWRqdXN0ZWQKcC12YWx1ZS4gIEkgd2lsbCByZXBlYXQgdGhpcyB3aXRoIGxpbW1hL0VkZ2VSIGFuZCBzZWUgaG93IHNpbWlsYXIgdGhlCmZpbmFsIHJlc3VsdHMgYXJlIHRvIHdoYXQgdGhvc2UgbWV0aG9kcyBwcm92aWRlIGluIHRoZSAoYS9iKS8oYy9kKQpjb21wYXJpc29ucy4gIEkgYW0gcmVhc29uYWJseSBjZXJ0YWluIHRoYXQgREVTZXEyJ3MgcmVzdWx0cygpIGZ1bmN0aW9uCmhhcyB0aGUgYWJpbGl0eSB0byBwZXJmb3JtIHRoZXNlIG9kZCBjb250cmFzdHMsIGJ1dCBJIGhhdmUgbmV2ZXIKZmlndXJlZCBvdXQgaG93OyBwZXJoYXBzIEkgd2lsbCB1c2UgdGhpcyBhcyBhIGNoYW5jZSB0byByZXZpc2l0IHRoYXQuLi4KCkxldCB1cyB0ZXN0IHRoaXMgaWRlYSB3aXRoIHRoZSBwMDggZGxnbiBxdWVyeSwgd2hpY2ggc2Vla3MgdG8gY29tcGFyZToKCihwMDhfaGV0X2RsZ24gLyBwMDhfaGV0X3JldGluYSkgLyAocDA4X2tvX2RsZ24gLyBwMDhfa29fcmV0aW5hKQoKVGhlc2UgYXJlIG1haW50YWluZWQgaW4gdGhlIGRlX3RhYmxlIHdpdGggdGhlIG5hbWVzCidwMDhfaGV0X2RsZ25fdnNfcmV0aW5hJyBhbmQgJ3AwOF9rb19kbGduX3ZzX3JldGluYScKCiMjIHAwOCBkbGduIGhldCB2cyBrbwoKYGBge3J9CnAwOF9kbGduX2NvbWJpbmVkX2Rlc2VxIDwtIHN1YnRyYWN0X2RlX3Jlc3VsdHMoCiAgZmlyc3RfdGFibGUgPSBwMDhfZGxnbl9jb21iaW5lZF90ZXN0W1siZGF0YSJdXVtbInAwOF9oZXRfZGxnbl92c19yZXRpbmEiXV0sCiAgc2Vjb25kX3RhYmxlID0gcDA4X2RsZ25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhfa29fZGxnbl92c19yZXRpbmEiXV0sCiAgZmlyc3RfbGZjID0gImRlc2VxX2xvZ2ZjIiwgc2Vjb25kX2xmYyA9ICJkZXNlcV9sb2dmYyIsCiAgZmlyc3RfcCA9ICJkZXNlcV9hZGpwIiwgc2Vjb25kX3AgPSAiZGVzZXFfYWRqcCIsCiAgZmlyc3RfbmFtZSA9ICJoZXQiLCBzZWNvbmRfbmFtZSA9ICJrbyIsCiAgZXhjZWwgPSBnbHVlKCIzNHRyYW5zbGF0b21lX2Rlc2Vxc3ViX3hsc3gvdHJhbnNsYXRvbWVfcDA4X2RsZ25fY29tYmluZWRfZGVzZXEtdnt2ZXJ9Lnhsc3giKSkKYGBgCgpTZWUgaG93IHNpbWlsYXIgdGhlc2UgcmVzdWx0cyBhcmUgdG8gdGhvc2Ugb2J0YWluZWQgZnJvbSBsaW1tYS9lZGdlci4KCmBgYHtyfQp0ZXN0X2NvbHVtbnMgPC0gYygiZWRnZXJfbG9nZmMiLCAibGltbWFfbG9nZmMiLCAiZWRnZXJfYWRqcCIsICJsaW1tYV9hZGpwIikKdGVzdF9kZiA8LSBwMDhfZGxnbl9jb21iaW5lZF90ZXN0W1siZGF0YSJdXVtbInAwOF9kbGduX3RyYW5zbGF0b21lIl1dWywgdGVzdF9jb2x1bW5zXQp0ZXN0X2RmIDwtIG1lcmdlKHRlc3RfZGYsIHAwOF9kbGduX2NvbWJpbmVkX2Rlc2VxLCBieSA9ICJyb3cubmFtZXMiKQpyb3duYW1lcyh0ZXN0X2RmKSA8LSB0ZXN0X2RmW1siUm93Lm5hbWVzIl1dCnRlc3RfZGZbWyJSb3cubmFtZXMiXV0gPC0gTlVMTApjb3IudGVzdCh0ZXN0X2RmW1sibGltbWFfbG9nZmMiXV0sIHRlc3RfZGZbWyJoZXRfdnNfa29fbG9nZmMiXV0pCmNvci50ZXN0KHRlc3RfZGZbWyJlZGdlcl9sb2dmYyJdXSwgdGVzdF9kZltbImhldF92c19rb19sb2dmYyJdXSkKdHQgPC0gcGxvdF9saW5lYXJfc2NhdHRlcih0ZXN0X2RmWywgYygibGltbWFfbG9nZmMiLCAiaGV0X3ZzX2tvX2xvZ2ZjIildKQp0dFtbInNjYXR0ZXIiXV0KdHQgPC0gcGxvdF9saW5lYXJfc2NhdHRlcih0ZXN0X2RmWywgYygiZWRnZXJfYWRqcCIsICJoZXRfdnNfa29fcCIpXSkKdHRbWyJzY2F0dGVyIl1dCiMjIFNvLCB1c2luZyB0aGUgbWF4aW11bSBwLXZhbHVlIGlzIGEgY29tcGxldGUgZmFpbHVyZTsgYnV0IHRoZSBleHRyZW1lIHNpbWlsYXJpdGllcwojIyBiZXR3ZWVuIHRoaXMgYW5kIGVkZ2VSIHN1Z2dlc3QgdG8gbWUgdGhhdCBpdCBpcyBsaWtlbHkgcG9zc2libGUgdG8gdXNlIHRoZSByZXN1bHRzCiMjIGZyb20gZWRnZVIgd2l0aG91dCBjb25jZXJuIChvciBsaW1tYSBmb3IgdGhhdCBtYXR0ZXIsIGl0IHdhcyBhbHNvIGV4dHJlbWVseSBzaW1pbGFyKQojIyBPciBJIGNhbiBzcGVuZCBhIGxpdHRsZSB0aW1lIGFuZCBjb2xsZWN0IHRoZSBudW1iZXJzIG9uIGVhY2ggc2lkZSBvZiB0aGUgZGl2aXNpb24KIyMgYW5kIGNhbGN1bGF0ZSBhIHQgc3RhdGlzdGljIG15c2VsZi4KYGBgCgojIE5vbi1TcGVjaWZpYyBmaWx0ZXJpbmcgb2YgdGhlIHRyYW5zbGF0b21lIGRhdGEKCkkgaGF2ZSBvbiBoYW5kCgoqIHAwOGhldF92c19wMDhrbyA6IChwMDhfaGV0X3NjbiAtIHAwOF9oZXRfcmV0aW5hKSAtIChwMDhfa29fc2NuIC0gcDA4X2tvX3JldGluYSkKKiBwMTVoZXRfdnNfcDE1a28gOiAocDE1X2hldF9zY24gLSBwMTVfaGV0X3JldGluYSkgLSAocDE1X2tvX3NjbiAtIHAxNV9rb19yZXRpbmEpCiogcDA4aGV0X3ZzX3AwOGtvIDogKHAwOF9oZXRfZGxnbiAtIHAwOF9oZXRfcmV0aW5hKSAtIChwMDhfa29fZGxnbiAtIHAwOF9rb19yZXRpbmEpCiogcDE1aGV0X3ZzX3AwOGhldCA6IChwMTVfaGV0X3NjbiAtIHAxNV9oZXRfcmV0aW5hKSAtIChwMDhfaGV0X3NjbiAtIHAwOF9oZXRfcmV0aW5hKQoqIHAxNWtvX3ZzX3AwOGtvIDogKHAxNV9rb19zY24gLSBwMTVfa29fcmV0aW5hKSAtIChwMDhfa29fc2NuIC0gcDA4X2tvX3JldGluYSkKCkkgaGF2ZSBnZW5lIHNldHMgdXAgYWJvdmUgd2hpY2ggZGVmaW5lIHRoZSBnZW5lcyBzdWl0YWJsZSBmb3IgZWFjaCBvZgp0aGVzZSBwaWVjZXMuICBUaGVyZSBhcmUgb25seSA1IGNvbXBhcmlzb25zLCBsZXQgdXMgc3RlcCB0aHJvdWdoIHRoZW0uCgojIyBTQ04gdHJhbnNsYXRvbWUgaGV0L2tvIGF0IHAwOAoKVGhlIGRhdGEgZm9yIHRoaXMgY29udHJhc3QgcmVzaWRlcyBpbgpzY25fY29tYmluZWRfdGVzdCRkYXRhJHAwOF9zY25fdHJhbnNsYXRvbWUgb3IgdGhlIHNhbWUgc2xvdCBvZgpzY25fY29tYmluZWRfdGVzdF9zdmEKCiogcDA4X2hldF9zY24gLSBwMDhfaGV0X3JldGluYSkgLSAocDA4X2tvX3NjbiAtIHAwOF9rb19yZXRpbmEpCgpUaHVzLCB0aGUgaW5jbHVzaW9uX3NpZyBwb3J0aW9ucyB0byBleHRyYWN0IGFyZSBmb3VuZCBpbjoKaW5jbHVzaW9uX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dLCBhbmQgYXJlIG5hbWVkIGV4YWN0bHkgYXMgd3JpdHRlbiBhYm92ZSEKCmBgYHtyfQpwMDhfaGV0X3ZzX2tvX3RyYW5zbGF0b21lX3VuZmlsdCA8LSBzY25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhfc2NuX3RyYW5zbGF0b21lIl1dCm51bV91bmlvbiA8LSB1bmlxdWUoYyhyb3duYW1lcyhpbmNsdXNpb25fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJwMDhfaGV0X3NjbiJdXSksCiAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhpbmNsdXNpb25fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJwMDhfaGV0X3JldGluYSJdXSkpKQpsZW5ndGgobnVtX3VuaW9uKQpkZW5fdW5pb24gPC0gdW5pcXVlKGMocm93bmFtZXMoaW5jbHVzaW9uX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sicDA4X2tvX3NjbiJdXSksCiAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhpbmNsdXNpb25fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJwMDhfa29fcmV0aW5hIl1dKSkpCmxlbmd0aChkZW5fdW5pb24pCmJvdGhfdW5pb24gPC0gdW5pcXVlKGMobnVtX3VuaW9uLCBkZW5fdW5pb24pKQpsZW5ndGgoYm90aF91bmlvbikKYm90aF9pbnRlcl9pZHggPC0gbnVtX3VuaW9uICVpbiUgZGVuX3VuaW9uCmJvdGhfaW50ZXIgPC0gbnVtX3VuaW9uW2JvdGhfaW50ZXJfaWR4XQpsZW5ndGgoYm90aF9pbnRlcikKa2VlcGVyIDwtIGxpc3QoInAwOF9zY25fdHJhbnNsYXRvbWUiID0gYygicDA4aGV0IiwgInAwOGtvIikpCnAwOF9zY25fdHJhbnNsYXRvbWVfdW5pb25fZmlsdGVyZWQgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgc2NuX3RyYW5zbGF0b21lX2RlLCBrZWVwZXJzID0ga2VlcGVyLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjM1dHJhbnNsYXRvbWVfdW5pb24vcDA4X3Njbl90cmFuc2xhdG9tZV91bmlvbl9maWx0ZXJlZF9ub3N2YS12e3Zlcn0ueGxzeCIpLAogIHdhbnRlZF9nZW5lcyA9IGJvdGhfdW5pb24pCnAwOF9zY25fdHJhbnNsYXRvbWVfaW50ZXJfZmlsdGVyZWQgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgc2NuX3RyYW5zbGF0b21lX2RlLCBrZWVwZXJzID0ga2VlcGVyLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjM1dHJhbnNsYXRvbWVfdW5pb24vcDA4X3Njbl90cmFuc2xhdG9tZV9pbnRlcnNlY3RfZmlsdGVyZWRfbm9zdmEtdnt2ZXJ9Lnhsc3giKSwKICB3YW50ZWRfZ2VuZXMgPSBib3RoX2ludGVyKQpwMDhfc2NuX3RyYW5zbGF0b21lX3VuaW9uX2ZpbHRlcmVkX3N2YSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBzY25fdHJhbnNsYXRvbWVfZGVfc3ZhLCBrZWVwZXJzID0ga2VlcGVyLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjM1dHJhbnNsYXRvbWVfdW5pb24vcDA4X3Njbl90cmFuc2xhdG9tZV91bmlvbl9maWx0ZXJlZF9zdmEtdnt2ZXJ9Lnhsc3giKSwKICB3YW50ZWRfZ2VuZXMgPSBib3RoX3VuaW9uKQpwMDhfc2NuX3RyYW5zbGF0b21lX3VuaW9uX2ZpbHRlcmVkIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHNjbl90cmFuc2xhdG9tZV9kZSwga2VlcGVycyA9IGtlZXBlciwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzNXRyYW5zbGF0b21lX3VuaW9uL3AwOF9zY25fdHJhbnNsYXRvbWVfaW50ZXJzZWN0X2ZpbHRlcmVkX3N2YS12e3Zlcn0ueGxzeCIpLAogIHdhbnRlZF9nZW5lcyA9IGJvdGhfaW50ZXIpCmBgYAoKIyBWZW5uL1VwU2V0IG9mIFJldGluYSwgU0NOLCBhbmQgZExHTiBERSBHZW5lcwoKSGVyZSBpcyBhIHNuaXBwZXQgZnJvbSBSYXNobWkgd2hpY2ggZXhwcmVzc2VzIG5pY2VseSB0aGUgREUtcmVzdWx0CmNvbXBhcmlzb25zIHNoZSBpcyBtb3N0IGludGVyZXN0ZWQ6CgpTaW5jZSwgSSB3YW50IHRvIGtub3cgdGhlIG51bWJlciBvZiBERUcgZXhwcmVzc2VkIGluIFJldGluYSwgU0NOIGFuZApkTEdOIHdpdGggcmVzcGVjdCB0byBnZW5vdHlwZSwgTG9jYXRpb24gYW5kIHRpbWUuIEkgcHJlcGFyZWQgdGhlIHZlbm4KZGlhZ3JhbSBmb3IgdGhlc2UgY29tcGFyaXNvbjoKCiogR2Vub3R5cGU6IFA4IFJldCBIZXQgdnMgS08sIFAxNSBSZXQgSGV0IHZzIEtPLCBQOCBTQ04gSGV0IHZzIEtPLAogICAgICAgICAgICBQMTUgU0NOIEhldCB2cyBLTywgUDggZExHTiBIZXQgdnMgS08sIFAxNSBkTEdOIEhldCB2cyBLTwoqIExvY2F0aW9uOiBQOF9oZXQgUmV0IHZzIFNDTiwgUDhfS08gUmV0IHZzIFNDTiwgUDE1X2hldCBSZXQgdnMgU0NOLAogICAgICAgICAgICBQMTVfS08gUmV0IHZzIFNDTiwgUDhfaGV0IFJldCB2cyBkTEdOLCBQOF9LTyBSZXQgdnMgZExHTiwKICAgICAgICAgICAgUDE1X2hldCBSZXQgdnMgZExHTiwgUDE1X0tPIFJldCB2cyBkTEdOLCBQOF9oZXQgU0NOIHZzIGRMR04sCiAgICAgICAgICAgIFA4X0tPIFNDTiB2cyBkTEdOLCBQMTVfaGV0IFNDTiB2cyBkTEdOLCBQMTVfS08gU0NOIHZzIGRMR04uCgpTaW5jZSBJIHdhcyBpbnRlcmVzdGVkIGluIHVuZGVyc3RhbmRpbmcgdGhlIGNoYW5nZSBpbiBsb2NhbCB0cmFuc2xhdG9tZQphY2NvcmRpbmcgdG8gTG9jYXRpb24gZm9yIGRpZmZlcmVudCBkZXZlbG9wbWVudGFsIHRpbWUgcG9pbnRzIGZvciBIZXQKYW5kIEtPLiBIZW5jZSwgSSB0cmllZCB0byBnZW5lcmF0ZSBhIHZlbm4gZGlhZ3JhbSBmb3IgTG9jYXRpb24gKFJldAphbmQgU0NOKSBhdCBkZXZlbG9wbWVudGFsIHRpbWUgcG9pbnRzIFA4IGFuZCBQMTUgZm9yIGdlbm90eXBlIGhldCBhbmQKS08uICBTbyB0aGUgdmVubiBkaWFncmFtIC8gdXBzZXQgcGxvdCB3aWxsIGJlIGZvciBsb2NhdGlvbiB3aGVyZSBzb21lCmdlbmVzIHdpbGwgYmUgc2hhcmVkL3VuaXF1ZSBmb3IgUDhfUmV0X2hldCwgUDhfU0NOX0hldCwgUDE1X1JldF9IRVQsClAxNV9TQ05fSEVULiAgV2UgY2FuIHByZXBhcmUgYW4gdXBzZXQgcGxvdCBmb3IgUDhfUmV0X0tPLApQOF9TQ05fS08sIFAxNV9SZXRfS08gYW5kIFAxNV9TQ05fS08gYWxzby4gT3IgY2FuIGdlbmVyYXRlIGFuIHVwc2V0CnBsb3QgYnkgY29tYmluaW5nIGJvdGggUDhfUmV0X2hldCwgUDhfU0NOX0hldCwgUDE1X1JldF9IRVQgYW5kClAxNV9TQ05fSEVUIGFuZCBQOF9SZXRfS08sIFA4X1NDTl9LTywgUDE1X1JldF9LTyBhbmQgUDE1X1NDTl9LTy4KCk9rLCBsZXQgdXMgc2VlIGlmIEkgY2FuIGltcGxlbWVudCB0aGlzLCBzdGFydGluZyB3aXRoIHRoZSBnZW5vdHlwZSBxdWVyeQoKKiBHZW5vdHlwZTogUDggUmV0IEhldCB2cyBLTywgUDE1IFJldCBIZXQgdnMgS08sIFA4IFNDTiBIZXQgdnMgS08sCiAgICAgICAgICAgIFAxNSBTQ04gSGV0IHZzIEtPLCBQOCBkTEdOIEhldCB2cyBLTywgUDE1IGRMR04gSGV0IHZzIEtPCgojIyBrbyB2cyBoZXQ7IGFsbCBsb2NhdGlvbnMgYW5kIHRpbWVzCgpgYGB7cn0KIyMgVGhlIGFwcHJvcHJpYXRlIGRhdGEgc3RydWN0dXJlIGlzICdnZW5vdHlwZV90YWJsZXMnLAojIyBhbmQgdGhlIHRhYmxlcyBvZiBpbnRlcmVzdCBhcmU6CnRhYmxlX25hbWVzIDwtIGMoImtoX3AwOF9yZXRpbmEiLCAia2hfcDE1X3JldGluYSIsICJraF9wMDhfc2NuIiwKICAgICAgICAgICAgICAgICAia2hfcDE1X3NjbiIsICJraF9wMDhfZGxnbiIsICJraF9wMTVfZGxnbiIpCnRhYmxlX25hbWVzICVpbiUgbmFtZXMoZ2Vub3R5cGVfc2lnKQpuZXdzaWcgPC0gZ2Vub3R5cGVfc2lnW1sxXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBnZW5vdHlwZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gZ2Vub3R5cGVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpnZW5vdHlwZV91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmdlbm90eXBlX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGdlbm90eXBlX3Vwc2V0ciwgZXhjZWwgPSAiMzZ1cHNldF9nZW5vdHlwZS9nZW5vdHlwZV91cHNldF9ncm91cHMueGxzeCIpCmdlbm90eXBlX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzZ1cHNldF9nZW5vdHlwZS90ZXN0X2dlbm90eXBlX3Vwc2V0LnBkZiIpCnByaW50KGdlbm90eXBlX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCk5vdyBsZXQgdXMgdHJ5IHRoZSBsb2NhdGlvbi1zcGVjaWZpYyBjb21wYXJpc29ucwoKIyMgc2NuIHZzIHJldGluYSwgcDA4CgpgYGB7cn0KIyMgVGhlIGFwcHJvcHJpYXRlIGRhdGEgc3RydWN0dXJlIGlzICdnZW5vdHlwZV90YWJsZXMnLAojIyBhbmQgdGhlIHRhYmxlcyBvZiBpbnRlcmVzdCBhcmU6CnRhYmxlX25hbWVzIDwtIGMoInNyX3AwOF9oZXQiLCAic3JfcDA4X2tvIikKdGFibGVfbmFtZXMgJWluJSBuYW1lcyhsb2NhdGlvbl9zaWcpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjM2dXBzZXRfZ2Vub3R5cGUvc3JfcDA4X2hldGtvX3Vwc2V0X2dyb3Vwcy54bHN4IikKbG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzNnVwc2V0X2dlbm90eXBlL3Rlc3RfbG9jYXRpb25fc3JfcDA4X2hldGtvX3Vwc2V0LnBkZiIpCnByaW50KGxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCkkgYW0gcmVhc29uYWJseSBjZXJ0YWluIHRoYXQgUmFzaG1pIHdvdWxkIGxpa2UgYSB0YWJsZSBvZiB0aGUgZ2VuZXMKc2hhcmVkIGFtb25nIGluY3JlYXNlZCBzY24ga28gYW5kIGhldCBpbiB0aGUgYWJvdmUgcGxvdCBhbG9uZyB3aXRoIHRoZQppbmNyZWFzZWQgcmV0aW5hIChlLmcuIHRoZSAyNjkgYW5kIDEwMyBnZW5lIHNldHMpLgoKIyMgc2NuIHZzIHJldGluYSwgcDE1CgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygic3JfcDE1X2hldCIsICJzcl9wMTVfa28iKQp0YWJsZV9uYW1lcyAlaW4lIG5hbWVzKGxvY2F0aW9uX3NpZykKbG9jYXRpb25fdXBzZXRfaW5wdXQgPC0gbGlzdCgpCmZpcnN0X3RhYmxlIDwtIHRhYmxlX25hbWVzWzFdCm5ld3NpZyA8LSBsb2NhdGlvbl9zaWdbW2ZpcnN0X3RhYmxlXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpsb2NhdGlvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmxvY2F0aW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGxvY2F0aW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzZ1cHNldF9nZW5vdHlwZS9zcl9wMTVfaGV0a29fdXBzZXRfZ3JvdXBzLnhsc3giKQpsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcmludChzY25fcmV0aW5hX3AxNV91cHNldF9yZXN1bHQpCnBwKGZpbGUgPSAiMzZ1cHNldF9nZW5vdHlwZS90ZXN0X2xvY2F0aW9uX3NyX3AxNV9oZXRrb191cHNldC5wZGYiKQpwcmludChsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgojIyBkbGduIHZzIHJldGluYSwgcDA4CgpgYGB7cn0KIyMgVGhlIGFwcHJvcHJpYXRlIGRhdGEgc3RydWN0dXJlIGlzICdnZW5vdHlwZV90YWJsZXMnLAojIyBhbmQgdGhlIHRhYmxlcyBvZiBpbnRlcmVzdCBhcmU6CnRhYmxlX25hbWVzIDwtIGMoImRyX3AwOF9oZXQiLCAiZHJfcDA4X2tvIikKbG9jYXRpb25fdXBzZXRfaW5wdXQgPC0gbGlzdCgpCmZpcnN0X3RhYmxlIDwtIHRhYmxlX25hbWVzWzFdCm5ld3NpZyA8LSBsb2NhdGlvbl9zaWdbW2ZpcnN0X3RhYmxlXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpsb2NhdGlvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmxvY2F0aW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGxvY2F0aW9uX3Vwc2V0ciwgZXhjZWwgPSAiM3Vwc2V0X2dlbm90eXBlL2RyX3AwOF9oZXRrb191cHNldF9ncm91cHMueGxzeCIpCmxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzZ1cHNldF9nZW5vdHlwZS90ZXN0X2xvY2F0aW9uX2RyX3AwOF9oZXRrb191cHNldC5wZGYiKQpwcmludChsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgojIyBkbGduIHZzIHJldGluYSwgcDE1CgpgYGB7cn0KIyMgVGhlIGFwcHJvcHJpYXRlIGRhdGEgc3RydWN0dXJlIGlzICdnZW5vdHlwZV90YWJsZXMnLAojIyBhbmQgdGhlIHRhYmxlcyBvZiBpbnRlcmVzdCBhcmU6CnRhYmxlX25hbWVzIDwtIGMoImRyX3AxNV9oZXQiLCAiZHJfcDE1X2tvIikKbG9jYXRpb25fdXBzZXRfaW5wdXQgPC0gbGlzdCgpCmZpcnN0X3RhYmxlIDwtIHRhYmxlX25hbWVzWzFdCm5ld3NpZyA8LSBsb2NhdGlvbl9zaWdbW2ZpcnN0X3RhYmxlXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpsb2NhdGlvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmxvY2F0aW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGxvY2F0aW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbi9kcl9wMTVfaGV0a29fdXBzZXRfZ3JvdXBzLnhsc3giKQpsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb24vdGVzdF9sb2NhdGlvbl9kcl9wMTVfaGV0a29fdXBzZXQucGRmIikKcHJpbnQobG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgZGxnbiB2cyBzY24sIHAwOAoKYGBge3J9CnRhYmxlX25hbWVzIDwtIGMoImRzX3AwOF9oZXQiLCAiZHNfcDA4X2tvIikKbG9jYXRpb25fdXBzZXRfaW5wdXQgPC0gbGlzdCgpCmZpcnN0X3RhYmxlIDwtIHRhYmxlX25hbWVzWzFdCm5ld3NpZyA8LSBsb2NhdGlvbl9zaWdbW2ZpcnN0X3RhYmxlXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpsb2NhdGlvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmxvY2F0aW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGxvY2F0aW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbi9kc19wMDhfaGV0a29fdXBzZXRfZ3JvdXBzLnhsc3giKQpsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb24vdGVzdF9sb2NhdGlvbl9kc19wMDhfaGV0a29fdXBzZXQucGRmIikKcHJpbnQobG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgZGxnbiB2cyBzY24sIHAxNQoKYGBge3J9CnRhYmxlX25hbWVzIDwtIGMoImRzX3AxNV9oZXQiLCAiZHNfcDE1X2tvIikKbG9jYXRpb25fdXBzZXRfaW5wdXQgPC0gbGlzdCgpCmZpcnN0X3RhYmxlIDwtIHRhYmxlX25hbWVzWzFdCm5ld3NpZyA8LSBsb2NhdGlvbl9zaWdbW2ZpcnN0X3RhYmxlXV0KZm9yIChzaWcgaW4gMjpsZW5ndGgodGFibGVfbmFtZXMpKSB7CiAgbmFtZSA8LSB0YWJsZV9uYW1lc1tzaWddCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0KICBuZXdzaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0KfQpsb2NhdGlvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhuZXdzaWcpCmxvY2F0aW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGxvY2F0aW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbi9kc19wMTVfaGV0a29fdXBzZXRfZ3JvdXBzLnhsc3giKQpsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb24vdGVzdF9sb2NhdGlvbl9kc19wMTVfaGV0a29fdXBzZXQucGRmIikKcHJpbnQobG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyBTaGFyZWQgYW5kIHVuaXF1ZSBnZW5lIHNldHMgYWNyb3NzIHgvd3QKCkluIHRoaXMgYmxvY2sgSSB3YW50IHRvIGZpbmQgdGhlIHVuaXF1ZSBhbmQgc2hhcmVkIGdlbmVzIGJldHdlZW46CgoxLiAgc2NuIHA4IGhldC93dCBhbmQgcmV0aW5hIHA4IGhldC93dDogaHdwMDhzY25pbmMsIGh3cDA4cmV0aW5jLCBod3AwOHNjbmRlYywgaHdwMDhyZXRkZWMKMi4gIHNjbiBwMTUgaGV0L3d0IGFuZCByZXRpbmEgcDE1IGhldC93dDogaHdwMTVzY25pbmMsIGh3cDE1cmV0aW5jLCBod3AxNXNjbmRlYywgaHdwMTVyZXRkZWMKMy4gICMxIGFuZCAjMiB0b2dldGhlcjogIDggY2F0Z29yaWVzIGFib3ZlCjQuICBzY24gcDgga28vd3QgYW5kIHJldGluYSBwOCBrby93dAo1LiAgc2NuIHAxNSBrby93dCBhbmQgcmV0aW5hIHAxNSBrby93dAo2LiAgIzQgYW5kICM1IHRvZ2V0aGVyCgpUaGUgY29tcGFyaXNvbnMgb2YgaGV0L3d0IGFyZSBmb3VuZCBpbiB0aGUgJ2luY2x1c2lvbl9zaWcnIGRhdGFzZXQ7CmJlY2F1c2UgdGhleSBhcmUgcHJvdmlkaW5nIG91ciBjdXRvZmZzIGZvciBub25zcGVjaWZpYyBiaW5kaW5nLgoKIyMgTnVtYmVyIDEgYWJvdmU6IHAwOF9oZXQgdnMgd3QgZm9yIHNjbiBhbmQgcmV0aW5hLgoKYGBge3J9CnRhYmxlX25hbWVzIDwtIGMoInAwOF9oZXRfc2NuIiwgInAwOF9oZXRfcmV0aW5hIikKaW5jbHVzaW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcsIGNvbnRyYXN0cyA9IHRhYmxlX25hbWVzKQppbmNsdXNpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMoaW5jbHVzaW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbnMvcnNfcDA4X2hldF9pbmNsdXNpb25fdXBzZXRfZ3JvdXBzLnhsc3giKQppbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9ucy9pbmNsdXNpb25fc3JfcDA4X3Vwc2V0LnBkZiIpCnByaW50KGluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgojIyBOdW1iZXIgMiBhYm92ZTogcDE1X2hldCB2cyB3dCBmb3Igc2NuIGFuZCByZXRpbmEuCgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygicDE1X2hldF9zY24iLCAicDE1X2hldF9yZXRpbmEiKQppbmNsdXNpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcoaW5jbHVzaW9uX3NpZywgY29udHJhc3RzID0gdGFibGVfbmFtZXMpCmluY2x1c2lvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcyhpbmNsdXNpb25fdXBzZXRyLCBleGNlbCA9ICIzN3Vwc2V0X2xvY2F0aW9ucy9yc19wMTVfaGV0X2luY2x1c2lvbl91cHNldF9ncm91cHMueGxzeCIpCmluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb25zL2luY2x1c2lvbl9zcl9wMTVfdXBzZXQucGRmIikKcHJpbnQoaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIE51bWJlciAzIGFib3ZlOiBjb21iaW5hdGlvbiBvZiAjMSBhbmQgIzIKCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIsICJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpCmluY2x1c2lvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhpbmNsdXNpb25fc2lnLCBjb250cmFzdHMgPSB0YWJsZV9uYW1lcykKaW5jbHVzaW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGluY2x1c2lvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25zL3JzX3AwOHAxNV9oZXRfaW5jbHVzaW9uX3Vwc2V0X2dyb3Vwcy54bHN4IikKaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzd1cHNldF9sb2NhdGlvbnMvaW5jbHVzaW9uX3NyX3AwOHAxNV91cHNldC5wZGYiKQpwcmludChpbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgTnVtYmVyIDQgYWJvdmUgcDA4X2tvIHZzIHd0IGZvciBzY24gYW5kIHJldGluYS4KCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiKQppbmNsdXNpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcoaW5jbHVzaW9uX3NpZywgY29udHJhc3RzID0gdGFibGVfbmFtZXMpCmluY2x1c2lvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcyhpbmNsdXNpb25fdXBzZXRyLCBleGNlbCA9ICIzN3Vwc2V0X2xvY2F0aW9ucy9yc19wMDhfa29faW5jbHVzaW9uX3Vwc2V0X2dyb3Vwcy54bHN4IikKaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzd1cHNldF9sb2NhdGlvbnMvaW5jbHVzaW9uX3NyX3AwOF9rb191cHNldC5wZGYiKQpwcmludChpbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgTnVtYmVyIDUgYWJvdmUgcDE1X2tvIHZzIHd0IGZvciBzY24gYW5kIHJldGluYS4KCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJwMTVfa29fc2NuIiwgInAxNV9rb19yZXRpbmEiKQppbmNsdXNpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcoaW5jbHVzaW9uX3NpZywgY29udHJhc3RzID0gdGFibGVfbmFtZXMpCmluY2x1c2lvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcyhpbmNsdXNpb25fdXBzZXRyLCBleGNlbCA9ICIzN3Vwc2V0X2xvY2F0aW9ucy9yc19wMTVfa29faW5jbHVzaW9uX3Vwc2V0X2dyb3Vwcy54bHN4IikKaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzd1cHNldF9sb2NhdGlvbnMvaW5jbHVzaW9uX3NyX3AxNV9rb191cHNldC5wZGYiKQpwcmludChpbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgTnVtYmVyIDYgYWJvdmU6IENvbWJpbmluZyAjNCBhbmQgIzUKCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiLCAicDE1X2tvX3NjbiIsICJwMTVfa29fcmV0aW5hIikKaW5jbHVzaW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcsIGNvbnRyYXN0cyA9IHRhYmxlX25hbWVzKQppbmNsdXNpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMoaW5jbHVzaW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbnMvcnNfcDA4cDE1X2tvX2luY2x1c2lvbl91cHNldF9ncm91cHMueGxzeCIpCmluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb25zL2luY2x1c2lvbl9zcl9wMDhwMTVfa29fdXBzZXQucGRmIikKcHJpbnQoaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMgR1NWQQoKYGBge3J9Cm1zaWdkYiA8LSAicmVmZXJlbmNlL21zaWdkYl92MjAyNC4xLk1tLmRiIgppZiAoZmlsZS5leGlzdHMobXNpZ2RiKSkgewogIHYzX2hfZ3N2YSA8LSBzaW1wbGVfZ3N2YSh2M19wYWlyd2lzZV9pbnB1dCwgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgc2lnbmF0dXJlX2NhdGVnb3J5ID0gIm1oIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZWRfaWQgPSAibWdpX3N5bWJvbCIpCiAgdjNfaF9nc3ZhCgogIHYzX2hfZ3N2YV9zaWcgPC0gZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICB2M19oX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiL2dzdmFfc2lnX2hhbGxtYXJrX2NhdGVnb3JpZXMueGxzeCIpCiAgdjNfaF9nc3ZhX3NpZwoKICB2M19tMV9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHYzX3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gIm1naV9zeW1ib2wiKQogIHYzX20xX2dzdmEKICB2M19tMV9nc3ZhX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHYzX20xX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiL2dzdmFfc2lnX3Bvc2l0aW9uYWxfY2F0ZWdvcmllcy54bHN4IikKICB2M19tMV9nc3ZhX3NpZwoKICB2M19tMl9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHYzX3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gIm1naV9zeW1ib2wiKQogIHYzX20yX2dzdmEKICB2M19tMl9nc3ZhX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHYzX20yX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiL2dzdmFfc2lnX2N1cmF0ZWRfY2F0ZWdvcmllcy54bHN4IikKICB2M19tMl9nc3ZhX3NpZwoKICB2M19tM19nc3ZhIDwtIHNpbXBsZV9nc3ZhKHYzX3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gIm1naV9zeW1ib2wiKQogIHYzX20zX2dzdmEKICB2M19tM19nc3ZhX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHYzX20zX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiL2dzdmFfc2lnX3JlZ3VsYXRvcnlfY2F0ZWdvcmllcy54bHN4IikKICB2M19tM19nc3ZhX3NpZwoKICB2M19tNV9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHYzX3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gIm1naV9zeW1ib2wiKQogIHYzX201X2dzdmEKICB2M19tNV9nc3ZhX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHYzX201X2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiL2dzdmFfc2lnX29udG9sb2d5X2NhdGVnb3JpZXMueGxzeCIpCiAgdjNfbTVfZ3N2YV9zaWcKCiAgdjNfbThfZ3N2YSA8LSBzaW1wbGVfZ3N2YSh2M19wYWlyd2lzZV9pbnB1dCwgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgc2lnbmF0dXJlX2NhdGVnb3J5ID0gIm04IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZXMgPSBtc2lnZGIsIGlkX3NvdXJjZSA9ICJmZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1aXJlZF9pZCA9ICJtZ2lfc3ltYm9sIikKICB2M19tOF9nc3ZhCiAgdjNfbThfZ3N2YV9zaWcgPC0gZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICB2M19tOF9nc3ZhLCBleGNlbCA9ICIzOG1zaWdkYi9nc3ZhX3NpZ19jZWxsdHlwZV9jYXRlZ29yaWVzLnhsc3giKQogIHYzX204X2dzdmFfc2lnCn0KYGBgCgojIEdTRUEgaW1hZ2VzCgpVcCBhYm92ZSBJIGNyZWF0ZWQgYSBmYWlybHkgbGFyZ2Ugc2V0IG9mIGVucmljaG1lbnQvR1NFQSBhbmFseXNlcy4KTGV0IHVzIHB1bGwgc29tZSBvZiB0aGUgbW9zdCBpbnRlcmVzdGluZyByZXN1bHRzIGhlcmUgYW5kIGxvb2sgYXQKdGhlbS4KCkhlcmUgYXJlIHRoZSBzcGVjaWZpYyBxdWVyaWVzIGZyb20gUmFzaG1pOgoKKiBHZW5vdHlwZSAoaGV0IHZzIGtvKToKICAqIFA4IGhldCBhbmQga28gZm9yIFJldAogICogU0NOIChQOCBoZXQgdnMgS08gU0NOCiAgKiBQOCBoZXQgdnMgS08gUmV0KQogICogUDE1IGhldCBhbmQga28gZm9yIFJldAoqIExvY2F0aW9uIChzb21hbCB2cyBheG9uYWwpOgogICogU1JfUDA4X0tPCiAgKiBTUl9QMDhfSGV0CiAgKiBTUl9QMTVfS08KICAqIFNSX1AxNV9IZXQKKiBUaW1lKHA4dnMgcDE1KToKICAqIHRfaGV0X1JldF8gcG84LXAxNQogICogdF9LT19SZXRfQyBwbzgtcDE1CiAgKiB0X2hldF9TQ05fcG84LXAxNQogICogdF9LT19TQ05fcG84LXAxNQoKIyMgR2Vub3R5cGUKCkxldCB1cyB0YWtlIGEgbW9tZW50IGFuZCBzZWUgZm9yIHdoaWNoIGNvbnRyYXN0cyBJIGFjcXVpcmVkIHJlc3VsdHM6CgpJIG5lZWQgdG8gbWFrZSBhIGxpdHRsZSBzdW1tYXJ5IGZvciBjbHVzdGVycHJvZmlsZXIgdG9vIHNvIHRoYXQgSSBjYW4gZWFzaWx5IHNlZSBob3cgbWFueSBoaXRzIHRoZXJlCmFyZSBmb3IgZWFjaCBjb250cmFzdC4KCmBgYHtyfQpzdW1tYXJ5KGdlbm90eXBlX2Z1bGxfZ3ApCmZvciAoaSBpbiBuYW1lcyhnZW5vdHlwZV9mdWxsX2dwKSkgewogIHByaW50KGkpCiAgcHJpbnQoZ2Vub3R5cGVfZnVsbF9ncFtbaV1dW1sibnVtX2hpdHMiXV0pCn0Kc3VtbWFyeShnZW5vdHlwZV9mdWxsX2NwKQpmb3IgKGkgaW4gbmFtZXMoZ2Vub3R5cGVfZnVsbF9jcCkpIHsKICBwcmludChpKQogIHByaW50KG5yb3coZ2Vub3R5cGVfZnVsbF9jcFtbaV1dW1siZ3NlX2dvIl1dKSkKfQpgYGAKCiMjIyBwOCBoZXQva28gZm9yIHJldGluYToKClRoaXMgY29udHJhc3QsIGV2ZW4gYmVmb3JlIGZpbHRlcmluZyBhd2F5IHRoZSBoaWdoLXd0IGdlbmVzLCBvbmx5IGhhcyA4IGdlbmVzIGluIHRoZSBzZXQgb2YgdXAgYW5kCmRvd24gZ2VuZXMgY29tYmluZWQuICBBcyBhIHJlc3VsdCwgbXkgZnVuY3Rpb24gd2hpY2ggcGVyZm9ybXMgZ1Byb2ZpbGVyL2NsdXN0ZXJQcm9maWxlciBza2lwcyBpdCwKYW5kIGFsc28gc2tpcHMgdGhlIHAxNSBoZXQva28gZm9yIHJldGluYSBzYW1wbGVzLgoKIyMjIHA4IGhldC9rbyBmb3Igc2NuOgoKVGhpcyBoYXMgYSBidW5jaCBtb3JlIGdlbmVzOiA1MSB1cCBhbmQgMTI4IGRvd24uClVuZm9ydHVuYXRlbHksIGdQcm9maWxlciBzZWVzIG5vIHNpZ25pZmljYW50IG92ZXItcmVwcmVzZW50YXRpb24gaW4gdGhlIHVwIGNhdGVnb3J5IG9mIGdlbmVzLgpUaGUgZG93biBjYXRlZ29yeSBoYXMKClRoZSB1cC9kb3duIHNldHMgZnJvbSBjbHVzdGVyUHJvZmlsZXIgaGF2ZSBlbnJpY2hfZ28sIGdzZV9nbywgYW5kIGdvX2RhdGEgdG8gbG9vayBhdC4KCmBgYHtyfQpnZW5vdHlwZV9mdWxsX2dwJGtoX3AwOF9zY25fdXAkbnVtX2hpdHMKZ2Vub3R5cGVfZnVsbF9ncCRraF9wMDhfc2NuX2Rvd24kbnVtX2hpdHMKCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGdlbm90eXBlX2Z1bGxfZ3Aka2hfcDA4X3Njbl9kb3duW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQpwbG90c1tbInRyZWUiXV0KYGBgCgpQZXJoYXBzIEkgc2hvdWxkIGp1c3QgYXNrIHRoZSBxdWVzdGlvbjogZm9yIHdoaWNoIGNhdGVnb3JpZXMgZGlkIEkgZ2V0IHJlc3VsdHMgYmFjaz8KCmBgYHtyfQpzdW1tYXJ5KGdlbm90eXBlX2Z1bGxfZ3ApCmBgYAoKa2hfcDA4X2RsZ25fdXA6IE5vIHNpZ25pZmljYW50IGdQcm9maWxlciByZXN1bHRzLgpraF9wMTVfZGxnbl91cDogU2lnbmlmaWNhbnQgQlAsIEhQLCBLRUdHLCBNRiwgUkVBQywgVEYKa2hfcDA4X3Njbl91cDogTm8gc2lnbmlmaWNhbnQgZ1Byb2ZpbGVyIHJlc3VsdHMuCmtoX3AwOF9zY25fZG93bjogU2lnbmlmaWNhbnQgQlAsIE1pUk5BLCBNRiwgVEYKa2hfcDE1X3Njbl9kb3duOiBTaWduaWZpY2FudCBCUCwgTUYKCgpgYGB7cn0KcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQoZ2Vub3R5cGVfZnVsbF9ncFtbImtoX3AxNV9kbGduX3VwIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQpgYGAKCiMjIExvY2F0aW9uCgojIyMgU2NuIHZzIHJldGluYSBrbywgcDA4CgpgYGB7cn0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDA4X2tvIl1dW1sic3JfcDA4X2tvX3VwIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQobG9jYXRpb25fZ3BbWyJzcl9wMDhfa28iXV1bWyJzcl9wMDhfa29fZG93biJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KYGBgCgojIyMgc2NuIHZzIHJldGluYSwgaGV0LCBwMDgKCkVucmljaGVkIGdyb3VwczogQlAsIEtFR0csIE1GLCBURiwgQ0MKCmBgYHtyfQpzdW1tYXJ5KGxvY2F0aW9uX2dwW1sic3JfcDA4X2hldCJdXVtbInNyX3AwOF9oZXRfdXAiXV0pCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDA4X2hldCJdXVtbInNyX3AwOF9oZXRfdXAiXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AwOF9oZXQiXV1bWyJzcl9wMDhfaGV0X3VwIl1dW1siQ0NfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQobG9jYXRpb25fZ3BbWyJzcl9wMDhfaGV0Il1dW1sic3JfcDA4X2hldF9kb3duIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKc3JfcDA4X2hldF90b3BuX2dzZWEgPC0gcGxvdF90b3BuX2dzZWEobG9jYXRpb25fY3BbWyIiXV0pCgpgYGAKCiMjIyBTY24gdnMgcmV0aW5hIGtvLCBwMTUKCmBgYHtyfQpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AxNV9rbyJdXVtbInNyX3AxNV9rb191cCJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDE1X2tvIl1dW1sic3JfcDE1X2tvX2Rvd24iXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCmBgYAoKIyMjIHNjbiB2cyByZXRpbmEsIGhldCwgcDE1CgpgYGB7cn0KcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQobG9jYXRpb25fZ3BbWyJzcl9wMTVfaGV0Il1dW1sic3JfcDE1X2hldF91cCJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDE1X2hldCJdXVtbInNyX3AxNV9oZXRfZG93biJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KYGBgCgojIyBUaW1lCgojIyMgaGV0IHJldGluYQoKVXBzOiBzaWduaWZpY2FudCByZXN1bHRzIGZvciBCUCwgTUYsIFRGCkRvd25zOiBCUCwgTUYsIFJFQUMsIFRGLCBXUAoKYGBge3J9CnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KHRpbWVfZ3BbWyJ0X2hldF9yZXRpbmEiXV1bWyJ0X2hldF9yZXRpbmFfdXAiXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdCh0aW1lX2dwW1sidF9oZXRfcmV0aW5hIl1dW1sidF9oZXRfcmV0aW5hX2Rvd24iXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCmBgYAoKIyMjIGtvIHJldGluYQoKVXA6IEJQLCBNaVJOQSwgTUYKRG93bjogQlAsIE1GLCBSRUFDLCBURgoKYGBge3J9CnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KHRpbWVfZ3BbWyJ0X2tvX3JldGluYSJdXVtbInRfa29fcmV0aW5hX3VwIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQodGltZV9ncFtbInRfa29fcmV0aW5hIl1dW1sidF9rb19yZXRpbmFfZG93biJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KYGBgCgojIyMgaGV0IHNjbgoKTmVpdGhlciBvZiB0aGUgU0NOIGdQcm9maWxlciBxdWVyaWVzIHByb3ZpZGVkIGFueSByZXN1bHRzLgoKIyBDb21wYXJlIHRoZSBidWxrIGFuZCBUUkFQIGRhdGEKClRoZXJlIGFyZSBhIGZldyB2YXJpYWJsZXMgZnJvbSB0aGUgYnVsayBhbmFseXNlcyB3aGljaCB3ZSBtYXkgdXNlIHRvCmNvbXBhcmUgdG8gdGhlIFRSQVAgZGF0YToKCm1tX2RlX2RsZ25fc3ZhLCBtbV9kZV9yZXRfc3ZhLCBtbV9kZV9zY25fc3ZhLCBtbV9kZV9kbGduLCBtbV9kZV9yZXQsCm1tX2RlX3Njbi4KClRob3NlIGFyZSBsb2NhdGlvbi1zcGVjaWZpYyBjb250cmFzdHMuCgpnZW5vbG9jX2RlX3N2YS9nZW5vbG9jX3RhYmxlX3N2YSBwcm92aWRlIGFsbCBjb250cmFzdHMgdGhhdCBJIHRob3VnaHQKbWlnaHQgYmUgZnVuLgoKVGhlIGZvbGxvd2luZyBpcyBhbGwgcHJlLXd0IGZpbHRlcmluZy4gIE5leHQgSSB3aWxsIHJlcGVhdCBldmVyeXRoaW5nIHBvc3QtZmlsdGVyaW5nLgoKYGBge3J9CiMjIFRoZSBidWxrIHRhYmxlcwpnZW5vbG9jX3RhYmxlX3N2YVtbInRhYmxlX25hbWVzIl1dCgojIyBUaGUgVFJBUCB0YWJsZXMKbG9jYXRpb25fdGFibGVzX2Z1bGxbWyJ0YWJsZV9uYW1lcyJdXQpnZW5vdHlwZV90YWJsZXNfZnVsbFtbInRhYmxlX25hbWVzIl1dCnRpbWVfdGFibGVzX2Z1bGxbWyJ0YWJsZV9uYW1lcyJdXQoKIyMgUmV0aW5hIGhldCB2cyBSZXRpbmEgd3QKYnVsa190YWJsZSA8LSBnZW5vbG9jX3RhYmxlX3N2YVtbImRhdGEiXV1bWyJSZXRpbmFfa29fdnNfUmV0aW5hX2hldCJdXQp0cmFwX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AwOF9yZXRpbmEiXV0KcmV0aW5hX2tvX2hldF9hdWNjIDwtIGNhbGN1bGF0ZV9hdWNjKGJ1bGtfdGFibGUsIHRyYXBfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBweCA9ICJkZXNlcV9hZGpwIiwgcHkgPSAiZGVzZXFfYWRqcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBseCA9ICJkZXNlcV9sb2dmYyIsIGx5ID0gImRlc2VxX2xvZ2ZjIikKcmV0aW5hX2tvX2hldF9hdWNjCnJldGluYV9rb19oZXRfcm9zIDwtIHJhbmtfb3JkZXJfc2NhdHRlcihidWxrX3RhYmxlLCB0cmFwX3RhYmxlKQpyZXRpbmFfa29faGV0X3Jvc1tbImxmY19zY2F0dGVyIl1dCgpidWxrX3RhYmxlIDwtIGdlbm9sb2NfdGFibGVfc3ZhW1siZGF0YSJdXVtbIlJldGluYV9rb192c19SZXRpbmFfaGV0Il1dCnRyYXBfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDE1X3JldGluYSJdXQpyZXRpbmFfa29faGV0X2F1Y2MgPC0gY2FsY3VsYXRlX2F1Y2MoYnVsa190YWJsZSwgdHJhcF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB4ID0gImRlc2VxX2FkanAiLCBweSA9ICJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx4ID0gImRlc2VxX2xvZ2ZjIiwgbHkgPSAiZGVzZXFfbG9nZmMiKQpyZXRpbmFfa29faGV0X2F1Y2MKcmV0aW5hX2tvX2hldF9yb3MgPC0gcmFua19vcmRlcl9zY2F0dGVyKGJ1bGtfdGFibGUsIHRyYXBfdGFibGUpCnJldGluYV9rb19oZXRfcm9zW1sibGZjX3NjYXR0ZXIiXV0KCmJ1bGtfdGFibGUgPC0gZ2Vub2xvY190YWJsZV9zdmFbWyJkYXRhIl1dW1siU0NOX2tvX3ZzX1NDTl9oZXQiXV0KdHJhcF90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMDhfc2NuIl1dCnNjbl9rb19oZXRfYXVjYyA8LSBjYWxjdWxhdGVfYXVjYyhidWxrX3RhYmxlLCB0cmFwX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHggPSAiZGVzZXFfYWRqcCIsIHB5ID0gImRlc2VxX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHggPSAiZGVzZXFfbG9nZmMiLCBseSA9ICJkZXNlcV9sb2dmYyIpCnNjbl9rb19oZXRfYXVjYwpzY25fa29faGV0X3JvcyA8LSByYW5rX29yZGVyX3NjYXR0ZXIoYnVsa190YWJsZSwgdHJhcF90YWJsZSkKc2NuX2tvX2hldF9yb3NbWyJsZmNfc2NhdHRlciJdXQoKCmJ1bGtfdGFibGUgPC0gZ2Vub2xvY190YWJsZV9zdmFbWyJkYXRhIl1dW1siU0NOX2tvX3ZzX1NDTl9oZXQiXV0KdHJhcF90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMTVfc2NuIl1dCnNjbl9rb19oZXRfYXVjYyA8LSBjYWxjdWxhdGVfYXVjYyhidWxrX3RhYmxlLCB0cmFwX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHggPSAiZGVzZXFfYWRqcCIsIHB5ID0gImRlc2VxX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHggPSAiZGVzZXFfbG9nZmMiLCBseSA9ICJkZXNlcV9sb2dmYyIpCnNjbl9rb19oZXRfYXVjYwpzY25fa29faGV0X3JvcyA8LSByYW5rX29yZGVyX3NjYXR0ZXIoYnVsa190YWJsZSwgdHJhcF90YWJsZSkKc2NuX2tvX2hldF9yb3NbWyJsZmNfc2NhdHRlciJdXQoKYnVsa190YWJsZSA8LSBnZW5vbG9jX3RhYmxlX3N2YVtbImRhdGEiXV1bWyJkTEdOX2tvX3ZzX2RMR05faGV0Il1dCnRyYXBfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDA4X2RsZ24iXV0KZGxnbl9rb19oZXRfYXVjYyA8LSBjYWxjdWxhdGVfYXVjYyhidWxrX3RhYmxlLCB0cmFwX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHggPSAiZGVzZXFfYWRqcCIsIHB5ID0gImRlc2VxX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHggPSAiZGVzZXFfbG9nZmMiLCBseSA9ICJkZXNlcV9sb2dmYyIpCmRsZ25fa29faGV0X2F1Y2MKZGxnbl9rb19oZXRfcm9zIDwtIHJhbmtfb3JkZXJfc2NhdHRlcihidWxrX3RhYmxlLCB0cmFwX3RhYmxlKQpkbGduX2tvX2hldF9yb3NbWyJsZmNfc2NhdHRlciJdXQoKYnVsa190YWJsZSA8LSBnZW5vbG9jX3RhYmxlX3N2YVtbImRhdGEiXV1bWyJkTEdOX2tvX3ZzX2RMR05faGV0Il1dCnRyYXBfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDE1X2RsZ24iXV0KZGxnbl9rb19oZXRfYXVjYyA8LSBjYWxjdWxhdGVfYXVjYyhidWxrX3RhYmxlLCB0cmFwX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHggPSAiZGVzZXFfYWRqcCIsIHB5ID0gImRlc2VxX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHggPSAiZGVzZXFfbG9nZmMiLCBseSA9ICJkZXNlcV9sb2dmYyIpCmRsZ25fa29faGV0X2F1Y2MKZGxnbl9rb19oZXRfcm9zIDwtIHJhbmtfb3JkZXJfc2NhdHRlcihidWxrX3RhYmxlLCB0cmFwX3RhYmxlKQpkbGduX2tvX2hldF9yb3NbWyJsZmNfc2NhdHRlciJdXQpgYGAKCmBgYHtyfQojIyBUaGUgYnVsayB0YWJsZXMKZ2Vub2xvY190YWJsZV9zdmFbWyJ0YWJsZV9uYW1lcyJdXQoKIyMgVGhlIFRSQVAgdGFibGVzCmxvY2F0aW9uX3RhYmxlc1tbInRhYmxlX25hbWVzIl1dCmdlbm90eXBlX3RhYmxlc1tbInRhYmxlX25hbWVzIl1dCnRpbWVfdGFibGVzW1sidGFibGVfbmFtZXMiXV0KCiMjIFJldGluYSBoZXQgdnMgUmV0aW5hIHd0CmJ1bGtfdGFibGUgPC0gZ2Vub2xvY190YWJsZV9zdmFbWyJkYXRhIl1dW1siUmV0aW5hX2tvX3ZzX1JldGluYV9oZXQiXV0KdHJhcF90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMDhfcmV0aW5hIl1dCnJldGluYV9rb19oZXRfYXVjYyA8LSBjYWxjdWxhdGVfYXVjYyhidWxrX3RhYmxlLCB0cmFwX3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHggPSAiZGVzZXFfYWRqcCIsIHB5ID0gImRlc2VxX2FkanAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHggPSAiZGVzZXFfbG9nZmMiLCBseSA9ICJkZXNlcV9sb2dmYyIpCnJldGluYV9rb19oZXRfYXVjYwpyZXRpbmFfa29faGV0X3JvcyA8LSByYW5rX29yZGVyX3NjYXR0ZXIoYnVsa190YWJsZSwgdHJhcF90YWJsZSkKcmV0aW5hX2tvX2hldF9yb3NbWyJsZmNfc2NhdHRlciJdXQoKYnVsa190YWJsZSA8LSBnZW5vbG9jX3RhYmxlX3N2YVtbImRhdGEiXV1bWyJSZXRpbmFfa29fdnNfUmV0aW5hX2hldCJdXQp0cmFwX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AxNV9yZXRpbmEiXV0KcmV0aW5hX2tvX2hldF9hdWNjIDwtIGNhbGN1bGF0ZV9hdWNjKGJ1bGtfdGFibGUsIHRyYXBfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBweCA9ICJkZXNlcV9hZGpwIiwgcHkgPSAiZGVzZXFfYWRqcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBseCA9ICJkZXNlcV9sb2dmYyIsIGx5ID0gImRlc2VxX2xvZ2ZjIikKcmV0aW5hX2tvX2hldF9hdWNjCnJldGluYV9rb19oZXRfcm9zIDwtIHJhbmtfb3JkZXJfc2NhdHRlcihidWxrX3RhYmxlLCB0cmFwX3RhYmxlKQpyZXRpbmFfa29faGV0X3Jvc1tbImxmY19zY2F0dGVyIl1dCgpidWxrX3RhYmxlIDwtIGdlbm9sb2NfdGFibGVfc3ZhW1siZGF0YSJdXVtbIlNDTl9rb192c19TQ05faGV0Il1dCnRyYXBfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDA4X3NjbiJdXQpzY25fa29faGV0X2F1Y2MgPC0gY2FsY3VsYXRlX2F1Y2MoYnVsa190YWJsZSwgdHJhcF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB4ID0gImRlc2VxX2FkanAiLCBweSA9ICJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx4ID0gImRlc2VxX2xvZ2ZjIiwgbHkgPSAiZGVzZXFfbG9nZmMiKQpzY25fa29faGV0X2F1Y2MKc2NuX2tvX2hldF9yb3MgPC0gcmFua19vcmRlcl9zY2F0dGVyKGJ1bGtfdGFibGUsIHRyYXBfdGFibGUpCnNjbl9rb19oZXRfcm9zW1sibGZjX3NjYXR0ZXIiXV0KCgpidWxrX3RhYmxlIDwtIGdlbm9sb2NfdGFibGVfc3ZhW1siZGF0YSJdXVtbIlNDTl9rb192c19TQ05faGV0Il1dCnRyYXBfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDE1X3NjbiJdXQpzY25fa29faGV0X2F1Y2MgPC0gY2FsY3VsYXRlX2F1Y2MoYnVsa190YWJsZSwgdHJhcF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB4ID0gImRlc2VxX2FkanAiLCBweSA9ICJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx4ID0gImRlc2VxX2xvZ2ZjIiwgbHkgPSAiZGVzZXFfbG9nZmMiKQpzY25fa29faGV0X2F1Y2MKc2NuX2tvX2hldF9yb3MgPC0gcmFua19vcmRlcl9zY2F0dGVyKGJ1bGtfdGFibGUsIHRyYXBfdGFibGUpCnNjbl9rb19oZXRfcm9zW1sibGZjX3NjYXR0ZXIiXV0KCmJ1bGtfdGFibGUgPC0gZ2Vub2xvY190YWJsZV9zdmFbWyJkYXRhIl1dW1siZExHTl9rb192c19kTEdOX2hldCJdXQp0cmFwX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AwOF9kbGduIl1dCmRsZ25fa29faGV0X2F1Y2MgPC0gY2FsY3VsYXRlX2F1Y2MoYnVsa190YWJsZSwgdHJhcF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB4ID0gImRlc2VxX2FkanAiLCBweSA9ICJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx4ID0gImRlc2VxX2xvZ2ZjIiwgbHkgPSAiZGVzZXFfbG9nZmMiKQpkbGduX2tvX2hldF9hdWNjCmRsZ25fa29faGV0X3JvcyA8LSByYW5rX29yZGVyX3NjYXR0ZXIoYnVsa190YWJsZSwgdHJhcF90YWJsZSkKZGxnbl9rb19oZXRfcm9zW1sibGZjX3NjYXR0ZXIiXV0KCmJ1bGtfdGFibGUgPC0gZ2Vub2xvY190YWJsZV9zdmFbWyJkYXRhIl1dW1siZExHTl9rb192c19kTEdOX2hldCJdXQp0cmFwX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AxNV9kbGduIl1dCmRsZ25fa29faGV0X2F1Y2MgPC0gY2FsY3VsYXRlX2F1Y2MoYnVsa190YWJsZSwgdHJhcF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB4ID0gImRlc2VxX2FkanAiLCBweSA9ICJkZXNlcV9hZGpwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx4ID0gImRlc2VxX2xvZ2ZjIiwgbHkgPSAiZGVzZXFfbG9nZmMiKQpkbGduX2tvX2hldF9hdWNjCmRsZ25fa29faGV0X3JvcyA8LSByYW5rX29yZGVyX3NjYXR0ZXIoYnVsa190YWJsZSwgdHJhcF90YWJsZSkKZGxnbl9rb19oZXRfcm9zW1sibGZjX3NjYXR0ZXIiXV0KYGBgCgojIEJpYmxpb2dyYXBoeQoKYGBge3Igc2F2ZW1lLCBldmFsPUZBTFNFfQpwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQptZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCBzYXZlZmlsZSkpCnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkpCmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsPUZBTFNFfQp0bXAgPC0gbG9hZG1lKGZpbGVuYW1lID0gc2F2ZWZpbGUpCmBgYAo=