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")
M. musculus
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.
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
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"))
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
## Error in `h()`:
## ! error in evaluating the argument 'data' in selecting a method for function 'plot_quantreads': object 'mm38_hisat' not found
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
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).
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
## 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
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
## 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
## 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.
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
## 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
## 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.
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
## 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
## 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
## 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
## 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
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"
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"
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"
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
## 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
## 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
## Error:
## ! object 'mm_scn_sva_sig' not found
dLGN
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
## Error:
## ! object 'pca_norm_plot_nobatch' not found
## Error:
## ! object 'pca_norm_plot_batch' not found
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.
SCN
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
## Error:
## ! object 'pca_norm_plot_batch_scn' not found
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"
Retina
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
## Error:
## ! object 'pca_norm_plot_batch_ret' not found
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"
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
## 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
## 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