1 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/’)

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

3 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…

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

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

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")
## Dropped 1 rows from the sample metadata because the sample ID is blank.
## Warning in extract_metadata(starting_metadata): There were NA values in the condition column, setting them to 'undefined'.

## Warning in extract_metadata(starting_metadata): There were NA values in the condition column, setting them to 'undefined'.
## Warning in dispatch_regex_search(meta, search, replace, input_file_spec, : NAs introduced by coercion

## Warning in dispatch_regex_search(meta, search, replace, input_file_spec, : NAs introduced by coercion
## Warning in readLines(input_handle): line 58 appears to contain an embedded nul

## Warning in readLines(input_handle): line 58 appears to contain an embedded nul

## Warning in readLines(input_handle): line 58 appears to contain an embedded nul

## Warning in readLines(input_handle): line 58 appears to contain an embedded nul

## Warning in readLines(input_handle): line 58 appears to contain an embedded nul

## Warning in readLines(input_handle): line 58 appears to contain an embedded nul
## Writing new metadata to: sample_sheets/20240606_only_umd_sequenced_modified.xlsx
## Deleting the file sample_sheets/20240606_only_umd_sequenced_modified.xlsx before writing the tables.

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!

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

mm_annot <- load_biomart_annotations(species = "mmusculus", year = "2023", month = "02")
## The biomart annotations file already exists, loading from it.
mm_annot <- mm_annot[["annotation"]]
mm_annot[["txid"]] <- paste0(mm_annot[["ensembl_transcript_id"]], ".", mm_annot[["version"]])
rownames(mm_annot) <- make.names(mm_annot[["ensembl_gene_id"]], unique=TRUE)
tx_gene_map <- mm_annot[, c("txid", "ensembl_gene_id")]

6 Hisat2 expressionsets

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.

6.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" = "#9ECAE1",
    "p15_het_dlgn" = "#9ECAE1",
    "p08_het_retina" = "#F46D43",
    "p15_het_retina" = "#F46D43",
    "p08_het_scn" = "#2CA25F",
    "p15_het_scn" = "#2CA25F",
    "p08_ko_dlgn" = "#3182BD",
    "p15_ko_dlgn" = "#3182BD",
    "p08_ko_retina" = "#FDAE61",
    "p15_ko_retina" = "#FDAE61",
    "p08_ko_scn" = "#006D2C",
    "p15_ko_scn" = "#006D2C",
    "p08_wt_dlgn" = "#DEEBF7",
    "p15_wt_dlgn" = "#DEEBF7",
    "p08_wt_retina" = "#D73027",
    "p15_wt_retina" = "#D73027",
    "p08_wt_scn" = "#66C2A4",
    "p15_wt_scn" = "#66C2A4"),
  "geno_loc" = list(
    "het_dlgn" = "#9ECAE1",
    "het_retina" = "#F46D43",
    "het_scn" = "#2CA25F",
    "ko_dlgn" = "#3182BD",
    "ko_retina" = "#FDAE61",
    "ko_scn" = "#006D2C",
    "wt_dlgn" = "#DEEBF7",
    "wt_retina" = "#D73027",
    "wt_scn" = "#66C2A4"),
  ## These colors are coming from ipRGC_summaryplots.html
  ## I am using kcolorchooser to grab them rather than get confused by the text
  "location" = list(
    "retina" = "#d73027",
    "dlgn" = "#3182bd",
    "scn" = "#006b29"),
  "genotype" = list(
    "wt" = "#D4D4D4",
    "het" = "#787878",
    "ko" = "#313131"),
  "time" = list(
    "p08" = "#5E104B",
    "p15" = "#4E9231"))
label_column <- "mgisymbol" ## Set the column used to extract gene symbols rather than ENSG.....

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.

mm38_hisat_v1 <- create_expt(iprgc_2022_meta[["new_meta"]],
                             gene_info = mm_annot,
                             file_column = "symlink") %>%
  set_expt_conditions(fact = "genolocatb") %>%
  set_expt_batches(fact = "timeatb") %>%
  set_expt_colors(color_choices[["geno_loc"]])
## Reading the sample metadata.
## The sample definitions comprises: 69 rows(samples) and 72 columns(metadata fields).
## Warning in create_expt(iprgc_2022_meta[["new_meta"]], gene_info = mm_annot, : Some samples were removed when cross referencing the samples against
## the count data.
## Matched 25663 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 25760 features and 61 samples.
## The numbers of samples by condition are:
## 
##   het_dlgn het_retina    het_scn    ko_dlgn  ko_retina     ko_scn    wt_dlgn  wt_retina     wt_scn 
##          7          7          7          5          6          5          9         11          4
## The number of samples by batch are:
## 
## p08 p15 p60 
##  26  32   3
mm38_hisat_v1
## An expressionSet containing experiment with 25760
## gene and 61 samples. There are 72 metadata columns and
## 15 annotation columns; the primary condition is comprised of:
## het_dlgn, het_retina, het_scn, ko_dlgn, ko_retina, ko_scn, wt_dlgn, wt_retina, wt_scn.
## Its current state is: raw(data).
mm38_hisat_v2 <- create_expt(iprgc_2022_meta[["new_meta"]], gene_info = mm_annot,
                             file_column = "hisat_count_table") %>%
  set_expt_conditions(fact = "genolocatb") %>%
  set_expt_batches(fact = "timeatb") %>%
  set_expt_colors(color_choices[["geno_loc"]])
## Reading the sample metadata.
## The sample definitions comprises: 69 rows(samples) and 72 columns(metadata fields).
## Warning in create_expt(iprgc_2022_meta[["new_meta"]], gene_info = mm_annot, : Some samples were removed when cross referencing the samples against
## the count data.
## Matched 25404 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 25425 features and 68 samples.
## The numbers of samples by condition are:
## 
##   het_dlgn het_retina    het_scn    ko_dlgn  ko_retina     ko_scn    wt_dlgn  wt_retina     wt_scn 
##          7          7          7          6          6          6         11         11          7
## The number of samples by batch are:
## 
## p08 p15 p60 
##  31  34   3
mm38_hisat_v2
## An expressionSet containing experiment with 25425
## gene and 68 samples. There are 72 metadata columns and
## 15 annotation columns; the primary condition is comprised of:
## het_dlgn, het_retina, het_scn, ko_dlgn, ko_retina, ko_scn, wt_dlgn, wt_retina, wt_scn.
## Its current state is: raw(data).
mm38_hisat_v3 <- create_expt(iprgc_2022_meta[["new_meta"]], gene_info = mm_annot,
                             file_column = "umi_dedup_output_count") %>%
  set_expt_conditions(fact = "genolocatb") %>%
  set_expt_batches(fact = "timeatb") %>%
  set_expt_colors(color_choices[["geno_loc"]])
## Reading the sample metadata.
## The sample definitions comprises: 69 rows(samples) and 72 columns(metadata fields).
## Warning in create_expt(iprgc_2022_meta[["new_meta"]], gene_info = mm_annot, : Some samples were removed when cross referencing the samples against
## the count data.
## Matched 25404 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 25425 features and 68 samples.
## The numbers of samples by condition are:
## 
##   het_dlgn het_retina    het_scn    ko_dlgn  ko_retina     ko_scn    wt_dlgn  wt_retina     wt_scn 
##          7          7          7          6          6          6         11         11          7
## The number of samples by batch are:
## 
## p08 p15 p60 
##  31  34   3
mm38_hisat_v3
## An expressionSet containing experiment with 25425
## gene and 68 samples. There are 72 metadata columns and
## 15 annotation columns; the primary condition is comprised of:
## het_dlgn, het_retina, het_scn, ko_dlgn, ko_retina, ko_scn, wt_dlgn, wt_retina, wt_scn.
## Its current state is: raw(data).
all_fact <- paste0(pData(mm38_hisat_v3)[["timeatb"]], "_",
                   pData(mm38_hisat_v3)[["genolocatb"]])
pData(mm38_hisat_v3)[["time_geno_loc"]] <- all_fact

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.

7 Non-zero Counts per Sample

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

plot_legend(mm38_hisat_v1)
## Warning in MASS::cov.trob(data[, vars]): Probable convergence failure

## Warning in MASS::cov.trob(data[, vars]): Probable convergence failure
## The colors used in the expressionset are: #9ECAE1, #F46D43, #2CA25F, #3182BD, #FDAE61, #006D2C, #DEEBF7, #D73027, #66C2A4.

v1_nonzero <- plot_nonzero(mm38_hisat_v1)
## The following samples have less than 16744 genes.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_65"  "iprgc_66"  "iprgc_67"  "iprgc_68"  "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73" 
## [12] "iprgc_74"  "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_79"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85" 
## [23] "iprgc_86"  "iprgc_88"  "iprgc_93"  "iprgc_95"  "iprgc_96"  "iprgc_98"  "iprgc_100" "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108"
## [34] "iprgc_111" "iprgc_117"
## 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.
v1_nonzero
## A non-zero genes plot of 61 samples.
## These samples have an average 15.13 CPM coverage and 16229 genes observed, ranging from 13031 to
## 17347.
## Warning: ggrepel: 27 unlabeled data points (too many overlaps). Consider increasing max.overlaps

v2_nonzero  <- plot_nonzero(mm38_hisat_v2)
## The following samples have less than 16526.25 genes.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68"  "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74" 
## [12] "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85"  "iprgc_86"  "iprgc_87" 
## [23] "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95"  "iprgc_96"  "iprgc_97"  "iprgc_98" 
## [34] "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113"
## [45] "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_121" "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127" "iprgc_128"
## [56] "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.
v2_nonzero
## A non-zero genes plot of 68 samples.
## These samples have an average 13.7 CPM coverage and 15744 genes observed, ranging from 13692 to
## 17083.
## Warning: ggrepel: 15 unlabeled data points (too many overlaps). Consider increasing max.overlaps

v3_nonzero  <- plot_nonzero(mm38_hisat_v3)
## The following samples have less than 16526.25 genes.
##  [1] "iprgc_62"  "iprgc_63"  "iprgc_64"  "iprgc_66"  "iprgc_67"  "iprgc_68"  "iprgc_70"  "iprgc_71"  "iprgc_72"  "iprgc_73"  "iprgc_74" 
## [12] "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85"  "iprgc_86"  "iprgc_87" 
## [23] "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95"  "iprgc_96"  "iprgc_97"  "iprgc_98" 
## [34] "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108" "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113"
## [45] "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_119" "iprgc_121" "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127"
## [56] "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.803 CPM coverage and 15787 genes observed, ranging from 13868 to
## 17101.
## Warning: ggrepel: 19 unlabeled data points (too many overlaps). Consider increasing max.overlaps

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.

mm38_hisat_v1 <- subset_expt(mm38_hisat_v1, subset = "timeatb!='p60'")
## The samples excluded are: iprgc_78, iprgc_79, iprgc_80.
## subset_expt(): There were 61, now there are 58 samples.
mm38_hisat_v2 <- subset_expt(mm38_hisat_v2, subset = "timeatb!='p60'")
## The samples excluded are: iprgc_78, iprgc_79, iprgc_80.
## subset_expt(): There were 68, now there are 65 samples.
mm38_hisat_v3 <- subset_expt(mm38_hisat_v3, subset = "timeatb!='p60'")
## The samples excluded are: iprgc_78, iprgc_79, iprgc_80.
## subset_expt(): There were 68, now there are 65 samples.

8 Quick PCA, then return to Theresa’s document

v1_norm <- normalize_expt(mm38_hisat_v1, transform = "log2", convert = "cpm",
                          norm = "quant", filter = TRUE)
## Removing 10970 low-count genes (14790 remaining).
## transform_counts: Found 3225 values equal to 0, adding 1 to the matrix.
v2_norm <- normalize_expt(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.
v3_norm <- normalize_expt(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.
plot_pca(v1_norm)
## 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.
## Warning in MASS::cov.trob(data[, vars]): Probable convergence failure

## Warning in MASS::cov.trob(data[, vars]): Probable convergence failure

plot_pca(v2_norm)
## 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.

plot_pca(v3_norm)
## 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.

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 steps including homogenization, antibody labeling, pulldown efficiency/specificity, sample handling during cleanup steps, 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_expt_conditions(mm38_hisat_v3, fact = "locationatb",
                                   colors = color_choices[["location"]]) %>%
  set_expt_batches(fact = "genotypeatb")
## 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

8.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_expt(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.
plot_pca(loc_geno_nq)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by dlgn, retina, scn
## Shapes are defined by het, ko, wt.

## 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_expt(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.
plot_pca(loc_geno_nt)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by dlgn, retina, scn
## Shapes are defined by het, ko, wt.
## Warning in MASS::cov.trob(data[, vars]): Probable convergence failure

## Warning in MASS::cov.trob(data[, vars]): 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("genotypeatb", "locationatb", "timeatb"))
sample_sankey
## A sankey plot describing the metadata of 65 samples,
## including 30 out of 0 nodes and traversing metadata factors:
## .

9 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 ‘projectah’ 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.

10 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 = pData(loc_geno_nt)[["genolocatb"]],
                         location = pData(loc_geno_nt)[["locationatb"]],
                         genotype = pData(loc_geno_nt)[["genotypeatb"]],
                         opn = exprs(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 median   p75   max     n std.error mean.conf.low mean.conf.high
##   <fct>    <chr>     <chr>           <int>    <dbl>  <dbl> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <int>     <dbl>         <dbl>          <dbl>
## 1 dlgn     numeric   opn                 0        1 0.0849 0.195     0  0      0     0    0.675    23    0.0407      0.000476          0.169
## 2 retina   numeric   opn                 0        1 2.82   2.10      0  1.59   2.14  4.68 6.57     23    0.439       1.91              3.73 
## 3 scn      numeric   opn                 0        1 0.0450 0.142     0  0      0     0    0.561    19    0.0326     -0.0234            0.113
ggbetweenstats(data = opn4_exprs, x = location, y = opn)
## Warning in min(x): no non-missing arguments to min; returning Inf
## Warning in max(x): no non-missing arguments to max; returning -Inf

ggbetweenstats(data = opn4_exprs, x = genotype, y = opn)
## Warning in min(x): no non-missing arguments to min; returning Inf

## Warning in min(x): no non-missing arguments to max; returning -Inf

ggbetweenstats(data = opn4_exprs, x = combined, y = opn)
## Number of labels is greater than default palette color count.
## • Select another color `palette` (and/or `package`).
## Warning in min(x): no non-missing arguments to min; returning Inf

## Warning in min(x): no non-missing arguments to max; returning -Inf

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!

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

plot_libsize(mm38_hisat_v3)
## Library sizes of 65 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.

test <- pData(mm38_hisat_v3)[, c("hisatgenomesingleall", "umideduppctreads")]
test_plot <- plot_linear_scatter(test)
test_plot[["scatter"]]

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

plot_density(mm38_hisat_v3)
## Changed 627293 zero count features.
## Density plot describing 65 samples.

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

12 PCA plots

12.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_expt_conditions(mm38_hisat_v3, fact = "locationatb") %>%
  set_expt_batches(fact = "genotypeatb")
## 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
v3_location_norm <- normalize_expt(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.
plot_pca(v3_location_norm)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by dlgn, retina, scn
## Shapes are defined by het, ko, wt.

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_expt(mm38_hisat_v3, subset="sampleid!='iprgc_130'") %>%
  subset_expt(subset="sampleid!='iprgc_66'")
## The samples excluded are: iprgc_130.
## subset_expt(): There were 65, now there are 64 samples.
## The samples excluded are: iprgc_66.
## subset_expt(): There were 64, now there are 63 samples.
v3_location <- set_expt_conditions(mm38_hisat_v3, fact = "locationatb") %>%
  set_expt_batches(fact = "genotypeatb")
## The numbers of samples by condition are:
## 
##   dlgn retina    scn 
##     23     23     17
## The number of samples by batch are:
## 
## het  ko  wt 
##  20  18  25
v3_location_norm <- normalize_expt(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.
plot_pca(v3_location_norm)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by dlgn, retina, scn
## Shapes are defined by het, ko, wt.

removed_sankey <- plot_meta_sankey(v3_location, color_choices = color_choices,
                                   factors = c("genotypeatb", "locationatb", "timeatb"))
removed_sankey
## A sankey plot describing the metadata of 63 samples,
## including 30 out of 0 nodes and traversing metadata factors:
## .

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.

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

13.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_expt(mm38_hisat_v3, subset = "timeatb=='p08' & locationatb=='retina'")
## The samples excluded are: iprgc_62, iprgc_63, iprgc_64, iprgc_65, iprgc_67, iprgc_68, iprgc_69, iprgc_70, iprgc_71, iprgc_72, iprgc_73, iprgc_74, iprgc_75, iprgc_76, iprgc_77, iprgc_81, iprgc_82, iprgc_85, iprgc_87, iprgc_88, iprgc_89, iprgc_92, iprgc_93, iprgc_94, iprgc_95, iprgc_96, iprgc_97, iprgc_98, iprgc_99, iprgc_100, iprgc_101, iprgc_102, iprgc_104, iprgc_105, iprgc_106, iprgc_107, iprgc_108, iprgc_110, iprgc_111, iprgc_112, iprgc_113, iprgc_114, iprgc_116, iprgc_119, iprgc_122, iprgc_123, iprgc_124, iprgc_125, iprgc_126, iprgc_127, iprgc_128, iprgc_129.
## subset_expt(): There were 63, now there are 11 samples.
mm_normal_p8_ret_de <- all_pairwise(mm38_p8_retina, model_batch = "svaseq", filter = TRUE)
## 
## het_retina  ko_retina  wt_retina 
##          3          3          5
## Removing 0 low-count genes (13424 remaining).
## Setting 46 low elements to zero.
## transform_counts: Found 46 values equal to 0, adding 1 to the matrix.

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

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("hetretina", "wtretina"))
het_wt_table <- combine_de_tables(mm_normal_p8_ret_de, keepers = wt_het_keeper,
                                  label_column = label_column,
                                  excel = "excel/het_retina_control.xlsx")
## Deleting the file excel/het_retina_control.xlsx before writing the tables.
wanted_sig <- extract_significant_genes(het_wt_table,
                                        lfc = 0.25,
                                        according_to = "deseq")

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$wtretina_vs_hetretina %>%
  filter(logFC <= -0.25 & adj.P.Val <= 0.05)

kokeeper_genes <- mm_de_normal_p8_ret$deseq$all_tables$wtretina_vs_koretina %>%
  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.

13.2 Prove I understood

hetkeeper_genes <- mm_normal_p8_ret_de$deseq$all_tables$wtretina_vs_hetretina %>%
  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("koretina", "wtretina"))
ko_wt_table <- combine_de_tables(mm_normal_p8_ret_de, keepers = wt_ko_keeper,
                                 label_column = label_column,
                                 excel = "excel/ko_retina_control.xlsx")
## Deleting the file excel/ko_retina_control.xlsx before writing the tables.
wanted_sig <- extract_significant_genes(ko_wt_table,
                                        lfc = 0.25,
                                        according_to = "deseq")
wanted_ko_increased <- wanted_sig[["deseq"]][["ups"]][["ko_vs_wt"]]
increased_ko_genes <- rownames(wanted_ko_increased)

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_gene_name’ 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 | limma_tbl$adj.P.Val > .05, "Significance"] <- "Not \nEnriched"
    limma_tbl[limma_tbl$logFC >= 1  & limma_tbl$adj.P.Val <= .05, ][["Significance"]] <- "Disease \nUpregulated"
    limma_tbl[limma_tbl$logFC <= -1  & limma_tbl$adj.P.Val <= .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 | limma_tbl$adj.P.Val > .05, "Significance"] <- "Not \nEnriched"
    if(nrow(limma_tbl[limma_tbl$logFC >= 1  & limma_tbl$adj.P.Val <= .05, ]) != 0) {
      limma_tbl[limma_tbl$logFC >= 1  & limma_tbl$adj.P.Val <= .05, ][["Significance"]] <- factors[1]
    }
    if (nrow(limma_tbl[limma_tbl$logFC <= -1  & limma_tbl$adj.P.Val <= .05, ]) != 0) {
      limma_tbl[limma_tbl$logFC <= -1  & limma_tbl$adj.P.Val <= .05, ][["Significance"]] <- factors[2]
    }
    limma_tbl$Significance <- factor(limma_tbl$Significance, levels = c(factors,  "Not \nEnriched"))
  }
  return(limma_tbl)
}

13.2.1 Combining het/wt and ko/wt

mm_annot[["external_gene_name"]] <- mm_annot[["mgi_symbol"]]
keepergenes <- unique(c(rownames(hetkeeper_genes), rownames(kokeeper_genes)))
length(keepergenes)
## [1] 3632
annots_to_merge <- mm_annot %>%
  select(ensembl_gene_id, external_gene_name) %>%
  filter(ensembl_gene_id %in% rownames(mm_de_normal_p8_ret$deseq$all_tables$koretina_vs_hetretina)) %>%
  distinct()

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

df <- mm_de_normal_p8_ret$deseq$all_tables$koretina_vs_hetretina %>%
  dplyr::mutate(logFC = -logFC) %>%
  set_sig_limma(factors = c("Het Enriched", "KO Enriched"))

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
exclude_increased_genes <- all_genes[exclude_idx]
retina_keepers <- list(
  "het_vs_wt" = c("hetretina", "wtretina"),
  "ko_vs_wt" = c("koretina", "wtretina"),
  "ko_vs_het" = c("koretina", "hetretina"))

## 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("excel/p8_retina_kept_genes_increased_in_wt_tables-v{ver}.xlsx"))
p8_retina_sig <- extract_significant_genes(
  p8_retina_tables,
  excel = glue("excel/p8_retina_kept_genes_increased_in_wt_sig-v{ver}.xlsx"),
  according_to = "deseq")

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("excel/p8_retina_removed_genes_increased_in_wt_tables-v{ver}.xlsx"))
opposite_p8_retina_sig <- extract_significant_genes(
  p8_retina_tables,
  excel = glue("excel/p8_retina_removed_genes_increased_in_wt_sig-v{ver}.xlsx"),
  according_to = "deseq")

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

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

labels_ups <- df %>%
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1) %>%
  arrange(logFC) %>%
  head(n = 9)

