1 Introduction

This document is intended to repeat with minimal modification the work performed by Theresa when analyzing the RNASeq IPRGC data. This is being performed in an apptainer (ugh I hate that name) container and so I will likely remove some of the libraries invoked in it.

Not all of these are available in the container, and I do not think I have the version of Theresa’s helper_functions.R which was used for this. I did find a version of it that appears to work without any problems, though.

At the end of this document, I am going to try to re-implement it with some minor changes to see if I can more easily reconcile the results to the tables provided by Colenso.

library("hpgltools")
library("ggplot2")
library("patchwork")
library("plotly")
library("RColorBrewer")
library("DT")
library("dplyr")
library("openxlsx")
library("ComplexHeatmap")
library("circlize")
library("gprofiler2")
source("/data/helper_functions.R")
library("gplots")
library("ggrepel")
#setwd("~/scratch_02/reesyxan/mmusculus_iprgc_2019")

2 M. musculus

2.1 Annotations

I am using mm38_100.

mm_annot <- load_biomart_annotations(species = "mmusculus")
## 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)

mm_tx_annot <- mm_annot
## yeah, the ID tag in my gff file has transcript: as a prefix, so the featureCounts outputs
## includes it...  I will fix that inpost.
rownames(mm_tx_annot) <- make.names(mm_tx_annot[["ensembl_transcript_id"]], unique = TRUE)

tx_gene_map <- mm_annot[, c("txid", "ensembl_gene_id")]

So, I now have a table of mouse annotations.

2.2 Hisat2 expressionset

mm38_hisat <- create_se("sample_sheets/samplesheet_bulkrnaseq_Opn4.xlsx",
                        gene_info = mm_tx_annot, file_column = "salmon_count_table")
## Reading the sample metadata.
## Checking the state of the condition column.
## Checking the state of the batch column.
## Checking the condition factor.
## The sample definitions comprises: 57 rows(samples) and 27 columns(metadata fields).
## There are 184622 rows with trailing numbers, removing them.
## Matched 184622 annotations and counts out of 184622 count rows and 916710 annotations.
## The final summarized experiment has 184622 rows and 27 columns.

3 Color Set Up

color_condition <- mm38_hisat$initial_metadata$condition
color_condition <- factor(color_condition, levels = c("Retina_het", "Retina_ko",
                                                      "SCN_het", "SCN_ko", "dLGN_het", "dLGN_ko"))

color_values <- c( "#00BFC4",  "#9AD2D3", "#F8766D", "#FBADA7", "#7CAE00", "#D3EE8F")
col_fun = colorRamp2(c(0, 3, 6), c("blue", "pink", "red"))

4 Mapped Counts Per Sample Plot

library(forcats)
mm38_hisat <- set_conditions(mm38_hisat, fact = "batch")
## The numbers of samples by condition are:
## 
##  1  2  3 
## 18 18 21
## Setting colors with no pre-defined colors, using the Dark2 palette.
libsize_df <- as.data.frame(plot_libsize(mm38_hisat)$table)
rownames(libsize_df) <- mm38_hisat$design$sampleid
libsize_df$samplenum <- paste0(mm38_hisat$design[rownames(libsize_df), "samplenumb"], "_",
                               mm38_hisat$design[rownames(libsize_df), "batch"])
libsize_df$sample_id <-  rownames(mm38_hisat$design)
libsize_df <- libsize_df[order(libsize_df$sum),]

ggplot(libsize_df, aes(x = fct_rev(fct_infreq(samplenum, sum)), y = sum, fill = condition)) +
  geom_bar(stat = "identity", color = "black") +
  theme_classic() +
  #theme(axis.text.x= element_text(fct_rev(fct_infreq(libsize_df$samplenum, libsize_df$sum))), #remove x axis labels
  #    axis.ticks.x=element_blank()) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  scale_fill_manual(values = c("#60449b", "#009f6f", "orange")) +
  xlab("Sample") +
  ylab("Sum of Mapped Gene Counts") +
  labs(fill = "")

plot_libsize(mm38_hisat)
## Library sizes of 57 samples, 
## ranging from 3,037,266 to 19,545,726.

5 Normalize Expression

First we will filter out the genes which have low counts across all samples. Then I will normalize both without and with SVA correction.

mm38_filt <- normalize(mm38_hisat, filter = TRUE)
## Removing 128079 low-count genes (56543 remaining).
des <- colData(mm38_filt)
new_factor <- paste0(des[["location"]], "_", des[["genotype"]])
colData(mm38_hisat)[["location_genotype"]] <- new_factor

mm38_norm <- normalize(mm38_hisat, filter = TRUE, convert = "cpm",
                       norm = "quant", transform="log2")
## Removing 128079 low-count genes (56543 remaining).
## transform_counts: Found 1386506 values equal to 0, adding 1 to the matrix.
mm38_norm <- set_conditions(mm38_norm, fact = "location_genotype")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##         11          4          4         11          4          4         11 
##    dLGN_ko    dLGN_wt 
##          4          4
## Setting colors with no pre-defined colors, using the Dark2 palette.

6 Melanopsin Expression

Here is a plot of the Opn4 expression across all retina samples split by batch. The 4 quadrants in the plot are

het:1 – retina het samples in batch 1
het:2 – retina het samples in batch 2
ko:1 – retina ko samples in batch 1
ko:2 – retina ko samples in batch 2

This is a Tx comparison; I need to either drop this or hunt down the set of transcript IDs (which I did)

library(RColorBrewer)
colors <- brewer.pal(name = "Spectral", n = 2)
mm38_cpm <- normalize(mm38_filt, convert = "cpm")
df <- data.frame(exprs = assay(mm38_cpm)["ENSMUSG00000021799",],
                 genotype = as.factor(des[["genotype"]]),
                 location = as.factor(des[["location"]]),
                 sampleid = des[["sampleid"]],
                 samplenum = des[["samplenumb"]],
                 batch = des[["batch"]])

## Set postscript arguments
setEPS()
postscript("bulkRNAseq_Opn4Expression_Retina.eps")
cpm_df <- df |>
  filter(location == "Retina" | location == "retina")

## This is where I most miss ggstatsplot
## I am going to sit and write my own version of it.
ggplot(cpm_df, aes(x = samplenum, y = exprs, fill = genotype, group = genotype)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
  xlab("Sample") +
  ylab("Opn4 Counts Per Million (CPMs)") +
  #scale_fill_manual(values = c("#FFC107", "#004D40", "orange"),
  #                  aesthetics = "fill") +
  ggtitle("Retina Melanopsin Expression") +
  facet_wrap(~genotype:batch, scales = "free") +
  ylim(c(0, 25)) +
  theme_classic()
dev.off()

The WT samples in batch 3 have about double the Opn4 expression as the het samples in batch 3 (and batch 2).

7 PCA

pca_norm <- plot_pca(mm38_norm, plot_labels = FALSE)
pca_norm[["plot"]]

## rownames(pca_norm$result$v)
labels <- des[["sampleid"]]
## labels <- paste0(mm38_norm$design$sampleid, "_", mm38_norm$design$samplenumb)
all_df <-  cbind(as.data.frame(pca_norm$result$v), labels)

shape_genotype <- mm38_norm$design$genotype
color_condition <- mm38_norm$condition

## filter(sample_id %in% c("S3_Het_Ret_S1", "S4_Het_Ret_S4", "S5_Het_Ret_S16", "S1_Het_Ret_S1", "S2_Het_Ret_S4", "S3_Het_Ret_S7", "S4_Het_Ret_S10", "S5_Het_Ret_S13")) |>

pca_norm_plot <-  ggplot(all_df, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = color_condition, shape = shape_genotype),
             size = 5) +
  #scale_color_manual(values = color_values,
  #                  aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_norm$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_norm$prop_var[2], "% variance"))

#setEPS()                                             # Set postscript arguments
#postscript("bulkRNAseq_PCA_allsamples_labeledS5.eps")                           # Start graphics device driver
all_df[["labels"]] <- rownames(all_df)
pca_norm_plot + ggtitle("PCA Normalized Counts") +
geom_label_repel(data=filter(all_df,
                             labels %in% labels), #c('s5_het_dlgn', 's5_het_ret', 's5_het_scn')),
    nudge_x = 0.15,
    nudge_y = 0.15)

#dev.off()

7.1 Look at the first batch of sequencing

