Introduction
Having established that the TMRC2 macrophage data looks robust and
illustrative of a couple of interesting questions, let us perform a
couple of differential analyses of it.
Also note that as of 202212, we received a new set of samples which
now include some which are of a completely different cell type, U937. As
their ATCC page states, they are malignant cells taken from the pleural
effusion of a 37 year old white male with histiocytic lymphoma and which
exhibit the morphology of monocytes. Thus, this document now includes
some comparisons of the cell types as well as the various macrophage
donors (given that there are now more donors too).
Human data
I am moving the dataset manipulations here so that I can look at them
all together before running the various DE analyses.
Create sets focused
on drug, celltype, strain, and combinations
Let us start by playing with the metadata a little and create sets
with the condition set to:
- Drug treatment
- Cell type (macrophage or U937)
- Donor
- Infection Strain
- Some useful combinations thereof
In addition, keep mental track of which datasets are comprised of all
samples vs. those which are only macrophage vs. those which are only
U937. (Thus, the usage of all_human vs. hs_macr vs. u937 as prefixes for
the data structures.)
Ideally, these recreations of the data should perhaps be in the
datastructures worksheet.
all_human <- sanitize_expt_metadata(hs_macrophage, columns = "drug") %>%
set_expt_conditions(fact = "drug") %>%
set_expt_batches(fact = "typeofcells")
##
## antimony none
## 34 34
##
## Macrophages U937
## 54 14
## The following 3 lines were copy/pasted to datastructures and should be removed soon.
no_strain_idx <- pData(all_human)[["strainid"]] == "none"
##pData(all_human)[["strainid"]] <- paste0("s", pData(all_human)[["strainid"]],
## "_", pData(all_human)[["macrophagezymodeme"]])
pData(all_human)[no_strain_idx, "strainid"] <- "none"
table(pData(all_human)[["strainid"]])
##
## none s10763_z22 s10772_z23 s10977_z22 s11026_z23 s11075_z22 s11126_z22
## 10 2 8 2 2 2 8
## s12251_z23 s12309_z22 s12355_z23 s12367_z22 s2169_z23 s7158_z23
## 7 8 2 7 8 2
all_human_types <- set_expt_conditions(all_human, fact = "typeofcells") %>%
set_expt_batches(fact = "drug")
##
## Macrophages U937
## 54 14
##
## antimony none
## 34 34
type_zymo_fact <- paste0(pData(all_human_types)[["condition"]], "_",
pData(all_human_types)[["macrophagezymodeme"]])
type_zymo <- set_expt_conditions(all_human_types, fact = type_zymo_fact)
##
## Macrophages_none Macrophages_z22 Macrophages_z23 U937_none
## 8 23 23 2
## U937_z22 U937_z23
## 6 6
type_drug_fact <- paste0(pData(all_human_types)[["condition"]], "_",
pData(all_human_types)[["drug"]])
type_drug <- set_expt_conditions(all_human_types, fact = type_drug_fact)
##
## Macrophages_antimony Macrophages_none U937_antimony
## 27 27 7
## U937_none
## 7
strain_fact <- pData(all_human_types)[["strainid"]]
table(strain_fact)
## strain_fact
## none s10763_z22 s10772_z23 s10977_z22 s11026_z23 s11075_z22 s11126_z22
## 10 2 8 2 2 2 8
## s12251_z23 s12309_z22 s12355_z23 s12367_z22 s2169_z23 s7158_z23
## 7 8 2 7 8 2
new_conditions <- paste0(pData(hs_macrophage)[["macrophagetreatment"]], "_",
pData(hs_macrophage)[["macrophagezymodeme"]])
## Note the sanitize() call is redundant with the addition of sanitize() in the
## datastructures file, but I don't want to wait to rerun that.
hs_macr <- set_expt_conditions(hs_macrophage, fact = new_conditions) %>%
sanitize_expt_metadata(column = "drug")
##
## inf_z22 inf_z23 infsb_z22 infsb_z23 uninf_none uninfsb_none
## 14 15 15 14 5 5
Separate Macrophage
samples
Once again, we should reconsider where the following block is placed,
but these datastructures are likely to be used in many of the following
analyses.
hs_macr_drug_expt <- set_expt_conditions(hs_macr, fact = "drug")
##
## antimony none
## 34 34
hs_macr_strain_expt <- set_expt_conditions(hs_macr, fact = "macrophagezymodeme") %>%
subset_expt(subset = "macrophagezymodeme != 'none'")
##
## none z22 z23
## 10 29 29
## subset_expt(): There were 68, now there are 58 samples.
table(pData(hs_macr)[["strainid"]])
##
## none s10763_z22 s10772_z23 s10977_z22 s11026_z23 s11075_z22 s11126_z22
## 10 2 8 2 2 2 8
## s12251_z23 s12309_z22 s12355_z23 s12367_z22 s2169_z23 s7158_z23
## 7 8 2 7 8 2
Refactor U937
samples
The U937 samples were separated in the datastructures file, but we
want to use the combination of drug/zymodeme with them pretty much
exclusively.
new_conditions <- paste0(pData(hs_u937)[["macrophagetreatment"]], "_",
pData(hs_u937)[["macrophagezymodeme"]])
u937_expt <- set_expt_conditions(hs_u937, fact = new_conditions)
##
## inf_z22 inf_z23 infsb_z22 infsb_z23 uninf_none uninfsb_none
## 3 3 3 3 1 1
Contrasts used in
this document
Given the various ways we have chopped up this dataset, there are a
few general types of contrasts we will perform, which will then be
combined into greater complexity:
- drug treatment
- strains used
- cellltypes
- donors
In the end, our actual goal is to consider the variable effects of
drug+strain and see if we can discern patterns which lead to better or
worse drug treatment outcome.
There is a set of contrasts in which we are primarily interested in
this data, these follow. I created one ratio of ratios contrast which I
think has the potential to ask our biggest question.
tmrc2_human_extra <- "z23drugnodrug_vs_z22drugnodrug = (infsbz23 - infz23) - (infsbz22 - infz22), z23z22drug_vs_z23z22nodrug = (infsbz23 - infsbz22) - (infz23 - infz22)"
tmrc2_human_keepers <- list(
"z23nosb_vs_uninf" = c("infz23", "uninfnone"),
"z22nosb_vs_uninf" = c("infz22", "uninfnone"),
"z23nosb_vs_z22nosb" = c("infz23", "infz22"),
"z23sb_vs_z22sb" = c("infsbz23", "infsbz22"),
"z23sb_vs_z23nosb" = c("infsbz23", "infz23"),
"z22sb_vs_z22nosb" = c("infsbz22", "infz22"),
"z23sb_vs_sb" = c("infz23", "uninfsbnone"),
"z22sb_vs_sb" = c("infz22", "uninfsbnone"),
"z23sb_vs_uninf" = c("infsbz23", "uninfnone"),
"z22sb_vs_uninf" = c("infsbz22", "uninfnone"),
"sb_vs_uninf" = c("uninfsbnone", "uninfnone"),
"extra_z2322" = c("z23drugnodrug", "z22drugnodrug"),
"extra_drugnodrug" = c("z23z22drug", "z23z22nodrug"))
tmrc2_drug_keepers <- list(
"drug" = c("antimony", "none"))
tmrc2_type_keepers <- list(
"type" = c("U937", "Macrophages"))
tmrc2_strain_keepers <- list(
"strain" = c("z23", "z22"))
type_zymo_extra <- "zymos_vs_types = (U937_z2.3 - U937_z2.2) - (Macrophages_z2.3 - Macrophages_z2.2)"
tmrc2_typezymo_keepers <- list(
"u937_macr" = c("Macrophagesnone", "U937none"),
"zymo_macr" = c("Macrophagesz23", "Macrophagesz22"),
"zymo_u937" = c("U937z23", "U937z22"),
"z23_types" = c("U937z23", "Macrophagesz23"),
"z22_types" = c("U937z22", "Macrophagesz22"),
"zymos_types" = c("zymos_vs_types"))
tmrc2_typedrug_keepers <- list(
"type_nodrug" = c("U937none", "Macrophagesnone"),
"type_drug" = c("U937antimony", "Macrophagesantimony"),
"macr_drugs" = c("Macrophagesantimony", "Macrophagesnone"),
"u937_drugs" = c("U937antimony", "U937none"))
u937_keepers <- list(
"z23nosb_vs_uninf" = c("infz23", "uninfnone"),
"z22nosb_vs_uninf" = c("infz22", "uninfnone"),
"z23nosb_vs_z22nosb" = c("infz23", "infz22"),
"z23sb_vs_z22sb" = c("infsbz23", "infsbz22"),
"z23sb_vs_z23nosb" = c("infsbz23", "infz23"),
"z22sb_vs_z22nosb" = c("infsbz22", "infz22"),
"z23sb_vs_sb" = c("infz23", "uninfsbnone"),
"z22sb_vs_sb" = c("infz22", "uninfsbnone"),
"z23sb_vs_uninf" = c("infsbz23", "uninfnone"),
"z22sb_vs_uninf" = c("infsbz22", "uninfnone"),
"sb_vs_uninf" = c("uninfsbnone", "uninfnone"))
Primary
queries
There is a series of initial questions which make some sense to me,
but these do not necessarily match the set of questions which are most
pressing. I am hoping to pull both of these sets of queries in one.
Before extracting these groups of queries, let us invoke the
all_pairwise() function and get all of the likely contrasts along with
one or more extras that might prove useful (the ‘extra’ argument).
Combined U937 and
Macrophages: Compare drug effects
When we have the u937 cells in the same dataset as the macrophages,
that provides an interesting opportunity to see if we can observe
drug-dependant effects which are shared across both cell types.
drug_de <- all_pairwise(all_human, filter = TRUE, model_batch = "svaseq")
##
## antimony none
## 34 34
## Removing 0 low-count genes (12283 remaining).
## Setting 3092 low elements to zero.
## transform_counts: Found 3092 values equal to 0, adding 1 to the matrix.
drug_table <- combine_de_tables(
drug_de, keepers = tmrc2_drug_keepers,
excel = glue::glue("analyses/macrophage_de/tmrc2_macrophage_drug_comparison-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/tmrc2_macrophage_drug_comparison-v202301.xlsx before writing the tables.
Combined U937 and
Macrophages: compare cell types
There are a couple of ways one might want to directly compare the two
cell types.
- Given that the variance between the two celltypes is so huge, just
compare all samples.
- One might want to compare them with the interaction effects of
drug/zymodeme.
type_de <- all_pairwise(all_human_types, filter = TRUE, model_batch = "svaseq")
##
## Macrophages U937
## 54 14
## Removing 0 low-count genes (12283 remaining).
## Setting 8682 low elements to zero.
## transform_counts: Found 8682 values equal to 0, adding 1 to the matrix.
type_table <- combine_de_tables(
type_de, keepers = tmrc2_type_keepers,
excel = glue::glue("analyses/macrophage_de/tmrc2_macrophage_type_comparison-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/tmrc2_macrophage_type_comparison-v202301.xlsx before writing the tables.
Combined factors
of interest: celltype+zymodeme, celltype+drug
Given the above explicit comparison of all samples comprising the two
cell types, now let us look at the drug treatment+zymodeme status with
all samples, macrophages and U937.
type_zymo_de <- all_pairwise(type_zymo, filter = TRUE, model_batch = "svaseq",
extra_contrasts=type_zymo_extra)
##
## Macrophages_none Macrophages_z22 Macrophages_z23 U937_none
## 8 23 23 2
## U937_z22 U937_z23
## 6 6
## Removing 0 low-count genes (12283 remaining).
## Setting 9655 low elements to zero.
## transform_counts: Found 9655 values equal to 0, adding 1 to the matrix.
## Error in e$fun(obj, substitute(ex), parent.frame(), e$data): worker initialization failed: there is no package called ‘hpgltools’
type_zymo_table <- combine_de_tables(
type_zymo_de, keepers = tmrc2_typezymo_keepers,
excel = glue::glue("analyses/macrophage_de/tmrc2_macrophage_type_zymo_comparison-v{ver}.xlsx"))
## Error in get_expt_colors(apr[["input"]]): object 'type_zymo_de' not found
type_drug_de <- all_pairwise(type_drug, filter = TRUE, model_batch = "svaseq")
##
## Macrophages_antimony Macrophages_none U937_antimony
## 27 27 7
## U937_none
## 7
## Removing 0 low-count genes (12283 remaining).
## Setting 9642 low elements to zero.
## transform_counts: Found 9642 values equal to 0, adding 1 to the matrix.
## Error in e$fun(obj, substitute(ex), parent.frame(), e$data): worker initialization failed: there is no package called ‘hpgltools’
type_drug_table <- combine_de_tables(
type_drug_de, keepers = tmrc2_typedrug_keepers,
excel=glue::glue("analyses/macrophage_de/tmrc2_macrophage_type_drug_comparison-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/tmrc2_macrophage_type_drug_comparison-v202301.xlsx before writing the tables.
## Error in get_expt_colors(apr[["input"]]): object 'type_drug_de' not found
Individual cell
types
At this point, I think it is fair to say that the two cell types are
sufficiently different that they do not really belong together in a
single analysis.
drug or strain
effects, single cell type
One of the queries Najib asked which I think I misinterpreted was to
look at drug and/or strain effects. My interpretation is somewhere below
and was not what he was looking for. Instead, he was looking to see
all(macrophage) drug/nodrug and all(macrophage) z23/z22 and compare them
to each other. It may be that this is still a wrong interpretation, if
so the most likely comparison is either:
- (z23drug/z22drug) / (z23nodrug/z22nodrug), or perhaps
- (z23drug/z23nodrug) / (z22drug/z22nodrug),
I am not sure those confuse me, and at least one of them is below
Macrophages
In these blocks we will explicitly query only one factor at a time,
drug and strain. The eventual goal is to look for effects of drug
treatment and/or strain treatment which are shared?
Macrophage Drug
only
Thus we will start with the pure drug query. In this block we will
look only at the drug/nodrug effect.
hs_macr_drug_de <- all_pairwise(hs_macr_drug_expt, filter = TRUE, model_batch = "svaseq")
##
## antimony none
## 34 34
## Removing 0 low-count genes (12283 remaining).
## Setting 3092 low elements to zero.
## transform_counts: Found 3092 values equal to 0, adding 1 to the matrix.
hs_macr_drug_table <- combine_de_tables(
hs_macr_drug_de, keepers = tmrc2_drug_keepers,
excel = glue::glue("analyses/macrophage_de/tmrc2_macrophage_onlydrug_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/tmrc2_macrophage_onlydrug_table-v202301.xlsx before writing the tables.
hs_macr_drug_sig <- extract_significant_genes(
hs_macr_drug_table)
Macrophage Strain
only
In a similar fashion, let us look for effects which are observed when
we consider only the strain used during infection.
hs_macr_strain_de <- all_pairwise(hs_macr_strain_expt, filter = TRUE, model_batch = "svaseq")
##
## z22 z23
## 29 29
## Removing 0 low-count genes (12249 remaining).
## Setting 2048 low elements to zero.
## transform_counts: Found 2048 values equal to 0, adding 1 to the matrix.
hs_macr_strain_table <- combine_de_tables(
hs_macr_strain_de, keepers = tmrc2_strain_keepers,
excel = glue::glue("analyses/macrophage_de/tmrc2_macrophage_onlystrain_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/tmrc2_macrophage_onlystrain_table-v202301.xlsx before writing the tables.
hs_macr_strain_sig <- extract_significant_genes(
hs_macr_strain_table)
Compare Drug and
Strain Effects
Now let us consider the above two comparisons together. First, I will
plot the logFC values of them against each other (drug on x-axis and
strain on the y-axis). Then we can extract the significant genes in a
few combined categories of interest. I assume these will focus
exclusively on the categories which include the introduction of the
drug.
drug_strain_comp_df <- merge(hs_macr_drug_table[["data"]][["drug"]],
hs_macr_strain_table[["data"]][["strain"]],
by = "row.names")
drug_strain_comp_plot <- plot_linear_scatter(
drug_strain_comp_df[, c("deseq_logfc.x", "deseq_logfc.y")])
## Contrasts: antimony/none, z23/z22; x-axis: drug, y-axis: strain
## top left: higher no drug, z23; top right: higher drug z23
## bottom left: higher no drug, z22; bottom right: higher drug z22
drug_strain_comp_plot$scatter

As I noted in the comments above, some quadrants of the scatter plot
are likely to be of greater interest to us than others (the right side).
Because I get confused sometimes, the following block will explicitly
name the categories of likely interest, then ask which genes are shared
among them, and finally use UpSetR to extract the various gene
intersection/union categories.
higher_drug <- hs_macr_drug_sig[["deseq"]][["downs"]][[1]]
higher_nodrug <- hs_macr_drug_sig[["deseq"]][["ups"]][[1]]
higher_z23 <- hs_macr_strain_sig[["deseq"]][["ups"]][[1]]
higher_z22 <- hs_macr_strain_sig[["deseq"]][["downs"]][[1]]
sum(rownames(higher_drug) %in% rownames(higher_z23))
## [1] 65
sum(rownames(higher_drug) %in% rownames(higher_z22))
## [1] 87
sum(rownames(higher_nodrug) %in% rownames(higher_z23))
## [1] 18
sum(rownames(higher_nodrug) %in% rownames(higher_z22))
## [1] 43
drug_z23_lst <- list("drug" = rownames(higher_drug),
"z23" = rownames(higher_z23))
higher_drug_z23 <- upset(UpSetR::fromList(drug_z23_lst), text.scale = 2)
higher_drug_z23

drug_z23_shared_genes <- overlap_groups(drug_z23_lst)
drug_z22_lst <- list("drug" = rownames(higher_drug),
"z22" = rownames(higher_z22))
higher_drug_z22 <- upset(UpSetR::fromList(drug_z22_lst), text.scale = 2)
higher_drug_z22

drug_z22_shared_genes <- overlap_groups(drug_z22_lst)
shared_genes_drug_z22 <- attr(drug_z22_shared_genes, "elements")[drug_z22_shared_genes[["drug:z22"]]]
Our main question of
interest
The data structure hs_macr contains our primary macrophages, which
are, as shown above, the data we can really sink our teeth into.
Note, we expect some errors when running the combine_de_tables()
because not all methods I use are comfortable using the ratio or ratios
contrasts we added in the ‘extras’ argument. As a result, when we
combine them into the larger output tables, those peculiar contrasts
fail. This does not stop it from writing the rest of the results,
however.
hs_macr_de <- all_pairwise(
hs_macr, model_batch = "svaseq",
filter = TRUE,
extra_contrasts = tmrc2_human_extra)
##
## inf_z22 inf_z23 infsb_z22 infsb_z23 uninf_none uninfsb_none
## 14 15 15 14 5 5
## Removing 0 low-count genes (12283 remaining).
## Setting 3485 low elements to zero.
## transform_counts: Found 3485 values equal to 0, adding 1 to the matrix.

test_keepers <- tmrc2_human_keepers[13]
hs_macr_table <- combine_de_tables(
hs_macr_de,
keepers = tmrc2_human_keepers,
##keepers = test_keepers,
excel = glue::glue("analyses/macrophage_de/hs_macr_drug_zymo_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_macr_drug_zymo_table-v202301.xlsx before writing the tables.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The deseq table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The basic table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The deseq table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The basic table seems to be missing.
hs_macr_sig <- extract_significant_genes(
hs_macr_table,
excel = glue::glue("analyses/macrophage_de/hs_macr_drug_zymo_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_macr_drug_zymo_sig-v202301.xlsx before writing the tables.
## There is no deseq_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no deseq_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no basic_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no basic_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
Our main questions
in U937
Let us do the same comparisons in the U937 samples, though I will not
do the extra contrasts, primarily because I think the dataset is less
likely to support them.
u937_de <- all_pairwise(u937_expt, model_batch = "svaseq", filter = TRUE)
##
## inf_z22 inf_z23 infsb_z22 infsb_z23 uninf_none uninfsb_none
## 3 3 3 3 1 1
## Removing 0 low-count genes (10751 remaining).
## Setting 5 low elements to zero.
## transform_counts: Found 5 values equal to 0, adding 1 to the matrix.

u937_table <- combine_de_tables(
u937_de,
keepers = u937_keepers,
excel = glue::glue("analyses/macrophage_de/u937_drug_zymo_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/u937_drug_zymo_table-v202301.xlsx before writing the tables.
u937_sig <- extract_significant_genes(
u937_table,
excel = glue::glue("analyses/macrophage_de/u937_drug_zymo_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/u937_drug_zymo_sig-v202301.xlsx before writing the tables.
Compare (no)Sb
z2.3/z2.2 treatments among macrophages
upset_plots_hs_macr <- upsetr_sig(
hs_macr_sig, both = TRUE,
contrasts = c("z23sb_vs_z22sb", "z23nosb_vs_z22nosb"))
upset_plots_hs_macr[["both"]]

groups <- upset_plots_hs_macr[["both_groups"]]
shared_genes <- attr(groups, "elements")[groups[[2]]] %>%
gsub(pattern = "^gene:", replacement = "")
length(shared_genes)
## [1] 275
shared_gp <- simple_gprofiler(shared_genes)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
shared_gp[["pvalue_plots"]][["MF"]]

shared_gp[["pvalue_plots"]][["BP"]]

shared_gp[["pvalue_plots"]][["REAC"]]

drug_genes <- attr(groups, "elements")[groups[["z23sb_vs_z22sb"]]] %>%
gsub(pattern = "^gene:", replacement = "")
drugonly_gp <- simple_gprofiler(drug_genes)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
drugonly_gp[["pvalue_plots"]][["BP"]]

I want to try something, directly include the u937 data in this…
both_sig <- hs_macr_sig
names(both_sig[["deseq"]][["ups"]]) <- paste0("macr_", names(both_sig[["deseq"]][["ups"]]))
names(both_sig[["deseq"]][["downs"]]) <- paste0("macr_", names(both_sig[["deseq"]][["downs"]]))
u937_deseq <- u937_sig[["deseq"]]
names(u937_deseq[["ups"]]) <- paste0("u937_", names(u937_deseq[["ups"]]))
names(u937_deseq[["downs"]]) <- paste0("u937_", names(u937_deseq[["downs"]]))
both_sig[["deseq"]][["ups"]] <- c(both_sig[["deseq"]][["ups"]], u937_deseq[["ups"]])
both_sig[["deseq"]][["downs"]] <- c(both_sig[["deseq"]][["ups"]], u937_deseq[["downs"]])
summary(both_sig[["deseq"]][["ups"]])
## Length Class Mode
## macr_z23nosb_vs_uninf 47 data.frame list
## macr_z22nosb_vs_uninf 47 data.frame list
## macr_z23nosb_vs_z22nosb 47 data.frame list
## macr_z23sb_vs_z22sb 47 data.frame list
## macr_z23sb_vs_z23nosb 47 data.frame list
## macr_z22sb_vs_z22nosb 47 data.frame list
## macr_z23sb_vs_sb 47 data.frame list
## macr_z22sb_vs_sb 47 data.frame list
## macr_z23sb_vs_uninf 47 data.frame list
## macr_z22sb_vs_uninf 47 data.frame list
## macr_sb_vs_uninf 47 data.frame list
## macr_extra_z2322 0 data.frame list
## macr_extra_drugnodrug 0 data.frame list
## u937_z23nosb_vs_uninf 47 data.frame list
## u937_z22nosb_vs_uninf 47 data.frame list
## u937_z23nosb_vs_z22nosb 47 data.frame list
## u937_z23sb_vs_z22sb 47 data.frame list
## u937_z23sb_vs_z23nosb 47 data.frame list
## u937_z22sb_vs_z22nosb 47 data.frame list
## u937_z23sb_vs_sb 47 data.frame list
## u937_z22sb_vs_sb 47 data.frame list
## u937_z23sb_vs_uninf 47 data.frame list
## u937_z22sb_vs_uninf 47 data.frame list
## u937_sb_vs_uninf 47 data.frame list
upset_plots_both <- upsetr_sig(
both_sig, both=TRUE,
contrasts=c("macr_z23sb_vs_z22sb", "macr_z23nosb_vs_z22nosb",
"u937_z23sb_vs_z22sb", "u937_z23nosb_vs_z22nosb"))
upset_plots_both$both

Compare DE
results from macrophages and U937 samples
Looking a bit more closely at these, I think the u937 data is too
sparse to effectively compare.
macr_u937_comparison <- compare_de_results(hs_macr_table, u937_table)



macr_u937_comparison$lfc_heat

macr_u937_venns <- compare_significant_contrasts(hs_macr_sig, second_sig_tables = u937_sig,
contrasts = "z23sb_vs_z23nosb")


macr_u937_venns$up_plot

macr_u937_venns$down_plot

macr_u937_venns_v2 <- compare_significant_contrasts(hs_macr_sig, second_sig_tables = u937_sig,
contrasts = "z22sb_vs_z22nosb")


macr_u937_venns_v2$up_plot

macr_u937_venns_v2$down_plot

macr_u937_venns_v3 <- compare_significant_contrasts(hs_macr_sig, second_sig_tables = u937_sig,
contrasts = "sb_vs_uninf")


macr_u937_venns_v3$up_plot

macr_u937_venns_v3$down_plot

Compare
macrophage/u937 with respect to z2.3/z2.2
comparison_df <- merge(hs_macr_table[["data"]][["z23sb_vs_z22sb"]],
u937_table[["data"]][["z23sb_vs_z22sb"]],
by = "row.names")
macru937_z23z22_plot <- plot_linear_scatter(comparison_df[, c("deseq_logfc.x", "deseq_logfc.y")])
macru937_z23z22_plot$scatter

comparison_df <- merge(hs_macr_table[["data"]][["z23nosb_vs_z22nosb"]],
u937_table[["data"]][["z23nosb_vs_z22nosb"]],
by = "row.names")
macru937_z23z22_plot <- plot_linear_scatter(comparison_df[, c("deseq_logfc.x", "deseq_logfc.y")])
macru937_z23z22_plot$scatter

Add donor to the
contrasts, no sva
no_power_fact <- paste0(pData(hs_macr)[["donor"]], "_",
pData(hs_macr)[["condition"]])
table(pData(hs_macr)[["donor"]])
##
## d01 d02 d09 d81 du937
## 13 14 13 14 14
table(no_power_fact)
## no_power_fact
## d01_inf_z22 d01_inf_z23 d01_infsb_z22 d01_infsb_z23
## 2 3 3 3
## d01_uninf_none d01_uninfsb_none d02_inf_z22 d02_inf_z23
## 1 1 3 3
## d02_infsb_z22 d02_infsb_z23 d02_uninf_none d02_uninfsb_none
## 3 3 1 1
## d09_inf_z22 d09_inf_z23 d09_infsb_z22 d09_infsb_z23
## 3 3 3 2
## d09_uninf_none d09_uninfsb_none d81_inf_z22 d81_inf_z23
## 1 1 3 3
## d81_infsb_z22 d81_infsb_z23 d81_uninf_none d81_uninfsb_none
## 3 3 1 1
## du937_inf_z22 du937_inf_z23 du937_infsb_z22 du937_infsb_z23
## 3 3 3 3
## du937_uninf_none du937_uninfsb_none
## 1 1
hs_nopower <- set_expt_conditions(hs_macr, fact = no_power_fact)
##
## d01_inf_z22 d01_inf_z23 d01_infsb_z22 d01_infsb_z23
## 2 3 3 3
## d01_uninf_none d01_uninfsb_none d02_inf_z22 d02_inf_z23
## 1 1 3 3
## d02_infsb_z22 d02_infsb_z23 d02_uninf_none d02_uninfsb_none
## 3 3 1 1
## d09_inf_z22 d09_inf_z23 d09_infsb_z22 d09_infsb_z23
## 3 3 3 2
## d09_uninf_none d09_uninfsb_none d81_inf_z22 d81_inf_z23
## 1 1 3 3
## d81_infsb_z22 d81_infsb_z23 d81_uninf_none d81_uninfsb_none
## 3 3 1 1
## du937_inf_z22 du937_inf_z23 du937_infsb_z22 du937_infsb_z23
## 3 3 3 3
## du937_uninf_none du937_uninfsb_none
## 1 1
hs_nopower <- subset_expt(hs_nopower, subset="macrophagezymodeme!='none'")
## subset_expt(): There were 68, now there are 58 samples.
hs_nopower_nosva_de <- all_pairwise(hs_nopower, model_batch = FALSE, filter = TRUE)
##
## d01_inf_z22 d01_inf_z23 d01_infsb_z22 d01_infsb_z23 d02_inf_z22
## 2 3 3 3 3
## d02_inf_z23 d02_infsb_z22 d02_infsb_z23 d09_inf_z22 d09_inf_z23
## 3 3 3 3 3
## d09_infsb_z22 d09_infsb_z23 d81_inf_z22 d81_inf_z23 d81_infsb_z22
## 3 2 3 3 3
## d81_infsb_z23 du937_inf_z22 du937_inf_z23 du937_infsb_z22 du937_infsb_z23
## 3 3 3 3 3

nopower_keepers <- list(
"d01_zymo" = c("d01infz23", "d01infz22"),
"d01_sbzymo" = c("d01infsbz23", "d01infsbz22"),
"d02_zymo" = c("d02infz23", "d02infz22"),
"d02_sbzymo" = c("d02infsbz23", "d02infsbz22"),
"d09_zymo" = c("d09infz23", "d09infz22"),
"d09_sbzymo" = c("d09infsbz23", "d09infsbz22"),
"d81_zymo" = c("d81infz23", "d81infz22"),
"d81_sbzymo" = c("d81infsbz23", "d81infsbz22"))
hs_nopower_nosva_table <- combine_de_tables(
hs_nopower_nosva_de, keepers = nopower_keepers,
excel = glue::glue("analyses/macrophage_de/hs_nopower_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_nopower_table-v202301.xlsx before writing the tables.
## extra_contrasts = extra)
hs_nopower_nosva_sig <- extract_significant_genes(
hs_nopower_nosva_table,
excel = glue::glue("analyses/macrophage_de/hs_nopower_nosva_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_nopower_nosva_sig-v202301.xlsx before writing the tables.
d01d02_zymo_nosva_comp <- merge(hs_nopower_nosva_table[["data"]][["d01_zymo"]],
hs_nopower_nosva_table[["data"]][["d02_zymo"]],
by="row.names")
d0102_zymo_nosva_plot <- plot_linear_scatter(d01d02_zymo_nosva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0102_zymo_nosva_plot$scatter

d0102_zymo_nosva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 164, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.8240 0.8351
## sample estimates:
## cor
## 0.8296
d0102_zymo_nosva_plot$lm_rsq
## [1] 0.8278
d09d81_zymo_nosva_comp <- merge(hs_nopower_nosva_table[["data"]][["d09_zymo"]],
hs_nopower_nosva_table[["data"]][["d81_zymo"]],
by="row.names")
d0981_zymo_nosva_plot <- plot_linear_scatter(d09d81_zymo_nosva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0981_zymo_nosva_plot$scatter

d0981_zymo_nosva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 88, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.6122 0.6339
## sample estimates:
## cor
## 0.6232
d0981_zymo_nosva_plot$lm_rsq
## [1] 0.4569
d01d81_zymo_nosva_comp <- merge(hs_nopower_nosva_table[["data"]][["d01_zymo"]],
hs_nopower_nosva_table[["data"]][["d81_zymo"]],
by="row.names")
d0181_zymo_nosva_plot <- plot_linear_scatter(d01d81_zymo_nosva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0181_zymo_nosva_plot$scatter

d0181_zymo_nosva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 73, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.5363 0.5611
## sample estimates:
## cor
## 0.5488
d0181_zymo_nosva_plot$lm_rsq
## [1] 0.272
upset_plots_nosva <- upsetr_sig(hs_nopower_nosva_sig, both=TRUE,
contrasts=c("d01_zymo", "d02_zymo", "d09_zymo", "d81_zymo"))
upset_plots_nosva$up

upset_plots_nosva$down

upset_plots_nosva$both

## The 7th element in the both groups list is the set shared among all donors.
## I don't feel like writing out x:y:z:a
groups <- upset_plots_nosva[["both_groups"]]
shared_genes <- attr(groups, "elements")[groups[[7]]] %>%
gsub(pattern = "^gene:", replacement = "")
shared_gp <- simple_gprofiler(shared_genes)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
shared_gp$pvalue_plots$MF

shared_gp$pvalue_plots$BP

shared_gp$pvalue_plots$REAC

shared_gp$pvalue_plots$WP

Add donor to the
contrasts, sva
hs_nopower_sva_de <- all_pairwise(hs_nopower, model_batch = "svaseq", filter = TRUE)
##
## d01_inf_z22 d01_inf_z23 d01_infsb_z22 d01_infsb_z23 d02_inf_z22
## 2 3 3 3 3
## d02_inf_z23 d02_infsb_z22 d02_infsb_z23 d09_inf_z22 d09_inf_z23
## 3 3 3 3 3
## d09_infsb_z22 d09_infsb_z23 d81_inf_z22 d81_inf_z23 d81_infsb_z22
## 3 2 3 3 3
## d81_infsb_z23 du937_inf_z22 du937_inf_z23 du937_infsb_z22 du937_infsb_z23
## 3 3 3 3 3
## Removing 0 low-count genes (12249 remaining).
## Setting 8711 low elements to zero.
## transform_counts: Found 8711 values equal to 0, adding 1 to the matrix.

nopower_keepers <- list(
"d01_zymo" = c("d01infz23", "d01infz22"),
"d01_sbzymo" = c("d01infsbz23", "d01infsbz22"),
"d02_zymo" = c("d02infz23", "d02infz22"),
"d02_sbzymo" = c("d02infsbz23", "d02infsbz22"),
"d09_zymo" = c("d09infz23", "d09infz22"),
"d09_sbzymo" = c("d09infsbz23", "d09infsbz22"),
"d81_zymo" = c("d81infz23", "d81infz22"),
"d81_sbzymo" = c("d81infsbz23", "d81infsbz22"))
hs_nopower_sva_table <- combine_de_tables(
hs_nopower_sva_de, keepers = nopower_keepers,
excel = glue::glue("analyses/macrophage_de/hs_nopower_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_nopower_table-v202301.xlsx before writing the tables.
## extra_contrasts = extra)
hs_nopower_sva_sig <- extract_significant_genes(
hs_nopower_sva_table,
excel = glue::glue("analyses/macrophage_de/hs_nopower_sva_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/hs_nopower_sva_sig-v202301.xlsx before writing the tables.
d01d02_zymo_sva_comp <- merge(hs_nopower_sva_table[["data"]][["d01_zymo"]],
hs_nopower_sva_table[["data"]][["d02_zymo"]],
by="row.names")
d0102_zymo_sva_plot <- plot_linear_scatter(d01d02_zymo_sva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0102_zymo_sva_plot$scatter

d0102_zymo_sva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 149, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.7963 0.8089
## sample estimates:
## cor
## 0.8027
d0102_zymo_sva_plot$lm_rsq
## [1] 0.7858
d09d81_zymo_sva_comp <- merge(hs_nopower_sva_table[["data"]][["d09_zymo"]],
hs_nopower_sva_table[["data"]][["d81_zymo"]],
by="row.names")
d0981_zymo_sva_plot <- plot_linear_scatter(d09d81_zymo_sva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0981_zymo_sva_plot$scatter

d0981_zymo_sva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 87, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.6091 0.6309
## sample estimates:
## cor
## 0.6202
d0981_zymo_sva_plot$lm_rsq
## [1] 0.4411
d01d81_zymo_sva_comp <- merge(hs_nopower_sva_table[["data"]][["d01_zymo"]],
hs_nopower_sva_table[["data"]][["d81_zymo"]],
by="row.names")
d0181_zymo_sva_plot <- plot_linear_scatter(d01d81_zymo_sva_comp[, c("deseq_logfc.x", "deseq_logfc.y")])
d0181_zymo_sva_plot$scatter

d0181_zymo_sva_plot$correlation
##
## Pearson's product-moment correlation
##
## data: df[[xcol]] and df[[ycol]]
## t = 66, df = 12247, p-value <2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.5000 0.5261
## sample estimates:
## cor
## 0.5131
d0181_zymo_sva_plot$lm_rsq
## [1] 0.2779
upset_plots_sva <- upsetr_sig(hs_nopower_sva_sig, both=TRUE,
contrasts=c("d01_zymo", "d02_zymo", "d09_zymo", "d81_zymo"))
upset_plots_sva$up

upset_plots_sva$down

upset_plots_sva$both

## The 7th element in the both groups list is the set shared among all donors.
## I don't feel like writing out x:y:z:a
groups <- upset_plots_sva[["both_groups"]]
shared_genes <- attr(groups, "elements")[groups[[7]]] %>%
gsub(pattern = "^gene:", replacement = "")
shared_gp <- simple_gprofiler(shared_genes)
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
## No results to show
## Please make sure that the organism is correct or set significant = FALSE
shared_gp$pvalue_plots$MF
## NULL
shared_gp$pvalue_plots$BP

shared_gp$pvalue_plots$REAC
## NULL
shared_gp$pvalue_plots$WP
## NULL
Donor
comparison
hs_donors <- set_expt_conditions(hs_macr, fact = "donor")
##
## d01 d02 d09 d81 du937
## 13 14 13 14 14
donor_de <- all_pairwise(hs_donors, model_batch="svaseq", filter=TRUE)
##
## d01 d02 d09 d81 du937
## 13 14 13 14 14
## Removing 0 low-count genes (12283 remaining).
## Setting 10588 low elements to zero.
## transform_counts: Found 10588 values equal to 0, adding 1 to the matrix.

donor_table <- combine_de_tables(
donor_de,
excel=glue::glue("analyses/macrophage_de/donor_tables-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/donor_tables-v202301.xlsx before writing the tables.
donor_sig <- extract_significant_genes(
donor_table,
excel = glue::glue("analyses/macrophage_de/donor_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/donor_sig-v202301.xlsx before writing the tables.
Primary query
contrasts
The final contrast in this list is interesting because it depends on
the extra contrasts applied to the all_pairwise() above. In my way of
thinking, the primary comparisons to consider are either cross-drug or
cross-strain, but not both. However I think in at least a few instances
Olga is interested in strain+drug / uninfected+nodrug.
Write contrast
results
Now let us write out the xlsx file containing the above contrasts.
The file with the suffix _table-version will therefore contain all genes
and the file with the suffix _sig-version will contain only those deemed
significant via our default criteria of DESeq2 |logFC| >= 1.0 and
adjusted p-value <= 0.05.
hs_macr_table <- combine_de_tables(
hs_macr_de,
keepers = tmrc2_human_keepers,
excel=glue::glue("analyses/macrophage_de/macrophage_human_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/macrophage_human_table-v202301.xlsx before writing the tables.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The deseq table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The basic table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The deseq table seems to be missing.
## Warning in combine_single_de_table(li = limma, ed = edger, eb = ebseq, de =
## deseq, : The basic table seems to be missing.
hs_macr_sig <- extract_significant_genes(
hs_macr_table,
excel=glue::glue("analyses/macrophage_de/macrophage_human_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/macrophage_human_sig-v202301.xlsx before writing the tables.
## There is no deseq_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no deseq_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no basic_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
## There is no basic_logfc column in the table.
## The columns are: ensembltranscriptid, ensemblgeneid, version, transcriptversion, hgncsymbol, description, genebiotype, cdslength, chromosomename, strand, startposition, endposition, transcript, edger_logfc, edger_adjp, limma_logfc, limma_adjp, edger_logcpm, edger_lr, edger_p, limma_ave, limma_t, limma_b, limma_p, limma_adjp_ihw, edger_adjp_ihw
u937_table <- combine_de_tables(
u937_de,
keepers = tmrc2_human_keepers,
excel=glue::glue("analyses/macrophage_de/u937_human_table-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/u937_human_table-v202301.xlsx before writing the tables.
## Warning in extract_keepers_lst(extracted, keepers, table_names,
## all_coefficients, : FOUND NEITHER z23drugnodrug_vs_z22drugnodrug NOR
## z22drugnodrug_vs_z23drugnodrug!
u937_sig <- extract_significant_genes(
u937_table,
excel=glue::glue("analyses/macrophage_de/u937_human_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/u937_human_sig-v202301.xlsx before writing the tables.
Plot contrasts of
interest
One suggestion I received recently was to set the axes for these
volcano plots to be static rather than let ggplot choose its own. I am
assuming this is only relevant for pairs of contrasts, but that might
not be true.
Individual zymodemes
vs. uninfected
z23nosb_vs_uninf_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z23nosb_vs_uninf"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z23nosb_vs_uninf_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
z22nosb_vs_uninf_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z22nosb_vs_uninf"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z22nosb_vs_uninf_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[3L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[3L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[3L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
Zymodeme 2.3
without drug vs. uninfected
z23nosb_vs_uninf_volcano$plot +
xlim(-10, 25) +
ylim(0, 40)

pp(file="images/z23_uninf_reactome_up.png", image=all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z23_uninf_reactome_up.png", image =
## all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["REAC"]], : There is no
## device to shut down.
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["KEGG"]]
## KEGG, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_uninf_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_uninf_up"]][["interactive_plots"]][["WP"]]
all_gp[["z23nosb_vs_uninf_down"]][["pvalue_plots"]][["REAC"]]
## NULL
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23nosb_vs_uninf_down"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23nosb_vs_uninf_down"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
z22nosb_vs_uninf_volcano$plot +
xlim(-10, 25) +
ylim(0, 40)
## Warning: ggrepel: 8 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pp(file="images/z22_uninf_reactome_up.png", image=all_gp[["z22nosb_vs_uninf_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z22_uninf_reactome_up.png", image =
## all_gp[["z22nosb_vs_uninf_up"]][["pvalue_plots"]][["REAC"]], : There is no
## device to shut down.
## Reactome, zymodeme2.2 without drug vs. uninfected without drug, up.
all_gp[["z22nosb_vs_uninf_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.2 without drug vs. uninfected without drug, up.
all_gp[["z22nosb_vs_uninf_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.2 without drug vs. uninfected without drug, up.
all_gp[["z22nosb_vs_uninf_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.2 without drug vs. uninfected without drug, up.
all_gp[["z22nosb_vs_uninf_down"]][["pvalue_plots"]][["REAC"]]
## NULL
## Reactome, zymodeme2.2 without drug vs. uninfected without drug, down.
all_gp[["z22nosb_vs_uninf_down"]][["pvalue_plots"]][["MF"]]
## NULL
## MF, zymodeme2.2 without drug vs. uninfected without drug, down.
all_gp[["z22nosb_vs_uninf_down"]][["pvalue_plots"]][["TF"]]
## NULL
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
Check that my perception of the number of significant up/down genes
matches what the table/venn says.
shared <- Vennerable::Venn(list("drug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z23sb_vs_uninf"]]),
"nodrug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z23nosb_vs_uninf"]])))
pp(file="images/z23_vs_uninf_venn_up.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
Vennerable::plot(shared)

## I see 910 z23sb/uninf and 670 no z23nosb/uninf genes in the venn diagram.
length(shared@IntersectionSets[["10"]]) + length(shared@IntersectionSets[["11"]])
## [1] 720
dim(hs_macr_sig[["deseq"]][["ups"]][["z23sb_vs_uninf"]])
## [1] 720 47
shared <- Vennerable::Venn(list("drug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z22sb_vs_uninf"]]),
"nodrug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z22nosb_vs_uninf"]])))
pp(file="images/z22_vs_uninf_venn_up.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
Vennerable::plot(shared)

length(shared@IntersectionSets[["10"]]) + length(shared@IntersectionSets[["11"]])
## [1] 644
dim(hs_macr_sig[["deseq"]][["ups"]][["z22sb_vs_uninf"]])
## [1] 644 47
Note to self: There is an error in my volcano plot code
which takes effect when the numerator and denominator of the
all_pairwise contrasts are different than those in combine_de_tables. It
is putting the ups/downs on the correct sides of the plot, but calling
the down genes ‘up’ and vice-versa. The reason for this is that I did a
check for this happening, but used the wrong argument to handle it.
A likely bit of text for these volcano plots:
The set of genes differentially expressed between the zymodeme 2.3
and uninfected samples without druge treatment was quantified with
DESeq2 and included surrogate estimates from SVA. Given the criteria of
significance of a abs(logFC) >= 1.0 and false discovery rate adjusted
p-value <= 0.05, 670 genes were observed as significantly increased
between the infected and uninfected samples and 386 were observed as
decreased. The most increased genes from the uninfected samples include
some which are potentially indicative of a strong innate immune response
and the inflammatory response.
In contrast, when the set of genes differentially expressed between
the zymodeme 2.2 and uninfected samples was visualized, only 7 genes
were observed as decreased and 435 increased. The inflammatory response
was significantly less apparent in this set, but instead included genes
related to transporter activity and oxidoreductases.
Direct zymodeme
comparisons
An orthogonal comparison to that performed above is to directly
compare the zymodeme 2.3 and 2.2 samples with and without antimonial
treatment.
z23nosb_vs_z22nosb_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z23nosb_vs_z22nosb"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z23nosb_vs_z22nosb_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
z23sb_vs_z22sb_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z23sb_vs_z22sb"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z23sb_vs_z22sb_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
z23nosb_vs_z22nosb_volcano$plot +
xlim(-10, 10) +
ylim(0, 60)
## Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pp(file="images/z23nosb_vs_z22nosb_reactome_up.png", image=all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z23nosb_vs_z22nosb_reactome_up.png", image =
## all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["REAC"]], : There is no
## device to shut down.
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["KEGG"]]
## KEGG, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_z22nosb_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23nosb_vs_z22nosb_up"]][["interactive_plots"]][["WP"]]
all_gp[["z23nosb_vs_z22nosb_down"]][["pvalue_plots"]][["REAC"]]
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23nosb_vs_z22nosb_down"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23nosb_vs_z22nosb_down"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
z23sb_vs_z22sb_volcano$plot +
xlim(-10, 10) +
ylim(0, 60)
## Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pp(file="images/z23sb_vs_z22sb_reactome_up.png", image=all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z23sb_vs_z22sb_reactome_up.png", image =
## all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["REAC"]], : There is no device
## to shut down.
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["KEGG"]]
## KEGG, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z22sb_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z22sb_up"]][["interactive_plots"]][["WP"]]
all_gp[["z23sb_vs_z22sb_down"]][["pvalue_plots"]][["REAC"]]
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23sb_vs_z22sb_down"]][["pvalue_plots"]][["MF"]]
## NULL
## MF, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23sb_vs_z22sb_down"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
shared <- Vennerable::Venn(list("drug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z23sb_vs_z22sb"]]),
"nodrug" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z23nosb_vs_z22nosb"]])))
pp(file="images/drug_nodrug_venn_up.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
Vennerable::plot(shared)

shared <- Vennerable::Venn(list("drug" = rownames(hs_macr_sig[["deseq"]][["downs"]][["z23sb_vs_z22sb"]]),
"nodrug" = rownames(hs_macr_sig[["deseq"]][["downs"]][["z23nosb_vs_z22nosb"]])))
pp(file="images/drug_nodrug_venn_down.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
A slightly different way of looking at the differences between the
two zymodeme infections is to directly compare the infected samples with
and without drug. Thus, when a volcano plot showing the comparison of
the zymodeme 2.3 vs. 2.2 samples was plotted, 484 genes were observed as
increased and 422 decreased; these groups include many of the same
inflammatory (up) and membrane (down) genes.
Similar patterns were observed when the antimonial was included.
Thus, when a Venn diagram of the two sets of increased genes was
plotted, a significant number of the genes was observed as increased
(313) and decreased (244) in both the untreated and antimonial treated
samples.
Drug effects on each
zymodeme infection
Another likely question is to directly compare the treated vs
untreated samples for each zymodeme infection in order to visualize the
effects of antimonial.
z23sb_vs_z23nosb_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z23sb_vs_z23nosb"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z23sb_vs_z23nosb_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
z22sb_vs_z22nosb_volcano <- plot_volcano_de(
table = hs_macr_table[["data"]][["z22sb_vs_z22nosb"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(z22sb_vs_z22nosb_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
z23sb_vs_z23nosb_volcano$plot +
xlim(-8, 8) +
ylim(0, 210)
## Warning: ggrepel: 8 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

pp(file="images/z23sb_vs_z23nosb_reactome_up.png",
image=all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z23sb_vs_z23nosb_reactome_up.png", image =
## all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["REAC"]], : There is no
## device to shut down.
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["KEGG"]]
## KEGG, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z23nosb_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z23sb_vs_z23nosb_up"]][["interactive_plots"]][["WP"]]
all_gp[["z23sb_vs_z23nosb_down"]][["pvalue_plots"]][["REAC"]]
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23sb_vs_z23nosb_down"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z23sb_vs_z23nosb_down"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
z22sb_vs_z22nosb_volcano$plot +
xlim(-8, 8) +
ylim(0, 210)
## Warning: Removed 1 rows containing missing values (`geom_point()`).

pp(file="images/z22sb_vs_z22nosb_reactome_up.png",
image=all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["REAC"]], height=12, width=9)
## Warning in pp(file = "images/z22sb_vs_z22nosb_reactome_up.png", image =
## all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["REAC"]], : There is no
## device to shut down.
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["KEGG"]]
## KEGG, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z22sb_vs_z22nosb_up"]][["pvalue_plots"]][["WP"]]
## WikiPathways, zymodeme2.3 without drug vs. uninfected without drug, up.
all_gp[["z22sb_vs_z22nosb_up"]][["interactive_plots"]][["WP"]]
all_gp[["z22sb_vs_z22nosb_down"]][["pvalue_plots"]][["REAC"]]
## Reactome, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z22sb_vs_z22nosb_down"]][["pvalue_plots"]][["MF"]]
## MF, zymodeme2.3 without drug vs. uninfected without drug, down.
all_gp[["z22sb_vs_z22nosb_down"]][["pvalue_plots"]][["TF"]]
## TF, zymodeme2.3 without drug vs. uninfected without drug, down.
shared <- Vennerable::Venn(list("z23" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z23sb_vs_z23nosb"]]),
"z22" = rownames(hs_macr_sig[["deseq"]][["ups"]][["z22sb_vs_z22nosb"]])))
pp(file="images/z23_z22_drug_venn_up.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
Vennerable::plot(shared)

shared <- Vennerable::Venn(list("z23" = rownames(hs_macr_sig[["deseq"]][["downs"]][["z23sb_vs_z23nosb"]]),
"z22" = rownames(hs_macr_sig[["deseq"]][["downs"]][["z22sb_vs_z22nosb"]])))
pp(file="images/z23_z22_drug_venn_down.png")
Vennerable::plot(shared)
dev.off()
## png
## 2
Vennerable::plot(shared)

Note: I am settig the x and y-axis boundaries by allowing the plotter
to pick its own axis the first time, writing down the ranges I observe,
and then setting them to the largest of the pair. It is therefore
possible that I missed one or more genes which lies outside that
range.
The previous plotted contrasts sought to show changes between the two
strains z2.3 and z2.2. Conversely, the previous volcano plots seek to
directly compare each strain before/after drug treatment.
LRT of the Human
Macrophage
tmrc2_lrt_strain_drug <- deseq_lrt(hs_macr, interactor_column = "drug",
interest_column = "macrophagezymodeme", factors = c("drug", "macrophagezymodeme"))
## converting counts to integer mode
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
## -- replacing outliers and refitting for 517 genes
## -- DESeq argument 'minReplicatesForReplace' = 7
## -- original counts are preserved in counts(dds)
## estimating dispersions
## fitting model and testing
## rlog() may take a long time with 50 or more samples,
## vst() is a much faster transformation
## Working with 138 genes.
## Working with 138 genes after filtering: minc > 3
## Joining with `by = join_by(merge)`
## Joining with `by = join_by(merge)`

tmrc2_lrt_strain_drug$cluster_data$plot

Parasite
lp_macrophage_de <- all_pairwise(lp_macrophage,
model_batch="svaseq", filter=TRUE)
##
## z2.2 z2.3
## 11 9
## Removing 0 low-count genes (8541 remaining).
## Setting 134 low elements to zero.
## transform_counts: Found 134 values equal to 0, adding 1 to the matrix.
tmrc2_parasite_keepers <- list(
"z23_vs_z22" = c("z23", "z22"))
lp_macrophage_table <- combine_de_tables(
lp_macrophage_de, keepers = tmrc2_parasite_keepers,
excel=glue::glue("analyses/macrophage_de/macrophage_parasite_infection_de-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/macrophage_parasite_infection_de-v202301.xlsx before writing the tables.
lp_macrophage_sig <- extract_significant_genes(
lp_macrophage_table,
excel=glue::glue("analyses/macrophage_de/macrophage_parasite_sig-v{ver}.xlsx"))
## Deleting the file analyses/macrophage_de/macrophage_parasite_sig-v202301.xlsx before writing the tables.
pp(file="images/lp_macrophage_z23_z22.png",
image=lp_macrophage_table[["plots"]][["z23nosb_vs_z22nosb"]][["deseq_vol_plots"]][["plot"]])
up_genes <- lp_macrophage_sig[["deseq"]][["ups"]][[1]]
dim(up_genes)
## [1] 47 58
down_genes <- lp_macrophage_sig[["deseq"]][["downs"]][[1]]
dim(down_genes)
## [1] 88 58
lp_z23sb_vs_z22sb_volcano <- plot_volcano_de(
table = lp_macrophage_table[["data"]][["z23_vs_z22"]],
fc_col = "deseq_logfc", p_col = "deseq_adjp",
shapes_by_state = FALSE, color_by = "fc", label = 10, label_column = "hgncsymbol")
plotly::ggplotly(lp_z23sb_vs_z22sb_volcano$plot)
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
## Warning in geom2trace.default(dots[[1L]][[2L]], dots[[2L]][[1L]], dots[[3L]][[1L]]): geom_GeomTextRepel() has yet to be implemented in plotly.
## If you'd like to see this geom implemented,
## Please open an issue with your example code at
## https://github.com/ropensci/plotly/issues
lp_z23sb_vs_z22sb_volcano$plot
## Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

up_goseq <- simple_goseq(up_genes, go_db=lp_go, length_db=lp_lengths)
## Found 16 go_db genes and 47 length_db genes out of 47.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## View categories over represented in the 2.3 samples
up_goseq$pvalue_plots$bpp_plot_over

down_goseq <- simple_goseq(down_genes, go_db=lp_go, length_db=lp_lengths)
## Found 28 go_db genes and 88 length_db genes out of 88.
## Testing that go categories are defined.
## Removing undefined categories.
## Gathering synonyms.
## Gathering category definitions.
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## The score column is null, defaulting to score.
## Possible columns are:
## [1] "category" "over_represented_pvalue"
## [3] "under_represented_pvalue" "numDEInCat"
## [5] "numInCat" "term"
## [7] "ontology" "qvalue"
## View categories over represented in the 2.2 samples
down_goseq$pvalue_plots$bpp_plot_over

GSVA
hs_infected <- subset_expt(hs_macrophage, subset="macrophagetreatment!='uninf'") %>%
subset_expt(subset="macrophagetreatment!='uninf_sb'")
## subset_expt(): There were 68, now there are 63 samples.
## subset_expt(): There were 63, now there are 63 samples.
hs_gsva_c2 <- simple_gsva(hs_infected)
## Converting the rownames() of the expressionset to ENTREZID.
## 1630 ENSEMBL ID's didn't have a matching ENTEREZ ID. Dropping them now.
## Before conversion, the expressionset has 21481 entries.
## After conversion, the expressionset has 20006 entries.
hs_gsva_c2_meta <- get_msigdb_metadata(hs_gsva_c2, msig_xml="reference/msigdb_v7.2.xml")
## The downloaded msigdb contained 2725 rownames shared with the gsva result out of 2989.
hs_gsva_c2_sig <- get_sig_gsva_categories(hs_gsva_c2_meta, excel = "analyses/macrophage_de/hs_macrophage_gsva_c2_sig.xlsx")
## Length Class Mode
## title 1 -none- character
## notes 1 -none- character
## initial_metadata 70 data.frame list
## expressionset 1 ExpressionSet S4
## design 70 data.frame list
## conditions 63 -none- character
## batches 63 -none- character
## samplenames 63 -none- character
## colors 63 -none- character
## state 5 -none- list
## libsize 63 -none- numeric
## Starting limma pairwise comparison.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$libsize.
## Limma step 1/6: choosing model.
## Assuming this data is similar to a micro array and not performign voom.
## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## Limma step 5/6: Running eBayes with robust = FALSE and trend = FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/3: Creating table: infsb_vs_inf. Adjust = BH
## Limma step 6/6: 2/3: Creating table: uninfsb_vs_inf. Adjust = BH
## Limma step 6/6: 3/3: Creating table: uninfsb_vs_infsb. Adjust = BH
## Limma step 6/6: 1/3: Creating table: inf. Adjust = BH
## Limma step 6/6: 2/3: Creating table: infsb. Adjust = BH
## Limma step 6/6: 3/3: Creating table: uninfsb. Adjust = BH
## Length Class Mode
## title 1 -none- character
## notes 1 -none- character
## initial_metadata 70 data.frame list
## expressionset 1 ExpressionSet S4
## design 70 data.frame list
## conditions 63 -none- character
## batches 63 -none- character
## samplenames 63 -none- character
## colors 63 -none- character
## state 5 -none- list
## libsize 63 -none- numeric
## The factor inf has 29 rows.
## The factor inf_sb has 29 rows.
## The factor uninf_sb has 5 rows.
## Testing each factor against the others.
## Scoring inf against everything else.
## Scoring inf_sb against everything else.
## Scoring uninf_sb against everything else.
## Deleting the file analyses/macrophage_de/hs_macrophage_gsva_c2_sig.xlsx before writing the tables.
hs_gsva_c2_sig$raw_plot

hs_gsva_c7 <- simple_gsva(hs_infected, signature_category = "c7")
## Converting the rownames() of the expressionset to ENTREZID.
## 1630 ENSEMBL ID's didn't have a matching ENTEREZ ID. Dropping them now.
## Before conversion, the expressionset has 21481 entries.
## After conversion, the expressionset has 20006 entries.
hs_gsva_c7_meta <- get_msigdb_metadata(hs_gsva_c7, msig_xml="reference/msigdb_v7.2.xml")
## The downloaded msigdb contained 2725 rownames shared with the gsva result out of 2989.
hs_gsva_c7_sig <- get_sig_gsva_categories(hs_gsva_c7, excel = "analyses/macrophage_de/hs_macrophage_gsva_c7_sig.xlsx")
## Length Class Mode
## title 1 -none- character
## notes 1 -none- character
## initial_metadata 70 data.frame list
## expressionset 1 ExpressionSet S4
## design 70 data.frame list
## conditions 63 -none- character
## batches 63 -none- character
## samplenames 63 -none- character
## colors 63 -none- character
## state 5 -none- list
## libsize 63 -none- numeric
## Starting limma pairwise comparison.
## libsize was not specified, this parameter has profound effects on limma's result.
## Using the libsize from expt$libsize.
## Limma step 1/6: choosing model.
## Assuming this data is similar to a micro array and not performign voom.
## Limma step 3/6: running lmFit with method: ls.
## Limma step 4/6: making and fitting contrasts with no intercept. (~ 0 + factors)
## Limma step 5/6: Running eBayes with robust = FALSE and trend = FALSE.
## Limma step 6/6: Writing limma outputs.
## Limma step 6/6: 1/3: Creating table: infsb_vs_inf. Adjust = BH
## Limma step 6/6: 2/3: Creating table: uninfsb_vs_inf. Adjust = BH
## Limma step 6/6: 3/3: Creating table: uninfsb_vs_infsb. Adjust = BH
## Limma step 6/6: 1/3: Creating table: inf. Adjust = BH
## Limma step 6/6: 2/3: Creating table: infsb. Adjust = BH
## Limma step 6/6: 3/3: Creating table: uninfsb. Adjust = BH
## Length Class Mode
## title 1 -none- character
## notes 1 -none- character
## initial_metadata 70 data.frame list
## expressionset 1 ExpressionSet S4
## design 70 data.frame list
## conditions 63 -none- character
## batches 63 -none- character
## samplenames 63 -none- character
## colors 63 -none- character
## state 5 -none- list
## libsize 63 -none- numeric
## The factor inf has 29 rows.
## The factor inf_sb has 29 rows.
## The factor uninf_sb has 5 rows.
## Testing each factor against the others.
## Scoring inf against everything else.
## Scoring inf_sb against everything else.
## Scoring uninf_sb against everything else.
## Deleting the file analyses/macrophage_de/hs_macrophage_gsva_c7_sig.xlsx before writing the tables.
hs_gsva_c7_sig$raw_plot
LS0tCnRpdGxlOiAiVE1SQzIgMjAyMzAxOiBNYWNyb3BoYWdlIERpZmZlcmVudGlhbCBFeHByZXNzaW9uLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgIGNvbGxhcHNlZDogZmFsc2UKICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoSGVhdHBsdXMpCmxpYnJhcnkoaHBnbHRvb2xzKQp0dCA8LSBkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikKa25pdHI6Om9wdHNfa25pdCRzZXQocHJvZ3Jlc3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSA5MCwKICAgICAgICAgICAgICAgICAgICAgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA4LAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICBkcGkgPSA5NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHMgPSA0LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjMwMSIKcHJldmlvdXNfZmlsZSA8LSAiIgpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQgPSAiJVklbSVkIikKCiMjIHRtcCA8LSB0cnkoc20obG9hZG1lKGZpbGVuYW1lID0gZ3N1YihwYXR0ZXJuID0gIlxcLlJtZCIsIHJlcGxhY2UgPSAiXFwucmRhXFwueHoiLCB4ID0gcHJldmlvdXNfZmlsZSkpKSkKcm1kX2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgidG1yYzJfbWFjcm9waGFnZV9kaWZmZXJlbnRpYWxfZXhwcmVzc2lvbl97dmVyfS5SbWQiKQpsb2FkZWQgPC0gbG9hZChmaWxlID0gZ2x1ZTo6Z2x1ZSgicmRhL3RtcmMyX2RhdGFfc3RydWN0dXJlcy12e3Zlcn0ucmRhIikpCnNhdmVmaWxlIDwtIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLCByZXBsYWNlID0gIlxcLnJkYVxcLnh6IiwgeCA9IHJtZF9maWxlKQpsaWJyYXJ5KFVwU2V0UikKYGBgCgojIEludHJvZHVjdGlvbgoKSGF2aW5nIGVzdGFibGlzaGVkIHRoYXQgdGhlIFRNUkMyIG1hY3JvcGhhZ2UgZGF0YSBsb29rcyByb2J1c3QgYW5kCmlsbHVzdHJhdGl2ZSBvZiBhIGNvdXBsZSBvZiBpbnRlcmVzdGluZyBxdWVzdGlvbnMsIGxldCB1cyBwZXJmb3JtIGEKY291cGxlIG9mIGRpZmZlcmVudGlhbCBhbmFseXNlcyBvZiBpdC4KCkFsc28gbm90ZSB0aGF0IGFzIG9mIDIwMjIxMiwgd2UgcmVjZWl2ZWQgYSBuZXcgc2V0IG9mIHNhbXBsZXMgd2hpY2gKbm93IGluY2x1ZGUgc29tZSB3aGljaCBhcmUgb2YgYSBjb21wbGV0ZWx5IGRpZmZlcmVudCBjZWxsIHR5cGUsClU5MzcuIEFzIHRoZWlyIEFUQ0MgcGFnZSBzdGF0ZXMsIHRoZXkgYXJlIG1hbGlnbmFudCBjZWxscyB0YWtlbiBmcm9tCnRoZSBwbGV1cmFsIGVmZnVzaW9uIG9mIGEgMzcgeWVhciBvbGQgd2hpdGUgbWFsZSB3aXRoIGhpc3Rpb2N5dGljCmx5bXBob21hIGFuZCB3aGljaCBleGhpYml0IHRoZSBtb3JwaG9sb2d5IG9mIG1vbm9jeXRlcy4gIFRodXMsIHRoaXMKZG9jdW1lbnQgbm93IGluY2x1ZGVzIHNvbWUgY29tcGFyaXNvbnMgb2YgdGhlIGNlbGwgdHlwZXMgYXMgd2VsbCBhcwp0aGUgdmFyaW91cyBtYWNyb3BoYWdlIGRvbm9ycyAoZ2l2ZW4gdGhhdCB0aGVyZSBhcmUgbm93IG1vcmUgZG9ub3JzCnRvbykuCgojIyBIdW1hbiBkYXRhCgpJIGFtIG1vdmluZyB0aGUgZGF0YXNldCBtYW5pcHVsYXRpb25zIGhlcmUgc28gdGhhdCBJIGNhbiBsb29rIGF0IHRoZW0KYWxsIHRvZ2V0aGVyIGJlZm9yZSBydW5uaW5nIHRoZSB2YXJpb3VzIERFIGFuYWx5c2VzLgoKIyMgQ3JlYXRlIHNldHMgZm9jdXNlZCBvbiBkcnVnLCBjZWxsdHlwZSwgc3RyYWluLCBhbmQgY29tYmluYXRpb25zCgpMZXQgdXMgc3RhcnQgYnkgcGxheWluZyB3aXRoIHRoZSBtZXRhZGF0YSBhIGxpdHRsZSBhbmQgY3JlYXRlIHNldHMKd2l0aCB0aGUgY29uZGl0aW9uIHNldCB0bzoKCiogRHJ1ZyB0cmVhdG1lbnQKKiBDZWxsIHR5cGUgKG1hY3JvcGhhZ2Ugb3IgVTkzNykKKiBEb25vcgoqIEluZmVjdGlvbiBTdHJhaW4KKiBTb21lIHVzZWZ1bCBjb21iaW5hdGlvbnMgdGhlcmVvZgoKSW4gYWRkaXRpb24sIGtlZXAgbWVudGFsIHRyYWNrIG9mIHdoaWNoIGRhdGFzZXRzIGFyZSBjb21wcmlzZWQgb2YgYWxsCnNhbXBsZXMgdnMuIHRob3NlIHdoaWNoIGFyZSBvbmx5IG1hY3JvcGhhZ2UgdnMuIHRob3NlIHdoaWNoIGFyZSBvbmx5ClU5MzcuICAoVGh1cywgdGhlIHVzYWdlIG9mIGFsbF9odW1hbiB2cy4gaHNfbWFjciB2cy4gdTkzNyBhcyBwcmVmaXhlcwpmb3IgdGhlIGRhdGEgc3RydWN0dXJlcy4pCgpJZGVhbGx5LCB0aGVzZSByZWNyZWF0aW9ucyBvZiB0aGUgZGF0YSBzaG91bGQgcGVyaGFwcyBiZSBpbiB0aGUKZGF0YXN0cnVjdHVyZXMgd29ya3NoZWV0LgoKYGBge3IgZGVfZGF0YXNldHN9CmFsbF9odW1hbiA8LSBzYW5pdGl6ZV9leHB0X21ldGFkYXRhKGhzX21hY3JvcGhhZ2UsIGNvbHVtbnMgPSAiZHJ1ZyIpICU+JQogIHNldF9leHB0X2NvbmRpdGlvbnMoZmFjdCA9ICJkcnVnIikgJT4lCiAgc2V0X2V4cHRfYmF0Y2hlcyhmYWN0ID0gInR5cGVvZmNlbGxzIikKCiMjIFRoZSBmb2xsb3dpbmcgMyBsaW5lcyB3ZXJlIGNvcHkvcGFzdGVkIHRvIGRhdGFzdHJ1Y3R1cmVzIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCBzb29uLgpub19zdHJhaW5faWR4IDwtIHBEYXRhKGFsbF9odW1hbilbWyJzdHJhaW5pZCJdXSA9PSAibm9uZSIKIyNwRGF0YShhbGxfaHVtYW4pW1sic3RyYWluaWQiXV0gPC0gcGFzdGUwKCJzIiwgcERhdGEoYWxsX2h1bWFuKVtbInN0cmFpbmlkIl1dLAojIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIl8iLCBwRGF0YShhbGxfaHVtYW4pW1sibWFjcm9waGFnZXp5bW9kZW1lIl1dKQpwRGF0YShhbGxfaHVtYW4pW25vX3N0cmFpbl9pZHgsICJzdHJhaW5pZCJdIDwtICJub25lIgp0YWJsZShwRGF0YShhbGxfaHVtYW4pW1sic3RyYWluaWQiXV0pCgphbGxfaHVtYW5fdHlwZXMgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhhbGxfaHVtYW4sIGZhY3QgPSAidHlwZW9mY2VsbHMiKSAlPiUKICBzZXRfZXhwdF9iYXRjaGVzKGZhY3QgPSAiZHJ1ZyIpCgp0eXBlX3p5bW9fZmFjdCA8LSBwYXN0ZTAocERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbImNvbmRpdGlvbiJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgcERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbIm1hY3JvcGhhZ2V6eW1vZGVtZSJdXSkKdHlwZV96eW1vIDwtIHNldF9leHB0X2NvbmRpdGlvbnMoYWxsX2h1bWFuX3R5cGVzLCBmYWN0ID0gdHlwZV96eW1vX2ZhY3QpCgp0eXBlX2RydWdfZmFjdCA8LSBwYXN0ZTAocERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbImNvbmRpdGlvbiJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgcERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbImRydWciXV0pCnR5cGVfZHJ1ZyA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGFsbF9odW1hbl90eXBlcywgZmFjdCA9IHR5cGVfZHJ1Z19mYWN0KQoKc3RyYWluX2ZhY3QgPC0gcERhdGEoYWxsX2h1bWFuX3R5cGVzKVtbInN0cmFpbmlkIl1dCnRhYmxlKHN0cmFpbl9mYWN0KQoKbmV3X2NvbmRpdGlvbnMgPC0gcGFzdGUwKHBEYXRhKGhzX21hY3JvcGhhZ2UpW1sibWFjcm9waGFnZXRyZWF0bWVudCJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgcERhdGEoaHNfbWFjcm9waGFnZSlbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCiMjIE5vdGUgdGhlIHNhbml0aXplKCkgY2FsbCBpcyByZWR1bmRhbnQgd2l0aCB0aGUgYWRkaXRpb24gb2Ygc2FuaXRpemUoKSBpbiB0aGUKIyMgZGF0YXN0cnVjdHVyZXMgZmlsZSwgYnV0IEkgZG9uJ3Qgd2FudCB0byB3YWl0IHRvIHJlcnVuIHRoYXQuCmhzX21hY3IgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhoc19tYWNyb3BoYWdlLCBmYWN0ID0gbmV3X2NvbmRpdGlvbnMpICU+JQogIHNhbml0aXplX2V4cHRfbWV0YWRhdGEoY29sdW1uID0gImRydWciKQpgYGAKCiMjIyBTZXBhcmF0ZSBNYWNyb3BoYWdlIHNhbXBsZXMKCk9uY2UgYWdhaW4sIHdlIHNob3VsZCByZWNvbnNpZGVyIHdoZXJlIHRoZSBmb2xsb3dpbmcgYmxvY2sgaXMgcGxhY2VkLApidXQgdGhlc2UgZGF0YXN0cnVjdHVyZXMgYXJlIGxpa2VseSB0byBiZSB1c2VkIGluIG1hbnkgb2YgdGhlCmZvbGxvd2luZyBhbmFseXNlcy4KCmBgYHtyIGhzX21hY3JfZHJ1Z19zdHJhaW59CmhzX21hY3JfZHJ1Z19leHB0IDwtIHNldF9leHB0X2NvbmRpdGlvbnMoaHNfbWFjciwgZmFjdCA9ICJkcnVnIikKCmhzX21hY3Jfc3RyYWluX2V4cHQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhoc19tYWNyLCBmYWN0ID0gIm1hY3JvcGhhZ2V6eW1vZGVtZSIpICU+JQogIHN1YnNldF9leHB0KHN1YnNldCA9ICJtYWNyb3BoYWdlenltb2RlbWUgIT0gJ25vbmUnIikKCnRhYmxlKHBEYXRhKGhzX21hY3IpW1sic3RyYWluaWQiXV0pCmBgYAoKIyMjIFJlZmFjdG9yIFU5Mzcgc2FtcGxlcwoKVGhlIFU5Mzcgc2FtcGxlcyB3ZXJlIHNlcGFyYXRlZCBpbiB0aGUgZGF0YXN0cnVjdHVyZXMgZmlsZSwgYnV0IHdlCndhbnQgdG8gdXNlIHRoZSBjb21iaW5hdGlvbiBvZiBkcnVnL3p5bW9kZW1lIHdpdGggdGhlbSBwcmV0dHkgbXVjaApleGNsdXNpdmVseS4KCmBgYHtyIHU5Mzdfc2FtcGxlc30KbmV3X2NvbmRpdGlvbnMgPC0gcGFzdGUwKHBEYXRhKGhzX3U5MzcpW1sibWFjcm9waGFnZXRyZWF0bWVudCJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgcERhdGEoaHNfdTkzNylbWyJtYWNyb3BoYWdlenltb2RlbWUiXV0pCnU5MzdfZXhwdCA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGhzX3U5MzcsIGZhY3QgPSBuZXdfY29uZGl0aW9ucykKYGBgCgojIyBDb250cmFzdHMgdXNlZCBpbiB0aGlzIGRvY3VtZW50CgpHaXZlbiB0aGUgdmFyaW91cyB3YXlzIHdlIGhhdmUgY2hvcHBlZCB1cCB0aGlzIGRhdGFzZXQsIHRoZXJlIGFyZSBhCmZldyBnZW5lcmFsIHR5cGVzIG9mIGNvbnRyYXN0cyB3ZSB3aWxsIHBlcmZvcm0sIHdoaWNoIHdpbGwgdGhlbiBiZQpjb21iaW5lZCBpbnRvIGdyZWF0ZXIgY29tcGxleGl0eToKCiogZHJ1ZyB0cmVhdG1lbnQKKiBzdHJhaW5zIHVzZWQKKiBjZWxsbHR5cGVzCiogZG9ub3JzCgpJbiB0aGUgZW5kLCBvdXIgYWN0dWFsIGdvYWwgaXMgdG8gY29uc2lkZXIgdGhlIHZhcmlhYmxlIGVmZmVjdHMgb2YKZHJ1ZytzdHJhaW4gYW5kIHNlZSBpZiB3ZSBjYW4gZGlzY2VybiBwYXR0ZXJucyB3aGljaCBsZWFkIHRvIGJldHRlciBvcgp3b3JzZSBkcnVnIHRyZWF0bWVudCBvdXRjb21lLgoKVGhlcmUgaXMgYSBzZXQgb2YgY29udHJhc3RzIGluIHdoaWNoIHdlIGFyZSBwcmltYXJpbHkgaW50ZXJlc3RlZCBpbgp0aGlzIGRhdGEsIHRoZXNlIGZvbGxvdy4gIEkgY3JlYXRlZCBvbmUgcmF0aW8gb2YgcmF0aW9zIGNvbnRyYXN0IHdoaWNoCkkgdGhpbmsgaGFzIHRoZSBwb3RlbnRpYWwgdG8gYXNrIG91ciBiaWdnZXN0IHF1ZXN0aW9uLgoKYGBge3IgdHVtcmMyX2h1bWFuX2tlZXBlcnN9CnRtcmMyX2h1bWFuX2V4dHJhIDwtICJ6MjNkcnVnbm9kcnVnX3ZzX3oyMmRydWdub2RydWcgPSAoaW5mc2J6MjMgLSBpbmZ6MjMpIC0gKGluZnNiejIyIC0gaW5mejIyKSwgejIzejIyZHJ1Z192c196MjN6MjJub2RydWcgPSAoaW5mc2J6MjMgLSBpbmZzYnoyMikgLSAoaW5mejIzIC0gaW5mejIyKSIKdG1yYzJfaHVtYW5fa2VlcGVycyA8LSBsaXN0KAogICAgInoyM25vc2JfdnNfdW5pbmYiID0gYygiaW5mejIzIiwgInVuaW5mbm9uZSIpLAogICAgInoyMm5vc2JfdnNfdW5pbmYiID0gYygiaW5mejIyIiwgInVuaW5mbm9uZSIpLAogICAgInoyM25vc2JfdnNfejIybm9zYiIgPSBjKCJpbmZ6MjMiLCAiaW5mejIyIiksCiAgICAiejIzc2JfdnNfejIyc2IiID0gYygiaW5mc2J6MjMiLCAiaW5mc2J6MjIiKSwKICAgICJ6MjNzYl92c196MjNub3NiIiA9IGMoImluZnNiejIzIiwgImluZnoyMyIpLAogICAgInoyMnNiX3ZzX3oyMm5vc2IiID0gYygiaW5mc2J6MjIiLCAiaW5mejIyIiksCiAgICAiejIzc2JfdnNfc2IiID0gYygiaW5mejIzIiwgInVuaW5mc2Jub25lIiksCiAgICAiejIyc2JfdnNfc2IiID0gYygiaW5mejIyIiwgInVuaW5mc2Jub25lIiksCiAgICAiejIzc2JfdnNfdW5pbmYiID0gYygiaW5mc2J6MjMiLCAidW5pbmZub25lIiksCiAgICAiejIyc2JfdnNfdW5pbmYiID0gYygiaW5mc2J6MjIiLCAidW5pbmZub25lIiksCiAgICAic2JfdnNfdW5pbmYiID0gYygidW5pbmZzYm5vbmUiLCAidW5pbmZub25lIiksCiAgICAiZXh0cmFfejIzMjIiID0gYygiejIzZHJ1Z25vZHJ1ZyIsICJ6MjJkcnVnbm9kcnVnIiksCiAgICAiZXh0cmFfZHJ1Z25vZHJ1ZyIgPSBjKCJ6MjN6MjJkcnVnIiwgInoyM3oyMm5vZHJ1ZyIpKQp0bXJjMl9kcnVnX2tlZXBlcnMgPC0gbGlzdCgKICAgICJkcnVnIiA9IGMoImFudGltb255IiwgIm5vbmUiKSkKdG1yYzJfdHlwZV9rZWVwZXJzIDwtIGxpc3QoCiAgICAidHlwZSIgPSBjKCJVOTM3IiwgIk1hY3JvcGhhZ2VzIikpCnRtcmMyX3N0cmFpbl9rZWVwZXJzIDwtIGxpc3QoCiAgICAic3RyYWluIiA9IGMoInoyMyIsICJ6MjIiKSkKdHlwZV96eW1vX2V4dHJhIDwtICJ6eW1vc192c190eXBlcyA9IChVOTM3X3oyLjMgLSBVOTM3X3oyLjIpIC0gKE1hY3JvcGhhZ2VzX3oyLjMgLSBNYWNyb3BoYWdlc196Mi4yKSIKdG1yYzJfdHlwZXp5bW9fa2VlcGVycyA8LSBsaXN0KAogICAgInU5MzdfbWFjciIgPSBjKCJNYWNyb3BoYWdlc25vbmUiLCAiVTkzN25vbmUiKSwKICAgICJ6eW1vX21hY3IiID0gYygiTWFjcm9waGFnZXN6MjMiLCAiTWFjcm9waGFnZXN6MjIiKSwKICAgICJ6eW1vX3U5MzciID0gYygiVTkzN3oyMyIsICJVOTM3ejIyIiksCiAgICAiejIzX3R5cGVzIiA9IGMoIlU5Mzd6MjMiLCAiTWFjcm9waGFnZXN6MjMiKSwKICAgICJ6MjJfdHlwZXMiID0gYygiVTkzN3oyMiIsICJNYWNyb3BoYWdlc3oyMiIpLAogICAgInp5bW9zX3R5cGVzIiA9IGMoInp5bW9zX3ZzX3R5cGVzIikpCnRtcmMyX3R5cGVkcnVnX2tlZXBlcnMgPC0gbGlzdCgKICAgICJ0eXBlX25vZHJ1ZyIgPSBjKCJVOTM3bm9uZSIsICJNYWNyb3BoYWdlc25vbmUiKSwKICAgICJ0eXBlX2RydWciID0gYygiVTkzN2FudGltb255IiwgIk1hY3JvcGhhZ2VzYW50aW1vbnkiKSwKICAgICJtYWNyX2RydWdzIiA9IGMoIk1hY3JvcGhhZ2VzYW50aW1vbnkiLCAiTWFjcm9waGFnZXNub25lIiksCiAgICAidTkzN19kcnVncyIgPSBjKCJVOTM3YW50aW1vbnkiLCAiVTkzN25vbmUiKSkKdTkzN19rZWVwZXJzIDwtIGxpc3QoCiAgICAiejIzbm9zYl92c191bmluZiIgPSBjKCJpbmZ6MjMiLCAidW5pbmZub25lIiksCiAgICAiejIybm9zYl92c191bmluZiIgPSBjKCJpbmZ6MjIiLCAidW5pbmZub25lIiksCiAgICAiejIzbm9zYl92c196MjJub3NiIiA9IGMoImluZnoyMyIsICJpbmZ6MjIiKSwKICAgICJ6MjNzYl92c196MjJzYiIgPSBjKCJpbmZzYnoyMyIsICJpbmZzYnoyMiIpLAogICAgInoyM3NiX3ZzX3oyM25vc2IiID0gYygiaW5mc2J6MjMiLCAiaW5mejIzIiksCiAgICAiejIyc2JfdnNfejIybm9zYiIgPSBjKCJpbmZzYnoyMiIsICJpbmZ6MjIiKSwKICAgICJ6MjNzYl92c19zYiIgPSBjKCJpbmZ6MjMiLCAidW5pbmZzYm5vbmUiKSwKICAgICJ6MjJzYl92c19zYiIgPSBjKCJpbmZ6MjIiLCAidW5pbmZzYm5vbmUiKSwKICAgICJ6MjNzYl92c191bmluZiIgPSBjKCJpbmZzYnoyMyIsICJ1bmluZm5vbmUiKSwKICAgICJ6MjJzYl92c191bmluZiIgPSBjKCJpbmZzYnoyMiIsICJ1bmluZm5vbmUiKSwKICAgICJzYl92c191bmluZiIgPSBjKCJ1bmluZnNibm9uZSIsICJ1bmluZm5vbmUiKSkKYGBgCgojIyMgUHJpbWFyeSBxdWVyaWVzCgpUaGVyZSBpcyBhIHNlcmllcyBvZiBpbml0aWFsIHF1ZXN0aW9ucyB3aGljaCBtYWtlIHNvbWUgc2Vuc2UKdG8gbWUsIGJ1dCB0aGVzZSBkbyBub3QgbmVjZXNzYXJpbHkgbWF0Y2ggdGhlIHNldCBvZiBxdWVzdGlvbnMgd2hpY2gKYXJlIG1vc3QgcHJlc3NpbmcuICBJIGFtIGhvcGluZyB0byBwdWxsIGJvdGggb2YgdGhlc2Ugc2V0cyBvZgpxdWVyaWVzIGluIG9uZS4KCkJlZm9yZSBleHRyYWN0aW5nIHRoZXNlIGdyb3VwcyBvZiBxdWVyaWVzLCBsZXQgdXMgaW52b2tlIHRoZQphbGxfcGFpcndpc2UoKSBmdW5jdGlvbiBhbmQgZ2V0IGFsbCBvZiB0aGUgbGlrZWx5IGNvbnRyYXN0cyBhbG9uZyB3aXRoCm9uZSBvciBtb3JlIGV4dHJhcyB0aGF0IG1pZ2h0IHByb3ZlIHVzZWZ1bCAodGhlICdleHRyYScgYXJndW1lbnQpLgoKIyMjIENvbWJpbmVkIFU5MzcgYW5kIE1hY3JvcGhhZ2VzOiBDb21wYXJlIGRydWcgZWZmZWN0cwoKV2hlbiB3ZSBoYXZlIHRoZSB1OTM3IGNlbGxzIGluIHRoZSBzYW1lIGRhdGFzZXQgYXMgdGhlIG1hY3JvcGhhZ2VzLAp0aGF0IHByb3ZpZGVzIGFuIGludGVyZXN0aW5nIG9wcG9ydHVuaXR5IHRvIHNlZSBpZiB3ZSBjYW4gb2JzZXJ2ZQpkcnVnLWRlcGVuZGFudCBlZmZlY3RzIHdoaWNoIGFyZSBzaGFyZWQgYWNyb3NzIGJvdGggY2VsbCB0eXBlcy4KCmBgYHtyIGJvdGhfdHlwZXNfZHJ1Z30KZHJ1Z19kZSA8LSBhbGxfcGFpcndpc2UoYWxsX2h1bWFuLCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKQpkcnVnX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgZHJ1Z19kZSwga2VlcGVycyA9IHRtcmMyX2RydWdfa2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS90bXJjMl9tYWNyb3BoYWdlX2RydWdfY29tcGFyaXNvbi12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBDb21iaW5lZCBVOTM3IGFuZCBNYWNyb3BoYWdlczogY29tcGFyZSBjZWxsIHR5cGVzCgpUaGVyZSBhcmUgYSBjb3VwbGUgb2Ygd2F5cyBvbmUgbWlnaHQgd2FudCB0byBkaXJlY3RseSBjb21wYXJlIHRoZSB0d28KY2VsbCB0eXBlcy4KCiogR2l2ZW4gdGhhdCB0aGUgdmFyaWFuY2UgYmV0d2VlbiB0aGUgdHdvIGNlbGx0eXBlcyBpcyBzbyBodWdlLCBqdXN0CiAgY29tcGFyZSBhbGwgc2FtcGxlcy4KKiBPbmUgbWlnaHQgd2FudCB0byBjb21wYXJlIHRoZW0gd2l0aCB0aGUgaW50ZXJhY3Rpb24gZWZmZWN0cyBvZiBkcnVnL3p5bW9kZW1lLgoKYGBge3IgYm90aF90eXBlc19jb21wYXJlfQp0eXBlX2RlIDwtIGFsbF9wYWlyd2lzZShhbGxfaHVtYW5fdHlwZXMsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpCnR5cGVfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0eXBlX2RlLCBrZWVwZXJzID0gdG1yYzJfdHlwZV9rZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL3RtcmMyX21hY3JvcGhhZ2VfdHlwZV9jb21wYXJpc29uLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBDb21iaW5lZCBmYWN0b3JzIG9mIGludGVyZXN0OiBjZWxsdHlwZSt6eW1vZGVtZSwgY2VsbHR5cGUrZHJ1ZwoKR2l2ZW4gdGhlIGFib3ZlIGV4cGxpY2l0IGNvbXBhcmlzb24gb2YgYWxsIHNhbXBsZXMgY29tcHJpc2luZyB0aGUgdHdvCmNlbGwgdHlwZXMsIG5vdyBsZXQgdXMgbG9vayBhdCB0aGUgZHJ1ZyB0cmVhdG1lbnQrenltb2RlbWUgc3RhdHVzIHdpdGgKYWxsIHNhbXBsZXMsIG1hY3JvcGhhZ2VzIGFuZCBVOTM3LgoKYGBge3IgYWxsX3NhbXBsZXNfenltb190eXBlfQp0eXBlX3p5bW9fZGUgPC0gYWxsX3BhaXJ3aXNlKHR5cGVfenltbywgZmlsdGVyID0gVFJVRSwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9jb250cmFzdHM9dHlwZV96eW1vX2V4dHJhKQp0eXBlX3p5bW9fdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0eXBlX3p5bW9fZGUsIGtlZXBlcnMgPSB0bXJjMl90eXBlenltb19rZWVwZXJzLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL3RtcmMyX21hY3JvcGhhZ2VfdHlwZV96eW1vX2NvbXBhcmlzb24tdnt2ZXJ9Lnhsc3giKSkKCnR5cGVfZHJ1Z19kZSA8LSBhbGxfcGFpcndpc2UodHlwZV9kcnVnLCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKQp0eXBlX2RydWdfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0eXBlX2RydWdfZGUsIGtlZXBlcnMgPSB0bXJjMl90eXBlZHJ1Z19rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS90bXJjMl9tYWNyb3BoYWdlX3R5cGVfZHJ1Z19jb21wYXJpc29uLXZ7dmVyfS54bHN4IikpCmBgYAoKIyBJbmRpdmlkdWFsIGNlbGwgdHlwZXMKCkF0IHRoaXMgcG9pbnQsIEkgdGhpbmsgaXQgaXMgZmFpciB0byBzYXkgdGhhdCB0aGUgdHdvIGNlbGwgdHlwZXMgYXJlCnN1ZmZpY2llbnRseSBkaWZmZXJlbnQgdGhhdCB0aGV5IGRvIG5vdCByZWFsbHkgYmVsb25nIHRvZ2V0aGVyIGluIGEKc2luZ2xlIGFuYWx5c2lzLgoKIyMgZHJ1ZyBvciBzdHJhaW4gZWZmZWN0cywgc2luZ2xlIGNlbGwgdHlwZQoKT25lIG9mIHRoZSBxdWVyaWVzIE5hamliIGFza2VkIHdoaWNoIEkgdGhpbmsgSSBtaXNpbnRlcnByZXRlZCB3YXMgdG8KbG9vayBhdCBkcnVnIGFuZC9vciBzdHJhaW4gZWZmZWN0cy4gIE15IGludGVycHJldGF0aW9uIGlzIHNvbWV3aGVyZQpiZWxvdyBhbmQgd2FzIG5vdCB3aGF0IGhlIHdhcyBsb29raW5nIGZvci4gIEluc3RlYWQsIGhlIHdhcyBsb29raW5nIHRvCnNlZSBhbGwobWFjcm9waGFnZSkgZHJ1Zy9ub2RydWcgYW5kIGFsbChtYWNyb3BoYWdlKSB6MjMvejIyIGFuZApjb21wYXJlIHRoZW0gdG8gZWFjaCBvdGhlci4gIEl0IG1heSBiZSB0aGF0IHRoaXMgaXMgc3RpbGwgYSB3cm9uZwppbnRlcnByZXRhdGlvbiwgaWYgc28gdGhlIG1vc3QgbGlrZWx5IGNvbXBhcmlzb24gaXMgZWl0aGVyOgoKKiAgKHoyM2RydWcvejIyZHJ1ZykgLyAoejIzbm9kcnVnL3oyMm5vZHJ1ZyksIG9yIHBlcmhhcHMKKiAgKHoyM2RydWcvejIzbm9kcnVnKSAvICh6MjJkcnVnL3oyMm5vZHJ1ZyksCgpJIGFtIG5vdCBzdXJlIHRob3NlIGNvbmZ1c2UgbWUsIGFuZCBhdCBsZWFzdCBvbmUgb2YgdGhlbSBpcyBiZWxvdwoKIyMjIE1hY3JvcGhhZ2VzCgpJbiB0aGVzZSBibG9ja3Mgd2Ugd2lsbCBleHBsaWNpdGx5IHF1ZXJ5IG9ubHkgb25lIGZhY3RvciBhdCBhIHRpbWUsCmRydWcgYW5kIHN0cmFpbi4gIFRoZSBldmVudHVhbCBnb2FsIGlzIHRvIGxvb2sgZm9yIGVmZmVjdHMgb2YKZHJ1ZyB0cmVhdG1lbnQgYW5kL29yIHN0cmFpbiB0cmVhdG1lbnQgd2hpY2ggYXJlIHNoYXJlZD8KCiMjIyMgTWFjcm9waGFnZSBEcnVnIG9ubHkKClRodXMgd2Ugd2lsbCBzdGFydCB3aXRoIHRoZSBwdXJlIGRydWcgcXVlcnkuICBJbiB0aGlzIGJsb2NrIHdlIHdpbGwKbG9vayBvbmx5IGF0IHRoZSBkcnVnL25vZHJ1ZyBlZmZlY3QuCgpgYGB7ciBtYWNyb3BoYWdlX2RydWdvbmx5X2RlfQpoc19tYWNyX2RydWdfZGUgPC0gYWxsX3BhaXJ3aXNlKGhzX21hY3JfZHJ1Z19leHB0LCBmaWx0ZXIgPSBUUlVFLCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiKQpoc19tYWNyX2RydWdfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBoc19tYWNyX2RydWdfZGUsIGtlZXBlcnMgPSB0bXJjMl9kcnVnX2tlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvdG1yYzJfbWFjcm9waGFnZV9vbmx5ZHJ1Z190YWJsZS12e3Zlcn0ueGxzeCIpKQpoc19tYWNyX2RydWdfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBoc19tYWNyX2RydWdfdGFibGUpCmBgYAoKIyMjIyBNYWNyb3BoYWdlIFN0cmFpbiBvbmx5CgpJbiBhIHNpbWlsYXIgZmFzaGlvbiwgbGV0IHVzIGxvb2sgZm9yIGVmZmVjdHMgd2hpY2ggYXJlIG9ic2VydmVkIHdoZW4Kd2UgY29uc2lkZXIgb25seSB0aGUgc3RyYWluIHVzZWQgZHVyaW5nIGluZmVjdGlvbi4KCmBgYHtyIG1hY3JvcGhhZ2Vfc3RyYWlub25seV9kZX0KaHNfbWFjcl9zdHJhaW5fZGUgPC0gYWxsX3BhaXJ3aXNlKGhzX21hY3Jfc3RyYWluX2V4cHQsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2JhdGNoID0gInN2YXNlcSIpCmhzX21hY3Jfc3RyYWluX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgaHNfbWFjcl9zdHJhaW5fZGUsIGtlZXBlcnMgPSB0bXJjMl9zdHJhaW5fa2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS90bXJjMl9tYWNyb3BoYWdlX29ubHlzdHJhaW5fdGFibGUtdnt2ZXJ9Lnhsc3giKSkKaHNfbWFjcl9zdHJhaW5fc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBoc19tYWNyX3N0cmFpbl90YWJsZSkKYGBgCgojIyMjIENvbXBhcmUgRHJ1ZyBhbmQgU3RyYWluIEVmZmVjdHMKCk5vdyBsZXQgdXMgY29uc2lkZXIgdGhlIGFib3ZlIHR3byBjb21wYXJpc29ucyB0b2dldGhlci4gIEZpcnN0LCBJIHdpbGwKcGxvdCB0aGUgbG9nRkMgdmFsdWVzIG9mIHRoZW0gYWdhaW5zdCBlYWNoIG90aGVyIChkcnVnIG9uIHgtYXhpcyBhbmQKc3RyYWluIG9uIHRoZSB5LWF4aXMpLiAgVGhlbiB3ZSBjYW4gZXh0cmFjdCB0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgaW4gYQpmZXcgY29tYmluZWQgY2F0ZWdvcmllcyBvZiBpbnRlcmVzdC4gIEkgYXNzdW1lIHRoZXNlIHdpbGwgZm9jdXMKZXhjbHVzaXZlbHkgb24gdGhlIGNhdGVnb3JpZXMgd2hpY2ggaW5jbHVkZSB0aGUgaW50cm9kdWN0aW9uIG9mIHRoZQpkcnVnLgoKYGBge3IgY29tcGFyZV9kcnVnX3N0cmFpbl9lZmZlY3RzfQpkcnVnX3N0cmFpbl9jb21wX2RmIDwtIG1lcmdlKGhzX21hY3JfZHJ1Z190YWJsZVtbImRhdGEiXV1bWyJkcnVnIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhzX21hY3Jfc3RyYWluX3RhYmxlW1siZGF0YSJdXVtbInN0cmFpbiJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJyb3cubmFtZXMiKQpkcnVnX3N0cmFpbl9jb21wX3Bsb3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcigKICBkcnVnX3N0cmFpbl9jb21wX2RmWywgYygiZGVzZXFfbG9nZmMueCIsICJkZXNlcV9sb2dmYy55IildKQojIyBDb250cmFzdHM6IGFudGltb255L25vbmUsIHoyMy96MjI7IHgtYXhpczogZHJ1ZywgeS1heGlzOiBzdHJhaW4KIyMgdG9wIGxlZnQ6IGhpZ2hlciBubyBkcnVnLCB6MjM7IHRvcCByaWdodDogaGlnaGVyIGRydWcgejIzCiMjIGJvdHRvbSBsZWZ0OiBoaWdoZXIgbm8gZHJ1ZywgejIyOyBib3R0b20gcmlnaHQ6IGhpZ2hlciBkcnVnIHoyMgpkcnVnX3N0cmFpbl9jb21wX3Bsb3Qkc2NhdHRlcgpgYGAKCkFzIEkgbm90ZWQgaW4gdGhlIGNvbW1lbnRzIGFib3ZlLCBzb21lIHF1YWRyYW50cyBvZiB0aGUgc2NhdHRlciBwbG90CmFyZSBsaWtlbHkgdG8gYmUgb2YgZ3JlYXRlciBpbnRlcmVzdCB0byB1cyB0aGFuIG90aGVycyAodGhlIHJpZ2h0CnNpZGUpLiAgQmVjYXVzZSBJIGdldCBjb25mdXNlZCBzb21ldGltZXMsIHRoZSBmb2xsb3dpbmcgYmxvY2sgd2lsbApleHBsaWNpdGx5IG5hbWUgdGhlIGNhdGVnb3JpZXMgb2YgbGlrZWx5IGludGVyZXN0LCB0aGVuIGFzayB3aGljaApnZW5lcyBhcmUgc2hhcmVkIGFtb25nIHRoZW0sIGFuZCBmaW5hbGx5IHVzZSBVcFNldFIgdG8gZXh0cmFjdCB0aGUKdmFyaW91cyBnZW5lIGludGVyc2VjdGlvbi91bmlvbiBjYXRlZ29yaWVzLgoKYGBge3IgZHJ1Z19zdHJhaW5fc2NhdHRlcl9zdWJncm91cHN9CmhpZ2hlcl9kcnVnIDwtIGhzX21hY3JfZHJ1Z19zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0KaGlnaGVyX25vZHJ1ZyA8LSBoc19tYWNyX2RydWdfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWzFdXQpoaWdoZXJfejIzIDwtIGhzX21hY3Jfc3RyYWluX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sxXV0KaGlnaGVyX3oyMiA8LSBoc19tYWNyX3N0cmFpbl9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0Kc3VtKHJvd25hbWVzKGhpZ2hlcl9kcnVnKSAlaW4lIHJvd25hbWVzKGhpZ2hlcl96MjMpKQpzdW0ocm93bmFtZXMoaGlnaGVyX2RydWcpICVpbiUgcm93bmFtZXMoaGlnaGVyX3oyMikpCnN1bShyb3duYW1lcyhoaWdoZXJfbm9kcnVnKSAlaW4lIHJvd25hbWVzKGhpZ2hlcl96MjMpKQpzdW0ocm93bmFtZXMoaGlnaGVyX25vZHJ1ZykgJWluJSByb3duYW1lcyhoaWdoZXJfejIyKSkKCmRydWdfejIzX2xzdCA8LSBsaXN0KCJkcnVnIiA9IHJvd25hbWVzKGhpZ2hlcl9kcnVnKSwKICAgICAgICAgICAgICAgICAgICAgInoyMyIgPSByb3duYW1lcyhoaWdoZXJfejIzKSkKaGlnaGVyX2RydWdfejIzIDwtIHVwc2V0KFVwU2V0Ujo6ZnJvbUxpc3QoZHJ1Z196MjNfbHN0KSwgdGV4dC5zY2FsZSA9IDIpCmhpZ2hlcl9kcnVnX3oyMwoKZHJ1Z196MjNfc2hhcmVkX2dlbmVzIDwtIG92ZXJsYXBfZ3JvdXBzKGRydWdfejIzX2xzdCkKCmRydWdfejIyX2xzdCA8LSBsaXN0KCJkcnVnIiA9IHJvd25hbWVzKGhpZ2hlcl9kcnVnKSwKICAgICAgICAgICAgICAgICAgICAgInoyMiIgPSByb3duYW1lcyhoaWdoZXJfejIyKSkKaGlnaGVyX2RydWdfejIyIDwtIHVwc2V0KFVwU2V0Ujo6ZnJvbUxpc3QoZHJ1Z196MjJfbHN0KSwgdGV4dC5zY2FsZSA9IDIpCmhpZ2hlcl9kcnVnX3oyMgoKZHJ1Z196MjJfc2hhcmVkX2dlbmVzIDwtIG92ZXJsYXBfZ3JvdXBzKGRydWdfejIyX2xzdCkKc2hhcmVkX2dlbmVzX2RydWdfejIyIDwtIGF0dHIoZHJ1Z196MjJfc2hhcmVkX2dlbmVzLCAiZWxlbWVudHMiKVtkcnVnX3oyMl9zaGFyZWRfZ2VuZXNbWyJkcnVnOnoyMiJdXV0KYGBgCgojIyMjIFBlcmZvcm0gZ1Byb2ZpbGVyIG9uIGRydWcvc3RyYWluIGVmZmVjdCBzaGFyZWQgZ2VuZXMKCk5vdyB0aGF0IHdlIGhhdmUgc29tZSBwb3B1bGF0aW9ucyBvZiBnZW5lcyB3aGljaCBhcmUgc2hhcmVkIGFjcm9zcyB0aGUKZHJ1Zy9zdHJhaW4gZWZmZWN0cywgbGV0IHVzIHBhc3MgdGhlbSB0byBzb21lIEdTRUEgYW5hbHlzZXMgYW5kIHNlZQp3aGF0IHBvcHMgb3V0LgoKYGBge3IgZ3BfZHJ1Z19zdHJhaW59CndhbnRlZCA8LSBkcnVnX3oyM19zaGFyZWRfZ2VuZXNbWyJkcnVnOnoyMyJdXQpzaGFyZWRfZ2VuZXNfZHJ1Z196MjMgPC0gYXR0cihkcnVnX3oyM19zaGFyZWRfZ2VuZXMsICJlbGVtZW50cyIpW3dhbnRlZF0Kc2hhcmVkX2RydWdfejIzX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2hhcmVkX2dlbmVzX2RydWdfejIzKQpzaGFyZWRfZHJ1Z196MjNfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQpzaGFyZWRfZHJ1Z196MjNfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJCUCJdXQpzaGFyZWRfZHJ1Z196MjNfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJSRUFDIl1dCgp3YW50ZWQgPC0gZHJ1Z196MjJfc2hhcmVkX2dlbmVzW1siZHJ1Zzp6MjIiXV0Kc2hhcmVkX2dlbmVzX2RydWdfejIyIDwtIGF0dHIoZHJ1Z196MjJfc2hhcmVkX2dlbmVzLCAiZWxlbWVudHMiKVt3YW50ZWRdCnNoYXJlZF9kcnVnX3oyMl9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNoYXJlZF9nZW5lc19kcnVnX3oyMikKc2hhcmVkX2RydWdfejIyX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siQlAiXV0KYGBgCgojIyBPdXIgbWFpbiBxdWVzdGlvbiBvZiBpbnRlcmVzdAoKVGhlIGRhdGEgc3RydWN0dXJlIGhzX21hY3IgY29udGFpbnMgb3VyIHByaW1hcnkgbWFjcm9waGFnZXMsIHdoaWNoCmFyZSwgYXMgc2hvd24gYWJvdmUsIHRoZSBkYXRhIHdlIGNhbiByZWFsbHkgc2luayBvdXIgdGVldGggaW50by4KCk5vdGUsIHdlIGV4cGVjdCBzb21lIGVycm9ycyB3aGVuIHJ1bm5pbmcgdGhlIGNvbWJpbmVfZGVfdGFibGVzKCkKYmVjYXVzZSBub3QgYWxsIG1ldGhvZHMgSSB1c2UgYXJlIGNvbWZvcnRhYmxlIHVzaW5nIHRoZSByYXRpbyBvcgpyYXRpb3MgY29udHJhc3RzIHdlIGFkZGVkIGluIHRoZSAnZXh0cmFzJyBhcmd1bWVudC4gIEFzIGEgcmVzdWx0LCB3aGVuCndlIGNvbWJpbmUgdGhlbSBpbnRvIHRoZSBsYXJnZXIgb3V0cHV0IHRhYmxlcywgdGhvc2UgcGVjdWxpYXIKY29udHJhc3RzIGZhaWwuICBUaGlzIGRvZXMgbm90IHN0b3AgaXQgZnJvbSB3cml0aW5nIHRoZSByZXN0IG9mIHRoZQpyZXN1bHRzLCBob3dldmVyLgoKYGBge3IgaHNfZGV9CmhzX21hY3JfZGUgPC0gYWxsX3BhaXJ3aXNlKAogICAgaHNfbWFjciwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwKICAgIGZpbHRlciA9IFRSVUUsCiAgICBleHRyYV9jb250cmFzdHMgPSB0bXJjMl9odW1hbl9leHRyYSkKdGVzdF9rZWVwZXJzIDwtIHRtcmMyX2h1bWFuX2tlZXBlcnNbMTNdCmhzX21hY3JfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBoc19tYWNyX2RlLAogICAga2VlcGVycyA9IHRtcmMyX2h1bWFuX2tlZXBlcnMsCiAgICAjI2tlZXBlcnMgPSB0ZXN0X2tlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvaHNfbWFjcl9kcnVnX3p5bW9fdGFibGUtdnt2ZXJ9Lnhsc3giKSkKCmhzX21hY3Jfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBoc19tYWNyX3RhYmxlLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL2hzX21hY3JfZHJ1Z196eW1vX3NpZy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBPdXIgbWFpbiBxdWVzdGlvbnMgaW4gVTkzNwoKTGV0IHVzIGRvIHRoZSBzYW1lIGNvbXBhcmlzb25zIGluIHRoZSBVOTM3IHNhbXBsZXMsIHRob3VnaCBJIHdpbGwgbm90CmRvIHRoZSBleHRyYSBjb250cmFzdHMsIHByaW1hcmlseSBiZWNhdXNlIEkgdGhpbmsgdGhlIGRhdGFzZXQgaXMgbGVzcwpsaWtlbHkgdG8gc3VwcG9ydCB0aGVtLgoKYGBge3IgaHNfdTkzN19kZX0KdTkzN19kZSA8LSBhbGxfcGFpcndpc2UodTkzN19leHB0LCBtb2RlbF9iYXRjaCA9ICJzdmFzZXEiLCBmaWx0ZXIgPSBUUlVFKQp1OTM3X3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgdTkzN19kZSwKICAgIGtlZXBlcnMgPSB1OTM3X2tlZXBlcnMsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvdTkzN19kcnVnX3p5bW9fdGFibGUtdnt2ZXJ9Lnhsc3giKSkKdTkzN19zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIHU5MzdfdGFibGUsCiAgICBleGNlbCA9IGdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvdTkzN19kcnVnX3p5bW9fc2lnLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIyBDb21wYXJlIChubylTYiB6Mi4zL3oyLjIgdHJlYXRtZW50cyBhbW9uZyBtYWNyb3BoYWdlcwoKYGBge3IgY29tcGFyZV9kcnVnX3oyMzIyfQp1cHNldF9wbG90c19oc19tYWNyIDwtIHVwc2V0cl9zaWcoCiAgICBoc19tYWNyX3NpZywgYm90aCA9IFRSVUUsCiAgICBjb250cmFzdHMgPSBjKCJ6MjNzYl92c196MjJzYiIsICJ6MjNub3NiX3ZzX3oyMm5vc2IiKSkKdXBzZXRfcGxvdHNfaHNfbWFjcltbImJvdGgiXV0KZ3JvdXBzIDwtIHVwc2V0X3Bsb3RzX2hzX21hY3JbWyJib3RoX2dyb3VwcyJdXQpzaGFyZWRfZ2VuZXMgPC0gYXR0cihncm91cHMsICJlbGVtZW50cyIpW2dyb3Vwc1tbMl1dXSAlPiUKICBnc3ViKHBhdHRlcm4gPSAiXmdlbmU6IiwgcmVwbGFjZW1lbnQgPSAiIikKbGVuZ3RoKHNoYXJlZF9nZW5lcykKCnNoYXJlZF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNoYXJlZF9nZW5lcykKc2hhcmVkX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siTUYiXV0Kc2hhcmVkX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siQlAiXV0Kc2hhcmVkX2dwW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXQoKZHJ1Z19nZW5lcyA8LSBhdHRyKGdyb3VwcywgImVsZW1lbnRzIilbZ3JvdXBzW1siejIzc2JfdnNfejIyc2IiXV1dICU+JQogICAgZ3N1YihwYXR0ZXJuID0gIl5nZW5lOiIsIHJlcGxhY2VtZW50ID0gIiIpCmRydWdvbmx5X2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoZHJ1Z19nZW5lcykKZHJ1Z29ubHlfZ3BbWyJwdmFsdWVfcGxvdHMiXV1bWyJCUCJdXQpgYGAKCkkgd2FudCB0byB0cnkgc29tZXRoaW5nLCBkaXJlY3RseSBpbmNsdWRlIHRoZSB1OTM3IGRhdGEgaW4gdGhpcy4uLgoKYGBge3IgYWRkX3U5Mzd9CmJvdGhfc2lnIDwtIGhzX21hY3Jfc2lnCm5hbWVzKGJvdGhfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV0pIDwtIHBhc3RlMCgibWFjcl8iLCBuYW1lcyhib3RoX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dKSkKbmFtZXMoYm90aF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dKSA8LSBwYXN0ZTAoIm1hY3JfIiwgbmFtZXMoYm90aF9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dKSkKdTkzN19kZXNlcSA8LSB1OTM3X3NpZ1tbImRlc2VxIl1dCm5hbWVzKHU5MzdfZGVzZXFbWyJ1cHMiXV0pIDwtIHBhc3RlMCgidTkzN18iLCBuYW1lcyh1OTM3X2Rlc2VxW1sidXBzIl1dKSkKbmFtZXModTkzN19kZXNlcVtbImRvd25zIl1dKSA8LSBwYXN0ZTAoInU5MzdfIiwgbmFtZXModTkzN19kZXNlcVtbImRvd25zIl1dKSkKYm90aF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXSA8LSBjKGJvdGhfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV0sIHU5MzdfZGVzZXFbWyJ1cHMiXV0pCmJvdGhfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXSA8LSBjKGJvdGhfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV0sIHU5MzdfZGVzZXFbWyJkb3ducyJdXSkKc3VtbWFyeShib3RoX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dKQoKdXBzZXRfcGxvdHNfYm90aCA8LSB1cHNldHJfc2lnKAogICAgYm90aF9zaWcsIGJvdGg9VFJVRSwKICAgIGNvbnRyYXN0cz1jKCJtYWNyX3oyM3NiX3ZzX3oyMnNiIiwgIm1hY3JfejIzbm9zYl92c196MjJub3NiIiwKICAgICAgICAgICAgICAgICJ1OTM3X3oyM3NiX3ZzX3oyMnNiIiwgInU5MzdfejIzbm9zYl92c196MjJub3NiIikpCnVwc2V0X3Bsb3RzX2JvdGgkYm90aApgYGAKCiMjIyMgQ29tcGFyZSBERSByZXN1bHRzIGZyb20gbWFjcm9waGFnZXMgYW5kIFU5Mzcgc2FtcGxlcwoKTG9va2luZyBhIGJpdCBtb3JlIGNsb3NlbHkgYXQgdGhlc2UsIEkgdGhpbmsgdGhlIHU5MzcgZGF0YSBpcyB0b28Kc3BhcnNlIHRvIGVmZmVjdGl2ZWx5IGNvbXBhcmUuCgpgYGB7ciBjb21wYXJlX2RlX3U5MzdfbWFjcm99Cm1hY3JfdTkzN19jb21wYXJpc29uIDwtIGNvbXBhcmVfZGVfcmVzdWx0cyhoc19tYWNyX3RhYmxlLCB1OTM3X3RhYmxlKQptYWNyX3U5MzdfY29tcGFyaXNvbiRsZmNfaGVhdAoKbWFjcl91OTM3X3Zlbm5zIDwtIGNvbXBhcmVfc2lnbmlmaWNhbnRfY29udHJhc3RzKGhzX21hY3Jfc2lnLCBzZWNvbmRfc2lnX3RhYmxlcyA9IHU5Mzdfc2lnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzID0gInoyM3NiX3ZzX3oyM25vc2IiKQptYWNyX3U5MzdfdmVubnMkdXBfcGxvdAptYWNyX3U5MzdfdmVubnMkZG93bl9wbG90CgptYWNyX3U5MzdfdmVubnNfdjIgPC0gY29tcGFyZV9zaWduaWZpY2FudF9jb250cmFzdHMoaHNfbWFjcl9zaWcsIHNlY29uZF9zaWdfdGFibGVzID0gdTkzN19zaWcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHMgPSAiejIyc2JfdnNfejIybm9zYiIpCm1hY3JfdTkzN192ZW5uc192MiR1cF9wbG90Cm1hY3JfdTkzN192ZW5uc192MiRkb3duX3Bsb3QKCm1hY3JfdTkzN192ZW5uc192MyA8LSBjb21wYXJlX3NpZ25pZmljYW50X2NvbnRyYXN0cyhoc19tYWNyX3NpZywgc2Vjb25kX3NpZ190YWJsZXMgPSB1OTM3X3NpZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cyA9ICJzYl92c191bmluZiIpCm1hY3JfdTkzN192ZW5uc192MyR1cF9wbG90Cm1hY3JfdTkzN192ZW5uc192MyRkb3duX3Bsb3QKYGBgCgojIyMgQ29tcGFyZSBtYWNyb3BoYWdlL3U5Mzcgd2l0aCByZXNwZWN0IHRvIHoyLjMvejIuMgoKYGBge3IgbWFjcl91OTM3X3oyM3oyMn0KY29tcGFyaXNvbl9kZiA8LSBtZXJnZShoc19tYWNyX3RhYmxlW1siZGF0YSJdXVtbInoyM3NiX3ZzX3oyMnNiIl1dLAogICAgICAgICAgICAgICAgICAgICAgIHU5MzdfdGFibGVbWyJkYXRhIl1dW1siejIzc2JfdnNfejIyc2IiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAicm93Lm5hbWVzIikKbWFjcnU5MzdfejIzejIyX3Bsb3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihjb21wYXJpc29uX2RmWywgYygiZGVzZXFfbG9nZmMueCIsICJkZXNlcV9sb2dmYy55IildKQptYWNydTkzN196MjN6MjJfcGxvdCRzY2F0dGVyCgpjb21wYXJpc29uX2RmIDwtIG1lcmdlKGhzX21hY3JfdGFibGVbWyJkYXRhIl1dW1siejIzbm9zYl92c196MjJub3NiIl1dLAogICAgICAgICAgICAgICAgICAgICAgIHU5MzdfdGFibGVbWyJkYXRhIl1dW1siejIzbm9zYl92c196MjJub3NiIl1dLAogICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gInJvdy5uYW1lcyIpCm1hY3J1OTM3X3oyM3oyMl9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoY29tcGFyaXNvbl9kZlssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXSkKbWFjcnU5MzdfejIzejIyX3Bsb3Qkc2NhdHRlcgpgYGAKCiMjIyMgQWRkIGRvbm9yIHRvIHRoZSBjb250cmFzdHMsIG5vIHN2YQoKYGBge3Igbm9wb3dlcl9ub3N2YX0Kbm9fcG93ZXJfZmFjdCA8LSBwYXN0ZTAocERhdGEoaHNfbWFjcilbWyJkb25vciJdXSwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICBwRGF0YShoc19tYWNyKVtbImNvbmRpdGlvbiJdXSkKdGFibGUocERhdGEoaHNfbWFjcilbWyJkb25vciJdXSkKdGFibGUobm9fcG93ZXJfZmFjdCkKaHNfbm9wb3dlciA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGhzX21hY3IsIGZhY3QgPSBub19wb3dlcl9mYWN0KQpoc19ub3Bvd2VyIDwtIHN1YnNldF9leHB0KGhzX25vcG93ZXIsIHN1YnNldD0ibWFjcm9waGFnZXp5bW9kZW1lIT0nbm9uZSciKQpoc19ub3Bvd2VyX25vc3ZhX2RlIDwtIGFsbF9wYWlyd2lzZShoc19ub3Bvd2VyLCBtb2RlbF9iYXRjaCA9IEZBTFNFLCBmaWx0ZXIgPSBUUlVFKQpub3Bvd2VyX2tlZXBlcnMgPC0gbGlzdCgKICAgICJkMDFfenltbyIgPSBjKCJkMDFpbmZ6MjMiLCAiZDAxaW5mejIyIiksCiAgICAiZDAxX3NienltbyIgPSBjKCJkMDFpbmZzYnoyMyIsICJkMDFpbmZzYnoyMiIpLAogICAgImQwMl96eW1vIiA9IGMoImQwMmluZnoyMyIsICJkMDJpbmZ6MjIiKSwKICAgICJkMDJfc2J6eW1vIiA9IGMoImQwMmluZnNiejIzIiwgImQwMmluZnNiejIyIiksCiAgICAiZDA5X3p5bW8iID0gYygiZDA5aW5mejIzIiwgImQwOWluZnoyMiIpLAogICAgImQwOV9zYnp5bW8iID0gYygiZDA5aW5mc2J6MjMiLCAiZDA5aW5mc2J6MjIiKSwKICAgICJkODFfenltbyIgPSBjKCJkODFpbmZ6MjMiLCAiZDgxaW5mejIyIiksCiAgICAiZDgxX3NienltbyIgPSBjKCJkODFpbmZzYnoyMyIsICJkODFpbmZzYnoyMiIpKQpoc19ub3Bvd2VyX25vc3ZhX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgaHNfbm9wb3dlcl9ub3N2YV9kZSwga2VlcGVycyA9IG5vcG93ZXJfa2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9oc19ub3Bvd2VyX3RhYmxlLXZ7dmVyfS54bHN4IikpCiMjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IGV4dHJhKQpoc19ub3Bvd2VyX25vc3ZhX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgaHNfbm9wb3dlcl9ub3N2YV90YWJsZSwKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9oc19ub3Bvd2VyX25vc3ZhX3NpZy12e3Zlcn0ueGxzeCIpKQoKZDAxZDAyX3p5bW9fbm9zdmFfY29tcCA8LSBtZXJnZShoc19ub3Bvd2VyX25vc3ZhX3RhYmxlW1siZGF0YSJdXVtbImQwMV96eW1vIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhzX25vcG93ZXJfbm9zdmFfdGFibGVbWyJkYXRhIl1dW1siZDAyX3p5bW8iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9InJvdy5uYW1lcyIpCmQwMTAyX3p5bW9fbm9zdmFfcGxvdCA8LSBwbG90X2xpbmVhcl9zY2F0dGVyKGQwMWQwMl96eW1vX25vc3ZhX2NvbXBbLCBjKCJkZXNlcV9sb2dmYy54IiwgImRlc2VxX2xvZ2ZjLnkiKV0pCmQwMTAyX3p5bW9fbm9zdmFfcGxvdCRzY2F0dGVyCmQwMTAyX3p5bW9fbm9zdmFfcGxvdCRjb3JyZWxhdGlvbgpkMDEwMl96eW1vX25vc3ZhX3Bsb3QkbG1fcnNxCgpkMDlkODFfenltb19ub3N2YV9jb21wIDwtIG1lcmdlKGhzX25vcG93ZXJfbm9zdmFfdGFibGVbWyJkYXRhIl1dW1siZDA5X3p5bW8iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgaHNfbm9wb3dlcl9ub3N2YV90YWJsZVtbImRhdGEiXV1bWyJkODFfenltbyJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBieT0icm93Lm5hbWVzIikKZDA5ODFfenltb19ub3N2YV9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoZDA5ZDgxX3p5bW9fbm9zdmFfY29tcFssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXSkKZDA5ODFfenltb19ub3N2YV9wbG90JHNjYXR0ZXIKZDA5ODFfenltb19ub3N2YV9wbG90JGNvcnJlbGF0aW9uCmQwOTgxX3p5bW9fbm9zdmFfcGxvdCRsbV9yc3EKCmQwMWQ4MV96eW1vX25vc3ZhX2NvbXAgPC0gbWVyZ2UoaHNfbm9wb3dlcl9ub3N2YV90YWJsZVtbImRhdGEiXV1bWyJkMDFfenltbyJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoc19ub3Bvd2VyX25vc3ZhX3RhYmxlW1siZGF0YSJdXVtbImQ4MV96eW1vIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJyb3cubmFtZXMiKQpkMDE4MV96eW1vX25vc3ZhX3Bsb3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihkMDFkODFfenltb19ub3N2YV9jb21wWywgYygiZGVzZXFfbG9nZmMueCIsICJkZXNlcV9sb2dmYy55IildKQpkMDE4MV96eW1vX25vc3ZhX3Bsb3Qkc2NhdHRlcgpkMDE4MV96eW1vX25vc3ZhX3Bsb3QkY29ycmVsYXRpb24KZDAxODFfenltb19ub3N2YV9wbG90JGxtX3JzcQoKdXBzZXRfcGxvdHNfbm9zdmEgPC0gdXBzZXRyX3NpZyhoc19ub3Bvd2VyX25vc3ZhX3NpZywgYm90aD1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1jKCJkMDFfenltbyIsICJkMDJfenltbyIsICJkMDlfenltbyIsICJkODFfenltbyIpKQp1cHNldF9wbG90c19ub3N2YSR1cAp1cHNldF9wbG90c19ub3N2YSRkb3duCnVwc2V0X3Bsb3RzX25vc3ZhJGJvdGgKIyMgVGhlIDd0aCBlbGVtZW50IGluIHRoZSBib3RoIGdyb3VwcyBsaXN0IGlzIHRoZSBzZXQgc2hhcmVkIGFtb25nIGFsbCBkb25vcnMuCiMjIEkgZG9uJ3QgZmVlbCBsaWtlIHdyaXRpbmcgb3V0IHg6eTp6OmEKZ3JvdXBzIDwtIHVwc2V0X3Bsb3RzX25vc3ZhW1siYm90aF9ncm91cHMiXV0Kc2hhcmVkX2dlbmVzIDwtIGF0dHIoZ3JvdXBzLCAiZWxlbWVudHMiKVtncm91cHNbWzddXV0gJT4lCiAgZ3N1YihwYXR0ZXJuID0gIl5nZW5lOiIsIHJlcGxhY2VtZW50ID0gIiIpCnNoYXJlZF9ncCA8LSBzaW1wbGVfZ3Byb2ZpbGVyKHNoYXJlZF9nZW5lcykKc2hhcmVkX2dwJHB2YWx1ZV9wbG90cyRNRgpzaGFyZWRfZ3AkcHZhbHVlX3Bsb3RzJEJQCnNoYXJlZF9ncCRwdmFsdWVfcGxvdHMkUkVBQwpzaGFyZWRfZ3AkcHZhbHVlX3Bsb3RzJFdQCmBgYAoKIyMjIyBBZGQgZG9ub3IgdG8gdGhlIGNvbnRyYXN0cywgc3ZhCgpgYGB7ciBkb25vcl9kcnVnX3p5bW9fZXRjfQpoc19ub3Bvd2VyX3N2YV9kZSA8LSBhbGxfcGFpcndpc2UoaHNfbm9wb3dlciwgbW9kZWxfYmF0Y2ggPSAic3Zhc2VxIiwgZmlsdGVyID0gVFJVRSkKbm9wb3dlcl9rZWVwZXJzIDwtIGxpc3QoCiAgICAiZDAxX3p5bW8iID0gYygiZDAxaW5mejIzIiwgImQwMWluZnoyMiIpLAogICAgImQwMV9zYnp5bW8iID0gYygiZDAxaW5mc2J6MjMiLCAiZDAxaW5mc2J6MjIiKSwKICAgICJkMDJfenltbyIgPSBjKCJkMDJpbmZ6MjMiLCAiZDAyaW5mejIyIiksCiAgICAiZDAyX3NienltbyIgPSBjKCJkMDJpbmZzYnoyMyIsICJkMDJpbmZzYnoyMiIpLAogICAgImQwOV96eW1vIiA9IGMoImQwOWluZnoyMyIsICJkMDlpbmZ6MjIiKSwKICAgICJkMDlfc2J6eW1vIiA9IGMoImQwOWluZnNiejIzIiwgImQwOWluZnNiejIyIiksCiAgICAiZDgxX3p5bW8iID0gYygiZDgxaW5mejIzIiwgImQ4MWluZnoyMiIpLAogICAgImQ4MV9zYnp5bW8iID0gYygiZDgxaW5mc2J6MjMiLCAiZDgxaW5mc2J6MjIiKSkKaHNfbm9wb3dlcl9zdmFfdGFibGUgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBoc19ub3Bvd2VyX3N2YV9kZSwga2VlcGVycyA9IG5vcG93ZXJfa2VlcGVycywKICAgIGV4Y2VsID0gZ2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9oc19ub3Bvd2VyX3RhYmxlLXZ7dmVyfS54bHN4IikpCiMjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IGV4dHJhKQpoc19ub3Bvd2VyX3N2YV9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGhzX25vcG93ZXJfc3ZhX3RhYmxlLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL2hzX25vcG93ZXJfc3ZhX3NpZy12e3Zlcn0ueGxzeCIpKQoKZDAxZDAyX3p5bW9fc3ZhX2NvbXAgPC0gbWVyZ2UoaHNfbm9wb3dlcl9zdmFfdGFibGVbWyJkYXRhIl1dW1siZDAxX3p5bW8iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgaHNfbm9wb3dlcl9zdmFfdGFibGVbWyJkYXRhIl1dW1siZDAyX3p5bW8iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9InJvdy5uYW1lcyIpCmQwMTAyX3p5bW9fc3ZhX3Bsb3QgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihkMDFkMDJfenltb19zdmFfY29tcFssIGMoImRlc2VxX2xvZ2ZjLngiLCAiZGVzZXFfbG9nZmMueSIpXSkKZDAxMDJfenltb19zdmFfcGxvdCRzY2F0dGVyCmQwMTAyX3p5bW9fc3ZhX3Bsb3QkY29ycmVsYXRpb24KZDAxMDJfenltb19zdmFfcGxvdCRsbV9yc3EKCmQwOWQ4MV96eW1vX3N2YV9jb21wIDwtIG1lcmdlKGhzX25vcG93ZXJfc3ZhX3RhYmxlW1siZGF0YSJdXVtbImQwOV96eW1vIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhzX25vcG93ZXJfc3ZhX3RhYmxlW1siZGF0YSJdXVtbImQ4MV96eW1vIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJyb3cubmFtZXMiKQpkMDk4MV96eW1vX3N2YV9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoZDA5ZDgxX3p5bW9fc3ZhX2NvbXBbLCBjKCJkZXNlcV9sb2dmYy54IiwgImRlc2VxX2xvZ2ZjLnkiKV0pCmQwOTgxX3p5bW9fc3ZhX3Bsb3Qkc2NhdHRlcgpkMDk4MV96eW1vX3N2YV9wbG90JGNvcnJlbGF0aW9uCmQwOTgxX3p5bW9fc3ZhX3Bsb3QkbG1fcnNxCgpkMDFkODFfenltb19zdmFfY29tcCA8LSBtZXJnZShoc19ub3Bvd2VyX3N2YV90YWJsZVtbImRhdGEiXV1bWyJkMDFfenltbyJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHNfbm9wb3dlcl9zdmFfdGFibGVbWyJkYXRhIl1dW1siZDgxX3p5bW8iXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJyb3cubmFtZXMiKQpkMDE4MV96eW1vX3N2YV9wbG90IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIoZDAxZDgxX3p5bW9fc3ZhX2NvbXBbLCBjKCJkZXNlcV9sb2dmYy54IiwgImRlc2VxX2xvZ2ZjLnkiKV0pCmQwMTgxX3p5bW9fc3ZhX3Bsb3Qkc2NhdHRlcgpkMDE4MV96eW1vX3N2YV9wbG90JGNvcnJlbGF0aW9uCmQwMTgxX3p5bW9fc3ZhX3Bsb3QkbG1fcnNxCgp1cHNldF9wbG90c19zdmEgPC0gdXBzZXRyX3NpZyhoc19ub3Bvd2VyX3N2YV9zaWcsIGJvdGg9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9YygiZDAxX3p5bW8iLCAiZDAyX3p5bW8iLCAiZDA5X3p5bW8iLCAiZDgxX3p5bW8iKSkKdXBzZXRfcGxvdHNfc3ZhJHVwCnVwc2V0X3Bsb3RzX3N2YSRkb3duCnVwc2V0X3Bsb3RzX3N2YSRib3RoCiMjIFRoZSA3dGggZWxlbWVudCBpbiB0aGUgYm90aCBncm91cHMgbGlzdCBpcyB0aGUgc2V0IHNoYXJlZCBhbW9uZyBhbGwgZG9ub3JzLgojIyBJIGRvbid0IGZlZWwgbGlrZSB3cml0aW5nIG91dCB4Onk6ejphCmdyb3VwcyA8LSB1cHNldF9wbG90c19zdmFbWyJib3RoX2dyb3VwcyJdXQpzaGFyZWRfZ2VuZXMgPC0gYXR0cihncm91cHMsICJlbGVtZW50cyIpW2dyb3Vwc1tbN11dXSAlPiUKICBnc3ViKHBhdHRlcm4gPSAiXmdlbmU6IiwgcmVwbGFjZW1lbnQgPSAiIikKc2hhcmVkX2dwIDwtIHNpbXBsZV9ncHJvZmlsZXIoc2hhcmVkX2dlbmVzKQpzaGFyZWRfZ3AkcHZhbHVlX3Bsb3RzJE1GCnNoYXJlZF9ncCRwdmFsdWVfcGxvdHMkQlAKc2hhcmVkX2dwJHB2YWx1ZV9wbG90cyRSRUFDCnNoYXJlZF9ncCRwdmFsdWVfcGxvdHMkV1AKYGBgCgojIyMgRG9ub3IgY29tcGFyaXNvbgoKYGBge3IgZG9ub3JfZGV9CmhzX2Rvbm9ycyA8LSBzZXRfZXhwdF9jb25kaXRpb25zKGhzX21hY3IsIGZhY3QgPSAiZG9ub3IiKQpkb25vcl9kZSA8LSBhbGxfcGFpcndpc2UoaHNfZG9ub3JzLCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCmRvbm9yX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgZG9ub3JfZGUsCiAgICBleGNlbD1nbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL2Rvbm9yX3RhYmxlcy12e3Zlcn0ueGxzeCIpKQpkb25vcl9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICAgIGRvbm9yX3RhYmxlLAogICAgZXhjZWwgPSBnbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL2Rvbm9yX3NpZy12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyMgUHJpbWFyeSBxdWVyeSBjb250cmFzdHMKClRoZSBmaW5hbCBjb250cmFzdCBpbiB0aGlzIGxpc3QgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBpdCBkZXBlbmRzIG9uCnRoZSBleHRyYSBjb250cmFzdHMgYXBwbGllZCB0byB0aGUgYWxsX3BhaXJ3aXNlKCkgYWJvdmUuICBJbiBteSB3YXkgb2YKdGhpbmtpbmcsIHRoZSBwcmltYXJ5IGNvbXBhcmlzb25zIHRvIGNvbnNpZGVyIGFyZSBlaXRoZXIgY3Jvc3MtZHJ1ZyBvcgpjcm9zcy1zdHJhaW4sIGJ1dCBub3QgYm90aC4gIEhvd2V2ZXIgSSB0aGluayBpbiBhdCBsZWFzdCBhIGZldwppbnN0YW5jZXMgT2xnYSBpcyBpbnRlcmVzdGVkIGluIHN0cmFpbitkcnVnIC8gdW5pbmZlY3RlZCtub2RydWcuCgojIyMjIFdyaXRlIGNvbnRyYXN0IHJlc3VsdHMKCk5vdyBsZXQgdXMgd3JpdGUgb3V0IHRoZSB4bHN4IGZpbGUgY29udGFpbmluZyB0aGUgYWJvdmUgY29udHJhc3RzLgpUaGUgZmlsZSB3aXRoIHRoZSBzdWZmaXggX3RhYmxlLXZlcnNpb24gd2lsbCB0aGVyZWZvcmUgY29udGFpbiBhbGwKZ2VuZXMgYW5kIHRoZSBmaWxlIHdpdGggdGhlIHN1ZmZpeCBfc2lnLXZlcnNpb24gd2lsbCBjb250YWluIG9ubHkKdGhvc2UgZGVlbWVkIHNpZ25pZmljYW50IHZpYSBvdXIgZGVmYXVsdCBjcml0ZXJpYSBvZiBERVNlcTIgfGxvZ0ZDfCA+PSAxLjAKYW5kIGFkanVzdGVkIHAtdmFsdWUgPD0gMC4wNS4KCmBgYHtyIG1ha2VfdGFibGVzX3RtcmMyfQpoc19tYWNyX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgaHNfbWFjcl9kZSwKICAgIGtlZXBlcnMgPSB0bXJjMl9odW1hbl9rZWVwZXJzLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9tYWNyb3BoYWdlX2h1bWFuX3RhYmxlLXZ7dmVyfS54bHN4IikpCmhzX21hY3Jfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBoc19tYWNyX3RhYmxlLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9tYWNyb3BoYWdlX2h1bWFuX3NpZy12e3Zlcn0ueGxzeCIpKQoKdTkzN190YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICAgIHU5MzdfZGUsCiAgICBrZWVwZXJzID0gdG1yYzJfaHVtYW5fa2VlcGVycywKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvdTkzN19odW1hbl90YWJsZS12e3Zlcn0ueGxzeCIpKQp1OTM3X3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgdTkzN190YWJsZSwKICAgIGV4Y2VsPWdsdWU6OmdsdWUoImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvdTkzN19odW1hbl9zaWctdnt2ZXJ9Lnhsc3giKSkKYGBgCgojIE92ZXIgcmVwcmVzZW50YXRpb24gc2VhcmNoZXMKCkkgZGVjaWRlZCB0byBtYWtlIG9uZSBpbml0aWFsbHkgc21hbGwsIGJ1dCBJIHRoaW5rIHF1aWNrbHkgYmlnIGNoYW5nZQp0byB0aGUgb3JnYW5pemF0aW9uIG9mIHRoaXMgZG9jdW1lbnQ6ICBJIGFtIG1vdmluZyB0aGUgR1NFQSBzZWFyY2hlcwp1cCB0byBpbW1lZGlhdGVseSBhZnRlciB0aGUgREUuICBJIHdpbGwgdGhlbiBtb3ZlIHRoZSBwbG90cyBvZiB0aGUKZ3Byb2ZpbGVyIHJlc3VsdHMgdG8gaW1tZWRpYXRlbHkgYWZ0ZXIgdGhlIHZhcmlvdXMgdm9sY2FubyBwbG90cyBzbwp0aGF0IGl0IGlzIGVhc2llciB0byBpbnRlcnByZXQgdGhlbS4KCmBgYHtyIG92ZXJfcmVwcmVzZW50X2RhdGF9CmFsbF9ncCA8LSBhbGxfZ3Byb2ZpbGVyKGhzX21hY3Jfc2lnKQpgYGAKCiMgUGxvdCBjb250cmFzdHMgb2YgaW50ZXJlc3QKCk9uZSBzdWdnZXN0aW9uIEkgcmVjZWl2ZWQgcmVjZW50bHkgd2FzIHRvIHNldCB0aGUgYXhlcyBmb3IgdGhlc2UKdm9sY2FubyBwbG90cyB0byBiZSBzdGF0aWMgcmF0aGVyIHRoYW4gbGV0IGdncGxvdCBjaG9vc2UgaXRzIG93bi4gIEkKYW0gYXNzdW1pbmcgdGhpcyBpcyBvbmx5IHJlbGV2YW50IGZvciBwYWlycyBvZiBjb250cmFzdHMsIGJ1dCB0aGF0Cm1pZ2h0IG5vdCBiZSB0cnVlLgoKIyMgSW5kaXZpZHVhbCB6eW1vZGVtZXMgdnMuIHVuaW5mZWN0ZWQKCmBgYHtyIGhzX21hY3JvcGhhZ2Vfc2lnX2dlbmVzXzIzMjJ2c3VuaW5mfQp6MjNub3NiX3ZzX3VuaW5mX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2RlKAogICAgdGFibGUgPSBoc19tYWNyX3RhYmxlW1siZGF0YSJdXVtbInoyM25vc2JfdnNfdW5pbmYiXV0sCiAgICBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICAgIHNoYXBlc19ieV9zdGF0ZSA9IEZBTFNFLCBjb2xvcl9ieSA9ICJmYyIsICBsYWJlbCA9IDEwLCBsYWJlbF9jb2x1bW4gPSAiaGduY3N5bWJvbCIpCgpwbG90bHk6OmdncGxvdGx5KHoyM25vc2JfdnNfdW5pbmZfdm9sY2FubyRwbG90KQp6MjJub3NiX3ZzX3VuaW5mX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2RlKAogICAgdGFibGUgPSBoc19tYWNyX3RhYmxlW1siZGF0YSJdXVtbInoyMm5vc2JfdnNfdW5pbmYiXV0sCiAgICBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICAgIHNoYXBlc19ieV9zdGF0ZSA9IEZBTFNFLCBjb2xvcl9ieSA9ICJmYyIsICBsYWJlbCA9IDEwLCBsYWJlbF9jb2x1bW4gPSAiaGduY3N5bWJvbCIpCnBsb3RseTo6Z2dwbG90bHkoejIybm9zYl92c191bmluZl92b2xjYW5vJHBsb3QpCmBgYAoKIyMjIFp5bW9kZW1lIDIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQKCmBgYHtyIHp5bW8yM192c191bmluZn0KejIzbm9zYl92c191bmluZl92b2xjYW5vJHBsb3QgKwogIHhsaW0oLTEwLCAyNSkgKwogIHlsaW0oMCwgNDApCgpwcChmaWxlPSJpbWFnZXMvejIzX3VuaW5mX3JlYWN0b21lX3VwLnBuZyIsIGltYWdlPWFsbF9ncFtbInoyM25vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJSRUFDIl1dLCBoZWlnaHQ9MTIsIHdpZHRoPTkpCiMjIFJlYWN0b21lLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIzbm9zYl92c191bmluZl91cCJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIktFR0ciXV0KIyMgS0VHRywgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM25vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM25vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJURiJdXQojIyBURiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM25vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJXUCJdXQojIyBXaWtpUGF0aHdheXMsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjNub3NiX3ZzX3VuaW5mX3VwIl1dW1siaW50ZXJhY3RpdmVfcGxvdHMiXV1bWyJXUCJdXQoKYWxsX2dwW1siejIzbm9zYl92c191bmluZl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgZG93bi4KYWxsX2dwW1siejIzbm9zYl92c191bmluZl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siTUYiXV0KIyMgTUYsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIGRvd24uCmFsbF9ncFtbInoyM25vc2JfdnNfdW5pbmZfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgpgYGAKCmBgYHtyIHoyMm5vc2JfdnNfdW5pbmZfcGxvdHN9CnoyMm5vc2JfdnNfdW5pbmZfdm9sY2FubyRwbG90ICsKICB4bGltKC0xMCwgMjUpICsKICB5bGltKDAsIDQwKQoKcHAoZmlsZT0iaW1hZ2VzL3oyMl91bmluZl9yZWFjdG9tZV91cC5wbmciLCBpbWFnZT1hbGxfZ3BbWyJ6MjJub3NiX3ZzX3VuaW5mX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXSwgaGVpZ2h0PTEyLCB3aWR0aD05KQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjIgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyMm5vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjIgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyMm5vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJURiJdXQojIyBURiwgenltb2RlbWUyLjIgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyMm5vc2JfdnNfdW5pbmZfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJXUCJdXQojIyBXaWtpUGF0aHdheXMsIHp5bW9kZW1lMi4yIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgoKYWxsX2dwW1siejIybm9zYl92c191bmluZl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjIgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgZG93bi4KYWxsX2dwW1siejIybm9zYl92c191bmluZl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siTUYiXV0KIyMgTUYsIHp5bW9kZW1lMi4yIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIGRvd24uCmFsbF9ncFtbInoyMm5vc2JfdnNfdW5pbmZfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgpgYGAKCkNoZWNrIHRoYXQgbXkgcGVyY2VwdGlvbiBvZiB0aGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IHVwL2Rvd24gZ2VuZXMKbWF0Y2hlcyB3aGF0IHRoZSB0YWJsZS92ZW5uIHNheXMuCgpgYGB7ciBjaGVja19zaWdfdmVubjAxfQpzaGFyZWQgPC0gVmVubmVyYWJsZTo6VmVubihsaXN0KCJkcnVnIiA9IHJvd25hbWVzKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJ6MjNzYl92c191bmluZiJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vZHJ1ZyIgPSByb3duYW1lcyhoc19tYWNyX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siejIzbm9zYl92c191bmluZiJdXSkpKQpwcChmaWxlPSJpbWFnZXMvejIzX3ZzX3VuaW5mX3Zlbm5fdXAucG5nIikKVmVubmVyYWJsZTo6cGxvdChzaGFyZWQpCmRldi5vZmYoKQpWZW5uZXJhYmxlOjpwbG90KHNoYXJlZCkKIyMgSSBzZWUgOTEwIHoyM3NiL3VuaW5mIGFuZCA2NzAgbm8gejIzbm9zYi91bmluZiBnZW5lcyBpbiB0aGUgdmVubiBkaWFncmFtLgpsZW5ndGgoc2hhcmVkQEludGVyc2VjdGlvblNldHNbWyIxMCJdXSkgKyBsZW5ndGgoc2hhcmVkQEludGVyc2VjdGlvblNldHNbWyIxMSJdXSkKZGltKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJ6MjNzYl92c191bmluZiJdXSkKCnNoYXJlZCA8LSBWZW5uZXJhYmxlOjpWZW5uKGxpc3QoImRydWciID0gcm93bmFtZXMoaHNfbWFjcl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInoyMnNiX3ZzX3VuaW5mIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibm9kcnVnIiA9IHJvd25hbWVzKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJ6MjJub3NiX3ZzX3VuaW5mIl1dKSkpCnBwKGZpbGU9ImltYWdlcy96MjJfdnNfdW5pbmZfdmVubl91cC5wbmciKQpWZW5uZXJhYmxlOjpwbG90KHNoYXJlZCkKZGV2Lm9mZigpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkKQoKbGVuZ3RoKHNoYXJlZEBJbnRlcnNlY3Rpb25TZXRzW1siMTAiXV0pICsgbGVuZ3RoKHNoYXJlZEBJbnRlcnNlY3Rpb25TZXRzW1siMTEiXV0pCmRpbShoc19tYWNyX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siejIyc2JfdnNfdW5pbmYiXV0pCmBgYAoKKk5vdGUgdG8gc2VsZio6IFRoZXJlIGlzIGFuIGVycm9yIGluIG15IHZvbGNhbm8gcGxvdCBjb2RlIHdoaWNoIHRha2VzCmVmZmVjdCB3aGVuIHRoZSBudW1lcmF0b3IgYW5kIGRlbm9taW5hdG9yIG9mIHRoZSBhbGxfcGFpcndpc2UKY29udHJhc3RzIGFyZSBkaWZmZXJlbnQgdGhhbiB0aG9zZSBpbiBjb21iaW5lX2RlX3RhYmxlcy4gIEl0IGlzCnB1dHRpbmcgdGhlIHVwcy9kb3ducyBvbiB0aGUgY29ycmVjdCBzaWRlcyBvZiB0aGUgcGxvdCwgYnV0IGNhbGxpbmcKdGhlIGRvd24gZ2VuZXMgJ3VwJyBhbmQgdmljZS12ZXJzYS4gIFRoZSByZWFzb24gZm9yIHRoaXMgaXMgdGhhdCBJIGRpZAphIGNoZWNrIGZvciB0aGlzIGhhcHBlbmluZywgYnV0IHVzZWQgdGhlIHdyb25nIGFyZ3VtZW50IHRvIGhhbmRsZSBpdC4KCkEgbGlrZWx5IGJpdCBvZiB0ZXh0IGZvciB0aGVzZSB2b2xjYW5vIHBsb3RzOgoKVGhlIHNldCBvZiBnZW5lcyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0aGUgenltb2RlbWUgMi4zCmFuZCB1bmluZmVjdGVkIHNhbXBsZXMgd2l0aG91dCBkcnVnZSB0cmVhdG1lbnQgd2FzIHF1YW50aWZpZWQgd2l0aApERVNlcTIgYW5kIGluY2x1ZGVkIHN1cnJvZ2F0ZSBlc3RpbWF0ZXMgZnJvbSBTVkEuICBHaXZlbiB0aGUgY3JpdGVyaWEKb2Ygc2lnbmlmaWNhbmNlIG9mIGEgYWJzKGxvZ0ZDKSA+PSAxLjAgYW5kIGZhbHNlIGRpc2NvdmVyeSByYXRlCmFkanVzdGVkIHAtdmFsdWUgPD0gMC4wNSwgNjcwIGdlbmVzIHdlcmUgb2JzZXJ2ZWQgYXMgc2lnbmlmaWNhbnRseQppbmNyZWFzZWQgYmV0d2VlbiB0aGUgaW5mZWN0ZWQgYW5kIHVuaW5mZWN0ZWQgc2FtcGxlcyBhbmQgMzg2IHdlcmUKb2JzZXJ2ZWQgYXMgZGVjcmVhc2VkLiBUaGUgbW9zdCBpbmNyZWFzZWQgZ2VuZXMgZnJvbSB0aGUgdW5pbmZlY3RlZApzYW1wbGVzIGluY2x1ZGUgc29tZSB3aGljaCBhcmUgcG90ZW50aWFsbHkgaW5kaWNhdGl2ZSBvZiBhIHN0cm9uZwppbm5hdGUgaW1tdW5lIHJlc3BvbnNlIGFuZCB0aGUgaW5mbGFtbWF0b3J5IHJlc3BvbnNlLgoKSW4gY29udHJhc3QsIHdoZW4gdGhlIHNldCBvZiBnZW5lcyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2Vlbgp0aGUgenltb2RlbWUgMi4yIGFuZCB1bmluZmVjdGVkIHNhbXBsZXMgd2FzIHZpc3VhbGl6ZWQsIG9ubHkgNyBnZW5lcwp3ZXJlIG9ic2VydmVkIGFzIGRlY3JlYXNlZCBhbmQgNDM1IGluY3JlYXNlZC4gIFRoZSBpbmZsYW1tYXRvcnkKcmVzcG9uc2Ugd2FzIHNpZ25pZmljYW50bHkgbGVzcyBhcHBhcmVudCBpbiB0aGlzIHNldCwgYnV0IGluc3RlYWQKaW5jbHVkZWQgZ2VuZXMgcmVsYXRlZCB0byB0cmFuc3BvcnRlciBhY3Rpdml0eSBhbmQgb3hpZG9yZWR1Y3Rhc2VzLgoKIyMgRGlyZWN0IHp5bW9kZW1lIGNvbXBhcmlzb25zCgpBbiBvcnRob2dvbmFsIGNvbXBhcmlzb24gdG8gdGhhdCBwZXJmb3JtZWQgYWJvdmUgaXMgdG8gZGlyZWN0bHkKY29tcGFyZSB0aGUgenltb2RlbWUgMi4zIGFuZCAyLjIgc2FtcGxlcyB3aXRoIGFuZCB3aXRob3V0IGFudGltb25pYWwKdHJlYXRtZW50LgoKYGBge3IgejIyejIzX2NvbXBhcmlzb25fcGxvdHN9CnoyM25vc2JfdnNfejIybm9zYl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19kZSgKICAgIHRhYmxlID0gaHNfbWFjcl90YWJsZVtbImRhdGEiXV1bWyJ6MjNub3NiX3ZzX3oyMm5vc2IiXV0sCiAgICBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICAgIHNoYXBlc19ieV9zdGF0ZSA9IEZBTFNFLCBjb2xvcl9ieSA9ICJmYyIsICBsYWJlbCA9IDEwLCBsYWJlbF9jb2x1bW4gPSAiaGduY3N5bWJvbCIpCnBsb3RseTo6Z2dwbG90bHkoejIzbm9zYl92c196MjJub3NiX3ZvbGNhbm8kcGxvdCkKCnoyM3NiX3ZzX3oyMnNiX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2RlKAogICAgdGFibGUgPSBoc19tYWNyX3RhYmxlW1siZGF0YSJdXVtbInoyM3NiX3ZzX3oyMnNiIl1dLAogICAgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgICBzaGFwZXNfYnlfc3RhdGUgPSBGQUxTRSwgY29sb3JfYnkgPSAiZmMiLCAgbGFiZWwgPSAxMCwgbGFiZWxfY29sdW1uID0gImhnbmNzeW1ib2wiKQpwbG90bHk6OmdncGxvdGx5KHoyM3NiX3ZzX3oyMnNiX3ZvbGNhbm8kcGxvdCkKYGBgCgpgYGB7ciB6MjNub3NiX3ZzX3oyMm5vc2JfcGxvdHN9CnoyM25vc2JfdnNfejIybm9zYl92b2xjYW5vJHBsb3QgKwogIHhsaW0oLTEwLCAxMCkgKwogIHlsaW0oMCwgNjApCgpwcChmaWxlPSJpbWFnZXMvejIzbm9zYl92c196MjJub3NiX3JlYWN0b21lX3VwLnBuZyIsIGltYWdlPWFsbF9ncFtbInoyM25vc2JfdnNfejIybm9zYl91cCJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlJFQUMiXV0sIGhlaWdodD0xMiwgd2lkdGg9OSkKIyMgUmVhY3RvbWUsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjNub3NiX3ZzX3oyMm5vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJLRUdHIl1dCiMjIEtFR0csIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjNub3NiX3ZzX3oyMm5vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM25vc2JfdnNfejIybm9zYl91cCJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIzbm9zYl92c196MjJub3NiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siV1AiXV0KIyMgV2lraVBhdGh3YXlzLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIzbm9zYl92c196MjJub3NiX3VwIl1dW1siaW50ZXJhY3RpdmVfcGxvdHMiXV1bWyJXUCJdXQoKYWxsX2dwW1siejIzbm9zYl92c196MjJub3NiX2Rvd24iXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJSRUFDIl1dCiMjIFJlYWN0b21lLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgphbGxfZ3BbWyJ6MjNub3NiX3ZzX3oyMm5vc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIk1GIl1dCiMjIE1GLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgphbGxfZ3BbWyJ6MjNub3NiX3ZzX3oyMm5vc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgpgYGAKCmBgYHtyIHoyM192c196MjJzYl9wbG90c30KejIzc2JfdnNfejIyc2Jfdm9sY2FubyRwbG90ICsKICB4bGltKC0xMCwgMTApICsKICB5bGltKDAsIDYwKQoKcHAoZmlsZT0iaW1hZ2VzL3oyM3NiX3ZzX3oyMnNiX3JlYWN0b21lX3VwLnBuZyIsIGltYWdlPWFsbF9ncFtbInoyM3NiX3ZzX3oyMnNiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXSwgaGVpZ2h0PTEyLCB3aWR0aD05KQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyMnNiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siS0VHRyJdXQojIyBLRUdHLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIzc2JfdnNfejIyc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyMnNiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siVEYiXV0KIyMgVEYsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjNzYl92c196MjJzYl91cCJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIldQIl1dCiMjIFdpa2lQYXRod2F5cywgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyMnNiX3VwIl1dW1siaW50ZXJhY3RpdmVfcGxvdHMiXV1bWyJXUCJdXQoKYWxsX2dwW1siejIzc2JfdnNfejIyc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlJFQUMiXV0KIyMgUmVhY3RvbWUsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIGRvd24uCmFsbF9ncFtbInoyM3NiX3ZzX3oyMnNiX2Rvd24iXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgZG93bi4KYWxsX2dwW1siejIzc2JfdnNfejIyc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgpgYGAKCgpgYGB7ciB6MjNzYl92c196MjJzYl92ZW5ufQpzaGFyZWQgPC0gVmVubmVyYWJsZTo6VmVubihsaXN0KCJkcnVnIiA9IHJvd25hbWVzKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJ6MjNzYl92c196MjJzYiJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vZHJ1ZyIgPSByb3duYW1lcyhoc19tYWNyX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1siejIzbm9zYl92c196MjJub3NiIl1dKSkpCnBwKGZpbGU9ImltYWdlcy9kcnVnX25vZHJ1Z192ZW5uX3VwLnBuZyIpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkKQpkZXYub2ZmKCkKVmVubmVyYWJsZTo6cGxvdChzaGFyZWQpCgpzaGFyZWQgPC0gVmVubmVyYWJsZTo6VmVubihsaXN0KCJkcnVnIiA9IHJvd25hbWVzKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbInoyM3NiX3ZzX3oyMnNiIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibm9kcnVnIiA9IHJvd25hbWVzKGhzX21hY3Jfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbInoyM25vc2JfdnNfejIybm9zYiJdXSkpKQpwcChmaWxlPSJpbWFnZXMvZHJ1Z19ub2RydWdfdmVubl9kb3duLnBuZyIpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkKQpkZXYub2ZmKCkKYGBgCgpBIHNsaWdodGx5IGRpZmZlcmVudCB3YXkgb2YgbG9va2luZyBhdCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvCnp5bW9kZW1lIGluZmVjdGlvbnMgaXMgdG8gZGlyZWN0bHkgY29tcGFyZSB0aGUgaW5mZWN0ZWQgc2FtcGxlcyB3aXRoCmFuZCB3aXRob3V0IGRydWcuICBUaHVzLCB3aGVuIGEgdm9sY2FubyBwbG90IHNob3dpbmcgdGhlIGNvbXBhcmlzb24gb2YKdGhlIHp5bW9kZW1lIDIuMyB2cy4gMi4yIHNhbXBsZXMgd2FzIHBsb3R0ZWQsIDQ4NCBnZW5lcyB3ZXJlIG9ic2VydmVkCmFzIGluY3JlYXNlZCBhbmQgNDIyIGRlY3JlYXNlZDsgdGhlc2UgZ3JvdXBzIGluY2x1ZGUgbWFueSBvZiB0aGUgc2FtZQppbmZsYW1tYXRvcnkgKHVwKSBhbmQgbWVtYnJhbmUgKGRvd24pIGdlbmVzLgoKU2ltaWxhciBwYXR0ZXJucyB3ZXJlIG9ic2VydmVkIHdoZW4gdGhlIGFudGltb25pYWwgd2FzIGluY2x1ZGVkLgpUaHVzLCB3aGVuIGEgVmVubiBkaWFncmFtIG9mIHRoZSB0d28gc2V0cyBvZiBpbmNyZWFzZWQgZ2VuZXMgd2FzCnBsb3R0ZWQsIGEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHRoZSBnZW5lcyB3YXMgb2JzZXJ2ZWQgYXMgaW5jcmVhc2VkCigzMTMpIGFuZCBkZWNyZWFzZWQgKDI0NCkgaW4gYm90aCB0aGUgdW50cmVhdGVkIGFuZCBhbnRpbW9uaWFsIHRyZWF0ZWQKc2FtcGxlcy4KCiMjIERydWcgZWZmZWN0cyBvbiBlYWNoIHp5bW9kZW1lIGluZmVjdGlvbgoKQW5vdGhlciBsaWtlbHkgcXVlc3Rpb24gaXMgdG8gZGlyZWN0bHkgY29tcGFyZSB0aGUgdHJlYXRlZCB2cwp1bnRyZWF0ZWQgc2FtcGxlcyBmb3IgZWFjaCB6eW1vZGVtZSBpbmZlY3Rpb24gaW4gb3JkZXIgdG8gdmlzdWFsaXplCnRoZSBlZmZlY3RzIG9mIGFudGltb25pYWwuCgpgYGB7ciB6MjNkcnVnX3oyM25vZHJ1Z196MjJkcnVnX3oyMm5vZHJ1Z19wbG90c30KejIzc2JfdnNfejIzbm9zYl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19kZSgKICAgIHRhYmxlID0gaHNfbWFjcl90YWJsZVtbImRhdGEiXV1bWyJ6MjNzYl92c196MjNub3NiIl1dLAogICAgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgICBzaGFwZXNfYnlfc3RhdGUgPSBGQUxTRSwgY29sb3JfYnkgPSAiZmMiLCAgbGFiZWwgPSAxMCwgbGFiZWxfY29sdW1uID0gImhnbmNzeW1ib2wiKQpwbG90bHk6OmdncGxvdGx5KHoyM3NiX3ZzX3oyM25vc2Jfdm9sY2FubyRwbG90KQp6MjJzYl92c196MjJub3NiX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2RlKAogICAgdGFibGUgPSBoc19tYWNyX3RhYmxlW1siZGF0YSJdXVtbInoyMnNiX3ZzX3oyMm5vc2IiXV0sCiAgICBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICAgIHNoYXBlc19ieV9zdGF0ZSA9IEZBTFNFLCBjb2xvcl9ieSA9ICJmYyIsICBsYWJlbCA9IDEwLCBsYWJlbF9jb2x1bW4gPSAiaGduY3N5bWJvbCIpCnBsb3RseTo6Z2dwbG90bHkoejIyc2JfdnNfejIybm9zYl92b2xjYW5vJHBsb3QpCmBgYAoKYGBge3IgejIzc2JfdnNfejIzbm9zYl9wbG90c30KejIzc2JfdnNfejIzbm9zYl92b2xjYW5vJHBsb3QgKwogIHhsaW0oLTgsIDgpICsKICB5bGltKDAsIDIxMCkKCnBwKGZpbGU9ImltYWdlcy96MjNzYl92c196MjNub3NiX3JlYWN0b21lX3VwLnBuZyIsCiAgIGltYWdlPWFsbF9ncFtbInoyM3NiX3ZzX3oyM25vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJSRUFDIl1dLCBoZWlnaHQ9MTIsIHdpZHRoPTkpCiMjIFJlYWN0b21lLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIzc2JfdnNfejIzbm9zYl91cCJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIktFR0ciXV0KIyMgS0VHRywgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyM25vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJNRiJdXQojIyBNRiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyM25vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJURiJdXQojIyBURiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyM3NiX3ZzX3oyM25vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJXUCJdXQojIyBXaWtpUGF0aHdheXMsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjNzYl92c196MjNub3NiX3VwIl1dW1siaW50ZXJhY3RpdmVfcGxvdHMiXV1bWyJXUCJdXQoKYWxsX2dwW1siejIzc2JfdnNfejIzbm9zYl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgZG93bi4KYWxsX2dwW1siejIzc2JfdnNfejIzbm9zYl9kb3duIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siTUYiXV0KIyMgTUYsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIGRvd24uCmFsbF9ncFtbInoyM3NiX3ZzX3oyM25vc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlRGIl1dCiMjIFRGLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgpgYGAKCmBgYHtyIHoyMnNiX3ZzX3oyMm5vc2JfcGxvdHN9CnoyMnNiX3ZzX3oyMm5vc2Jfdm9sY2FubyRwbG90ICsKICB4bGltKC04LCA4KSArCiAgeWxpbSgwLCAyMTApCgpwcChmaWxlPSJpbWFnZXMvejIyc2JfdnNfejIybm9zYl9yZWFjdG9tZV91cC5wbmciLAogICBpbWFnZT1hbGxfZ3BbWyJ6MjJzYl92c196MjJub3NiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siUkVBQyJdXSwgaGVpZ2h0PTEyLCB3aWR0aD05KQojIyBSZWFjdG9tZSwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgdXAuCmFsbF9ncFtbInoyMnNiX3ZzX3oyMm5vc2JfdXAiXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJLRUdHIl1dCiMjIEtFR0csIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjJzYl92c196MjJub3NiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siTUYiXV0KIyMgTUYsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjJzYl92c196MjJub3NiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siVEYiXV0KIyMgVEYsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIHVwLgphbGxfZ3BbWyJ6MjJzYl92c196MjJub3NiX3VwIl1dW1sicHZhbHVlX3Bsb3RzIl1dW1siV1AiXV0KIyMgV2lraVBhdGh3YXlzLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCB1cC4KYWxsX2dwW1siejIyc2JfdnNfejIybm9zYl91cCJdXVtbImludGVyYWN0aXZlX3Bsb3RzIl1dW1siV1AiXV0KCmFsbF9ncFtbInoyMnNiX3ZzX3oyMm5vc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIlJFQUMiXV0KIyMgUmVhY3RvbWUsIHp5bW9kZW1lMi4zIHdpdGhvdXQgZHJ1ZyB2cy4gdW5pbmZlY3RlZCB3aXRob3V0IGRydWcsIGRvd24uCmFsbF9ncFtbInoyMnNiX3ZzX3oyMm5vc2JfZG93biJdXVtbInB2YWx1ZV9wbG90cyJdXVtbIk1GIl1dCiMjIE1GLCB6eW1vZGVtZTIuMyB3aXRob3V0IGRydWcgdnMuIHVuaW5mZWN0ZWQgd2l0aG91dCBkcnVnLCBkb3duLgphbGxfZ3BbWyJ6MjJzYl92c196MjJub3NiX2Rvd24iXV1bWyJwdmFsdWVfcGxvdHMiXV1bWyJURiJdXQojIyBURiwgenltb2RlbWUyLjMgd2l0aG91dCBkcnVnIHZzLiB1bmluZmVjdGVkIHdpdGhvdXQgZHJ1ZywgZG93bi4KYGBgCgpgYGB7ciB6MjJzYl92c196MjJub3NiX3Zlbm5zfQpzaGFyZWQgPC0gVmVubmVyYWJsZTo6VmVubihsaXN0KCJ6MjMiID0gcm93bmFtZXMoaHNfbWFjcl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInoyM3NiX3ZzX3oyM25vc2IiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ6MjIiID0gcm93bmFtZXMoaHNfbWFjcl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInoyMnNiX3ZzX3oyMm5vc2IiXV0pKSkKcHAoZmlsZT0iaW1hZ2VzL3oyM196MjJfZHJ1Z192ZW5uX3VwLnBuZyIpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkKQpkZXYub2ZmKCkKVmVubmVyYWJsZTo6cGxvdChzaGFyZWQpCgpzaGFyZWQgPC0gVmVubmVyYWJsZTo6VmVubihsaXN0KCJ6MjMiID0gcm93bmFtZXMoaHNfbWFjcl9zaWdbWyJkZXNlcSJdXVtbImRvd25zIl1dW1siejIzc2JfdnNfejIzbm9zYiJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInoyMiIgPSByb3duYW1lcyhoc19tYWNyX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJ6MjJzYl92c196MjJub3NiIl1dKSkpCnBwKGZpbGU9ImltYWdlcy96MjNfejIyX2RydWdfdmVubl9kb3duLnBuZyIpClZlbm5lcmFibGU6OnBsb3Qoc2hhcmVkKQpkZXYub2ZmKCkKVmVubmVyYWJsZTo6cGxvdChzaGFyZWQpCmBgYAoKTm90ZTogSSBhbSBzZXR0aWcgdGhlIHggYW5kIHktYXhpcyBib3VuZGFyaWVzIGJ5IGFsbG93aW5nIHRoZSBwbG90dGVyCnRvIHBpY2sgaXRzIG93biBheGlzIHRoZSBmaXJzdCB0aW1lLCB3cml0aW5nIGRvd24gdGhlIHJhbmdlcyBJCm9ic2VydmUsIGFuZCB0aGVuIHNldHRpbmcgdGhlbSB0byB0aGUgbGFyZ2VzdCBvZiB0aGUgcGFpci4gIEl0IGlzCnRoZXJlZm9yZSBwb3NzaWJsZSB0aGF0IEkgbWlzc2VkIG9uZSBvciBtb3JlIGdlbmVzIHdoaWNoIGxpZXMgb3V0c2lkZQp0aGF0IHJhbmdlLgoKVGhlIHByZXZpb3VzIHBsb3R0ZWQgY29udHJhc3RzIHNvdWdodCB0byBzaG93IGNoYW5nZXMgYmV0d2VlbiB0aGUgdHdvCnN0cmFpbnMgejIuMyBhbmQgejIuMi4gIENvbnZlcnNlbHksIHRoZSBwcmV2aW91cyB2b2xjYW5vIHBsb3RzIHNlZWsgdG8KZGlyZWN0bHkgY29tcGFyZSBlYWNoIHN0cmFpbiBiZWZvcmUvYWZ0ZXIgZHJ1ZyB0cmVhdG1lbnQuCgojIyBMUlQgb2YgdGhlIEh1bWFuIE1hY3JvcGhhZ2UKCmBgYHtyIGxydF90bXJjMl9tYWNyfQp0bXJjMl9scnRfc3RyYWluX2RydWcgPC0gZGVzZXFfbHJ0KGhzX21hY3IsIGludGVyYWN0b3JfY29sdW1uID0gImRydWciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVyZXN0X2NvbHVtbiA9ICJtYWNyb3BoYWdlenltb2RlbWUiLCBmYWN0b3JzID0gYygiZHJ1ZyIsICJtYWNyb3BoYWdlenltb2RlbWUiKSkKdG1yYzJfbHJ0X3N0cmFpbl9kcnVnJGNsdXN0ZXJfZGF0YSRwbG90CmBgYAoKIyMgUGFyYXNpdGUKCmBgYHtyIGxwX2RlfQpscF9tYWNyb3BoYWdlX2RlIDwtIGFsbF9wYWlyd2lzZShscF9tYWNyb3BoYWdlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCnRtcmMyX3BhcmFzaXRlX2tlZXBlcnMgPC0gbGlzdCgKICAgICJ6MjNfdnNfejIyIiA9IGMoInoyMyIsICJ6MjIiKSkKbHBfbWFjcm9waGFnZV90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBscF9tYWNyb3BoYWdlX2RlLCBrZWVwZXJzID0gdG1yYzJfcGFyYXNpdGVfa2VlcGVycywKICBleGNlbD1nbHVlOjpnbHVlKCJhbmFseXNlcy9tYWNyb3BoYWdlX2RlL21hY3JvcGhhZ2VfcGFyYXNpdGVfaW5mZWN0aW9uX2RlLXZ7dmVyfS54bHN4IikpCmxwX21hY3JvcGhhZ2Vfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBscF9tYWNyb3BoYWdlX3RhYmxlLAogICAgZXhjZWw9Z2x1ZTo6Z2x1ZSgiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9tYWNyb3BoYWdlX3BhcmFzaXRlX3NpZy12e3Zlcn0ueGxzeCIpKQoKcHAoZmlsZT0iaW1hZ2VzL2xwX21hY3JvcGhhZ2VfejIzX3oyMi5wbmciLAogICBpbWFnZT1scF9tYWNyb3BoYWdlX3RhYmxlW1sicGxvdHMiXV1bWyJ6MjNub3NiX3ZzX3oyMm5vc2IiXV1bWyJkZXNlcV92b2xfcGxvdHMiXV1bWyJwbG90Il1dKQoKdXBfZ2VuZXMgPC0gbHBfbWFjcm9waGFnZV9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dCmRpbSh1cF9nZW5lcykKZG93bl9nZW5lcyA8LSBscF9tYWNyb3BoYWdlX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWzFdXQpkaW0oZG93bl9nZW5lcykKYGBgCgpgYGB7ciBwYXJhc2l0ZV92b2xjYW5vfQpscF96MjNzYl92c196MjJzYl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19kZSgKICAgIHRhYmxlID0gbHBfbWFjcm9waGFnZV90YWJsZVtbImRhdGEiXV1bWyJ6MjNfdnNfejIyIl1dLAogICAgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgICBzaGFwZXNfYnlfc3RhdGUgPSBGQUxTRSwgY29sb3JfYnkgPSAiZmMiLCAgbGFiZWwgPSAxMCwgbGFiZWxfY29sdW1uID0gImhnbmNzeW1ib2wiKQpwbG90bHk6OmdncGxvdGx5KGxwX3oyM3NiX3ZzX3oyMnNiX3ZvbGNhbm8kcGxvdCkKbHBfejIzc2JfdnNfejIyc2Jfdm9sY2FubyRwbG90CmBgYAoKYGBge3IgZ29zZXFfbHB9CnVwX2dvc2VxIDwtIHNpbXBsZV9nb3NlcSh1cF9nZW5lcywgZ29fZGI9bHBfZ28sIGxlbmd0aF9kYj1scF9sZW5ndGhzKQojIyBWaWV3IGNhdGVnb3JpZXMgb3ZlciByZXByZXNlbnRlZCBpbiB0aGUgMi4zIHNhbXBsZXMKdXBfZ29zZXEkcHZhbHVlX3Bsb3RzJGJwcF9wbG90X292ZXIKZG93bl9nb3NlcSA8LSBzaW1wbGVfZ29zZXEoZG93bl9nZW5lcywgZ29fZGI9bHBfZ28sIGxlbmd0aF9kYj1scF9sZW5ndGhzKQojIyBWaWV3IGNhdGVnb3JpZXMgb3ZlciByZXByZXNlbnRlZCBpbiB0aGUgMi4yIHNhbXBsZXMKZG93bl9nb3NlcSRwdmFsdWVfcGxvdHMkYnBwX3Bsb3Rfb3ZlcgpgYGAKCiMgR1NWQQoKYGBge3IgZ3N2YX0KaHNfaW5mZWN0ZWQgPC0gc3Vic2V0X2V4cHQoaHNfbWFjcm9waGFnZSwgc3Vic2V0PSJtYWNyb3BoYWdldHJlYXRtZW50IT0ndW5pbmYnIikgJT4lCiAgc3Vic2V0X2V4cHQoc3Vic2V0PSJtYWNyb3BoYWdldHJlYXRtZW50IT0ndW5pbmZfc2InIikKaHNfZ3N2YV9jMiA8LSBzaW1wbGVfZ3N2YShoc19pbmZlY3RlZCkKaHNfZ3N2YV9jMl9tZXRhIDwtIGdldF9tc2lnZGJfbWV0YWRhdGEoaHNfZ3N2YV9jMiwgbXNpZ194bWw9InJlZmVyZW5jZS9tc2lnZGJfdjcuMi54bWwiKQpoc19nc3ZhX2MyX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcyhoc19nc3ZhX2MyX21ldGEsIGV4Y2VsID0gImFuYWx5c2VzL21hY3JvcGhhZ2VfZGUvaHNfbWFjcm9waGFnZV9nc3ZhX2MyX3NpZy54bHN4IikKaHNfZ3N2YV9jMl9zaWckcmF3X3Bsb3QKCmhzX2dzdmFfYzcgPC0gc2ltcGxlX2dzdmEoaHNfaW5mZWN0ZWQsIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJjNyIpCmhzX2dzdmFfYzdfbWV0YSA8LSBnZXRfbXNpZ2RiX21ldGFkYXRhKGhzX2dzdmFfYzcsIG1zaWdfeG1sPSJyZWZlcmVuY2UvbXNpZ2RiX3Y3LjIueG1sIikKaHNfZ3N2YV9jN19zaWcgPC0gZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoaHNfZ3N2YV9jNywgZXhjZWwgPSAiYW5hbHlzZXMvbWFjcm9waGFnZV9kZS9oc19tYWNyb3BoYWdlX2dzdmFfYzdfc2lnLnhsc3giKQpoc19nc3ZhX2M3X3NpZyRyYXdfcGxvdApgYGAKCiMgVHJ5IG91dCBhIG5ldyB0b29sCgpUd28gcmVhc29uczogTmFqaWIgbG92ZXMgaGltIHNvbWUgUENBLCB0aGlzIHVzZXMgd2lraXBhdGh3YXlzLCB3aGljaCBpcyBzb21ldGhpbmcgSSB0aGluayBpcyBuZWF0LgoKT2ssIEkgc3BlbnQgc29tZSB0aW1lIGxvb2tpbmcgdGhyb3VnaCB0aGUgY29kZSBhbmQgSSBoYXZlIHNvbWUKcHJvYmxlbXMgd2l0aCBzb21lIG9mIHRoZSBkZXNpZ24gZGVjaXNpb25zLgoKTW9zdCBpbXBvcnRhbnRseSwgaXQgcmVxdWlyZXMgYSBkYXRhLmZyYW1lKCkgd2hpY2ggaGFzIHRoZSBmb2xsb3dpbmcgZm9ybWF0OgoKMS4gIE5vIHJvd25hbWVzLCBpbnN0ZWFkIGNvbHVtbiAjMSBpcyB0aGUgc2FtcGxlIElELgoyLiAgQ29sdW1ucyAyLW0gYXJlIHRoZSBjYXRlZ29yaWNhbC9zdXJ2aXZhbC9ldGMgbWV0cmljcy4KMy4gIENvbHVtbnMgbS1uIGFyZSAxIGdlbmUtcGVyLWNvbHVtbiB3aXRoIGxvZzIgdmFsdWVzLgoKQnV0IHdoZW4gSSB0aGluayBhYm91dCBpdCBJIHRoaW5rIEkgZ2V0IHRoZSBpZGVhLCB0aGV5IHdhbnQgdG8gYmUgYWJsZSB0byBkbyBtb2RlbGxpbmcgc3R1ZmYKbW9yZSBlYXNpbHkgd2l0aCByZXNwb25zZSBmYWN0b3JzLgoKYGBge3IgcGF0aHdheVBDQSwgZXZhbD1GQUxTRX0KbGlicmFyeShwYXRod2F5UENBKQpsaWJyYXJ5KHJXaWtpUGF0aHdheXMpCgpkb3dubG9hZGVkIDwtIGRvd25sb2FkUGF0aHdheUFyY2hpdmUob3JnYW5pc20gPSAiSG9tbyBzYXBpZW5zIiwgZm9ybWF0ID0gImdtdCIpCmRhdGFfcGF0aCA8LSBzeXN0ZW0uZmlsZSgiZXh0ZGF0YSIsIHBhY2thZ2U9InBhdGh3YXlQQ0EiKQp3aWtpcGF0aHdheXMgPC0gcmVhZF9nbXQocGFzdGUwKGRhdGFfcGF0aCwgIi93aWtpcGF0aHdheXNfaHVtYW5fc3ltYm9sLmdtdCIpLCBkZXNjcmlwdGlvbj1UUlVFKQoKZXhwdCA8LSBzdWJzZXRfZXhwdChoc19tYWNyb3BoYWdlLCBzdWJzZXQ9Im1hY3JvcGhhZ2V0cmVhdG1lbnQhPSd1bmluZiciKSAlPiUKICBzdWJzZXRfZXhwdChzdWJzZXQ9Im1hY3JvcGhhZ2V0cmVhdG1lbnQhPSd1bmluZl9zYiciKQpleHB0IDwtIHNldF9leHB0X2NvbmRpdGlvbnMoZXhwdCwgZmFjdD0ibWFjcm9waGFnZXp5bW9kZW1lIikKCnN5bWJvbF92ZWN0b3IgPC0gZkRhdGEoZXhwdClbW3N5bWJvbF9jb2x1bW5dXQpuYW1lcyhzeW1ib2xfdmVjdG9yKSA8LSByb3duYW1lcyhmRGF0YShleHB0KSkKc3ltYm9sX2RmIDwtIGFzLmRhdGEuZnJhbWUoc3ltYm9sX3ZlY3RvcikKCmFzc2F5X2RmIDwtIG1lcmdlKHN5bWJvbF9kZiwgYXMuZGF0YS5mcmFtZShleHBycyhleHB0KSksIGJ5ID0gInJvdy5uYW1lcyIpCmFzc2F5X2RmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKcm93bmFtZXMoYXNzYXlfZGYpIDwtIG1ha2UubmFtZXMoYXNzYXlfZGZbWyJzeW1ib2xfdmVjdG9yIl1dLCB1bmlxdWUgPSBUUlVFKQphc3NheV9kZltbInN5bWJvbF92ZWN0b3IiXV0gPC0gTlVMTAphc3NheV9kZiA8LSBhcy5kYXRhLmZyYW1lKHQoYXNzYXlfZGYpKQphc3NheV9kZltbIlNhbXBsZUlEIl1dIDwtIHJvd25hbWVzKGFzc2F5X2RmKQphc3NheV9kZiA8LSBkcGx5cjo6c2VsZWN0KGFzc2F5X2RmLCAiU2FtcGxlSUQiLCBldmVyeXRoaW5nKCkpCgpmYWN0b3JfZGYgPC0gYXMuZGF0YS5mcmFtZShwRGF0YShleHB0KSkKZmFjdG9yX2RmW1siU2FtcGxlSUQiXV0gPC0gcm93bmFtZXMoZmFjdG9yX2RmKQpmYWN0b3JfZGYgPC0gZHBseXI6OnNlbGVjdChmYWN0b3JfZGYsICJTYW1wbGVJRCIsIGV2ZXJ5dGhpbmcoKSkKZmFjdG9yX2RmIDwtIGZhY3Rvcl9kZlssIGMoIlNhbXBsZUlEIiwgZmFjdG9ycyldCgp0dCA8LSBDcmVhdGVPbWljcygKICAgIGFzc2F5RGF0YV9kZiA9IGFzc2F5X2RmLAogICAgcGF0aHdheUNvbGxlY3Rpb25fbHMgPSB3aWtpcGF0aHdheXMsCiAgICByZXNwb25zZSA9IGZhY3Rvcl9kZiwKICAgIHJlc3BUeXBlID0gImNhdGVnb3JpY2FsIiwKICAgIG1pblBhdGhTaXplPTUpCgpzdXBlciA8LSBBRVNQQ0FfcFZhbHMoCiAgICBvYmplY3QgPSB0dCwKICAgIG51bVBDcyA9IDIsCiAgICBwYXJhbGxlbCA9IEZBTFNFLAogICAgbnVtQ29yZXMgPSA4LAogICAgbnVtUmVwcyA9IDIsCiAgICBhZGp1c3RtZW50ID0gIkJIIikKYGBgCgpgYGB7ciBzYXZlbWV9CiMjIFN0b3BwaW5nIHRoaXMgYmVjYXVzZSBpdCB0YWtlcyBmb3JldmVyCiMjaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiMjICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQojIyAgbWVzc2FnZSgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKQojIyAgbWVzc2FnZSgiU2F2aW5nIHRvICIsIHNhdmVmaWxlKQojIyAgdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKIyN9CmBgYAoKYGBge3IgbG9hZG1lX2FmdGVyLCBldmFsID0gRkFMU0V9CnRtcCA8LSBsb2FkbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==