labels_downs <- df %>%
  filter(adj.P.Val <= 0.05 & abs(logFC) > 1) %>%
  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 = external_gene_name)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1,1)) +
  geom_hline(yintercept = -log10(.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")) +
  geom_label_repel(
    data = filter(df,
                  ## c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
                  external_gene_name %in% labels$external_gene_name),
    ## nudge_x = -0.5,
    nudge_y = 3, max.overlaps = 15) +
  xlim(c(-3, 6))

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/p08_retina_DE_1312024.eps")
## Error in postscript(file = "axonTRAP_Volcanoplots_20240202/p08_retina_DE_1312024.eps"): cannot open file 'axonTRAP_Volcanoplots_20240202/p08_retina_DE_1312024.eps'
DEplot
## Warning: Removed 2 rows containing missing values or values outside the scale range (`geom_point()`).
## Warning: Removed 2 rows containing missing values or values outside the scale range (`geom_label_repel()`).

dev.off()
## null device 
##           1
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_label_repel()`).
writexl::write_xlsx(df, path = "axonTRAP_DE_results_20240202/retinahet_vs_retinako_WTfiltered.xlsx")
## Error: Error in libxlsxwriter: 'Error creating output xlsx file. Usually a permissions error.'

14.1 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

14.2 category enrichment/GSEA

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

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

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

gsea_result_alldysregulated <- gost(query = alldysregulated_genes$external_gene_name,
                                    organism = "mmusculus",
                                    evcodes = TRUE,
                                    ordered_query = TRUE)

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"))
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Error in plot.window(...) : need finite 'ylim' values
## Add a little logic here to use enrichplot::dotplot().
het_gp
## 
## Category REAC is the most populated with 21 hits.

enrichplot::dotplot(het_gp[["GO_enrich"]])

gp_pair <- enrichplot::pairwise_termsim(het_gp[["GO_enrich"]])
enrichplot::emapplot(gp_pair)

enrichplot::ssplot(gp_pair)
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'layout.params = list(coords = your_value)' instead of 'coords'.
##  The coords parameter will be removed in the next version.
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'edge.params = list(show = your_value)' instead of 'with_edge'.
##  The with_edge parameter will be removed in the next version.
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'cluster.params = list(cluster = your_value)' instead of 'group_category'.
##  The group_category parameter will be removed in the next version.

enrichplot::treeplot(gp_pair)
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.

upsetplot(het_gp[["GO_enrich"]])

enrichplot::dotplot(het_gp[["REAC_enrich"]])

gp_pair <- enrichplot::pairwise_termsim(het_gp[["REAC_enrich"]])
enrichplot::emapplot(gp_pair)

enrichplot::ssplot(gp_pair)
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'layout.params = list(coords = your_value)' instead of 'coords'.
##  The coords parameter will be removed in the next version.
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'edge.params = list(show = your_value)' instead of 'with_edge'.
##  The with_edge parameter will be removed in the next version.
## Warning in emapplot.enrichResult(x, showCategory = showCategory, ...): Use 'cluster.params = list(cluster = your_value)' instead of 'group_category'.
##  The group_category parameter will be removed in the next version.

enrichplot::treeplot(gp_pair)
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.
## ! # Invaild edge matrix for <phylo>. A <tbl_df> is returned.

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")
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Reading KEGG annotation online: "https://rest.kegg.jp/link/mmu/pathway"...
## Reading KEGG annotation online: "https://rest.kegg.jp/list/pathway/mmu"...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## --> No gene can be mapped....
## --> Expected input gene ID: 74551,22235,110119,13806,433182,11677
## --> return NULL...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## No gene sets have size between 5 and 500 ...
## --> return NULL...
## No gene sets have size between 5 and 500 ...
## --> return NULL...
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

enrichplot::dotplot(p08_retina_all_cp[["ko_vs_het_up"]][["enrich_objects"]][["MF_all"]])

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 = "images/gsea_p08_retina_ko_vs_het_top_hit.png")
p08_topn_gsea[["GO_ko_vs_het_up"]][[1]]
dev.off()
## png 
##   2
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]]

#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"]] %>%
  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("GSEA 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("GSEA Score")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_p08_axontrap_retinahet_upregulated_vs_retinako.eps")
## Error in postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_p08_axontrap_retinahet_upregulated_vs_retinako.eps"): cannot open file 'axonTRAP_Volcanoplots_20240202/GSEA_p08_axontrap_retinahet_upregulated_vs_retinako.eps'
gsea_plots_het

dev.off()
## null device 
##           1
setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_p08_retina_axontrap_alldysregulatedgenes.eps")
## Error in postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_p08_retina_axontrap_alldysregulatedgenes.eps"): cannot open file 'axonTRAP_Volcanoplots_20240202/GSEA_p08_retina_axontrap_alldysregulatedgenes.eps'
gsea_plots_all
dev.off()
## null device 
##           1

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

15.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_expt(
  mm38_hisat,
  subset = "(batch == '4' | batch == '5' | batch == '6') & time == 'p08' & location == 'scn' | sampleid == 'iprgc_03'")

mm38_norm <- normalize_expt(mm38_subset, filter = TRUE, convert = "cpm",
                            transform = "log2", batch = "svaseq")

mm38_norm <- set_expt_batches(mm38_norm, fact = "location")
mm38_norm <- set_expt_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_expt(mm38_hisat_v3,
                           subset = "locationatb == 'scn'") %>%
  set_expt_batches(fact = "locationatb") %>%
  set_expt_conditions(fact = "genotypeatb")
## The samples excluded are: iprgc_62, iprgc_63, iprgc_64, iprgc_65, iprgc_68, iprgc_69, iprgc_71, iprgc_72, iprgc_73, iprgc_74, iprgc_75, iprgc_76, iprgc_81, iprgc_82, iprgc_83, iprgc_84, iprgc_86, iprgc_87, iprgc_88, iprgc_90, iprgc_91, iprgc_92, iprgc_94, iprgc_96, iprgc_98, iprgc_99, iprgc_100, iprgc_101, iprgc_104, iprgc_105, iprgc_106, iprgc_107, iprgc_108, iprgc_109, iprgc_115, iprgc_116, iprgc_117, iprgc_118, iprgc_119, iprgc_120, iprgc_121, iprgc_122, iprgc_123, iprgc_125, iprgc_126, iprgc_127.
## subset_expt(): There were 63, now there are 17 samples.
## 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_expt(scn_samples, filter = TRUE, convert = "cpm",
                           transform = "log2", batch = "svaseq")
## Removing 11109 low-count genes (14316 remaining).
## Setting 919 low elements to zero.
## transform_counts: Found 919 values equal to 0, adding 1 to the matrix.
scn_norm_pca <- plot_pca(scn_norm)
scn_norm_pc
## Error in eval(expr, envir, enclos): object 'scn_norm_pc' not found

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

16.1 DE

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_gene_name) %>%
  filter(ensembl_gene_id %in% rownames(mm_de_normal_p8_scn$deseq$all_tables$koscn_vs_hetscn)) %>%
  distinct()

mm_de_normal_p8_scn$deseq$all_tables$koscn_vs_hetscn <- merge(
  mm_de_normal_p8_scn$deseq$all_tables$koscn_vs_hetscn,
  annots_to_merge, by.x = 0, by.y = "ensembl_gene_id", all.x = TRUE)
hetkeeper_genes <- mm_de_normal_p8_scn$deseq$all_tables$wtscn_vs_hetscn %>%
  filter(logFC <= -.1 & adj.P.Val <= 0.05)

kokeeper_genes <- mm_de_normal_p8_scn$deseq$all_tables$wtscn_vs_koscn %>%
  filter(logFC <= -.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_gene_name)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1,1)) +
  geom_hline(yintercept = -log10(.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_gene_name %in% labels$external_gene_name),
                   ## nudge_x = -0.5,
                   nudge_y = 3, max.overlaps = 15) +
  ggtitle("SCN Het vs KO Translatome")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/p08_scn_DE_1312024.eps")
DEplot
dev.off()

writexl::write_xlsx(df, path = "axonTRAP_DE_results_20240202/scnhet_vs_scnko_WTfiltered.xlsx")

16.2 How many ups/downs

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

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

16.3 GSEA

ko_genes <- res_tbl %>%
  filter(adj.P.Val <= 0.05) %>%
  arrange(-abs(logFC)) %>%
  select(Row.names, logFC, adj.P.Val, external_gene_name, 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_gene_name, Significance) %>%
  filter(logFC >= 1)

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

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

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

gsea_result_alldysregulated <- gost(query = alldysregulated_genes$external_gene_name,
                                    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("GSEA 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("GSEA 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("GSEA Score")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_p08_retina_axontrap_alldysregulatedgenes.eps")
gsea_plots_all
dev.off()

17 Het Retina vs Het SCN

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

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

17.1 PCA

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

17.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$wtretina_vs_hetretina %>%
  filter(logFC <= -.1 & adj.P.Val <= 0.05)

scnkeeper_genes <- mm_de_subset2$deseq$all_tables$wtscn_vs_hetscn %>%
  filter(logFC <= -.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_gene_name) %>%
  filter(ensembl_gene_id %in% rownames(mm_de_subset2$deseq$all_tables$hetscn_vs_hetretina)) %>%
  distinct()

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

df <- mm_de_subset2$deseq$all_tables$hetscn_vs_hetretina %>%
  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_gene_name, 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) %>%
  arrange(logFC)  %>%
  select(Row.names, external_gene_name, logFC, adj.P.Val) %>%
  mutate(Significance = "Retina Enriched") %>%
  filter(Row.names %in% rownames(retinakeeper_genes))

notenriched <- df %>%
  select(Row.names, external_gene_name, 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) %>%
  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)

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_gene_name)) +
  geom_point(aes(colour = Significance), size = 4) +
  geom_vline(xintercept = c(-1,1)) +
  geom_hline(yintercept = -log10(.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_gene_name %in% labels_requested),
                   ## c(labels$external_gene_name, "Opn4")), #c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
                   ## nudge_x = -0.5,
                   nudge_y = 15, max.overlaps = 25)

#setEPS()
#postscript(file = "axonTRAP_Volcanoplots_20240202/p08_retinavsscnhet_DE_requested_genelabels_02052024.eps")
DEplot
#dev.off()

17.3 How many ups/downs

scn_enriched <- df %>%
  filter(adj.P.Val <= 0.05 & logFC >= 1) %>%
  arrange(-logFC) %>%
  select(Row.names, external_gene_name, logFC, adj.P.Val, Significance)

retina_enriched <- df %>%
  filter(adj.P.Val <= 0.05 & logFC <= -1) %>%
  arrange(logFC)  %>%
  select(Row.names, external_gene_name, logFC, adj.P.Val, Significance)

scn_enriched
retina_enriched

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

17.4 GSEA

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

gsea_result_ret <- gost(query = retina_enriched$external_gene_name,
                        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")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_SCNhet_vs_retina_enriched_P08.eps")
gsea_plots_scn
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")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_Retinahet_vs_SCN_enriched_P08.eps")
gsea_plots_ret
dev.off()

18 KO Retina vs KO SCN

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

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

18.1 PCA

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

18.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 & adj.P.Val <= 0.05)

scnkeeper_genes <- mm_de_subset3$deseq$all_tables$wtscn_vs_koscn %>%
  filter(logFC <= -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_gene_name) %>%
  filter(ensembl_gene_id %in% rownames(mm_de_subset3$deseq$all_tables$koscn_vs_koretina)) %>%
  distinct()

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

df <- mm_de_subset3$deseq$all_tables$koscn_vs_koretina %>%
  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_gene_name, 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_gene_name, logFC, adj.P.Val) %>%
  mutate(Significance = "Retina Enriched") %>%
  filter(Row.names %in% rownames(retinakeeper_genes)) -> retina_enriched

notenriched <- df %>%
  select(Row.names, external_gene_name, 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_gene_name)) +
  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_gene_name %in% c(labels$external_gene_name, "Opn4")),
    ## c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
    ## nudge_x = -0.5,
    nudge_y = 10, max.overlaps = 25)

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/p08_retinavsscnko_DE_1312024.eps")
DEplot
dev.off()

18.3 How many ups/downs

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

18.4 GSEA

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

gsea_result_ret <- gost(query = retina_enriched$external_gene_name,
                        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")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_SCNko_enriched_vs_retina_P08.eps")
gsea_plots_scn
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")

setEPS()
postscript(file = "axonTRAP_Volcanoplots_20240202/GSEA_Retinako_enriched_vs_SCN_P08.eps")
gsea_plots_ret
dev.off()

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

19.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_expt_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     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn 
##              3              3              3              3              3              3              5              5              3 
##   p15_het_dlgn p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              4              4              3              3              3              3              5              5              2

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

19.2.1 Exclusion 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.

inclusions <- list(
  ## I like alphabetizing things, start with dlgn
  "p15_het_dlgn" = c("p15hetdlgn", "p15wtdlgn"),
  "p08_het_dlgn" = c("p08hetdlgn", "p08wtdlgn"),
  "p15_ko_dlgn" = c("p15kodlgn", "p15wtdlgn"),
  "p08_ko_dlgn" = c("p08kodlgn", "p08wtdlgn"),
  ## Then retinas
  "p15_het_retina" = c("p15hetretina", "p15wtretina"),
  "p08_het_retina" = c("p08hetretina", "p08wtretina"),
  "p15_ko_retina" = c("p15koretina", "p15wtretina"),
  "p08_ko_retina" = c("p08koretina", "p08wtretina"),
  ## Then scn
  "p15_het_scn" = c("p15hetscn", "p15wtscn"),
  "p08_het_scn" = c("p08hetscn", "p08wtscn"),
  "p15_ko_scn" = c("p15koscn", "p15wtscn"),
  "p08_ko_scn" = c("p08koscn", "p08wtscn"))

19.2.2 Time contrasts

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

time_keepers <- list(
  ## DLGN
  "t_het_dlgn" = c("p15hetdlgn", "p08hetdlgn"),
  "t_ko_dlgn" = c("p15kodlgn", "p08kodlgn"),
  ## Retina
  "t_het_retina" = c("p15hetretina", "p08hetretina"),
  "t_ko_retina" = c("p15koretina", "p08koretina"),
  ## SCN
  "t_het_scn" = c("p15hetscn", "p08hetscn"),
  "t_ko_scn" = c("p15koscn", "p08koscn"))

19.2.3 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("p08hetdlgn", "p08hetretina"),
  "dr_p15_het" = c("p15hetdlgn", "p15hetretina"),
  "dr_p08_ko" = c("p08kodlgn", "p08koretina"),
  "dr_p15_ko" = c("p15kodlgn", "p15koretina"),
  ## scn/retina
  "sr_p08_het" = c("p08hetscn", "p08hetretina"),
  "sr_p15_het" = c("p15hetscn", "p15hetretina"),
  "sr_p08_ko" = c("p08koscn", "p08koretina"),
  "sr_p15_ko" = c("p15koscn", "p15koretina"),
  ## dlgn/scn
  "ds_p08_het" = c("p08hetdlgn", "p08hetscn"),
  "ds_p15_het" = c("p15hetdlgn", "p15hetscn"),
  "ds_p08_ko" = c("p08kodlgn", "p08koscn"),
  "ds_p15_ko" = c("p15kodlgn", "p15koscn"))

19.2.4 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("p08kodlgn", "p08hetdlgn"),
  "kh_p15_dlgn" = c("p15kodlgn", "p15hetdlgn"),
  ## Retina
  "kh_p08_retina" = c("p08koretina", "p08hetretina"),
  "kh_p15_retina" = c("p15koretina", "p15hetretina"),
  ## SCN
  "kh_p08_scn" = c("p08koscn", "p08hetscn"),
  "kh_p15_scn" = c("p15koscn", "p15hetscn"))

19.3 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:

lfc_cutoff <- 0.1
adjp_cutoff <- 0.1
inclusion_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                             keepers = inclusions, model_batch = "svaseq")
## 
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn 
##              3              3              3              3              3              3              5              5              3 
##   p15_het_dlgn p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              4              4              3              3              3              3              5              5              2
## Removing 0 low-count genes (15263 remaining).
## Setting 9594 low elements to zero.
## transform_counts: Found 9594 values equal to 0, adding 1 to the matrix.
inclusion_de
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 10 comparisons.
inclusion_tables <- combine_de_tables(
  inclusion_de, keepers = inclusions, label_column = label_column,
  excel = glue("wt_comparisons/inclusion_tables-v{ver}.xlsx"))
inclusion_tables
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1      p15hetdlgn_vs_p15wtdlgn         509          1028         574          1095         622           516
## 2      p08hetdlgn_vs_p08wtdlgn          41            54          90            60          53            27
## 3       p15kodlgn_vs_p15wtdlgn         810          1370         946          1362         837           803
## 4       p08kodlgn_vs_p08wtdlgn         382           523         426           561         485           385
## 5  p15hetretina_vs_p15wtretina         305            58         327            79         350            52
## 6  p08hetretina_vs_p08wtretina         852           615         870           712         862           605
## 7   p15koretina_vs_p15wtretina         111            28         136            34          42            17
## 8   p08koretina_vs_p08wtretina         711           221         733           291         721           284
## 9        p15hetscn_vs_p15wtscn           4             6           4             8           0             0
## 10       p08hetscn_vs_p08wtscn          61            23          54            25           0             0
## 11        p15koscn_vs_p15wtscn           1             3           1             8           2             0
## 12        p08koscn_vs_p08wtscn           2             1           3             1           4             1
## Plot describing unique/shared genes in a differential expression table.

inclusion_sig <- extract_significant_genes(
  inclusion_tables, lfc = lfc_cutoff, p = adjp_cutoff,
  according_to = "deseq",
  excel = glue("wt_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       2191       2645
## p08_het_dlgn        369        388
## p15_ko_dlgn        2623       3073
## p08_ko_dlgn        1397       1462
## p15_het_retina      948        371
## p08_het_retina     2284       2094
## p15_ko_retina       262         68
## p08_ko_retina      1728       1047
## p15_het_scn           7          6
## p08_het_scn         311        138
## p15_ko_scn            1          3
## p08_ko_scn            3          1

19.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)
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) {
  all_written <- list()
  for (g in seq_len(length(all_cp))) {
    name <- names(all_cp)[g]
    datum <- all_cp[[name]]
    filename <- glue("cprofiler/{ver}/{name}_cprofiler-v{ver}.xlsx")
    written <- sm(write_cp_data(datum, excel = filename))
    all_written[[g]] <- written
  }
  return(all_written)
}

write_all_gp <- function(all_gp) {
  all_written <- list()
  for (g in seq_len(length(all_gp))) {
    name <- names(all_gp)[g]
    datum <- all_gp[[name]]
    filename <- glue("gprofiler/{ver}/{name}_gprofiler-v{ver}.xlsx")
    written <- sm(write_gprofiler_data(datum, excel = filename))
    all_written[[g]] <- written
  }
  return(all_written)
}

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.
    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("included_genes/{include_name}-v{ver}.xlsx"))
    retlist[[include_name]] <- include_genes
    retlist[[contrast]] <- include_genes
  }
  return(retlist)
}

19.3.2 Extract genes excluded 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(exprs(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 2191.
## The set of unique genes higher in p08_het_dlgn vs. wt is 369.
## The unique union of them is 2241 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2623.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 1397.
## The unique union of them is 3318 genes.
## The set of unique genes higher in p15_het_retina vs. wt is 948.
## The set of unique genes higher in p08_het_retina vs. wt is 2284.
## The unique union of them is 2443 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 262.
## The set of unique genes higher in p08_ko_retina vs. wt is 1728.
## The unique union of them is 1810 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 7.
## The set of unique genes higher in p08_het_scn vs. wt is 311.
## The unique union of them is 316 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 1.
## The set of unique genes higher in p08_ko_scn vs. wt is 3.
## The unique union of them is 4 genes.
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 369.
## The set of unique genes higher in p08_het_retina vs. wt is 2284.
## The unique union of them is 2493 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2191.
## The set of unique genes higher in p15_het_retina vs. wt is 948.
## The unique union of them is 2787 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 1397.
## The set of unique genes higher in p08_ko_retina vs. wt is 1728.
## The unique union of them is 2749 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2623.
## The set of unique genes higher in p15_ko_retina vs. wt is 262.
## The unique union of them is 2809 genes.
## The set of unique genes higher in p08_het_scn vs. wt is 311.
## The set of unique genes higher in p08_het_retina vs. wt is 2284.
## The unique union of them is 2546 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 7.
## The set of unique genes higher in p15_het_retina vs. wt is 948.
## The unique union of them is 955 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 3.
## The set of unique genes higher in p08_ko_retina vs. wt is 1728.
## The unique union of them is 1731 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 1.
## The set of unique genes higher in p15_ko_retina vs. wt is 262.
## The unique union of them is 263 genes.
## The set of unique genes higher in p08_het_dlgn vs. wt is 369.
## The set of unique genes higher in p08_het_scn vs. wt is 311.
## The unique union of them is 671 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2191.
## The set of unique genes higher in p15_het_scn vs. wt is 7.
## The unique union of them is 2197 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 1397.
## The set of unique genes higher in p08_ko_scn vs. wt is 3.
## The unique union of them is 1399 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2623.
## The set of unique genes higher in p15_ko_scn vs. wt is 1.
## The unique union of them is 2624 genes.
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 1397.
## The set of unique genes higher in p08_het_dlgn vs. wt is 369.
## The unique union of them is 1475 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 2623.
## The set of unique genes higher in p15_het_dlgn vs. wt is 2191.
## The unique union of them is 2906 genes.
## The set of unique genes higher in p08_ko_retina vs. wt is 1728.
## The set of unique genes higher in p08_het_retina vs. wt is 2284.
## The unique union of them is 2653 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 262.
## The set of unique genes higher in p15_het_retina vs. wt is 948.
## The unique union of them is 1030 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 3.
## The set of unique genes higher in p08_het_scn vs. wt is 311.
## The unique union of them is 314 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 1.
## The set of unique genes higher in p15_het_scn vs. wt is 7.
## The unique union of them is 8 genes.

19.4 Perform the DE analyses and exclude the target genes

genotype_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                            keepers = genotype_keepers, model_batch = "svaseq")
## 
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn 
##              3              3              3              3              3              3              5              5              3 
##   p15_het_dlgn p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              4              4              3              3              3              3              5              5              2
## Removing 0 low-count genes (15263 remaining).
## Setting 9594 low elements to zero.
## transform_counts: Found 9594 values equal to 0, adding 1 to the matrix.

genotype_de
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 10 comparisons.
location_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                            keepers = location_keepers, model_batch = "svaseq")
## 
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn 
##              3              3              3              3              3              3              5              5              3 
##   p15_het_dlgn p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              4              4              3              3              3              3              5              5              2
## Removing 0 low-count genes (15263 remaining).
## Setting 9594 low elements to zero.
## transform_counts: Found 9594 values equal to 0, adding 1 to the matrix.

location_de
## A pairwise differential expression with results from: basic, deseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 10 comparisons.
time_de <- all_pairwise(v3_pairwise_input, filter = TRUE,
                        keepers = time_keepers, model_batch = "svaseq")
## 
##   p08_het_dlgn p08_het_retina    p08_het_scn    p08_ko_dlgn  p08_ko_retina     p08_ko_scn    p08_wt_dlgn  p08_wt_retina     p08_wt_scn 
##              3              3              3              3              3              3              5              5              3 
##   p15_het_dlgn p15_het_retina    p15_het_scn    p15_ko_dlgn  p15_ko_retina     p15_ko_scn    p15_wt_dlgn  p15_wt_retina     p15_wt_scn 
##              4              4              3              3              3              3              5              5              2
## Removing 0 low-count genes (15263 remaining).
## Setting 9594 low elements to zero.
## transform_counts: Found 9594 values equal to 0, adding 1 to the matrix.

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

19.5 Extract the relevant tables and include genes lower in wt

19.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.
genotype_tables_full <- combine_de_tables(
  genotype_de, keepers = genotype_keepers, label_column = label_column,
  excel = glue("full_contrasts/genotype_full_tables-v{ver}.xlsx"))
genotype_tables_full
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1     p08kodlgn_vs_p08hetdlgn          34             1          43             2          41             1
## 2     p15kodlgn_vs_p15hetdlgn          49             2          85             2           0             0
## 3 p08koretina_vs_p08hetretina           6             2           4             2           3             1
## 4 p15koretina_vs_p15hetretina           6             4           8             4           0             3
## 5       p08koscn_vs_p08hetscn          51           128          82           136          31            22
## 6       p15koscn_vs_p15hetscn           0            12           0            25           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("full_contrasts/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         34          1
## kh_p15_dlgn         49          2
## kh_p08_retina        6          2
## kh_p15_retina        6          4
## kh_p08_scn          51        128
## kh_p15_scn           0         12

genotype_tables <- list()
genotype_sig <- list()
genotype_gp <- list()
genotype_cp <- 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("genotype_contrasts/genotype_{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("genotype_contrasts/genotype_{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"]][["ups"]][[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")
    gp_written <- write_all_gp(genotype_gp[[name]])
    genotype_cp[[name]] <- all_cprofiler(genotype_sig[[name]], genotype_tables[[name]],
                                         orgdb = "org.Mm.eg.db")
    cp_written <- write_all_cp(genotype_cp[[name]])
  }
}
## Examining kh_p08_dlgn
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08kodlgn_vs_p08hetdlgn          34             1          37             0          31             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       34          1
## There are 68 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## There are only, 1 returning null.
## preparing geneSet collections...
## GSEA analysis...
## no term enriched under specific pvalueCutoff...

## preparing geneSet collections...
## GSEA analysis...
## no term enriched under specific pvalueCutoff...
## --> No gene can be mapped....
## --> Expected input gene ID: 56451,226413,666168,16770,50790,270076
## --> return NULL...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining kh_p15_dlgn
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15kodlgn_vs_p15hetdlgn          43             0          76             0           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       43          0
## There are 86 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining kh_p08_retina
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08koretina_vs_p08hetretina           3             1           3             1           3             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 6 significant up and down genes.
## Examining kh_p15_retina
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15koretina_vs_p15hetretina           5             4           6             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        5          4
## There are 10 significant up and down genes.
## Examining kh_p08_scn
## A set of combined differential expression results.
##                   table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08koscn_vs_p08hetscn           3            68           3            67           1            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
## kh_p08_scn        3         68
## There are 6 significant up and down genes.
## Examining kh_p15_scn
## A set of combined differential expression results.
##                   table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15koscn_vs_p15hetscn           0             5           0             5           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 0 significant up and down genes.

19.5.2 Location contrasts with genes removed/kept

Repeat the same block with a find/replace of genotype/location.

location_tables_full <- combine_de_tables(
  location_de, keepers = location_keepers, label_column = label_column,
  excel = glue("full_contrasts/location_full_tables-v{ver}.xlsx"))
location_tables_full
## A set of combined differential expression results.
##                         table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1  p08hetdlgn_vs_p08hetretina        2174          1563        2232          1639        1895          1646
## 2  p15hetdlgn_vs_p15hetretina        2429          3362        2584          3348        2738          2634
## 3    p08kodlgn_vs_p08koretina        2198          1864        2163          2089        2131          1961
## 4    p15kodlgn_vs_p15koretina        2711          3941        2930          3852        3243          2974
## 5   p08hetscn_vs_p08hetretina        2630          1701        2593          1892        2225          1894
## 6   p15hetscn_vs_p15hetretina        2846          2381        2724          2617        2729          2360
## 7     p08koscn_vs_p08koretina        2733          1716        2674          1937        2412          2174
## 8     p15koscn_vs_p15koretina        2620          3023        2613          3159        2827          2646
## 9     p08hetdlgn_vs_p08hetscn         646           785         760           783         645           759
## 10    p15hetdlgn_vs_p15hetscn        1698          2769        1985          2620        1965          2014
## 11      p08kodlgn_vs_p08koscn         986          1312        1104          1411        1162          1277
## 12      p15kodlgn_vs_p15koscn        1841          2529        2161          2413        1892          2006
## Plot describing unique/shared genes in a differential expression table.

location_sig_full <- extract_significant_genes(
  location_tables_full, according_to = "deseq",
  excel = glue("full_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     2174       1563
## dr_p15_het     2429       3362
## dr_p08_ko      2198       1864
## dr_p15_ko      2711       3941
## sr_p08_het     2630       1701
## sr_p15_het     2846       2381
## sr_p08_ko      2733       1716
## sr_p15_ko      2620       3023
## ds_p08_het      646        785
## ds_p15_het     1698       2769
## ds_p08_ko       986       1312
## ds_p15_ko      1841       2529

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("location_contrasts/location_{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("location_contrasts/location_{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"]][["ups"]][[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")
    gp_written <- write_all_gp(genotype_gp[[name]])
    location_cp[[name]] <- all_cprofiler(location_sig[[name]], location_tables[[name]],
                                         orgdb = "org.Mm.eg.db")
    cp_written <- write_all_cp(genotype_cp[[name]])
  }
}
## Examining dr_p08_het
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08hetdlgn_vs_p08hetretina         463           178         466           180         420           188
## `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      463        178
## There are 926 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining dr_p15_het
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetdlgn_vs_p15hetretina         992           137        1051           133         965           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_p15_het      992        137
## There are 1984 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining dr_p08_ko
## A set of combined differential expression results.
##                      table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08kodlgn_vs_p08koretina         829           145         801           158         756           162
## `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      829        145
## There are 1658 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining dr_p15_ko
## A set of combined differential expression results.
##                      table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15kodlgn_vs_p15koretina        1111           259        1181           250        1237           219
## `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     1111        259
## There are 2222 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining sr_p08_het
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08hetscn_vs_p08hetretina         548           265         531           291         473           291
## `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      548        265
## There are 1096 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining sr_p15_het
## A set of combined differential expression results.
##                       table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetscn_vs_p15hetretina         254           129         237           136         231           126
## `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      254        129
## There are 508 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining sr_p08_ko
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08koscn_vs_p08koretina         402           151         387           164         390           181
## `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      402        151
## There are 804 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining sr_p15_ko
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15koscn_vs_p15koretina          77            54          75            57          89            49
## `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       77         54
## There are 154 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining ds_p08_het
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08hetdlgn_vs_p08hetscn          51            57          63            48          49            39
## `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       51         57
## There are 102 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining ds_p15_het
## A set of combined differential expression results.
##                     table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetdlgn_vs_p15hetscn        1039             3        1191             3        1043             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_p15_het     1039          3
## There are 2078 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## There are only, 3 returning null.
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining ds_p08_ko
## A set of combined differential expression results.
##                   table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p08kodlgn_vs_p08koscn         365            12         397            12         339            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
## ds_p08_ko      365         12
## There are 730 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining ds_p15_ko
## A set of combined differential expression results.
##                   table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15kodlgn_vs_p15koscn        1117             4        1286             3        1024             6
## `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     1117          4
## There are 2234 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## There are only, 4 returning null.
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

19.5.3 And time

time_tables_full <- combine_de_tables(
  time_de, keepers = time_keepers,
  label_column = label_column,
  excel = glue("full_contrasts/time_full_tables-v{ver}.xlsx"))
time_sig_full <- extract_significant_genes(
  time_tables_full, according_to = "deseq",
  excel = glue("full_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("time_contrasts/time_{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
  include_sig_filename <- glue("time_contrasts/time_{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_filename)
  print(time_sig[[name]])
  num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
    nrow(time_sig[[name]][["deseq"]][["ups"]][[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")
    cp_written <- write_all_cp(time_cp[[name]])
  }
}
## Examining t_het_dlgn
## A set of combined differential expression results.
##                      table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetdlgn_vs_p08hetdlgn         499            17         534            15         436            17
## `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.
## Deleting the file time_contrasts/time_t_het_dlgn_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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      499         17
## There are 998 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining t_ko_dlgn
## A set of combined differential expression results.
##                    table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15kodlgn_vs_p08kodlgn         719           229         846           205         624           196
## `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.

## Deleting the file time_contrasts/time_t_ko_dlgn_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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      719        229
## There are 1438 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining t_het_retina
## A set of combined differential expression results.
##                          table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetretina_vs_p08hetretina          74           273          78           280          57           358
## `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.

## Deleting the file time_contrasts/time_t_het_retina_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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       74        273
## There are 148 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## leading edge analysis...
## done...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining t_ko_retina
## A set of combined differential expression results.
##                        table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15koretina_vs_p08koretina          47           339          52           358          39           516
## `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.

## Deleting the file time_contrasts/time_t_ko_retina_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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       47        339
## There are 94 significant up and down genes.
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## Did not find the column:  in the significant genes.
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## Add a little logic here to use enrichplot::dotplot().
## preparing geneSet collections...
## GSEA analysis...
## no term enriched under specific pvalueCutoff...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## preparing geneSet collections...
## GSEA analysis...
## no term enriched under specific pvalueCutoff...
## Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.Scale for size is already present.
## Adding another scale for size, which will replace the existing scale.

## Examining t_het_scn
## A set of combined differential expression results.
##                    table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15hetscn_vs_p08hetscn           1             2           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.

## Deleting the file time_contrasts/time_t_het_scn_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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 2 significant up and down genes.
## Examining t_ko_scn
## A set of combined differential expression results.
##                  table deseq_sigup deseq_sigdown edger_sigup edger_sigdown limma_sigup limma_sigdown
## 1 p15koscn_vs_p08koscn           0             3           1             3           1             2
## Only t_ko_scn_down has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## Deleting the file time_contrasts/time_t_ko_scn_including_wt_0.1_decreased_table-v20240909.xlsx before writing the tables.
## 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          3
## There are 0 significant up and down genes.

20 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!

scn_extra <- "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)"
scn_translatome_keepers <- list(
  "p08_het_scn_vs_retina" = c("p08_het_scn", "p08_het_retina"),
  "p08_ko_scn_vs_retina" = c("p08_ko_scn", "p08_ko_retina"),
  "p08_scn_translatome" = c("p08het", "p08ko"),
  "p15_het_scn_vs_retina" = c("p15_het_scn", "p15_het_retina"),
  "p15_ko_scn_vs_retina" = c("p15_ko_scn", "p15_ko_retina"),
  "p15_scn_translatome" = c("p15het", "p15ko"))

p08_dlgn_extra <- "p08het_vs_p08ko = (p08_het_dlgn - p08_het_retina) - (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"))

time_het_scn_extra <- "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)"
time_het_scn_translatome_keepers <- list(
  "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"))

21 Bibliography

LS0tCnRpdGxlOiAiQW5hbHlzZXMgb2YgdGhlIElQUkdDIHJlLXByb2Nlc3NlZCBzYW1wbGVzLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgICAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgICAgIGRmX3ByaW50OiBwYWdlZAogICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgZmlnX2hlaWdodDogNwogICAgICAgIGZpZ193aWR0aDogNwogICAgICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgICAgIHdpZHRoOiAzMDAKICAgICAgICBrZWVwX21kOiBmYWxzZQogICAgICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgICAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgICBmaWdfaGVpZ2h0OiA3CiAgICAgICAgICBmaWdfd2lkdGg6IDcKICAgICAgICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgICAgICAga2VlcF9tZDogZmFsc2UKICAgICAgICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CmZvbnQtc2l6ZTogMTZweAp9CmJvZHkgLm1haW4tY29udGFpbmVyIHsKbWF4LXdpZHRoOiAxNjAwcHg7Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGVucmljaHBsb3QpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdnc3RhdHNwbG90KQpsaWJyYXJ5KGdwcm9maWxlcjIpCnR0IDwtIHRyeShkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KAogIHByb2dyZXNzID0gVFJVRSwgdmVyYm9zZSA9IFRSVUUsIHdpZHRoID0gOTAsIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXJyb3IgPSBUUlVFLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnJldGluYSA9IDIsCiAgb3V0LndpZHRoID0gIjEwMCUiLCBkZXYgPSAicG5nIiwKICBkZXYuYXJncyA9IGxpc3QocG5nID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKSkKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSAiMjAyNDA4IgpwcmV2aW91c19maWxlIDwtICIiCnZlciA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgIiVZJW0lZCIpCgojI3RtcCA8LSBzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkKcm1kX2ZpbGUgPC0gImlwcmdjX2FuYWx5c2VzXzIwMjQwOC5SbWQiCmBgYAoKIyBUT0RPcwoKKiBDaGVjayB0aGlzIGZvciBjb3JyZWN0bmVzcy4KKiBSZW9yZ2FuaXplIGl0CiogR1NWQSAoQGhhbnplbG1hbm5HU1ZBR2VuZVNldDIwMTNhKQoqIENvbnNpZGVyIGVtYmVkZGluZyBzb21lL21hbnkvYWxsIG9mIHRoZSBFeGNlbCBvdXRwdXRzIGludG8gdGhlIGh0bWwKICBvdXRwdXQgdmlhIHhmdW46OmVtYmVkX2RpcignZXhjZWwvJykKCiMgTWVldGluZyB3aXRoIFRoZXJlc2EKClByZXZpb3VzIHBhcGVycyBkaWQgbm90IGRvIGFuIGV4cGxpY2l0IHN1YnRyYWN0aW9uLCBpbnN0ZWFkIGp1c3QKY29tcGFyZWQgdG8gV1QgYW5kIGtlcHQgdGhlIGdlbmVzIHdoaWNoIGFyZSA+IGluIGRlbHRhL2hldCB2cy4gd3QuClRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIHRvIGRlYWwgd2l0aCB0aGlzIGFuZCB0aGF0IHF1ZXJ5IGhhcyBub3QgeWV0CmJlZW4gZGVmaW5lZC4gIExhdGVyLCBUaGVyZXNhIGNhbWUgdG8gdGhlIGNvbmNsdXNpb24gdGhhdCB0aGUKc3VidHJhY3Rpb24gbWV0aG9kIGlzIG5vdCBhcHByb3ByaWF0ZS4KCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIGRvY3VtZW50IEkgaG9wZSB0byBleHBsb3JlIHRoZSBmcmVzaGx5IHByb2Nlc3NlZCBzYW1wbGVzIGFuZApwZXJmb3JtIHNvbWUgY29tcGFyaXNvbnMgdG8gc2VlIHRoYXQgd2UgaGF2ZSB0aGUgZXhwZWN0ZWQgc2ltaWxhcml0aWVzCmFuZCBkaWZmZXJlbmNlcyBmcm9tIHRoZSBwcmlvciBhbmFseXNpcyBwZXJmb3JtZWQgYnkgVGhlcmVzYS4KClRoZXJlIGlzIG9uZSB3YXkgaW4gd2hpY2ggSSBleHBlY3QgYW55L2FsbCBvZiB0aGVzZSBhbmFseXNlcyB0byBiZQpleHBsaWNpdGx5IGRpZmZlcmVudDogdGhpcyBzaG91bGQgaW5jbHVkZSB0aGUgY2hhbmdlcyBwcm9kdWNlZCBieQpBcHJpbCdzIHJlbmFtaW5nIG9mIHNvbWUgc2FtcGxlcy4KCk15IGludGVudGlvbiBpcyB0byBwcm9kdWNlIGEgc2FtcGxlIHNoZWV0IHdoaWNoIGluY2x1ZGVzIG9uZSBjb2x1bW4Kd2l0aCBub24tdW1pLWRlZHVwbGljYXRlZCByZXN1bHRzIGFuZCBvbmUgd2l0aCBkZWR1cGxpY2F0ZWQgcmVzdWx0cy4KV2l0aCB0aGUgZXhjZXB0aW9uIG9mIHRoZSBwcmV2aW91cyBwb2ludCwgSSBob3BlIHRoYXQgdGhlIGZpcnN0IHdpbGwKYmUgaWRlbnRpY2FsIChvciBhdCBsZWFzdCB2ZXJ5IGNsb3NlIHRvIGlkZW50aWNhbCkgdG8gVGhlcmVzYSdzIHJlc3VsdAp3aGlsZSB0aGUgc2Vjb25kIEkgZXhwZWN0IHdpbGwgYmUgc3VidGx5IGRpZmZlcmVudCAtLSBidXQgSSBhbSBob3BpbmcKc3VidGx5IGVub3VnaCB0aGF0IGl0IHdpbGwgbm90IHNpZ25pZmljYW50bHkgY2hhbmdlIHRoZSBpbnRlcnByZXRhdGlvbgpidXQgYmUgYSBsaXR0bGUgbW9yZSBwcmVjaXNlLgoKTGV0cyBzZWUhICBJIG5lZWQgdGhlcmVmb3JlIHRvIG1ha2UgYSBjaGFuZ2UgdG8gbXkgbWV0YWRhdGEgZ2F0aGVyaW5nCmZ1bmN0aW9uIHRvIGluY2x1ZGUgdGhlIHVtaSBkZWR1cGxpY2F0ZWQgcmVzdWx0LiAgSSBhbSB0aGlua2luZwp0aGVyZWZvcmUgdG8gY3JlYXRlIGEgc2VwYXJhdGUgc3BlY2lmaWNhdGlvbiBmb3IgdW1pLWJhcmNvZGVkIHNhbXBsZXMKYmVjYXVzZSBsb29raW5nIHRocm91Z2ggdGhlIGxvZ3MgZm9yIHVtaSBzdHVmZiB3aGVuIHRoZXkgYXJlIG5vdCB1c2VkCndpbGwgYmUgdG9vIG11Y2ggb2YgYSBwYWluLi4uCgojIyBTbWFsbCByYW5kb20gcmVtaW5kZXIKCkkgaGF2ZSBhIGNvdXBsZSBwaWN0dXJlcyBvZiBSUEwyMiB0byBoZWxwIG1lIHJlbWVtYmVyIHRoZSBleHBlcmltZW50YWwKZGVzaWduOgoKKiBUaGUgaHVtYW4gcmlib3NvbWUgd2l0aCBSUEwyMiBpbiByZWQ6ICFbaHVtYW5fcnBsMjJfcmVkXShodW1hbl9yaWJvc29tZV9MMjJfcmVkLnBuZykKKiBUaGUgbW91c2Ugcmlib3NvbWUgd2l0aCBSUEwyMiBpbiBncmVlbiBhdCB0aGUgY2VudGVyOgohW21vdXNlX3JwbDIyXShtbXVzY3VsdXNfUlBMMjJfZ3JlZW5fY2VudGVyLnBuZykKClRoYXQgc2Vjb25kIHBpY3R1cmUgY2FtZSBmcm9tOiAoQGxpTWFsZUdlcm1jZWxsc3BlY2lmaWNSaWJvc29tZTIwMjIpCgojIEEgbm90ZSBhYm91dCBpbXBsZW1lbnRhdGlvbgoKSSB3b3VsZCBsaWtlIHRvIGltcHJvdmUgdGhpcyBkb2N1bWVudCBieSBjb21wYXJpbmcvY29udHJhc3RpbmcgdGhlCm1ldGhvZG9sb2dpZXMgcGVyZm9ybWVkIGJ5IG90aGVyIGdyb3VwcyBhbmQgdGhvc2UgcGVyZm9ybWVkIGJ5IG1lIGluCml0LiAgSSBuZXZlciBmdWxseSBhcHByZWNpYXRlZCB0aGUgc3VpdGUgb2YgY29tcHV0YXRpb25hbCBtZXRob2RzCmFwcGxpZWQgYnkgcHJldmlvdXMgZ3JvdXBzIHdoZW4gZXhhbWluaW5nIFRSQVAgZGF0YTsgSSBpbnN0ZWFkIHNpbXBseQpmb2xsb3dlZCBUaGVyZXNhJ3Mgbm90ZWJvb2sgd2l0aG91dCBjb25zaWRlcmluZyBvdGhlciBwb3NzaWJpbGl0aWVzLgoKSSB0aGVyZWZvcmUgc3BlbnQgYSBsaXR0bGUgdGltZSBzdGVwcGluZyB0aHJvdWdoIGhlciB0aGVzaXMgYW5kCnB1bGxpbmcgb3V0IHRoZSByZWxldmFudCBwYXBlcnMgaW4gdGhlIGhvcGVzIG9mIGxlYXJuaW5nIHRoZXNlIHZhcmlvdXMKbWV0aG9kcy4gIEkgc2hvdWxkIHRoZXJlZm9yZSBiZSBhYmxlIHNvb24gdG8gY29tcGFyZS9jb250cmFzdCB0aGUKdmFyaW91cyBtZXRob2RzIGVtcGxveWVkIGJ5IG90aGVyIGxhYnMgaW4gYWRkaXRpb24gdG8gY29weWluZwpUaGVyZXNhJ3MgbG9naWMuCgpgYGB7cn0KdW1pX3NwZWMgPC0gbWFrZV9ybmFzZXFfc3BlYyh1bWkgPSBUUlVFKQppcHJnY18yMDIyX21ldGEgPC0gZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoInNhbXBsZV9zaGVldHMvMjAyNDA2MDZfb25seV91bWRfc2VxdWVuY2VkLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlYyA9IHVtaV9zcGVjLCBzcGVjaWVzID0gIm1tMzlfMTEyIiwgdmVyYm9zZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZWRpciA9ICJwcmVwcm9jZXNzaW5nL3VtZF9zZXF1ZW5jZWQiKQpgYGAKCkZyb20gdGhpcyBwb2ludCBvbiwgSSBhbSBob3BpbmcvaW50ZW5kaW5nIHRvIHB1bGwgbGliZXJhbGx5IGZyb20KVGhlcmVzYSdzIG5vdGVib29rIHdpdGggYSBkaXZlcnNpb24gdG8gY29tcGFyZSB0aGUgdGhyZWUgZGF0YXNldHM6CgoqIFByZS1BcHJpbCByZW5hbWluZzogRS5nLiBUaGVyZXNhJ3MgY3VycmVudCBkYXRhc2V0CiogUG9zdCByZW5hbWluZzogVW5sZXNzIEkgYW0gbWlzdGFrZW4sIHRoaXMgc2hvdWxkIGJlIHZlcnkgc2ltaWxhciB0bwogIHRoZSBhYm92ZS4KKiBQb3N0IGRlZHVwbGljYXRpb246IEdpdmVuIHdoYXQgSSBzYXcgZnJvbSB0aGUgZXh0cmFjdGVkIGxvZ3MgaW4gdGhlCiAgc2FtcGxlIHNoZWV0LCBJIGV4cGVjdCB0aGlzIHRvIGJlIHNpbWlsYXIgYnV0IG5vdCBpZGVudGljYWwgdG8gdGhlCiAgcHJldmlvdXMgdHdvLgoKTGV0cyBmaW5kIG91dCEgICBCdXQgZmlyc3QsIGFubm90YXRpb25zIQoKIyBBbm5vdGF0aW9uIGRhdGEKCkkgYW0gcHVsbGluZyB0aGlzIGZyb20gVGhlcmVzYSdzIGFueG9udHJhcFJfcGlwZWxpbmUuUm1kLCBwcmltYXJpbHkKYmVjYXVzZSBpdCBsb29rcyBzaW1pbGFyIHRvIHRoZSBvdGhlciBkb2N1bWVudHMsIGJ1dCB3YXMgbW9kaWZpZWQgbW9yZQpyZWNlbnRseS4gIEkgd2lsbCBjaGFuZ2UgaXQgc2xpZ2h0bHksIHByaW1hcmlseSBiZWNhdXNlIEkgZ3JhYmJlZCBhCm5ldyBtbXVzY3VsdXMgYXNzZW1ibHkgYW5kIHRoZXJlZm9yZSBJIHdpbGwgcHVsbCB0aGUgbW11c2N1bHVzCmFubm90YXRpb25zIGZyb20gYSBzcGVjaWZpYyBiaW9tYXJ0CihAc21lZGxleUJpb01hcnRCaW9sb2dpY2FsUXVlcmllczIwMDkpIGFyY2hpdmUgdGhhdCBzaG91bGQgbWF0Y2ggaXQuCgpgYGB7cn0KbW1fYW5ub3QgPC0gbG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHNwZWNpZXMgPSAibW11c2N1bHVzIiwgeWVhciA9ICIyMDIzIiwgbW9udGggPSAiMDIiKQptbV9hbm5vdCA8LSBtbV9hbm5vdFtbImFubm90YXRpb24iXV0KbW1fYW5ub3RbWyJ0eGlkIl1dIDwtIHBhc3RlMChtbV9hbm5vdFtbImVuc2VtYmxfdHJhbnNjcmlwdF9pZCJdXSwgIi4iLCBtbV9hbm5vdFtbInZlcnNpb24iXV0pCnJvd25hbWVzKG1tX2Fubm90KSA8LSBtYWtlLm5hbWVzKG1tX2Fubm90W1siZW5zZW1ibF9nZW5lX2lkIl1dLCB1bmlxdWU9VFJVRSkKdHhfZ2VuZV9tYXAgPC0gbW1fYW5ub3RbLCBjKCJ0eGlkIiwgImVuc2VtYmxfZ2VuZV9pZCIpXQpgYGAKCiMgSGlzYXQyIGV4cHJlc3Npb25zZXRzCgpUaGUgcHJpbWFyeSBkaWZmZXJlbmNlIGJldHdlZW4gbXkgYmxvY2sgYW5kIFRoZXJlc2EncyBhcmU6CgoxLiAgSSBhbSBwdWxsaW5nIHRoZSBtZXRhZGF0YSBkaXJlY3RseSBmcm9tIHRoZQogICAgZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoKSBhYm92ZS4KMi4gIEkgYW0gdXNpbmcgdGhlIGNvbHVtbiAnc3ltbGluaycgd2hpY2ggaXMganVzdCBhIGNvcHkgb2YgdGhlCiAgICBleGlzdGluZyAnZmlsZScgY29sdW1uIHdpdGggYSBzbWFsbCBjaGFuZ2Ugc28gSSBjYW4gbG9hZCBpdCBmcm9tCiAgICBteSBkaXJlY3Rvcnkgd2l0aG91dCBoYXZpbmcgdG8gY29weSBldmVyeXRoaW5nLgozLiAgSSBhbSB1c2luZyB0aGUgZW5zZW1ibCBnZW5vbWUgcmVsZWFzZSAzOSwgdmVyc2lvbiAxMTIgYW5kIHNvCiAgICBwdWxsZWQgYSBzb21ld2hhdCBuZXdlciBjb3B5IG9mIHRoZSBhbm5vdGF0aW9uIGRhdGEuCjQuICBUaGUgb3JpZ2luYWwgaXMgbmFtZWQgJ3YxJywgZm9sbG93ZWQgYnkgJ3YyJyBhbmQgJ3YzJyBmb3IgdGhlCiAgICBvdGhlciB0d28gdHJlYXRtZW50cyBJIHBlcmZvcm1lZC4KCiMjIENvbG9yIGNob2ljZXMgYW5kIHJldXNlZCBwYXJhbWV0ZXJzCgpHaXZlbiB0aGF0IHdlIGFyZSBleGNsdWRpbmcgYSBidW5jaCBvZiB0aGUgb2xkZXIgc2FtcGxlcywgdGhlIHNldCBvZgpjb2xvcnMgSSBleHBlY3QgdG8gZmluZCBpcyBkaWZmZXJlbnQ7IHNvIEkgd2lsbCBtYWtlIGV4cGxpY2l0IGhlcmUgdGhlCnZhcmlvdXMgY29sb3JzIHVzZWQgdG8gZGVub3RlIGxvY2F0aW9uL2dlbm90eXBlL3RpbWUvZXRjLgoKQXByaWwgdHVybmVkIG1lIG9udG8gdGhpcyB3ZWJzaXRlICdwYWxldHRvbi5jb20nIGZvciB0aGlzIGtpbmQgb2YKc3R1ZmYgYW5kIEkgd2lsbCB0cnkgYW5kIHBpY2sgb3V0IHBhbGV0dGVzIHdoaWNoIGJhc2ljYWxseSBtYXRjaCB3aGF0CkkgYW0gZ2V0dGluZyB3aXRoIHRoZSBvcmlnaW5hbCBjb2xvcnMuCgpgYGB7cn0KY29sb3JfY2hvaWNlcyA8LSBsaXN0KAogICJhbGwiID0gbGlzdCgKICAgICJwMDhfaGV0X2RsZ24iID0gIiM5RUNBRTEiLAogICAgInAxNV9oZXRfZGxnbiIgPSAiIzlFQ0FFMSIsCiAgICAicDA4X2hldF9yZXRpbmEiID0gIiNGNDZENDMiLAogICAgInAxNV9oZXRfcmV0aW5hIiA9ICIjRjQ2RDQzIiwKICAgICJwMDhfaGV0X3NjbiIgPSAiIzJDQTI1RiIsCiAgICAicDE1X2hldF9zY24iID0gIiMyQ0EyNUYiLAogICAgInAwOF9rb19kbGduIiA9ICIjMzE4MkJEIiwKICAgICJwMTVfa29fZGxnbiIgPSAiIzMxODJCRCIsCiAgICAicDA4X2tvX3JldGluYSIgPSAiI0ZEQUU2MSIsCiAgICAicDE1X2tvX3JldGluYSIgPSAiI0ZEQUU2MSIsCiAgICAicDA4X2tvX3NjbiIgPSAiIzAwNkQyQyIsCiAgICAicDE1X2tvX3NjbiIgPSAiIzAwNkQyQyIsCiAgICAicDA4X3d0X2RsZ24iID0gIiNERUVCRjciLAogICAgInAxNV93dF9kbGduIiA9ICIjREVFQkY3IiwKICAgICJwMDhfd3RfcmV0aW5hIiA9ICIjRDczMDI3IiwKICAgICJwMTVfd3RfcmV0aW5hIiA9ICIjRDczMDI3IiwKICAgICJwMDhfd3Rfc2NuIiA9ICIjNjZDMkE0IiwKICAgICJwMTVfd3Rfc2NuIiA9ICIjNjZDMkE0IiksCiAgImdlbm9fbG9jIiA9IGxpc3QoCiAgICAiaGV0X2RsZ24iID0gIiM5RUNBRTEiLAogICAgImhldF9yZXRpbmEiID0gIiNGNDZENDMiLAogICAgImhldF9zY24iID0gIiMyQ0EyNUYiLAogICAgImtvX2RsZ24iID0gIiMzMTgyQkQiLAogICAgImtvX3JldGluYSIgPSAiI0ZEQUU2MSIsCiAgICAia29fc2NuIiA9ICIjMDA2RDJDIiwKICAgICJ3dF9kbGduIiA9ICIjREVFQkY3IiwKICAgICJ3dF9yZXRpbmEiID0gIiNENzMwMjciLAogICAgInd0X3NjbiIgPSAiIzY2QzJBNCIpLAogICMjIFRoZXNlIGNvbG9ycyBhcmUgY29taW5nIGZyb20gaXBSR0Nfc3VtbWFyeXBsb3RzLmh0bWwKICAjIyBJIGFtIHVzaW5nIGtjb2xvcmNob29zZXIgdG8gZ3JhYiB0aGVtIHJhdGhlciB0aGFuIGdldCBjb25mdXNlZCBieSB0aGUgdGV4dAogICJsb2NhdGlvbiIgPSBsaXN0KAogICAgInJldGluYSIgPSAiI2Q3MzAyNyIsCiAgICAiZGxnbiIgPSAiIzMxODJiZCIsCiAgICAic2NuIiA9ICIjMDA2YjI5IiksCiAgImdlbm90eXBlIiA9IGxpc3QoCiAgICAid3QiID0gIiNENEQ0RDQiLAogICAgImhldCIgPSAiIzc4Nzg3OCIsCiAgICAia28iID0gIiMzMTMxMzEiKSwKICAidGltZSIgPSBsaXN0KAogICAgInAwOCIgPSAiIzVFMTA0QiIsCiAgICAicDE1IiA9ICIjNEU5MjMxIikpCmxhYmVsX2NvbHVtbiA8LSAibWdpc3ltYm9sIiAjIyBTZXQgdGhlIGNvbHVtbiB1c2VkIHRvIGV4dHJhY3QgZ2VuZSBzeW1ib2xzIHJhdGhlciB0aGFuIEVOU0cuLi4uLgpgYGAKClRoZXJlIGlzIG9uZSBub3Rld29ydGh5IHNhbXBsZTogaXByZ2NfMTAzLCBpdCB3YXMgZWZmZWN0aXZlbHkgcmVwbGFjZWQKd2hlbiBBcHJpbCByZW5hbWVkIHRoZSBzYW1wbGVzIGFuZCBzbyBleGlzdHMgaW4gdGhlIHYxIGRhdGEsIGJ1dCBub3QKdjIvdjM7IHRoZXkgaW5zdGVhZCBoYXZlIHRoZSBuZXdseSBuYW1lZCBzYW1wbGVzIHdoaWNoIEkgY2FsbGVkCmlwcmdjXzEyMyB0byBpcHJnY18xMzAuICBBcyBhIHJlc3VsdCwgSSBjb3BpZWQgdGhlIGFubm90YXRpb25zIGZvcgppcHJnY18xMjMgdG8gbXkgY29sdW1uIHNvIHRoYXQgdGhlcmUgaXMgbm8gZGlzY3JlcGVuY3kgaW4gdGVybXMgb2YKZ2Vub3R5cGUvbG9jYXRpb24vdGltZS4KCmBgYHtyfQptbTM4X2hpc2F0X3YxIDwtIGNyZWF0ZV9leHB0KGlwcmdjXzIwMjJfbWV0YVtbIm5ld19tZXRhIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IG1tX2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gInN5bWxpbmsiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiZ2Vub2xvY2F0YiIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ0aW1lYXRiIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXSkKbW0zOF9oaXNhdF92MQoKbW0zOF9oaXNhdF92MiA8LSBjcmVhdGVfZXhwdChpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSwgZ2VuZV9pbmZvID0gbW1fYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAiaGlzYXRfY291bnRfdGFibGUiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiZ2Vub2xvY2F0YiIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ0aW1lYXRiIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXSkKbW0zOF9oaXNhdF92MgoKbW0zOF9oaXNhdF92MyA8LSBjcmVhdGVfZXhwdChpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSwgZ2VuZV9pbmZvID0gbW1fYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidW1pX2RlZHVwX291dHB1dF9jb3VudCIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vbG9jYXRiIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInRpbWVhdGIiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImdlbm9fbG9jIl1dKQptbTM4X2hpc2F0X3YzCgphbGxfZmFjdCA8LSBwYXN0ZTAocERhdGEobW0zOF9oaXNhdF92MylbWyJ0aW1lYXRiIl1dLCAiXyIsCiAgICAgICAgICAgICAgICAgICBwRGF0YShtbTM4X2hpc2F0X3YzKVtbImdlbm9sb2NhdGIiXV0pCnBEYXRhKG1tMzhfaGlzYXRfdjMpW1sidGltZV9nZW5vX2xvYyJdXSA8LSBhbGxfZmFjdApgYGAKCk5vdGUgdGhlIGVuZCBvZiB0aGUgcHJldmlvdXMgYmxvY2ssIEkgY3JlYXRlZCBhIGZhY3RvciBvdXQgb2YgdGhlCmNvbWJpbmF0aW9uIG9mIHRpbWUsIGdlbm90eXBlLCBhbmQgbG9jYXRpb24uICBJbiBhIGZ1dHVyZSBpbnZvY2F0aW9uCm9mIHRoaXMgbm90ZWJvb2ssIEkgd2lsbCBjaGFuZ2UgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHRvIGFkZCBlYWNoCm9mIHRoZXNlIHRocmVlIGZhY3RvcnMgdG8gdGhlIHN0YXRpc3RpY2FsIG1vZGVsIGluc3RlYWQgb2YgdGhpcy4gIFRoZQpjb2RlIHRvIGRvIHRoYXQgaXMgbm90IF9xdWl0ZV8gcmVhZHkgeWV0LgoKIyBOb24temVybyBDb3VudHMgcGVyIFNhbXBsZQoKTGV0J3MgbG9vayBhdCB0aGUgbnVtYmVyIG9mIG5vbi16ZXJvIGdlbmVzIGZvciBhbGwgc2FtcGxlcyB2ZXJzdXMgdGhlCmNvdmVyYWdlLgoKYGBge3J9CnBsb3RfbGVnZW5kKG1tMzhfaGlzYXRfdjEpCgp2MV9ub256ZXJvIDwtIHBsb3Rfbm9uemVybyhtbTM4X2hpc2F0X3YxKQp2MV9ub256ZXJvCgp2Ml9ub256ZXJvICA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF92MikKdjJfbm9uemVybwoKdjNfbm9uemVybyAgPC0gcGxvdF9ub256ZXJvKG1tMzhfaGlzYXRfdjMpCnYzX25vbnplcm8KYGBgCgpPaCB3b3csIEkgZGlkIG5vdCBleHBlY3Qgc3VjaCBhIHByb2ZvdW5kIGVmZmVjdCBvbiB0aGUgY3BtIHZhbHVlcyBvbgp0aGUgbW9yZSBzYXR1cmF0ZWQgbGlicmFyaWVzLiAgSSBndWVzcyBpbiByZXRyb3NwZWN0IEkgc2hvdWxkIGhhdmU/CgpBbHNvIG5vdGUgdG8gc2VsZiwgd2UgYXJlIG5vdCBtZXNzaW5nIHdpdGggcDYwLgoKYGBge3J9Cm1tMzhfaGlzYXRfdjEgPC0gc3Vic2V0X2V4cHQobW0zOF9oaXNhdF92MSwgc3Vic2V0ID0gInRpbWVhdGIhPSdwNjAnIikKbW0zOF9oaXNhdF92MiA8LSBzdWJzZXRfZXhwdChtbTM4X2hpc2F0X3YyLCBzdWJzZXQgPSAidGltZWF0YiE9J3A2MCciKQptbTM4X2hpc2F0X3YzIDwtIHN1YnNldF9leHB0KG1tMzhfaGlzYXRfdjMsIHN1YnNldCA9ICJ0aW1lYXRiIT0ncDYwJyIpCmBgYAoKIyBRdWljayBQQ0EsIHRoZW4gcmV0dXJuIHRvIFRoZXJlc2EncyBkb2N1bWVudAoKYGBge3J9CnYxX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MSwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnYyX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MiwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnYzX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MywgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCgpwbG90X3BjYSh2MV9ub3JtKQpwbG90X3BjYSh2Ml9ub3JtKQpwbG90X3BjYSh2M19ub3JtKQpgYGAKClRvIG15IGV5ZXMgaXQgbG9va3MgbGlrZSB3ZSBqdXN0IGhhdmUgMSB3ZWlyZG8gcDE1IHNhbXBsZT8KRGVkdXBsaWNhdGlvbiBoYWQgYSBtaW5vciBidXQgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBQQ0EuCgpXaXRoIHRoYXQgaW4gbWluZCwgbGV0IHVzIGxvb2sgYXQgVGhlcmVzYSdzIFdPUktJTkcgZG9jdW1lbnQgYW5kIHNlZQp3aGF0IHdlIGNhbiByZWNhcGl0dWxhdGUuCgpUaGVyZXNhJ3MgZG9jdW1lbnQ6IFRoZSBUUkFQIHByb3RvY29sIGhhcyBzb21lIHZhcmlhYmlsaXR5IHdoaWNoIGlzCmludHJvZHVjZWQgYXQgZGlmZmVyZW50IHN0ZXBzIGluY2x1ZGluZyBob21vZ2VuaXphdGlvbiwgYW50aWJvZHkKbGFiZWxpbmcsIHB1bGxkb3duIGVmZmljaWVuY3kvc3BlY2lmaWNpdHksIHNhbXBsZSBoYW5kbGluZyBkdXJpbmcKY2xlYW51cCBzdGVwcywgYW5kIGxpYnJhcnkgcHJlcC9zZXF1ZW5jaW5nLiBXZSBrbm93IGZyb20gUmFzaG1pJ3MgUUMKdGhhdCB0aGVyZSBpcyB2YXJpYWJpbGl0eSBhdCB0aGUgbGV2ZWwgb2YgcHVsbGRvd24gZWZmaWNpZW5jeSAoYW1vdW50Cm9mIFJOQSBpc29sYXRlZCkuIFNoZSBpcyBkb2luZyBhIGdvb2Qgam9iIG9mIGtlZXBpbmcgdHJhY2sgb2YgdGhpcyBmb3IKYWxsIGhlciBzYW1wbGVzIGFuZCB3ZSBoYXZlIHZhbGlkYXRlZCBoZXIgUDggcmVzdWx0cyAoYXR0YWNoZWQKc3VwcGxlbWVudGFyeSBmaWd1cmUgM0QpLiBXZSBjb25zaXN0ZW50bHkgc2VlIGNsZWFyIGRpZmZlcmVuY2VzCmJldHdlZW4gY29udHJvbCBhbmQgY3JlIHNhbXBsZXMgZm9yIHRoZSByZXRpbmEsIHdoaWNoIG1ha2VzIHNlbnNlCmJlY2F1c2UgdGhlIGNlbGwgYm9kaWVzIGFyZSBpbiB0aGUgcmV0aW5hLiBUaGUgdGFyZ2V0IHRpc3N1ZQpkaWZmZXJlbmNlcyBhcmUgc21hbGxlciwgd2hpY2ggYWxzbyBtYWtlcyBzZW5zZSBmb3IgYXhvbi1UUkFQLiBXZQp0aGluayB0aGF0IHNvbWUgb2YgaGVyIFAxNSBzYW1wbGVzIGFyZSBub3QgZ29vZCBiYXNlZCBvbiBsb3cgYW1vdW50cwpvZiBpc29sYXRlZCBSTkEgZnJvbSBjcmUoKykgcmV0aW5hIHNhbXBsZXMuIFdlIHBsYW4gdG8gZHJvcCB0aGVzZQpzYW1wbGVzIGFuZCBub3QgcGVyZm9ybSBhZGRpdGlvbmFsIGlzb2xhdGlvbnMgYXQgdGhpcyB0aW1lCnBvaW50LiBCYXNlZCBvbiB0aGlzIChhbmQgdGhlIGdlbmVyYWwgbGFjayBvZiBsYXJnZSBkZXZlbG9wbWVudGFsCmVmZmVjdHMpLCB3ZSB3ZXJlIHBsYW5uaW5nIHRvIGZvY3VzIG9uIHByZXNlbnRpbmcgdGhlIFA4IGRhdGEgb25seSBpbgp0aGUgcGFwZXIuIEludGVyZXN0ZWQgdG8gaGVhciB5b3VyIHRob3VnaHRzIGluIHRoaXMuLi4KCk15IG5vdGVzOiBUaGVyZXNhJ3MgZmlyc3Qgb3BlcmF0aW9ucyBpbiB0aGlzIG5vdGVib29rIHdlcmUgdG86CgoxLiAgU2V0IGxvY2F0aW9uIGFzIGNvbmRpdGlvbiwgZ2Vub3R5cGUgYXMgYmF0Y2guCjIuICBQZXJmb3JtIFBDQSBiZWZvcmUvYWZ0ZXIgc3ZhLgoKYGBge3J9CnYzX2xvY19nZW5vIDwtIHNldF9leHB0X2NvbmRpdGlvbnMobW0zOF9oaXNhdF92MywgZmFjdCA9ICJsb2NhdGlvbmF0YiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZ2Vub3R5cGVhdGIiKQpgYGAKCiMjIFRoZSBhc3NvY2lhdGVkIFBDQQoKQXQgZGlmZmVyZW50IHRpbWVzLCBpdCBhcHBlYXJzIHRvIG1lIHRoYXQgVGhlcmVzYSBoYXMgcHJlZmVycmVkCnNsaWdodGx5IGRpZmZlcmVudCBub3JtYWxpemF0aW9uIG1ldGhvZHMsIHByaW1hcmlseSBhIG1peCBvZiBUTU0gYW5kCnF1YW50aWxlLgoKVGh1cyBJIHdpbGwgdXNlIGRpZmZlcmVudCBzdWZmaXggbGV0dGVycyB0byBkZW5vdGUgdmFyaW91cwpub3JtYWxpemF0aW9ucyBlbXBsb3llZCwgYW5kIGlmIHRoZXkgdHVybiBvdXQgdGhlIHNhbWUgSSB3aWxsIHBpY2sgb25lIGFyYml0cmFyaWx5LgoKYGBge3J9CmxvY19nZW5vX25xIDwtIG5vcm1hbGl6ZV9leHB0KHYzX2xvY19nZW5vLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCnBsb3RfcGNhKGxvY19nZW5vX25xKQojIyBvaywgSSBoYXZlIHR3byB3ZWlyZG8gc2FtcGxlcyB3aGljaCBsb29rIHZlcnkgbXVjaCBsaWtlIHRoZXkgYXJlIGFjdHVhbGx5IGRsZ24uCiMjIFRoZXNlIGFyZSBzYW1wbGUgSURzIGlwcmdjXzY2IGFuZCBpcHJnY18xMzAKCmxvY19nZW5vX250IDwtIG5vcm1hbGl6ZV9leHB0KHYzX2xvY19nZW5vLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJ0bW0iKQpwbG90X3BjYShsb2NfZ2Vub19udCkKYGBgCgpBIHJhbmRvbSB0aG91Z2h0IGFib3V0IHRoZXNlIFBDQSBwbG90cywgaXQgbWlnaHQgYmUgd29ydGggd2hpbGUgdG8gYWRkCmEgcGFuZWwgYmVsb3cgdGhlIGxlZ2VuZCB3aXRoIHRoZSBzYW1wbGUgbnVtYmVycyBwZXIgY29uZGl0aW9uL2JhdGNoLgoKT2YgY291cnNlLCB0aGUgc2FtZSBpbmZvcm1hdGlvbiBpcyBwcm92aWRlZCBpbiBhIG1vcmUgZnVuIGZhc2hpb24gdmlhCm15IHNpbGx5IHNhbmtleSBmdW5jdGlvbjoKCmBgYHtyfQpzYW1wbGVfc2Fua2V5IDwtIHBsb3RfbWV0YV9zYW5rZXkodjNfbG9jX2dlbm8sIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9ycyA9IGMoImdlbm90eXBlYXRiIiwgImxvY2F0aW9uYXRiIiwgInRpbWVhdGIiKSkKc2FtcGxlX3NhbmtleQpgYGAKCiMgQSBTaG9ydCBjb252ZXJzYXRpb24gd2l0aCBSYXNobWkKClJhc2htaSBjYW1lIGJ5IGFuZCB3ZSBkaXNjdXNzZWQgdGhlIHNhbXBsZXMgYSBsaXR0bGUuICBTaGUgc3VnZ2VzdGVkCnRoYXQgaXMgbGlrZWx5IHRoYXQgd2Ugd2lsbCBuZWVkIHRvIGV4Y2x1ZGUgdGhlIDIwMjIwNSBzYW1wbGVzLCB0aGVzZQptYXkgYmUgaWRlbnRpZmllZCBieSBhIGZldyB3YXlzLCBtb3N0IGVhc2lseSBJIHRoaW5rIHZpYSB0aGUKJ3Byb2plY3RhaCcgY29sdW1uLCB0aGV5IGFyZSB0aGUgMDIxXzEgc2FtcGxlcy4KCk15IHNlbnNlIHdhcyB0aGF0IHNoZSBjb25jdXJyZWQgd2l0aCBteSBpbnRlcnByZXRhdGlvbiBvZiB0aGUgdW1pCmRlZHVwbGljYXRpb24sIHNvIEkgd2lsbCBjb250aW51ZSB1c2luZyB0aGUgZGVkdXBsaWNhdGVkIHJlc3VsdHMKZXhjbHVzaXZlbHksIGF0IGxlYXN0IGZvciBub3cuCgojIE1lbGFub3BzaW4gU2FuaXR5IENoZWNrCgpPbmUgb2YgVGhlcmVzYSdzIGZpcnN0IGNoZWNrcyB3YXMgd2lzZWx5IGZvciBtZWxhbm9wc2luLiAgTGV0IHVzCnJlcGVhdCBhIHZlcnNpb24gb2YgdGhpczoKCmBgYHtyfQpvcG40X2V4cHJzIDwtIGRhdGEuZnJhbWUoY29tYmluZWQgPSBwRGF0YShsb2NfZ2Vub19udClbWyJnZW5vbG9jYXRiIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb24gPSBwRGF0YShsb2NfZ2Vub19udClbWyJsb2NhdGlvbmF0YiJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgIGdlbm90eXBlID0gcERhdGEobG9jX2dlbm9fbnQpW1siZ2Vub3R5cGVhdGIiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBvcG4gPSBleHBycyhsb2NfZ2Vub19udClbIkVOU01VU0cwMDAwMDAyMTc5OSIsIF0pCgpncm91cGVkc3RhdHM6Omdyb3VwZWRfc3VtbWFyeShvcG40X2V4cHJzLCBsb2NhdGlvbiwgb3BuKQpnZ2JldHdlZW5zdGF0cyhkYXRhID0gb3BuNF9leHBycywgeCA9IGxvY2F0aW9uLCB5ID0gb3BuKQpnZ2JldHdlZW5zdGF0cyhkYXRhID0gb3BuNF9leHBycywgeCA9IGdlbm90eXBlLCB5ID0gb3BuKQpnZ2JldHdlZW5zdGF0cyhkYXRhID0gb3BuNF9leHBycywgeCA9IGNvbWJpbmVkLCB5ID0gb3BuKQpgYGAKCm9rLCBzbyBJIHBsb3R0ZWQgdGhlIHF1ZXN0aW9uIGEgYml0IGRpZmZlcmVudGx5LCBidXQgZ290IHRoZSBzYW1lCmFuc3dlci4KCkhlcmUgaXMgdGhlIHRleHQgb2YgVGhlcmVzYSdzIG5vdGVib29rIGZvbGxvd2luZyB0aGlzIGFuYWx5c2lzOgoKIlVnaCBvaCwgbG9va3MgbGlrZSB0aGVyZSBpcyBhdCBsZWFzdCBvbmUgcmV0aW5hIEtPIHNhbXBsZSB0aGF0IGhhcwpzb21lIG1lbGFub3BzaW4gZXhwcmVzc2lvbiBpbiBpdC4gVHVybnMgb3V0IGlwUkdDXzA3IGlzIGEgYmFkIGVnZwp3aGljaCBpcyBzdXBwb3NlZCB0byBiZSBhIEtPIGJ1dCBoYXMgbWVsYW5vcHNpbiBleHByZXNzaW9uLiBJdOKAmXMKZnJpZW5kcyB3aGljaCB3ZXJlIHBvb2xlZCBmcm9tIHRoZSBzYW1lIG1pY2UgYXJlIGlwcmdjXzA2IGFuZAppcHJnY18wOCwgc28gd2UgbmVlZCB0byBleGNsdWRlIGFsbCB0aGVzZSBzYW1wbGVzLiIKCkkgYW0gYWxzbyBzZWVpbmcgc29tZSBrbm9ja291dCBleHByZXNzaW9uIHdpdGggc29tZSBjYXZlYXRzOiBJIGRvIG5vdApoYXZlIHRoZSBhZmZlY3RlZCBzYW1wbGVzIGluIG15IGRhdGFzZXQgKGlwcmdjXzA3KSBhbmQgdGhlIGxldmVscyBJIGFtCnNlZWluZyBhcmUgcXVpdGUgbG93IC0tIEkgd2lsbCBsb29rIGluIElHViB0byBkb3VibGUgY2hlY2ssIGJ1dCBJCnN0cm9uZ2x5IHN1c3BlY3QgdGhhdCB0aGVzZSBhcmUgc29tZSBwaWRkbHkgcmVhZHMgbmVhciB0aGUgVVRScy4KCk9ud2FyZCEKCiMgTGlicmFyeSBzaXplcyBwb3N0LWRlZHVwbGljYXRpb24KClRoZXJlc2EncyBuZXh0IG9wZXJhdGlvbiB3YXMgdG8gcGVyZm9ybSBsaWJzaXplL25vbnplcm8gcGxvdHMuICBJCmFscmVhZHkgZGlkIHRoZSBwcmUvcG9zdCBkZWR1cGxpY2F0aW9uIG5vbnplcm8sIGhlcmUgaXMgdGhlIGFuYWxhZ291cwpsaWJzaXplLgoKdjIgaXMgcHJlLWRlZHVwbGljYXRpb24gYW5kIHYzIGlzIHBvc3QuCgpgYGB7cn0KcGxvdF9saWJzaXplKG1tMzhfaGlzYXRfdjIpCnBsb3RfbGlic2l6ZShtbTM4X2hpc2F0X3YzKQpgYGAKCkkgYW0gYSBiaXQgY29uY2VybmVkIGFib3V0IHNvbWUgb2YgdGhlc2UgbGlicmFyeSBzaXplcwpwb3N0LWRlZHVwbGljYXRpb24uCgpMZXQgdXMgbG9vayBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVhZHMgYW5kIGR1cGxpY2F0aW9uLCB3aGljaCBJCmFzc3VtZSB3aWxsIGJlIHJlbGF0aXZlbHkgbGluZWFyLgoKYGBge3J9CnRlc3QgPC0gcERhdGEobW0zOF9oaXNhdF92MylbLCBjKCJoaXNhdGdlbm9tZXNpbmdsZWFsbCIsICJ1bWlkZWR1cHBjdHJlYWRzIildCnRlc3RfcGxvdCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKHRlc3QpCnRlc3RfcGxvdFtbInNjYXR0ZXIiXV0KYGBgCgpUaGVyZXNhIGFsc28gcHJvZHVjZWQgYSBkZW5zaXR5L3NhbXBsZSBwbG90LCB0aGF0IG1pZ2h0IHByb3ZlIHF1aXRlCnVzZWZ1bCBmb3IgdGhlc2UgZHVlIHRvIHRoZWlyIHNpZ25pZmljYW50bHkgbGFyZ2VyIHZhcmlhbmNlIGFjcm9zcwpzYW1wbGVzIChkdWUgdG8gZGVkdXBsaWNhdGlvbikuCgpgYGB7cn0KcGxvdF9kZW5zaXR5KG1tMzhfaGlzYXRfdjMpCmBgYAoKVGhlcmUgaXMgc29tZSBkaWZmZXJlbmNlIGFjcm9zcyBzYW1wbGUgZGVuc2l0aWVzLCBidXQgaXQgaXMgbm90IHRvbwpjcmF6eXRvd24uCgojIFBDQSBwbG90cwoKIyMgUENBIG9mIGFsbCBnZW5lcyBieSBsb2NhdGlvbgoKVGhlcmVzYSdzIGZpcnN0IHBjYSB3YXMgb2YgbG9nMiBjcG0gdmFsdWVzLiAgSSBtaWdodCBhZGQgcXVhbnRpbGUvdG1tCnRvIHRoaXM/CgpgYGB7cn0KdjNfbG9jYXRpb24gPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3YzLCBmYWN0ID0gImxvY2F0aW9uYXRiIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImdlbm90eXBlYXRiIikKCnYzX2xvY2F0aW9uX25vcm0gPC0gbm9ybWFsaXplX2V4cHQodjNfbG9jYXRpb24sIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iKQpwbG90X3BjYSh2M19sb2NhdGlvbl9ub3JtKQpgYGAKCk9uY2UgYWdhaW4gd2Ugc2VlIHRoYXQgc2FtcGxlcyBpcHJnY182NiBhbmQgaXByZ2NfMTMwIGFyZSBsaWtlbHkKYWN0dWFsbHkgRExHTiBhbmQgbm90IFNDTi4gIEkgYW0gdGhlcmVmb3JlIGdvaW5nIHRvIGFkZCBhIGNvbHVtbiB0bwp0aGUgc2FtcGxlIHNoZWV0IG5vdGluZyB0aGlzLCBhbmQgcmVtb3ZlIHRoZW0gZnJvbSB0aGUgZXhwcmVzc2lvbnNldC4KCkkgd2lsbCB0aHVzIHJlcGxvdCB0aGUgZGF0YSBhZnRlciByZW1vdmluZyB0aG9zZSB0d28uICBJZiB3ZSB3YW50IHRvCnNlZSB3aGF0IGl0IGxvb2tzIGxpa2Ugd2l0aCB0aGUgcmUtYXR0cmlidXRlZCBsb2NhdGlvbnMsIHdlIGNhbiBkbyBzby4KClRoZXJlc2EgaGFzIGEgbmljZSBjaGFuZ2UgdG8gdGhlIFBDQSBwbG90dGVyIGluIHdoaWNoIHNoZSBzZXRzIHRoZQphbHBoYSBjaGFubmVsIGFzIGFuIGFkZGl0aW9uYWwgdmlzdWFsIHF1ZXVlIGZvciBhIG1ldGFkYXRhIGZhY3Rvci4uLgoKYGBge3J9Cm1tMzhfaGlzYXRfdjMgPC0gc3Vic2V0X2V4cHQobW0zOF9oaXNhdF92Mywgc3Vic2V0PSJzYW1wbGVpZCE9J2lwcmdjXzEzMCciKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9InNhbXBsZWlkIT0naXByZ2NfNjYnIikKdjNfbG9jYXRpb24gPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3YzLCBmYWN0ID0gImxvY2F0aW9uYXRiIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gImdlbm90eXBlYXRiIikKdjNfbG9jYXRpb25fbm9ybSA8LSBub3JtYWxpemVfZXhwdCh2M19sb2NhdGlvbiwgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIpCnBsb3RfcGNhKHYzX2xvY2F0aW9uX25vcm0pCgpyZW1vdmVkX3NhbmtleSA8LSBwbG90X21ldGFfc2Fua2V5KHYzX2xvY2F0aW9uLCBjb2xvcl9jaG9pY2VzID0gY29sb3JfY2hvaWNlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JzID0gYygiZ2Vub3R5cGVhdGIiLCAibG9jYXRpb25hdGIiLCAidGltZWF0YiIpKQpyZW1vdmVkX3NhbmtleQpgYGAKCkhlcmUgaXMgVGhlcmVzYSdzIHRleHQsIHJlY2FsbCBvbmNlIGFnYWluIHRoYXQgSSBkbyBub3QgaGF2ZSBzb21lIG9mCnRoZXNlIG9sZGVyIHNhbXBsZXMgKGlwcmdjXzYyKToKClBDMSB2cyBQQzIgaWRlbnRpZmllcyByZXRpbmEgdnMgYXhvbiBpcyBzdGlsbCB0aGUgbWFpbiBjb21wb25lbnQgb2YKdmFyaWF0aW9uLiBXZSBkbyBzZWUgdGhvdWdoIHRoYXQgaW4gdGhlIFBDMiBkaXJlY3Rpb24sIHdlIHNlZSB3aXRoIHRoZQpuZXcgc2FtcGxlcyBhZGRlZCwgd2UgZG9u4oCZdCBzZWUgc2VwYXJhdGlvbiBiYXNlZCBvbiBheG9uYWwgdGFyZ2V0cwooZExHTiB2cyBTQ04pLiBJbiB0aGUgUEMxIHZzIFBDMyBwbG90LCB3ZSBzZWUgdGhhdCBpdOKAmXMgUEMzIHdoZXJlIHdlCnN0YXJ0IHRvIHNlZSB2YXJpYXRpb24gY29ycmVsYXRlZCB3aXRoIGF4b25hbCBjb21wYXJ0bWVudC4gTGV04oCZcyBsb29rCmF0IFBDMSB2cyBQQzIgY29sb3JlZCBieSBiYXRjaCAod2hlbiB0aGV5IHdlcmUgcHJvY2Vzc2VkL3NlcXVlbmNlZCkgdG8Kc2VlIGlmIHRoYXQgaXMgd2hhdCBpcyBjb250cmlidXRpbmcgc28gbXVjaCB2YXJpYXRpb24gaW4gUEMyLgoKU2lkZSBub3RlOiBpcFJHQyA2MiBzZWVtcyBsaWtlIGFuIG9kZCBiYWxsLiBUaGlzIHNlZW1zIHRvIG1lIGxpa2UgaXQKc2hvdWxkIGhhdmUgYmVlbiBhIGRMR04gUDA4IHNhbXBsZS4gSXMgdGhlcmUgYW55IHBvc3NpYmlsaXR5IHRoaXMgZ290Cm1pc2xhYmVsZWQgZWFybHkgb24/IEkgd2VudCBiYWNrIGFuZCBkb3VibGUgY2hlY2tlZCB0byBzZWUgaWYgYWxsIG15CnByb2Nlc3NpbmcgaXMgY29ycmVjdCBhbmQgaXQgaW5kZWVkIHdhcyBsYWJlbGVkIGFuIFNDTiBQMTUgZnJvbSB0aGUKdGltZSBJIGdvdCB0aGUgc2FtcGxlcywgYW5kIGl0IGlzIGluZGVlZC4KCiMgREUKCkkgbm93IHN3aXRjaGVkIHRvIFRoZXJlc2EncyBkb2N1bWVudCAnV09SS0lOR19heG9uVFJBUC4uLicgYW5kIHdpbGwKc3RhcnQgcHVsbGluZyBzZWN0aW9ucyBmcm9tIGl0LiAgSSBhbSByZWFzb25hYmx5IGNlcnRhaW4gSSBoYXZlCnJlYXNvbmFibHkgc2ltaWxhciBzYW1wbGUgZGlzdHJpYnV0aW9ucywgc28gSSBwcmVzdW1lIEkgY2FuIGludm9rZQpzaW1pbGFyL2lkZW50aWNhbCBjYWxscyBmb3IgREVTZXEgYW5kIGZyaWVuZHMuCgojIyBwOCByZXRpbmFzCgpJbiB0aGUgYmxvY2sgaW1tZWRpYXRlbHkgYmVmb3JlIHRoZSBERSBhbmFseXNlcywgVGhlcmVzYSBjcmVhdGVkIGEKc3Vic2V0IGV4cHJlc3Npb25zZXQgb2Ygb25seSBwMDggcmV0aW5hcy4gIFRodXMgdGhpcyBpbml0aWFsIERFIEkKYXNzdW1lIHdpbGwgYmUgdXNlZCB0byBzdWJ0cmFjdCBmb3IgdGhlIFNDTi9ETEdOIGFuYWx5c2VzIHRoYXQgZm9sbG93LgooSSBndWVzcyBJIGNvdWxkIHJlYWQgYWhlYWQgYW5kIGZpbmQgb3V0LCBidXQgbm8hIEkgd2FudCB0byBiZSBhCmJsYW5rIHNsYXRlKQoKVGhlcmVzYSdzIHByaW1hcnkgd29ya2Zsb3cgbWFrZXMgaGVhdnkgdXNlIG9mIERFU2VxMgooQGxvdmVNb2RlcmF0ZWRFc3RpbWF0aW9uRm9sZDIwMTQpIGFuZCBzdmEKKEBsZWVrU1ZBUGFja2FnZVJlbW92aW5nMjAxMikuICBJbiBzb21lKG1vc3Q/KSBvZiBUaGVyZXNhJ3MKaW52b2NhdGlvbnMgb2YgdGhlIGFsbF9wYWlyd2lzZSgpIGZ1bmN0aW9uLCBzaGUgZXhjbHVkZXMgdGhlIG90aGVyCm1ldGhvZHMgdGhhdCBpdCBwZXJmb3Jtcy4gIEluIHRoaXMgd29ya2Jvb2ssIEkgbGVmdCB0aG9zZSBtZXRob2RzIG9uLAp0aHVzIHdlIGNhbiBldmFsdWF0ZSB0aGUgcmVsYXRpdmUgcGVyZm9ybWFuY2UgREVTZXEyIHZzLiBzb21lIChhbGw/IEkKbWF5IGhhdmUgZGlzYWJsZWQgRUJTZXEvZHJlYW0gYmVjYXVzZSB0aGV5IHdlcmUgdGFraW5nIHRvbyBsb25nKQpvZiB0aGUgZm9sbG93aW5nOgoKKiBsaW1tYTogKEByaXRjaGllTGltbWFQb3dlcnNEaWZmZXJlbnRpYWwyMDE1KSAoYW1vbmcgb3RoZXIKICByZWZlcmVuY2VzKSBvcmlnaW5hbGx5IHdyaXR0ZW4gZm9yIG1pY3JvYXJyYXlzLgoqIEVkZ2VSOiAoQHJvYmluc29uRWRnZVJCaW9jb25kdWN0b3JQYWNrYWdlMjAxMCksIHdoaWNoIHNoYXJlcyBtYW55CiAgYXNzdW1wdGlvbnMgd2l0aCBERVNlcTIuCiogRUJTZXE6IChAbGVuZ0VCU2VxRW1waXJpY2FsQmF5ZXMyMDEzKSwgYmVjYXVzZSBJIGhhdmUgYSBzb2Z0IHNwb3QKICBmb3IgYW55IEJheWVzaWFuIG1ldGhvZC4KKiBOb2lzZXE6IChAdGFyYXpvbmFOT0lzZXFSTkFzZXFEaWZmZXJlbnRpYWwyMDExKSwgd2hpY2ggc2Vla3MgdG8KICBkaXJlY3RseSBtb2RlbCB2YXJpYW5jZSBpbiBhbiBSTkFTZXEgZGF0YXNldCBhbmQgdXNlIHRoYXQgdG8gaW1wcm92ZQogIHRoZSBzZW5zaXRpdml0eSBvZiB0aGUgcmVzdWx0LCBtdWNoIGxpa2U6CiogRHJlYW06IChAaG9mZm1hbkRyZWFtUG93ZXJmdWxEaWZmZXJlbnRpYWwyMDIwKSwgd3JpdHRlbiBieSB0aGUgc2FtZQogIGF1dGhvcnMgKGFuZCB1c2VzIHZlcnkgc2ltaWxhciBsb2dpYykgYXMgb25lIG9mIG15IGZhdm9yaXRlIHRvb2xzLAogIHZhcmlhbmNlUGFydGl0aW9uKEBob2ZmbWFuVmFyaWFuY2VQYXJ0aXRpb25JbnRlcnByZXRpbmdEcml2ZXJzMjAxNikuCgpgYGB7cn0KbW0zOF9wOF9yZXRpbmEgPC0gc3Vic2V0X2V4cHQobW0zOF9oaXNhdF92Mywgc3Vic2V0ID0gInRpbWVhdGI9PSdwMDgnICYgbG9jYXRpb25hdGI9PSdyZXRpbmEnIikKCm1tX25vcm1hbF9wOF9yZXRfZGUgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfcDhfcmV0aW5hLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9ub3JtYWxfcDhfcmV0X2RlCmBgYAoKVGhlIGZvbGxvd2luZyBpbnZvY2F0aW9uIHBlcmZvcm1lZCBieSBUaGVyZXNhIGZpbHRlcnMgdGhlIHd0L2hldApjb21wYXJpc29uIGZvciBvbmx5IHRob3NlIGdlbmVzIHdoaWNoIGluY3JlYXNlZCBieSBhdCBsZWFzdCAwLjI1IGxvZ0ZDCndpdGggYSBzaWduaWZpY2FudCBhZGp1c3RlZCBwLXZhbHVlLiAgSSBhc3N1bWUgdGhhdCB0aGlzIGlzIHRvIHVzZSB0aGUKd3Qgc2FtcGxlcyBhcyBhIHRyYW5zbGF0aW9uYWwgY29udHJvbCBmb3IgdGhlIGtldC9rbyBjb21wYXJpc29uczsgSSBhbQp0aGVyZWZvcmUgdGhpbmtpbmcgdGhhdCBmb3IgbXkgcHVycG9zZXMsIEkgd2lsbCB0aGVyZWZvcmUgc2VwYXJhdGUgdGhlCmNvbnRyYXN0cyBmcm9tIGFsbF9wYWlyd2lzZSBkbyB0aGlzIGluIGEgc3RlcHdpc2UgZmFzaGlvbi4uLgoKVGhlIGJsb2NrIG9mIGNvZGUgaW1tZWRpYXRlbHkgZm9sbG93aW5nIFRoZXJlc2EncyBhbGxfcGFpcndpc2UoKQppbnZvY2F0aW9uIGlzIGEgbGl0dGxlIGNvbmZ1c2luZyBmb3IgbWUgYW5kIHdhcnJhbnRzIHNvbWUgZXhwbGFuYXRpb24KYnkgbWUgdG8gbWUgaW4gdGhlIGhvcGVzIHRoYXQgSSBkbyBub3QgbWlzdW5kZXJzdGFuZCB3aGF0IGlzIGhhcHBlbmluZwphbmQgdGhlIGdvYWxzIHRoZXJlaW4uCgpJIHRoaW5rIEkgY2FuIHNhZmVseSBhc3N1bWUgdGhhdCB0aGUgZ29hbCBoZXJlIGlzIHRvIHB1bGwgb3V0IHRoZSBJRHMKd2hpY2ggaW5jcmVhc2VkIGluIGhldCB3aXRoIHJlc3BlY3QgdG8gd2lsZCB0eXBlOyBldmVuIGlmIGJ5IGEgc21hbGwKbWFyZ2luLCBhcyBsb25nIGFzIGl0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgdmlzIGEgdmlzIHRoZQphZGp1c3RlZCBwLXZhbHVlLgoKSSBhbSBnb2luZyB0byBwZXJmb3JtIHdoYXQgSSB0aGluayBpcyB0aGUgc2FtZSB0aGluZyBpbiBhIHNsaWdodGx5CmRpZmZlcmVudCBmYXNoaW9uIHNvIHRoYXQgSSBjYW4gc2hhcmUgYSBjb3B5IG9mIHRoZSByZXN1bHRzIHdpdGgKd2hvbWV2ZXIgaXMgaW50ZXJlc3RlZC4gIEkgd2lsbCBhbHNvIHJlcGVhdCBUaGVyZXNhJ3MgaW52b2NhdGlvbiBhbmQKcHJvdmUgdG8gbXlzZWxmIHRoYXQgSSB1bmRlcnN0b29kIGFuZCBnb3QgdGhlIHNhbWUgYW5zd2VyLgoKYGBge3J9Cnd0X2hldF9rZWVwZXIgPC0gbGlzdCgiaGV0X3ZzX3d0IiA9IGMoImhldHJldGluYSIsICJ3dHJldGluYSIpKQpoZXRfd3RfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMobW1fbm9ybWFsX3A4X3JldF9kZSwga2VlcGVycyA9IHd0X2hldF9rZWVwZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICJleGNlbC9oZXRfcmV0aW5hX2NvbnRyb2wueGxzeCIpCndhbnRlZF9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhoZXRfd3RfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZmMgPSAwLjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIikKCndhbnRlZF9oZXRfaW5jcmVhc2VkIDwtIHdhbnRlZF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImhldF92c193dCJdXQppbmNyZWFzZWRfaGV0X2dlbmVzIDwtIHJvd25hbWVzKHdhbnRlZF9oZXRfaW5jcmVhc2VkKQpgYGAKCkhlcmUgYXJlIFRoZXJlc2EncyBuZXh0IGxpbmVzOgoKYGBge3J9Cm1tX2RlX25vcm1hbF9wOF9yZXQgPC0gbW1fbm9ybWFsX3A4X3JldF9kZQpoZXRrZWVwZXJfZ2VuZXMgPC0gbW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJHd0cmV0aW5hX3ZzX2hldHJldGluYSAlPiUKICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKCmtva2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyR3dHJldGluYV92c19rb3JldGluYSAlPiUKICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKCmtlZXBlcmdlbmVzIDwtIHVuaXF1ZShjKHJvd25hbWVzKGhldGtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKGtva2VlcGVyX2dlbmVzKSkpCgojIyBXZSBrbm93IGEgcHJpb3JpIHRoYXQgT3BuNCBpcyBFTlNNVVNHMDAwMDAwMjE3OTkKIyMgSSBkbyBub3QgZXhwZWN0IHRvIHNlZSBpdCBpbiB0aGlzIHNldCwgaXQgc2hvdWxkIGJlIGhpZ2hlciBpbiB3dAojIyByZXRpbmEgdnMga28gcmV0aW5hIGJ5IGEgc2lnbmlmaWNhbnQgbWFyZ2luLgoiRU5TTVVTRzAwMDAwMDIxNzk5IiAlaW4lIGtlZXBlcmdlbmVzCiMjIE9vb29oaGggYnV0IGl0IF9pc18gaGlnaGVyIGluIGhldCB2cy4gd3QsIGFzIHdlIHNhdyBpbgojIyB0aGUgdmlvbGluIHBsb3QgZWFybGllci4KYGBgCgpJIHRoaW5rIFJhc2htaSBtYWRlIGEgY29tcGVsbGluZyBwb2ludCB3aGljaCBpbGx1c3RyYXRlcyB3aHkgd2UgbGlrZWx5CnNob3VsZCBleHBlY3QgdGhlIGV4cHJlc3Npb24gb2YgT3BuNCB0byBzaWduaWZpY2FudGx5IGhpZ2hlciBpbiB0aGUKaGV0ZXJvenlnb3RlcyB2cyB3aWxkLXR5cGU6CgoxLiAgUmVjYWxsIHRoYXQgdGhlIGFzc2F5IGlzIHVzaW5nIHRoZSBpbW11bm9wdXJpZmljYXRpb24gdG8gZXh0cmFjdAogICAgdGhlIFJOQXMuCjIuICBUaGUgd3Qgc2FtcGxlcyBkbyBub3QgaGF2ZSB0aGUgY3JlIHJlY29tYmluYXNlIGFuZCB0aGVyZWZvcmUgbm8gSEEKICAgIGFuZCB0aGVyZWZvcmUgZXZlcnl0aGluZyB3ZSBvYnNlcnZlIGlzIGR1ZSB0byBub24tc3BlY2lmaWMKICAgIGJpbmRpbmcuCjMuICBUaGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGR1ZSB0byBub24tc3BlY2lmaWMgYmluZGluZyBpcyBkaWZmZXJlbnQKICAgIHRoYW4gaGV0L2tvIChwcmVzdW1hYmx5IGEgbGFyZ2VyIG51bWJlciBvZiByZWxhdGl2ZWx5IHNtYWxsCiAgICB2YWx1ZXMpLCB0aGVyZWZvcmUgdGhlIGRpdmlzb3IgcGVyZm9ybWVkIGluIHRoZSBjcG0gaXMgbGlrZWx5CiAgICByZWxhdGl2bHkgbGFyZ2UgcmVzdWx0aW5nIGluIG5vcm1hbGl6ZWQgdmFsdWVzIGdldHRpbmcgc2hpZnRlZAogICAgZG93biB0byBzb21lIGRlZ3JlZS4KNC4gIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGluIGhldC9rbyBhcmUgbW9yZQogICAgbGlrZWx5IHRvIGJlIG9ubHkgdGhlIHNwZWNpZmljIGJpbmRlcnMgYW5kIHRoZXJlZm9yZSBzbWFsbGVyIChJCiAgICBjYW4gdGVzdCB0aGlzKSByZXN1bHRpbmcgaW4gYSBzbWFsbGVyIGRpdmlzb3IgYW5kIHNsaWdodCBzaGlmdGluZwogICAgdXAgaW4gdGhlIGNwbSB2YWx1ZXMuCgpUaGlzIG1ha2VzIG1lIHdvbmRlciBpZiBhbnkgbm9ybWFsaXphdGlvbiBtZXRob2RzIGV4aXN0IHdoaWNoIGRvCnNvbWV0aGluZyBsaWtlIG11bHRpcGx5IHRoZSB2YWx1ZXMgYnkgc29tZSB2YWx1ZSByZWxhdGVkIHRvIHRoZQpwcm9wb3J0aW9uIG9mIG9ic2VydmVkIGdlbmVzOyBhbmQvb3IgaWYgdGhpcyBpcyBhIGdvb2QvYmFkL2luZGlmZmVyZW50CmlkZWEuCgpBbHNvLCBqdXN0IGEgbm90ZSBmb3IgbWUgdG8gcmVtZW1iZXI6IFJQTDIyLCBub3QgUlBTMjIsIGZvciBzb21lCnJlYXNvbiBJIGtlZXAgdGhpbmtpbmcgdGhlIHNtYWxsIHN1YnVuaXQuCgojIyBQcm92ZSBJIHVuZGVyc3Rvb2QKCmBgYHtyfQpoZXRrZWVwZXJfZ2VuZXMgPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0cmV0aW5hX3ZzX2hldHJldGluYSAlPiUKICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKdGVzdHRoYXQ6OmV4cGVjdF90cnVlKG5yb3coaGV0a2VlcGVyX2dlbmVzKSA9PSBsZW5ndGgoaW5jcmVhc2VkX2hldF9nZW5lcykpCgp0YWFfa2VlcGVycyA8LSBzb3J0KHJvd25hbWVzKGhldGtlZXBlcl9nZW5lcykpCmF0Yl9rZWVwZXJzIDwtIHNvcnQoaW5jcmVhc2VkX2hldF9nZW5lcykKdGVzdHRoYXQ6OmV4cGVjdF9lcXVhbCh0YWFfa2VlcGVycywgYXRiX2tlZXBlcnMpCmBgYAoKWWF5ISBJIGNhbiByZWFkISAgTm93IGxldCB1cyByZXBlYXQgZm9yIHRoZSBLTyB2cyB3dAoKYGBge3J9Cnd0X2tvX2tlZXBlciA8LSBsaXN0KCJrb192c193dCIgPSBjKCJrb3JldGluYSIsICJ3dHJldGluYSIpKQprb193dF90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gd3Rfa29fa2VlcGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gImV4Y2VsL2tvX3JldGluYV9jb250cm9sLnhsc3giKQp3YW50ZWRfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoa29fd3RfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZmMgPSAwLjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIikKd2FudGVkX2tvX2luY3JlYXNlZCA8LSB3YW50ZWRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJrb192c193dCJdXQppbmNyZWFzZWRfa29fZ2VuZXMgPC0gcm93bmFtZXMod2FudGVkX2tvX2luY3JlYXNlZCkKYGBgCgpUaGUgbmV4dCB0aGluZyBwZXJmb3JtZWQgaW4gVGhlcmVzYSdzIGRvY3VtZW50IGlzIGEgdW5pcXVlKGNvbmNhdGVuYXRpb24gb2YKdGhlc2UgdHdvIGdlbmUgZ3JvdXBzKSwgdGh1cyBzdWNraW5nIHVwIGV2ZXJ5IGdlbmUgd2hpY2ggd2FzCnNpZ25pZmljYW50bHkgaGlnaGVyIGluIGVpdGhlciB0aGUga25vY2tvdXQgX29yXyBoZXRlcnp5b3VzIHNhbXBsZXMKd2l0aCByZXNwZWN0IHRvIHdpbGQtdHlwZS4KClRoaXMgd2FzIGZvbGxvd2VkIGJ5IGEgY291cGxlIG9mIG1lcmdlIG9wZXJhdGlvbnMgb2YgYSBsaXR0bGUgYml0IG9mCnRoZSBhbm5vdGF0aW9uIGRhdGE7IEkgYW0gbm90IHN1cmUgSSB1bmRlcnN0YW5kIHRoZSBnb2FsIHlldC4uLgoKSGVyZSBpcyBoZXIgY29kZS4gSSBjb3BpZWQgdGhlIGFubm90YXRpb24gJ21naV9zeW1ib2wnIGNvbHVtbiB0bwonZXh0ZXJuYWxfZ2VuZV9uYW1lJyBzbyB0aGF0IEkgbmVlZCBub3QgY2hhbmdlIGFueSBvZiBoZXIgY29kZS4gIEkgYW0KYXNzdW1pbmcgdGhpcyBpcyB0aGUgYXBwcm9wcmlhdGUgY29sdW1uIG9mIGludGVyZXN0LCBJIGRvIG5vdCBrbm93CnRoaXMgZm9yIGNlcnRhaW4sIGJ1dCBpdCBzZWVtcyBxdWl0ZSBsaWtlbHkuCgpXaGlsZSBJIGFtIGF0IGl0LCBoZXJlIGlzIHRoZSBzZXRfc2lnX2xpbW1hKCkgZnVuY3Rpb24gZnJvbSBUaGVyZXNhJ3MgaGVscGVycy5SCgpgYGB7cn0Kc2V0X3NpZ19saW1tYSA8LSBmdW5jdGlvbihsaW1tYV90YmwsIGZhY3RvcnMgPSBOVUxMKSB7CiAgaWYgKGlzLm51bGwoZmFjdG9ycykpIHsKICAgICNzZXQgc2lnbmlmaWNhbmNlIGZvciBwbG90dGluZyBjb2xvcnMKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gTkEKICAgIGxpbW1hX3RibFthYnMobGltbWFfdGJsJGxvZ0ZDKSA8IDEgfCBsaW1tYV90YmwkYWRqLlAuVmFsID4gLjA1LCAiU2lnbmlmaWNhbmNlIl0gPC0gIk5vdCBcbkVucmljaGVkIgogICAgbGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA+PSAxICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuVXByZWd1bGF0ZWQiCiAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDIDw9IC0xICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuRG93bnJlZ3VsYXRlZCIKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gZmFjdG9yKGxpbW1hX3RibCRTaWduaWZpY2FuY2UsIGxldmVscyA9IGMoIlVwcmVndWxhdGVkIiwgIkRvd25yZWd1bGF0ZWQiLCAgIk5vdCBcbkVucmljaGVkIikpCiAgfSBlbHNlIHsKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gTkEKICAgIGxpbW1hX3RibFthYnMobGltbWFfdGJsJGxvZ0ZDKSA8IDEgfCBsaW1tYV90YmwkYWRqLlAuVmFsID4gLjA1LCAiU2lnbmlmaWNhbmNlIl0gPC0gIk5vdCBcbkVucmljaGVkIgogICAgaWYobnJvdyhsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDID49IDEgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAuMDUsIF0pICE9IDApIHsKICAgICAgbGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA+PSAxICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtIGZhY3RvcnNbMV0KICAgIH0KICAgIGlmIChucm93KGxpbW1hX3RibFtsaW1tYV90YmwkbG9nRkMgPD0gLTEgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAuMDUsIF0pICE9IDApIHsKICAgICAgbGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA8PSAtMSAgJiBsaW1tYV90YmwkYWRqLlAuVmFsIDw9IC4wNSwgXVtbIlNpZ25pZmljYW5jZSJdXSA8LSBmYWN0b3JzWzJdCiAgICB9CiAgICBsaW1tYV90YmwkU2lnbmlmaWNhbmNlIDwtIGZhY3RvcihsaW1tYV90YmwkU2lnbmlmaWNhbmNlLCBsZXZlbHMgPSBjKGZhY3RvcnMsICAiTm90IFxuRW5yaWNoZWQiKSkKICB9CiAgcmV0dXJuKGxpbW1hX3RibCkKfQpgYGAKCiMjIyBDb21iaW5pbmcgaGV0L3d0IGFuZCBrby93dAoKYGBge3J9Cm1tX2Fubm90W1siZXh0ZXJuYWxfZ2VuZV9uYW1lIl1dIDwtIG1tX2Fubm90W1sibWdpX3N5bWJvbCJdXQprZWVwZXJnZW5lcyA8LSB1bmlxdWUoYyhyb3duYW1lcyhoZXRrZWVwZXJfZ2VuZXMpLCByb3duYW1lcyhrb2tlZXBlcl9nZW5lcykpKQpsZW5ndGgoa2VlcGVyZ2VuZXMpCgphbm5vdHNfdG9fbWVyZ2UgPC0gbW1fYW5ub3QgJT4lCiAgc2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgZXh0ZXJuYWxfZ2VuZV9uYW1lKSAlPiUKICBmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXMobW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvcmV0aW5hX3ZzX2hldHJldGluYSkpICU+JQogIGRpc3RpbmN0KCkKCm1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyRrb3JldGluYV92c19oZXRyZXRpbmEgPC0gbWVyZ2UoCiAgbW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvcmV0aW5hX3ZzX2hldHJldGluYSwgYW5ub3RzX3RvX21lcmdlLAogIGJ5LnggPSAwLCBieS55ID0gImVuc2VtYmxfZ2VuZV9pZCIsIGFsbC54ID0gVFJVRSkKCmRmIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyRrb3JldGluYV92c19oZXRyZXRpbmEgJT4lCiAgZHBseXI6Om11dGF0ZShsb2dGQyA9IC1sb2dGQykgJT4lCiAgc2V0X3NpZ19saW1tYShmYWN0b3JzID0gYygiSGV0IEVucmljaGVkIiwgIktPIEVucmljaGVkIikpCmBgYAoKTXkgdmVyc2lvbiBvZiB0aGUgYWJvdmUgdGFzayBtYWtlcyB1c2Ugb2YgdGhlIGV4Y2x1ZGVzIG9wdGlvbiBvZgpjb21iaW5lX2RlX3RhYmVzLiAgR2l2ZW4gdGhlIHNldCBvZiB1bmlxdWUgZ2VuZSBJRHMgaW5jcmVhc2VkIGluIHRoZQpoZXQva28sIEkgY2FuIGFzayB0byBleGx1ZGUgYW55dGhpbmcgbm90IGluIHRoYXQgc2V0LiAgSSBjb3VsZCBhbHNvCmhhdmUgbW9yZSBwYXJzaW1vbmlvdXNseSBkaXJlY3RseSBleGNsdWRlZCBhbnkgZ2VuZSBJRCBpbmNyZWFzZWQgaW4KdGhlIHd0IHNhbXBsZXMuICBCdXQsIFRoZXJlc2EgYWxyZWFkeSBwcm92aWRlZCB0aGUgY29kZSB0byBkbyB0aGUKZm9ybWVyLCBzbyBpdCB3aWxsIGJlIGxlc3MgdHlwaW5nL29wcG9ydHVuaXR5IGZvciBzaWxseSBtaXN0YWtlcyB0bwpqdXN0IGRvIHRoYXQuCgpgYGB7cn0KYm90aF9pbmNyZWFzZWRfZ2VuZXMgPC0gdW5pcXVlKGMoaW5jcmVhc2VkX2hldF9nZW5lcywgaW5jcmVhc2VkX2tvX2dlbmVzKSkKIyMgYXJiaXRyYWlybHkgZ3JhYiBhbGwgZ2VuZXMgZnJvbSBvbmUgb2YgbXkgZGF0YSBzdHJ1Y3R1cmVzLgphbGxfZ2VuZXMgPC0gcm93bmFtZXMoZXhwcnMobW0zOF9oaXNhdF92MykpCmV4Y2x1ZGVfaWR4IDwtIGFsbF9nZW5lcyAlaW4lIGJvdGhfaW5jcmVhc2VkX2dlbmVzCnN1bW1hcnkoZXhjbHVkZV9pZHgpCmV4Y2x1ZGVfaW5jcmVhc2VkX2dlbmVzIDwtIGFsbF9nZW5lc1tleGNsdWRlX2lkeF0KcmV0aW5hX2tlZXBlcnMgPC0gbGlzdCgKICAiaGV0X3ZzX3d0IiA9IGMoImhldHJldGluYSIsICJ3dHJldGluYSIpLAogICJrb192c193dCIgPSBjKCJrb3JldGluYSIsICJ3dHJldGluYSIpLAogICJrb192c19oZXQiID0gYygia29yZXRpbmEiLCAiaGV0cmV0aW5hIikpCgojIyBBIHJlbWluZGVyIHRvIG15c2VsZjogdGhlcmUgaXMgYWxzbyBhIHBhcmFtZXRlciAnd2FudGVkX2dlbmVzJwojIyB3aGljaCBkb2VzIGVmZmVjdGl2ZWx5IHRoZSBzYW1lIHRoaW5nIGFzIGV4Y2x1ZGVzIGluIHRoaXMgY29udGV4dDsKIyMgZXhjbHVkZXMgd2FzIG9yaWdpbmFsbHkgd3JpdHRlbiB0byBhbGxvdyBmbGV4aWJsZSwga2V5d29yZC1iYXNlZAojIyBleGNsdXNpb24uCnA4X3JldGluYV90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgbW1fbm9ybWFsX3A4X3JldF9kZSwga2VlcGVycyA9IHJldGluYV9rZWVwZXJzLAogIHdhbnRlZF9nZW5lcyA9IGJvdGhfaW5jcmVhc2VkX2dlbmVzLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCJleGNlbC9wOF9yZXRpbmFfa2VwdF9nZW5lc19pbmNyZWFzZWRfaW5fd3RfdGFibGVzLXZ7dmVyfS54bHN4IikpCnA4X3JldGluYV9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBwOF9yZXRpbmFfdGFibGVzLAogIGV4Y2VsID0gZ2x1ZSgiZXhjZWwvcDhfcmV0aW5hX2tlcHRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3NpZy12e3Zlcn0ueGxzeCIpLAogIGFjY29yZGluZ190byA9ICJkZXNlcSIpCgpvcHBvc2l0ZV9wOF9yZXRpbmFfdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX25vcm1hbF9wOF9yZXRfZGUsIGtlZXBlcnMgPSByZXRpbmFfa2VlcGVycywKICBleGNsdWRlcyA9IGJvdGhfaW5jcmVhc2VkX2dlbmVzLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCJleGNlbC9wOF9yZXRpbmFfcmVtb3ZlZF9nZW5lc19pbmNyZWFzZWRfaW5fd3RfdGFibGVzLXZ7dmVyfS54bHN4IikpCm9wcG9zaXRlX3A4X3JldGluYV9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBwOF9yZXRpbmFfdGFibGVzLAogIGV4Y2VsID0gZ2x1ZSgiZXhjZWwvcDhfcmV0aW5hX3JlbW92ZWRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3NpZy12e3Zlcn0ueGxzeCIpLAogIGFjY29yZGluZ190byA9ICJkZXNlcSIpCmBgYAoKIyBGaWx0ZXJpbmcgb3V0IG5vbi1zcGVjaWZpYyBnZW5lcyBhbmQgZXhhbWluaW5nIHRoZSByZXN1bHRzCgpUaGUgZm9sbG93aW5nIGlzIGEgY29weS9wYXN0ZSBmcm9tIFRoZXJlc2EgY29udGFpbmluZyB0aGUgcmVtYWluaW5nCnRhc2tzIHNoZSBwZXJmb3JtZWQgYW5kIHdpbGwgcHJvdmlkZSB0aGUgdGVtcGxhdGUgZm9yIGltcGxlbWVudGF0aW9uCm9mIHRoZSBmaW5hbCB0YXNrcy4KClRoaXMgcGlja3MgdXAgd2l0aCB0aGUgbGluZXMgZnJvbSBoZXIgbm90ZWJvb2sgaW1tZWRpYXRlbHkgZm9sbG93aW5nCnRoZSBpbnZvY2F0aW9uIG9mICdzZXRfc2lnX2xpbW1hKGZhY3RvcnMgPSBjKCJIZXQgRW5yaWNoZWQiIC4uLicuCgpGb3IgYWxsIG9mIHRoZSByZW1haW5pbmcgYmxvY2tzIEkgd2lsbCBjb3B5IGluIGhlciBjb2RlLCB0dXJuIG9mZiBpdHMKZXZhbHVhdGlvbiwgcnVuIHRoZSBibG9ja3MgbWFudWFsbHksIGNvbXBhcmUgdGhlbSB0byBoZXIgbm90ZWJvb2sKb3V0cHV0LCB0aGVuIGVuYWJsZSBlYWNoIGJsb2NrIGFzIEkgZW5zdXJlIEkgdW5kZXJzdGFuZCBpdC4KCkkgd2lsbCBsaWtlbHkgdGhlcmVmb3JlIGludHJvZHVjZSBzb21lIHNtYWxsIGZvcm1hdHRpbmcgY2hhbmdlcyBhbmQKYWRkIHNvbWUgYWRkaXRpb25hbCBHU0VBL2VucmljaG1lbnQgdGFza3Mgb25jZSB0aGUgbm9uLXNwZWNpZmljCmZpbHRlcmluZyBpcyBjb21wbGV0ZS4KCmBgYHtyfQpkZiA8LSBkZiAlPiUKICBmaWx0ZXIoUm93Lm5hbWVzICVpbiUga2VlcGVyZ2VuZXMpCgpsYWJlbHNfdXBzIDwtIGRmICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPiAxKSAlPiUKICBhcnJhbmdlKGxvZ0ZDKSAlPiUKICBoZWFkKG4gPSA5KQoKbGFiZWxzX2Rvd25zIDwtIGRmICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPiAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgaGVhZChuID0gMTEpCgpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQoKcmVzX3RibCA8LSBkZgpERXBsb3QgPC0gZ2dwbG90KHJlc190YmwsIGFlcyh4ID0gbG9nRkMsIHkgPSAtbG9nMTAoYWRqLlAuVmFsKSwgbGFiZWwgPSBleHRlcm5hbF9nZW5lX25hbWUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU2lnbmlmaWNhbmNlKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKC4wNSkpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDIwKSArCiAgeGxhYigibG9nMihGQykiKSArCiAgeWxhYigiLWxvZzEwKHAtdmFsdWUpIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0Y4NzY2RCIsICIjMDBCRkM0IiwgIkdyZXkiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoCiAgICBkYXRhID0gZmlsdGVyKGRmLAogICAgICAgICAgICAgICAgICAjIyBjKCdzNV9oZXRfZGxnbicsICdzNV9oZXRfcmV0JywgJ3M1X2hldF9zY24nKSksCiAgICAgICAgICAgICAgICAgIGV4dGVybmFsX2dlbmVfbmFtZSAlaW4lIGxhYmVscyRleHRlcm5hbF9nZW5lX25hbWUpLAogICAgIyMgbnVkZ2VfeCA9IC0wLjUsCiAgICBudWRnZV95ID0gMywgbWF4Lm92ZXJsYXBzID0gMTUpICsKICB4bGltKGMoLTMsIDYpKQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9wMDhfcmV0aW5hX0RFXzEzMTIwMjQuZXBzIikKREVwbG90CmRldi5vZmYoKQpERXBsb3QKCndyaXRleGw6OndyaXRlX3hsc3goZGYsIHBhdGggPSAiYXhvblRSQVBfREVfcmVzdWx0c18yMDI0MDIwMi9yZXRpbmFoZXRfdnNfcmV0aW5ha29fV1RmaWx0ZXJlZC54bHN4IikKYGBgCgojIyBIb3cgbWFueSB1cHMvZG93bnMKCmBgYHtyfQprb19lbnJpY2hlZCA8LSBkZiAlPiUKICBmaWx0ZXIoU2lnbmlmaWNhbmNlID09ICJLTyBFbnJpY2hlZCIpCm5yb3coa29fZW5yaWNoZWQpCgpoZXRfZW5yaWNoZWQgPC0gIGRmICU+JQogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIkhldCBFbnJpY2hlZCIpCm5yb3coaGV0X2VucmljaGVkKQpgYGAKCiMjIGNhdGVnb3J5IGVucmljaG1lbnQvR1NFQQoKYGBge3J9CmFsbGR5c3JlZ3VsYXRlZF9nZW5lcyA8LSByZXNfdGJsICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgYXJyYW5nZShsb2dGQykgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgbG9nRkMsIGFkai5QLlZhbCwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBTaWduaWZpY2FuY2UpICU+JQogIGZpbHRlcihhYnMobG9nRkMpID49IDEpCgojIyBnc2VhX3Jlc3VsdF9rbyA8LSBnb3N0KHF1ZXJ5ID0ga29fZ2VuZXMkZXh0ZXJuYWxfZ2VuZV9uYW1lLAojIyAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiMjICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUsCiMjICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUpCgpnc2VhX3Jlc3VsdF9oZXQgPC0gZ29zdChxdWVyeSA9IGhldF9lbnJpY2hlZCRleHRlcm5hbF9nZW5lX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKCmdzZWFfcmVzdWx0X2FsbGR5c3JlZ3VsYXRlZCA8LSBnb3N0KHF1ZXJ5ID0gYWxsZHlzcmVndWxhdGVkX2dlbmVzJGV4dGVybmFsX2dlbmVfbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQpgYGAKCkkgaGF2ZSBhIGZ1bmN0aW9uIGluIG15IHBhY2thZ2Ugd2hpY2ggc2Vla3MgdG8gbWFrZSBnUHJvZmlsZXIgcXVlcmllcwphIGJpdCBtb3JlIGNvbXBsZXRlIGFuZCBlYXN5LiAgTGV0IHVzIHNlZSBob3cgc2ltaWxhciB0aGUgcmVzdWx0IGlzLi4uCgpgYGB7cn0Kcm93bmFtZXMoYWxsZHlzcmVndWxhdGVkX2dlbmVzKSA8LSBhbGxkeXNyZWd1bGF0ZWRfZ2VuZXNbWyJSb3cubmFtZXMiXV0KYWxsZHlzcmVndWxhdGVkX2dlbmVzW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKCmhldF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHJvd25hbWVzKGFsbGR5c3JlZ3VsYXRlZF9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWNpZXMgPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlKCJleGNlbC9oZXRfZ3Byb2ZpbGVyLXZ7dmVyfS54bHN4IikpCmhldF9ncAplbnJpY2hwbG90Ojpkb3RwbG90KGhldF9ncFtbIkdPX2VucmljaCJdXSkKZ3BfcGFpciA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKGhldF9ncFtbIkdPX2VucmljaCJdXSkKZW5yaWNocGxvdDo6ZW1hcHBsb3QoZ3BfcGFpcikKZW5yaWNocGxvdDo6c3NwbG90KGdwX3BhaXIpCmVucmljaHBsb3Q6OnRyZWVwbG90KGdwX3BhaXIpCnVwc2V0cGxvdChoZXRfZ3BbWyJHT19lbnJpY2giXV0pCgplbnJpY2hwbG90Ojpkb3RwbG90KGhldF9ncFtbIlJFQUNfZW5yaWNoIl1dKQpncF9wYWlyIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oaGV0X2dwW1siUkVBQ19lbnJpY2giXV0pCmVucmljaHBsb3Q6OmVtYXBwbG90KGdwX3BhaXIpCmVucmljaHBsb3Q6OnNzcGxvdChncF9wYWlyKQplbnJpY2hwbG90Ojp0cmVlcGxvdChncF9wYWlyKQp1cHNldHBsb3QoaGV0X2dwW1siUkVBQ19lbnJpY2giXV0pCmBgYAoKSSBtYWtlIGEgc29tZXdoYXQgYXJiaXRyYXJ5IGRpc3RpbmN0aW9uIGJldHdlZW4gdGhlIGNvbmNlcHRzIG9mCm92ZXItZW5yaWNobWVudCBhbmFseXNlcyBhbmQgR1NFQTogdGhlIGZvcm1lciAoYXMgcGVyZm9ybWVkIGJ5Cmdwcm9maWxlcikgKEByYXVkdmVyZVByb2ZpbGVyV2ViU2VydmVyMjAxOSkgc2Vla3MgdG8gZmluZCBncm91cHMgb2YKZ2VuZXMgb3ZlcnJlcHJlc2VudGVkIGluIEdPL3JlYWN0b21lL2V0Yy4gIFRoZXNlIGdyb3VwcyBvZiBnZW5lcyBhcmUKdGFrZW4gZXhjbHVzaXZlbHkgZnJvbSB0aGUgdG9wLW4vYm90dG9tLW4gZ2VuZXMgd2l0aCByZXNwZWN0IHRvCmZvbGQtY2hhbmdlIGJldHdlZW4gY29uZGl0aW9ucyBvZiBpbnRlcmVzdDsgaW4gdGhpcyBjYXNlIG1vc3QKZGlmZmVyZW50IHRoYW4gd3QgaW4gdGhlIHAwOCByZXRpbmEga28gb3IgaGV0IHNhbXBsZXMuCgpXaXRoIHRoYXQgaW4gbWluZCwgSSBjYW4gaW52b2tlIGEgc2ltaWxhciBmdW5jdGlvbiB1c2luZyB0aGUgZnVsbAp0YWJsZSBvZiBERSByZXN1bHRzIHRvIGdldCB3aGF0IEkgY2FsbCB0aGUgR1NFQSByZXN1bHQgdXNpbmcKY2x1c3RlclByb2ZpbGVyIChAeXVJbnRyb2R1Y3Rpb25CaW9tZWRpY2FsS25vd2xlZGdlKS4gIEluIHRoZQpmb2xsb3dpbmcgYmxvY2sgSSB3aWxsIHVzZSB0aGUgJ2FsbF9jcHJvZmlsZXInIGZ1bmN0aW9uIG9uIHRoZSBkYXRhCnN0cnVjdHVyZXMgbmFtZWQgJ3A4X3JldGluYV90YWJsZXMnIGFuZCAnb3Bwb3NpdGVfcDhfcmV0aW5hX3RhYmxlcycgaW4Kb3JkZXIgdG8gZ2V0IHRoZXNlIEdTRUEgcmVzdWx0cyBmb3IgZWFjaCBjb250cmFzdCBwZXJmb3JtZWQgKGhldC93dCwKa28vd3QsIGhldC9rbykuICBJIHdpbGwgZm9sbG93IHRoYXQgdXAgd2l0aCAnYWxsX2dwcm9maWxlcicgd2hpY2ggZG9lcwp0aGUgc2FtZSwgYnV0IHVzZXMgZ1Byb2ZpbGVyJ3MgZW5yaWNobWVudCBhbmFseXNlcyAoaXQgd2lsbCB0aGVyZWZvcmUKaW5jbHVkZSB3aGF0IHdlIGp1c3QgbG9va2VkIGF0KS4KCmBgYHtyfQpwMDhfcmV0aW5hX2FsbF9jcCA8LSBhbGxfY3Byb2ZpbGVyKHA4X3JldGluYV9zaWcsIHA4X3JldGluYV90YWJsZXMsIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIpCgplbnJpY2hwbG90Ojpkb3RwbG90KHAwOF9yZXRpbmFfYWxsX2NwW1sia29fdnNfaGV0X3VwIl1dW1siZW5yaWNoX29iamVjdHMiXV1bWyJNRl9hbGwiXV0pCgpwMDhfdG9wbl9nc2VhIDwtIHBsb3RfdG9wbl9nc2VhKHAwOF9yZXRpbmFfYWxsX2NwKQpwcChmaWxlID0gImltYWdlcy9nc2VhX3AwOF9yZXRpbmFfa29fdnNfaGV0X3RvcF9oaXQucG5nIikKcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbMV1dCmRldi5vZmYoKQpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1sxXV0KcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbMl1dCnAwOF90b3BuX2dzZWFbWyJHT19rb192c19oZXRfdXAiXV1bWzNdXQpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1s0XV0KcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbNV1dCmBgYAoKYGBge3J9CiNnc2VhX2tvIDwtICBnc2VhX3Jlc3VsdF9rb1tbInJlc3VsdCJdXSAlPiUKIyAgICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKIyAgICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiMgICAgaGVhZChuID0gMTApCiMgIGdzZWFfcGxvdHNfa28gPC0gZ2dwbG90KGdzZWFfa28sIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwojICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiMgIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwojICB0aGVtZV9idygpKwojICB5bGFiKCIiKSArCiMgIHhsYWIoIkdTRUEgU2NvcmUiKQoKZ3NlYV9oZXQgPC0gIGdzZWFfcmVzdWx0X2hldFtbInJlc3VsdCJdXSAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgaGVhZChuID0gMTApCmdzZWFfcGxvdHNfaGV0IDwtIGdncGxvdChnc2VhX2hldCwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpnc2VhX2FsbCA8LSAgZ3NlYV9yZXN1bHRfYWxsZHlzcmVndWxhdGVkW1sicmVzdWx0Il1dICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBoZWFkKG4gPSAxMCkKZ3NlYV9wbG90c19hbGwgPC0gZ2dwbG90KGdzZWFfYWxsLCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIiIpICsKICB4bGFiKCJHU0VBIFNjb3JlIikKCnNldEVQUygpCnBvc3RzY3JpcHQoZmlsZSA9ICJheG9uVFJBUF9Wb2xjYW5vcGxvdHNfMjAyNDAyMDIvR1NFQV9wMDhfYXhvbnRyYXBfcmV0aW5haGV0X3VwcmVndWxhdGVkX3ZzX3JldGluYWtvLmVwcyIpCmdzZWFfcGxvdHNfaGV0CmRldi5vZmYoKQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9HU0VBX3AwOF9yZXRpbmFfYXhvbnRyYXBfYWxsZHlzcmVndWxhdGVkZ2VuZXMuZXBzIikKZ3NlYV9wbG90c19hbGwKZGV2Lm9mZigpCmBgYAoKIyBTQ04gSGV0IHZzIEtPCgpJdCBpcyBvbmx5IG5vdyB0aGF0IEkgcmVhbGl6ZWQgd2UgYXJlIHNwbGl0dGluZyB0aGUgZGF0YSBieSBsb2NhdGlvbgpmb3IgZWFjaCBzZXQgb2YgY29tcGFyaXNvbnMuICBJIHRoaW5rIHRoYXQsIGxlZnQgdG8gbXkgb3duIGRldmljZXMsIEkKd291bGQgcHJlZmVyIHRvIGtlZXAgdGhlIGlucHV0IGRhdGEgc3RydWN0dXJlIGludGFjdCwgcGVyZm9ybSB0aGUKc29tZXdoYXQgbGFyZ2VyIG51bWJlciBvZiBjb250cmFzdHMsIGFuZCB0aGVuIHNwbGl0IHVwIHRoZSByZXN1bHRzLgpJZGVhbGx5IHRoaXMgd2lsbCBzbGlnaHRseSBpbXByb3ZlIHRoZSBmaWRlbGl0eSBvZiB0aGUgcmVzdWx0cwpyZXR1cm5lZCBieSBERVNlcTIgYW5kIGZyaWVuZHMuICBCdXQsIEkgd2lsbCBydW4gdGhlIHN0YXRlIG9mClRoZXJlc2EncyBub3RlYm9vayB3aXRoIGFzIGZldyBjaGFuZ2VzIGFzIHBvc3NpYmxlIGZpcnN0LCB0aGVuIGFkZAp0aGlzLgoKIyMgUENBCgpJIGFtIGdvaW5nIHRvIHNraXAgdGhpcyBQQ0EgcGxvdCBmb3IgYSBjb3VwbGUgb2YgcmVhc29uczogSSBhbHJlYWR5CmRpZCBhIHN1cGVyc2V0IG9mIGl0LCBhbmQgdGhlIHN1YnNldCBUaGVyZXNhIHBlcmZvcm1lZCBpcyBub3QgdmFsaWQKZ2l2ZW4gdGhlIHNldCBvZiBzYW1wbGVzIGluY2x1ZGVkIGluIG15IHNhbXBsZSBzaGVldCwgYW5kIGZpZ3VyaW5nIG91dAp0aGUgYWN0dWFsbHkgY29ycmVzcG9uZGluZyBzdWJzZXQgd2lsbCB0YWtlIG1lIGZvcmV2ZXIuLi4gIEluCmFkZGl0aW9uLCBJIHdhbnQgdG8gdXNlIG15IG1tMzhfaGlzYXRfdjMgZm9yIGV2ZXJ5dGhpbmcuLi4KCmBgYHtyLCBldmFsPUZBTFNFfQptbTM4X3N1YnNldCA8LSBzdWJzZXRfZXhwdCgKICBtbTM4X2hpc2F0LAogIHN1YnNldCA9ICIoYmF0Y2ggPT0gJzQnIHwgYmF0Y2ggPT0gJzUnIHwgYmF0Y2ggPT0gJzYnKSAmIHRpbWUgPT0gJ3AwOCcgJiBsb2NhdGlvbiA9PSAnc2NuJyB8IHNhbXBsZWlkID09ICdpcHJnY18wMyciKQoKbW0zOF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KG1tMzhfc3Vic2V0LCBmaWx0ZXIgPSBUUlVFLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCgptbTM4X25vcm0gPC0gc2V0X2V4cHRfYmF0Y2hlcyhtbTM4X25vcm0sIGZhY3QgPSAibG9jYXRpb24iKQptbTM4X25vcm0gPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtbTM4X25vcm0sIGZhY3QgPSAiZ2Vub3R5cGUiKQpwY2Ffbm9ybSA8LSBwbG90X3BjYShtbTM4X25vcm0sIG1heF9vdmVybGFwcyA9IDcwKQpwY2Ffbm9ybSRwbG90CmBgYAoKSW5zdGVhZCBJIHdpbGwgc2ltcGxpZnkgdGhlIHN1YnNldCBhbmQgc2VlIHdoYXQgaGFwcGVucy4uLgoKYGBge3J9CnNjbl9zYW1wbGVzIDwtIHN1YnNldF9leHB0KG1tMzhfaGlzYXRfdjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldCA9ICJsb2NhdGlvbmF0YiA9PSAnc2NuJyIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJsb2NhdGlvbmF0YiIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vdHlwZWF0YiIpCgpzY25fbm9ybSA8LSBub3JtYWxpemVfZXhwdChzY25fc2FtcGxlcywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCnNjbl9ub3JtX3BjYSA8LSBwbG90X3BjYShzY25fbm9ybSkKc2NuX25vcm1fcGMKYGBgCgojIERpdmVyZ2luZyBhIGxpdHRsZQoKQXQgdGhpcyBwb2ludCBpbiB0aGUgZG9jdW1lbnQgSSByZWFkIGFoZWFkIGEgYml0IGFuZCBjYW1lIHRvIHRoZQpjb25jbHVzaW9uIHRoYXQgaXQgcmVwZWF0cyB0aGUgYWJvdmUgbG9naWMgb2YgdGFraW5nIHRoZSB1bmlvbiBvZiB3dApjb21wYXJpc29ucyB0byByZW1vdmUgZ2VuZXMgZnJvbSB0aGUgYXBwcm9wcmlhdGUgaGV0L2tvIG9yIHAxNS9wMDggb3IKbG9jYXRpb24gY29tcGFyaXNvbnMuICBUaGlzIHNlZW1zIHF1aXRlIHJlYXNvbmFibGUgdG8gbWUsIGJ1dCBJIHdvdWxkCnByZWZlciB0byBub3Qgc2VwYXJhdGUgYWxsIHRoZSBkYXRhLCBzbyBJIHdpbGwgYXR0ZW1wdCB0byBkdXBsaWNhdGUKYW5kIHNsaWdodGx5IHN0cmVhbWxpbmUgdGhpcyBsb2dpYyBvbiB0aGUgZnVsbCBkYXRhc2V0LiAgVGh1cyBJIGFtCmdvaW5nIHRvIHNraXAgZG93biB0byB0aGUgZW5kIGFuZCBhdHRlbXB0IHRvIGltcGxlbWVudCB0aGlzLgoKIyMgREUKCmBgYHtyLCBldmFsPUZBTFNFfQptbV9kZV9ub3JtYWxfcDhfc2NuIDwtIGFsbF9wYWlyd2lzZShtbTM4X3N1YnNldCwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWwgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwgZG9fYmFzaWMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fZHJlYW0gPSBGQUxTRSwgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2VkZ2VyID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUpCgphbm5vdHNfdG9fbWVyZ2UgPC0gbW1fYW5ub3QgJT4lCiAgc2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgZXh0ZXJuYWxfZ2VuZV9uYW1lKSAlPiUKICBmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXMobW1fZGVfbm9ybWFsX3A4X3NjbiRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2hldHNjbikpICU+JQogIGRpc3RpbmN0KCkKCm1tX2RlX25vcm1hbF9wOF9zY24kZGVzZXEkYWxsX3RhYmxlcyRrb3Njbl92c19oZXRzY24gPC0gbWVyZ2UoCiAgbW1fZGVfbm9ybWFsX3A4X3NjbiRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2hldHNjbiwKICBhbm5vdHNfdG9fbWVyZ2UsIGJ5LnggPSAwLCBieS55ID0gImVuc2VtYmxfZ2VuZV9pZCIsIGFsbC54ID0gVFJVRSkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KaGV0a2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9zY24kZGVzZXEkYWxsX3RhYmxlcyR3dHNjbl92c19oZXRzY24gJT4lCiAgZmlsdGVyKGxvZ0ZDIDw9IC0uMSAmIGFkai5QLlZhbCA8PSAwLjA1KQoKa29rZWVwZXJfZ2VuZXMgPC0gbW1fZGVfbm9ybWFsX3A4X3NjbiRkZXNlcSRhbGxfdGFibGVzJHd0c2NuX3ZzX2tvc2NuICU+JQogIGZpbHRlcihsb2dGQyA8PSAtLjEgJiBhZGouUC5WYWwgPD0gMC4wNSkKCmtlZXBlcmdlbmVzIDwtIHVuaXF1ZShjKHJvd25hbWVzKGhldGtlZXBlcl9nZW5lcyksIHJvd25hbWVzKGtva2VlcGVyX2dlbmVzKSkpCgpkZiA8LSBtbV9kZV9ub3JtYWxfcDhfc2NuJGRlc2VxJGFsbF90YWJsZXMka29zY25fdnNfaGV0c2NuICU+JQogIGRwbHlyOjptdXRhdGUobG9nRkMgPSAtbG9nRkMpICU+JQogIHNldF9zaWdfbGltbWEoZmFjdG9ycyA9IGMoIkhldCBFbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS08gRW5yaWNoZWQiKSkKCmRmIDwtIGRmICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSBrZWVwZXJnZW5lcykKCmxhYmVsc191cHMgPC0gZGYgJT4lCiAgZmlsdGVyKGFicyhsb2dGQykgPiAxKSAlPiUKICBhcnJhbmdlKGxvZ0ZDKSAlPiUKICBoZWFkKG4gPSAxKQoKbGFiZWxzX2Rvd25zIDwtIGRmICU+JQogIGZpbHRlcihhYnMobG9nRkMpID4gMSkgJT4lCiAgYXJyYW5nZSgtbG9nRkMpICU+JQogIGhlYWQobiA9IDEpCgpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQoKcmVzX3RibCA8LSBkZgpERXBsb3QgPC0gZ2dwbG90KHJlc190YmwsIGFlcyh4ID0gbG9nRkMsIHkgPSAtbG9nMTAoYWRqLlAuVmFsKSwgbGFiZWwgPSBleHRlcm5hbF9nZW5lX25hbWUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU2lnbmlmaWNhbmNlKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLDEpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKC4wNSkpICsKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDIwKSArCiAgeGxhYigibG9nMihGQykiKSArCiAgeWxhYigiLWxvZzEwKHAtdmFsdWUpIikgKwogICMjIGdndGl0bGUodGl0bGUsIHN1YnRpdGxlID0gc3VidGl0bGUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiSGV0IEVucmljaGVkIiA9ICIjRjg3NjZEIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIktPIEVucmljaGVkIiA9ICIjMDBCRkM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdFxuIEVucmljaGVkIiA9ICJHcmV5IikpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKGRmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMgYygnczVfaGV0X2RsZ24nLCAnczVfaGV0X3JldCcsICdzNV9oZXRfc2NuJykpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0ZXJuYWxfZ2VuZV9uYW1lICVpbiUgbGFiZWxzJGV4dGVybmFsX2dlbmVfbmFtZSksCiAgICAgICAgICAgICAgICAgICAjIyBudWRnZV94ID0gLTAuNSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAzLCBtYXgub3ZlcmxhcHMgPSAxNSkgKwogIGdndGl0bGUoIlNDTiBIZXQgdnMgS08gVHJhbnNsYXRvbWUiKQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9wMDhfc2NuX0RFXzEzMTIwMjQuZXBzIikKREVwbG90CmRldi5vZmYoKQoKd3JpdGV4bDo6d3JpdGVfeGxzeChkZiwgcGF0aCA9ICJheG9uVFJBUF9ERV9yZXN1bHRzXzIwMjQwMjAyL3NjbmhldF92c19zY25rb19XVGZpbHRlcmVkLnhsc3giKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3IsIGV2YWw9RkFMU0V9CmtvX2VucmljaGVkIDwtIGRmICU+JQogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIktPIEVucmljaGVkIikKCmhldF9lbnJpY2hlZCA8LSBkZiAlPiUKICBmaWx0ZXIoU2lnbmlmaWNhbmNlID09ICJIZXQgRW5yaWNoZWQiKQpgYGAKCiMjIEdTRUEKCmBgYHtyLCBldmFsPUZBTFNFfQprb19nZW5lcyA8LSByZXNfdGJsICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgYXJyYW5nZSgtYWJzKGxvZ0ZDKSkgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgbG9nRkMsIGFkai5QLlZhbCwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBTaWduaWZpY2FuY2UpICU+JQogIGZpbHRlcihsb2dGQyA8PSAtMSkKCmhldF9nZW5lcyA8LSByZXNfdGJsICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgJT4lCiAgYXJyYW5nZSgtYWJzKGxvZ0ZDKSkgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgbG9nRkMsIGFkai5QLlZhbCwgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBTaWduaWZpY2FuY2UpICU+JQogIGZpbHRlcihsb2dGQyA+PSAxKQoKYWxsZHlzcmVndWxhdGVkX2dlbmVzIDwtIHJlc190YmwgJT4lCiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSAlPiUKICBhcnJhbmdlKGxvZ0ZDKSAlPiUKICBzZWxlY3QoUm93Lm5hbWVzLCBsb2dGQywgYWRqLlAuVmFsLCBleHRlcm5hbF9nZW5lX25hbWUsIFNpZ25pZmljYW5jZSkgJT4lCiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMSkKCmdzZWFfcmVzdWx0X2tvIDwtIGdvc3QocXVlcnkgPSBrb19nZW5lcyRleHRlcm5hbF9nZW5lX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKCmdzZWFfcmVzdWx0X2hldCA8LSBnb3N0KHF1ZXJ5ID0gaGV0X2dlbmVzJGV4dGVybmFsX2dlbmVfbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgZXZjb2RlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWRfcXVlcnkgPSBUUlVFKQoKZ3NlYV9yZXN1bHRfYWxsZHlzcmVndWxhdGVkIDwtIGdvc3QocXVlcnkgPSBhbGxkeXNyZWd1bGF0ZWRfZ2VuZXMkZXh0ZXJuYWxfZ2VuZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CmdzZWFfa28gPC0gIGdzZWFfcmVzdWx0X2tvW1sicmVzdWx0Il1dICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBoZWFkKG4gPSAxMCkKZ3NlYV9wbG90c19rbyA8LSBnZ3Bsb3QoZ3NlYV9rbywgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpnc2VhX2hldCA8LSAgZ3NlYV9yZXN1bHRfaGV0W1sicmVzdWx0Il1dICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBoZWFkKG4gPSAxMCkKZ3NlYV9wbG90c19oZXQgPC0gZ2dwbG90KGdzZWFfaGV0LCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIiIpICsKICB4bGFiKCJHU0VBIFNjb3JlIikKCmdzZWFfYWxsIDwtICBnc2VhX3Jlc3VsdF9hbGxkeXNyZWd1bGF0ZWRbWyJyZXN1bHQiXV0gJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGhlYWQobiA9IDEwKQpnc2VhX3Bsb3RzX2FsbCA8LSBnZ3Bsb3QoZ3NlYV9hbGwsIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIkdTRUEgU2NvcmUiKQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9HU0VBX3AwOF9yZXRpbmFfYXhvbnRyYXBfYWxsZHlzcmVndWxhdGVkZ2VuZXMuZXBzIikKZ3NlYV9wbG90c19hbGwKZGV2Lm9mZigpCmBgYAoKIyBIZXQgUmV0aW5hIHZzIEhldCBTQ04KCmBgYHtyLCBldmFsPUZBTFNFfQptbTM4X3N1YnNldDIgPC0gc3Vic2V0X2V4cHQoCiAgbW0zOF9oaXNhdCwKICBzdWJzZXQgPSAiKGJhdGNoID09ICc0JyB8IGJhdGNoID09ICc1JyB8IGJhdGNoID09ICc2JykgJiB0aW1lID09ICdwMDgnICAmIGdlbm90eXBlICE9ICdrbycgJiBsb2NhdGlvbiAhPSAnZGxnbicgfCBzYW1wbGVpZCA9PSAnaXByZ2NfMDMnIikKCm1tMzhfc3Vic2V0MiA8LSBzdWJzZXRfZXhwdChtbTM4X3N1YnNldDIsIHN1YnNldCA9ICJzYW1wbGVpZCAhPSAnaXByZ2NfODknIikKbW0zOF9zdWJzZXQyJGRlc2lnbiAlPiUKICBzZWxlY3QoZ2Vub3R5cGUsIGxvY2F0aW9uKSAlPiUKICB0YWJsZSgpCm1tMzhfbm9ybTIgPC0gbm9ybWFsaXplX2V4cHQobW0zOF9zdWJzZXQyLCBmaWx0ZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCmBgYAoKIyMgUENBCgpgYGB7ciwgZXZhbD1GQUxTRX0KbW0zOF9ub3JtMiA8LSBzZXRfZXhwdF9iYXRjaGVzKG1tMzhfbm9ybTIsIGZhY3QgPSAibG9jYXRpb24iKQptbTM4X25vcm0yIDwtIHNldF9leHB0X2NvbmRpdGlvbnMobW0zOF9ub3JtMiwgZmFjdCA9ICJnZW5vdHlwZSIpCnBjYV9ub3JtMiA8LSBwbG90X3BjYShtbTM4X25vcm0yLCBtYXhfb3ZlcmxhcHMgPSA3MCkKcGNhX25vcm0yJHBsb3QKYGBgCgojIyBERQoKYGBge3IsIGV2YWw9RkFMU0V9Cm1tX2RlX3N1YnNldDIgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfc3Vic2V0MiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFLCBkb19lYnNlcT1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fYmFzaWMgPSBGQUxTRSwgZG9fZHJlYW0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2VkZ2VyID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CnJldGluYWtlZXBlcl9nZW5lcyA8LSBtbV9kZV9zdWJzZXQyJGRlc2VxJGFsbF90YWJsZXMkd3RyZXRpbmFfdnNfaGV0cmV0aW5hICU+JQogIGZpbHRlcihsb2dGQyA8PSAtLjEgJiBhZGouUC5WYWwgPD0gMC4wNSkKCnNjbmtlZXBlcl9nZW5lcyA8LSBtbV9kZV9zdWJzZXQyJGRlc2VxJGFsbF90YWJsZXMkd3RzY25fdnNfaGV0c2NuICU+JQogIGZpbHRlcihsb2dGQyA8PSAtLjEgJiBhZGouUC5WYWwgPD0gMC4wNSkKCmtlZXBlcmdlbmVzIDwtIHVuaXF1ZShjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksIHJvd25hbWVzKHNjbmtlZXBlcl9nZW5lcykpKQoKYW5ub3RzX3RvX21lcmdlIDwtIG1tX2Fubm90ICU+JQogIHNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGV4dGVybmFsX2dlbmVfbmFtZSkgJT4lCiAgZmlsdGVyKGVuc2VtYmxfZ2VuZV9pZCAlaW4lIHJvd25hbWVzKG1tX2RlX3N1YnNldDIkZGVzZXEkYWxsX3RhYmxlcyRoZXRzY25fdnNfaGV0cmV0aW5hKSkgJT4lCiAgZGlzdGluY3QoKQoKbW1fZGVfc3Vic2V0MiRkZXNlcSRhbGxfdGFibGVzJGhldHNjbl92c19oZXRyZXRpbmEgPC0gbWVyZ2UoCiAgbW1fZGVfc3Vic2V0MiRkZXNlcSRhbGxfdGFibGVzJGhldHNjbl92c19oZXRyZXRpbmEsCiAgYW5ub3RzX3RvX21lcmdlLCBieS54ID0gMCwKICBieS55ID0gImVuc2VtYmxfZ2VuZV9pZCIsIGFsbC54ID0gVFJVRSkKCmRmIDwtIG1tX2RlX3N1YnNldDIkZGVzZXEkYWxsX3RhYmxlcyRoZXRzY25fdnNfaGV0cmV0aW5hICU+JQogIG11dGF0ZShTaWduaWZpY2FuY2UgPSBjYXNlX3doZW4obG9nRkMgPD0gLTEgfiAiUmV0aW5hIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID49IDEgfiAiU0NOIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID4gLTEgJiBsb2dGQyA8IDEgfiAiTm90XG4gRW5yaWNoZWQiKSkKCmRmIDwtIGRmICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSBrZWVwZXJnZW5lcykKCnNjbl9lbnJpY2hlZCA8LSBkZiAlPiUKICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA+PSAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsKSAlPiUKICBtdXRhdGUoU2lnbmlmaWNhbmNlID0gIlNDTiBFbnJpY2hlZCIpICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSByb3duYW1lcyhzY25rZWVwZXJfZ2VuZXMpKQoKcmV0aW5hX2VucmljaGVkIDwtIGRmICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGxvZ0ZDIDw9IC0xKSAlPiUKICBhcnJhbmdlKGxvZ0ZDKSAgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsKSAlPiUKICBtdXRhdGUoU2lnbmlmaWNhbmNlID0gIlJldGluYSBFbnJpY2hlZCIpICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSByb3duYW1lcyhyZXRpbmFrZWVwZXJfZ2VuZXMpKQoKbm90ZW5yaWNoZWQgPC0gZGYgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSBjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSlbZHVwbGljYXRlZChjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKHNjbmtlZXBlcl9nZW5lcykpKV0pICU+JQogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIk5vdFxuIEVucmljaGVkIikKCmRmIDwtIHJiaW5kKHNjbl9lbnJpY2hlZCwgcmV0aW5hX2VucmljaGVkLCBub3RlbnJpY2hlZCkKZGYgPC0gZGYgJT4lCiAgZGlzdGluY3QoKQoKIyMgd3JpdGV4bDo6d3JpdGVfeGxzeChkZiwgcGF0aCA9ICJheG9uVFJBUF9ERV9yZXN1bHRzXzIwMjQwMjAyL3JldGluYWhldF92c19zY25faGV0X1dUZmlsdGVyZWQueGxzeCIpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CmxhYmVsc191cHMgPC0gZGYgJT4lCiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgYWJzKGxvZ0ZDKSA+IDEpICU+JQogIGFycmFuZ2UobG9nRkMpICU+JQogIGhlYWQobiA9IDEwKQoKbGFiZWxzX2Rvd25zIDwtIGRmICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPiAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgaGVhZChuID0gMTApCgpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQoKbGFiZWxzX3JlcXVlc3RlZCA8LSBjKCJDZGgxMCIsIkNkaDEyIiwiQ2RoMTMiLCJDZGgxOCIsCiAgICAgICAgICAgICAgICAgICAgICAiQ2RoNyIsIkNkaDgiLCJDZGg5IiwiQ250bjMiLAogICAgICAgICAgICAgICAgICAgICAgIkNudG40IiwiQ250bjUiLCJDbnRuNiIsIktpcnJlbDMiLAogICAgICAgICAgICAgICAgICAgICAgIk5yeG4xIiwiTnJ4bjMiLCJTZW1hM2MiLCJTZW1hNmQiLAogICAgICAgICAgICAgICAgICAgICAgIlRlbm0xIiwiVGVubTIiLCJUZW5tNCIpCnJlc190YmwgPC0gZGYKREVwbG90IDwtIGdncGxvdChyZXNfdGJsLCBhZXMoeCA9IGxvZ0ZDLCB5ID0gLWxvZzEwKGFkai5QLlZhbCksIGxhYmVsID0gZXh0ZXJuYWxfZ2VuZV9uYW1lKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IFNpZ25pZmljYW5jZSksIHNpemUgPSA0KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMSwxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCguMDUpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAyMCkgKwogIHhsYWIoImxvZzIoRkMpIikgKwogIHlsYWIoIi1sb2cxMChwLXZhbHVlKSIpICsKICAjIyBnZ3RpdGxlKHRpdGxlLCBzdWJ0aXRsZSA9IHN1YnRpdGxlKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIkdyZXkiLCAiI0Y4NzY2RCIsICIjMDBCRkM0IikpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKGRmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0ZXJuYWxfZ2VuZV9uYW1lICVpbiUgbGFiZWxzX3JlcXVlc3RlZCksCiAgICAgICAgICAgICAgICAgICAjIyBjKGxhYmVscyRleHRlcm5hbF9nZW5lX25hbWUsICJPcG40IikpLCAjYygnczVfaGV0X2RsZ24nLCAnczVfaGV0X3JldCcsICdzNV9oZXRfc2NuJykpLAogICAgICAgICAgICAgICAgICAgIyMgbnVkZ2VfeCA9IC0wLjUsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMTUsIG1heC5vdmVybGFwcyA9IDI1KQoKI3NldEVQUygpCiNwb3N0c2NyaXB0KGZpbGUgPSAiYXhvblRSQVBfVm9sY2Fub3Bsb3RzXzIwMjQwMjAyL3AwOF9yZXRpbmF2c3NjbmhldF9ERV9yZXF1ZXN0ZWRfZ2VuZWxhYmVsc18wMjA1MjAyNC5lcHMiKQpERXBsb3QKI2Rldi5vZmYoKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3IsIGV2YWw9RkFMU0V9CnNjbl9lbnJpY2hlZCA8LSBkZiAlPiUKICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA+PSAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpCgpyZXRpbmFfZW5yaWNoZWQgPC0gZGYgJT4lCiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgbG9nRkMgPD0gLTEpICU+JQogIGFycmFuZ2UobG9nRkMpICAlPiUKICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9nZW5lX25hbWUsIGxvZ0ZDLCBhZGouUC5WYWwsIFNpZ25pZmljYW5jZSkKCnNjbl9lbnJpY2hlZApyZXRpbmFfZW5yaWNoZWQKCmRmICU+JQogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIk5vdFxuIEVucmljaGVkIikKYGBgCgojIyBHU0VBCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9yZXN1bHRfc2NuIDwtIGdvc3QocXVlcnkgPSBzY25fZW5yaWNoZWQkZXh0ZXJuYWxfZ2VuZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLCBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUsIHNvdXJjZSA9IGMoIkdPIikpCgpnc2VhX3Jlc3VsdF9yZXQgPC0gZ29zdChxdWVyeSA9IHJldGluYV9lbnJpY2hlZCRleHRlcm5hbF9nZW5lX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSwgc291cmNlID0gYygiR08iKSkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9zY24gPC0gIGdzZWFfcmVzdWx0X3NjbltbInJlc3VsdCJdXSAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgaGVhZChuID0gMjApCmdzZWFfcGxvdHNfc2NuIDwtIGdncGxvdChnc2VhX3NjbiwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpzZXRFUFMoKQpwb3N0c2NyaXB0KGZpbGUgPSAiYXhvblRSQVBfVm9sY2Fub3Bsb3RzXzIwMjQwMjAyL0dTRUFfU0NOaGV0X3ZzX3JldGluYV9lbnJpY2hlZF9QMDguZXBzIikKZ3NlYV9wbG90c19zY24KZGV2Lm9mZigpCgpnc2VhX3JldCA8LSAgZ3NlYV9yZXN1bHRfcmV0W1sicmVzdWx0Il1dICU+JQogIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pICU+JQogIGFycmFuZ2UoZGVzYyhyZWNhbGwpKSAlPiUKICBoZWFkKG4gPSAyMCkKZ3NlYV9wbG90c19yZXQgPC0gZ2dwbG90KGdzZWFfcmV0LCBhZXMoeCA9IHJlY2FsbCwgeSA9IHJlb3JkZXIodGVybV9uYW1lLCByZWNhbGwpLCBmaWxsID0gcF92YWx1ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKwogIHlsYWIoIiIpICsKICB4bGFiKCJHU0VBIFNjb3JlIikKCnNldEVQUygpCnBvc3RzY3JpcHQoZmlsZSA9ICJheG9uVFJBUF9Wb2xjYW5vcGxvdHNfMjAyNDAyMDIvR1NFQV9SZXRpbmFoZXRfdnNfU0NOX2VucmljaGVkX1AwOC5lcHMiKQpnc2VhX3Bsb3RzX3JldApkZXYub2ZmKCkKYGBgCgojIEtPIFJldGluYSB2cyBLTyBTQ04KCmBgYHtyLCBldmFsPUZBTFNFfQptbTM4X3N1YnNldDMgPC0gc3Vic2V0X2V4cHQoCiAgbW0zOF9oaXNhdCwKICBzdWJzZXQgPSAiKGJhdGNoID09ICc0JyB8IGJhdGNoID09ICc1JyB8IGJhdGNoID09ICc2JykgJiB0aW1lID09ICdwMDgnICAmIGdlbm90eXBlICE9ICdoZXQnICYgbG9jYXRpb24gIT0gJ2RsZ24nIHwgc2FtcGxlaWQgPT0gJ2lwcmdjXzAzJyIpCgptbTM4X3N1YnNldDMgPC0gc3Vic2V0X2V4cHQobW0zOF9zdWJzZXQzLCBzdWJzZXQgPSAic2FtcGxlaWQgIT0gJ2lwcmdjXzg2JyIpCm1tMzhfc3Vic2V0MyRkZXNpZ24gJT4lCiAgc2VsZWN0KGdlbm90eXBlLCBsb2NhdGlvbikgJT4lCiAgdGFibGUoKQptbTM4X25vcm0zIDwtIG5vcm1hbGl6ZV9leHB0KG1tMzhfc3Vic2V0MywgZmlsdGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0iY3BtIiwgdHJhbnNmb3JtPSJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKYGBgCgojIyBQQ0EKCmBgYHtyLCBldmFsPUZBTFNFfQptbTM4X25vcm0zIDwtIHNldF9leHB0X2JhdGNoZXMobW0zOF9ub3JtMywgZmFjdCA9ICJsb2NhdGlvbiIpCm1tMzhfbm9ybTMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhtbTM4X25vcm0zLCBmYWN0ID0gImdlbm90eXBlIikKcGNhX25vcm0zIDwtIHBsb3RfcGNhKG1tMzhfbm9ybTMsIG1heF9vdmVybGFwcyA9IDcwKQpwY2Ffbm9ybTMkcGxvdApgYGAKCiMjIERFCgpgYGB7ciwgZXZhbD1GQUxTRX0KbW1fZGVfc3Vic2V0MyA8LSBhbGxfcGFpcndpc2UobW0zOF9zdWJzZXQzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWw9RkFMU0UsIGRvX2Vic2VxPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWRnZXIgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSkKCnJldGluYWtlZXBlcl9nZW5lcyA8LSBtbV9kZV9zdWJzZXQzJGRlc2VxJGFsbF90YWJsZXMkd3RyZXRpbmFfdnNfa29yZXRpbmEgJT4lCiAgZmlsdGVyKGxvZ0ZDIDw9IC0xICYgYWRqLlAuVmFsIDw9IDAuMDUpCgpzY25rZWVwZXJfZ2VuZXMgPC0gbW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJHd0c2NuX3ZzX2tvc2NuICU+JQogIGZpbHRlcihsb2dGQyA8PSAtMSAmIGFkai5QLlZhbCA8PSAwLjA1KQoKa2VlcGVyZ2VuZXMgPC0gdW5pcXVlKGMocm93bmFtZXMocmV0aW5ha2VlcGVyX2dlbmVzKSwgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSkpCgphbm5vdHNfdG9fbWVyZ2UgPC0gbW1fYW5ub3QgJT4lCiAgc2VsZWN0KGVuc2VtYmxfZ2VuZV9pZCwgZXh0ZXJuYWxfZ2VuZV9uYW1lKSAlPiUKICBmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXMobW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2tvcmV0aW5hKSkgJT4lCiAgZGlzdGluY3QoKQoKbW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2tvcmV0aW5hIDwtIG1lcmdlKAogIG1tX2RlX3N1YnNldDMkZGVzZXEkYWxsX3RhYmxlcyRrb3Njbl92c19rb3JldGluYSwKICBhbm5vdHNfdG9fbWVyZ2UsIGJ5LnggPSAwLAogIGJ5LnkgPSAiZW5zZW1ibF9nZW5lX2lkIiwgYWxsLnggPSBUUlVFKQoKZGYgPC0gbW1fZGVfc3Vic2V0MyRkZXNlcSRhbGxfdGFibGVzJGtvc2NuX3ZzX2tvcmV0aW5hICU+JQogIG11dGF0ZShTaWduaWZpY2FuY2UgPSBjYXNlX3doZW4obG9nRkMgPD0gLTEgfiAiUmV0aW5hIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID49IDEgfiAiU0NOIEVucmljaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0ZDID4gLTEgJiBsb2dGQyA8IDEgfiAiTm90XG4gRW5yaWNoZWQiKSkKCmRmIDwtIGRmICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSBrZWVwZXJnZW5lcykKCnNjbl9lbnJpY2hlZCA8LSBkZiAlPiUKICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUgJiBsb2dGQyA+PSAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsKSAlPiUKICBtdXRhdGUoU2lnbmlmaWNhbmNlID0gIlNDTiBFbnJpY2hlZCIpICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSByb3duYW1lcyhzY25rZWVwZXJfZ2VuZXMpKQoKZGYgJT4lCiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgbG9nRkMgPD0gLTEpICU+JQogIGFycmFuZ2UobG9nRkMpICAlPiUKICBzZWxlY3QoUm93Lm5hbWVzLCBleHRlcm5hbF9nZW5lX25hbWUsIGxvZ0ZDLCBhZGouUC5WYWwpICU+JQogIG11dGF0ZShTaWduaWZpY2FuY2UgPSAiUmV0aW5hIEVucmljaGVkIikgJT4lCiAgZmlsdGVyKFJvdy5uYW1lcyAlaW4lIHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcykpIC0+IHJldGluYV9lbnJpY2hlZAoKbm90ZW5yaWNoZWQgPC0gZGYgJT4lCiAgc2VsZWN0KFJvdy5uYW1lcywgZXh0ZXJuYWxfZ2VuZV9uYW1lLCBsb2dGQywgYWRqLlAuVmFsLCBTaWduaWZpY2FuY2UpICU+JQogIGZpbHRlcihSb3cubmFtZXMgJWluJSBjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoc2Nua2VlcGVyX2dlbmVzKSlbZHVwbGljYXRlZChjKHJvd25hbWVzKHJldGluYWtlZXBlcl9nZW5lcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKHNjbmtlZXBlcl9nZW5lcykpKV0pCgpkZiA8LSByYmluZChzY25fZW5yaWNoZWQsIHJldGluYV9lbnJpY2hlZCwgbm90ZW5yaWNoZWQpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CmxhYmVsc191cHMgPC0gZGYgJT4lCiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgYWJzKGxvZ0ZDKSA+IDEpICU+JQogIGFycmFuZ2UobG9nRkMpICU+JQogIGhlYWQobiA9IDEwKQoKbGFiZWxzX2Rvd25zIDwtIGRmICU+JQogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPiAxKSAlPiUKICBhcnJhbmdlKC1sb2dGQykgJT4lCiAgaGVhZChuID0gMTApCgpsYWJlbHMgPC0gcmJpbmQobGFiZWxzX3VwcywgbGFiZWxzX2Rvd25zKQojIyB3YW50ZWRfY29sdW1uIDwtICJTaWduaWZpY2FuY2UiCgpyZXNfdGJsIDwtIGRmCkRFcGxvdCA8LSBnZ3Bsb3QocmVzX3RibCwgYWVzKHggPSBsb2dGQywgeSA9IC1sb2cxMChhZGouUC5WYWwpLCBsYWJlbCA9IGV4dGVybmFsX2dlbmVfbmFtZSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTaWduaWZpY2FuY2UpLCBzaXplID0gNCkgKwogICMjIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9ICEhc3ltKHdhbnRlZF9jb2x1bW4pKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB4bGFiKCJsb2cyKEZDKSIpICsKICB5bGFiKCItbG9nMTAocC12YWx1ZSkiKSArCiAgIyMgZ2d0aXRsZSh0aXRsZSwgc3VidGl0bGUgPSBzdWJ0aXRsZSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiR3JleSIsICIjRjg3NjZEIiwgIiMwMEJGQzQiKSkgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGZpbHRlcigKICAgIGRmLCBleHRlcm5hbF9nZW5lX25hbWUgJWluJSBjKGxhYmVscyRleHRlcm5hbF9nZW5lX25hbWUsICJPcG40IikpLAogICAgIyMgYygnczVfaGV0X2RsZ24nLCAnczVfaGV0X3JldCcsICdzNV9oZXRfc2NuJykpLAogICAgIyMgbnVkZ2VfeCA9IC0wLjUsCiAgICBudWRnZV95ID0gMTAsIG1heC5vdmVybGFwcyA9IDI1KQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9wMDhfcmV0aW5hdnNzY25rb19ERV8xMzEyMDI0LmVwcyIpCkRFcGxvdApkZXYub2ZmKCkKYGBgCgojIyBIb3cgbWFueSB1cHMvZG93bnMKCmBgYHtyLCBldmFsPUZBTFNFfQpzY25fZW5yaWNoZWQKcmV0aW5hX2VucmljaGVkCm5vdGVucmljaGVkICU+JQogIGZpbHRlcihTaWduaWZpY2FuY2UgPT0gIk5vdFxuIEVucmljaGVkIikKYGBgCgojIyBHU0VBCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9yZXN1bHRfc2NuIDwtIGdvc3QocXVlcnkgPSBzY25fZW5yaWNoZWQkZXh0ZXJuYWxfZ2VuZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJtbXVzY3VsdXMiLAogICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZSA9IGMoIkdPIikpCgpnc2VhX3Jlc3VsdF9yZXQgPC0gZ29zdChxdWVyeSA9IHJldGluYV9lbnJpY2hlZCRleHRlcm5hbF9nZW5lX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlID0gYygiR08iKSkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KZ3NlYV9zY24gPC0gIGdzZWFfcmVzdWx0X3NjbltbInJlc3VsdCJdXSAlPiUKICBzZWxlY3QodGVybV9uYW1lLCBwX3ZhbHVlLCB0ZXJtX3NpemUsIGludGVyc2VjdGlvbl9zaXplLCByZWNhbGwsIHNvdXJjZSwgaW50ZXJzZWN0aW9uKSAlPiUKICBhcnJhbmdlKGRlc2MocmVjYWxsKSkgJT4lCiAgaGVhZChuID0gMjApCmdzZWFfcGxvdHNfc2NuIDwtIGdncGxvdChnc2VhX3NjbiwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiR1NFQSBTY29yZSIpCgpzZXRFUFMoKQpwb3N0c2NyaXB0KGZpbGUgPSAiYXhvblRSQVBfVm9sY2Fub3Bsb3RzXzIwMjQwMjAyL0dTRUFfU0NOa29fZW5yaWNoZWRfdnNfcmV0aW5hX1AwOC5lcHMiKQpnc2VhX3Bsb3RzX3NjbgpkZXYub2ZmKCkKCmdzZWFfcmV0IDwtICBnc2VhX3Jlc3VsdF9yZXRbWyJyZXN1bHQiXV0gJT4lCiAgc2VsZWN0KHRlcm1fbmFtZSwgcF92YWx1ZSwgdGVybV9zaXplLCBpbnRlcnNlY3Rpb25fc2l6ZSwgcmVjYWxsLCBzb3VyY2UsIGludGVyc2VjdGlvbikgJT4lCiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpICU+JQogIGhlYWQobiA9IDIwKQpnc2VhX3Bsb3RzX3JldCA8LSBnZ3Bsb3QoZ3NlYV9yZXQsIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgdGhlbWVfYncoKSArCiAgeWxhYigiIikgKwogIHhsYWIoIkdTRUEgU2NvcmUiKQoKc2V0RVBTKCkKcG9zdHNjcmlwdChmaWxlID0gImF4b25UUkFQX1ZvbGNhbm9wbG90c18yMDI0MDIwMi9HU0VBX1JldGluYWtvX2VucmljaGVkX3ZzX1NDTl9QMDguZXBzIikKZ3NlYV9wbG90c19yZXQKZGV2Lm9mZigpCmBgYAoKIyBNeSB2ZXJzaW9uIG9mIHRoZSBnbG9iYWwgYW5hbHlzaXMKCkkgd2FudCB0byBoYXZlIGFuIGludm9jYXRpb24gb2YgYWxsX3BhaXJ3aXNlKCkgd2hpY2ggdXNlcyBhbGwgc2FtcGxlcywKaW4gdGhlIGZvbGxvd2luZyBibG9jayBJIHdpbGwgc2V0IHRoYXQgdXAgdXNpbmcgYSBzZXQgb2YgJ2tlZXBlcnMnCndoaWNoIHdpbGwgYmUgbmFtZWQgYnkgdGltZSwgbG9jYXRpb24sIHRoZW4gMiBsZXR0ZXJzIGZvciB0aGUKbnVtZXJhdG9yL2Rlbm9taW5hdG9yOiB3IGZvciBXVCwgaCBmb3IgaGV0LCBkIGZvciBkZWx0YTsgdGh1cwoicDA4X3JldGluYV9odyIgaXMgY29tcGFyaW5nIHRoZSBoZXQvd3QgZm9yIHRoZSBwMDggcmV0aW5hIHNhbXBsZXMuCgpJZiB0aGV5IGFyZSBvZiBpbnRlcmVzdCwgSSB3aWxsIGhhdmUgYSBzZXBhcmF0ZSBzZXQgd2hpY2ggZm9sbG93cyB0aGUKc2FtZSBjb252ZW50aW9uIHdpdGggbmFtZXMgbGlrZSAicDA4X2tvX3NyIiB0byBjb21wYXJlIHAwOCBkZWx0YXMgd2l0aApTQ04gYXMgdGhlIG51bWVyYXRvciBhbmQgcmV0aW5hIGFzIHRoZSBkZW5vbWluYXRvci4KCiMjIFNldCB1cCB0aGUgZXhjbHVzaW9uIGRhdGFzZXQKClRoZSBtb3N0IHBlY3VsaWFyIGFzcGVjdCBvZiB0aGlzIGFuYWx5c2lzIHJlc2lkZXMgaW4gdGhlIGNob2ljZXMKYXJvdW5kIGNob29zaW5nIHdoaWNoIGdlbmVzIHRvIGNvbnNpZGVyIHdoZW4gY29tcGFyaW5nIHRoZQpnZW5vdHlwZXMvbG9jYXRpb25zL3RpbWVzLiAgVGhlIGdlbmVyYWwgaWRlYSBpcyBwcmV0dHkgY2xlYXI6IGZpbmQgdGhlCmdlbmVzIHdoaWNoIGFyZSBub24tc3BlY2lmaWNhbGx5IGJlaW5nIHB1bGxlZCBkb3duIGluIHRoZSBXVCBzYW1wbGVzCmFuZCBlaXRoZXIgZXhjbHVkZSBvciBkaXNjb3VudCB0aGVtLiAgVGhlIHZhcmlvdXMgcG90ZW50aWFsIG1ldGhvZHMKZm9yIHBlcmZvcm1pbmcgdGhpcyBhcmUgY29uZnVzaW5nOgoKMS4gIFdoaWNoIHNldCBvZiBjb21wYXJpc29ucyBvZiB3dC9rbyB3dC9oZXQgZG8gd2UgdXNlIHRvCiAgICBleGNsdWRlL2Rpc2NvdW50IGdlbmVzPwogICAgYS4gIFNob3VsZCBpdCBiZSBhIGNvbWJpbmF0aW9uIG9mIGFsbCBzYW1wbGVzIHd0IHZzLiB4PwogICAgYi4gIFNob3VsZCBpdCBiZSBvbmx5IHRoZSAncmVsZXZhbnQnIGNvbXBhcmlzb24sIGUuZy4gaWYgd2UgYXJlCiAgICBjb21wYXJpbmcgcDA4X2RsZ25faGV0IHZzLiBwMDhfc2NuX2hldDsgZG8gd2UgcmVtb3ZlIGdlbmVzCiAgICBvYnNlcnZlZCBpbiAocDA4X2RsZ25faGV0L3d0ICYmIHAwOF9zY25faGV0L3d0KQoyLiAgRG8gd2UgaW5zdGVhZCBhdHRlbXB0IHRvIHVzZSB0aGlzIHgvd3QgaW5mb3JtYXRpb24gdG8gbm9ybWFsaXplCiAgICB0aGUgZXhwcmVzc2lvbiB2YWx1ZXMgaW4gdGhlIG90aGVyIGNvbmRpdGlvbnMgYW5kIGtlZXAgdGhvc2UKICAgIGdlbmVzPwoKVGhlcmVzYSdzIGN1cnJlbnQgd29ya3NoZWV0IGltcGxlbWVudHMgYSB2ZXJzaW9uIG9mIDFiIGluIHdoaWNoIHNoZQpzZXBhcmF0ZWQgdGhlIHZhcmlvdXMgaW5wdXQgZ2VuZSBzZXRzIHRvIGRlZmluZSB0aGUgZXhjbHVzaW9uIGdlbmVzLgpJIGFtIGdvaW5nIHRvIHJlcGVhdCB0aGlzLCBidXQgbGVhdmUgdGhlIHN0YXJ0aW5nIGRhdGEgc3RydWN0dXJlCmludGFjdC4KCkluIHRoaXMgZmlyc3QgaXRlcmF0aW9uLCBJIHdpbGwgZG8gdGhhdCBieSBjcmVhdGluZyBhIHNpbXBsaWZpZWQgbW9kZWwKb2YgdGhlIGRhdGEgd2hpY2ggY29tYmluZXMgdGhlIHRpbWUvZ2Vub3R5cGUvbG9jYXRpb24gYW5kIHVzaW5nIHN2YS4KSW4gbXkgbmV4dCBpdGVyYXRpb24gSSB3aWxsIHVzZSBhIGZ1bGwgc3RhdGlzdGljYWwgbW9kZWwgY29udGFpbmluZwplYWNoIG9mIHRob3NlIGZhY3RvcnMgKGFuZCBwcm9iYWJseSBhbHNvIHVzaW5nIHN2YSkuCgpOb3RlOiBteSBjb2xvciBjaG9pY2VzIGFyZSBraW5kIG9mIGdhcmJhZ2UuCgpJbiBhZGRpdGlvbiwgdGhlIGV4Y2x1c2lvbiBkYXRhc2V0IGlzIHRoZSBzYW1lIGFzIHRoZSBhbmFseXNpcwpkYXRhc2V0LCBpdCBpcyByZWFsbHkgb25seSB0aGUgY29udHJhc3RzIHdoaWNoIHdpbGwgYmUgZGlmZmVyZW50LgoKYGBge3J9CnYzX3BhaXJ3aXNlX2lucHV0IDwtIHNldF9leHB0X2NvbmRpdGlvbnMobW0zOF9oaXNhdF92MywgZmFjdCA9ICJ0aW1lX2dlbm9fbG9jIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9jaG9pY2VzW1siYWxsIl1dKQpgYGAKCiMjIFNldCB1cCB0aGUgY29udHJhc3RzCgpJbiB0aGUgZm9sbG93aW5nIGZldyBibG9ja3MgSSB3aWxsIHNldCB1cCB0aGUgdmFyaW91cyBjb21wYXJpc29ucyBvZgppbnRlcmVzdC4gIFN0YXJ0aW5nIHdpdGggdGhlIHNldCBvZiBnZW5lcyB0byBleGNsdWRlIGJlY2F1c2UgdGhleSB3ZXJlCm9ic2VydmVkIHRvIGJpbmQgbm9uLXNwZWNpZmljYWxseSBpbiB0aGUgd3Qgc2FtcGxlcy4KCiMjIyBFeGNsdXNpb24gY29udHJhc3RzCgpJbiBlYWNoIGV4Y2x1c2lvbiBJIHdpbGwgaGF2ZSB0aGUgY29udHJhc3QgZmlyc3QgZm9sbG93ZWQgYnkgdGhlIHBhaXIKb2YgY29udHJhc3RzIHdoaWNoIHdpbGwgYmUgdXNlZCB0byBkZWZpbmUgdGhlIGdlbmUgc2V0IHRvIGV4Y2x1ZGUuCgoqIHAxNV9oZXRfZGxnbi9wMDhfaGV0X2RsZ246IHAxNV93dF9kbGduL3AxNV9oZXRfZGxnbiwKICBwMDhfd3RfZGxnbi9wMDhfaGV0X2RsZ247IHJlbW92ZSB0aGUgZ2VuZXMgaW5jcmVhc2VkIGluIHd0LgoqIHAxNV9rb19zY24vcDA4X2tvX3NjbjogcDE1X3d0X3Njbi9wMTVfa29fc2NuLCBwMDhfd3Rfc2NuL3AxNV9rb19zY24KKiBwMTVfaGV0X3JldGluYS9wMDhfaGV0X3JldGluYTogSSB0aGluayB5b3UgZ2V0IGl0LCB3dC9oZXQgZm9yIGJvdGgKICBwMTUgcmV0aW5hcyBhbmQgcDA4IHJldGluYXMuLi4KClB1dCBzbGlnaHRseSBkaWZmZXJlbnRseSwgZm9yIGV2ZXJ5IHRlcm0gb2YgaW50ZXJlc3QgSSB3aWxsIGNyZWF0ZSBhCmNvbnRyYXN0IHdpdGggdGhlIHd0IGFzIG51bWVyYXRvciBhbmQgdGhlIGRlc2lyZWQgdGVybSBhcyBkZW5vbWluYXRvciwKdGhlbiBwdWxsIG91dCB0aGUgZ2VuZXMgaW5jcmVhc2VkIGluIHd0LgoKYGBge3J9CmluY2x1c2lvbnMgPC0gbGlzdCgKICAjIyBJIGxpa2UgYWxwaGFiZXRpemluZyB0aGluZ3MsIHN0YXJ0IHdpdGggZGxnbgogICJwMTVfaGV0X2RsZ24iID0gYygicDE1aGV0ZGxnbiIsICJwMTV3dGRsZ24iKSwKICAicDA4X2hldF9kbGduIiA9IGMoInAwOGhldGRsZ24iLCAicDA4d3RkbGduIiksCiAgInAxNV9rb19kbGduIiA9IGMoInAxNWtvZGxnbiIsICJwMTV3dGRsZ24iKSwKICAicDA4X2tvX2RsZ24iID0gYygicDA4a29kbGduIiwgInAwOHd0ZGxnbiIpLAogICMjIFRoZW4gcmV0aW5hcwogICJwMTVfaGV0X3JldGluYSIgPSBjKCJwMTVoZXRyZXRpbmEiLCAicDE1d3RyZXRpbmEiKSwKICAicDA4X2hldF9yZXRpbmEiID0gYygicDA4aGV0cmV0aW5hIiwgInAwOHd0cmV0aW5hIiksCiAgInAxNV9rb19yZXRpbmEiID0gYygicDE1a29yZXRpbmEiLCAicDE1d3RyZXRpbmEiKSwKICAicDA4X2tvX3JldGluYSIgPSBjKCJwMDhrb3JldGluYSIsICJwMDh3dHJldGluYSIpLAogICMjIFRoZW4gc2NuCiAgInAxNV9oZXRfc2NuIiA9IGMoInAxNWhldHNjbiIsICJwMTV3dHNjbiIpLAogICJwMDhfaGV0X3NjbiIgPSBjKCJwMDhoZXRzY24iLCAicDA4d3RzY24iKSwKICAicDE1X2tvX3NjbiIgPSBjKCJwMTVrb3NjbiIsICJwMTV3dHNjbiIpLAogICJwMDhfa29fc2NuIiA9IGMoInAwOGtvc2NuIiwgInAwOHd0c2NuIikpCmBgYAoKIyMjIFRpbWUgY29udHJhc3RzCgpGb3IgZWFjaCBsb2NhdGlvbi9nZW5vdHlwZSBvZiBpbnRlcmVzdCwgbGV0IHVzIGNvbXBhcmUgcDE1L3AwOAoKYGBge3J9CnRpbWVfa2VlcGVycyA8LSBsaXN0KAogICMjIERMR04KICAidF9oZXRfZGxnbiIgPSBjKCJwMTVoZXRkbGduIiwgInAwOGhldGRsZ24iKSwKICAidF9rb19kbGduIiA9IGMoInAxNWtvZGxnbiIsICJwMDhrb2RsZ24iKSwKICAjIyBSZXRpbmEKICAidF9oZXRfcmV0aW5hIiA9IGMoInAxNWhldHJldGluYSIsICJwMDhoZXRyZXRpbmEiKSwKICAidF9rb19yZXRpbmEiID0gYygicDE1a29yZXRpbmEiLCAicDA4a29yZXRpbmEiKSwKICAjIyBTQ04KICAidF9oZXRfc2NuIiA9IGMoInAxNWhldHNjbiIsICJwMDhoZXRzY24iKSwKICAidF9rb19zY24iID0gYygicDE1a29zY24iLCAicDA4a29zY24iKSkKYGBgCgojIyMgTG9jYXRpb24gY29udHJhc3RzCgpDb21wYXJlIGxvY2F0aW9ucyBhbmQga2VlcCB0aW1lL2dlbm90eXBlIGNvbnNpc3RlbnQuICBJIHdpbGwgdXNlIHRoZQpsb2NhdGlvbiBpbml0aWFscyB0byBkZWZpbmUgbnVtZXJhdG9yL2Rlbm9taW5hdG9yLgoKYGBge3J9CmxvY2F0aW9uX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBkbGduL3JldGluYQogICJkcl9wMDhfaGV0IiA9IGMoInAwOGhldGRsZ24iLCAicDA4aGV0cmV0aW5hIiksCiAgImRyX3AxNV9oZXQiID0gYygicDE1aGV0ZGxnbiIsICJwMTVoZXRyZXRpbmEiKSwKICAiZHJfcDA4X2tvIiA9IGMoInAwOGtvZGxnbiIsICJwMDhrb3JldGluYSIpLAogICJkcl9wMTVfa28iID0gYygicDE1a29kbGduIiwgInAxNWtvcmV0aW5hIiksCiAgIyMgc2NuL3JldGluYQogICJzcl9wMDhfaGV0IiA9IGMoInAwOGhldHNjbiIsICJwMDhoZXRyZXRpbmEiKSwKICAic3JfcDE1X2hldCIgPSBjKCJwMTVoZXRzY24iLCAicDE1aGV0cmV0aW5hIiksCiAgInNyX3AwOF9rbyIgPSBjKCJwMDhrb3NjbiIsICJwMDhrb3JldGluYSIpLAogICJzcl9wMTVfa28iID0gYygicDE1a29zY24iLCAicDE1a29yZXRpbmEiKSwKICAjIyBkbGduL3NjbgogICJkc19wMDhfaGV0IiA9IGMoInAwOGhldGRsZ24iLCAicDA4aGV0c2NuIiksCiAgImRzX3AxNV9oZXQiID0gYygicDE1aGV0ZGxnbiIsICJwMTVoZXRzY24iKSwKICAiZHNfcDA4X2tvIiA9IGMoInAwOGtvZGxnbiIsICJwMDhrb3NjbiIpLAogICJkc19wMTVfa28iID0gYygicDE1a29kbGduIiwgInAxNWtvc2NuIikpCmBgYAoKIyMjIEdlbm90eXBlIGNvbnRyYXN0cwoKQ29tcGFyZSBrby9oZXQgd2hpbGUga2VlcGluZyB0aW1lL2xvY2F0aW9uIGNvbnN0YW50LiAgU2ltaWxhcmx5LCB1c2UKdGhlIGluaXRpYWxzIHRvIGRlbm90ZSBudW1lcmF0b3IvZGVub21pbmF0b3IsIHdoaWNoIHdpbGwgYWx3YXlzIGJlIGtoLgoKYGBge3J9Cmdlbm90eXBlX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBETEdOCiAgImtoX3AwOF9kbGduIiA9IGMoInAwOGtvZGxnbiIsICJwMDhoZXRkbGduIiksCiAgImtoX3AxNV9kbGduIiA9IGMoInAxNWtvZGxnbiIsICJwMTVoZXRkbGduIiksCiAgIyMgUmV0aW5hCiAgImtoX3AwOF9yZXRpbmEiID0gYygicDA4a29yZXRpbmEiLCAicDA4aGV0cmV0aW5hIiksCiAgImtoX3AxNV9yZXRpbmEiID0gYygicDE1a29yZXRpbmEiLCAicDE1aGV0cmV0aW5hIiksCiAgIyMgU0NOCiAgImtoX3AwOF9zY24iID0gYygicDA4a29zY24iLCAicDA4aGV0c2NuIiksCiAgImtoX3AxNV9zY24iID0gYygicDE1a29zY24iLCAicDE1aGV0c2NuIikpCmBgYAoKIyMgUGVyZm9ybSB0aGUgZXhjbHVzaW9uIGNvbXBhcmlzb24KCk15IGFsbF9wYWlyd2lzZSgpIGZ1bmN0aW9uIG5vdyBoYXMgYSBwYXJhbWV0ZXIgd2hpY2ggYWxsb3dzIG1lIHRvCmNob29zZSB3aGljaCBjb250cmFzdHMgdG8gcGVyZm9ybSBpbnN0ZWFkIG9mIGxpdGVyYWxseSBkb2luZyBldmVyeQpwb3NzaWJsZSBjb21wYXJpc29uLiAgVGhhdCBpcyB3ZWxsIHN1aXRlZCBmb3IgdGhlc2Ugb3BlcmF0aW9uczoKCmBgYHtyfQpsZmNfY3V0b2ZmIDwtIDAuMQphZGpwX2N1dG9mZiA8LSAwLjEKaW5jbHVzaW9uX2RlIDwtIGFsbF9wYWlyd2lzZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gaW5jbHVzaW9ucywgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikKaW5jbHVzaW9uX2RlCmluY2x1c2lvbl90YWJsZXMgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgaW5jbHVzaW9uX2RlLCBrZWVwZXJzID0gaW5jbHVzaW9ucywgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgid3RfY29tcGFyaXNvbnMvaW5jbHVzaW9uX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQppbmNsdXNpb25fdGFibGVzCmluY2x1c2lvbl9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBpbmNsdXNpb25fdGFibGVzLCBsZmMgPSBsZmNfY3V0b2ZmLCBwID0gYWRqcF9jdXRvZmYsCiAgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoInd0X2NvbXBhcmlzb25zL2luY2x1c2lvbl9zaWctdnt2ZXJ9Lnhsc3giKSkKaW5jbHVzaW9uX3NpZwpgYGAKCiMjIyBDaGVjayB2cyBUaGVyZXNhJ3MgZmlsdGVyCgpVcCBhYm92ZSBUaGVyZXNhIHBlcmZvcm1lZCBhIDAuMjUgbG9nMkZDIGFuZCAwLjA1IGFkanAgZmlsdGVyIHdoaWNoCnByb3ZpZGVkIGEgc2V0IG9mIDIsNjQwIGdlbmVzIG9ic2VydmVkIGhpZ2hlciBpbiB0aGUgcDA4IGhldCByZXRpbmFzCnZzLiB3dCByZXRpbmFzLiAgSSBzaG91bGQgc2VlIHRoYXQgaW4gdGhpcyBpbmNsdXNpb25fc2lnIGRhdGEgc3RydWN0dXJlLgoKVGhlcmUgaXMgYW4gaW1wb3J0YW50IGNhdmVhdCB0aG91Z2g6IGluIFRoZXJlc2EncyBmaWx0ZXIgYWJvdmUsIHNoZQpkaWQgYSBERSBvZiBfb25seV8gdGhlIHJldGluYSBzYW1wbGVzIGJ1dCBJIGRpZCBhbGwgc2FtcGxlcy4gIEkKZXhwZWN0ZWQgdGhhdCB0aGlzIHdvdWxkIHJlc3VsdCBpbiBiYXNpY2FsbHkgdGhlIHNhbWUgcmVzdWx0IChJCmFjdHVhbGx5IGFzc3VtZWQgSSB3b3VsZCBnZXQgYSBmZXcgbW9yZSBnZW5lcyksIGJ1dCBpbnN0ZWFkIGl0IGFwcGVhcnMKdG8gaGF2ZSByZXRyaWV2ZWQgYSBzaWduaWZpY2FudGx5IHNtYWxsZXIgbnVtYmVyIG9mIGdlbmVzIChhYm91dCAxLzIsCmhhcHBpbHkgdGhleSBwcmV0dHkgbXVjaCBhbGwgYXBwZWFyIGluIHRoZSBwcmV2aW91cyBmaWx0ZXIpLiAgQXMgYQpyZXN1bHQsIEkgYW0gZ29pbmcgdG8gdHJ5IHJlbGF4aW5nIG15IGNvbnN0cmFpbnRzIHNsaWdodGx5IHRvIHNlZSBpZiBJCmNhbiByZWNhcGl0dWxhdGUgaGVyIGZpbHRlciAod2hpY2ggd291bGQgbWF0Y2ggVGhlcmVzYSdzIGxhdGVyIGZpbHRlciwKdGhvdWdoIEkgZ3Vlc3MgdGhhdCBpbiB0dXJuIHdpbGwgbGVhZCB0byBhIHNtYWxsZXIgc2V0IG9mIGdlbmVzCmNvbXBhcmVkIHRvIGhlciBsYXRlciwgcmVsYXhlZCAwLjEgZmlsdGVyKS4KCmBgYHtyfQpjb21wYXJpc29uIDwtIGluY2x1c2lvbl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInAwOF9oZXRfcmV0aW5hIl1dCmNvbXAgPC0gbGlzdCgKICAidGFhIiA9IHRhYV9rZWVwZXJzLAogICJuZXciID0gcm93bmFtZXMoY29tcGFyaXNvbikpCnRlc3RfY29tcGFyaXNvbiA8LSBWZW5uZXJhYmxlOjpWZW5uKGNvbXApCnBsb3QodGVzdF9jb21wYXJpc29uKQpgYGAKCkkgd2FudCB0byBoYXZlIGEgbGl0dGxlIGZ1bmN0aW9uIHdoaWNoLCBnaXZlbiBhIGNvbnRyYXN0IG9mIGludGVyZXN0LAp3aWxsIGV4dHJhY3QgdGhlIGdlbmUgc2V0cyB3aGljaCBzaG91bGQgYmUgaW5jbHVkZWQvZXhjbHVkZWQgZ2l2ZW4gdGhlCmFib3ZlLgoKYGBge3J9CndyaXRlX2FsbF9jcCA8LSBmdW5jdGlvbihhbGxfY3ApIHsKICBhbGxfd3JpdHRlbiA8LSBsaXN0KCkKICBmb3IgKGcgaW4gc2VxX2xlbihsZW5ndGgoYWxsX2NwKSkpIHsKICAgIG5hbWUgPC0gbmFtZXMoYWxsX2NwKVtnXQogICAgZGF0dW0gPC0gYWxsX2NwW1tuYW1lXV0KICAgIGZpbGVuYW1lIDwtIGdsdWUoImNwcm9maWxlci97dmVyfS97bmFtZX1fY3Byb2ZpbGVyLXZ7dmVyfS54bHN4IikKICAgIHdyaXR0ZW4gPC0gc20od3JpdGVfY3BfZGF0YShkYXR1bSwgZXhjZWwgPSBmaWxlbmFtZSkpCiAgICBhbGxfd3JpdHRlbltbZ11dIDwtIHdyaXR0ZW4KICB9CiAgcmV0dXJuKGFsbF93cml0dGVuKQp9Cgp3cml0ZV9hbGxfZ3AgPC0gZnVuY3Rpb24oYWxsX2dwKSB7CiAgYWxsX3dyaXR0ZW4gPC0gbGlzdCgpCiAgZm9yIChnIGluIHNlcV9sZW4obGVuZ3RoKGFsbF9ncCkpKSB7CiAgICBuYW1lIDwtIG5hbWVzKGFsbF9ncClbZ10KICAgIGRhdHVtIDwtIGFsbF9ncFtbbmFtZV1dCiAgICBmaWxlbmFtZSA8LSBnbHVlKCJncHJvZmlsZXIve3Zlcn0ve25hbWV9X2dwcm9maWxlci12e3Zlcn0ueGxzeCIpCiAgICB3cml0dGVuIDwtIHNtKHdyaXRlX2dwcm9maWxlcl9kYXRhKGRhdHVtLCBleGNlbCA9IGZpbGVuYW1lKSkKICAgIGFsbF93cml0dGVuW1tnXV0gPC0gd3JpdHRlbgogIH0KICByZXR1cm4oYWxsX3dyaXR0ZW4pCn0KCmV4dHJhY3RfaW5jbHVzaW9ucyA8LSBmdW5jdGlvbihpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLCBrZWVwZXJzLCBhbGxfZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLCB3aGljaCA9ICJ1cHMiKSB7CiAgcmV0bGlzdCA8LSBsaXN0KCkKICB0YWJsZV9uYW1lcyA8LSBuYW1lcyhpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXSkKICBmb3IgKGNfbnVtIGluIHNlcV9hbG9uZyhrZWVwZXJzKSkgewogICAgY29udHJhc3QgPC0gbmFtZXMoa2VlcGVycylbY19udW1dCiAgICBudW1lcmF0b3JfbmFtZSA8LSBrZWVwZXJzW1tjX251bV1dWzFdCiAgICBkZW5vbWluYXRvcl9uYW1lIDwtIGtlZXBlcnNbW2NfbnVtXV1bMl0KICAgICMjIEluIG15IG5ldyBicmFuY2ggSSBjbGVhbmVkIHVwIHRoZSBzYW5pdGl6ZXIgZnVuY3Rpb24gZm9yIGNvbnRyYXN0cyBzbyB0aGlzIGlzIG5vdCBuZWVkZWQuCiAgICBudW1lcmF0b3JfbmFtZSA8LSBnc3ViKHggPSBudW1lcmF0b3JfbmFtZSwgcGF0dGVybiA9ICIoaGV0fGtvfHd0KSIsIHJlcGxhY2VtZW50ID0gIl9cXDFfIikKICAgIGRlbm9taW5hdG9yX25hbWUgPC0gZ3N1Yih4ID0gZGVub21pbmF0b3JfbmFtZSwgcGF0dGVybiA9ICIoaGV0fGtvfHd0KSIsIHJlcGxhY2VtZW50ID0gIl9cXDFfIikKICAgIG51bWVyYXRvcl90YWJsZSA8LSBpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXVtbbnVtZXJhdG9yX25hbWVdXQogICAgbnVtZXJhdG9yX2dlbmVzIDwtIHJvd25hbWVzKG51bWVyYXRvcl90YWJsZSkKICAgIGRlbm9taW5hdG9yX3RhYmxlIDwtIGluY2x1c2lvbl9zaWdbW2FjY29yZGluZ190b11dW1t3aGljaF1dW1tkZW5vbWluYXRvcl9uYW1lXV0KICAgIGRlbm9taW5hdG9yX2dlbmVzIDwtIHJvd25hbWVzKGRlbm9taW5hdG9yX3RhYmxlKQogICAgZGZfY29sdW1ucyA8LSBwYXN0ZTAoImRlc2VxXyIsIGMoImxvZ2ZjIiwgImFkanAiLCAiZGVuIikpCiAgICBpbmNsdWRlZF9udW0gPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW251bWVyYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfbnVtKSA8LSBjKCJudW1lcmF0b3JfdnNfd3RfbG9nZmMiLCAibnVtZXJhdG9yX3ZzX3d0X2FkanAiLCAibnVtX3d0X21lYW5fZXhwcnMiKQogICAgaW5jbHVkZWRfZGVuIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1tkZW5vbWluYXRvcl9uYW1lXV1bLCBkZl9jb2x1bW5zXQogICAgY29sbmFtZXMoaW5jbHVkZWRfZGVuKSA8LSBjKCJkZW5vbWluYXRvcl92c193dF9sb2dmYyIsICJkZW5vbWluYXRvcl92c193dF9hZGpwIiwgImRlbl93dF9tZWFuX2V4cHJzIikKICAgIGluY2x1ZGVkX2RmIDwtIG1lcmdlKGluY2x1ZGVkX251bSwgaW5jbHVkZWRfZGVuLCBieSA9ICJyb3cubmFtZXMiKQogICAgcm93bmFtZXMoaW5jbHVkZWRfZGYpIDwtIGluY2x1ZGVkX2RmW1siUm93Lm5hbWVzIl1dCiAgICBpbmNsdWRlZF9kZltbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCiAgICBpbmNsdWRlX2dlbmVzIDwtIHVuaXF1ZShjKG51bWVyYXRvcl9nZW5lcywgZGVub21pbmF0b3JfZ2VuZXMpKQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIG51bWVyYXRvcl9uYW1lLAogICAgICAgICAgICAiIHZzLiB3dCBpcyAiLCBsZW5ndGgobnVtZXJhdG9yX2dlbmVzKSwgIi4iKQogICAgbWVzc2FnZSgiVGhlIHNldCBvZiB1bmlxdWUgZ2VuZXMgaGlnaGVyIGluICIsIGRlbm9taW5hdG9yX25hbWUsCiAgICAgICAgICAgICIgdnMuIHd0IGlzICIsIGxlbmd0aChkZW5vbWluYXRvcl9nZW5lcyksICIuIikKICAgIG1lc3NhZ2UoIlRoZSB1bmlxdWUgdW5pb24gb2YgdGhlbSBpcyAiLCBsZW5ndGgoaW5jbHVkZV9nZW5lcyksICIgZ2VuZXMuIikKICAgIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBjb250cmFzdCkKICAgIGluY2x1ZGVfaWR4IDwtIGFsbF9nZW5lcyAlaW4lIGluY2x1ZGVfZ2VuZXMKICAgIGluY2x1ZGVfZ2VuZXMgPC0gYWxsX2dlbmVzW2luY2x1ZGVfaWR4XQogICAgZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIGNvbnRyYXN0KQogICAgcmV0bGlzdFtbZGZfbmFtZV1dIDwtIGluY2x1ZGVkX2RmCiAgICB3cml0dGVuX2luY2x1c2lvbiA8LSB3cml0ZV94bHN4KGRhdGEgPSBpbmNsdWRlZF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWwgPSBnbHVlKCJpbmNsdWRlZF9nZW5lcy97aW5jbHVkZV9uYW1lfS12e3Zlcn0ueGxzeCIpKQogICAgcmV0bGlzdFtbaW5jbHVkZV9uYW1lXV0gPC0gaW5jbHVkZV9nZW5lcwogICAgcmV0bGlzdFtbY29udHJhc3RdXSA8LSBpbmNsdWRlX2dlbmVzCiAgfQogIHJldHVybihyZXRsaXN0KQp9CmBgYAoKIyMjIEV4dHJhY3QgZ2VuZXMgZXhjbHVkZWQgZm9yIGVhY2ggc2V0IG9mIGNvbnRyYXN0cwoKTm93LCB1c2luZyB0aGF0IGZ1bmN0aW9uLCBwdWxsIG91dCB0aGUgZ2VuZSBJRHMgb2YgZ2VuZXMgd2UgZG8gbm90CnRydXN0IGJlY2F1c2UgdGhleSB3ZXJlIHRvbyBoaWdoIGluIHd0IGZvciBldmVyeSBjb250cmFzdCB3ZSBhcmUKbGlrZWx5IHRvIHBlcmZvcm0uCgpgYGB7cn0KYWxsX2dlbmVzIDwtIHJvd25hbWVzKGV4cHJzKHYzX3BhaXJ3aXNlX2lucHV0KSkKdGltZV9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfa2VlcGVycywgYWxsX2dlbmVzKQoKbG9jYXRpb25faW5jbHVzaW9ucyA8LSBleHRyYWN0X2luY2x1c2lvbnMoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fa2VlcGVycywgYWxsX2dlbmVzKQoKZ2Vub3R5cGVfaW5jbHVzaW9ucyA8LSBleHRyYWN0X2luY2x1c2lvbnMoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2Vub3R5cGVfa2VlcGVycywgYWxsX2dlbmVzKQpgYGAKCiMjIFBlcmZvcm0gdGhlIERFIGFuYWx5c2VzIGFuZCBleGNsdWRlIHRoZSB0YXJnZXQgZ2VuZXMKCmBgYHtyfQpnZW5vdHlwZV9kZSA8LSBhbGxfcGFpcndpc2UodjNfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gZ2Vub3R5cGVfa2VlcGVycywgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIikKZ2Vub3R5cGVfZGUKCmxvY2F0aW9uX2RlIDwtIGFsbF9wYWlyd2lzZSh2M19wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBsb2NhdGlvbl9rZWVwZXJzLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKQpsb2NhdGlvbl9kZQoKdGltZV9kZSA8LSBhbGxfcGFpcndpc2UodjNfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSB0aW1lX2tlZXBlcnMsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpCnRpbWVfZGUKYGBgCgojIyBFeHRyYWN0IHRoZSByZWxldmFudCB0YWJsZXMgYW5kIGluY2x1ZGUgZ2VuZXMgbG93ZXIgaW4gd3QKCiMjIyBHZW5vdHlwZSBjb250cmFzdHMKCkkgd2lsbCBzdGFydCB3aXRoIHRoZSB0YWJsZXMgYW5kIG5vIGluY2x1c2lvbnMgc28gSSBjYW4gY2hlY2sgbXkgd29yay4KCkluIHRoaXMgZmlyc3QgYmxvY2sgSSB3aWxsIGV4cGxhaW4gYSBsaXR0bGUgbW9yZSB0aG9yb3VnaGx5IHdoYXQgaXMKZ29pbmcgb246CgoxLiAgRHVtcCB0aGUgZnVsbCB0YWJsZSBvZiB0aGUgY29udHJhc3RzIEkgZGVmaW5lZCBhYm92ZSBjb21wYXJpbmcgdGhlCiAgICAzIGdlbm90eXBlcyBhY3Jvc3MgdGltZS9sb2NhdGlvbi4KMi4gIEl0ZXJhdGUgb3ZlciBlYWNoIG9mIHRob3NlIGNvbnRyYXN0cyBhbmQgZG8gdGhlIGZvbGxvd2luZzoKICAgIGEuICBFeHRyYWN0IHRoZSBuYW1lIG9mIHRoZSBjb250cmFzdCwgJ2toX3AwOF9kbGduJyBmb3IgZXhhbXBsZQogICAgYi4gIFlhbmsgb3V0IHRoYXQgc3BlY2lmaWMgZW50cnkgZnJvbSB0aGUga2VlcGVyIGxpc3QgYW5kIGl0cyBuYW1lCiAgICBjLiAgWWFuayBvdXQgdGhlIGNvcnJlc3BvbmRpbmcgc2V0IG9mIGdlbmVzIHRvIGluY2x1ZGUgZnJvbSB0aGUKICAgICAgICBpbmNsdXNpb25zIGRhdGEgc3RydWN0dXJlLgogICAgZC4gIENyZWF0ZSBhIGZpbGVuYW1lIGdpdmVuIHRoZSBuYW1lIGluIChhKSBhYm92ZSBhbmQgdGhlIGxvZ0ZDCiAgICAgICAgY3V0b2ZmIGNob3NlbiBmb3IgdGhlIGluY2x1c2lvbnMgKEkgYW0gYXNzdW1pbmcgd2UgbWF5IGNoYW5nZQogICAgICAgIHRoaXMpCiAgICBlLiAgR2l2ZW4gKGIpLCAoYyksIGFuZCAoZCksIGV4dHJhY3QgdGhlIGNvcnJlc3BvbmRpbmcgdGFibGUgZnJvbQogICAgICAgIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBhbmQgaW5jbHVkZSB0aGUgYXBwcm9wcmlhdGUKICAgICAgICBnZW5lcy4KCmBgYHtyfQpnZW5vdHlwZV90YWJsZXNfZnVsbCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBnZW5vdHlwZV9kZSwga2VlcGVycyA9IGdlbm90eXBlX2tlZXBlcnMsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoImZ1bGxfY29udHJhc3RzL2dlbm90eXBlX2Z1bGxfdGFibGVzLXZ7dmVyfS54bHN4IikpCmdlbm90eXBlX3RhYmxlc19mdWxsCgpnZW5vdHlwZV9zaWdfZnVsbCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGdlbm90eXBlX3RhYmxlc19mdWxsLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogIGV4Y2VsID0gZ2x1ZSgiZnVsbF9jb250cmFzdHMvZ2Vub3R5cGVfZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKZ2Vub3R5cGVfc2lnX2Z1bGwKCmdlbm90eXBlX3RhYmxlcyA8LSBsaXN0KCkKZ2Vub3R5cGVfc2lnIDwtIGxpc3QoKQpnZW5vdHlwZV9ncCA8LSBsaXN0KCkKZ2Vub3R5cGVfY3AgPC0gbGlzdCgpCmZvciAoayBpbiBzZXFfYWxvbmcoZ2Vub3R5cGVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGdlbm90eXBlX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGdlbm90eXBlX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSBnZW5vdHlwZV9pbmNsdXNpb25zW1tpbmNsdWRlX25hbWVdXQogIHN1bW1hcnkocm93bmFtZXMoZ2Vub3R5cGVfc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzKQogIGluY2x1ZGVfZmlsZW5hbWUgPC0gZ2x1ZSgiZ2Vub3R5cGVfY29udHJhc3RzL2dlbm90eXBlX3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiZ2Vub3R5cGVfY29udHJhc3RzL2dlbm90eXBlX3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIGdlbm90eXBlX3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgZ2Vub3R5cGVfZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9kZiwKICAgIGtlZXBlcnMgPSBrZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSwgd2FudGVkX2dlbmVzID0gaW5jbHVkZXMpCiAgcHJpbnQoZ2Vub3R5cGVfdGFibGVzW1tuYW1lXV0pCiAgZ2Vub3R5cGVfc2lnW1tuYW1lXV0gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGdlbm90eXBlX3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludChnZW5vdHlwZV9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhnZW5vdHlwZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgaWYgKG51bV9yb3dzID4gMTApIHsKICAgIG1lc3NhZ2UoIlBlcmZvcm1pbmcgZ3Byb2ZpbGVyL2NsdXN0ZXJQcm9maWxlci4iKQogICAgZ2Vub3R5cGVfZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKGdlbm90eXBlX3NpZ1tbbmFtZV1dLCBzcGVjaWVzID0gIm1tdXNjdWx1cyIpCiAgICBncF93cml0dGVuIDwtIHdyaXRlX2FsbF9ncChnZW5vdHlwZV9ncFtbbmFtZV1dKQogICAgZ2Vub3R5cGVfY3BbW25hbWVdXSA8LSBhbGxfY3Byb2ZpbGVyKGdlbm90eXBlX3NpZ1tbbmFtZV1dLCBnZW5vdHlwZV90YWJsZXNbW25hbWVdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AoZ2Vub3R5cGVfY3BbW25hbWVdXSkKICB9Cn0KYGBgCgojIyMgTG9jYXRpb24gY29udHJhc3RzIHdpdGggZ2VuZXMgcmVtb3ZlZC9rZXB0CgpSZXBlYXQgdGhlIHNhbWUgYmxvY2sgd2l0aCBhIGZpbmQvcmVwbGFjZSBvZiBnZW5vdHlwZS9sb2NhdGlvbi4KCmBgYHtyfQpsb2NhdGlvbl90YWJsZXNfZnVsbCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBsb2NhdGlvbl9kZSwga2VlcGVycyA9IGxvY2F0aW9uX2tlZXBlcnMsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoImZ1bGxfY29udHJhc3RzL2xvY2F0aW9uX2Z1bGxfdGFibGVzLXZ7dmVyfS54bHN4IikpCmxvY2F0aW9uX3RhYmxlc19mdWxsCgpsb2NhdGlvbl9zaWdfZnVsbCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGxvY2F0aW9uX3RhYmxlc19mdWxsLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogIGV4Y2VsID0gZ2x1ZSgiZnVsbF9jb250cmFzdHMvbG9jYXRpb25fZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKbG9jYXRpb25fc2lnX2Z1bGwKCmxvY2F0aW9uX3RhYmxlcyA8LSBsaXN0KCkKbG9jYXRpb25fc2lnIDwtIGxpc3QoKQpsb2NhdGlvbl9ncCA8LSBsaXN0KCkKbG9jYXRpb25fY3AgPC0gbGlzdCgpCmZvciAoayBpbiBzZXFfYWxvbmcobG9jYXRpb25fa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGxvY2F0aW9uX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGxvY2F0aW9uX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tuYW1lXV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gbG9jYXRpb25faW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tpbmNsdWRlX25hbWVdXQogIHN1bW1hcnkocm93bmFtZXMobG9jYXRpb25fc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzKQogIGluY2x1ZGVfZmlsZW5hbWUgPC0gZ2x1ZSgibG9jYXRpb25fY29udHJhc3RzL2xvY2F0aW9uX3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgibG9jYXRpb25fY29udHJhc3RzL2xvY2F0aW9uX3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIGxvY2F0aW9uX3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbG9jYXRpb25fZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9kZiwKICAgIGtlZXBlcnMgPSBrZWVwZXIsIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSwgd2FudGVkX2dlbmVzID0gaW5jbHVkZXMpCiAgcHJpbnQobG9jYXRpb25fdGFibGVzW1tuYW1lXV0pCiAgbG9jYXRpb25fc2lnW1tuYW1lXV0gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGxvY2F0aW9uX3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludChsb2NhdGlvbl9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgaWYgKG51bV9yb3dzID4gMTApIHsKICAgIGxvY2F0aW9uX2dwW1tuYW1lXV0gPC0gYWxsX2dwcm9maWxlcihsb2NhdGlvbl9zaWdbW25hbWVdXSwgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AoZ2Vub3R5cGVfZ3BbW25hbWVdXSkKICAgIGxvY2F0aW9uX2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcihsb2NhdGlvbl9zaWdbW25hbWVdXSwgbG9jYXRpb25fdGFibGVzW1tuYW1lXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnZGIgPSAib3JnLk1tLmVnLmRiIikKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKGdlbm90eXBlX2NwW1tuYW1lXV0pCiAgfQp9CmBgYAoKIyMjIEFuZCB0aW1lCgpgYGB7cn0KdGltZV90YWJsZXNfZnVsbCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICB0aW1lX2RlLCBrZWVwZXJzID0gdGltZV9rZWVwZXJzLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoImZ1bGxfY29udHJhc3RzL3RpbWVfZnVsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKdGltZV9zaWdfZnVsbCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIHRpbWVfdGFibGVzX2Z1bGwsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCJmdWxsX2NvbnRyYXN0cy90aW1lX2Z1bGxfc2lnLXZ7dmVyfS54bHN4IikpCnRpbWVfdGFibGVzIDwtIGxpc3QoKQp0aW1lX3NpZyA8LSBsaXN0KCkKdGltZV9ncCA8LSBsaXN0KCkKdGltZV9jcCA8LSBsaXN0KCkKZm9yIChrIGluIHNlcV9hbG9uZyh0aW1lX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyh0aW1lX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIHRpbWVfa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc1tbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIHRpbWVfaW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSB0aW1lX2luY2x1c2lvbnNbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyh0aW1lX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoInRpbWVfY29udHJhc3RzL3RpbWVfe25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3RhYmxlLXZ7dmVyfS54bHN4IikKICBpbmNsdWRlX3NpZ19maWxlbmFtZSA8LSBnbHVlKCJ0aW1lX2NvbnRyYXN0cy90aW1lX3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIHRpbWVfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0aW1lX2RlLCBleHRyYV9hbm5vdCA9IGluY2x1ZGVfZGYsCiAgICBrZWVwZXJzID0ga2VlcGVyLCBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgICBleGNlbCA9IGluY2x1ZGVfZmlsZW5hbWUsIHdhbnRlZF9nZW5lcyA9IGluY2x1ZGVzKQogIHByaW50KHRpbWVfdGFibGVzW1tuYW1lXV0pCiAgdGltZV9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgdGltZV90YWJsZXNbW25hbWVdXSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSkKICBwcmludCh0aW1lX3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgaWYgKG51bV9yb3dzID4gMTApIHsKICAgIHRpbWVfZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKHRpbWVfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKHRpbWVfZ3BbW25hbWVdXSkKICAgIHRpbWVfY3BbW25hbWVdXSA8LSBhbGxfY3Byb2ZpbGVyKHRpbWVfc2lnW1tuYW1lXV0sIHRpbWVfdGFibGVzW1tuYW1lXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AodGltZV9jcFtbbmFtZV1dKQogIH0KfQpgYGAKCiMgVHJhbnNsYXRvbWUgcXVlcmllcwoKSW4gY29udmVyc2F0aW9uIHdpdGggQ29sZW5zbywgaGUgc3Bva2UgYWJvdXQgYSBzZXJpZXMgb2YgY29udHJhc3RzCndoaWNoIHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGF0dGVtcHQgaW4gb3JkZXIgdG8gcXVlcnkgdGhlIGNoYW5nZXMKYWNyb3NzIGJvdGggbG9jYXRpb25zIGFuZCBnZW5vdHlwZXMgYW5kL29yIGJvdGggbG9jYXRpb25zIGFuZCB0aW1lLAp0aHVzOgoKKHAwOF9oZXRfc2NuIC8gcDA4X2hldF9yZXRpbmEpIC8gKHAwOF9rb19zY24gLyBwMDhfa29fcmV0aW5hKQoKYXMgYW4gZXhhbXBsZS4gIFdlIGNhbiBkZWZpbml0ZWx5IGRvIHRoZXNlLCBidXQgdGhleSBkbyBub3Qgd29yayBmb3IKYWxsIG1ldGhvZHMgZW1wbG95ZWQgKEkgdGhpbmsgdGhleSB3b3JrIGJlc3Qgd2l0aCBsaW1tYSBhbmQgZWRnZVIpLgoKTGV0cyBmaW5kIG91dCEKCmBgYHtyfQpzY25fZXh0cmEgPC0gInAwOGhldF92c19wMDhrbyA9IChwMDhfaGV0X3NjbiAtIHAwOF9oZXRfcmV0aW5hKSAtIChwMDhfa29fc2NuIC0gcDA4X2tvX3JldGluYSksIHAxNWhldF92c19wMTVrbyA9IChwMTVfaGV0X3NjbiAtIHAxNV9oZXRfcmV0aW5hKSAtIChwMTVfa29fc2NuIC0gcDE1X2tvX3JldGluYSkiCnNjbl90cmFuc2xhdG9tZV9rZWVwZXJzIDwtIGxpc3QoCiAgInAwOF9oZXRfc2NuX3ZzX3JldGluYSIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhfa29fc2NuX3ZzX3JldGluYSIgPSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiKSwKICAicDA4X3Njbl90cmFuc2xhdG9tZSIgPSBjKCJwMDhoZXQiLCAicDA4a28iKSwKICAicDE1X2hldF9zY25fdnNfcmV0aW5hIiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAxNV9rb19zY25fdnNfcmV0aW5hIiA9IGMoInAxNV9rb19zY24iLCAicDE1X2tvX3JldGluYSIpLAogICJwMTVfc2NuX3RyYW5zbGF0b21lIiA9IGMoInAxNWhldCIsICJwMTVrbyIpKQoKcDA4X2RsZ25fZXh0cmEgPC0gInAwOGhldF92c19wMDhrbyA9IChwMDhfaGV0X2RsZ24gLSBwMDhfaGV0X3JldGluYSkgLSAocDA4X2tvX2RsZ24gLSBwMDhfa29fcmV0aW5hKSIKcDA4X2RsZ25fdHJhbnNsYXRvbWVfa2VlcGVycyA8LSBsaXN0KAogICJwMDhfaGV0X2RsZ25fdnNfcmV0aW5hIiA9IGMoInAwOF9oZXRfZGxnbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhfa29fZGxnbl92c19yZXRpbmEiID0gYygicDA4X2tvX2RsZ24iLCAicDA4X2tvX3JldGluYSIpLAogICJwMDhfZGxnbl90cmFuc2xhdG9tZSIgPSBjKCJwMDhoZXQiLCAicDA4a28iKSkKCnRpbWVfaGV0X3Njbl9leHRyYSA8LSAicDE1aGV0X3ZzX3AwOGhldCA9IChwMTVfaGV0X3NjbiAtIHAxNV9oZXRfcmV0aW5hKSAtIChwMDhfaGV0X3NjbiAtIHAwOF9oZXRfcmV0aW5hKSwgcDE1a29fdnNfcDA4a28gPSAocDE1X2tvX3NjbiAtIHAxNV9rb19yZXRpbmEpIC0gKHAwOF9rb19zY24gLSBwMDhfa29fcmV0aW5hKSIKdGltZV9oZXRfc2NuX3RyYW5zbGF0b21lX2tlZXBlcnMgPC0gbGlzdCgKICAicDE1X2hldF9zY192c19yZXRpbmEiID0gYygicDE1X2hldF9zY24iLCAicDE1X2hldF9yZXRpbmEiKSwKICAicDA4X2hldF9zY192c19yZXRpbmEiID0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAic2NuX2hldF90cmFuc2xhdG9tZSIgPSBjKCJwMTVoZXQiLCAicDA4aGV0IiksCiAgInNjbl9rb190cmFuc2xhdG9tZSIgPSBjKCJwMTVrbyIsICJwMDhrbyIpKQoKCgpgYGAKCiMgQmlibGlvZ3JhcGh5Cg==