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[["annotation"]]
## 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) <- paste0("transcript:", rownames(mm_tx_annot))
## Error in `rownames<-`:
## ! attempt to set 'rownames' on an object with no dimensions
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).
## Error in `read_counts_salmon()`:
## ! object 'remove_trailing_number' not found

3 Color Set Up

color_condition <- mm38_hisat$initial_metadata$condition
## Error:
## ! object 'mm38_hisat' not found
color_condition <- factor(color_condition, levels = c("Retina_het", "Retina_ko",
                                                      "SCN_het", "SCN_ko", "dLGN_het", "dLGN_ko"))
## Error:
## ! object 'color_condition' not found
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")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_hisat' not found
libsize_df <- as.data.frame(plot_libsize(mm38_hisat)$table)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': error in evaluating the argument 'data' in selecting a method for function 'plot_quantreads': object 'mm38_hisat' not found
rownames(libsize_df) <- mm38_hisat$design$sampleid
## Error:
## ! object 'mm38_hisat' not found
libsize_df$samplenum <- paste0(mm38_hisat$design[rownames(libsize_df), "samplenumb"], "_",
                               mm38_hisat$design[rownames(libsize_df), "batch"])
## Error:
## ! object 'mm38_hisat' not found
libsize_df$sample_id <-  rownames(mm38_hisat$design)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'mm38_hisat' not found
libsize_df <- libsize_df[order(libsize_df$sum),]
## Error:
## ! object 'libsize_df' not found
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 = "")
## Error:
## ! object 'libsize_df' not found
plot_libsize(mm38_hisat)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_quantreads': object 'mm38_hisat' not found

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)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_hisat' not found
des <- colData(mm38_filt)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
new_factor <- paste0(des[["location"]], "_", des[["genotype"]])
## Error:
## ! object 'des' not found
colData(mm38_hisat)[["location_genotype"]] <- new_factor
## Error:
## ! object 'new_factor' not found
mm38_norm <- normalize(mm38_hisat, filter = TRUE, convert = "cpm",
                       norm = "quant", transform="log2")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_hisat' not found
mm38_norm <- set_conditions(mm38_norm, fact = "location_genotype")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_norm' not found

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)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_norm' not found
pca_norm[["plot"]]
## Error:
## ! object 'pca_norm' not found
## rownames(pca_norm$result$v)
labels <- des[["sampleid"]]
## Error:
## ! object 'des' not found
## labels <- paste0(mm38_norm$design$sampleid, "_", mm38_norm$design$samplenumb)
all_df <-  cbind(as.data.frame(pca_norm$result$v), labels)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'pca_norm' not found
shape_genotype <- mm38_norm$design$genotype
## Error:
## ! object 'mm38_norm' not found
color_condition <- mm38_norm$condition
## Error:
## ! object 'mm38_norm' not found
## 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"))
## Error:
## ! object 'all_df' not found
#setEPS()                                             # Set postscript arguments
#postscript("bulkRNAseq_PCA_allsamples_labeledS5.eps")                           # Start graphics device driver
all_df[["labels"]] <- rownames(all_df)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'all_df' not found
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)
## Error:
## ! object 'pca_norm_plot' not found
#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"))
## Error:
## ! object 'all_df' not found

I think there is an easier way to do the above