#batch 1 plot
all_df[rownames(all_df) %in% tolower(rownames(des[des[["batch"]] == "1",])),] |>
  ggplot(aes(x = PC1, y = PC2)) +
  geom_point(aes(color = color_condition[which(rownames(all_df) %in% tolower(rownames(des[des$batch == "1",])))],
                 shape = shape_genotype[which(rownames(all_df) %in% tolower(rownames(des[des$batch == "1",])))]),
             size = 5) +
  scale_color_manual(values = color_values,
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype", shape = "Genotype")   +
  ggtitle("PCA - Batch 1 RNAseq")  +
  labs(x = paste0("PC1: ",  pca_norm$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_norm$prop_var[2], "% variance"))

I think there is an easier way to do the above

b1 <- subset_se(mm38_norm, subset = "batch == '1'")
plot_pca(b1)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by Retina_het, Retina_ko, SCN_het, SCN_ko, dLGN_het, dLGN_ko
## Shapes are defined by 1.

b1_b2 <- subset_se(mm38_norm, subset = "batch == '1'|batch == '2'")
plot_pca(b1_b2)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by Retina_het, Retina_ko, SCN_het, SCN_ko, dLGN_het, dLGN_ko
## Shapes are defined by 1, 2.

#batch 1&2 plot
pca_batch1and2 <- all_df |>
  ggplot(aes(x = PC1, y = PC2)) +
  geom_point(aes(color = color_condition,
                 shape = shape_genotype),
             size = 5) +
  scale_color_manual(values = color_values,
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype", shape = "Genotype")   +
  ggtitle("PCA - Batch 1&2 RNAseq")  +
  labs(x = paste0("PC1: ",  pca_norm$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_norm$prop_var[2], "% variance"))


#setEPS()
#postscript(file = "rnaseq_pca-batch1and2.eps")
#pca_batch1and2
#dev.off()

In this pca plot, we see the retina samples cluster on the right in the PC1 direction and the brain samples cluster on the left in the PC 1 direction.

As we saw before, there is disparity between some of the hets. As it turns out, all of the new Het samples cluster with the KO samples as our one weirdo did before. So now it seems that it is quite easy to get some genetic drift that leads to these mice’s expression to behave in weird ways.

As we did before, let’s look at the Opn4 expression across all the retina samples to see if the Het samples that behave like KOs have lower Opn4 expression.

8 A closer look at the similar KOs and Hets

Let’s exclude the 2 Hets that are the most dissimilar from the bunch and look at a PCA plot of the rest of the samples.

## The following subset is using an older sample ID which I am unable to find anywhere.
## As a result, I rewrote that portion of Theresa's pca plot and labeled everything
## according to the extant naming scheme, I will now try and figure out which
## samples were removed.
## mm38_subset <- subset_se(
##   mm38_filt,
## subset = "sampleid != 'S3_Het_dLGN'&sampleid != 'S3_Het_Ret'&sampleid != 'S3_Het_SCN'&sampleid != 'S4_Het_dLGN'&sampleid != 'S4_Het_Ret'&sampleid != 'S4_Het_SCN'")
## S3_Het_dLGN_S2 is an outlier marked by Theresa
## S3_Het_Ret_S1 is an outlier
## S3_Het_SCN_S3 is an outlier
## S4_Het_dLGN_S11 is somewhat an outlier, I might be inclined to leave it.
## S4_Het_Ret_S4 is a huge outlier
## S4_Het_SCN_S6 is an outlier

## If I were choosing likely samples, I think I would go for:
##S4_Het_Ret_S4, S3_Het_Ret_S1, S3_Het_SCN_s3, S3_Het_dLGN_S2, S4_Het_dLGN_S5, S4_Het_SCN_S6

## Either way, I am adding a couple columns to the sample sheet with these calls for included samples.

mm38_subset <- subset_se(mm38_filt, subset = "included=='yes'")

mm38_subset <- normalize(mm38_subset, filter=TRUE, convert="cpm",
                         norm = "quant", transform="log2")
## Removing 2435 low-count genes (54108 remaining).
## transform_counts: Found 1107260 values equal to 0, adding 1 to the matrix.
mm38_subset <- set_conditions(mm38_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Setting colors with no pre-defined colors, using the Dark2 palette.
pca_norm_subset <- plot_pca(mm38_subset, plot_labels = FALSE)
pca_norm_subset
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by Retina_het, Retina_ko, Retina_wt, SCN_het, SCN_ko, SCN_wt, dLGN_het, dLGN_ko, dLGN_wt
## Shapes are defined by 1, 2, 3.

labels <- rownames(pca_norm_subset$result$v)

all_df <-  cbind(as.data.frame(pca_norm_subset$result$v), labels)
shape_genotype <- mm38_subset$design$genotype
color_condition <- pca_norm_subset$table$condition

pca_norm_plot <-  ggplot(pca_norm_subset$table, aes(x = PC1, y = PC2)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values,
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_norm_subset$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_norm_subset$prop_var[2], "% variance"))

pca_norm_plot <-  ggplot(all_df, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = color_condition, shape = shape_genotype),
             size = 5) +
  #scale_color_manual(values = color_values,
  #                  aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_norm_subset$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_norm_subset$prop_var[2], "% variance"))

#setEPS()                                             # Set postscript arguments
#postscript("bulkRNAseq_PCA_allsamples_labeledS5.eps")                           # Start graphics device driver
pca_norm_plot + ggtitle("PCA Normalized Counts -- Subset") +
  geom_label_repel(data=filter(all_df,
                               labels %in% c('s4_het_scn_s12', 's4_het_ret', 's4_het_scn', 's5_het_dlgn')),
                   nudge_x = 0.15,
                   nudge_y = 0.1)

pca_norm_plot + ggtitle("PCA Normalized Counts")# +

pca_norm_plot

# geom_label_repel(data=filter(all_df,
#                               labels %in% labels), #c('s4_het_scn', 's5_het_ret', 's5_het_scn', 's5_het_dlgn')),
#                   nudge_x = 0.15,
#                   nudge_y = 0.15)
#dev.off()

There really doesn’t seem to be a discernible difference globally between the hets and kos within each location. We can do a DE with these samples between het/kos to quantify this.

9 DE of KOs versus Low expressor Hets

mm38_filt_sub <- subset_se(mm38_filt, subset = "sampleid != 'S3_Het_dLGN'&sampleid != 'S3_Het_Ret'&sampleid != 'S3_Het_SCN'&sampleid != 'S4_Het_dLGN' & sampleid != 'S4_Het_Ret' & sampleid != 'S4_Het_SCN'")

mm38_dlgn_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'dLGN_het' | location_time == 'dLGN_ko'")
mm38_ret_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'Retina_het' | location_time == 'Retina_ko'")
mm38_scn_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'SCN_het' | location_time == 'SCN_ko'")

mm38_dlgn_subset <- normalize(mm38_dlgn_subset, filter = TRUE)
## Removing 16951 low-count genes (39592 remaining).
mm38_scn_subset <- normalize(mm38_scn_subset, filter = TRUE)
## Removing 16859 low-count genes (39684 remaining).
mm38_ret_subset <- normalize(mm38_ret_subset, filter = TRUE)
## Removing 18328 low-count genes (38215 remaining).
mm38_dlgn_subset <- set_batches(mm38_dlgn_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_scn_subset <- set_batches(mm38_scn_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_ret_subset <- set_batches(mm38_ret_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_dlgn_subset <- set_conditions(mm38_dlgn_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## dLGN_het  dLGN_ko 
##       11        4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm38_scn_subset <- set_conditions(mm38_scn_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## SCN_het  SCN_ko 
##      11       4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm38_ret_subset <- set_conditions(mm38_ret_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko 
##         11          4
## Setting colors with no pre-defined colors, using the Dark2 palette.
test <- set_conditions(mm38_filt, fact = "location_time") |>
normalize(transform = "log2", convert = "cpm", batch = "sva")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##         11          4          4         11          4          4         11 
##    dLGN_ko    dLGN_wt 
##          4          4
## Setting colors with no pre-defined colors, using the Dark2 palette.
## transform_counts: Found 460060 values less than 0.
## transform_counts: Found 460060 values equal to 0, adding 1 to the matrix.
plot_pca(test)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by Retina_het, Retina_ko, Retina_wt, SCN_het, SCN_ko, SCN_wt, dLGN_het, dLGN_ko, dLGN_wt
## Shapes are defined by 1, 2, 3.

I do not think one should really do the DE with the data separate like this unless there is some compelling reason. I am going to repeat without this constraint and see how similar/different the results are. In addition, the current revision of all_pairwise() is much more comfortable with more complex models, even with sva; so that might make this more fun.

mm_de_dlgn <- all_pairwise(mm38_dlgn_subset, model_fstring = "~ 0 + condition",
                           model_svs = "svaseq", filter = TRUE)
## dLGN_het  dLGN_ko 
##       11        4
## Removing 0 low-count genes (39592 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 219467 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_dlgn
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## The factors used are: dLGN_het, dLGN_ko.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 1 comparisons.
## The logFC agreement among the methods follows:
##                 dLGN___LGN
## basic_vs_dream   0.5048447
## basic_vs_ebseq   0.5902495
## basic_vs_edger   0.3869976
## basic_vs_limma   0.5131146
## basic_vs_noiseq  0.7710287
## dream_vs_ebseq   0.5027929
## dream_vs_edger   0.7223475
## dream_vs_limma   0.9804184
## dream_vs_noiseq  0.3396771
## ebseq_vs_edger   0.5814362
## ebseq_vs_limma   0.4727963
## ebseq_vs_noiseq  0.7726008
## edger_vs_limma   0.7157456
## edger_vs_noiseq  0.3700917
## limma_vs_noiseq  0.3317524
mm_table_dlgn <- combine_de_tables(mm_de_dlgn,
                                   excel = "39bulk_tables_tx/mm_de_dlgn_table.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
mm_sig_dlgn <- extract_significant_genes(mm_table_dlgn,
                                         excel = "39bulk_tables_tx/mm_de_dlgn_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.
mm_de_ret <- all_pairwise(mm38_ret_subset, model_fstring = "~ 0 + condition",
                          model_svs = "svaseq", filter = TRUE)
## Retina_het  Retina_ko 
##         11          4
## Removing 0 low-count genes (38215 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 165632 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## Retina_het  Retina_ko 
##         11          4
## conditions
## Retina_het  Retina_ko 
##         11          4
## conditions
## Retina_het  Retina_ko 
##         11          4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_ret
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## The factors used are: Retina_het, Retina_ko.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 1 comparisons.
## The logFC agreement among the methods follows:
##                 Rtn_k_v_R_
## basic_vs_dream   0.4567153
## basic_vs_ebseq   0.5316853
## basic_vs_edger   0.3292782
## basic_vs_limma   0.4681497
## basic_vs_noiseq  0.5870014
## dream_vs_ebseq   0.4335788
## dream_vs_edger   0.6679701
## dream_vs_limma   0.9889980
## dream_vs_noiseq  0.4626451
## ebseq_vs_edger   0.6107728
## ebseq_vs_limma   0.4217901
## ebseq_vs_noiseq  0.7164748
## edger_vs_limma   0.6669577
## edger_vs_noiseq  0.5256508
## limma_vs_noiseq  0.4617358
mm_table_ret <- combine_de_tables(mm_de_ret,
                                  excel = "39bulk_tables_tx/mm_de_ret_table.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
mm_sig_ret <- extract_significant_genes(mm_table_ret,
                                         excel = "39bulk_tables_tx/mm_de_ret_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.
mm_de_scn <- all_pairwise(mm38_scn_subset, model_fstring = "~ 0 + condition",
                          model_svs = "svaseq", filter = TRUE)
## SCN_het  SCN_ko 
##      11       4
## Removing 0 low-count genes (39684 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 201034 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## SCN_het  SCN_ko 
##      11       4
## conditions
## SCN_het  SCN_ko 
##      11       4
## conditions
## SCN_het  SCN_ko 
##      11       4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_scn
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## The factors used are: SCN_het, SCN_ko.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 1 comparisons.
## The logFC agreement among the methods follows:
##                 SCN___SCN_
## basic_vs_dream   0.5541243
## basic_vs_ebseq   0.5750793
## basic_vs_edger   0.4334210
## basic_vs_limma   0.5651717
## basic_vs_noiseq  0.7471217
## dream_vs_ebseq   0.5613151
## dream_vs_edger   0.7242821
## dream_vs_limma   0.9846958
## dream_vs_noiseq  0.3919830
## ebseq_vs_edger   0.6739467
## ebseq_vs_limma   0.5196392
## ebseq_vs_noiseq  0.7754524
## edger_vs_limma   0.7127799
## edger_vs_noiseq  0.4396494
## limma_vs_noiseq  0.3742456
mm_table_scn <- combine_de_tables(mm_de_scn, excel = "39bulk_tables_tx/mm_de_scn_table.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
mm_sig_scn <- extract_significant_genes(mm_table_scn, according_to = "deseq",
                                        excel = "39bulk_tables_tx/mm_de_scn_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.

9.1 SCN

keepers <- names(mm_de_scn$deseq$all_tables)
## Error in `mm_de_scn$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_scn <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_scn, table = tbl)
  res_tbls_scn[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  fctr <- c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
            paste(sub('.*\\_', '', tbl), "\nEnriched"))
  res_tbls_scn[[tbl]] <- set_sig_limma(res_tbls_scn[[tbl]], factors = fctr)
  res_tbls_scn[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_scn[[tbl]],
                                                          title = paste("Volcano Plot:", tbl),
                                                          type = "plotly",
                                                          tbl = "limma",
                                                          gene_name_col = "uniprot_gn_symbol")
  res_tbls_scn[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_scn[[tbl]],
                                                          title = paste("Volcano Plot:", tbl),
                                                          tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_scn$SCNko_vs_SCNhetvolc_ggplot
## NULL
res_tbls_scn$SCNko_vs_SCNhetvolc_plotly
## NULL
res_tbls_scn$SCNko_vs_SCNhet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

9.2 dLGN

keepers <- names(mm_de_dlgn$deseq$all_tables)
## Error in `mm_de_dlgn$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_dlgn <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_dlgn, table = tbl)
  res_tbls_dlgn[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls_dlgn[[tbl]] <- set_sig_limma(res_tbls_dlgn[[tbl]], factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                                                          paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls_dlgn[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_dlgn[[tbl]],
                                                           title = paste("Volcano Plot:", tbl),
                                                           type = "plotly",
                                                           tbl = "limma",
                                                           gene_name_col = "uniprot_gn_symbol")
  res_tbls_dlgn[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_dlgn[[tbl]],
                                                           title = paste("Volcano Plot:", tbl),
                                                           tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_dlgn$dLGNko_vs_dLGNhetvolc_ggplot
## NULL
res_tbls_dlgn$dLGNko_vs_dLGNhetvolc_plotly
## NULL
res_tbls_dlgn$dLGNko_vs_dLGNhet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

9.3 Retina

keepers <- names(mm_de_ret$deseq$all_tables)
## Error in `mm_de_ret$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_ret <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_ret, table = tbl)
  res_tbls_ret[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls_ret[[tbl]] <- set_sig_limma(res_tbls_ret[[tbl]], factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                                                        paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls_ret[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_ret[[tbl]],
                                                          title = paste("Volcano Plot:", tbl),
                                                          type = "plotly",
                                                          tbl = "limma",
                                                          gene_name_col = "uniprot_gn_symbol")
  res_tbls_ret[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_ret[[tbl]],
                                                          title = paste("Volcano Plot:", tbl),
                                                          tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_ret$Retinako_vs_Retinahetvolc_ggplot
## NULL
res_tbls_ret$Retinako_vs_Retinahetvolc_plotly
## NULL
res_tbls_ret$Retinako_vs_Retinahet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

10 DE of all samples with SVA batch correction for high v low expressors

mm38_dlgn_subset <- subset_se(
  mm38_filt, subset = "location_time == 'dLGN_het'| location_time == 'dLGN_ko'")
mm38_ret_subset <- subset_se(
  mm38_filt, subset = "location_time == 'Retina_het'| location_time == 'Retina_ko'")
mm38_scn_subset <- subset_se(
  mm38_filt, subset = "location_time == 'SCN_het'| location_time == 'SCN_ko'")

mm38_dlgn_subset <- normalize(mm38_dlgn_subset, filter = TRUE)
## Removing 16951 low-count genes (39592 remaining).
mm38_scn_subset <- normalize(mm38_scn_subset, filter = TRUE)
## Removing 16859 low-count genes (39684 remaining).
mm38_ret_subset <- normalize(mm38_ret_subset, filter = TRUE)
## Removing 18328 low-count genes (38215 remaining).
mm38_dlgn_subset <- set_batches(mm38_dlgn_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_scn_subset <- set_batches(mm38_scn_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_ret_subset <- set_batches(mm38_ret_subset, fact = "condition")
## The number of samples by batch are:
## 
## 1 2 3 
## 6 6 3
mm38_dlgn_subset <- set_conditions(mm38_dlgn_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## dLGN_het  dLGN_ko 
##       11        4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm38_scn_subset <- set_conditions(mm38_scn_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## SCN_het  SCN_ko 
##      11       4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm38_ret_subset <- set_conditions(mm38_ret_subset, fact = "location_time")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko 
##         11          4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm_de_dlgn_sva <- all_pairwise(mm38_dlgn_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## dLGN_het  dLGN_ko 
##       11        4
## Removing 0 low-count genes (39592 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 219467 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## conditions
## dLGN_het  dLGN_ko 
##       11        4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_ret_sva <- all_pairwise(mm38_ret_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## Retina_het  Retina_ko 
##         11          4
## Removing 0 low-count genes (38215 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 165632 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## Retina_het  Retina_ko 
##         11          4
## conditions
## Retina_het  Retina_ko 
##         11          4
## conditions
## Retina_het  Retina_ko 
##         11          4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_scn_sva <- all_pairwise(mm38_scn_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## SCN_het  SCN_ko 
##      11       4
## Removing 0 low-count genes (39684 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 201034 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## conditions
## SCN_het  SCN_ko 
##      11       4
## conditions
## SCN_het  SCN_ko 
##      11       4
## conditions
## SCN_het  SCN_ko 
##      11       4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.
mm_de_scn_sva
## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## The factors used are: SCN_het, SCN_ko.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 1 comparisons.
## The logFC agreement among the methods follows:
##                 SCN___SCN_
## basic_vs_dream   0.5541243
## basic_vs_ebseq   0.5750793
## basic_vs_edger   0.4334210
## basic_vs_limma   0.5651717
## basic_vs_noiseq  0.7471217
## dream_vs_ebseq   0.5613151
## dream_vs_edger   0.7242821
## dream_vs_limma   0.9846958
## dream_vs_noiseq  0.3919830
## ebseq_vs_edger   0.6739467
## ebseq_vs_limma   0.5196392
## ebseq_vs_noiseq  0.7754524
## edger_vs_limma   0.7127799
## edger_vs_noiseq  0.4396494
## limma_vs_noiseq  0.3742456
mm_scn_sva_table <- combine_de_tables(
  mm_de_scn_sva, excel = "excel/mm_subset_scn_sva_table.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
mm_scn_sva_table
## A set of combined differential expression results.
##               table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 SCN_ko_vs_SCN_het           0             0         276           156
##   limma_sigup limma_sigdown
## 1          17             0
## Only  has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
mm_scn_sva_sig <- extract_significant_genes(
  mm_scn_sva_table, excel = "excel/mm_subset_scn_sva_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.
mm_scn_sva_sig
## A set of genes deemed significant according to .
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## data frame with 0 columns and 0 rows

10.1 dLGN

10.1.1 PCA pre and post SVAseq

mm38_dlgn_subset_norm_batch <- normalize(mm38_dlgn_subset, convert = "cpm",
                                         transform = "log2", batch = "svaseq")
## transform_counts: Found 55001 values less than 0.
## transform_counts: Found 55001 values equal to 0, adding 1 to the matrix.
mm38_dlgn_subset_norm_nobatch <- normalize(mm38_dlgn_subset, convert = "cpm", norm = "quant",
                                           transform = "log2")
## transform_counts: Found 197525 values equal to 0, adding 1 to the matrix.
pca_mm38_dlgn_subset_norm_nobatch <- plot_pca(mm38_dlgn_subset_norm_nobatch)
pca_norm_plot_nobatch <-  ggplot(pca_mm38_dlgn_subset_norm_nobatch$table, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values,
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_dlgn_subset_norm_nobatch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_dlgn_subset_norm_nobatch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_dlgn_subset_norm_nobatch$table,
                               labels %in% c('S3_Ht_dLGN', 'S4_Ht_dLGN')),
                   nudge_x = 0.1,
                   nudge_y = 0.1)


pca_mm38_dlgn_subset_norm_batch <- plot_pca(mm38_dlgn_subset_norm_batch)
pca_norm_plot_batch <-  ggplot(pca_mm38_dlgn_subset_norm_batch$table, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values,
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with SVA Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_dlgn_subset_norm_batch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_dlgn_subset_norm_batch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_dlgn_subset_norm_batch$table,
                               labels %in% c('S3_Ht_dLGN', 'S4_Ht_dLGN')),
                   nudge_x = 0.1,
                   nudge_y = 0.1)


pca_norm_plot_nobatch

pca_norm_plot_batch

10.1.2 Volcano Plots ad DE table results

keepers <- names(mm_de_dlgn_sva$deseq$all_tables)
## Error in `mm_de_dlgn_sva$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_dlgn_sva <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_dlgn_sva, table = tbl)
  res_tbls_dlgn_sva[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls_dlgn_sva[[tbl]] <- set_sig_limma(res_tbls_dlgn_sva[[tbl]], factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                                                                  paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls_dlgn_sva[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_dlgn_sva[[tbl]],
                                                               title = paste("Volcano Plot:", tbl),
                                                               type = "plotly",
                                                               tbl = "limma",
                                                               gene_name_col = "uniprot_gn_symbol")
  res_tbls_dlgn_sva[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_dlgn_sva[[tbl]],
                                                               title = paste("Volcano Plot:", tbl),
                                                               tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_dlgn_sva$dLGNko_vs_dLGNhetvolc_ggplot
## NULL
res_tbls_dlgn_sva$dLGNko_vs_dLGNhetvolc_plotly
## NULL
res_tbls_dlgn_sva$dLGNko_vs_dLGNhet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

Samd11 and Dmrt3 are still both upregulated in dLGN KOs (as they were without including the high-expressors).

Pttg1, Sema3g, Ifih1, Dppa5a, and Prg4 are all upregulated in dLGN Hets including and excluding the high expressors. We do lose a few genes when including high expressors that were enriched in dLGN hets before.

10.2 SCN

10.2.1 PCA pre and post SVAseq

mm38_scn_subset_norm_batch <- normalize(mm38_scn_subset, convert = "cpm",
                                        transform = "log2", batch = "svaseq")
## transform_counts: Found 49815 values less than 0.
## transform_counts: Found 49815 values equal to 0, adding 1 to the matrix.
mm38_scn_subset_norm_nobatch <- normalize(mm38_scn_subset, convert = "cpm", norm = "quant",
                                          transform = "log2")
## transform_counts: Found 176602 values equal to 0, adding 1 to the matrix.
pca_mm38_scn_subset_norm_nobatch <- plot_pca(mm38_scn_subset_norm_nobatch)
pca_norm_plot_nobatch_scn <-  ggplot(pca_mm38_scn_subset_norm_nobatch$table,
                                     aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values[5:6],
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_scn_subset_norm_nobatch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_scn_subset_norm_nobatch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_scn_subset_norm_nobatch$table,
                               labels %in% c('S3_Het_SCN', 'S4_Het_SCN')),
                   nudge_x = 0.2,
                   nudge_y = 0.2)


pca_mm38_scn_subset_norm_batch <- plot_pca(mm38_scn_subset_norm_batch)
pca_norm_plot_batch_scn <-  ggplot(pca_mm38_scn_subset_norm_batch$table, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values[5:6],
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with SVA Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_scn_subset_norm_batch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_scn_subset_norm_batch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_scn_subset_norm_batch$table,
                               labels %in% c('S3_Het_SCN', 'S4_Het_SCN')),
                   nudge_x = 0.2,
                   nudge_y = 0.2)


pca_norm_plot_nobatch_scn

pca_norm_plot_batch_scn

10.2.2 Volcano Plots ad DE table results

keepers <- names(mm_de_scn_sva$deseq$all_tables)
## Error in `mm_de_scn_sva$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_scn_sva <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_scn_sva, table = tbl)
  res_tbls_scn_sva[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls_scn_sva[[tbl]] <- set_sig_limma(res_tbls_scn_sva[[tbl]], factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                                                                paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls_scn_sva[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_scn_sva[[tbl]],
                                                              title = paste("Volcano Plot:", tbl),
                                                              type = "plotly",
                                                              tbl = "limma",
                                                              gene_name_col = "uniprot_gn_symbol")
  res_tbls_scn_sva[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_scn_sva[[tbl]],
                                                              title = paste("Volcano Plot:", tbl),
                                                              tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_scn_sva$SCNko_vs_SCNhetvolc_ggplot
## NULL
res_tbls_scn_sva$SCNko_vs_SCNhetvolc_plotly
## NULL
res_tbls_scn_sva$SCNko_vs_SCNhet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

10.3 Retina

10.3.1 PCA pre and post SVAseq

mm38_ret_subset_norm_batch <- normalize(mm38_ret_subset, convert = "cpm",
                                        transform = "log2", batch = "svaseq")
## transform_counts: Found 48664 values less than 0.
## transform_counts: Found 48664 values equal to 0, adding 1 to the matrix.
mm38_ret_subset_norm_nobatch <- normalize(mm38_ret_subset, convert = "cpm", norm = "quant",
                                          transform = "log2")
## transform_counts: Found 137516 values equal to 0, adding 1 to the matrix.
pca_mm38_ret_subset_norm_nobatch <- plot_pca(mm38_ret_subset_norm_nobatch)
pca_norm_plot_nobatch_ret <-  ggplot(pca_mm38_ret_subset_norm_nobatch$table, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values[3:4],
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with No Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_ret_subset_norm_nobatch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_ret_subset_norm_nobatch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_ret_subset_norm_nobatch$table,
                               labels %in% c('S3_Het_Ret', 'S4_Het_Ret')),
                   nudge_x = 0.2,
                   nudge_y = 0.2)


pca_mm38_ret_subset_norm_batch <- plot_pca(mm38_ret_subset_norm_batch)
pca_norm_plot_batch_ret <-  ggplot(pca_mm38_ret_subset_norm_batch$table, aes(x = PC1, y = PC2, label = labels)) +
  geom_point(aes(color = condition),
             size = 5) +
  scale_color_manual(values = color_values[3:4],
                     aesthetics = "color") +
  theme_classic() +
  labs(color="Cell Compartment/Genotype")   +
  ggtitle("PCA with SVA Batch Correction")  +
  labs(x = paste0("PC1: ",  pca_mm38_ret_subset_norm_batch$prop_var[1], "% variance"),
       y =  paste0("PC2: ",  pca_mm38_ret_subset_norm_batch$prop_var[2], "% variance"))  +
  geom_label_repel(data=filter(pca_mm38_ret_subset_norm_batch$table,
                               labels %in% c('S3_Het_Ret', 'S4_Het_Ret')),
                   nudge_x = 0.2,
                   nudge_y = 0.2)


pca_norm_plot_nobatch_ret

pca_norm_plot_batch_ret

10.3.2 Volcano Plots ad DE table results

keepers <- names(mm_de_ret_sva$deseq$all_tables)
## Error in `mm_de_ret_sva$deseq$all_tables`:
## ! $ operator is invalid for atomic vectors
res_tbls_ret_sva <- c()
for (tbl in keepers) {
  deseq_tbl <- get_de_table(mm_de_ret_sva, table = tbl)
  res_tbls_ret_sva[[tbl]] <- merge(deseq_tbl, hisat_annot, by = "row.names")
  res_tbls_ret_sva[[tbl]] <- set_sig_limma(res_tbls_ret_sva[[tbl]], factors = c(paste(gsub("\\_.*","",tbl), "\nEnriched"),
                                                                                paste(sub('.*\\_', '', tbl), "\nEnriched")))
  res_tbls_ret_sva[[paste0(tbl, "volc_plotly")]] <- volc_plot(res_tbls_ret_sva[[tbl]],
                                                              title = paste("Volcano Plot:", tbl),
                                                              type = "plotly",
                                                              tbl = "limma",
                                                              gene_name_col = "uniprot_gn_symbol")
  res_tbls_ret_sva[[paste0(tbl, "volc_ggplot")]] <- volc_plot(res_tbls_ret_sva[[tbl]],
                                                              title = paste("Volcano Plot:", tbl),
                                                              tbl = "limma")
}
## Error:
## ! object 'keepers' not found
res_tbls_ret_sva$Retinako_vs_Retinahetvolc_ggplot
## NULL
res_tbls_ret_sva$Retinako_vs_Retinahetvolc_plotly
## NULL
res_tbls_ret_sva$Retinako_vs_Retinahet |>
  filter(adj.P.Val <= 0.05) |>
  filter(abs(logFC) >= 1) |>
  select("ensembl_gene_id", "uniprot_gn_symbol", "Significance", "description", "baseMean", "logFC", "adj.P.Val") |>
  arrange(logFC) |>
  DT::datatable(rownames = FALSE)
## Error in `UseMethod()`:
## ! no applicable method for 'filter' applied to an object of class "NULL"

11 Re-Implementation

Let us start with the full set of desired tables. In the above, the data was separated into ~ 9 separate chunks and I think it will benefit from being kept together – also I seem to recall expressing this to Theresa and that she changed the notebook to this kind of analysis. If I am correct, then it is possible she did so in a separate notebook which I have not found and that this will provide the fully reconciled set of results.

I have reasonable hope for this because the various plots etc early on look identical between this containerized notebook, and those notebooks I found in her working tree.

While I wait for these tables to come back, let us count the number of samples in the plot provided by Colenso so that I may doublecheck that nothing got filtered out or anything important like that.

8 pink samples, 17 green samples, 17 blue samples.

4 light pink, 4 dark pink 9 medium green, 4 light green, 4 dark green. 9 medium blue, 4 light blue, 4 dark blue.

With the above in mind, let us make a small change in how the data is handled and see if I cannot get numbers more closely aligned to the tables from Colenso.

## Here is a reminder of Theresa's filter:
## filter(sample_id %in% c("S3_Het_Ret_S1", "S4_Het_Ret_S4", "S5_Het_Ret_S16", "S1_Het_Ret_S1", "S2_Het_Ret_S4", "S3_Het_Ret_S7", "S4_Het_Ret_S10", "S5_Het_Ret_S13")) |>

mm_final <- subset_se(mm38_hisat, subset = "included=='yes'") |>
  set_conditions(fact = "location_genotype")
## The numbers of samples by condition are:
## 
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Setting colors with no pre-defined colors, using the Dark2 palette.
mm_norm <- normalize(mm_final, transform = "log2", convert = "cpm", filter = TRUE, norm = "quant")
## Removing 130546 low-count genes (54076 remaining).
## transform_counts: Found 1106225 values equal to 0, adding 1 to the matrix.
plot_pca(mm_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 Retina_het, Retina_ko, Retina_wt, SCN_het, SCN_ko, SCN_wt, dLGN_het, dLGN_ko, dLGN_wt
## Shapes are defined by 1, 2, 3.

mm_nb <- normalize(mm_final, transform = "log2", convert = "cpm", filter = TRUE, batch = "svaseq")
## Removing 130546 low-count genes (54076 remaining).
## transform_counts: Found 369880 values less than 0.
## transform_counts: Found 369880 values equal to 0, adding 1 to the matrix.
plot_pca(mm_nb)
## The result of performing a fast_svd dimension reduction.
## The x-axis is PC1 and the y-axis is PC2
## Colors are defined by Retina_het, Retina_ko, Retina_wt, SCN_het, SCN_ko, SCN_wt, dLGN_het, dLGN_ko, dLGN_wt
## Shapes are defined by 1, 2, 3.
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure
## Warning in MASS::cov.trob(data[, vars], wt = weight * nrow(data)): Probable
## convergence failure

There remain a couple of weirdo samples, but things look quite a bit easier to interpret to my eyes.

final_keepers <- list(
  ## Three comparisons among the dLGN samples.
  "dlgn_kw" = c("dLGN_ko", "dLGN_wt"),
  "dlgn_kh" = c("dLGN_ko", "dLGN_het"),
  "dlgn_hw" = c("dLGN_het", "dLGN_wt"),
  ## Three comparisons among the SCN samples.
  "scn_kw" = c("SCN_ko", "SCN_wt"),
  "scn_kh" = c("SCN_ko", "SCN_het"),
  "scn_hw" = c("SCN_het", "SCN_wt"),
  ## and the retina samples
  "retina_kw" = c("Retina_ko", "Retina_wt"),
  "retina_kh" = c("Retina_ko", "Retina_het"),
  "retina_hw" = c("Retina_het", "Retina_wt")
)

genoloc_de_sva <- all_pairwise(mm_final, model_fstring = "~ 0 + condition", filter = TRUE,
                               model_svs = "svaseq", keepers = final_keepers)
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Removing 130546 low-count genes (54076 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 1297894 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## Warning in variancePartition::voomWithDreamWeights(counts = data, formula = model_fstring, : The maximum precision weight is 4.654586e+13, suggesting a poor smoothing fit
## on the mean-variance plot for large expression values. Such large weights can
## have unexpected effects downstream.  Consider examining the mean-variance plot
## and reducing the span parameter.
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.

genoloc_table_sva <- combine_de_tables(genoloc_de_sva, excel = "excel/genotype_location_tables.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_ko_vs_dLGN_het.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to dLGN_het_vs_dLGN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_wt.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_ko_vs_SCN_het.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to SCN_het_vs_SCN_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_wt.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_ko_vs_Retina_het.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
## Adding the coefficient plot to Retina_het_vs_Retina_wt.
genoloc_sig_sva <- extract_significant_genes(genoloc_table_sva, according_to = "deseq",
                                             excel = "excel/genotype_location_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.
location_keepers <- list(
  ## ko across locations
  "ko_dlgn_scn" = c("dLGN_ko", "SCN_ko"),
  "ko_dlgn_ret" = c("dLGN_ko", "Retina_ko"),
  "ko_scn_ret" = c("SCN_ko", "Retina_ko"),
  ## het across locations
  "het_dlgn_scn" = c("dLGN_het", "SCN_het"),
  "het_dlgn_ret" = c("dLGN_het", "Retina_het"),
  "het_scn_ret" = c("SCN_het", "Retina_het"),
  ## wt across locations
  "wt_dlgn_scn" = c("dLGN_wt", "SCN_wt"),
  "wt_dlgn_ret" = c("dLGN_wt", "Retina_wt"),
  "wt_scn_ret" = c("SCN_wt", "Retina_wt"))
location_comparisons <- all_pairwise(mm_final, model_fstring = "~ 0 + condition", filter = TRUE,
                               model_svs = "svaseq", keepers = location_keepers)
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Removing 130546 low-count genes (54076 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## Basic step 0/3: Transforming data.
## Setting 1297894 entries to zero.
## This received a matrix of SVs.
## Error in DESeqDataSet(se, design = design, ignoreRank) : 
##   some values in assay are not integers
## Warning in variancePartition::voomWithDreamWeights(counts = data, formula = model_fstring, : The maximum precision weight is 4.654586e+13, suggesting a poor smoothing fit
## on the mean-variance plot for large expression values. Such large weights can
## have unexpected effects downstream.  Consider examining the mean-variance plot
## and reducing the span parameter.
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## conditions
## Retina_het  Retina_ko  Retina_wt    SCN_het     SCN_ko     SCN_wt   dLGN_het 
##          9          4          4          9          4          4          9 
##    dLGN_ko    dLGN_wt 
##          4          4
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The deseq results are not of class hpgltools::deseq_pairwise.

location_table <- combine_de_tables(location_comparisons, excel = "excel/locations.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_SCN_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to SCN_ko_vs_Retina_ko.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_SCN_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to SCN_het_vs_Retina_het.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_SCN_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to dLGN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
## Adding the coefficient plot to SCN_wt_vs_Retina_wt.
location_sig <- extract_significant_genes(location_table, according_to = "deseq",
                                             excel = "excel/location_sig.xlsx")
## Unable to discern the methods to test significance, according_to is NULL.

Save some of the DE results for comparison agains the TRAP data

de_list <- c("mm_de_dlgn_sva", "mm_de_ret_sva", "mm_de_scn_sva",
             "mm_de_dlgn", "mm_de_ret", "mm_de_scn",
             "genoloc_de_sva", "genoloc_table_sva")
saved <- save(list = de_list, file = "bulk_results.rda")
LS0tCnRpdGxlOiAiaXBSR0MgYnVsayBSTkFzZXEgLS0gQWxsIFNhbXBsZXMgLS0gVGhpcyB0aW1lIHdpdGggZmVlbGluZyAodHJhbnNjcmlwdC1sZXZlbCBhYnVuZGFuY2VzKSEiCmF1dGhvcjogIlRoZXJlc2EgQWxleGFuZGVyLCBtb2RpZmllZCBieSBhdGIiCmRhdGU6ICI0LzE1LzIwMjMsIG1vZGlmaWVkIDIwMjYwMyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCiAgICAgIHRvY19kZXB0aDogNQotLS0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoaHBnbHRvb2xzKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGVucmljaHBsb3QpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdwcm9maWxlcjIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KAogIHByb2dyZXNzID0gVFJVRSwgdmVyYm9zZSA9IFRSVUUsIHdpZHRoID0gOTAsIGVjaG8gPSBUUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZXJyb3IgPSBUUlVFLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnJldGluYSA9IDIsCiAgb3V0LndpZHRoID0gIjEwMCUiLCBkZXYgPSAicG5nIiwKICBkZXYuYXJncyA9IGxpc3QocG5nID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKSkKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemUgPSAxMikpCnZlciA8LSAiMjAyNDA4IgpwcmV2aW91c19maWxlIDwtICIiCnZlciA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgIiVZJW0lZCIpCgojI3RtcCA8LSBzbShsb2FkbWUoZmlsZW5hbWU9cGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1wcmV2aW91c19maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpKSkKcm1kX2ZpbGUgPC0gIjA0X2lwcmdjX2J1bGtfdHJhbnNjcmlwdF9hbmFseXNlcy5SbWQiCnNhdmVmaWxlIDwtIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHJtZF9maWxlKQojIyBObyBvbmUgd2lsbCBldmVyIHJlYWQgdGhpcyBJIHN1c3BlY3QsIGJ1dCB0aGVyZSB3aWxsIF9uZXZlcl8gYmUgYSB3b3JkIHByb2R1Y2VkCiMjIGJ5IGFuIExMTSBpbiBhIGRvY3VtZW50IHdyaXR0ZW4gYnkgbWUuCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgaXMgaW50ZW5kZWQgdG8gcmVwZWF0IHdpdGggbWluaW1hbCBtb2RpZmljYXRpb24gdGhlIHdvcmsKcGVyZm9ybWVkIGJ5IFRoZXJlc2Egd2hlbiBhbmFseXppbmcgdGhlIFJOQVNlcSBJUFJHQyBkYXRhLiAgVGhpcyBpcwpiZWluZyBwZXJmb3JtZWQgaW4gYW4gYXBwdGFpbmVyICh1Z2ggSSBoYXRlIHRoYXQgbmFtZSkgY29udGFpbmVyIGFuZApzbyBJIHdpbGwgbGlrZWx5IHJlbW92ZSBzb21lIG9mIHRoZSBsaWJyYXJpZXMgaW52b2tlZCBpbiBpdC4KCk5vdCBhbGwgb2YgdGhlc2UgYXJlIGF2YWlsYWJsZSBpbiB0aGUgY29udGFpbmVyLCBhbmQgSSBkbyBub3QgdGhpbmsgSSBoYXZlIHRoZSB2ZXJzaW9uCm9mIFRoZXJlc2EncyBoZWxwZXJfZnVuY3Rpb25zLlIgd2hpY2ggd2FzIHVzZWQgZm9yIHRoaXMuICBJIGRpZCBmaW5kIGEKdmVyc2lvbiBvZiBpdCB0aGF0IGFwcGVhcnMgdG8gd29yayB3aXRob3V0IGFueSBwcm9ibGVtcywgdGhvdWdoLgoKQXQgdGhlIGVuZCBvZiB0aGlzIGRvY3VtZW50LCBJIGFtIGdvaW5nIHRvIHRyeSB0byByZS1pbXBsZW1lbnQgaXQKd2l0aCBzb21lIG1pbm9yIGNoYW5nZXMgdG8gc2VlIGlmIEkgY2FuIG1vcmUgZWFzaWx5IHJlY29uY2lsZSB0aGUKcmVzdWx0cyB0byB0aGUgdGFibGVzIHByb3ZpZGVkIGJ5IENvbGVuc28uCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoInBhdGNod29yayIpCmxpYnJhcnkoInBsb3RseSIpCmxpYnJhcnkoIlJDb2xvckJyZXdlciIpCmxpYnJhcnkoIkRUIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJvcGVueGxzeCIpCmxpYnJhcnkoIkNvbXBsZXhIZWF0bWFwIikKbGlicmFyeSgiY2lyY2xpemUiKQpsaWJyYXJ5KCJncHJvZmlsZXIyIikKc291cmNlKCIvZGF0YS9oZWxwZXJfZnVuY3Rpb25zLlIiKQpsaWJyYXJ5KCJncGxvdHMiKQpsaWJyYXJ5KCJnZ3JlcGVsIikKYGBgCgoKYGBge3J9CiNzZXR3ZCgifi9zY3JhdGNoXzAyL3JlZXN5eGFuL21tdXNjdWx1c19pcHJnY18yMDE5IikKYGBgCgojIE0uIG11c2N1bHVzCgojIyBBbm5vdGF0aW9ucwoKSSBhbSB1c2luZyBtbTM4XzEwMC4KCmBgYHtyfQptbV9hbm5vdCA8LSBsb2FkX2Jpb21hcnRfYW5ub3RhdGlvbnMoc3BlY2llcyA9ICJtbXVzY3VsdXMiKQptbV9hbm5vdCA8LSBtbV9hbm5vdFtbImFubm90YXRpb24iXV0KbW1fYW5ub3RbWyJ0eGlkIl1dIDwtIHBhc3RlMChtbV9hbm5vdFtbImVuc2VtYmxfdHJhbnNjcmlwdF9pZCJdXSwgIi4iLCBtbV9hbm5vdFtbInZlcnNpb24iXV0pCnJvd25hbWVzKG1tX2Fubm90KSA8LSBtYWtlLm5hbWVzKG1tX2Fubm90W1siZW5zZW1ibF9nZW5lX2lkIl1dLCB1bmlxdWU9VFJVRSkKCm1tX3R4X2Fubm90IDwtIG1tX2Fubm90CiMjIHllYWgsIHRoZSBJRCB0YWcgaW4gbXkgZ2ZmIGZpbGUgaGFzIHRyYW5zY3JpcHQ6IGFzIGEgcHJlZml4LCBzbyB0aGUgZmVhdHVyZUNvdW50cyBvdXRwdXRzCiMjIGluY2x1ZGVzIGl0Li4uICBJIHdpbGwgZml4IHRoYXQgaW5wb3N0Lgpyb3duYW1lcyhtbV90eF9hbm5vdCkgPC0gbWFrZS5uYW1lcyhtbV90eF9hbm5vdFtbImVuc2VtYmxfdHJhbnNjcmlwdF9pZCJdXSwgdW5pcXVlID0gVFJVRSkKCnR4X2dlbmVfbWFwIDwtIG1tX2Fubm90WywgYygidHhpZCIsICJlbnNlbWJsX2dlbmVfaWQiKV0KYGBgCgoKU28sIEkgbm93IGhhdmUgYSB0YWJsZSBvZiBtb3VzZSBhbm5vdGF0aW9ucy4KCiMjIEhpc2F0MiBleHByZXNzaW9uc2V0CgpgYGB7cn0KbW0zOF9oaXNhdCA8LSBjcmVhdGVfc2UoInNhbXBsZV9zaGVldHMvc2FtcGxlc2hlZXRfYnVsa3JuYXNlcV9PcG40Lnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICBnZW5lX2luZm8gPSBtbV90eF9hbm5vdCwgZmlsZV9jb2x1bW4gPSAic2FsbW9uX2NvdW50X3RhYmxlIikKYGBgCgojIENvbG9yIFNldCBVcAoKYGBge3J9CmNvbG9yX2NvbmRpdGlvbiA8LSBtbTM4X2hpc2F0JGluaXRpYWxfbWV0YWRhdGEkY29uZGl0aW9uCmNvbG9yX2NvbmRpdGlvbiA8LSBmYWN0b3IoY29sb3JfY29uZGl0aW9uLCBsZXZlbHMgPSBjKCJSZXRpbmFfaGV0IiwgIlJldGluYV9rbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTQ05faGV0IiwgIlNDTl9rbyIsICJkTEdOX2hldCIsICJkTEdOX2tvIikpCgpjb2xvcl92YWx1ZXMgPC0gYyggIiMwMEJGQzQiLCAgIiM5QUQyRDMiLCAiI0Y4NzY2RCIsICIjRkJBREE3IiwgIiM3Q0FFMDAiLCAiI0QzRUU4RiIpCmNvbF9mdW4gPSBjb2xvclJhbXAyKGMoMCwgMywgNiksIGMoImJsdWUiLCAicGluayIsICJyZWQiKSkKYGBgCgojIE1hcHBlZCBDb3VudHMgUGVyIFNhbXBsZSBQbG90CgpgYGB7cn0KbGlicmFyeShmb3JjYXRzKQptbTM4X2hpc2F0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfaGlzYXQsIGZhY3QgPSAiYmF0Y2giKQpsaWJzaXplX2RmIDwtIGFzLmRhdGEuZnJhbWUocGxvdF9saWJzaXplKG1tMzhfaGlzYXQpJHRhYmxlKQpyb3duYW1lcyhsaWJzaXplX2RmKSA8LSBtbTM4X2hpc2F0JGRlc2lnbiRzYW1wbGVpZApsaWJzaXplX2RmJHNhbXBsZW51bSA8LSBwYXN0ZTAobW0zOF9oaXNhdCRkZXNpZ25bcm93bmFtZXMobGlic2l6ZV9kZiksICJzYW1wbGVudW1iIl0sICJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1tMzhfaGlzYXQkZGVzaWduW3Jvd25hbWVzKGxpYnNpemVfZGYpLCAiYmF0Y2giXSkKbGlic2l6ZV9kZiRzYW1wbGVfaWQgPC0gIHJvd25hbWVzKG1tMzhfaGlzYXQkZGVzaWduKQpsaWJzaXplX2RmIDwtIGxpYnNpemVfZGZbb3JkZXIobGlic2l6ZV9kZiRzdW0pLF0KCmdncGxvdChsaWJzaXplX2RmLCBhZXMoeCA9IGZjdF9yZXYoZmN0X2luZnJlcShzYW1wbGVudW0sIHN1bSkpLCB5ID0gc3VtLCBmaWxsID0gY29uZGl0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICN0aGVtZShheGlzLnRleHQueD0gZWxlbWVudF90ZXh0KGZjdF9yZXYoZmN0X2luZnJlcShsaWJzaXplX2RmJHNhbXBsZW51bSwgbGlic2l6ZV9kZiRzdW0pKSksICNyZW1vdmUgeCBheGlzIGxhYmVscwogICMgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM2MDQ0OWIiLCAiIzAwOWY2ZiIsICJvcmFuZ2UiKSkgKwogIHhsYWIoIlNhbXBsZSIpICsKICB5bGFiKCJTdW0gb2YgTWFwcGVkIEdlbmUgQ291bnRzIikgKwogIGxhYnMoZmlsbCA9ICIiKQoKcGxvdF9saWJzaXplKG1tMzhfaGlzYXQpCmBgYAoKIyBOb3JtYWxpemUgRXhwcmVzc2lvbgoKRmlyc3Qgd2Ugd2lsbCBmaWx0ZXIgb3V0IHRoZSBnZW5lcyB3aGljaCBoYXZlIGxvdyBjb3VudHMgYWNyb3NzIGFsbApzYW1wbGVzLiBUaGVuIEkgd2lsbCBub3JtYWxpemUgYm90aCB3aXRob3V0IGFuZCB3aXRoIFNWQSBjb3JyZWN0aW9uLgoKYGBge3J9Cm1tMzhfZmlsdCA8LSBub3JtYWxpemUobW0zOF9oaXNhdCwgZmlsdGVyID0gVFJVRSkKZGVzIDwtIGNvbERhdGEobW0zOF9maWx0KQpuZXdfZmFjdG9yIDwtIHBhc3RlMChkZXNbWyJsb2NhdGlvbiJdXSwgIl8iLCBkZXNbWyJnZW5vdHlwZSJdXSkKY29sRGF0YShtbTM4X2hpc2F0KVtbImxvY2F0aW9uX2dlbm90eXBlIl1dIDwtIG5ld19mYWN0b3IKCm1tMzhfbm9ybSA8LSBub3JtYWxpemUobW0zOF9oaXNhdCwgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm09ImxvZzIiKQoKbW0zOF9ub3JtIDwtIHNldF9jb25kaXRpb25zKG1tMzhfbm9ybSwgZmFjdCA9ICJsb2NhdGlvbl9nZW5vdHlwZSIpCmBgYAoKIyBNZWxhbm9wc2luIEV4cHJlc3Npb24KCkhlcmUgaXMgYSBwbG90IG9mIHRoZSBPcG40IGV4cHJlc3Npb24gYWNyb3NzIGFsbCByZXRpbmEgc2FtcGxlcyBzcGxpdApieSBiYXRjaC4gVGhlIDQgcXVhZHJhbnRzIGluIHRoZSBwbG90IGFyZSA8YnI+CgpoZXQ6MSAtLSByZXRpbmEgaGV0IHNhbXBsZXMgaW4gYmF0Y2ggMSA8YnI+CmhldDoyIC0tIHJldGluYSBoZXQgc2FtcGxlcyBpbiBiYXRjaCAyIDxicj4Ka286MSAtLSByZXRpbmEga28gc2FtcGxlcyBpbiBiYXRjaCAxIDxicj4Ka286MiAtLSByZXRpbmEga28gc2FtcGxlcyBpbiBiYXRjaCAyIDxicj4KClRoaXMgaXMgYSBUeCBjb21wYXJpc29uOyBJIG5lZWQgdG8gZWl0aGVyIGRyb3AgdGhpcyBvciBodW50IGRvd24gdGhlIHNldCBvZgp0cmFuc2NyaXB0IElEcyAod2hpY2ggSSBkaWQpCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCmNvbG9ycyA8LSBicmV3ZXIucGFsKG5hbWUgPSAiU3BlY3RyYWwiLCBuID0gMikKbW0zOF9jcG0gPC0gbm9ybWFsaXplKG1tMzhfZmlsdCwgY29udmVydCA9ICJjcG0iKQpkZiA8LSBkYXRhLmZyYW1lKGV4cHJzID0gYXNzYXkobW0zOF9jcG0pWyJFTlNNVVNHMDAwMDAwMjE3OTkiLF0sCiAgICAgICAgICAgICAgICAgZ2Vub3R5cGUgPSBhcy5mYWN0b3IoZGVzW1siZ2Vub3R5cGUiXV0pLAogICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gYXMuZmFjdG9yKGRlc1tbImxvY2F0aW9uIl1dKSwKICAgICAgICAgICAgICAgICBzYW1wbGVpZCA9IGRlc1tbInNhbXBsZWlkIl1dLAogICAgICAgICAgICAgICAgIHNhbXBsZW51bSA9IGRlc1tbInNhbXBsZW51bWIiXV0sCiAgICAgICAgICAgICAgICAgYmF0Y2ggPSBkZXNbWyJiYXRjaCJdXSkKCiMjIFNldCBwb3N0c2NyaXB0IGFyZ3VtZW50cwpzZXRFUFMoKQpwb3N0c2NyaXB0KCJidWxrUk5Bc2VxX09wbjRFeHByZXNzaW9uX1JldGluYS5lcHMiKQpjcG1fZGYgPC0gZGYgfD4KICBmaWx0ZXIobG9jYXRpb24gPT0gIlJldGluYSIgfCBsb2NhdGlvbiA9PSAicmV0aW5hIikKCiMjIFRoaXMgaXMgd2hlcmUgSSBtb3N0IG1pc3MgZ2dzdGF0c3Bsb3QKIyMgSSBhbSBnb2luZyB0byBzaXQgYW5kIHdyaXRlIG15IG93biB2ZXJzaW9uIG9mIGl0LgpnZ3Bsb3QoY3BtX2RmLCBhZXMoeCA9IHNhbXBsZW51bSwgeSA9IGV4cHJzLCBmaWxsID0gZ2Vub3R5cGUsIGdyb3VwID0gZ2Vub3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArCiAgeGxhYigiU2FtcGxlIikgKwogIHlsYWIoIk9wbjQgQ291bnRzIFBlciBNaWxsaW9uIChDUE1zKSIpICsKICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGQzEwNyIsICIjMDA0RDQwIiwgIm9yYW5nZSIpLAogICMgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiKSArCiAgZ2d0aXRsZSgiUmV0aW5hIE1lbGFub3BzaW4gRXhwcmVzc2lvbiIpICsKICBmYWNldF93cmFwKH5nZW5vdHlwZTpiYXRjaCwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxpbShjKDAsIDI1KSkgKwogIHRoZW1lX2NsYXNzaWMoKQpkZXYub2ZmKCkKYGBgCgpUaGUgV1Qgc2FtcGxlcyBpbiBiYXRjaCAzIGhhdmUgYWJvdXQgZG91YmxlIHRoZSBPcG40IGV4cHJlc3Npb24gYXMgdGhlCmhldCBzYW1wbGVzIGluIGJhdGNoIDMgKGFuZCBiYXRjaCAyKS4KCiMgUENBCgpgYGB7ciBwY2EsIG1lc3NhZ2UgPSBGQUxTRX0KcGNhX25vcm0gPC0gcGxvdF9wY2EobW0zOF9ub3JtLCBwbG90X2xhYmVscyA9IEZBTFNFKQpwY2Ffbm9ybVtbInBsb3QiXV0KIyMgcm93bmFtZXMocGNhX25vcm0kcmVzdWx0JHYpCmxhYmVscyA8LSBkZXNbWyJzYW1wbGVpZCJdXQojIyBsYWJlbHMgPC0gcGFzdGUwKG1tMzhfbm9ybSRkZXNpZ24kc2FtcGxlaWQsICJfIiwgbW0zOF9ub3JtJGRlc2lnbiRzYW1wbGVudW1iKQphbGxfZGYgPC0gIGNiaW5kKGFzLmRhdGEuZnJhbWUocGNhX25vcm0kcmVzdWx0JHYpLCBsYWJlbHMpCgpzaGFwZV9nZW5vdHlwZSA8LSBtbTM4X25vcm0kZGVzaWduJGdlbm90eXBlCmNvbG9yX2NvbmRpdGlvbiA8LSBtbTM4X25vcm0kY29uZGl0aW9uCgojIyBmaWx0ZXIoc2FtcGxlX2lkICVpbiUgYygiUzNfSGV0X1JldF9TMSIsICJTNF9IZXRfUmV0X1M0IiwgIlM1X0hldF9SZXRfUzE2IiwgIlMxX0hldF9SZXRfUzEiLCAiUzJfSGV0X1JldF9TNCIsICJTM19IZXRfUmV0X1M3IiwgIlM0X0hldF9SZXRfUzEwIiwgIlM1X0hldF9SZXRfUzEzIikpIHw+CgpwY2Ffbm9ybV9wbG90IDwtICBnZ3Bsb3QoYWxsX2RmLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb2xvcl9jb25kaXRpb24sIHNoYXBlID0gc2hhcGVfZ2Vub3R5cGUpLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAjICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBObyBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9ub3JtJHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9ub3JtJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKQoKI3NldEVQUygpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTZXQgcG9zdHNjcmlwdCBhcmd1bWVudHMKI3Bvc3RzY3JpcHQoImJ1bGtSTkFzZXFfUENBX2FsbHNhbXBsZXNfbGFiZWxlZFM1LmVwcyIpICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTdGFydCBncmFwaGljcyBkZXZpY2UgZHJpdmVyCmFsbF9kZltbImxhYmVscyJdXSA8LSByb3duYW1lcyhhbGxfZGYpCnBjYV9ub3JtX3Bsb3QgKyBnZ3RpdGxlKCJQQ0EgTm9ybWFsaXplZCBDb3VudHMiKSArCmdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIoYWxsX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGxhYmVscyksICNjKCdzNV9oZXRfZGxnbicsICdzNV9oZXRfcmV0JywgJ3M1X2hldF9zY24nKSksCiAgICBudWRnZV94ID0gMC4xNSwKICAgIG51ZGdlX3kgPSAwLjE1KQojZGV2Lm9mZigpCmBgYAoKIyMgTG9vayBhdCB0aGUgZmlyc3QgYmF0Y2ggb2Ygc2VxdWVuY2luZwoKYGBge3J9CiNiYXRjaCAxIHBsb3QKYWxsX2RmW3Jvd25hbWVzKGFsbF9kZikgJWluJSB0b2xvd2VyKHJvd25hbWVzKGRlc1tkZXNbWyJiYXRjaCJdXSA9PSAiMSIsXSkpLF0gfD4KICBnZ3Bsb3QoYWVzKHggPSBQQzEsIHkgPSBQQzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb2xvcl9jb25kaXRpb25bd2hpY2gocm93bmFtZXMoYWxsX2RmKSAlaW4lIHRvbG93ZXIocm93bmFtZXMoZGVzW2RlcyRiYXRjaCA9PSAiMSIsXSkpKV0sCiAgICAgICAgICAgICAgICAgc2hhcGUgPSBzaGFwZV9nZW5vdHlwZVt3aGljaChyb3duYW1lcyhhbGxfZGYpICVpbiUgdG9sb3dlcihyb3duYW1lcyhkZXNbZGVzJGJhdGNoID09ICIxIixdKSkpXSksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl92YWx1ZXMsCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIiwgc2hhcGUgPSAiR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0EgLSBCYXRjaCAxIFJOQXNlcSIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2Ffbm9ybSRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2Ffbm9ybSRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkKYGBgCgpJIHRoaW5rIHRoZXJlIGlzIGFuIGVhc2llciB3YXkgdG8gZG8gdGhlIGFib3ZlCgpgYGB7cn0KYjEgPC0gc3Vic2V0X3NlKG1tMzhfbm9ybSwgc3Vic2V0ID0gImJhdGNoID09ICcxJyIpCnBsb3RfcGNhKGIxKQoKYjFfYjIgPC0gc3Vic2V0X3NlKG1tMzhfbm9ybSwgc3Vic2V0ID0gImJhdGNoID09ICcxJ3xiYXRjaCA9PSAnMiciKQpwbG90X3BjYShiMV9iMikKYGBgCgpgYGB7cn0KI2JhdGNoIDEmMiBwbG90CnBjYV9iYXRjaDFhbmQyIDwtIGFsbF9kZiB8PgogIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbG9yX2NvbmRpdGlvbiwKICAgICAgICAgICAgICAgICBzaGFwZSA9IHNoYXBlX2dlbm90eXBlKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiLCBzaGFwZSA9ICJHZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSAtIEJhdGNoIDEmMiBSTkFzZXEiKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX25vcm0kcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX25vcm0kcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpCgoKI3NldEVQUygpCiNwb3N0c2NyaXB0KGZpbGUgPSAicm5hc2VxX3BjYS1iYXRjaDFhbmQyLmVwcyIpCiNwY2FfYmF0Y2gxYW5kMgojZGV2Lm9mZigpCmBgYAoKSW4gdGhpcyBwY2EgcGxvdCwgd2Ugc2VlIHRoZSByZXRpbmEgc2FtcGxlcyBjbHVzdGVyIG9uIHRoZSByaWdodCBpbgp0aGUgUEMxIGRpcmVjdGlvbiBhbmQgdGhlIGJyYWluIHNhbXBsZXMgY2x1c3RlciBvbiB0aGUgbGVmdCBpbiB0aGUgUEMKMSBkaXJlY3Rpb24uCgpBcyB3ZSBzYXcgYmVmb3JlLCB0aGVyZSBpcyBkaXNwYXJpdHkgYmV0d2VlbiBzb21lIG9mIHRoZSBoZXRzLiBBcyBpdAp0dXJucyBvdXQsIGFsbCBvZiB0aGUgbmV3IEhldCBzYW1wbGVzIGNsdXN0ZXIgd2l0aCB0aGUgS08gc2FtcGxlcyBhcwpvdXIgb25lIHdlaXJkbyBkaWQgYmVmb3JlLiBTbyBub3cgaXQgc2VlbXMgdGhhdCBpdCBpcyBxdWl0ZSBlYXN5IHRvCmdldCBzb21lIGdlbmV0aWMgZHJpZnQgdGhhdCBsZWFkcyB0byB0aGVzZSBtaWNlJ3MgZXhwcmVzc2lvbiB0byBiZWhhdmUKaW4gd2VpcmQgd2F5cy4KCkFzIHdlIGRpZCBiZWZvcmUsIGxldCdzIGxvb2sgYXQgdGhlIE9wbjQgZXhwcmVzc2lvbiBhY3Jvc3MgYWxsIHRoZQpyZXRpbmEgc2FtcGxlcyB0byBzZWUgaWYgdGhlIEhldCBzYW1wbGVzIHRoYXQgYmVoYXZlIGxpa2UgS09zIGhhdmUKbG93ZXIgT3BuNCBleHByZXNzaW9uLgoKIyBBIGNsb3NlciBsb29rIGF0IHRoZSBzaW1pbGFyIEtPcyBhbmQgSGV0cwoKTGV0J3MgZXhjbHVkZSB0aGUgMiBIZXRzIHRoYXQgYXJlIHRoZSBtb3N0IGRpc3NpbWlsYXIgZnJvbSB0aGUgYnVuY2gKYW5kIGxvb2sgYXQgYSBQQ0EgcGxvdCBvZiB0aGUgcmVzdCBvZiB0aGUgc2FtcGxlcy4KCmBgYHtyfQojIyBUaGUgZm9sbG93aW5nIHN1YnNldCBpcyB1c2luZyBhbiBvbGRlciBzYW1wbGUgSUQgd2hpY2ggSSBhbSB1bmFibGUgdG8gZmluZCBhbnl3aGVyZS4KIyMgQXMgYSByZXN1bHQsIEkgcmV3cm90ZSB0aGF0IHBvcnRpb24gb2YgVGhlcmVzYSdzIHBjYSBwbG90IGFuZCBsYWJlbGVkIGV2ZXJ5dGhpbmcKIyMgYWNjb3JkaW5nIHRvIHRoZSBleHRhbnQgbmFtaW5nIHNjaGVtZSwgSSB3aWxsIG5vdyB0cnkgYW5kIGZpZ3VyZSBvdXQgd2hpY2gKIyMgc2FtcGxlcyB3ZXJlIHJlbW92ZWQuCiMjIG1tMzhfc3Vic2V0IDwtIHN1YnNldF9zZSgKIyMgICBtbTM4X2ZpbHQsCiMjIHN1YnNldCA9ICJzYW1wbGVpZCAhPSAnUzNfSGV0X2RMR04nJnNhbXBsZWlkICE9ICdTM19IZXRfUmV0JyZzYW1wbGVpZCAhPSAnUzNfSGV0X1NDTicmc2FtcGxlaWQgIT0gJ1M0X0hldF9kTEdOJyZzYW1wbGVpZCAhPSAnUzRfSGV0X1JldCcmc2FtcGxlaWQgIT0gJ1M0X0hldF9TQ04nIikKIyMgUzNfSGV0X2RMR05fUzIgaXMgYW4gb3V0bGllciBtYXJrZWQgYnkgVGhlcmVzYQojIyBTM19IZXRfUmV0X1MxIGlzIGFuIG91dGxpZXIKIyMgUzNfSGV0X1NDTl9TMyBpcyBhbiBvdXRsaWVyCiMjIFM0X0hldF9kTEdOX1MxMSBpcyBzb21ld2hhdCBhbiBvdXRsaWVyLCBJIG1pZ2h0IGJlIGluY2xpbmVkIHRvIGxlYXZlIGl0LgojIyBTNF9IZXRfUmV0X1M0IGlzIGEgaHVnZSBvdXRsaWVyCiMjIFM0X0hldF9TQ05fUzYgaXMgYW4gb3V0bGllcgoKIyMgSWYgSSB3ZXJlIGNob29zaW5nIGxpa2VseSBzYW1wbGVzLCBJIHRoaW5rIEkgd291bGQgZ28gZm9yOgojI1M0X0hldF9SZXRfUzQsIFMzX0hldF9SZXRfUzEsIFMzX0hldF9TQ05fczMsIFMzX0hldF9kTEdOX1MyLCBTNF9IZXRfZExHTl9TNSwgUzRfSGV0X1NDTl9TNgoKIyMgRWl0aGVyIHdheSwgSSBhbSBhZGRpbmcgYSBjb3VwbGUgY29sdW1ucyB0byB0aGUgc2FtcGxlIHNoZWV0IHdpdGggdGhlc2UgY2FsbHMgZm9yIGluY2x1ZGVkIHNhbXBsZXMuCgptbTM4X3N1YnNldCA8LSBzdWJzZXRfc2UobW0zOF9maWx0LCBzdWJzZXQgPSAiaW5jbHVkZWQ9PSd5ZXMnIikKCm1tMzhfc3Vic2V0IDwtIG5vcm1hbGl6ZShtbTM4X3N1YnNldCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgdHJhbnNmb3JtPSJsb2cyIikKCm1tMzhfc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfc3Vic2V0LCBmYWN0ID0gImxvY2F0aW9uX3RpbWUiKQoKcGNhX25vcm1fc3Vic2V0IDwtIHBsb3RfcGNhKG1tMzhfc3Vic2V0LCBwbG90X2xhYmVscyA9IEZBTFNFKQpwY2Ffbm9ybV9zdWJzZXQKCmxhYmVscyA8LSByb3duYW1lcyhwY2Ffbm9ybV9zdWJzZXQkcmVzdWx0JHYpCgphbGxfZGYgPC0gIGNiaW5kKGFzLmRhdGEuZnJhbWUocGNhX25vcm1fc3Vic2V0JHJlc3VsdCR2KSwgbGFiZWxzKQpzaGFwZV9nZW5vdHlwZSA8LSBtbTM4X3N1YnNldCRkZXNpZ24kZ2Vub3R5cGUKY29sb3JfY29uZGl0aW9uIDwtIHBjYV9ub3JtX3N1YnNldCR0YWJsZSRjb25kaXRpb24KCnBjYV9ub3JtX3Bsb3QgPC0gIGdncGxvdChwY2Ffbm9ybV9zdWJzZXQkdGFibGUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29uZGl0aW9uKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBObyBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9ub3JtX3N1YnNldCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2Ffbm9ybV9zdWJzZXQkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpCgpwY2Ffbm9ybV9wbG90IDwtICBnZ3Bsb3QoYWxsX2RmLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb2xvcl9jb25kaXRpb24sIHNoYXBlID0gc2hhcGVfZ2Vub3R5cGUpLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICAjc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAjICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBObyBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9ub3JtX3N1YnNldCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2Ffbm9ybV9zdWJzZXQkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpCgojc2V0RVBTKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNldCBwb3N0c2NyaXB0IGFyZ3VtZW50cwojcG9zdHNjcmlwdCgiYnVsa1JOQXNlcV9QQ0FfYWxsc2FtcGxlc19sYWJlbGVkUzUuZXBzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFN0YXJ0IGdyYXBoaWNzIGRldmljZSBkcml2ZXIKcGNhX25vcm1fcGxvdCArIGdndGl0bGUoIlBDQSBOb3JtYWxpemVkIENvdW50cyAtLSBTdWJzZXQiKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihhbGxfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdzNF9oZXRfc2NuX3MxMicsICdzNF9oZXRfcmV0JywgJ3M0X2hldF9zY24nLCAnczVfaGV0X2RsZ24nKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4xNSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjEpCgpwY2Ffbm9ybV9wbG90ICsgZ2d0aXRsZSgiUENBIE5vcm1hbGl6ZWQgQ291bnRzIikjICsKCnBjYV9ub3JtX3Bsb3QKIyBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKGFsbF9kZiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBsYWJlbHMpLCAjYygnczRfaGV0X3NjbicsICdzNV9oZXRfcmV0JywgJ3M1X2hldF9zY24nLCAnczVfaGV0X2RsZ24nKSksCiMgICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMTUsCiMgICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMTUpCiNkZXYub2ZmKCkKYGBgCgpUaGVyZSByZWFsbHkgZG9lc24ndCBzZWVtIHRvIGJlIGEgZGlzY2VybmlibGUgZGlmZmVyZW5jZSBnbG9iYWxseQpiZXR3ZWVuIHRoZSBoZXRzIGFuZCBrb3Mgd2l0aGluIGVhY2ggbG9jYXRpb24uIFdlIGNhbiBkbyBhIERFIHdpdGgKdGhlc2Ugc2FtcGxlcyBiZXR3ZWVuIGhldC9rb3MgdG8gcXVhbnRpZnkgdGhpcy4KCgojIERFIG9mIEtPcyB2ZXJzdXMgTG93IGV4cHJlc3NvciBIZXRzCgpgYGB7cn0KbW0zOF9maWx0X3N1YiA8LSBzdWJzZXRfc2UobW0zOF9maWx0LCBzdWJzZXQgPSAic2FtcGxlaWQgIT0gJ1MzX0hldF9kTEdOJyZzYW1wbGVpZCAhPSAnUzNfSGV0X1JldCcmc2FtcGxlaWQgIT0gJ1MzX0hldF9TQ04nJnNhbXBsZWlkICE9ICdTNF9IZXRfZExHTicgJiBzYW1wbGVpZCAhPSAnUzRfSGV0X1JldCcgJiBzYW1wbGVpZCAhPSAnUzRfSGV0X1NDTiciKQoKbW0zOF9kbGduX3N1YnNldCA8LSBzdWJzZXRfc2UobW0zOF9maWx0X3N1Yiwgc3Vic2V0ID0gImxvY2F0aW9uX3RpbWUgPT0gJ2RMR05faGV0JyB8IGxvY2F0aW9uX3RpbWUgPT0gJ2RMR05fa28nIikKbW0zOF9yZXRfc3Vic2V0IDwtIHN1YnNldF9zZShtbTM4X2ZpbHRfc3ViLCBzdWJzZXQgPSAibG9jYXRpb25fdGltZSA9PSAnUmV0aW5hX2hldCcgfCBsb2NhdGlvbl90aW1lID09ICdSZXRpbmFfa28nIikKbW0zOF9zY25fc3Vic2V0IDwtIHN1YnNldF9zZShtbTM4X2ZpbHRfc3ViLCBzdWJzZXQgPSAibG9jYXRpb25fdGltZSA9PSAnU0NOX2hldCcgfCBsb2NhdGlvbl90aW1lID09ICdTQ05fa28nIikKCm1tMzhfZGxnbl9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfZGxnbl9zdWJzZXQsIGZpbHRlciA9IFRSVUUpCm1tMzhfc2NuX3N1YnNldCA8LSBub3JtYWxpemUobW0zOF9zY25fc3Vic2V0LCBmaWx0ZXIgPSBUUlVFKQptbTM4X3JldF9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfcmV0X3N1YnNldCwgZmlsdGVyID0gVFJVRSkKCm1tMzhfZGxnbl9zdWJzZXQgPC0gc2V0X2JhdGNoZXMobW0zOF9kbGduX3N1YnNldCwgZmFjdCA9ICJjb25kaXRpb24iKQptbTM4X3Njbl9zdWJzZXQgPC0gc2V0X2JhdGNoZXMobW0zOF9zY25fc3Vic2V0LCBmYWN0ID0gImNvbmRpdGlvbiIpCm1tMzhfcmV0X3N1YnNldCA8LSBzZXRfYmF0Y2hlcyhtbTM4X3JldF9zdWJzZXQsIGZhY3QgPSAiY29uZGl0aW9uIikKCm1tMzhfZGxnbl9zdWJzZXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9kbGduX3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKbW0zOF9zY25fc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfc2NuX3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKbW0zOF9yZXRfc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfcmV0X3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKYGBgCgpgYGB7cn0KdGVzdCA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2ZpbHQsIGZhY3QgPSAibG9jYXRpb25fdGltZSIpIHw+Cm5vcm1hbGl6ZSh0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwgYmF0Y2ggPSAic3ZhIikKcGxvdF9wY2EodGVzdCkKYGBgCgpJIGRvIG5vdCB0aGluayBvbmUgc2hvdWxkIHJlYWxseSBkbyB0aGUgREUgd2l0aCB0aGUgZGF0YSBzZXBhcmF0ZSBsaWtlCnRoaXMgdW5sZXNzIHRoZXJlIGlzIHNvbWUgY29tcGVsbGluZyByZWFzb24uICBJIGFtIGdvaW5nIHRvIHJlcGVhdAp3aXRob3V0IHRoaXMgY29uc3RyYWludCBhbmQgc2VlIGhvdyBzaW1pbGFyL2RpZmZlcmVudCB0aGUgcmVzdWx0cyBhcmUuCkluIGFkZGl0aW9uLCB0aGUgY3VycmVudCByZXZpc2lvbiBvZiBhbGxfcGFpcndpc2UoKSBpcyBtdWNoIG1vcmUKY29tZm9ydGFibGUgd2l0aCBtb3JlIGNvbXBsZXggbW9kZWxzLCBldmVuIHdpdGggc3ZhOyBzbyB0aGF0IG1pZ2h0Cm1ha2UgdGhpcyBtb3JlIGZ1bi4KCmBgYHtyfQptbV9kZV9kbGduIDwtIGFsbF9wYWlyd2lzZShtbTM4X2RsZ25fc3Vic2V0LCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9kbGduCm1tX3RhYmxlX2RsZ24gPC0gY29tYmluZV9kZV90YWJsZXMobW1fZGVfZGxnbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX2RsZ25fdGFibGUueGxzeCIpCm1tX3NpZ19kbGduIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobW1fdGFibGVfZGxnbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX2RsZ25fc2lnLnhsc3giKQoKbW1fZGVfcmV0IDwtIGFsbF9wYWlyd2lzZShtbTM4X3JldF9zdWJzZXQsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKbW1fZGVfcmV0Cm1tX3RhYmxlX3JldCA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV9kZV9yZXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX3JldF90YWJsZS54bHN4IikKbW1fc2lnX3JldCA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX3RhYmxlX3JldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX3JldF9zaWcueGxzeCIpCgptbV9kZV9zY24gPC0gYWxsX3BhaXJ3aXNlKG1tMzhfc2NuX3N1YnNldCwgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9zY24KbW1fdGFibGVfc2NuIDwtIGNvbWJpbmVfZGVfdGFibGVzKG1tX2RlX3NjbiwgZXhjZWwgPSAiMzlidWxrX3RhYmxlc190eC9tbV9kZV9zY25fdGFibGUueGxzeCIpCm1tX3NpZ19zY24gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhtbV90YWJsZV9zY24sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX3Njbl9zaWcueGxzeCIpCmBgYAoKIyMgU0NOCgpgYGB7cn0Ka2VlcGVycyA8LSBuYW1lcyhtbV9kZV9zY24kZGVzZXEkYWxsX3RhYmxlcykKCnJlc190YmxzX3NjbiA8LSBjKCkKZm9yICh0YmwgaW4ga2VlcGVycykgewogIGRlc2VxX3RibCA8LSBnZXRfZGVfdGFibGUobW1fZGVfc2NuLCB0YWJsZSA9IHRibCkKICByZXNfdGJsc19zY25bW3RibF1dIDwtIG1lcmdlKGRlc2VxX3RibCwgaGlzYXRfYW5ub3QsIGJ5ID0gInJvdy5uYW1lcyIpCiAgZmN0ciA8LSBjKHBhc3RlKGdzdWIoIlxcXy4qIiwiIix0YmwpLCAiXG5FbnJpY2hlZCIpLAogICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpCiAgcmVzX3RibHNfc2NuW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzX3NjbltbdGJsXV0sIGZhY3RvcnMgPSBmY3RyKQogIHJlc190YmxzX3NjbltbcGFzdGUwKHRibCwgInZvbGNfcGxvdGx5IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfc2NuW1t0YmxdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwbG90bHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAidW5pcHJvdF9nbl9zeW1ib2wiKQogIHJlc190YmxzX3NjbltbcGFzdGUwKHRibCwgInZvbGNfZ2dwbG90IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfc2NuW1t0YmxdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIikKfQoKcmVzX3RibHNfc2NuJFNDTmtvX3ZzX1NDTmhldHZvbGNfZ2dwbG90CnJlc190YmxzX3NjbiRTQ05rb192c19TQ05oZXR2b2xjX3Bsb3RseQpyZXNfdGJsc19zY24kU0NOa29fdnNfU0NOaGV0IHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSB8PgogIGZpbHRlcihhYnMobG9nRkMpID49IDEpIHw+CiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAidW5pcHJvdF9nbl9zeW1ib2wiLCAiU2lnbmlmaWNhbmNlIiwgImRlc2NyaXB0aW9uIiwgImJhc2VNZWFuIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIpIHw+CiAgYXJyYW5nZShsb2dGQykgfD4KICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKIyMgZExHTgoKYGBge3J9CmtlZXBlcnMgPC0gbmFtZXMobW1fZGVfZGxnbiRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfZGxnbiA8LSBjKCkKZm9yICh0YmwgaW4ga2VlcGVycykgewogIGRlc2VxX3RibCA8LSBnZXRfZGVfdGFibGUobW1fZGVfZGxnbiwgdGFibGUgPSB0YmwpCiAgcmVzX3RibHNfZGxnbltbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICByZXNfdGJsc19kbGduW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzX2RsZ25bW3RibF1dLCBmYWN0b3JzID0gYyhwYXN0ZShnc3ViKCJcXF8uKiIsIiIsdGJsKSwgIlxuRW5yaWNoZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpKQogIHJlc190YmxzX2RsZ25bW3Bhc3RlMCh0YmwsICJ2b2xjX3Bsb3RseSIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX2RsZ25bW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicGxvdGx5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAidW5pcHJvdF9nbl9zeW1ib2wiKQogIHJlc190YmxzX2RsZ25bW3Bhc3RlMCh0YmwsICJ2b2xjX2dncGxvdCIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX2RsZ25bW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIpCn0KCnJlc190YmxzX2RsZ24kZExHTmtvX3ZzX2RMR05oZXR2b2xjX2dncGxvdApyZXNfdGJsc19kbGduJGRMR05rb192c19kTEdOaGV0dm9sY19wbG90bHkKcmVzX3RibHNfZGxnbiRkTEdOa29fdnNfZExHTmhldCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAxKSB8PgogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgInVuaXByb3RfZ25fc3ltYm9sIiwgIlNpZ25pZmljYW5jZSIsICJkZXNjcmlwdGlvbiIsICJiYXNlTWVhbiIsICJsb2dGQyIsICJhZGouUC5WYWwiKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCgojIyBSZXRpbmEKCmBgYHtyfQprZWVwZXJzIDwtIG5hbWVzKG1tX2RlX3JldCRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfcmV0IDwtIGMoKQpmb3IgKHRibCBpbiBrZWVwZXJzKSB7CiAgZGVzZXFfdGJsIDwtIGdldF9kZV90YWJsZShtbV9kZV9yZXQsIHRhYmxlID0gdGJsKQogIHJlc190YmxzX3JldFtbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICByZXNfdGJsc19yZXRbW3RibF1dIDwtIHNldF9zaWdfbGltbWEocmVzX3RibHNfcmV0W1t0YmxdXSwgZmFjdG9ycyA9IGMocGFzdGUoZ3N1YigiXFxfLioiLCIiLHRibCksICJcbkVucmljaGVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHN1YignLipcXF8nLCAnJywgdGJsKSwgIlxuRW5yaWNoZWQiKSkpCiAgcmVzX3RibHNfcmV0W1twYXN0ZTAodGJsLCAidm9sY19wbG90bHkiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19yZXRbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9uYW1lX2NvbCA9ICJ1bmlwcm90X2duX3N5bWJvbCIpCiAgcmVzX3RibHNfcmV0W1twYXN0ZTAodGJsLCAidm9sY19nZ3Bsb3QiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19yZXRbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiKQp9CgpyZXNfdGJsc19yZXQkUmV0aW5ha29fdnNfUmV0aW5haGV0dm9sY19nZ3Bsb3QKcmVzX3RibHNfcmV0JFJldGluYWtvX3ZzX1JldGluYWhldHZvbGNfcGxvdGx5CnJlc190YmxzX3JldCRSZXRpbmFrb192c19SZXRpbmFoZXQgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUpIHw+CiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMSkgfD4KICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJ1bmlwcm90X2duX3N5bWJvbCIsICJTaWduaWZpY2FuY2UiLCAiZGVzY3JpcHRpb24iLCAiYmFzZU1lYW4iLCAibG9nRkMiLCAiYWRqLlAuVmFsIikgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgojIERFIG9mIGFsbCBzYW1wbGVzIHdpdGggU1ZBIGJhdGNoIGNvcnJlY3Rpb24gZm9yIGhpZ2ggdiBsb3cgZXhwcmVzc29ycwoKYGBge3J9Cm1tMzhfZGxnbl9zdWJzZXQgPC0gc3Vic2V0X3NlKAogIG1tMzhfZmlsdCwgc3Vic2V0ID0gImxvY2F0aW9uX3RpbWUgPT0gJ2RMR05faGV0J3wgbG9jYXRpb25fdGltZSA9PSAnZExHTl9rbyciKQptbTM4X3JldF9zdWJzZXQgPC0gc3Vic2V0X3NlKAogIG1tMzhfZmlsdCwgc3Vic2V0ID0gImxvY2F0aW9uX3RpbWUgPT0gJ1JldGluYV9oZXQnfCBsb2NhdGlvbl90aW1lID09ICdSZXRpbmFfa28nIikKbW0zOF9zY25fc3Vic2V0IDwtIHN1YnNldF9zZSgKICBtbTM4X2ZpbHQsIHN1YnNldCA9ICJsb2NhdGlvbl90aW1lID09ICdTQ05faGV0J3wgbG9jYXRpb25fdGltZSA9PSAnU0NOX2tvJyIpCgptbTM4X2RsZ25fc3Vic2V0IDwtIG5vcm1hbGl6ZShtbTM4X2RsZ25fc3Vic2V0LCBmaWx0ZXIgPSBUUlVFKQptbTM4X3Njbl9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfc2NuX3N1YnNldCwgZmlsdGVyID0gVFJVRSkKbW0zOF9yZXRfc3Vic2V0IDwtIG5vcm1hbGl6ZShtbTM4X3JldF9zdWJzZXQsIGZpbHRlciA9IFRSVUUpCgptbTM4X2RsZ25fc3Vic2V0IDwtIHNldF9iYXRjaGVzKG1tMzhfZGxnbl9zdWJzZXQsIGZhY3QgPSAiY29uZGl0aW9uIikKbW0zOF9zY25fc3Vic2V0IDwtIHNldF9iYXRjaGVzKG1tMzhfc2NuX3N1YnNldCwgZmFjdCA9ICJjb25kaXRpb24iKQptbTM4X3JldF9zdWJzZXQgPC0gc2V0X2JhdGNoZXMobW0zOF9yZXRfc3Vic2V0LCBmYWN0ID0gImNvbmRpdGlvbiIpCgptbTM4X2RsZ25fc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfZGxnbl9zdWJzZXQsIGZhY3QgPSAibG9jYXRpb25fdGltZSIpCm1tMzhfc2NuX3N1YnNldCA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X3Njbl9zdWJzZXQsIGZhY3QgPSAibG9jYXRpb25fdGltZSIpCm1tMzhfcmV0X3N1YnNldCA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X3JldF9zdWJzZXQsIGZhY3QgPSAibG9jYXRpb25fdGltZSIpCmBgYAoKYGBge3J9Cm1tX2RlX2RsZ25fc3ZhIDwtIGFsbF9wYWlyd2lzZShtbTM4X2RsZ25fc3Vic2V0LCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKbW1fZGVfcmV0X3N2YSA8LSBhbGxfcGFpcndpc2UobW0zOF9yZXRfc3Vic2V0LCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKbW1fZGVfc2NuX3N2YSA8LSBhbGxfcGFpcndpc2UobW0zOF9zY25fc3Vic2V0LCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKbW1fZGVfc2NuX3N2YQoKbW1fc2NuX3N2YV90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBtbV9kZV9zY25fc3ZhLCBleGNlbCA9ICJleGNlbC9tbV9zdWJzZXRfc2NuX3N2YV90YWJsZS54bHN4IikKbW1fc2NuX3N2YV90YWJsZQptbV9zY25fc3ZhX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIG1tX3Njbl9zdmFfdGFibGUsIGV4Y2VsID0gImV4Y2VsL21tX3N1YnNldF9zY25fc3ZhX3NpZy54bHN4IikKbW1fc2NuX3N2YV9zaWcKYGBgCgojIyBkTEdOCgojIyMgUENBIHByZSBhbmQgcG9zdCBTVkFzZXEKCmBgYHtyfQptbTM4X2RsZ25fc3Vic2V0X25vcm1fYmF0Y2ggPC0gbm9ybWFsaXplKG1tMzhfZGxnbl9zdWJzZXQsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCm1tMzhfZGxnbl9zdWJzZXRfbm9ybV9ub2JhdGNoIDwtIG5vcm1hbGl6ZShtbTM4X2RsZ25fc3Vic2V0LCBjb252ZXJ0ID0gImNwbSIsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiKQoKcGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9ub2JhdGNoIDwtIHBsb3RfcGNhKG1tMzhfZGxnbl9zdWJzZXRfbm9ybV9ub2JhdGNoKQpwY2Ffbm9ybV9wbG90X25vYmF0Y2ggPC0gIGdncGxvdChwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2gkdGFibGUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbmRpdGlvbiksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl92YWx1ZXMsCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIHdpdGggTm8gQmF0Y2ggQ29ycmVjdGlvbiIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2gkcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9ub2JhdGNoJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKSAgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIocGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9ub2JhdGNoJHRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzICVpbiUgYygnUzNfSHRfZExHTicsICdTNF9IdF9kTEdOJykpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjEpCgoKcGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCA8LSBwbG90X3BjYShtbTM4X2RsZ25fc3Vic2V0X25vcm1fYmF0Y2gpCnBjYV9ub3JtX3Bsb3RfYmF0Y2ggPC0gIGdncGxvdChwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX2JhdGNoJHRhYmxlLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb25kaXRpb24pLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIFNWQSBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9tbTM4X2RsZ25fc3Vic2V0X25vcm1fYmF0Y2gkcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkgICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKHBjYV9tbTM4X2RsZ25fc3Vic2V0X25vcm1fYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdTM19IdF9kTEdOJywgJ1M0X0h0X2RMR04nKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4xLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMSkKCgpwY2Ffbm9ybV9wbG90X25vYmF0Y2gKcGNhX25vcm1fcGxvdF9iYXRjaApgYGAKCgojIyMgVm9sY2FubyBQbG90cyBhZCBERSB0YWJsZSByZXN1bHRzCgpgYGB7cn0Ka2VlcGVycyA8LSBuYW1lcyhtbV9kZV9kbGduX3N2YSRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfZGxnbl9zdmEgPC0gYygpCmZvciAodGJsIGluIGtlZXBlcnMpIHsKICBkZXNlcV90YmwgPC0gZ2V0X2RlX3RhYmxlKG1tX2RlX2RsZ25fc3ZhLCB0YWJsZSA9IHRibCkKICByZXNfdGJsc19kbGduX3N2YVtbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICByZXNfdGJsc19kbGduX3N2YVtbdGJsXV0gPC0gc2V0X3NpZ19saW1tYShyZXNfdGJsc19kbGduX3N2YVtbdGJsXV0sIGZhY3RvcnMgPSBjKHBhc3RlKGdzdWIoIlxcXy4qIiwiIix0YmwpLCAiXG5FbnJpY2hlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoc3ViKCcuKlxcXycsICcnLCB0YmwpLCAiXG5FbnJpY2hlZCIpKSkKICByZXNfdGJsc19kbGduX3N2YVtbcGFzdGUwKHRibCwgInZvbGNfcGxvdGx5IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfZGxnbl9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwbG90bHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX25hbWVfY29sID0gInVuaXByb3RfZ25fc3ltYm9sIikKICByZXNfdGJsc19kbGduX3N2YVtbcGFzdGUwKHRibCwgInZvbGNfZ2dwbG90IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfZGxnbl9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIikKfQoKcmVzX3RibHNfZGxnbl9zdmEkZExHTmtvX3ZzX2RMR05oZXR2b2xjX2dncGxvdApyZXNfdGJsc19kbGduX3N2YSRkTEdOa29fdnNfZExHTmhldHZvbGNfcGxvdGx5CgpyZXNfdGJsc19kbGduX3N2YSRkTEdOa29fdnNfZExHTmhldCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAxKSB8PgogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgInVuaXByb3RfZ25fc3ltYm9sIiwgIlNpZ25pZmljYW5jZSIsICJkZXNjcmlwdGlvbiIsICJiYXNlTWVhbiIsICJsb2dGQyIsICJhZGouUC5WYWwiKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKClNhbWQxMSBhbmQgRG1ydDMgYXJlIHN0aWxsIGJvdGggdXByZWd1bGF0ZWQgaW4gZExHTiBLT3MgKGFzIHRoZXkgd2VyZQp3aXRob3V0IGluY2x1ZGluZyB0aGUgaGlnaC1leHByZXNzb3JzKS4KClB0dGcxLCBTZW1hM2csIElmaWgxLCBEcHBhNWEsIGFuZCBQcmc0IGFyZSBhbGwgdXByZWd1bGF0ZWQgaW4gZExHTgpIZXRzIGluY2x1ZGluZyBhbmQgZXhjbHVkaW5nIHRoZSBoaWdoIGV4cHJlc3NvcnMuIFdlIGRvIGxvc2UgYSBmZXcKZ2VuZXMgd2hlbiBpbmNsdWRpbmcgaGlnaCBleHByZXNzb3JzIHRoYXQgd2VyZSBlbnJpY2hlZCBpbiBkTEdOIGhldHMKYmVmb3JlLgoKIyMgU0NOCgojIyMgUENBIHByZSBhbmQgcG9zdCBTVkFzZXEKCmBgYHtyfQptbTM4X3Njbl9zdWJzZXRfbm9ybV9iYXRjaCA8LSBub3JtYWxpemUobW0zOF9zY25fc3Vic2V0LCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCm1tMzhfc2NuX3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gbm9ybWFsaXplKG1tMzhfc2NuX3N1YnNldCwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiKQoKcGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gcGxvdF9wY2EobW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCkKcGNhX25vcm1fcGxvdF9ub2JhdGNoX3NjbiA8LSAgZ2dwbG90KHBjYV9tbTM4X3Njbl9zdWJzZXRfbm9ybV9ub2JhdGNoJHRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gbGFiZWxzKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29uZGl0aW9uKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlc1s1OjZdLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIE5vIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX25vYmF0Y2gkcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX25vYmF0Y2gkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpICArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCR0YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGMoJ1MzX0hldF9TQ04nLCAnUzRfSGV0X1NDTicpKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLjIsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4yKQoKCnBjYV9tbTM4X3Njbl9zdWJzZXRfbm9ybV9iYXRjaCA8LSBwbG90X3BjYShtbTM4X3Njbl9zdWJzZXRfbm9ybV9iYXRjaCkKcGNhX25vcm1fcGxvdF9iYXRjaF9zY24gPC0gIGdncGxvdChwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fYmF0Y2gkdGFibGUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbmRpdGlvbiksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl92YWx1ZXNbNTo2XSwKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBTVkEgQmF0Y2ggQ29ycmVjdGlvbiIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fYmF0Y2gkcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX2JhdGNoJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKSAgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIocGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX2JhdGNoJHRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzICVpbiUgYygnUzNfSGV0X1NDTicsICdTNF9IZXRfU0NOJykpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMiwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjIpCgoKcGNhX25vcm1fcGxvdF9ub2JhdGNoX3NjbgpwY2Ffbm9ybV9wbG90X2JhdGNoX3NjbgpgYGAKCiMjIyBWb2xjYW5vIFBsb3RzIGFkIERFIHRhYmxlIHJlc3VsdHMKCmBgYHtyfQprZWVwZXJzIDwtIG5hbWVzKG1tX2RlX3Njbl9zdmEkZGVzZXEkYWxsX3RhYmxlcykKCnJlc190YmxzX3Njbl9zdmEgPC0gYygpCmZvciAodGJsIGluIGtlZXBlcnMpIHsKICBkZXNlcV90YmwgPC0gZ2V0X2RlX3RhYmxlKG1tX2RlX3Njbl9zdmEsIHRhYmxlID0gdGJsKQogIHJlc190YmxzX3Njbl9zdmFbW3RibF1dIDwtIG1lcmdlKGRlc2VxX3RibCwgaGlzYXRfYW5ub3QsIGJ5ID0gInJvdy5uYW1lcyIpCiAgcmVzX3RibHNfc2NuX3N2YVtbdGJsXV0gPC0gc2V0X3NpZ19saW1tYShyZXNfdGJsc19zY25fc3ZhW1t0YmxdXSwgZmFjdG9ycyA9IGMocGFzdGUoZ3N1YigiXFxfLioiLCIiLHRibCksICJcbkVucmljaGVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoc3ViKCcuKlxcXycsICcnLCB0YmwpLCAiXG5FbnJpY2hlZCIpKSkKICByZXNfdGJsc19zY25fc3ZhW1twYXN0ZTAodGJsLCAidm9sY19wbG90bHkiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19zY25fc3ZhW1t0YmxdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX25hbWVfY29sID0gInVuaXByb3RfZ25fc3ltYm9sIikKICByZXNfdGJsc19zY25fc3ZhW1twYXN0ZTAodGJsLCAidm9sY19nZ3Bsb3QiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19zY25fc3ZhW1t0YmxdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiKQp9CgpyZXNfdGJsc19zY25fc3ZhJFNDTmtvX3ZzX1NDTmhldHZvbGNfZ2dwbG90CnJlc190YmxzX3Njbl9zdmEkU0NOa29fdnNfU0NOaGV0dm9sY19wbG90bHkKCnJlc190YmxzX3Njbl9zdmEkU0NOa29fdnNfU0NOaGV0IHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSB8PgogIGZpbHRlcihhYnMobG9nRkMpID49IDEpIHw+CiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAidW5pcHJvdF9nbl9zeW1ib2wiLCAiU2lnbmlmaWNhbmNlIiwgImRlc2NyaXB0aW9uIiwgImJhc2VNZWFuIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIpIHw+CiAgYXJyYW5nZShsb2dGQykgfD4KICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKIyMgUmV0aW5hCgojIyMgUENBIHByZSBhbmQgcG9zdCBTVkFzZXEKCmBgYHtyfQptbTM4X3JldF9zdWJzZXRfbm9ybV9iYXRjaCA8LSBub3JtYWxpemUobW0zOF9yZXRfc3Vic2V0LCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCm1tMzhfcmV0X3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gbm9ybWFsaXplKG1tMzhfcmV0X3N1YnNldCwgY29udmVydCA9ICJjcG0iLCBub3JtID0gInF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiKQoKcGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gcGxvdF9wY2EobW0zOF9yZXRfc3Vic2V0X25vcm1fbm9iYXRjaCkKcGNhX25vcm1fcGxvdF9ub2JhdGNoX3JldCA8LSAgZ2dwbG90KHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9ub2JhdGNoJHRhYmxlLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb25kaXRpb24pLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzWzM6NF0sCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIHdpdGggTm8gQmF0Y2ggQ29ycmVjdGlvbiIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fbm9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fbm9iYXRjaCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkgICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9ub2JhdGNoJHRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzICVpbiUgYygnUzNfSGV0X1JldCcsICdTNF9IZXRfUmV0JykpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMiwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjIpCgoKcGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX2JhdGNoIDwtIHBsb3RfcGNhKG1tMzhfcmV0X3N1YnNldF9ub3JtX2JhdGNoKQpwY2Ffbm9ybV9wbG90X2JhdGNoX3JldCA8LSAgZ2dwbG90KHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9iYXRjaCR0YWJsZSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gbGFiZWxzKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29uZGl0aW9uKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlc1szOjRdLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIFNWQSBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fYmF0Y2gkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpICArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdTM19IZXRfUmV0JywgJ1M0X0hldF9SZXQnKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4yLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMikKCgpwY2Ffbm9ybV9wbG90X25vYmF0Y2hfcmV0CnBjYV9ub3JtX3Bsb3RfYmF0Y2hfcmV0CmBgYAoKIyMjIFZvbGNhbm8gUGxvdHMgYWQgREUgdGFibGUgcmVzdWx0cwoKYGBge3J9CmtlZXBlcnMgPC0gbmFtZXMobW1fZGVfcmV0X3N2YSRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfcmV0X3N2YSA8LSBjKCkKZm9yICh0YmwgaW4ga2VlcGVycykgewogIGRlc2VxX3RibCA8LSBnZXRfZGVfdGFibGUobW1fZGVfcmV0X3N2YSwgdGFibGUgPSB0YmwpCiAgcmVzX3RibHNfcmV0X3N2YVtbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICByZXNfdGJsc19yZXRfc3ZhW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzX3JldF9zdmFbW3RibF1dLCBmYWN0b3JzID0gYyhwYXN0ZShnc3ViKCJcXF8uKiIsIiIsdGJsKSwgIlxuRW5yaWNoZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpKQogIHJlc190YmxzX3JldF9zdmFbW3Bhc3RlMCh0YmwsICJ2b2xjX3Bsb3RseSIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3JldF9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicGxvdGx5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAidW5pcHJvdF9nbl9zeW1ib2wiKQogIHJlc190YmxzX3JldF9zdmFbW3Bhc3RlMCh0YmwsICJ2b2xjX2dncGxvdCIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3JldF9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIpCn0KCnJlc190YmxzX3JldF9zdmEkUmV0aW5ha29fdnNfUmV0aW5haGV0dm9sY19nZ3Bsb3QKcmVzX3RibHNfcmV0X3N2YSRSZXRpbmFrb192c19SZXRpbmFoZXR2b2xjX3Bsb3RseQoKcmVzX3RibHNfcmV0X3N2YSRSZXRpbmFrb192c19SZXRpbmFoZXQgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUpIHw+CiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMSkgfD4KICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJ1bmlwcm90X2duX3N5bWJvbCIsICJTaWduaWZpY2FuY2UiLCAiZGVzY3JpcHRpb24iLCAiYmFzZU1lYW4iLCAibG9nRkMiLCAiYWRqLlAuVmFsIikgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgojIFJlLUltcGxlbWVudGF0aW9uCgpMZXQgdXMgc3RhcnQgd2l0aCB0aGUgZnVsbCBzZXQgb2YgZGVzaXJlZCB0YWJsZXMuICBJbiB0aGUgYWJvdmUsIHRoZQpkYXRhIHdhcyBzZXBhcmF0ZWQgaW50byB+IDkgc2VwYXJhdGUgY2h1bmtzIGFuZCBJIHRoaW5rIGl0IHdpbGwKYmVuZWZpdCBmcm9tIGJlaW5nIGtlcHQgdG9nZXRoZXIgLS0gYWxzbyBJIHNlZW0gdG8gcmVjYWxsIGV4cHJlc3NpbmcKdGhpcyB0byBUaGVyZXNhIGFuZCB0aGF0IHNoZSBjaGFuZ2VkIHRoZSBub3RlYm9vayB0byB0aGlzIGtpbmQgb2YKYW5hbHlzaXMuICBJZiBJIGFtIGNvcnJlY3QsIHRoZW4gaXQgaXMgcG9zc2libGUgc2hlIGRpZCBzbyBpbiBhCnNlcGFyYXRlIG5vdGVib29rIHdoaWNoIEkgaGF2ZSBub3QgZm91bmQgYW5kIHRoYXQgdGhpcyB3aWxsIHByb3ZpZGUKdGhlIGZ1bGx5IHJlY29uY2lsZWQgc2V0IG9mIHJlc3VsdHMuCgpJIGhhdmUgcmVhc29uYWJsZSBob3BlIGZvciB0aGlzIGJlY2F1c2UgdGhlIHZhcmlvdXMgcGxvdHMgZXRjIGVhcmx5IG9uCmxvb2sgaWRlbnRpY2FsIGJldHdlZW4gdGhpcyBjb250YWluZXJpemVkIG5vdGVib29rLCBhbmQgdGhvc2UKbm90ZWJvb2tzIEkgZm91bmQgaW4gaGVyIHdvcmtpbmcgdHJlZS4KCldoaWxlIEkgd2FpdCBmb3IgdGhlc2UgdGFibGVzIHRvIGNvbWUgYmFjaywgbGV0IHVzIGNvdW50IHRoZSBudW1iZXIgb2YKc2FtcGxlcyBpbiB0aGUgcGxvdCBwcm92aWRlZCBieSBDb2xlbnNvIHNvIHRoYXQgSSBtYXkgZG91YmxlY2hlY2sgdGhhdApub3RoaW5nIGdvdCBmaWx0ZXJlZCBvdXQgb3IgYW55dGhpbmcgaW1wb3J0YW50IGxpa2UgdGhhdC4KCjggcGluayBzYW1wbGVzLCAxNyBncmVlbiBzYW1wbGVzLCAxNyBibHVlIHNhbXBsZXMuCgo0IGxpZ2h0IHBpbmssIDQgZGFyayBwaW5rCjkgbWVkaXVtIGdyZWVuLCA0IGxpZ2h0IGdyZWVuLCA0IGRhcmsgZ3JlZW4uCjkgbWVkaXVtIGJsdWUsIDQgbGlnaHQgYmx1ZSwgNCBkYXJrIGJsdWUuCgpXaXRoIHRoZSBhYm92ZSBpbiBtaW5kLCBsZXQgdXMgbWFrZSBhIHNtYWxsIGNoYW5nZSBpbiBob3cgdGhlIGRhdGEgaXMKaGFuZGxlZCBhbmQgc2VlIGlmIEkgY2Fubm90IGdldCBudW1iZXJzIG1vcmUgY2xvc2VseSBhbGlnbmVkIHRvIHRoZQp0YWJsZXMgZnJvbSBDb2xlbnNvLgoKYGBge3J9CiMjIEhlcmUgaXMgYSByZW1pbmRlciBvZiBUaGVyZXNhJ3MgZmlsdGVyOgojIyBmaWx0ZXIoc2FtcGxlX2lkICVpbiUgYygiUzNfSGV0X1JldF9TMSIsICJTNF9IZXRfUmV0X1M0IiwgIlM1X0hldF9SZXRfUzE2IiwgIlMxX0hldF9SZXRfUzEiLCAiUzJfSGV0X1JldF9TNCIsICJTM19IZXRfUmV0X1M3IiwgIlM0X0hldF9SZXRfUzEwIiwgIlM1X0hldF9SZXRfUzEzIikpIHw+CgptbV9maW5hbCA8LSBzdWJzZXRfc2UobW0zOF9oaXNhdCwgc3Vic2V0ID0gImluY2x1ZGVkPT0neWVzJyIpIHw+CiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJsb2NhdGlvbl9nZW5vdHlwZSIpCgptbV9ub3JtIDwtIG5vcm1hbGl6ZShtbV9maW5hbCwgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIsIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiKQpwbG90X3BjYShtbV9ub3JtKQoKbW1fbmIgPC0gbm9ybWFsaXplKG1tX2ZpbmFsLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwgYmF0Y2ggPSAic3Zhc2VxIikKcGxvdF9wY2EobW1fbmIpCmBgYAoKVGhlcmUgcmVtYWluIGEgY291cGxlIG9mIHdlaXJkbyBzYW1wbGVzLCBidXQgdGhpbmdzIGxvb2sgcXVpdGUgYSBiaXQKZWFzaWVyIHRvIGludGVycHJldCB0byBteSBleWVzLgoKYGBge3J9CmZpbmFsX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBUaHJlZSBjb21wYXJpc29ucyBhbW9uZyB0aGUgZExHTiBzYW1wbGVzLgogICJkbGduX2t3IiA9IGMoImRMR05fa28iLCAiZExHTl93dCIpLAogICJkbGduX2toIiA9IGMoImRMR05fa28iLCAiZExHTl9oZXQiKSwKICAiZGxnbl9odyIgPSBjKCJkTEdOX2hldCIsICJkTEdOX3d0IiksCiAgIyMgVGhyZWUgY29tcGFyaXNvbnMgYW1vbmcgdGhlIFNDTiBzYW1wbGVzLgogICJzY25fa3ciID0gYygiU0NOX2tvIiwgIlNDTl93dCIpLAogICJzY25fa2giID0gYygiU0NOX2tvIiwgIlNDTl9oZXQiKSwKICAic2NuX2h3IiA9IGMoIlNDTl9oZXQiLCAiU0NOX3d0IiksCiAgIyMgYW5kIHRoZSByZXRpbmEgc2FtcGxlcwogICJyZXRpbmFfa3ciID0gYygiUmV0aW5hX2tvIiwgIlJldGluYV93dCIpLAogICJyZXRpbmFfa2giID0gYygiUmV0aW5hX2tvIiwgIlJldGluYV9oZXQiKSwKICAicmV0aW5hX2h3IiA9IGMoIlJldGluYV9oZXQiLCAiUmV0aW5hX3d0IikKKQoKZ2Vub2xvY19kZV9zdmEgPC0gYWxsX3BhaXJ3aXNlKG1tX2ZpbmFsLCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwga2VlcGVycyA9IGZpbmFsX2tlZXBlcnMpCmdlbm9sb2NfdGFibGVfc3ZhIDwtIGNvbWJpbmVfZGVfdGFibGVzKGdlbm9sb2NfZGVfc3ZhLCBleGNlbCA9ICJleGNlbC9nZW5vdHlwZV9sb2NhdGlvbl90YWJsZXMueGxzeCIpCmdlbm9sb2Nfc2lnX3N2YSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGdlbm9sb2NfdGFibGVfc3ZhLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICJleGNlbC9nZW5vdHlwZV9sb2NhdGlvbl9zaWcueGxzeCIpCgoKbG9jYXRpb25fa2VlcGVycyA8LSBsaXN0KAogICMjIGtvIGFjcm9zcyBsb2NhdGlvbnMKICAia29fZGxnbl9zY24iID0gYygiZExHTl9rbyIsICJTQ05fa28iKSwKICAia29fZGxnbl9yZXQiID0gYygiZExHTl9rbyIsICJSZXRpbmFfa28iKSwKICAia29fc2NuX3JldCIgPSBjKCJTQ05fa28iLCAiUmV0aW5hX2tvIiksCiAgIyMgaGV0IGFjcm9zcyBsb2NhdGlvbnMKICAiaGV0X2RsZ25fc2NuIiA9IGMoImRMR05faGV0IiwgIlNDTl9oZXQiKSwKICAiaGV0X2RsZ25fcmV0IiA9IGMoImRMR05faGV0IiwgIlJldGluYV9oZXQiKSwKICAiaGV0X3Njbl9yZXQiID0gYygiU0NOX2hldCIsICJSZXRpbmFfaGV0IiksCiAgIyMgd3QgYWNyb3NzIGxvY2F0aW9ucwogICJ3dF9kbGduX3NjbiIgPSBjKCJkTEdOX3d0IiwgIlNDTl93dCIpLAogICJ3dF9kbGduX3JldCIgPSBjKCJkTEdOX3d0IiwgIlJldGluYV93dCIpLAogICJ3dF9zY25fcmV0IiA9IGMoIlNDTl93dCIsICJSZXRpbmFfd3QiKSkKbG9jYXRpb25fY29tcGFyaXNvbnMgPC0gYWxsX3BhaXJ3aXNlKG1tX2ZpbmFsLCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSAic3Zhc2VxIiwga2VlcGVycyA9IGxvY2F0aW9uX2tlZXBlcnMpCmxvY2F0aW9uX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKGxvY2F0aW9uX2NvbXBhcmlzb25zLCBleGNlbCA9ICJleGNlbC9sb2NhdGlvbnMueGxzeCIpCmxvY2F0aW9uX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKGxvY2F0aW9uX3RhYmxlLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICJleGNlbC9sb2NhdGlvbl9zaWcueGxzeCIpCmBgYAoKU2F2ZSBzb21lIG9mIHRoZSBERSByZXN1bHRzIGZvciBjb21wYXJpc29uIGFnYWlucyB0aGUgVFJBUCBkYXRhCgpgYGB7ciwgZXZhbD1GQUxTRX0KZGVfbGlzdCA8LSBjKCJtbV9kZV9kbGduX3N2YSIsICJtbV9kZV9yZXRfc3ZhIiwgIm1tX2RlX3Njbl9zdmEiLAogICAgICAgICAgICAgIm1tX2RlX2RsZ24iLCAibW1fZGVfcmV0IiwgIm1tX2RlX3NjbiIsCiAgICAgICAgICAgICAiZ2Vub2xvY19kZV9zdmEiLCAiZ2Vub2xvY190YWJsZV9zdmEiKQpzYXZlZCA8LSBzYXZlKGxpc3QgPSBkZV9saXN0LCBmaWxlID0gImJ1bGtfcmVzdWx0cy5yZGEiKQpgYGAKCg==