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

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

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!

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

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

4.1 Color choices

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

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

5 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" 
## [11] "iprgc_73"  "iprgc_74"  "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_79"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83" 
## [21] "iprgc_84"  "iprgc_85"  "iprgc_86"  "iprgc_88"  "iprgc_93"  "iprgc_95"  "iprgc_96"  "iprgc_98"  "iprgc_100" "iprgc_105"
## [31] "iprgc_106" "iprgc_107" "iprgc_108" "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" 
## [11] "iprgc_74"  "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85" 
## [21] "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95" 
## [31] "iprgc_96"  "iprgc_97"  "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108"
## [41] "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113" "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_121" "iprgc_123"
## [51] "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127" "iprgc_128" "iprgc_129" "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
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" 
## [11] "iprgc_74"  "iprgc_75"  "iprgc_77"  "iprgc_78"  "iprgc_80"  "iprgc_81"  "iprgc_82"  "iprgc_83"  "iprgc_84"  "iprgc_85" 
## [21] "iprgc_86"  "iprgc_87"  "iprgc_88"  "iprgc_89"  "iprgc_90"  "iprgc_91"  "iprgc_92"  "iprgc_93"  "iprgc_94"  "iprgc_95" 
## [31] "iprgc_96"  "iprgc_97"  "iprgc_98"  "iprgc_100" "iprgc_102" "iprgc_104" "iprgc_105" "iprgc_106" "iprgc_107" "iprgc_108"
## [41] "iprgc_110" "iprgc_111" "iprgc_112" "iprgc_113" "iprgc_114" "iprgc_115" "iprgc_117" "iprgc_118" "iprgc_119" "iprgc_121"
## [51] "iprgc_123" "iprgc_124" "iprgc_125" "iprgc_126" "iprgc_127" "iprgc_128" "iprgc_129" "iprgc_130"
## Scale for colour is already present.
## Adding another scale for colour, which will replace the existing scale.
## Scale for fill is already present.
## Adding another scale for fill, which will replace the existing scale.
v3_nonzero
## A non-zero genes plot of 68 samples.
## These samples have an average 4.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.

6 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

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

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

8 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
##   <fct>    <chr>     <chr>           <int>    <dbl>  <dbl> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <int>     <dbl>         <dbl>
## 1 dlgn     numeric   opn                 0        1 0.0849 0.195     0  0      0     0    0.675    23    0.0407      0.000476
## 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 scn      numeric   opn                 0        1 0.0450 0.142     0  0      0     0    0.561    19    0.0326     -0.0234  
## # ℹ 1 more variable: mean.conf.high <dbl>
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!

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

10 PCA plots

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

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

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

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.

Here is Theresa’s next line:

hetkeeper_genes <- mm_de_normal_p8_ret$deseq$all_tables$wtretina_vs_hetretina %>%
  filter(logFC <= -.25 & adj.P.Val <= 0.05)

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

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

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