b1 <- subset_se(mm38_norm, subset = "batch == '1'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_norm' not found
plot_pca(b1)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'b1' not found
b1_b2 <- subset_se(mm38_norm, subset = "batch == '1'|batch == '2'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_norm' not found
plot_pca(b1_b2)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'b1_b2' not found
#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"))
## Error:
## ! object 'all_df' not found
#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'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
mm38_subset <- normalize(mm38_subset, filter=TRUE, convert="cpm",
                         norm = "quant", transform="log2")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_subset' not found
mm38_subset <- set_conditions(mm38_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_subset' not found
pca_norm_subset <- plot_pca(mm38_subset, plot_labels = FALSE)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_subset' not found
pca_norm_subset
## Error:
## ! object 'pca_norm_subset' not found
labels <- rownames(pca_norm_subset$result$v)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'rownames': object 'pca_norm_subset' not found
all_df <-  cbind(as.data.frame(pca_norm_subset$result$v), labels)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'as.data.frame': object 'pca_norm_subset' not found
shape_genotype <- mm38_subset$design$genotype
## Error:
## ! object 'mm38_subset' not found
color_condition <- pca_norm_subset$table$condition
## Error:
## ! object 'pca_norm_subset' not found
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"))
## Error:
## ! object 'pca_norm_subset' not found
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"))
## Error:
## ! object 'all_df' not found
#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)
## Error:
## ! object 'pca_norm_plot' not found
pca_norm_plot + ggtitle("PCA Normalized Counts")# +
## Error:
## ! object 'pca_norm_plot' not found
pca_norm_plot
## Error:
## ! object 'pca_norm_plot' not found
# 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'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
mm38_dlgn_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'dLGN_het' | location_time == 'dLGN_ko'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt_sub' not found
mm38_ret_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'Retina_het' | location_time == 'Retina_ko'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt_sub' not found
mm38_scn_subset <- subset_se(mm38_filt_sub, subset = "location_time == 'SCN_het' | location_time == 'SCN_ko'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt_sub' not found
mm38_dlgn_subset <- normalize(mm38_dlgn_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- normalize(mm38_scn_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_scn_subset' not found
mm38_ret_subset <- normalize(mm38_ret_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_ret_subset' not found
mm38_dlgn_subset <- set_batches(mm38_dlgn_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- set_batches(mm38_scn_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_scn_subset' not found
mm38_ret_subset <- set_batches(mm38_ret_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_ret_subset' not found
mm38_dlgn_subset <- set_conditions(mm38_dlgn_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- set_conditions(mm38_scn_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_scn_subset' not found
mm38_ret_subset <- set_conditions(mm38_ret_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_ret_subset' not found
test <- set_conditions(mm38_filt, fact = "location_time") |>
normalize(transform = "log2", convert = "cpm", batch = "sva")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_filt' not found
plot_pca(test)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'test' not found

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)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_dlgn_subset' not found
mm_de_dlgn
## Error:
## ! object 'mm_de_dlgn' not found
mm_table_dlgn <- combine_de_tables(mm_de_dlgn,
                                   excel = "39bulk_tables_tx/mm_de_dlgn_table.xlsx")
## Error:
## ! object 'mm_de_dlgn' not found
mm_sig_dlgn <- extract_significant_genes(mm_table_dlgn,
                                         excel = "39bulk_tables_tx/mm_de_dlgn_sig.xlsx")
## Error:
## ! object 'mm_table_dlgn' not found
mm_de_ret <- all_pairwise(mm38_ret_subset, model_fstring = "~ 0 + condition",
                          model_svs = "svaseq", filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_ret_subset' not found
mm_de_ret
## Error:
## ! object 'mm_de_ret' not found
mm_table_ret <- combine_de_tables(mm_de_ret,
                                  excel = "39bulk_tables_tx/mm_de_ret_table.xlsx")
## Error:
## ! object 'mm_de_ret' not found
mm_sig_ret <- extract_significant_genes(mm_table_ret,
                                         excel = "39bulk_tables_tx/mm_de_ret_sig.xlsx")
## Error:
## ! object 'mm_table_ret' not found
mm_de_scn <- all_pairwise(mm38_scn_subset, model_fstring = "~ 0 + condition",
                          model_svs = "svaseq", filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_scn_subset' not found
mm_de_scn
## Error:
## ! object 'mm_de_scn' not found
mm_table_scn <- combine_de_tables(mm_de_scn, excel = "39bulk_tables_tx/mm_de_scn_table.xlsx")
## Error:
## ! object 'mm_de_scn' not found
mm_sig_scn <- extract_significant_genes(mm_table_scn, according_to = "deseq",
                                        excel = "39bulk_tables_tx/mm_de_scn_sig.xlsx")
## Error:
## ! object 'mm_table_scn' not found

9.1 SCN

keepers <- names(mm_de_scn$deseq$all_tables)
## Error:
## ! object 'mm_de_scn' not found
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:
## ! object 'mm_de_dlgn' not found
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:
## ! object 'mm_de_ret' not found
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'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
mm38_ret_subset <- subset_se(
  mm38_filt, subset = "location_time == 'Retina_het'| location_time == 'Retina_ko'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
mm38_scn_subset <- subset_se(
  mm38_filt, subset = "location_time == 'SCN_het'| location_time == 'SCN_ko'")
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_filt' not found
mm38_dlgn_subset <- normalize(mm38_dlgn_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- normalize(mm38_scn_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_scn_subset' not found
mm38_ret_subset <- normalize(mm38_ret_subset, filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_ret_subset' not found
mm38_dlgn_subset <- set_batches(mm38_dlgn_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- set_batches(mm38_scn_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_scn_subset' not found
mm38_ret_subset <- set_batches(mm38_ret_subset, fact = "condition")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_batches': object 'mm38_ret_subset' not found
mm38_dlgn_subset <- set_conditions(mm38_dlgn_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_dlgn_subset' not found
mm38_scn_subset <- set_conditions(mm38_scn_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_scn_subset' not found
mm38_ret_subset <- set_conditions(mm38_ret_subset, fact = "location_time")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': object 'mm38_ret_subset' not found
mm_de_dlgn_sva <- all_pairwise(mm38_dlgn_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_dlgn_subset' not found
mm_de_ret_sva <- all_pairwise(mm38_ret_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_ret_subset' not found
mm_de_scn_sva <- all_pairwise(mm38_scn_subset, model_fstring = "~ 0 + condition",
                               model_svs = "svaseq", filter = TRUE)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_scn_subset' not found
mm_de_scn_sva
## Error:
## ! object 'mm_de_scn_sva' not found
mm_scn_sva_table <- combine_de_tables(
  mm_de_scn_sva, excel = "excel/mm_subset_scn_sva_table.xlsx")
## Deleting the file excel/mm_subset_scn_sva_table.xlsx before writing the tables.
## Error:
## ! object 'mm_de_scn_sva' not found
mm_scn_sva_table
## Error:
## ! object 'mm_scn_sva_table' not found
mm_scn_sva_sig <- extract_significant_genes(
  mm_scn_sva_table, excel = "excel/mm_subset_scn_sva_sig.xlsx")
## Deleting the file excel/mm_subset_scn_sva_sig.xlsx before writing the tables.
## Error:
## ! object 'mm_scn_sva_table' not found
mm_scn_sva_sig
## Error:
## ! object 'mm_scn_sva_sig' not found

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")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_dlgn_subset' not found
mm38_dlgn_subset_norm_nobatch <- normalize(mm38_dlgn_subset, convert = "cpm", norm = "quant",
                                           transform = "log2")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_dlgn_subset' not found
pca_mm38_dlgn_subset_norm_nobatch <- plot_pca(mm38_dlgn_subset_norm_nobatch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_dlgn_subset_norm_nobatch' not found
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)
## Error:
## ! object 'pca_mm38_dlgn_subset_norm_nobatch' not found
pca_mm38_dlgn_subset_norm_batch <- plot_pca(mm38_dlgn_subset_norm_batch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_dlgn_subset_norm_batch' not found
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)
## Error:
## ! object 'pca_mm38_dlgn_subset_norm_batch' not found
pca_norm_plot_nobatch
## Error:
## ! object 'pca_norm_plot_nobatch' not found
pca_norm_plot_batch
## Error:
## ! object 'pca_norm_plot_batch' not found

10.1.2 Volcano Plots ad DE table results

keepers <- names(mm_de_dlgn_sva$deseq$all_tables)
## Error:
## ! object 'mm_de_dlgn_sva' not found
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")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_scn_subset' not found
mm38_scn_subset_norm_nobatch <- normalize(mm38_scn_subset, convert = "cpm", norm = "quant",
                                          transform = "log2")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_scn_subset' not found
pca_mm38_scn_subset_norm_nobatch <- plot_pca(mm38_scn_subset_norm_nobatch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_scn_subset_norm_nobatch' not found
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)
## Error:
## ! object 'pca_mm38_scn_subset_norm_nobatch' not found
pca_mm38_scn_subset_norm_batch <- plot_pca(mm38_scn_subset_norm_batch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_scn_subset_norm_batch' not found
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)
## Error:
## ! object 'pca_mm38_scn_subset_norm_batch' not found
pca_norm_plot_nobatch_scn
## Error:
## ! object 'pca_norm_plot_nobatch_scn' not found
pca_norm_plot_batch_scn
## Error:
## ! object 'pca_norm_plot_batch_scn' not found

10.2.2 Volcano Plots ad DE table results

keepers <- names(mm_de_scn_sva$deseq$all_tables)
## Error:
## ! object 'mm_de_scn_sva' not found
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")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_ret_subset' not found
mm38_ret_subset_norm_nobatch <- normalize(mm38_ret_subset, convert = "cpm", norm = "quant",
                                          transform = "log2")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm38_ret_subset' not found
pca_mm38_ret_subset_norm_nobatch <- plot_pca(mm38_ret_subset_norm_nobatch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_ret_subset_norm_nobatch' not found
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)
## Error:
## ! object 'pca_mm38_ret_subset_norm_nobatch' not found
pca_mm38_ret_subset_norm_batch <- plot_pca(mm38_ret_subset_norm_batch)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm38_ret_subset_norm_batch' not found
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)
## Error:
## ! object 'pca_mm38_ret_subset_norm_batch' not found
pca_norm_plot_nobatch_ret
## Error:
## ! object 'pca_norm_plot_nobatch_ret' not found
pca_norm_plot_batch_ret
## Error:
## ! object 'pca_norm_plot_batch_ret' not found

10.3.2 Volcano Plots ad DE table results

keepers <- names(mm_de_ret_sva$deseq$all_tables)
## Error:
## ! object 'mm_de_ret_sva' not found
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")
## Error in `h()`:
## ! error in evaluating the argument 'exp' in selecting a method for function 'set_conditions': error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm38_hisat' not found
mm_norm <- normalize(mm_final, transform = "log2", convert = "cpm", filter = TRUE, norm = "quant")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm_final' not found
plot_pca(mm_norm)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm_norm' not found
mm_nb <- normalize(mm_final, transform = "log2", convert = "cpm", filter = TRUE, batch = "svaseq")
## Error in `h()`:
## ! error in evaluating the argument 'object' in selecting a method for function 'normalize': object 'mm_final' not found
plot_pca(mm_nb)
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_pca': object 'mm_nb' not found

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)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm_final' not found
genoloc_table_sva <- combine_de_tables(genoloc_de_sva, excel = "excel/genotype_location_tables.xlsx")
## Deleting the file excel/genotype_location_tables.xlsx before writing the tables.
## Error:
## ! object 'genoloc_de_sva' not found
genoloc_sig_sva <- extract_significant_genes(genoloc_table_sva, according_to = "deseq",
                                             excel = "excel/genotype_location_sig.xlsx")
## Deleting the file excel/genotype_location_sig.xlsx before writing the tables.
## Error:
## ! object 'genoloc_table_sva' not found
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)
## Error in `h()`:
## ! error in evaluating the argument 'x' in selecting a method for function 'colData': object 'mm_final' not found
location_table <- combine_de_tables(location_comparisons, excel = "excel/locations.xlsx")
## Deleting the file excel/locations.xlsx before writing the tables.
## Error:
## ! object 'location_comparisons' not found
location_sig <- extract_significant_genes(location_table, according_to = "deseq",
                                             excel = "excel/location_sig.xlsx")
## Deleting the file excel/location_sig.xlsx before writing the tables.
## Error:
## ! object 'location_table' not found

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")
LS0tCnRpdGxlOiAiaXBSR0MgYnVsayBSTkFzZXEgLS0gQWxsIFNhbXBsZXMgLS0gVGhpcyB0aW1lIHdpdGggZmVlbGluZyAodHJhbnNjcmlwdC1sZXZlbCBhYnVuZGFuY2VzKSEiCmF1dGhvcjogIlRoZXJlc2EgQWxleGFuZGVyLCBtb2RpZmllZCBieSBhdGIiCmRhdGU6ICI0LzE1LzIwMjMsIG1vZGlmaWVkIDIwMjYwMyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCiAgICAgIHRvY19kZXB0aDogNQotLS0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNnB4Cn0KPC9zdHlsZT4KCmBgYHtyIG9wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CiNsaWJyYXJ5KGhwZ2x0b29scykKbGlicmFyeShkcGx5cikKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShncHJvZmlsZXIyKQp0dCA8LSB0cnkoZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldCgKICBwcm9ncmVzcyA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFLCB3aWR0aCA9IDkwLCBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVycm9yID0gVFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDgsIGZpZy5yZXRpbmEgPSAyLAogIG91dC53aWR0aCA9ICIxMDAlIiwgZGV2ID0gInBuZyIsCiAgZGV2LmFyZ3MgPSBsaXN0KHBuZyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjQwOCIKcHJldmlvdXNfZmlsZSA8LSAiIgp2ZXIgPC0gZm9ybWF0KFN5cy5EYXRlKCksICIlWSVtJWQiKQoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCnJtZF9maWxlIDwtICIwNF9pcHJnY19idWxrX3RyYW5zY3JpcHRfYW5hbHlzZXMuUm1kIgpzYXZlZmlsZSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBybWRfZmlsZSkKIyMgTm8gb25lIHdpbGwgZXZlciByZWFkIHRoaXMgSSBzdXNwZWN0LCBidXQgdGhlcmUgd2lsbCBfbmV2ZXJfIGJlIGEgd29yZCBwcm9kdWNlZAojIyBieSBhbiBMTE0gaW4gYSBkb2N1bWVudCB3cml0dGVuIGJ5IG1lLgpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IGlzIGludGVuZGVkIHRvIHJlcGVhdCB3aXRoIG1pbmltYWwgbW9kaWZpY2F0aW9uIHRoZSB3b3JrCnBlcmZvcm1lZCBieSBUaGVyZXNhIHdoZW4gYW5hbHl6aW5nIHRoZSBSTkFTZXEgSVBSR0MgZGF0YS4gIFRoaXMgaXMKYmVpbmcgcGVyZm9ybWVkIGluIGFuIGFwcHRhaW5lciAodWdoIEkgaGF0ZSB0aGF0IG5hbWUpIGNvbnRhaW5lciBhbmQKc28gSSB3aWxsIGxpa2VseSByZW1vdmUgc29tZSBvZiB0aGUgbGlicmFyaWVzIGludm9rZWQgaW4gaXQuCgpOb3QgYWxsIG9mIHRoZXNlIGFyZSBhdmFpbGFibGUgaW4gdGhlIGNvbnRhaW5lciwgYW5kIEkgZG8gbm90IHRoaW5rIEkgaGF2ZSB0aGUgdmVyc2lvbgpvZiBUaGVyZXNhJ3MgaGVscGVyX2Z1bmN0aW9ucy5SIHdoaWNoIHdhcyB1c2VkIGZvciB0aGlzLiAgSSBkaWQgZmluZCBhCnZlcnNpb24gb2YgaXQgdGhhdCBhcHBlYXJzIHRvIHdvcmsgd2l0aG91dCBhbnkgcHJvYmxlbXMsIHRob3VnaC4KCkF0IHRoZSBlbmQgb2YgdGhpcyBkb2N1bWVudCwgSSBhbSBnb2luZyB0byB0cnkgdG8gcmUtaW1wbGVtZW50IGl0CndpdGggc29tZSBtaW5vciBjaGFuZ2VzIHRvIHNlZSBpZiBJIGNhbiBtb3JlIGVhc2lseSByZWNvbmNpbGUgdGhlCnJlc3VsdHMgdG8gdGhlIHRhYmxlcyBwcm92aWRlZCBieSBDb2xlbnNvLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoImhwZ2x0b29scyIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJwYXRjaHdvcmsiKQpsaWJyYXJ5KCJwbG90bHkiKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpsaWJyYXJ5KCJEVCIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgib3Blbnhsc3giKQpsaWJyYXJ5KCJDb21wbGV4SGVhdG1hcCIpCmxpYnJhcnkoImNpcmNsaXplIikKbGlicmFyeSgiZ3Byb2ZpbGVyMiIpCnNvdXJjZSgiL2RhdGEvaGVscGVyX2Z1bmN0aW9ucy5SIikKbGlicmFyeSgiZ3Bsb3RzIikKbGlicmFyeSgiZ2dyZXBlbCIpCmBgYAoKCmBgYHtyfQojc2V0d2QoIn4vc2NyYXRjaF8wMi9yZWVzeXhhbi9tbXVzY3VsdXNfaXByZ2NfMjAxOSIpCmBgYAoKIyBNLiBtdXNjdWx1cwoKIyMgQW5ub3RhdGlvbnMKCkkgYW0gdXNpbmcgbW0zOF8xMDAuCgpgYGB7cn0KbW1fYW5ub3QgPC0gbG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHNwZWNpZXMgPSAibW11c2N1bHVzIikKbW1fYW5ub3QgPC0gbW1fYW5ub3RbWyJhbm5vdGF0aW9uIl1dCm1tX2Fubm90W1sidHhpZCJdXSA8LSBwYXN0ZTAobW1fYW5ub3RbWyJlbnNlbWJsX3RyYW5zY3JpcHRfaWQiXV0sICIuIiwgbW1fYW5ub3RbWyJ2ZXJzaW9uIl1dKQpyb3duYW1lcyhtbV9hbm5vdCkgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSwgdW5pcXVlPVRSVUUpCgptbV90eF9hbm5vdCA8LSBtbV9hbm5vdFtbImFubm90YXRpb24iXV0KIyMgeWVhaCwgdGhlIElEIHRhZyBpbiBteSBnZmYgZmlsZSBoYXMgdHJhbnNjcmlwdDogYXMgYSBwcmVmaXgsIHNvIHRoZSBmZWF0dXJlQ291bnRzIG91dHB1dHMKIyMgaW5jbHVkZXMgaXQuLi4gIEkgd2lsbCBmaXggdGhhdCBpbnBvc3QuCnJvd25hbWVzKG1tX3R4X2Fubm90KSA8LSBwYXN0ZTAoInRyYW5zY3JpcHQ6Iiwgcm93bmFtZXMobW1fdHhfYW5ub3QpKQoKdHhfZ2VuZV9tYXAgPC0gbW1fYW5ub3RbLCBjKCJ0eGlkIiwgImVuc2VtYmxfZ2VuZV9pZCIpXQpgYGAKCgpTbywgSSBub3cgaGF2ZSBhIHRhYmxlIG9mIG1vdXNlIGFubm90YXRpb25zLgoKIyMgSGlzYXQyIGV4cHJlc3Npb25zZXQKCmBgYHtyfQptbTM4X2hpc2F0IDwtIGNyZWF0ZV9zZSgic2FtcGxlX3NoZWV0cy9zYW1wbGVzaGVldF9idWxrcm5hc2VxX09wbjQueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbyA9IG1tX3R4X2Fubm90LCBmaWxlX2NvbHVtbiA9ICJzYWxtb25fY291bnRfdGFibGUiKQpgYGAKCiMgQ29sb3IgU2V0IFVwCgpgYGB7cn0KY29sb3JfY29uZGl0aW9uIDwtIG1tMzhfaGlzYXQkaW5pdGlhbF9tZXRhZGF0YSRjb25kaXRpb24KY29sb3JfY29uZGl0aW9uIDwtIGZhY3Rvcihjb2xvcl9jb25kaXRpb24sIGxldmVscyA9IGMoIlJldGluYV9oZXQiLCAiUmV0aW5hX2tvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNDTl9oZXQiLCAiU0NOX2tvIiwgImRMR05faGV0IiwgImRMR05fa28iKSkKCmNvbG9yX3ZhbHVlcyA8LSBjKCAiIzAwQkZDNCIsICAiIzlBRDJEMyIsICIjRjg3NjZEIiwgIiNGQkFEQTciLCAiIzdDQUUwMCIsICIjRDNFRThGIikKY29sX2Z1biA9IGNvbG9yUmFtcDIoYygwLCAzLCA2KSwgYygiYmx1ZSIsICJwaW5rIiwgInJlZCIpKQpgYGAKCiMgTWFwcGVkIENvdW50cyBQZXIgU2FtcGxlIFBsb3QKCmBgYHtyfQpsaWJyYXJ5KGZvcmNhdHMpCm1tMzhfaGlzYXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9oaXNhdCwgZmFjdCA9ICJiYXRjaCIpCmxpYnNpemVfZGYgPC0gYXMuZGF0YS5mcmFtZShwbG90X2xpYnNpemUobW0zOF9oaXNhdCkkdGFibGUpCnJvd25hbWVzKGxpYnNpemVfZGYpIDwtIG1tMzhfaGlzYXQkZGVzaWduJHNhbXBsZWlkCmxpYnNpemVfZGYkc2FtcGxlbnVtIDwtIHBhc3RlMChtbTM4X2hpc2F0JGRlc2lnbltyb3duYW1lcyhsaWJzaXplX2RmKSwgInNhbXBsZW51bWIiXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW0zOF9oaXNhdCRkZXNpZ25bcm93bmFtZXMobGlic2l6ZV9kZiksICJiYXRjaCJdKQpsaWJzaXplX2RmJHNhbXBsZV9pZCA8LSAgcm93bmFtZXMobW0zOF9oaXNhdCRkZXNpZ24pCmxpYnNpemVfZGYgPC0gbGlic2l6ZV9kZltvcmRlcihsaWJzaXplX2RmJHN1bSksXQoKZ2dwbG90KGxpYnNpemVfZGYsIGFlcyh4ID0gZmN0X3JldihmY3RfaW5mcmVxKHNhbXBsZW51bSwgc3VtKSksIHkgPSBzdW0sIGZpbGwgPSBjb25kaXRpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgI3RoZW1lKGF4aXMudGV4dC54PSBlbGVtZW50X3RleHQoZmN0X3JldihmY3RfaW5mcmVxKGxpYnNpemVfZGYkc2FtcGxlbnVtLCBsaWJzaXplX2RmJHN1bSkpKSwgI3JlbW92ZSB4IGF4aXMgbGFiZWxzCiAgIyAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzYwNDQ5YiIsICIjMDA5ZjZmIiwgIm9yYW5nZSIpKSArCiAgeGxhYigiU2FtcGxlIikgKwogIHlsYWIoIlN1bSBvZiBNYXBwZWQgR2VuZSBDb3VudHMiKSArCiAgbGFicyhmaWxsID0gIiIpCgpwbG90X2xpYnNpemUobW0zOF9oaXNhdCkKYGBgCgojIE5vcm1hbGl6ZSBFeHByZXNzaW9uCgpGaXJzdCB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGdlbmVzIHdoaWNoIGhhdmUgbG93IGNvdW50cyBhY3Jvc3MgYWxsCnNhbXBsZXMuIFRoZW4gSSB3aWxsIG5vcm1hbGl6ZSBib3RoIHdpdGhvdXQgYW5kIHdpdGggU1ZBIGNvcnJlY3Rpb24uCgpgYGB7cn0KbW0zOF9maWx0IDwtIG5vcm1hbGl6ZShtbTM4X2hpc2F0LCBmaWx0ZXIgPSBUUlVFKQpkZXMgPC0gY29sRGF0YShtbTM4X2ZpbHQpCm5ld19mYWN0b3IgPC0gcGFzdGUwKGRlc1tbImxvY2F0aW9uIl1dLCAiXyIsIGRlc1tbImdlbm90eXBlIl1dKQpjb2xEYXRhKG1tMzhfaGlzYXQpW1sibG9jYXRpb25fZ2Vub3R5cGUiXV0gPC0gbmV3X2ZhY3RvcgoKbW0zOF9ub3JtIDwtIG5vcm1hbGl6ZShtbTM4X2hpc2F0LCBmaWx0ZXIgPSBUUlVFLCBjb252ZXJ0ID0gImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgbm9ybSA9ICJxdWFudCIsIHRyYW5zZm9ybT0ibG9nMiIpCgptbTM4X25vcm0gPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9ub3JtLCBmYWN0ID0gImxvY2F0aW9uX2dlbm90eXBlIikKYGBgCgojIE1lbGFub3BzaW4gRXhwcmVzc2lvbgoKSGVyZSBpcyBhIHBsb3Qgb2YgdGhlIE9wbjQgZXhwcmVzc2lvbiBhY3Jvc3MgYWxsIHJldGluYSBzYW1wbGVzIHNwbGl0CmJ5IGJhdGNoLiBUaGUgNCBxdWFkcmFudHMgaW4gdGhlIHBsb3QgYXJlIDxicj4KCmhldDoxIC0tIHJldGluYSBoZXQgc2FtcGxlcyBpbiBiYXRjaCAxIDxicj4KaGV0OjIgLS0gcmV0aW5hIGhldCBzYW1wbGVzIGluIGJhdGNoIDIgPGJyPgprbzoxIC0tIHJldGluYSBrbyBzYW1wbGVzIGluIGJhdGNoIDEgPGJyPgprbzoyIC0tIHJldGluYSBrbyBzYW1wbGVzIGluIGJhdGNoIDIgPGJyPgoKVGhpcyBpcyBhIFR4IGNvbXBhcmlzb247IEkgbmVlZCB0byBlaXRoZXIgZHJvcCB0aGlzIG9yIGh1bnQgZG93biB0aGUgc2V0IG9mCnRyYW5zY3JpcHQgSURzICh3aGljaCBJIGRpZCkKCmBgYHtyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKY29sb3JzIDwtIGJyZXdlci5wYWwobmFtZSA9ICJTcGVjdHJhbCIsIG4gPSAyKQptbTM4X2NwbSA8LSBub3JtYWxpemUobW0zOF9maWx0LCBjb252ZXJ0ID0gImNwbSIpCmRmIDwtIGRhdGEuZnJhbWUoZXhwcnMgPSBhc3NheShtbTM4X2NwbSlbIkVOU01VU0cwMDAwMDAyMTc5OSIsXSwKICAgICAgICAgICAgICAgICBnZW5vdHlwZSA9IGFzLmZhY3RvcihkZXNbWyJnZW5vdHlwZSJdXSksCiAgICAgICAgICAgICAgICAgbG9jYXRpb24gPSBhcy5mYWN0b3IoZGVzW1sibG9jYXRpb24iXV0pLAogICAgICAgICAgICAgICAgIHNhbXBsZWlkID0gZGVzW1sic2FtcGxlaWQiXV0sCiAgICAgICAgICAgICAgICAgc2FtcGxlbnVtID0gZGVzW1sic2FtcGxlbnVtYiJdXSwKICAgICAgICAgICAgICAgICBiYXRjaCA9IGRlc1tbImJhdGNoIl1dKQoKIyMgU2V0IHBvc3RzY3JpcHQgYXJndW1lbnRzCnNldEVQUygpCnBvc3RzY3JpcHQoImJ1bGtSTkFzZXFfT3BuNEV4cHJlc3Npb25fUmV0aW5hLmVwcyIpCmNwbV9kZiA8LSBkZiB8PgogIGZpbHRlcihsb2NhdGlvbiA9PSAiUmV0aW5hIiB8IGxvY2F0aW9uID09ICJyZXRpbmEiKQoKIyMgVGhpcyBpcyB3aGVyZSBJIG1vc3QgbWlzcyBnZ3N0YXRzcGxvdAojIyBJIGFtIGdvaW5nIHRvIHNpdCBhbmQgd3JpdGUgbXkgb3duIHZlcnNpb24gb2YgaXQuCmdncGxvdChjcG1fZGYsIGFlcyh4ID0gc2FtcGxlbnVtLCB5ID0gZXhwcnMsIGZpbGwgPSBnZW5vdHlwZSwgZ3JvdXAgPSBnZW5vdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsKICB4bGFiKCJTYW1wbGUiKSArCiAgeWxhYigiT3BuNCBDb3VudHMgUGVyIE1pbGxpb24gKENQTXMpIikgKwogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRkZDMTA3IiwgIiMwMDRENDAiLCAib3JhbmdlIiksCiAgIyAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIpICsKICBnZ3RpdGxlKCJSZXRpbmEgTWVsYW5vcHNpbiBFeHByZXNzaW9uIikgKwogIGZhY2V0X3dyYXAofmdlbm90eXBlOmJhdGNoLCBzY2FsZXMgPSAiZnJlZSIpICsKICB5bGltKGMoMCwgMjUpKSArCiAgdGhlbWVfY2xhc3NpYygpCmRldi5vZmYoKQpgYGAKClRoZSBXVCBzYW1wbGVzIGluIGJhdGNoIDMgaGF2ZSBhYm91dCBkb3VibGUgdGhlIE9wbjQgZXhwcmVzc2lvbiBhcyB0aGUKaGV0IHNhbXBsZXMgaW4gYmF0Y2ggMyAoYW5kIGJhdGNoIDIpLgoKIyBQQ0EKCmBgYHtyIHBjYSwgbWVzc2FnZSA9IEZBTFNFfQpwY2Ffbm9ybSA8LSBwbG90X3BjYShtbTM4X25vcm0sIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBjYV9ub3JtW1sicGxvdCJdXQojIyByb3duYW1lcyhwY2Ffbm9ybSRyZXN1bHQkdikKbGFiZWxzIDwtIGRlc1tbInNhbXBsZWlkIl1dCiMjIGxhYmVscyA8LSBwYXN0ZTAobW0zOF9ub3JtJGRlc2lnbiRzYW1wbGVpZCwgIl8iLCBtbTM4X25vcm0kZGVzaWduJHNhbXBsZW51bWIpCmFsbF9kZiA8LSAgY2JpbmQoYXMuZGF0YS5mcmFtZShwY2Ffbm9ybSRyZXN1bHQkdiksIGxhYmVscykKCnNoYXBlX2dlbm90eXBlIDwtIG1tMzhfbm9ybSRkZXNpZ24kZ2Vub3R5cGUKY29sb3JfY29uZGl0aW9uIDwtIG1tMzhfbm9ybSRjb25kaXRpb24KCiMjIGZpbHRlcihzYW1wbGVfaWQgJWluJSBjKCJTM19IZXRfUmV0X1MxIiwgIlM0X0hldF9SZXRfUzQiLCAiUzVfSGV0X1JldF9TMTYiLCAiUzFfSGV0X1JldF9TMSIsICJTMl9IZXRfUmV0X1M0IiwgIlMzX0hldF9SZXRfUzciLCAiUzRfSGV0X1JldF9TMTAiLCAiUzVfSGV0X1JldF9TMTMiKSkgfD4KCnBjYV9ub3JtX3Bsb3QgPC0gIGdncGxvdChhbGxfZGYsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbG9yX2NvbmRpdGlvbiwgc2hhcGUgPSBzaGFwZV9nZW5vdHlwZSksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzLAogICMgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIE5vIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX25vcm0kcHJvcF92YXJbMV0sICIlIHZhcmlhbmNlIiksCiAgICAgICB5ID0gIHBhc3RlMCgiUEMyOiAiLCAgcGNhX25vcm0kcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpCgojc2V0RVBTKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNldCBwb3N0c2NyaXB0IGFyZ3VtZW50cwojcG9zdHNjcmlwdCgiYnVsa1JOQXNlcV9QQ0FfYWxsc2FtcGxlc19sYWJlbGVkUzUuZXBzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFN0YXJ0IGdyYXBoaWNzIGRldmljZSBkcml2ZXIKYWxsX2RmW1sibGFiZWxzIl1dIDwtIHJvd25hbWVzKGFsbF9kZikKcGNhX25vcm1fcGxvdCArIGdndGl0bGUoIlBDQSBOb3JtYWxpemVkIENvdW50cyIpICsKZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihhbGxfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzICVpbiUgbGFiZWxzKSwgI2MoJ3M1X2hldF9kbGduJywgJ3M1X2hldF9yZXQnLCAnczVfaGV0X3NjbicpKSwKICAgIG51ZGdlX3ggPSAwLjE1LAogICAgbnVkZ2VfeSA9IDAuMTUpCiNkZXYub2ZmKCkKYGBgCgojIyBMb29rIGF0IHRoZSBmaXJzdCBiYXRjaCBvZiBzZXF1ZW5jaW5nCgpgYGB7cn0KI2JhdGNoIDEgcGxvdAphbGxfZGZbcm93bmFtZXMoYWxsX2RmKSAlaW4lIHRvbG93ZXIocm93bmFtZXMoZGVzW2Rlc1tbImJhdGNoIl1dID09ICIxIixdKSksXSB8PgogIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbG9yX2NvbmRpdGlvblt3aGljaChyb3duYW1lcyhhbGxfZGYpICVpbiUgdG9sb3dlcihyb3duYW1lcyhkZXNbZGVzJGJhdGNoID09ICIxIixdKSkpXSwKICAgICAgICAgICAgICAgICBzaGFwZSA9IHNoYXBlX2dlbm90eXBlW3doaWNoKHJvd25hbWVzKGFsbF9kZikgJWluJSB0b2xvd2VyKHJvd25hbWVzKGRlc1tkZXMkYmF0Y2ggPT0gIjEiLF0pKSldKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiLCBzaGFwZSA9ICJHZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSAtIEJhdGNoIDEgUk5Bc2VxIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9ub3JtJHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9ub3JtJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKQpgYGAKCkkgdGhpbmsgdGhlcmUgaXMgYW4gZWFzaWVyIHdheSB0byBkbyB0aGUgYWJvdmUKCmBgYHtyfQpiMSA8LSBzdWJzZXRfc2UobW0zOF9ub3JtLCBzdWJzZXQgPSAiYmF0Y2ggPT0gJzEnIikKcGxvdF9wY2EoYjEpCgpiMV9iMiA8LSBzdWJzZXRfc2UobW0zOF9ub3JtLCBzdWJzZXQgPSAiYmF0Y2ggPT0gJzEnfGJhdGNoID09ICcyJyIpCnBsb3RfcGNhKGIxX2IyKQpgYGAKCmBgYHtyfQojYmF0Y2ggMSYyIHBsb3QKcGNhX2JhdGNoMWFuZDIgPC0gYWxsX2RmIHw+CiAgZ2dwbG90KGFlcyh4ID0gUEMxLCB5ID0gUEMyKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29sb3JfY29uZGl0aW9uLAogICAgICAgICAgICAgICAgIHNoYXBlID0gc2hhcGVfZ2Vub3R5cGUpLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIsIHNoYXBlID0gIkdlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIC0gQmF0Y2ggMSYyIFJOQXNlcSIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2Ffbm9ybSRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2Ffbm9ybSRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkKCgojc2V0RVBTKCkKI3Bvc3RzY3JpcHQoZmlsZSA9ICJybmFzZXFfcGNhLWJhdGNoMWFuZDIuZXBzIikKI3BjYV9iYXRjaDFhbmQyCiNkZXYub2ZmKCkKYGBgCgpJbiB0aGlzIHBjYSBwbG90LCB3ZSBzZWUgdGhlIHJldGluYSBzYW1wbGVzIGNsdXN0ZXIgb24gdGhlIHJpZ2h0IGluCnRoZSBQQzEgZGlyZWN0aW9uIGFuZCB0aGUgYnJhaW4gc2FtcGxlcyBjbHVzdGVyIG9uIHRoZSBsZWZ0IGluIHRoZSBQQwoxIGRpcmVjdGlvbi4KCkFzIHdlIHNhdyBiZWZvcmUsIHRoZXJlIGlzIGRpc3Bhcml0eSBiZXR3ZWVuIHNvbWUgb2YgdGhlIGhldHMuIEFzIGl0CnR1cm5zIG91dCwgYWxsIG9mIHRoZSBuZXcgSGV0IHNhbXBsZXMgY2x1c3RlciB3aXRoIHRoZSBLTyBzYW1wbGVzIGFzCm91ciBvbmUgd2VpcmRvIGRpZCBiZWZvcmUuIFNvIG5vdyBpdCBzZWVtcyB0aGF0IGl0IGlzIHF1aXRlIGVhc3kgdG8KZ2V0IHNvbWUgZ2VuZXRpYyBkcmlmdCB0aGF0IGxlYWRzIHRvIHRoZXNlIG1pY2UncyBleHByZXNzaW9uIHRvIGJlaGF2ZQppbiB3ZWlyZCB3YXlzLgoKQXMgd2UgZGlkIGJlZm9yZSwgbGV0J3MgbG9vayBhdCB0aGUgT3BuNCBleHByZXNzaW9uIGFjcm9zcyBhbGwgdGhlCnJldGluYSBzYW1wbGVzIHRvIHNlZSBpZiB0aGUgSGV0IHNhbXBsZXMgdGhhdCBiZWhhdmUgbGlrZSBLT3MgaGF2ZQpsb3dlciBPcG40IGV4cHJlc3Npb24uCgojIEEgY2xvc2VyIGxvb2sgYXQgdGhlIHNpbWlsYXIgS09zIGFuZCBIZXRzCgpMZXQncyBleGNsdWRlIHRoZSAyIEhldHMgdGhhdCBhcmUgdGhlIG1vc3QgZGlzc2ltaWxhciBmcm9tIHRoZSBidW5jaAphbmQgbG9vayBhdCBhIFBDQSBwbG90IG9mIHRoZSByZXN0IG9mIHRoZSBzYW1wbGVzLgoKYGBge3J9CiMjIFRoZSBmb2xsb3dpbmcgc3Vic2V0IGlzIHVzaW5nIGFuIG9sZGVyIHNhbXBsZSBJRCB3aGljaCBJIGFtIHVuYWJsZSB0byBmaW5kIGFueXdoZXJlLgojIyBBcyBhIHJlc3VsdCwgSSByZXdyb3RlIHRoYXQgcG9ydGlvbiBvZiBUaGVyZXNhJ3MgcGNhIHBsb3QgYW5kIGxhYmVsZWQgZXZlcnl0aGluZwojIyBhY2NvcmRpbmcgdG8gdGhlIGV4dGFudCBuYW1pbmcgc2NoZW1lLCBJIHdpbGwgbm93IHRyeSBhbmQgZmlndXJlIG91dCB3aGljaAojIyBzYW1wbGVzIHdlcmUgcmVtb3ZlZC4KIyMgbW0zOF9zdWJzZXQgPC0gc3Vic2V0X3NlKAojIyAgIG1tMzhfZmlsdCwKIyMgc3Vic2V0ID0gInNhbXBsZWlkICE9ICdTM19IZXRfZExHTicmc2FtcGxlaWQgIT0gJ1MzX0hldF9SZXQnJnNhbXBsZWlkICE9ICdTM19IZXRfU0NOJyZzYW1wbGVpZCAhPSAnUzRfSGV0X2RMR04nJnNhbXBsZWlkICE9ICdTNF9IZXRfUmV0JyZzYW1wbGVpZCAhPSAnUzRfSGV0X1NDTiciKQojIyBTM19IZXRfZExHTl9TMiBpcyBhbiBvdXRsaWVyIG1hcmtlZCBieSBUaGVyZXNhCiMjIFMzX0hldF9SZXRfUzEgaXMgYW4gb3V0bGllcgojIyBTM19IZXRfU0NOX1MzIGlzIGFuIG91dGxpZXIKIyMgUzRfSGV0X2RMR05fUzExIGlzIHNvbWV3aGF0IGFuIG91dGxpZXIsIEkgbWlnaHQgYmUgaW5jbGluZWQgdG8gbGVhdmUgaXQuCiMjIFM0X0hldF9SZXRfUzQgaXMgYSBodWdlIG91dGxpZXIKIyMgUzRfSGV0X1NDTl9TNiBpcyBhbiBvdXRsaWVyCgojIyBJZiBJIHdlcmUgY2hvb3NpbmcgbGlrZWx5IHNhbXBsZXMsIEkgdGhpbmsgSSB3b3VsZCBnbyBmb3I6CiMjUzRfSGV0X1JldF9TNCwgUzNfSGV0X1JldF9TMSwgUzNfSGV0X1NDTl9zMywgUzNfSGV0X2RMR05fUzIsIFM0X0hldF9kTEdOX1M1LCBTNF9IZXRfU0NOX1M2CgojIyBFaXRoZXIgd2F5LCBJIGFtIGFkZGluZyBhIGNvdXBsZSBjb2x1bW5zIHRvIHRoZSBzYW1wbGUgc2hlZXQgd2l0aCB0aGVzZSBjYWxscyBmb3IgaW5jbHVkZWQgc2FtcGxlcy4KCm1tMzhfc3Vic2V0IDwtIHN1YnNldF9zZShtbTM4X2ZpbHQsIHN1YnNldCA9ICJpbmNsdWRlZD09J3llcyciKQoKbW0zOF9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfc3Vic2V0LCBmaWx0ZXI9VFJVRSwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm0gPSAicXVhbnQiLCB0cmFuc2Zvcm09ImxvZzIiKQoKbW0zOF9zdWJzZXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9zdWJzZXQsIGZhY3QgPSAibG9jYXRpb25fdGltZSIpCgpwY2Ffbm9ybV9zdWJzZXQgPC0gcGxvdF9wY2EobW0zOF9zdWJzZXQsIHBsb3RfbGFiZWxzID0gRkFMU0UpCnBjYV9ub3JtX3N1YnNldAoKbGFiZWxzIDwtIHJvd25hbWVzKHBjYV9ub3JtX3N1YnNldCRyZXN1bHQkdikKCmFsbF9kZiA8LSAgY2JpbmQoYXMuZGF0YS5mcmFtZShwY2Ffbm9ybV9zdWJzZXQkcmVzdWx0JHYpLCBsYWJlbHMpCnNoYXBlX2dlbm90eXBlIDwtIG1tMzhfc3Vic2V0JGRlc2lnbiRnZW5vdHlwZQpjb2xvcl9jb25kaXRpb24gPC0gcGNhX25vcm1fc3Vic2V0JHRhYmxlJGNvbmRpdGlvbgoKcGNhX25vcm1fcGxvdCA8LSAgZ2dwbG90KHBjYV9ub3JtX3N1YnNldCR0YWJsZSwgYWVzKHggPSBQQzEsIHkgPSBQQzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb25kaXRpb24pLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIE5vIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX25vcm1fc3Vic2V0JHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9ub3JtX3N1YnNldCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkKCnBjYV9ub3JtX3Bsb3QgPC0gIGdncGxvdChhbGxfZGYsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbG9yX2NvbmRpdGlvbiwgc2hhcGUgPSBzaGFwZV9nZW5vdHlwZSksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzLAogICMgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIE5vIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX25vcm1fc3Vic2V0JHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9ub3JtX3N1YnNldCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkKCiNzZXRFUFMoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2V0IHBvc3RzY3JpcHQgYXJndW1lbnRzCiNwb3N0c2NyaXB0KCJidWxrUk5Bc2VxX1BDQV9hbGxzYW1wbGVzX2xhYmVsZWRTNS5lcHMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU3RhcnQgZ3JhcGhpY3MgZGV2aWNlIGRyaXZlcgpwY2Ffbm9ybV9wbG90ICsgZ2d0aXRsZSgiUENBIE5vcm1hbGl6ZWQgQ291bnRzIC0tIFN1YnNldCIpICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKGFsbF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGMoJ3M0X2hldF9zY25fczEyJywgJ3M0X2hldF9yZXQnLCAnczRfaGV0X3NjbicsICdzNV9oZXRfZGxnbicpKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLjE1LAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMSkKCnBjYV9ub3JtX3Bsb3QgKyBnZ3RpdGxlKCJQQ0EgTm9ybWFsaXplZCBDb3VudHMiKSMgKwoKcGNhX25vcm1fcGxvdAojIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIoYWxsX2RmLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGxhYmVscyksICNjKCdzNF9oZXRfc2NuJywgJ3M1X2hldF9yZXQnLCAnczVfaGV0X3NjbicsICdzNV9oZXRfZGxnbicpKSwKIyAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4xNSwKIyAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4xNSkKI2Rldi5vZmYoKQpgYGAKClRoZXJlIHJlYWxseSBkb2Vzbid0IHNlZW0gdG8gYmUgYSBkaXNjZXJuaWJsZSBkaWZmZXJlbmNlIGdsb2JhbGx5CmJldHdlZW4gdGhlIGhldHMgYW5kIGtvcyB3aXRoaW4gZWFjaCBsb2NhdGlvbi4gV2UgY2FuIGRvIGEgREUgd2l0aAp0aGVzZSBzYW1wbGVzIGJldHdlZW4gaGV0L2tvcyB0byBxdWFudGlmeSB0aGlzLgoKCiMgREUgb2YgS09zIHZlcnN1cyBMb3cgZXhwcmVzc29yIEhldHMKCmBgYHtyfQptbTM4X2ZpbHRfc3ViIDwtIHN1YnNldF9zZShtbTM4X2ZpbHQsIHN1YnNldCA9ICJzYW1wbGVpZCAhPSAnUzNfSGV0X2RMR04nJnNhbXBsZWlkICE9ICdTM19IZXRfUmV0JyZzYW1wbGVpZCAhPSAnUzNfSGV0X1NDTicmc2FtcGxlaWQgIT0gJ1M0X0hldF9kTEdOJyAmIHNhbXBsZWlkICE9ICdTNF9IZXRfUmV0JyAmIHNhbXBsZWlkICE9ICdTNF9IZXRfU0NOJyIpCgptbTM4X2RsZ25fc3Vic2V0IDwtIHN1YnNldF9zZShtbTM4X2ZpbHRfc3ViLCBzdWJzZXQgPSAibG9jYXRpb25fdGltZSA9PSAnZExHTl9oZXQnIHwgbG9jYXRpb25fdGltZSA9PSAnZExHTl9rbyciKQptbTM4X3JldF9zdWJzZXQgPC0gc3Vic2V0X3NlKG1tMzhfZmlsdF9zdWIsIHN1YnNldCA9ICJsb2NhdGlvbl90aW1lID09ICdSZXRpbmFfaGV0JyB8IGxvY2F0aW9uX3RpbWUgPT0gJ1JldGluYV9rbyciKQptbTM4X3Njbl9zdWJzZXQgPC0gc3Vic2V0X3NlKG1tMzhfZmlsdF9zdWIsIHN1YnNldCA9ICJsb2NhdGlvbl90aW1lID09ICdTQ05faGV0JyB8IGxvY2F0aW9uX3RpbWUgPT0gJ1NDTl9rbyciKQoKbW0zOF9kbGduX3N1YnNldCA8LSBub3JtYWxpemUobW0zOF9kbGduX3N1YnNldCwgZmlsdGVyID0gVFJVRSkKbW0zOF9zY25fc3Vic2V0IDwtIG5vcm1hbGl6ZShtbTM4X3Njbl9zdWJzZXQsIGZpbHRlciA9IFRSVUUpCm1tMzhfcmV0X3N1YnNldCA8LSBub3JtYWxpemUobW0zOF9yZXRfc3Vic2V0LCBmaWx0ZXIgPSBUUlVFKQoKbW0zOF9kbGduX3N1YnNldCA8LSBzZXRfYmF0Y2hlcyhtbTM4X2RsZ25fc3Vic2V0LCBmYWN0ID0gImNvbmRpdGlvbiIpCm1tMzhfc2NuX3N1YnNldCA8LSBzZXRfYmF0Y2hlcyhtbTM4X3Njbl9zdWJzZXQsIGZhY3QgPSAiY29uZGl0aW9uIikKbW0zOF9yZXRfc3Vic2V0IDwtIHNldF9iYXRjaGVzKG1tMzhfcmV0X3N1YnNldCwgZmFjdCA9ICJjb25kaXRpb24iKQoKbW0zOF9kbGduX3N1YnNldCA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2RsZ25fc3Vic2V0LCBmYWN0ID0gImxvY2F0aW9uX3RpbWUiKQptbTM4X3Njbl9zdWJzZXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9zY25fc3Vic2V0LCBmYWN0ID0gImxvY2F0aW9uX3RpbWUiKQptbTM4X3JldF9zdWJzZXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9yZXRfc3Vic2V0LCBmYWN0ID0gImxvY2F0aW9uX3RpbWUiKQpgYGAKCmBgYHtyfQp0ZXN0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfZmlsdCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikgfD4Kbm9ybWFsaXplKHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLCBiYXRjaCA9ICJzdmEiKQpwbG90X3BjYSh0ZXN0KQpgYGAKCkkgZG8gbm90IHRoaW5rIG9uZSBzaG91bGQgcmVhbGx5IGRvIHRoZSBERSB3aXRoIHRoZSBkYXRhIHNlcGFyYXRlIGxpa2UKdGhpcyB1bmxlc3MgdGhlcmUgaXMgc29tZSBjb21wZWxsaW5nIHJlYXNvbi4gIEkgYW0gZ29pbmcgdG8gcmVwZWF0CndpdGhvdXQgdGhpcyBjb25zdHJhaW50IGFuZCBzZWUgaG93IHNpbWlsYXIvZGlmZmVyZW50IHRoZSByZXN1bHRzIGFyZS4KSW4gYWRkaXRpb24sIHRoZSBjdXJyZW50IHJldmlzaW9uIG9mIGFsbF9wYWlyd2lzZSgpIGlzIG11Y2ggbW9yZQpjb21mb3J0YWJsZSB3aXRoIG1vcmUgY29tcGxleCBtb2RlbHMsIGV2ZW4gd2l0aCBzdmE7IHNvIHRoYXQgbWlnaHQKbWFrZSB0aGlzIG1vcmUgZnVuLgoKYGBge3J9Cm1tX2RlX2RsZ24gPC0gYWxsX3BhaXJ3aXNlKG1tMzhfZGxnbl9zdWJzZXQsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCm1tX2RlX2RsZ24KbW1fdGFibGVfZGxnbiA8LSBjb21iaW5lX2RlX3RhYmxlcyhtbV9kZV9kbGduLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjM5YnVsa190YWJsZXNfdHgvbW1fZGVfZGxnbl90YWJsZS54bHN4IikKbW1fc2lnX2RsZ24gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhtbV90YWJsZV9kbGduLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjM5YnVsa190YWJsZXNfdHgvbW1fZGVfZGxnbl9zaWcueGxzeCIpCgptbV9kZV9yZXQgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfcmV0X3N1YnNldCwgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9yZXQKbW1fdGFibGVfcmV0IDwtIGNvbWJpbmVfZGVfdGFibGVzKG1tX2RlX3JldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjM5YnVsa190YWJsZXNfdHgvbW1fZGVfcmV0X3RhYmxlLnhsc3giKQptbV9zaWdfcmV0IDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobW1fdGFibGVfcmV0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjM5YnVsa190YWJsZXNfdHgvbW1fZGVfcmV0X3NpZy54bHN4IikKCm1tX2RlX3NjbiA8LSBhbGxfcGFpcndpc2UobW0zOF9zY25fc3Vic2V0LCBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gInN2YXNlcSIsIGZpbHRlciA9IFRSVUUpCm1tX2RlX3NjbgptbV90YWJsZV9zY24gPC0gY29tYmluZV9kZV90YWJsZXMobW1fZGVfc2NuLCBleGNlbCA9ICIzOWJ1bGtfdGFibGVzX3R4L21tX2RlX3Njbl90YWJsZS54bHN4IikKbW1fc2lnX3NjbiA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKG1tX3RhYmxlX3NjbiwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjM5YnVsa190YWJsZXNfdHgvbW1fZGVfc2NuX3NpZy54bHN4IikKYGBgCgojIyBTQ04KCmBgYHtyfQprZWVwZXJzIDwtIG5hbWVzKG1tX2RlX3NjbiRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfc2NuIDwtIGMoKQpmb3IgKHRibCBpbiBrZWVwZXJzKSB7CiAgZGVzZXFfdGJsIDwtIGdldF9kZV90YWJsZShtbV9kZV9zY24sIHRhYmxlID0gdGJsKQogIHJlc190YmxzX3NjbltbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICBmY3RyIDwtIGMocGFzdGUoZ3N1YigiXFxfLioiLCIiLHRibCksICJcbkVucmljaGVkIiksCiAgICAgICAgICAgIHBhc3RlKHN1YignLipcXF8nLCAnJywgdGJsKSwgIlxuRW5yaWNoZWQiKSkKICByZXNfdGJsc19zY25bW3RibF1dIDwtIHNldF9zaWdfbGltbWEocmVzX3RibHNfc2NuW1t0YmxdXSwgZmFjdG9ycyA9IGZjdHIpCiAgcmVzX3RibHNfc2NuW1twYXN0ZTAodGJsLCAidm9sY19wbG90bHkiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19zY25bW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9uYW1lX2NvbCA9ICJ1bmlwcm90X2duX3N5bWJvbCIpCiAgcmVzX3RibHNfc2NuW1twYXN0ZTAodGJsLCAidm9sY19nZ3Bsb3QiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19zY25bW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiKQp9CgpyZXNfdGJsc19zY24kU0NOa29fdnNfU0NOaGV0dm9sY19nZ3Bsb3QKcmVzX3RibHNfc2NuJFNDTmtvX3ZzX1NDTmhldHZvbGNfcGxvdGx5CnJlc190YmxzX3NjbiRTQ05rb192c19TQ05oZXQgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUpIHw+CiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMSkgfD4KICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJ1bmlwcm90X2duX3N5bWJvbCIsICJTaWduaWZpY2FuY2UiLCAiZGVzY3JpcHRpb24iLCAiYmFzZU1lYW4iLCAibG9nRkMiLCAiYWRqLlAuVmFsIikgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgojIyBkTEdOCgpgYGB7cn0Ka2VlcGVycyA8LSBuYW1lcyhtbV9kZV9kbGduJGRlc2VxJGFsbF90YWJsZXMpCgpyZXNfdGJsc19kbGduIDwtIGMoKQpmb3IgKHRibCBpbiBrZWVwZXJzKSB7CiAgZGVzZXFfdGJsIDwtIGdldF9kZV90YWJsZShtbV9kZV9kbGduLCB0YWJsZSA9IHRibCkKICByZXNfdGJsc19kbGduW1t0YmxdXSA8LSBtZXJnZShkZXNlcV90YmwsIGhpc2F0X2Fubm90LCBieSA9ICJyb3cubmFtZXMiKQogIHJlc190YmxzX2RsZ25bW3RibF1dIDwtIHNldF9zaWdfbGltbWEocmVzX3RibHNfZGxnbltbdGJsXV0sIGZhY3RvcnMgPSBjKHBhc3RlKGdzdWIoIlxcXy4qIiwiIix0YmwpLCAiXG5FbnJpY2hlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHN1YignLipcXF8nLCAnJywgdGJsKSwgIlxuRW5yaWNoZWQiKSkpCiAgcmVzX3RibHNfZGxnbltbcGFzdGUwKHRibCwgInZvbGNfcGxvdGx5IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfZGxnbltbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwbG90bHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9uYW1lX2NvbCA9ICJ1bmlwcm90X2duX3N5bWJvbCIpCiAgcmVzX3RibHNfZGxnbltbcGFzdGUwKHRibCwgInZvbGNfZ2dwbG90IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfZGxnbltbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIikKfQoKcmVzX3RibHNfZGxnbiRkTEdOa29fdnNfZExHTmhldHZvbGNfZ2dwbG90CnJlc190YmxzX2RsZ24kZExHTmtvX3ZzX2RMR05oZXR2b2xjX3Bsb3RseQpyZXNfdGJsc19kbGduJGRMR05rb192c19kTEdOaGV0IHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSB8PgogIGZpbHRlcihhYnMobG9nRkMpID49IDEpIHw+CiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAidW5pcHJvdF9nbl9zeW1ib2wiLCAiU2lnbmlmaWNhbmNlIiwgImRlc2NyaXB0aW9uIiwgImJhc2VNZWFuIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIpIHw+CiAgYXJyYW5nZShsb2dGQykgfD4KICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKCiMjIFJldGluYQoKYGBge3J9CmtlZXBlcnMgPC0gbmFtZXMobW1fZGVfcmV0JGRlc2VxJGFsbF90YWJsZXMpCgpyZXNfdGJsc19yZXQgPC0gYygpCmZvciAodGJsIGluIGtlZXBlcnMpIHsKICBkZXNlcV90YmwgPC0gZ2V0X2RlX3RhYmxlKG1tX2RlX3JldCwgdGFibGUgPSB0YmwpCiAgcmVzX3RibHNfcmV0W1t0YmxdXSA8LSBtZXJnZShkZXNlcV90YmwsIGhpc2F0X2Fubm90LCBieSA9ICJyb3cubmFtZXMiKQogIHJlc190YmxzX3JldFtbdGJsXV0gPC0gc2V0X3NpZ19saW1tYShyZXNfdGJsc19yZXRbW3RibF1dLCBmYWN0b3JzID0gYyhwYXN0ZShnc3ViKCJcXF8uKiIsIiIsdGJsKSwgIlxuRW5yaWNoZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoc3ViKCcuKlxcXycsICcnLCB0YmwpLCAiXG5FbnJpY2hlZCIpKSkKICByZXNfdGJsc19yZXRbW3Bhc3RlMCh0YmwsICJ2b2xjX3Bsb3RseSIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3JldFtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicGxvdGx5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX25hbWVfY29sID0gInVuaXByb3RfZ25fc3ltYm9sIikKICByZXNfdGJsc19yZXRbW3Bhc3RlMCh0YmwsICJ2b2xjX2dncGxvdCIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3JldFtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJWb2xjYW5vIFBsb3Q6IiwgdGJsKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIpCn0KCnJlc190YmxzX3JldCRSZXRpbmFrb192c19SZXRpbmFoZXR2b2xjX2dncGxvdApyZXNfdGJsc19yZXQkUmV0aW5ha29fdnNfUmV0aW5haGV0dm9sY19wbG90bHkKcmVzX3RibHNfcmV0JFJldGluYWtvX3ZzX1JldGluYWhldCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAxKSB8PgogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgInVuaXByb3RfZ25fc3ltYm9sIiwgIlNpZ25pZmljYW5jZSIsICJkZXNjcmlwdGlvbiIsICJiYXNlTWVhbiIsICJsb2dGQyIsICJhZGouUC5WYWwiKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCiMgREUgb2YgYWxsIHNhbXBsZXMgd2l0aCBTVkEgYmF0Y2ggY29ycmVjdGlvbiBmb3IgaGlnaCB2IGxvdyBleHByZXNzb3JzCgpgYGB7cn0KbW0zOF9kbGduX3N1YnNldCA8LSBzdWJzZXRfc2UoCiAgbW0zOF9maWx0LCBzdWJzZXQgPSAibG9jYXRpb25fdGltZSA9PSAnZExHTl9oZXQnfCBsb2NhdGlvbl90aW1lID09ICdkTEdOX2tvJyIpCm1tMzhfcmV0X3N1YnNldCA8LSBzdWJzZXRfc2UoCiAgbW0zOF9maWx0LCBzdWJzZXQgPSAibG9jYXRpb25fdGltZSA9PSAnUmV0aW5hX2hldCd8IGxvY2F0aW9uX3RpbWUgPT0gJ1JldGluYV9rbyciKQptbTM4X3Njbl9zdWJzZXQgPC0gc3Vic2V0X3NlKAogIG1tMzhfZmlsdCwgc3Vic2V0ID0gImxvY2F0aW9uX3RpbWUgPT0gJ1NDTl9oZXQnfCBsb2NhdGlvbl90aW1lID09ICdTQ05fa28nIikKCm1tMzhfZGxnbl9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfZGxnbl9zdWJzZXQsIGZpbHRlciA9IFRSVUUpCm1tMzhfc2NuX3N1YnNldCA8LSBub3JtYWxpemUobW0zOF9zY25fc3Vic2V0LCBmaWx0ZXIgPSBUUlVFKQptbTM4X3JldF9zdWJzZXQgPC0gbm9ybWFsaXplKG1tMzhfcmV0X3N1YnNldCwgZmlsdGVyID0gVFJVRSkKCm1tMzhfZGxnbl9zdWJzZXQgPC0gc2V0X2JhdGNoZXMobW0zOF9kbGduX3N1YnNldCwgZmFjdCA9ICJjb25kaXRpb24iKQptbTM4X3Njbl9zdWJzZXQgPC0gc2V0X2JhdGNoZXMobW0zOF9zY25fc3Vic2V0LCBmYWN0ID0gImNvbmRpdGlvbiIpCm1tMzhfcmV0X3N1YnNldCA8LSBzZXRfYmF0Y2hlcyhtbTM4X3JldF9zdWJzZXQsIGZhY3QgPSAiY29uZGl0aW9uIikKCm1tMzhfZGxnbl9zdWJzZXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9kbGduX3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKbW0zOF9zY25fc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfc2NuX3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKbW0zOF9yZXRfc3Vic2V0IDwtIHNldF9jb25kaXRpb25zKG1tMzhfcmV0X3N1YnNldCwgZmFjdCA9ICJsb2NhdGlvbl90aW1lIikKYGBgCgpgYGB7cn0KbW1fZGVfZGxnbl9zdmEgPC0gYWxsX3BhaXJ3aXNlKG1tMzhfZGxnbl9zdWJzZXQsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9yZXRfc3ZhIDwtIGFsbF9wYWlyd2lzZShtbTM4X3JldF9zdWJzZXQsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9zY25fc3ZhIDwtIGFsbF9wYWlyd2lzZShtbTM4X3Njbl9zdWJzZXQsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQptbV9kZV9zY25fc3ZhCgptbV9zY25fc3ZhX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX2RlX3Njbl9zdmEsIGV4Y2VsID0gImV4Y2VsL21tX3N1YnNldF9zY25fc3ZhX3RhYmxlLnhsc3giKQptbV9zY25fc3ZhX3RhYmxlCm1tX3Njbl9zdmFfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgbW1fc2NuX3N2YV90YWJsZSwgZXhjZWwgPSAiZXhjZWwvbW1fc3Vic2V0X3Njbl9zdmFfc2lnLnhsc3giKQptbV9zY25fc3ZhX3NpZwpgYGAKCiMjIGRMR04KCiMjIyBQQ0EgcHJlIGFuZCBwb3N0IFNWQXNlcQoKYGBge3J9Cm1tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCA8LSBub3JtYWxpemUobW0zOF9kbGduX3N1YnNldCwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gbm9ybWFsaXplKG1tMzhfZGxnbl9zdWJzZXQsIGNvbnZlcnQgPSAiY3BtIiwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIpCgpwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2ggPC0gcGxvdF9wY2EobW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2gpCnBjYV9ub3JtX3Bsb3Rfbm9iYXRjaCA8LSAgZ2dwbG90KHBjYV9tbTM4X2RsZ25fc3Vic2V0X25vcm1fbm9iYXRjaCR0YWJsZSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gbGFiZWxzKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29uZGl0aW9uKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlcywKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBObyBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9tbTM4X2RsZ25fc3Vic2V0X25vcm1fbm9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2gkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpICArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX25vYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdTM19IdF9kTEdOJywgJ1M0X0h0X2RMR04nKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4xLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMSkKCgpwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX2JhdGNoIDwtIHBsb3RfcGNhKG1tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCkKcGNhX25vcm1fcGxvdF9iYXRjaCA8LSAgZ2dwbG90KHBjYV9tbTM4X2RsZ25fc3Vic2V0X25vcm1fYmF0Y2gkdGFibGUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbmRpdGlvbiksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl92YWx1ZXMsCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIHdpdGggU1ZBIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9kbGduX3N1YnNldF9ub3JtX2JhdGNoJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKSAgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIocGNhX21tMzhfZGxnbl9zdWJzZXRfbm9ybV9iYXRjaCR0YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGMoJ1MzX0h0X2RMR04nLCAnUzRfSHRfZExHTicpKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLjEsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4xKQoKCnBjYV9ub3JtX3Bsb3Rfbm9iYXRjaApwY2Ffbm9ybV9wbG90X2JhdGNoCmBgYAoKCiMjIyBWb2xjYW5vIFBsb3RzIGFkIERFIHRhYmxlIHJlc3VsdHMKCmBgYHtyfQprZWVwZXJzIDwtIG5hbWVzKG1tX2RlX2RsZ25fc3ZhJGRlc2VxJGFsbF90YWJsZXMpCgpyZXNfdGJsc19kbGduX3N2YSA8LSBjKCkKZm9yICh0YmwgaW4ga2VlcGVycykgewogIGRlc2VxX3RibCA8LSBnZXRfZGVfdGFibGUobW1fZGVfZGxnbl9zdmEsIHRhYmxlID0gdGJsKQogIHJlc190YmxzX2RsZ25fc3ZhW1t0YmxdXSA8LSBtZXJnZShkZXNlcV90YmwsIGhpc2F0X2Fubm90LCBieSA9ICJyb3cubmFtZXMiKQogIHJlc190YmxzX2RsZ25fc3ZhW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzX2RsZ25fc3ZhW1t0YmxdXSwgZmFjdG9ycyA9IGMocGFzdGUoZ3N1YigiXFxfLioiLCIiLHRibCksICJcbkVucmljaGVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpKQogIHJlc190YmxzX2RsZ25fc3ZhW1twYXN0ZTAodGJsLCAidm9sY19wbG90bHkiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19kbGduX3N2YVtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAidW5pcHJvdF9nbl9zeW1ib2wiKQogIHJlc190YmxzX2RsZ25fc3ZhW1twYXN0ZTAodGJsLCAidm9sY19nZ3Bsb3QiKV1dIDwtIHZvbGNfcGxvdChyZXNfdGJsc19kbGduX3N2YVtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiKQp9CgpyZXNfdGJsc19kbGduX3N2YSRkTEdOa29fdnNfZExHTmhldHZvbGNfZ2dwbG90CnJlc190YmxzX2RsZ25fc3ZhJGRMR05rb192c19kTEdOaGV0dm9sY19wbG90bHkKCnJlc190YmxzX2RsZ25fc3ZhJGRMR05rb192c19kTEdOaGV0IHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1KSB8PgogIGZpbHRlcihhYnMobG9nRkMpID49IDEpIHw+CiAgc2VsZWN0KCJlbnNlbWJsX2dlbmVfaWQiLCAidW5pcHJvdF9nbl9zeW1ib2wiLCAiU2lnbmlmaWNhbmNlIiwgImRlc2NyaXB0aW9uIiwgImJhc2VNZWFuIiwgImxvZ0ZDIiwgImFkai5QLlZhbCIpIHw+CiAgYXJyYW5nZShsb2dGQykgfD4KICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UpCmBgYAoKU2FtZDExIGFuZCBEbXJ0MyBhcmUgc3RpbGwgYm90aCB1cHJlZ3VsYXRlZCBpbiBkTEdOIEtPcyAoYXMgdGhleSB3ZXJlCndpdGhvdXQgaW5jbHVkaW5nIHRoZSBoaWdoLWV4cHJlc3NvcnMpLgoKUHR0ZzEsIFNlbWEzZywgSWZpaDEsIERwcGE1YSwgYW5kIFByZzQgYXJlIGFsbCB1cHJlZ3VsYXRlZCBpbiBkTEdOCkhldHMgaW5jbHVkaW5nIGFuZCBleGNsdWRpbmcgdGhlIGhpZ2ggZXhwcmVzc29ycy4gV2UgZG8gbG9zZSBhIGZldwpnZW5lcyB3aGVuIGluY2x1ZGluZyBoaWdoIGV4cHJlc3NvcnMgdGhhdCB3ZXJlIGVucmljaGVkIGluIGRMR04gaGV0cwpiZWZvcmUuCgojIyBTQ04KCiMjIyBQQ0EgcHJlIGFuZCBwb3N0IFNWQXNlcQoKYGBge3J9Cm1tMzhfc2NuX3N1YnNldF9ub3JtX2JhdGNoIDwtIG5vcm1hbGl6ZShtbTM4X3Njbl9zdWJzZXQsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKbW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCA8LSBub3JtYWxpemUobW0zOF9zY25fc3Vic2V0LCBjb252ZXJ0ID0gImNwbSIsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIpCgpwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCA8LSBwbG90X3BjYShtbTM4X3Njbl9zdWJzZXRfbm9ybV9ub2JhdGNoKQpwY2Ffbm9ybV9wbG90X25vYmF0Y2hfc2NuIDwtICBnZ3Bsb3QocGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX25vYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb25kaXRpb24pLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzWzU6Nl0sCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIHdpdGggTm8gQmF0Y2ggQ29ycmVjdGlvbiIpICArCiAgbGFicyh4ID0gcGFzdGUwKCJQQzE6ICIsICBwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fbm9iYXRjaCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkgICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKHBjYV9tbTM4X3Njbl9zdWJzZXRfbm9ybV9ub2JhdGNoJHRhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzICVpbiUgYygnUzNfSGV0X1NDTicsICdTNF9IZXRfU0NOJykpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMiwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjIpCgoKcGNhX21tMzhfc2NuX3N1YnNldF9ub3JtX2JhdGNoIDwtIHBsb3RfcGNhKG1tMzhfc2NuX3N1YnNldF9ub3JtX2JhdGNoKQpwY2Ffbm9ybV9wbG90X2JhdGNoX3NjbiA8LSAgZ2dwbG90KHBjYV9tbTM4X3Njbl9zdWJzZXRfbm9ybV9iYXRjaCR0YWJsZSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gbGFiZWxzKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY29uZGl0aW9uKSwKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3ZhbHVlc1s1OjZdLAogICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImNvbG9yIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhjb2xvcj0iQ2VsbCBDb21wYXJ0bWVudC9HZW5vdHlwZSIpICAgKwogIGdndGl0bGUoIlBDQSB3aXRoIFNWQSBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9tbTM4X3Njbl9zdWJzZXRfbm9ybV9iYXRjaCRwcm9wX3ZhclsxXSwgIiUgdmFyaWFuY2UiKSwKICAgICAgIHkgPSAgcGFzdGUwKCJQQzI6ICIsICBwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fYmF0Y2gkcHJvcF92YXJbMl0sICIlIHZhcmlhbmNlIikpICArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhPWZpbHRlcihwY2FfbW0zOF9zY25fc3Vic2V0X25vcm1fYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdTM19IZXRfU0NOJywgJ1M0X0hldF9TQ04nKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4yLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMikKCgpwY2Ffbm9ybV9wbG90X25vYmF0Y2hfc2NuCnBjYV9ub3JtX3Bsb3RfYmF0Y2hfc2NuCmBgYAoKIyMjIFZvbGNhbm8gUGxvdHMgYWQgREUgdGFibGUgcmVzdWx0cwoKYGBge3J9CmtlZXBlcnMgPC0gbmFtZXMobW1fZGVfc2NuX3N2YSRkZXNlcSRhbGxfdGFibGVzKQoKcmVzX3RibHNfc2NuX3N2YSA8LSBjKCkKZm9yICh0YmwgaW4ga2VlcGVycykgewogIGRlc2VxX3RibCA8LSBnZXRfZGVfdGFibGUobW1fZGVfc2NuX3N2YSwgdGFibGUgPSB0YmwpCiAgcmVzX3RibHNfc2NuX3N2YVtbdGJsXV0gPC0gbWVyZ2UoZGVzZXFfdGJsLCBoaXNhdF9hbm5vdCwgYnkgPSAicm93Lm5hbWVzIikKICByZXNfdGJsc19zY25fc3ZhW1t0YmxdXSA8LSBzZXRfc2lnX2xpbW1hKHJlc190YmxzX3Njbl9zdmFbW3RibF1dLCBmYWN0b3JzID0gYyhwYXN0ZShnc3ViKCJcXF8uKiIsIiIsdGJsKSwgIlxuRW5yaWNoZWQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZShzdWIoJy4qXFxfJywgJycsIHRibCksICJcbkVucmljaGVkIikpKQogIHJlc190YmxzX3Njbl9zdmFbW3Bhc3RlMCh0YmwsICJ2b2xjX3Bsb3RseSIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3Njbl9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicGxvdGx5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YmwgPSAibGltbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfbmFtZV9jb2wgPSAidW5pcHJvdF9nbl9zeW1ib2wiKQogIHJlc190YmxzX3Njbl9zdmFbW3Bhc3RlMCh0YmwsICJ2b2xjX2dncGxvdCIpXV0gPC0gdm9sY19wbG90KHJlc190YmxzX3Njbl9zdmFbW3RibF1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUoIlZvbGNhbm8gUGxvdDoiLCB0YmwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIpCn0KCnJlc190YmxzX3Njbl9zdmEkU0NOa29fdnNfU0NOaGV0dm9sY19nZ3Bsb3QKcmVzX3RibHNfc2NuX3N2YSRTQ05rb192c19TQ05oZXR2b2xjX3Bsb3RseQoKcmVzX3RibHNfc2NuX3N2YSRTQ05rb192c19TQ05oZXQgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUpIHw+CiAgZmlsdGVyKGFicyhsb2dGQykgPj0gMSkgfD4KICBzZWxlY3QoImVuc2VtYmxfZ2VuZV9pZCIsICJ1bmlwcm90X2duX3N5bWJvbCIsICJTaWduaWZpY2FuY2UiLCAiZGVzY3JpcHRpb24iLCAiYmFzZU1lYW4iLCAibG9nRkMiLCAiYWRqLlAuVmFsIikgfD4KICBhcnJhbmdlKGxvZ0ZDKSB8PgogIERUOjpkYXRhdGFibGUocm93bmFtZXMgPSBGQUxTRSkKYGBgCgojIyBSZXRpbmEKCiMjIyBQQ0EgcHJlIGFuZCBwb3N0IFNWQXNlcQoKYGBge3J9Cm1tMzhfcmV0X3N1YnNldF9ub3JtX2JhdGNoIDwtIG5vcm1hbGl6ZShtbTM4X3JldF9zdWJzZXQsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgYmF0Y2ggPSAic3Zhc2VxIikKbW0zOF9yZXRfc3Vic2V0X25vcm1fbm9iYXRjaCA8LSBub3JtYWxpemUobW0zOF9yZXRfc3Vic2V0LCBjb252ZXJ0ID0gImNwbSIsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIpCgpwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fbm9iYXRjaCA8LSBwbG90X3BjYShtbTM4X3JldF9zdWJzZXRfbm9ybV9ub2JhdGNoKQpwY2Ffbm9ybV9wbG90X25vYmF0Y2hfcmV0IDwtICBnZ3Bsb3QocGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX25vYmF0Y2gkdGFibGUsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBsYWJlbCA9IGxhYmVscykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbmRpdGlvbiksCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl92YWx1ZXNbMzo0XSwKICAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJjb2xvciIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoY29sb3I9IkNlbGwgQ29tcGFydG1lbnQvR2Vub3R5cGUiKSAgICsKICBnZ3RpdGxlKCJQQ0Egd2l0aCBObyBCYXRjaCBDb3JyZWN0aW9uIikgICsKICBsYWJzKHggPSBwYXN0ZTAoIlBDMTogIiwgIHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9ub2JhdGNoJHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9ub2JhdGNoJHByb3BfdmFyWzJdLCAiJSB2YXJpYW5jZSIpKSAgKwogIGdlb21fbGFiZWxfcmVwZWwoZGF0YT1maWx0ZXIocGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX25vYmF0Y2gkdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgJWluJSBjKCdTM19IZXRfUmV0JywgJ1M0X0hldF9SZXQnKSksCiAgICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4yLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMikKCgpwY2FfbW0zOF9yZXRfc3Vic2V0X25vcm1fYmF0Y2ggPC0gcGxvdF9wY2EobW0zOF9yZXRfc3Vic2V0X25vcm1fYmF0Y2gpCnBjYV9ub3JtX3Bsb3RfYmF0Y2hfcmV0IDwtICBnZ3Bsb3QocGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX2JhdGNoJHRhYmxlLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBsYWJlbHMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb25kaXRpb24pLAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfdmFsdWVzWzM6NF0sCiAgICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiY29sb3IiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKGNvbG9yPSJDZWxsIENvbXBhcnRtZW50L0dlbm90eXBlIikgICArCiAgZ2d0aXRsZSgiUENBIHdpdGggU1ZBIEJhdGNoIENvcnJlY3Rpb24iKSAgKwogIGxhYnMoeCA9IHBhc3RlMCgiUEMxOiAiLCAgcGNhX21tMzhfcmV0X3N1YnNldF9ub3JtX2JhdGNoJHByb3BfdmFyWzFdLCAiJSB2YXJpYW5jZSIpLAogICAgICAgeSA9ICBwYXN0ZTAoIlBDMjogIiwgIHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9iYXRjaCRwcm9wX3ZhclsyXSwgIiUgdmFyaWFuY2UiKSkgICsKICBnZW9tX2xhYmVsX3JlcGVsKGRhdGE9ZmlsdGVyKHBjYV9tbTM4X3JldF9zdWJzZXRfbm9ybV9iYXRjaCR0YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyAlaW4lIGMoJ1MzX0hldF9SZXQnLCAnUzRfSGV0X1JldCcpKSwKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLjIsCiAgICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4yKQoKCnBjYV9ub3JtX3Bsb3Rfbm9iYXRjaF9yZXQKcGNhX25vcm1fcGxvdF9iYXRjaF9yZXQKYGBgCgojIyMgVm9sY2FubyBQbG90cyBhZCBERSB0YWJsZSByZXN1bHRzCgpgYGB7cn0Ka2VlcGVycyA8LSBuYW1lcyhtbV9kZV9yZXRfc3ZhJGRlc2VxJGFsbF90YWJsZXMpCgpyZXNfdGJsc19yZXRfc3ZhIDwtIGMoKQpmb3IgKHRibCBpbiBrZWVwZXJzKSB7CiAgZGVzZXFfdGJsIDwtIGdldF9kZV90YWJsZShtbV9kZV9yZXRfc3ZhLCB0YWJsZSA9IHRibCkKICByZXNfdGJsc19yZXRfc3ZhW1t0YmxdXSA8LSBtZXJnZShkZXNlcV90YmwsIGhpc2F0X2Fubm90LCBieSA9ICJyb3cubmFtZXMiKQogIHJlc190YmxzX3JldF9zdmFbW3RibF1dIDwtIHNldF9zaWdfbGltbWEocmVzX3RibHNfcmV0X3N2YVtbdGJsXV0sIGZhY3RvcnMgPSBjKHBhc3RlKGdzdWIoIlxcXy4qIiwiIix0YmwpLCAiXG5FbnJpY2hlZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKHN1YignLipcXF8nLCAnJywgdGJsKSwgIlxuRW5yaWNoZWQiKSkpCiAgcmVzX3RibHNfcmV0X3N2YVtbcGFzdGUwKHRibCwgInZvbGNfcGxvdGx5IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfcmV0X3N2YVtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwbG90bHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRibCA9ICJsaW1tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9uYW1lX2NvbCA9ICJ1bmlwcm90X2duX3N5bWJvbCIpCiAgcmVzX3RibHNfcmV0X3N2YVtbcGFzdGUwKHRibCwgInZvbGNfZ2dwbG90IildXSA8LSB2b2xjX3Bsb3QocmVzX3RibHNfcmV0X3N2YVtbdGJsXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZSgiVm9sY2FubyBQbG90OiIsIHRibCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGJsID0gImxpbW1hIikKfQoKcmVzX3RibHNfcmV0X3N2YSRSZXRpbmFrb192c19SZXRpbmFoZXR2b2xjX2dncGxvdApyZXNfdGJsc19yZXRfc3ZhJFJldGluYWtvX3ZzX1JldGluYWhldHZvbGNfcGxvdGx5CgpyZXNfdGJsc19yZXRfc3ZhJFJldGluYWtvX3ZzX1JldGluYWhldCB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSkgfD4KICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAxKSB8PgogIHNlbGVjdCgiZW5zZW1ibF9nZW5lX2lkIiwgInVuaXByb3RfZ25fc3ltYm9sIiwgIlNpZ25pZmljYW5jZSIsICJkZXNjcmlwdGlvbiIsICJiYXNlTWVhbiIsICJsb2dGQyIsICJhZGouUC5WYWwiKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgRFQ6OmRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFKQpgYGAKCiMgUmUtSW1wbGVtZW50YXRpb24KCkxldCB1cyBzdGFydCB3aXRoIHRoZSBmdWxsIHNldCBvZiBkZXNpcmVkIHRhYmxlcy4gIEluIHRoZSBhYm92ZSwgdGhlCmRhdGEgd2FzIHNlcGFyYXRlZCBpbnRvIH4gOSBzZXBhcmF0ZSBjaHVua3MgYW5kIEkgdGhpbmsgaXQgd2lsbApiZW5lZml0IGZyb20gYmVpbmcga2VwdCB0b2dldGhlciAtLSBhbHNvIEkgc2VlbSB0byByZWNhbGwgZXhwcmVzc2luZwp0aGlzIHRvIFRoZXJlc2EgYW5kIHRoYXQgc2hlIGNoYW5nZWQgdGhlIG5vdGVib29rIHRvIHRoaXMga2luZCBvZgphbmFseXNpcy4gIElmIEkgYW0gY29ycmVjdCwgdGhlbiBpdCBpcyBwb3NzaWJsZSBzaGUgZGlkIHNvIGluIGEKc2VwYXJhdGUgbm90ZWJvb2sgd2hpY2ggSSBoYXZlIG5vdCBmb3VuZCBhbmQgdGhhdCB0aGlzIHdpbGwgcHJvdmlkZQp0aGUgZnVsbHkgcmVjb25jaWxlZCBzZXQgb2YgcmVzdWx0cy4KCkkgaGF2ZSByZWFzb25hYmxlIGhvcGUgZm9yIHRoaXMgYmVjYXVzZSB0aGUgdmFyaW91cyBwbG90cyBldGMgZWFybHkgb24KbG9vayBpZGVudGljYWwgYmV0d2VlbiB0aGlzIGNvbnRhaW5lcml6ZWQgbm90ZWJvb2ssIGFuZCB0aG9zZQpub3RlYm9va3MgSSBmb3VuZCBpbiBoZXIgd29ya2luZyB0cmVlLgoKV2hpbGUgSSB3YWl0IGZvciB0aGVzZSB0YWJsZXMgdG8gY29tZSBiYWNrLCBsZXQgdXMgY291bnQgdGhlIG51bWJlciBvZgpzYW1wbGVzIGluIHRoZSBwbG90IHByb3ZpZGVkIGJ5IENvbGVuc28gc28gdGhhdCBJIG1heSBkb3VibGVjaGVjayB0aGF0Cm5vdGhpbmcgZ290IGZpbHRlcmVkIG91dCBvciBhbnl0aGluZyBpbXBvcnRhbnQgbGlrZSB0aGF0LgoKOCBwaW5rIHNhbXBsZXMsIDE3IGdyZWVuIHNhbXBsZXMsIDE3IGJsdWUgc2FtcGxlcy4KCjQgbGlnaHQgcGluaywgNCBkYXJrIHBpbmsKOSBtZWRpdW0gZ3JlZW4sIDQgbGlnaHQgZ3JlZW4sIDQgZGFyayBncmVlbi4KOSBtZWRpdW0gYmx1ZSwgNCBsaWdodCBibHVlLCA0IGRhcmsgYmx1ZS4KCldpdGggdGhlIGFib3ZlIGluIG1pbmQsIGxldCB1cyBtYWtlIGEgc21hbGwgY2hhbmdlIGluIGhvdyB0aGUgZGF0YSBpcwpoYW5kbGVkIGFuZCBzZWUgaWYgSSBjYW5ub3QgZ2V0IG51bWJlcnMgbW9yZSBjbG9zZWx5IGFsaWduZWQgdG8gdGhlCnRhYmxlcyBmcm9tIENvbGVuc28uCgpgYGB7cn0KIyMgSGVyZSBpcyBhIHJlbWluZGVyIG9mIFRoZXJlc2EncyBmaWx0ZXI6CiMjIGZpbHRlcihzYW1wbGVfaWQgJWluJSBjKCJTM19IZXRfUmV0X1MxIiwgIlM0X0hldF9SZXRfUzQiLCAiUzVfSGV0X1JldF9TMTYiLCAiUzFfSGV0X1JldF9TMSIsICJTMl9IZXRfUmV0X1M0IiwgIlMzX0hldF9SZXRfUzciLCAiUzRfSGV0X1JldF9TMTAiLCAiUzVfSGV0X1JldF9TMTMiKSkgfD4KCm1tX2ZpbmFsIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0LCBzdWJzZXQgPSAiaW5jbHVkZWQ9PSd5ZXMnIikgfD4KICBzZXRfY29uZGl0aW9ucyhmYWN0ID0gImxvY2F0aW9uX2dlbm90eXBlIikKCm1tX25vcm0gPC0gbm9ybWFsaXplKG1tX2ZpbmFsLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIpCnBsb3RfcGNhKG1tX25vcm0pCgptbV9uYiA8LSBub3JtYWxpemUobW1fZmluYWwsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLCBmaWx0ZXIgPSBUUlVFLCBiYXRjaCA9ICJzdmFzZXEiKQpwbG90X3BjYShtbV9uYikKYGBgCgpUaGVyZSByZW1haW4gYSBjb3VwbGUgb2Ygd2VpcmRvIHNhbXBsZXMsIGJ1dCB0aGluZ3MgbG9vayBxdWl0ZSBhIGJpdAplYXNpZXIgdG8gaW50ZXJwcmV0IHRvIG15IGV5ZXMuCgpgYGB7cn0KZmluYWxfa2VlcGVycyA8LSBsaXN0KAogICMjIFRocmVlIGNvbXBhcmlzb25zIGFtb25nIHRoZSBkTEdOIHNhbXBsZXMuCiAgImRsZ25fa3ciID0gYygiZExHTl9rbyIsICJkTEdOX3d0IiksCiAgImRsZ25fa2giID0gYygiZExHTl9rbyIsICJkTEdOX2hldCIpLAogICJkbGduX2h3IiA9IGMoImRMR05faGV0IiwgImRMR05fd3QiKSwKICAjIyBUaHJlZSBjb21wYXJpc29ucyBhbW9uZyB0aGUgU0NOIHNhbXBsZXMuCiAgInNjbl9rdyIgPSBjKCJTQ05fa28iLCAiU0NOX3d0IiksCiAgInNjbl9raCIgPSBjKCJTQ05fa28iLCAiU0NOX2hldCIpLAogICJzY25faHciID0gYygiU0NOX2hldCIsICJTQ05fd3QiKSwKICAjIyBhbmQgdGhlIHJldGluYSBzYW1wbGVzCiAgInJldGluYV9rdyIgPSBjKCJSZXRpbmFfa28iLCAiUmV0aW5hX3d0IiksCiAgInJldGluYV9raCIgPSBjKCJSZXRpbmFfa28iLCAiUmV0aW5hX2hldCIpLAogICJyZXRpbmFfaHciID0gYygiUmV0aW5hX2hldCIsICJSZXRpbmFfd3QiKQopCgpnZW5vbG9jX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UobW1fZmluYWwsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBrZWVwZXJzID0gZmluYWxfa2VlcGVycykKZ2Vub2xvY190YWJsZV9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoZ2Vub2xvY19kZV9zdmEsIGV4Y2VsID0gImV4Y2VsL2dlbm90eXBlX2xvY2F0aW9uX3RhYmxlcy54bHN4IikKZ2Vub2xvY19zaWdfc3ZhIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoZ2Vub2xvY190YWJsZV9zdmEsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gImV4Y2VsL2dlbm90eXBlX2xvY2F0aW9uX3NpZy54bHN4IikKCgpsb2NhdGlvbl9rZWVwZXJzIDwtIGxpc3QoCiAgIyMga28gYWNyb3NzIGxvY2F0aW9ucwogICJrb19kbGduX3NjbiIgPSBjKCJkTEdOX2tvIiwgIlNDTl9rbyIpLAogICJrb19kbGduX3JldCIgPSBjKCJkTEdOX2tvIiwgIlJldGluYV9rbyIpLAogICJrb19zY25fcmV0IiA9IGMoIlNDTl9rbyIsICJSZXRpbmFfa28iKSwKICAjIyBoZXQgYWNyb3NzIGxvY2F0aW9ucwogICJoZXRfZGxnbl9zY24iID0gYygiZExHTl9oZXQiLCAiU0NOX2hldCIpLAogICJoZXRfZGxnbl9yZXQiID0gYygiZExHTl9oZXQiLCAiUmV0aW5hX2hldCIpLAogICJoZXRfc2NuX3JldCIgPSBjKCJTQ05faGV0IiwgIlJldGluYV9oZXQiKSwKICAjIyB3dCBhY3Jvc3MgbG9jYXRpb25zCiAgInd0X2RsZ25fc2NuIiA9IGMoImRMR05fd3QiLCAiU0NOX3d0IiksCiAgInd0X2RsZ25fcmV0IiA9IGMoImRMR05fd3QiLCAiUmV0aW5hX3d0IiksCiAgInd0X3Njbl9yZXQiID0gYygiU0NOX3d0IiwgIlJldGluYV93dCIpKQpsb2NhdGlvbl9jb21wYXJpc29ucyA8LSBhbGxfcGFpcndpc2UobW1fZmluYWwsIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLCBrZWVwZXJzID0gbG9jYXRpb25fa2VlcGVycykKbG9jYXRpb25fdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMobG9jYXRpb25fY29tcGFyaXNvbnMsIGV4Y2VsID0gImV4Y2VsL2xvY2F0aW9ucy54bHN4IikKbG9jYXRpb25fc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMobG9jYXRpb25fdGFibGUsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gImV4Y2VsL2xvY2F0aW9uX3NpZy54bHN4IikKYGBgCgpTYXZlIHNvbWUgb2YgdGhlIERFIHJlc3VsdHMgZm9yIGNvbXBhcmlzb24gYWdhaW5zIHRoZSBUUkFQIGRhdGEKCmBgYHtyLCBldmFsPUZBTFNFfQpkZV9saXN0IDwtIGMoIm1tX2RlX2RsZ25fc3ZhIiwgIm1tX2RlX3JldF9zdmEiLCAibW1fZGVfc2NuX3N2YSIsCiAgICAgICAgICAgICAibW1fZGVfZGxnbiIsICJtbV9kZV9yZXQiLCAibW1fZGVfc2NuIiwKICAgICAgICAgICAgICJnZW5vbG9jX2RlX3N2YSIsICJnZW5vbG9jX3RhYmxlX3N2YSIpCnNhdmVkIDwtIHNhdmUobGlzdCA9IGRlX2xpc3QsIGZpbGUgPSAiYnVsa19yZXN1bHRzLnJkYSIpCmBgYAoK