keepergenes <- unique(c(rownames(hetkeeper_genes), rownames(kokeeper_genes)))

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"))
both_increased_genes <- unique(c(increased_het_genes, increased_ko_genes))
LS0tCnRpdGxlOiAiQW4gaW5pdGlhbCBleHBsb3JhdGlvbiBvZiB0aGUgSVBSR0MgcmUtcHJvY2Vzc2VkIHNhbXBsZXMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBkZl9wcmludDogcGFnZWQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNnB4Cn0KYm9keSAubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTYwMHB4Owp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGhwZ2x0b29scykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdnc3RhdHNwbG90KQp0dCA8LSB0cnkoZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldCgKICBwcm9ncmVzcyA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFLCB3aWR0aCA9IDkwLCBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVycm9yID0gVFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDgsIGZpZy5yZXRpbmEgPSAyLAogIG91dC53aWR0aCA9ICIxMDAlIiwgZGV2ID0gInBuZyIsCiAgZGV2LmFyZ3MgPSBsaXN0KHBuZyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoZGlnaXRzID0gNCwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjQwNiIKcHJldmlvdXNfZmlsZSA8LSAiIgp2ZXIgPC0gZm9ybWF0KFN5cy5EYXRlKCksICIlWSVtJWQiKQoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCnJtZF9maWxlIDwtICJpbml0aWFsX2FuYWx5c2VzLlJtZCIKYGBgCgojIE1lZXRpbmcgd2l0aCBUaGVyZXNhCgpQcmV2aW91cyBwYXBlcnMgZGlkIG5vdCBkbyBhbiBleHBsaWNpdCBzdWJ0cmFjdGlvbiwgaW5zdGVhZCBqdXN0CmNvbXBhcmVkIHRvIFdUIGFuZCBrZXB0IHRoZSBnZW5lcyB3aGljaCBhcmUgPiBpbiBkZWx0YS9oZXQgdnMuIHd0LgpUaGVyZSBhcmUgbXVsdGlwbGUgd2F5cyB0byBkZWFsIHdpdGggdGhpcyBhbmQgdGhhdCBxdWVyeSBoYXMgbm90IHlldApiZWVuIGRlZmluZWQuICBMYXRlciwgVGhlcmVzYSBjYW1lIHRvIHRoZSBjb25jbHVzaW9uIHRoYXQgdGhlCnN1YnRyYWN0aW9uIG1ldGhvZCBpcyBub3QgYXBwcm9wcmlhdGUuCgojIEludHJvZHVjdGlvbgoKSW4gdGhpcyBkb2N1bWVudCBJIGhvcGUgdG8gZXhwbG9yZSB0aGUgZnJlc2hseSBwcm9jZXNzZWQgc2FtcGxlcyBhbmQKcGVyZm9ybSBzb21lIGNvbXBhcmlzb25zIHRvIHNlZSB0aGF0IHdlIGhhdmUgdGhlIGV4cGVjdGVkIHNpbWlsYXJpdGllcwphbmQgZGlmZmVyZW5jZXMgZnJvbSB0aGUgcHJpb3IgYW5hbHlzaXMgcGVyZm9ybWVkIGJ5IFRoZXJlc2EuCgpUaGVyZSBpcyBvbmUgd2F5IGluIHdoaWNoIEkgZXhwZWN0IGFueS9hbGwgb2YgdGhlc2UgYW5hbHlzZXMgdG8gYmUKZXhwbGljaXRseSBkaWZmZXJlbnQ6IHRoaXMgc2hvdWxkIGluY2x1ZGUgdGhlIGNoYW5nZXMgcHJvZHVjZWQgYnkKQXByaWwncyByZW5hbWluZyBvZiBzb21lIHNhbXBsZXMuCgpNeSBpbnRlbnRpb24gaXMgdG8gcHJvZHVjZSBhIHNhbXBsZSBzaGVldCB3aGljaCBpbmNsdWRlcyBvbmUgY29sdW1uCndpdGggbm9uLXVtaS1kZWR1cGxpY2F0ZWQgcmVzdWx0cyBhbmQgb25lIHdpdGggZGVkdXBsaWNhdGVkIHJlc3VsdHMuCldpdGggdGhlIGV4Y2VwdGlvbiBvZiB0aGUgcHJldmlvdXMgcG9pbnQsIEkgaG9wZSB0aGF0IHRoZSBmaXJzdCB3aWxsCmJlIGlkZW50aWNhbCAob3IgYXQgbGVhc3QgdmVyeSBjbG9zZSB0byBpZGVudGljYWwpIHRvIFRoZXJlc2EncyByZXN1bHQKd2hpbGUgdGhlIHNlY29uZCBJIGV4cGVjdCB3aWxsIGJlIHN1YnRseSBkaWZmZXJlbnQgLS0gYnV0IEkgYW0gaG9waW5nCnN1YnRseSBlbm91Z2ggdGhhdCBpdCB3aWxsIG5vdCBzaWduaWZpY2FudGx5IGNoYW5nZSB0aGUgaW50ZXJwcmV0YXRpb24KYnV0IGJlIGEgbGl0dGxlIG1vcmUgcHJlY2lzZS4KCkxldHMgc2VlISAgSSBuZWVkIHRoZXJlZm9yZSB0byBtYWtlIGEgY2hhbmdlIHRvIG15IG1ldGFkYXRhIGdhdGhlcmluZwpmdW5jdGlvbiB0byBpbmNsdWRlIHRoZSB1bWkgZGVkdXBsaWNhdGVkIHJlc3VsdC4gIEkgYW0gdGhpbmtpbmcKdGhlcmVmb3JlIHRvIGNyZWF0ZSBhIHNlcGFyYXRlIHNwZWNpZmljYXRpb24gZm9yIHVtaS1iYXJjb2RlZCBzYW1wbGVzCmJlY2F1c2UgbG9va2luZyB0aHJvdWdoIHRoZSBsb2dzIGZvciB1bWkgc3R1ZmYgd2hlbiB0aGV5IGFyZSBub3QgdXNlZAp3aWxsIGJlIHRvbyBtdWNoIG9mIGEgcGFpbi4uLgoKYGBge3J9CnVtaV9zcGVjIDwtIG1ha2Vfcm5hc2VxX3NwZWModW1pID0gVFJVRSkKaXByZ2NfMjAyMl9tZXRhIDwtIGdhdGhlcl9wcmVwcm9jZXNzaW5nX21ldGFkYXRhKCJzYW1wbGVfc2hlZXRzLzIwMjQwNjA2X29ubHlfdW1kX3NlcXVlbmNlZC54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwZWMgPSB1bWlfc3BlYywgc3BlY2llcyA9ICJtbTM5XzExMiIsIHZlcmJvc2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VkaXIgPSAicHJlcHJvY2Vzc2luZy91bWRfc2VxdWVuY2VkIikKYGBgCgpGcm9tIHRoaXMgcG9pbnQgb24sIEkgYW0gaG9waW5nL2ludGVuZGluZyB0byBwdWxsIGxpYmVyYWxseSBmcm9tClRoZXJlc2EncyBub3RlYm9vayB3aXRoIGEgZGl2ZXJzaW9uIHRvIGNvbXBhcmUgdGhlIHRocmVlIGRhdGFzZXRzOgoKKiBQcmUtQXByaWwgcmVuYW1pbmc6IEUuZy4gVGhlcmVzYSdzIGN1cnJlbnQgZGF0YXNldAoqIFBvc3QgcmVuYW1pbmc6IFVubGVzcyBJIGFtIG1pc3Rha2VuLCB0aGlzIHNob3VsZCBiZSB2ZXJ5IHNpbWlsYXIgdG8KICB0aGUgYWJvdmUuCiogUG9zdCBkZWR1cGxpY2F0aW9uOiBHaXZlbiB3aGF0IEkgc2F3IGZyb20gdGhlIGV4dHJhY3RlZCBsb2dzIGluIHRoZQogIHNhbXBsZSBzaGVldCwgSSBleHBlY3QgdGhpcyB0byBiZSBzaW1pbGFyIGJ1dCBub3QgaWRlbnRpY2FsIHRvIHRoZQogIHByZXZpb3VzIHR3by4KCkxldHMgZmluZCBvdXQhICAgQnV0IGZpcnN0LCBhbm5vdGF0aW9ucyEKCiMgQW5ub3RhdGlvbiBkYXRhCgpJIGFtIHB1bGxpbmcgdGhpcyBmcm9tIFRoZXJlc2EncyBhbnhvbnRyYXBSX3BpcGVsaW5lLlJtZCwgcHJpbWFyaWx5CmJlY2F1c2UgaXQgbG9va3Mgc2ltaWxhciB0byB0aGUgb3RoZXIgZG9jdW1lbnRzLCBidXQgd2FzIG1vZGlmaWVkIG1vcmUKcmVjZW50bHkuICBJIHdpbGwgY2hhbmdlIGl0IHNsaWdodGx5LCBwcmltYXJpbHkgYmVjYXVzZSBJIGdyYWJiZWQgYQpuZXcgbW11c2N1bHVzIGFzc2VtYmx5IGFuZCB0aGVyZWZvcmUgSSB3aWxsIHB1bGwgdGhlIG1tdXNjdWx1cwphbm5vdGF0aW9ucyBmcm9tIGEgc3BlY2lmaWMgYmlvbWFydCBhcmNoaXZlIHRoYXQgc2hvdWxkIG1hdGNoIGl0LgoKYGBge3J9Cm1tX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyhzcGVjaWVzID0gIm1tdXNjdWx1cyIsIHllYXIgPSAiMjAyMyIsIG1vbnRoID0gIjAyIikKbW1fYW5ub3QgPC0gbW1fYW5ub3RbWyJhbm5vdGF0aW9uIl1dCm1tX2Fubm90W1sidHhpZCJdXSA8LSBwYXN0ZTAobW1fYW5ub3RbWyJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiXV0sICIuIiwgbW1fYW5ub3RbWyJ2ZXJzaW9uIl1dKQpyb3duYW1lcyhtbV9hbm5vdCkgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlPVRSVUUpCnR4X2dlbmVfbWFwIDwtIG1tX2Fubm90WywgYygidHhpZCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KYGBgCgojIEhpc2F0MiBleHByZXNzaW9uc2V0cwoKVGhlIHByaW1hcnkgZGlmZmVyZW5jZSBiZXR3ZWVuIG15IGJsb2NrIGFuZCBUaGVyZXNhJ3MgYXJlOgoKMS4gIEkgYW0gcHVsbGluZyB0aGUgbWV0YWRhdGEgZGlyZWN0bHkgZnJvbSB0aGUKICAgIGdhdGhlcl9wcmVwcm9jZXNzaW5nX21ldGFkYXRhKCkgYWJvdmUuCjIuICBJIGFtIHVzaW5nIHRoZSBjb2x1bW4gJ3N5bWxpbmsnIHdoaWNoIGlzIGp1c3QgYSBjb3B5IG9mIHRoZQogICAgZXhpc3RpbmcgJ2ZpbGUnIGNvbHVtbiB3aXRoIGEgc21hbGwgY2hhbmdlIHNvIEkgY2FuIGxvYWQgaXQgZnJvbQogICAgbXkgZGlyZWN0b3J5IHdpdGhvdXQgaGF2aW5nIHRvIGNvcHkgZXZlcnl0aGluZy4KMy4gIEkgYW0gdXNpbmcgdGhlIGVuc2VtYmwgZ2Vub21lIHJlbGVhc2UgMzksIHZlcnNpb24gMTEyIGFuZCBzbwogICAgcHVsbGVkIGEgc29tZXdoYXQgbmV3ZXIgY29weSBvZiB0aGUgYW5ub3RhdGlvbiBkYXRhLgo0LiAgVGhlIG9yaWdpbmFsIGlzIG5hbWVkICd2MScsIGZvbGxvd2VkIGJ5ICd2MicgYW5kICd2MycgZm9yIHRoZQogICAgb3RoZXIgdHdvIHRyZWF0bWVudHMgSSBwZXJmb3JtZWQuCgojIyBDb2xvciBjaG9pY2VzCgpHaXZlbiB0aGF0IHdlIGFyZSBleGNsdWRpbmcgYSBidW5jaCBvZiB0aGUgb2xkZXIgc2FtcGxlcywgdGhlIHNldCBvZgpjb2xvcnMgSSBleHBlY3QgdG8gZmluZCBpcyBkaWZmZXJlbnQ7IHNvIEkgd2lsbCBtYWtlIGV4cGxpY2l0IGhlcmUgdGhlCnZhcmlvdXMgY29sb3JzIHVzZWQgdG8gZGVub3RlIGxvY2F0aW9uL2dlbm90eXBlL3RpbWUvZXRjLgoKQXByaWwgdHVybmVkIG1lIG9udG8gdGhpcyB3ZWJzaXRlICdwYWxldHRvbi5jb20nIGZvciB0aGlzIGtpbmQgb2YKc3R1ZmYgYW5kIEkgd2lsbCB0cnkgYW5kIHBpY2sgb3V0IHBhbGV0dGVzIHdoaWNoIGJhc2ljYWxseSBtYXRjaCB3aGF0CkkgYW0gZ2V0dGluZyB3aXRoIHRoZSBvcmlnaW5hbCBjb2xvcnMuCgpgYGB7cn0KY29sb3JfY2hvaWNlcyA8LSBsaXN0KAogICJnZW5vX2xvYyIgPSBsaXN0KAogICAgImhldF9kbGduIiA9ICIjOUVDQUUxIiwKICAgICJoZXRfcmV0aW5hIiA9ICIjRjQ2RDQzIiwKICAgICJoZXRfc2NuIiA9ICIjMkNBMjVGIiwKICAgICJrb19kbGduIiA9ICIjMzE4MkJEIiwKICAgICJrb19yZXRpbmEiID0gIiNGREFFNjEiLAogICAgImtvX3NjbiIgPSAiIzAwNkQyQyIsCiAgICAid3RfZGxnbiIgPSAiI0RFRUJGNyIsCiAgICAid3RfcmV0aW5hIiA9ICIjRDczMDI3IiwKICAgICJ3dF9zY24iID0gIiM2NkMyQTQiKSwKICAjIyBUaGVzZSBjb2xvcnMgYXJlIGNvbWluZyBmcm9tIGlwUkdDX3N1bW1hcnlwbG90cy5odG1sCiAgIyMgSSBhbSB1c2luZyBrY29sb3JjaG9vc2VyIHRvIGdyYWIgdGhlbSByYXRoZXIgdGhhbiBnZXQgY29uZnVzZWQgYnkgdGhlIHRleHQKICAibG9jYXRpb24iID0gbGlzdCgKICAgICJyZXRpbmEiID0gIiNkNzMwMjciLAogICAgImRsZ24iID0gIiMzMTgyYmQiLAogICAgInNjbiIgPSAiIzAwNmIyOSIpLAogICJnZW5vdHlwZSIgPSBsaXN0KAogICAgInd0IiA9ICIjRDRENEQ0IiwKICAgICJoZXQiID0gIiM3ODc4NzgiLAogICAgImtvIiA9ICIjMzEzMTMxIiksCiAgInRpbWUiID0gbGlzdCgKICAgICJwMDgiID0gIiM1RTEwNEIiLAogICAgInAxNSIgPSAiIzRFOTIzMSIpKQpgYGAKClRoZXJlIGlzIG9uZSBub3Rld29ydGh5IHNhbXBsZTogaXByZ2NfMTAzLCBpdCB3YXMgZWZmZWN0aXZlbHkgcmVwbGFjZWQKd2hlbiBBcHJpbCByZW5hbWVkIHRoZSBzYW1wbGVzIGFuZCBzbyBleGlzdHMgaW4gdGhlIHYxIGRhdGEsIGJ1dCBub3QKdjIvdjM7IHRoZXkgaW5zdGVhZCBoYXZlIHRoZSBuZXdseSBuYW1lZCBzYW1wbGVzIHdoaWNoIEkgY2FsbGVkCmlwcmdjXzEyMyB0byBpcHJnY18xMzAuICBBcyBhIHJlc3VsdCwgSSBjb3BpZWQgdGhlIGFubm90YXRpb25zIGZvcgppcHJnY18xMjMgdG8gbXkgY29sdW1uIHNvIHRoYXQgdGhlcmUgaXMgbm8gZGlzY3JlcGVuY3kgaW4gdGVybXMgb2YKZ2Vub3R5cGUvbG9jYXRpb24vdGltZS4KCmBgYHtyfQptbTM4X2hpc2F0X3YxIDwtIGNyZWF0ZV9leHB0KGlwcmdjXzIwMjJfbWV0YVtbIm5ld19tZXRhIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IG1tX2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfY29sdW1uID0gInN5bWxpbmsiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiZ2Vub2xvY2F0YiIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ0aW1lYXRiIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXSkKbW0zOF9oaXNhdF92MQoKbW0zOF9oaXNhdF92MiA8LSBjcmVhdGVfZXhwdChpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSwgZ2VuZV9pbmZvID0gbW1fYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAiaGlzYXRfY291bnRfdGFibGUiKSAlPiUKICBzZXRfZXhwdF9jb25kaXRpb25zKGZhY3QgPSAiZ2Vub2xvY2F0YiIpICU+JQogIHNldF9leHB0X2JhdGNoZXMoZmFjdCA9ICJ0aW1lYXRiIikgJT4lCiAgc2V0X2V4cHRfY29sb3JzKGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXSkKbW0zOF9oaXNhdF92MgoKbW0zOF9oaXNhdF92MyA8LSBjcmVhdGVfZXhwdChpcHJnY18yMDIyX21ldGFbWyJuZXdfbWV0YSJdXSwgZ2VuZV9pbmZvID0gbW1fYW5ub3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9jb2x1bW4gPSAidW1pX2RlZHVwX291dHB1dF9jb3VudCIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vbG9jYXRiIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInRpbWVhdGIiKSAlPiUKICBzZXRfZXhwdF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImdlbm9fbG9jIl1dKQptbTM4X2hpc2F0X3YzCmBgYAoKIyBOb24temVybyBDb3VudHMgcGVyIFNhbXBsZQoKTGV0J3MgbG9vayBhdCB0aGUgbnVtYmVyIG9mIG5vbi16ZXJvIGdlbmVzIGZvciBhbGwgc2FtcGxlcyB2ZXJzdXMgdGhlCmNvdmVyYWdlLgoKYGBge3J9CnBsb3RfbGVnZW5kKG1tMzhfaGlzYXRfdjEpCgp2MV9ub256ZXJvIDwtIHBsb3Rfbm9uemVybyhtbTM4X2hpc2F0X3YxKQp2MV9ub256ZXJvCgp2Ml9ub256ZXJvICA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF92MikKdjJfbm9uemVybwoKdjNfbm9uemVybyAgPC0gcGxvdF9ub256ZXJvKG1tMzhfaGlzYXRfdjMpCnYzX25vbnplcm8KYGBgCgpPaCB3b3csIEkgZGlkIG5vdCBleHBlY3Qgc3VjaCBhIHByb2ZvdW5kIGVmZmVjdCBvbiB0aGUgY3BtIHZhbHVlcyBvbgp0aGUgbW9yZSBzYXR1cmF0ZWQgbGlicmFyaWVzLiAgSSBndWVzcyBpbiByZXRyb3NwZWN0IEkgc2hvdWxkIGhhdmU/CgpBbHNvIG5vdGUgdG8gc2VsZiwgd2UgYXJlIG5vdCBtZXNzaW5nIHdpdGggcDYwLgoKYGBge3J9Cm1tMzhfaGlzYXRfdjEgPC0gc3Vic2V0X2V4cHQobW0zOF9oaXNhdF92MSwgc3Vic2V0ID0gInRpbWVhdGIhPSdwNjAnIikKbW0zOF9oaXNhdF92MiA8LSBzdWJzZXRfZXhwdChtbTM4X2hpc2F0X3YyLCBzdWJzZXQgPSAidGltZWF0YiE9J3A2MCciKQptbTM4X2hpc2F0X3YzIDwtIHN1YnNldF9leHB0KG1tMzhfaGlzYXRfdjMsIHN1YnNldCA9ICJ0aW1lYXRiIT0ncDYwJyIpCmBgYAoKIyBRdWljayBQQ0EsIHRoZW4gcmV0dXJuIHRvIFRoZXJlc2EncyBkb2N1bWVudAoKYGBge3J9CnYxX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MSwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnYyX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MiwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCnYzX25vcm0gPC0gbm9ybWFsaXplX2V4cHQobW0zOF9oaXNhdF92MywgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIGZpbHRlciA9IFRSVUUpCgpwbG90X3BjYSh2MV9ub3JtKQpwbG90X3BjYSh2Ml9ub3JtKQpwbG90X3BjYSh2M19ub3JtKQpgYGAKClRvIG15IGV5ZXMgaXQgbG9va3MgbGlrZSB3ZSBqdXN0IGhhdmUgMSB3ZWlyZG8gcDE1IHNhbXBsZT8KRGVkdXBsaWNhdGlvbiBoYWQgYSBtaW5vciBidXQgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBQQ0EuCgpXaXRoIHRoYXQgaW4gbWluZCwgbGV0IHVzIGxvb2sgYXQgVGhlcmVzYSdzIFdPUktJTkcgZG9jdW1lbnQgYW5kIHNlZQp3aGF0IHdlIGNhbiByZWNhcGl0dWxhdGUuCgpUaGVyZXNhJ3MgZG9jdW1lbnQ6IFRoZSBUUkFQIHByb3RvY29sIGhhcyBzb21lIHZhcmlhYmlsaXR5IHdoaWNoIGlzCmludHJvZHVjZWQgYXQgZGlmZmVyZW50IHN0ZXBzIGluY2x1ZGluZyBob21vZ2VuaXphdGlvbiwgYW50aWJvZHkKbGFiZWxpbmcsIHB1bGxkb3duIGVmZmljaWVuY3kvc3BlY2lmaWNpdHksIHNhbXBsZSBoYW5kbGluZyBkdXJpbmcKY2xlYW51cCBzdGVwcywgYW5kIGxpYnJhcnkgcHJlcC9zZXF1ZW5jaW5nLiBXZSBrbm93IGZyb20gUmFzaG1pJ3MgUUMKdGhhdCB0aGVyZSBpcyB2YXJpYWJpbGl0eSBhdCB0aGUgbGV2ZWwgb2YgcHVsbGRvd24gZWZmaWNpZW5jeSAoYW1vdW50Cm9mIFJOQSBpc29sYXRlZCkuIFNoZSBpcyBkb2luZyBhIGdvb2Qgam9iIG9mIGtlZXBpbmcgdHJhY2sgb2YgdGhpcyBmb3IKYWxsIGhlciBzYW1wbGVzIGFuZCB3ZSBoYXZlIHZhbGlkYXRlZCBoZXIgUDggcmVzdWx0cyAoYXR0YWNoZWQKc3VwcGxlbWVudGFyeSBmaWd1cmUgM0QpLiBXZSBjb25zaXN0ZW50bHkgc2VlIGNsZWFyIGRpZmZlcmVuY2VzCmJldHdlZW4gY29udHJvbCBhbmQgY3JlIHNhbXBsZXMgZm9yIHRoZSByZXRpbmEsIHdoaWNoIG1ha2VzIHNlbnNlCmJlY2F1c2UgdGhlIGNlbGwgYm9kaWVzIGFyZSBpbiB0aGUgcmV0aW5hLiBUaGUgdGFyZ2V0IHRpc3N1ZQpkaWZmZXJlbmNlcyBhcmUgc21hbGxlciwgd2hpY2ggYWxzbyBtYWtlcyBzZW5zZSBmb3IgYXhvbi1UUkFQLiBXZQp0aGluayB0aGF0IHNvbWUgb2YgaGVyIFAxNSBzYW1wbGVzIGFyZSBub3QgZ29vZCBiYXNlZCBvbiBsb3cgYW1vdW50cwpvZiBpc29sYXRlZCBSTkEgZnJvbSBjcmUoKykgcmV0aW5hIHNhbXBsZXMuIFdlIHBsYW4gdG8gZHJvcCB0aGVzZQpzYW1wbGVzIGFuZCBub3QgcGVyZm9ybSBhZGRpdGlvbmFsIGlzb2xhdGlvbnMgYXQgdGhpcyB0aW1lCnBvaW50LiBCYXNlZCBvbiB0aGlzIChhbmQgdGhlIGdlbmVyYWwgbGFjayBvZiBsYXJnZSBkZXZlbG9wbWVudGFsCmVmZmVjdHMpLCB3ZSB3ZXJlIHBsYW5uaW5nIHRvIGZvY3VzIG9uIHByZXNlbnRpbmcgdGhlIFA4IGRhdGEgb25seSBpbgp0aGUgcGFwZXIuIEludGVyZXN0ZWQgdG8gaGVhciB5b3VyIHRob3VnaHRzIGluIHRoaXMuLi4KCk15IG5vdGVzOiBUaGVyZXNhJ3MgZmlyc3Qgb3BlcmF0aW9ucyBpbiB0aGlzIG5vdGVib29rIHdlcmUgdG86CgoxLiAgU2V0IGxvY2F0aW9uIGFzIGNvbmRpdGlvbiwgZ2Vub3R5cGUgYXMgYmF0Y2guCjIuICBQZXJmb3JtIFBDQSBiZWZvcmUvYWZ0ZXIgc3ZhLgoKYGBge3J9CnYzX2xvY19nZW5vIDwtIHNldF9leHB0X2NvbmRpdGlvbnMobW0zOF9oaXNhdF92MywgZmFjdCA9ICJsb2NhdGlvbmF0YiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZ2Vub3R5cGVhdGIiKQpgYGAKCiMjIFRoZSBhc3NvY2lhdGVkIFBDQQoKQXQgZGlmZmVyZW50IHRpbWVzLCBpdCBhcHBlYXJzIHRvIG1lIHRoYXQgVGhlcmVzYSBoYXMgcHJlZmVycmVkCnNsaWdodGx5IGRpZmZlcmVudCBub3JtYWxpemF0aW9uIG1ldGhvZHMsIHByaW1hcmlseSBhIG1peCBvZiBUTU0gYW5kCnF1YW50aWxlLgoKVGh1cyBJIHdpbGwgdXNlIGRpZmZlcmVudCBzdWZmaXggbGV0dGVycyB0byBkZW5vdGUgdmFyaW91cwpub3JtYWxpemF0aW9ucyBlbXBsb3llZCwgYW5kIGlmIHRoZXkgdHVybiBvdXQgdGhlIHNhbWUgSSB3aWxsIHBpY2sgb25lIGFyYml0cmFyaWx5LgoKYGBge3J9CmxvY19nZW5vX25xIDwtIG5vcm1hbGl6ZV9leHB0KHYzX2xvY19nZW5vLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCnBsb3RfcGNhKGxvY19nZW5vX25xKQojIyBvaywgSSBoYXZlIHR3byB3ZWlyZG8gc2FtcGxlcyB3aGljaCBsb29rIHZlcnkgbXVjaCBsaWtlIHRoZXkgYXJlIGFjdHVhbGx5IGRsZ24uCiMjIFRoZXNlIGFyZSBzYW1wbGUgSURzIGlwcmdjXzY2IGFuZCBpcHJnY18xMzAKCmxvY19nZW5vX250IDwtIG5vcm1hbGl6ZV9leHB0KHYzX2xvY19nZW5vLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInRtbSIpCnBsb3RfcGNhKGxvY19nZW5vX250KQpgYGAKCkEgcmFuZG9tIHRob3VnaHQgYWJvdXQgdGhlc2UgUENBIHBsb3RzLCBpdCBtaWdodCBiZSB3b3J0aCB3aGlsZSB0byBhZGQKYSBwYW5lbCBiZWxvdyB0aGUgbGVnZW5kIHdpdGggdGhlIHNhbXBsZSBudW1iZXJzIHBlciBjb25kaXRpb24vYmF0Y2guCgpPZiBjb3Vyc2UsIHRoZSBzYW1lIGluZm9ybWF0aW9uIGlzIHByb3ZpZGVkIGluIGEgbW9yZSBmdW4gZmFzaGlvbiB2aWEKbXkgc2lsbHkgc2Fua2V5IGZ1bmN0aW9uOgoKYGBge3J9CnNhbXBsZV9zYW5rZXkgPC0gcGxvdF9tZXRhX3NhbmtleSh2M19sb2NfZ2VubywgY29sb3JfY2hvaWNlcyA9IGNvbG9yX2Nob2ljZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JzID0gYygiZ2Vub3R5cGVhdGIiLCAibG9jYXRpb25hdGIiLCAidGltZWF0YiIpKQpzYW1wbGVfc2Fua2V5CmBgYAoKIyBBIFNob3J0IGNvbnZlcnNhdGlvbiB3aXRoIFJhc2htaQoKUmFzaG1pIGNhbWUgYnkgYW5kIHdlIGRpc2N1c3NlZCB0aGUgc2FtcGxlcyBhIGxpdHRsZS4gIFNoZSBzdWdnZXN0ZWQKdGhhdCBpcyBsaWtlbHkgdGhhdCB3ZSB3aWxsIG5lZWQgdG8gZXhjbHVkZSB0aGUgMjAyMjA1IHNhbXBsZXMsIHRoZXNlCm1heSBiZSBpZGVudGlmaWVkIGJ5IGEgZmV3IHdheXMsIG1vc3QgZWFzaWx5IEkgdGhpbmsgdmlhIHRoZQoncHJvamVjdGFoJyBjb2x1bW4sIHRoZXkgYXJlIHRoZSAwMjFfMSBzYW1wbGVzLgoKTXkgc2Vuc2Ugd2FzIHRoYXQgc2hlIGNvbmN1cnJlZCB3aXRoIG15IGludGVycHJldGF0aW9uIG9mIHRoZSB1bWkKZGVkdXBsaWNhdGlvbiwgc28gSSB3aWxsIGNvbnRpbnVlIHVzaW5nIHRoZSBkZWR1cGxpY2F0ZWQgcmVzdWx0cwpleGNsdXNpdmVseSwgYXQgbGVhc3QgZm9yIG5vdy4KCiMgTWVsYW5vcHNpbiBTYW5pdHkgQ2hlY2sKCk9uZSBvZiBUaGVyZXNhJ3MgZmlyc3QgY2hlY2tzIHdhcyB3aXNlbHkgZm9yIG1lbGFub3BzaW4uICBMZXQgdXMKcmVwZWF0IGEgdmVyc2lvbiBvZiB0aGlzOgoKYGBge3J9Cm9wbjRfZXhwcnMgPC0gZGF0YS5mcmFtZShjb21iaW5lZCA9IHBEYXRhKGxvY19nZW5vX250KVtbImdlbm9sb2NhdGIiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbiA9IHBEYXRhKGxvY19nZW5vX250KVtbImxvY2F0aW9uYXRiIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgZ2Vub3R5cGUgPSBwRGF0YShsb2NfZ2Vub19udClbWyJnZW5vdHlwZWF0YiJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgIG9wbiA9IGV4cHJzKGxvY19nZW5vX250KVsiRU5TTVVTRzAwMDAwMDIxNzk5IiwgXSkKCmdyb3VwZWRzdGF0czo6Z3JvdXBlZF9zdW1tYXJ5KG9wbjRfZXhwcnMsIGxvY2F0aW9uLCBvcG4pCmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gbG9jYXRpb24sIHkgPSBvcG4pCmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gZ2Vub3R5cGUsIHkgPSBvcG4pCmdnYmV0d2VlbnN0YXRzKGRhdGEgPSBvcG40X2V4cHJzLCB4ID0gY29tYmluZWQsIHkgPSBvcG4pCmBgYAoKb2ssIHNvIEkgcGxvdHRlZCB0aGUgcXVlc3Rpb24gYSBiaXQgZGlmZmVyZW50bHksIGJ1dCBnb3QgdGhlIHNhbWUKYW5zd2VyLgoKSGVyZSBpcyB0aGUgdGV4dCBvZiBUaGVyZXNhJ3Mgbm90ZWJvb2sgZm9sbG93aW5nIHRoaXMgYW5hbHlzaXM6CgoiVWdoIG9oLCBsb29rcyBsaWtlIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSByZXRpbmEgS08gc2FtcGxlIHRoYXQgaGFzCnNvbWUgbWVsYW5vcHNpbiBleHByZXNzaW9uIGluIGl0LiBUdXJucyBvdXQgaXBSR0NfMDcgaXMgYSBiYWQgZWdnCndoaWNoIGlzIHN1cHBvc2VkIHRvIGJlIGEgS08gYnV0IGhhcyBtZWxhbm9wc2luIGV4cHJlc3Npb24uIEl04oCZcwpmcmllbmRzIHdoaWNoIHdlcmUgcG9vbGVkIGZyb20gdGhlIHNhbWUgbWljZSBhcmUgaXByZ2NfMDYgYW5kCmlwcmdjXzA4LCBzbyB3ZSBuZWVkIHRvIGV4Y2x1ZGUgYWxsIHRoZXNlIHNhbXBsZXMuIgoKSSBhbSBhbHNvIHNlZWluZyBzb21lIGtub2Nrb3V0IGV4cHJlc3Npb24gd2l0aCBzb21lIGNhdmVhdHM6IEkgZG8gbm90CmhhdmUgdGhlIGFmZmVjdGVkIHNhbXBsZXMgaW4gbXkgZGF0YXNldCAoaXByZ2NfMDcpIGFuZCB0aGUgbGV2ZWxzIEkgYW0Kc2VlaW5nIGFyZSBxdWl0ZSBsb3cgLS0gSSB3aWxsIGxvb2sgaW4gSUdWIHRvIGRvdWJsZSBjaGVjaywgYnV0IEkKc3Ryb25nbHkgc3VzcGVjdCB0aGF0IHRoZXNlIGFyZSBzb21lIHBpZGRseSByZWFkcyBuZWFyIHRoZSBVVFJzLgoKT253YXJkIQoKIyBMaWJyYXJ5IHNpemVzIHBvc3QtZGVkdXBsaWNhdGlvbgoKVGhlcmVzYSdzIG5leHQgb3BlcmF0aW9uIHdhcyB0byBwZXJmb3JtIGxpYnNpemUvbm9uemVybyBwbG90cy4gIEkKYWxyZWFkeSBkaWQgdGhlIHByZS9wb3N0IGRlZHVwbGljYXRpb24gbm9uemVybywgaGVyZSBpcyB0aGUgYW5hbGFnb3VzCmxpYnNpemUuCgp2MiBpcyBwcmUtZGVkdXBsaWNhdGlvbiBhbmQgdjMgaXMgcG9zdC4KCmBgYHtyfQpwbG90X2xpYnNpemUobW0zOF9oaXNhdF92MikKcGxvdF9saWJzaXplKG1tMzhfaGlzYXRfdjMpCmBgYAoKSSBhbSBhIGJpdCBjb25jZXJuZWQgYWJvdXQgc29tZSBvZiB0aGVzZSBsaWJyYXJ5IHNpemVzCnBvc3QtZGVkdXBsaWNhdGlvbi4KCkxldCB1cyBsb29rIGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiByZWFkcyBhbmQgZHVwbGljYXRpb24sIHdoaWNoIEkKYXNzdW1lIHdpbGwgYmUgcmVsYXRpdmVseSBsaW5lYXIuCgpgYGB7cn0KdGVzdCA8LSBwRGF0YShtbTM4X2hpc2F0X3YzKVssIGMoImhpc2F0Z2Vub21lc2luZ2xlYWxsIiwgInVtaWRlZHVwcGN0cmVhZHMiKV0KdGVzdF9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIodGVzdCkKdGVzdF9wbG90W1sic2NhdHRlciJdXQpgYGAKClRoZXJlc2EgYWxzbyBwcm9kdWNlZCBhIGRlbnNpdHkvc2FtcGxlIHBsb3QsIHRoYXQgbWlnaHQgcHJvdmUgcXVpdGUKdXNlZnVsIGZvciB0aGVzZSBkdWUgdG8gdGhlaXIgc2lnbmlmaWNhbnRseSBsYXJnZXIgdmFyaWFuY2UgYWNyb3NzCnNhbXBsZXMgKGR1ZSB0byBkZWR1cGxpY2F0aW9uKS4KCmBgYHtyfQpwbG90X2RlbnNpdHkobW0zOF9oaXNhdF92MykKYGBgCgpUaGVyZSBpcyBzb21lIGRpZmZlcmVuY2UgYWNyb3NzIHNhbXBsZSBkZW5zaXRpZXMsIGJ1dCBpdCBpcyBub3QgdG9vCmNyYXp5dG93bi4KCiMgUENBIHBsb3RzCgojIyBQQ0Egb2YgYWxsIGdlbmVzIGJ5IGxvY2F0aW9uCgpUaGVyZXNhJ3MgZmlyc3QgcGNhIHdhcyBvZiBsb2cyIGNwbSB2YWx1ZXMuICBJIG1pZ2h0IGFkZCBxdWFudGlsZS90bW0KdG8gdGhpcz8KCmBgYHtyfQp2M19sb2NhdGlvbiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG1tMzhfaGlzYXRfdjMsIGZhY3QgPSAibG9jYXRpb25hdGIiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZ2Vub3R5cGVhdGIiKQoKdjNfbG9jYXRpb25fbm9ybSA8LSBub3JtYWxpemVfZXhwdCh2M19sb2NhdGlvbiwgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIpCnBsb3RfcGNhKHYzX2xvY2F0aW9uX25vcm0pCmBgYAoKT25jZSBhZ2FpbiB3ZSBzZWUgdGhhdCBzYW1wbGVzIGlwcmdjXzY2IGFuZCBpcHJnY18xMzAgYXJlIGxpa2VseQphY3R1YWxseSBETEdOIGFuZCBub3QgU0NOLiAgSSBhbSB0aGVyZWZvcmUgZ29pbmcgdG8gYWRkIGEgY29sdW1uIHRvCnRoZSBzYW1wbGUgc2hlZXQgbm90aW5nIHRoaXMsIGFuZCByZW1vdmUgdGhlbSBmcm9tIHRoZSBleHByZXNzaW9uc2V0LgoKSSB3aWxsIHRodXMgcmVwbG90IHRoZSBkYXRhIGFmdGVyIHJlbW92aW5nIHRob3NlIHR3by4gIElmIHdlIHdhbnQgdG8Kc2VlIHdoYXQgaXQgbG9va3MgbGlrZSB3aXRoIHRoZSByZS1hdHRyaWJ1dGVkIGxvY2F0aW9ucywgd2UgY2FuIGRvIHNvLgoKVGhlcmVzYSBoYXMgYSBuaWNlIGNoYW5nZSB0byB0aGUgUENBIHBsb3R0ZXIgaW4gd2hpY2ggc2hlIHNldHMgdGhlCmFscGhhIGNoYW5uZWwgYXMgYW4gYWRkaXRpb25hbCB2aXN1YWwgcXVldWUgZm9yIGEgbWV0YWRhdGEgZmFjdG9yLi4uCgpgYGB7cn0KbW0zOF9oaXNhdF92MyA8LSBzdWJzZXRfZXhwdChtbTM4X2hpc2F0X3YzLCBzdWJzZXQ9InNhbXBsZWlkIT0naXByZ2NfMTMwJyIpICU+JQogIHN1YnNldF9leHB0KHN1YnNldD0ic2FtcGxlaWQhPSdpcHJnY182NiciKQp2M19sb2NhdGlvbiA8LSBzZXRfZXhwdF9jb25kaXRpb25zKG1tMzhfaGlzYXRfdjMsIGZhY3QgPSAibG9jYXRpb25hdGIiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZ2Vub3R5cGVhdGIiKQp2M19sb2NhdGlvbl9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHYzX2xvY2F0aW9uLCBmaWx0ZXIgPSBUUlVFLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIikKcGxvdF9wY2EodjNfbG9jYXRpb25fbm9ybSkKCnJlbW92ZWRfc2Fua2V5IDwtIHBsb3RfbWV0YV9zYW5rZXkodjNfbG9jYXRpb24sIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcnMgPSBjKCJnZW5vdHlwZWF0YiIsICJsb2NhdGlvbmF0YiIsICJ0aW1lYXRiIikpCnJlbW92ZWRfc2Fua2V5CmBgYAoKSGVyZSBpcyBUaGVyZXNhJ3MgdGV4dCwgcmVjYWxsIG9uY2UgYWdhaW4gdGhhdCBJIGRvIG5vdCBoYXZlIHNvbWUgb2YKdGhlc2Ugb2xkZXIgc2FtcGxlcyAoaXByZ2NfNjIpOgoKUEMxIHZzIFBDMiBpZGVudGlmaWVzIHJldGluYSB2cyBheG9uIGlzIHN0aWxsIHRoZSBtYWluIGNvbXBvbmVudCBvZgp2YXJpYXRpb24uIFdlIGRvIHNlZSB0aG91Z2ggdGhhdCBpbiB0aGUgUEMyIGRpcmVjdGlvbiwgd2Ugc2VlIHdpdGggdGhlCm5ldyBzYW1wbGVzIGFkZGVkLCB3ZSBkb27igJl0IHNlZSBzZXBhcmF0aW9uIGJhc2VkIG9uIGF4b25hbCB0YXJnZXRzCihkTEdOIHZzIFNDTikuIEluIHRoZSBQQzEgdnMgUEMzIHBsb3QsIHdlIHNlZSB0aGF0IGl04oCZcyBQQzMgd2hlcmUgd2UKc3RhcnQgdG8gc2VlIHZhcmlhdGlvbiBjb3JyZWxhdGVkIHdpdGggYXhvbmFsIGNvbXBhcnRtZW50LiBMZXTigJlzIGxvb2sKYXQgUEMxIHZzIFBDMiBjb2xvcmVkIGJ5IGJhdGNoICh3aGVuIHRoZXkgd2VyZSBwcm9jZXNzZWQvc2VxdWVuY2VkKSB0bwpzZWUgaWYgdGhhdCBpcyB3aGF0IGlzIGNvbnRyaWJ1dGluZyBzbyBtdWNoIHZhcmlhdGlvbiBpbiBQQzIuCgpTaWRlIG5vdGU6IGlwUkdDIDYyIHNlZW1zIGxpa2UgYW4gb2RkIGJhbGwuIFRoaXMgc2VlbXMgdG8gbWUgbGlrZSBpdApzaG91bGQgaGF2ZSBiZWVuIGEgZExHTiBQMDggc2FtcGxlLiBJcyB0aGVyZSBhbnkgcG9zc2liaWxpdHkgdGhpcyBnb3QKbWlzbGFiZWxlZCBlYXJseSBvbj8gSSB3ZW50IGJhY2sgYW5kIGRvdWJsZSBjaGVja2VkIHRvIHNlZSBpZiBhbGwgbXkKcHJvY2Vzc2luZyBpcyBjb3JyZWN0IGFuZCBpdCBpbmRlZWQgd2FzIGxhYmVsZWQgYW4gU0NOIFAxNSBmcm9tIHRoZQp0aW1lIEkgZ290IHRoZSBzYW1wbGVzLCBhbmQgaXQgaXMgaW5kZWVkLgoKIyBERQoKSSBub3cgc3dpdGNoZWQgdG8gVGhlcmVzYSdzIGRvY3VtZW50ICdXT1JLSU5HX2F4b25UUkFQLi4uJyBhbmQgd2lsbApzdGFydCBwdWxsaW5nIHNlY3Rpb25zIGZyb20gaXQuICBJIGFtIHJlYXNvbmFibHkgY2VydGFpbiBJIGhhdmUKcmVhc29uYWJseSBzaW1pbGFyIHNhbXBsZSBkaXN0cmlidXRpb25zLCBzbyBJIHByZXN1bWUgSSBjYW4gaW52b2tlCnNpbWlsYXIvaWRlbnRpY2FsIGNhbGxzIGZvciBERVNlcSBhbmQgZnJpZW5kcy4KCiMjIHA4IHJldGluYXMKCkluIHRoZSBibG9jayBpbW1lZGlhdGVseSBiZWZvcmUgdGhlIERFIGFuYWx5c2VzLCBUaGVyZXNhIGNyZWF0ZWQgYQpzdWJzZXQgZXhwcmVzc2lvbnNldCBvZiBvbmx5IHAwOCByZXRpbmFzLiAgVGh1cyB0aGlzIGluaXRpYWwgREUgSQphc3N1bWUgd2lsbCBiZSB1c2VkIHRvIHN1YnRyYWN0IGZvciB0aGUgU0NOL0RMR04gYW5hbHlzZXMgdGhhdCBmb2xsb3cuCihJIGd1ZXNzIEkgY291bGQgcmVhZCBhaGVhZCBhbmQgZmluZCBvdXQsIGJ1dCBubyEgSSB3YW50IHRvIGJlIGEKYmxhbmsgc2xhdGUpCgpgYGB7cn0KbW0zOF9wOF9yZXRpbmEgPC0gc3Vic2V0X2V4cHQobW0zOF9oaXNhdF92Mywgc3Vic2V0ID0gInRpbWVhdGI9PSdwMDgnICYgbG9jYXRpb25hdGI9PSdyZXRpbmEnIikKCm1tX25vcm1hbF9wOF9yZXRfZGUgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfcDhfcmV0aW5hLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9ub3JtYWxfcDhfcmV0X2RlCmBgYAoKVGhlIGZvbGxvd2luZyBpbnZvY2F0aW9uIHBlcmZvcm1lZCBieSBUaGVyZXNhIGZpbHRlcnMgdGhlIHd0L2hldApjb21wYXJpc29uIGZvciBvbmx5IHRob3NlIGdlbmVzIHdoaWNoIGluY3JlYXNlZCBieSBhdCBsZWFzdCAwLjI1IGxvZ0ZDCndpdGggYSBzaWduaWZpY2FudCBhZGp1c3RlZCBwLXZhbHVlLiAgSSBhc3N1bWUgdGhhdCB0aGlzIGlzIHRvIHVzZSB0aGUKd3Qgc2FtcGxlcyBhcyBhIHRyYW5zbGF0aW9uYWwgY29udHJvbCBmb3IgdGhlIGtldC9rbyBjb21wYXJpc29uczsgSSBhbQp0aGVyZWZvcmUgdGhpbmtpbmcgdGhhdCBmb3IgbXkgcHVycG9zZXMsIEkgd2lsbCB0aGVyZWZvcmUgc2VwYXJhdGUgdGhlCmNvbnRyYXN0cyBmcm9tIGFsbF9wYWlyd2lzZSBkbyB0aGlzIGluIGEgc3RlcHdpc2UgZmFzaGlvbi4uLgoKVGhlIGJsb2NrIG9mIGNvZGUgaW1tZWRpYXRlbHkgZm9sbG93aW5nIFRoZXJlc2EncyBhbGxfcGFpcndpc2UoKQppbnZvY2F0aW9uIGlzIGEgbGl0dGxlIGNvbmZ1c2luZyBmb3IgbWUgYW5kIHdhcnJhbnRzIHNvbWUgZXhwbGFuYXRpb24KYnkgbWUgdG8gbWUgaW4gdGhlIGhvcGVzIHRoYXQgSSBkbyBub3QgbWlzdW5kZXJzdGFuZCB3aGF0IGlzIGhhcHBlbmluZwphbmQgdGhlIGdvYWxzIHRoZXJlaW4uCgpIZXJlIGlzIFRoZXJlc2EncyBuZXh0IGxpbmU6CgpgYGB7ciwgZXZhbD1GQUxTRX0KaGV0a2VlcGVyX2dlbmVzIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyR3dHJldGluYV92c19oZXRyZXRpbmEgJT4lCiAgZmlsdGVyKGxvZ0ZDIDw9IC0uMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKYGBgCgpJIHRoaW5rIEkgY2FuIHNhZmVseSBhc3N1bWUgdGhhdCB0aGUgZ29hbCBoZXJlIGlzIHRvIHB1bGwgb3V0IHRoZSBJRHMKd2hpY2ggaW5jcmVhc2VkIGluIGhldCB3aXRoIHJlc3BlY3QgdG8gd2lsZCB0eXBlOyBldmVuIGlmIGJ5IGEgc21hbGwKbWFyZ2luLCBhcyBsb25nIGFzIGl0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgdmlzIGEgdmlzIHRoZQphZGp1c3RlZCBwLXZhbHVlLgoKSSBhbSBnb2luZyB0byBwZXJmb3JtIHdoYXQgSSB0aGluayBpcyB0aGUgc2FtZSB0aGluZyBpbiBhIHNsaWdodGx5CmRpZmZlcmVudCBmYXNoaW9uIHNvIHRoYXQgSSBjYW4gc2hhcmUgYSBjb3B5IG9mIHRoZSByZXN1bHRzIHdpdGgKd2hvbWV2ZXIgaXMgaW50ZXJlc3RlZC4gIEkgd2lsbCBhbHNvIHJlcGVhdCBUaGVyZXNhJ3MgaW52b2NhdGlvbiBhbmQKcHJvdmUgdG8gbXlzZWxmIHRoYXQgSSB1bmRlcnN0b29kIGFuZCBnb3QgdGhlIHNhbWUgYW5zd2VyLgoKYGBge3J9Cnd0X2hldF9rZWVwZXIgPC0gbGlzdCgiaGV0X3ZzX3d0IiA9IGMoImhldHJldGluYSIsICJ3dHJldGluYSIpKQpoZXRfd3RfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMobW1fbm9ybWFsX3A4X3JldF9kZSwga2VlcGVycyA9IHd0X2hldF9rZWVwZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICJleGNlbC9oZXRfcmV0aW5hX2NvbnRyb2wueGxzeCIpCgp3YW50ZWRfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoaGV0X3d0X3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGZjID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY29yZGluZ190byA9ICJkZXNlcSIpCgp3YW50ZWRfaGV0X2luY3JlYXNlZCA8LSB3YW50ZWRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJoZXRfdnNfd3QiXV0KaW5jcmVhc2VkX2hldF9nZW5lcyA8LSByb3duYW1lcyh3YW50ZWRfaGV0X2luY3JlYXNlZCkKYGBgCgojIyBQcm92ZSBJIHVuZGVyc3Rvb2QKCmBgYHtyfQpoZXRrZWVwZXJfZ2VuZXMgPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0cmV0aW5hX3ZzX2hldHJldGluYSAlPiUKICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKdGVzdHRoYXQ6OmV4cGVjdF90cnVlKG5yb3coaGV0a2VlcGVyX2dlbmVzKSA9PSBsZW5ndGgoaW5jcmVhc2VkX2hldF9nZW5lcykpCmBgYAoKWWF5ISBJIGNhbiByZWFkISAgTm93IGxldCB1cyByZXBlYXQgZm9yIHRoZSBLTyB2cyB3dAoKYGBge3J9Cnd0X2tvX2tlZXBlciA8LSBsaXN0KCJrb192c193dCIgPSBjKCJrb3JldGluYSIsICJ3dHJldGluYSIpKQprb193dF90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gd3Rfa29fa2VlcGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICJleGNlbC9rb19yZXRpbmFfY29udHJvbC54bHN4IikKd2FudGVkX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGtvX3d0X3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGZjID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY29yZGluZ190byA9ICJkZXNlcSIpCndhbnRlZF9rb19pbmNyZWFzZWQgPC0gd2FudGVkX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sia29fdnNfd3QiXV0KaW5jcmVhc2VkX2tvX2dlbmVzIDwtIHJvd25hbWVzKHdhbnRlZF9rb19pbmNyZWFzZWQpCmBgYAoKVGhlIG5leHQgdGhpbmcgcGVyZm9ybWVkIGluIFRoZXJlc2EncyBkb2N1bWVudCBpcyBhIHVuaXF1ZShjb25jYXRlbmF0aW9uIG9mCnRoZXNlIHR3byBnZW5lIGdyb3VwcyksIHRodXMgc3Vja2luZyB1cCBldmVyeSBnZW5lIHdoaWNoIHdhcwpzaWduaWZpY2FudGx5IGhpZ2hlciBpbiBlaXRoZXIgdGhlIGtub2Nrb3V0IF9vcl8gaGV0ZXJ6eW91cyBzYW1wbGVzCndpdGggcmVzcGVjdCB0byB3aWxkLXR5cGUuCgpUaGlzIHdhcyBmb2xsb3dlZCBieSBhIGNvdXBsZSBvZiBtZXJnZSBvcGVyYXRpb25zIG9mIGEgbGl0dGxlIGJpdCBvZgp0aGUgYW5ub3RhdGlvbiBkYXRhOyBJIGFtIG5vdCBzdXJlIEkgdW5kZXJzdGFuZCB0aGUgZ29hbCB5ZXQuLi4KCkhlcmUgaXMgaGVyIGNvZGU6CgpgYGB7ciwgZXZhbD1GQUxTRX0Ka2VlcGVyZ2VuZXMgPC0gdW5pcXVlKGMocm93bmFtZXMoaGV0a2VlcGVyX2dlbmVzKSwgcm93bmFtZXMoa29rZWVwZXJfZ2VuZXMpKSkKCmFubm90c190b19tZXJnZSA8LSBtbV9hbm5vdCAlPiUKICAgIHNlbGVjdChlbnNlbWJsX2dlbmVfaWQsIGV4dGVybmFsX2dlbmVfbmFtZSkgJT4lCiAgICBmaWx0ZXIoZW5zZW1ibF9nZW5lX2lkICVpbiUgcm93bmFtZXMobW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvcmV0aW5hX3ZzX2hldHJldGluYSkpICU+JQogICAgZGlzdGluY3QoKQoKbW1fZGVfbm9ybWFsX3A4X3JldCRkZXNlcSRhbGxfdGFibGVzJGtvcmV0aW5hX3ZzX2hldHJldGluYSA8LSBtZXJnZShtbV9kZV9ub3JtYWxfcDhfcmV0JGRlc2VxJGFsbF90YWJsZXMka29yZXRpbmFfdnNfaGV0cmV0aW5hLCBhbm5vdHNfdG9fbWVyZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieS54ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5LnkgPSAiZW5zZW1ibF9nZW5lX2lkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbC54ID0gVFJVRSkKCmRmIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyRrb3JldGluYV92c19oZXRyZXRpbmEgJT4lCiAgICBkcGx5cjo6bXV0YXRlKGxvZ0ZDID0gLWxvZ0ZDKSAlPiUKICAgIHNldF9zaWdfbGltbWEoZmFjdG9ycyA9IGMoIkhldCBFbnJpY2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLTyBFbnJpY2hlZCIpKQpgYGAKCmBgYHtyfQpib3RoX2luY3JlYXNlZF9nZW5lcyA8LSB1bmlxdWUoYyhpbmNyZWFzZWRfaGV0X2dlbmVzLCBpbmNyZWFzZWRfa29fZ2VuZXMpKQpgYGAK