Annotation data
I am pulling this from Theresa’s anxontrapR_pipeline.Rmd, primarily
because it looks similar to the other documents, but was modified more
recently. I will change it slightly, primarily because I grabbed a new
mmusculus assembly and therefore I will pull the mmusculus annotations
from a specific biomart (@smedleyBioMartBiologicalQueries2009) archive
that should match it.
A note from the future: multiple ensembl archive servers have been
taken offline since last I ran this. Let us see if Feb. 2023 still
works.
An important
note!
In the recent past, ensembl queries have become inconsistent, failing
much more often than ever in the past. I do not think this is the fault
of ensembl; but I think I need a fallback mechanism for collecting
annotation information.
In the case of ensembl, it should be trivial (but less fun) to use a
combination of the locally installed orgdb and txdb databases.
This does open a risk that the set of genes with annotations will be
different depending on when the container is run due to differences
between the orgdb/txdb instance and the Feb 2023 biomart. I am not sure
there is much I can do about that except to bundle the set of
annotations I downloaded in the container – since
load_biomart_annotations() does save a rda copy of its download.
ok, I did both. If you, dear reader, wish to download your own
annotations, and ensembl is having troubles, the following should work
without a problem; in addition the rda annotations are in /data of the
container and should get loaded.
tx_gene_map <- data.frame()
mm_annot <- try(load_biomart_annotations(species = "mmusculus", host = "useast.ensembl.org",
archive = FALSE, overwrite = FALSE,
gene_requests = annotation_columns))
## The biomart annotations file already exists, loading from it.
fields <- c("ACCNUM", "ENSEMBL", "ENSEMBLTRANS", "ENTEZID", "GENENAME", "SYMBOL")
orgdb_annot <- load_orgdb_annotations("org.Mm.eg.db", fields = fields)
## Loading required package: AnnotationDbi
## Loading required package: stats4
## Loading required package: BiocGenerics
## Loading required package: generics
##
## Attaching package: 'generics'
## The following object is masked from 'package:dplyr':
##
## explain
## The following objects are masked from 'package:base':
##
## as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
## setequal, union
##
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:hpgltools':
##
## IQR, conditions, conditions<-, mad, sd, var
## The following object is masked from 'package:dplyr':
##
## combine
## The following objects are masked from 'package:stats':
##
## IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
##
## Filter, Find, Map, Position, Reduce, anyDuplicated, aperm, append,
## as.data.frame, basename, cbind, colnames, dirname, do.call,
## duplicated, eval, evalq, get, grep, grepl, is.unsorted, lapply,
## mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
## rank, rbind, rownames, sapply, saveRDS, table, tapply, unique,
## unsplit, which.max, which.min
## Loading required package: Biobase
## Welcome to Bioconductor
##
## Vignettes contain introductory material; view with
## 'browseVignettes()'. To cite Bioconductor, see
## 'citation("Biobase")', and for packages 'citation("pkgname")'.
##
## Attaching package: 'Biobase'
## The following objects are masked from 'package:hpgltools':
##
## exprs<-, notes, pData<-, sampleNames<-
## Loading required package: IRanges
## Loading required package: S4Vectors
##
## Attaching package: 'S4Vectors'
## The following objects are masked from 'package:dplyr':
##
## first, rename
## The following object is masked from 'package:utils':
##
## findMatches
## The following objects are masked from 'package:base':
##
## I, expand.grid, unname
##
## Attaching package: 'IRanges'
## The following objects are masked from 'package:dplyr':
##
## collapse, desc, slice
##
## Attaching package: 'AnnotationDbi'
## The following object is masked from 'package:dplyr':
##
## select
##
## Unable to find CDSNAME, setting it to GENENAME.
## Unable to find GENE_TYPE, setting it to GENETYPE.
## Unable to find CDSCHROM in the db, removing it.
## Unable to find CDSSTRAND in the db, removing it.
## Unable to find CDSSTART in the db, removing it.
## Unable to find CDSEND in the db, removing it.
## Some requested columns are not available: ENTEZID.
## The following are available: ACCNUM, ALIAS, ENSEMBL, ENSEMBLPROT, ENSEMBLTRANS, ENTREZID, ENZYME, EVIDENCE, EVIDENCEALL, GENENAME, GENETYPE, GO, GOALL, IPI, MGI, ONTOLOGY, ONTOLOGYALL, PATH, PFAM, PMID, PROSITE, REFSEQ, SYMBOL, UNIPROT
## Extracted all gene ids.
## Attempting to select: GENENAME, GENETYPE, ACCNUM, ENSEMBL, ENSEMBLTRANS, GENENAME, SYMBOL
## 'select()' returned 1:many mapping between keys and columns
gene_info <- orgdb_annot[["genes"]]
## Note, there are a bunch of variants of the txdb package one might use.
## I do not think it matters a lot for our purposes, but I suspect that if we used
## a mismatched BSgenome and tried to pull CDS sequences, that might end badly.
pkg <- "TxDb.Mmusculus.UCSC.mm10.knownGene"
tx_annot <- load_txdb_annotations(pkg)
## Loading required package: GenomicFeatures
## Loading required package: Seqinfo
## Loading required package: GenomicRanges
## 'select()' returned 1:many mapping between keys and columns
## 'select()' returned 1:many mapping between keys and columns
## 'select()' returned 1:many mapping between keys and columns
transcripts <- tx_annot[["TX"]]
transcripts[["tx"]] <- gsub(x = transcripts[["TXNAME"]],
pattern = "\\.\\d+$", replacement = "")
mm_annot_orgdb <- merge(gene_info, transcripts, by.x = "ensembltrans", by.y = "tx")
rownames(mm_annot_orgdb) <- make.names(mm_annot_orgdb[["ensembl"]], unique = TRUE)
mm_annot_combined <- merge(mm_annot[["annotation"]], mm_annot_orgdb,
by.x = "ensembl_transcript_id", by.y = "ensembltrans", all.x = TRUE)
mm_annot_genes <- mm_annot_combined
rownames(mm_annot_genes) <- make.names(mm_annot_genes[["ensembl_gene_id"]], unique = TRUE)
mm_tx_annot <- mm_annot_combined
rownames(mm_tx_annot) <- make.names(mm_tx_annot[["ensembl_transcript_id"]], unique = TRUE)
tx_gene_map <- mm_annot_genes[, c("TXID", "ensembl_gene_id")]
DE
I now switched to Theresa’s document ‘WORKING_axonTRAP…’ and will
start pulling sections from it. I am reasonably certain I have
reasonably similar sample distributions, so I presume I can invoke
similar/identical calls for DESeq and friends.
p8 retinas
In the block immediately before the DE analyses, Theresa created a
subset expressionset of only p08 retinas. Thus this initial DE I assume
will be used to subtract for the SCN/DLGN analyses that follow. (I guess
I could read ahead and find out, but no! I want to be a blank slate)
Theresa’s primary workflow makes heavy use of DESeq2 (@loveModeratedEstimationFold2014) and sva (@leekSVAPackageRemoving2012). In some(most?) of
Theresa’s invocations of the all_pairwise() function, she excludes the
other methods that it performs. In this workbook, I left those methods
on, thus we can evaluate the relative performance DESeq2 vs. some (all?
I may have disabled EBSeq/dream because they were taking too long) of
the following:
- limma: (@ritchieLimmaPowersDifferential2015) (among
other references) originally written for microarrays.
- EdgeR: (@robinsonEdgeRBioconductorPackage2010), which
shares many assumptions with DESeq2.
- EBSeq: (@lengEBSeqEmpiricalBayes2013),
because I have a soft spot for any Bayesian method.
- Noiseq: (@tarazonaNOIseqRNAseqDifferential2011), which
seeks to directly model variance in an RNASeq dataset and use that to
improve the sensitivity of the result, much like:
- Dream: (@hoffmanDreamPowerfulDifferential2020), written
by the same authors (and uses very similar logic) as one of my favorite
tools, variancePartition(@hoffmanVariancePartitionInterpretingDrivers2016).
mm38_p8_retina <- subset_se(mm38_hisat_tx, subset = "time_atb=='p08' & location_atb=='retina'")
mm_normal_p8_ret_de <- all_pairwise(mm38_p8_retina, model_svs = "svaseq",
model_fstring = "~ 0 + condition", filter = TRUE)
## het_retina ko_retina wt_retina
## 3 3 5
## Removing 56421 low-count genes (9462 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 5313 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## het_retina ko_retina wt_retina
## 3 3 5
## conditions
## het_retina ko_retina wt_retina
## 3 3 5
## conditions
## het_retina ko_retina wt_retina
## 3 3 5

## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 3 comparisons.
There seems to be a discrepency with previous iterations of this. Let
us simplify to just doing deseq and find what is causing it. In my
previous iteration, I got 3632 genes in the unique(c()) or het+ko.
deseq_only <- deseq_pairwise(mm38_p8_retina, model_svs = "svaseq",
model_fstring = default_fstring, filter = TRUE)
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
deseq_hetkeeper_tx <- deseq_only$all_tables$wt_retina_vs_het_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_kokeeper_tx <- deseq_only$all_tables$wt_retina_vs_ko_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_keepertx <- unique(c(rownames(deseq_hetkeeper_tx),
rownames(deseq_kokeeper_tx)))
length(deseq_keepertx)
## [1] 1806
deseq_pair_hetkeeper_tx <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_het_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_pair_kokeeper_tx <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_ko_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
deseq_pair_keepertx <- unique(c(rownames(deseq_pair_hetkeeper_tx),
rownames(deseq_pair_kokeeper_tx)))
length(deseq_pair_keepertx)
## [1] 1806
The following invocation performed by Theresa filters the wt/het
comparison for only those genes which increased by at least 0.25 logFC
with a significant adjusted p-value. I assume that this is to use the wt
samples as a translational control for the ket/ko comparisons; I am
therefore thinking that for my purposes, I will therefore separate the
contrasts from all_pairwise do this in a stepwise fashion…
The block of code immediately following Theresa’s all_pairwise()
invocation is a little confusing for me and warrants some explanation by
me to me in the hopes that I do not misunderstand what is happening and
the goals therein.
I think I can safely assume that the goal here is to pull out the IDs
which increased in het with respect to wild type; even if by a small
margin, as long as it is statistically significant vis a vis the
adjusted p-value.
I am going to perform what I think is the same thing in a slightly
different fashion so that I can share a copy of the results with
whomever is interested. I will also repeat Theresa’s invocation and
prove to myself that I understood and got the same answer.
wt_het_keeper <- list("het_vs_wt" = c("het_retina", "wt_retina"))
het_wt_table <- combine_de_tables(
mm_normal_p8_ret_de, keepers = wt_het_keeper, label_column = tx_label_column,
excel = "03theresa_comparison_excel_tx/het_retina_control.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
wanted_sig <- extract_significant_genes(
het_wt_table, lfc = 0.25, according_to = "deseq",
excel = "03theresa_comparison_excel_tx/het_retina_control-sig.xlsx")
wanted_het_increased <- wanted_sig[["deseq"]][["ups"]][["het_vs_wt"]]
increased_het_genes <- rownames(wanted_het_increased)
Here are Theresa’s next lines:
mm_de_normal_p8_ret <- mm_normal_p8_ret_de
hetkeeper_tx <- mm_de_normal_p8_ret$deseq$all_tables$wt_retina_vs_het_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
kokeeper_tx <- mm_de_normal_p8_ret$deseq$all_tables$wt_retina_vs_ko_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
keepertx <- unique(c(rownames(hetkeeper_tx),
rownames(kokeeper_tx)))
## We know a priori that Opn4 is ENSMUSG00000021799
## I do not expect to see it in this set, it should be higher in wt
## retina vs ko retina by a significant margin.
## "ENSMUSG00000021799" %in% keepertx
## Oooohhh but it _is_ higher in het vs. wt, as we saw in
## the violin plot earlier.
I think Rashmi made a compelling point which illustrates why we
likely should expect the expression of Opn4 to significantly higher in
the heterozygotes vs wild-type:
- Recall that the assay is using the immunopurification to extract the
RNAs.
- The wt samples do not have the cre recombinase and therefore no HA
and therefore everything we observe is due to non-specific binding.
- The set of genes observed due to non-specific binding is different
than het/ko (presumably a larger number of relatively small values),
therefore the divisor performed in the cpm is likely relativly large
resulting in normalized values getting shifted down to some degree.
- On the other hand, the set of genes observed in het/ko are more
likely to be only the specific binders and therefore smaller (I can test
this) resulting in a smaller divisor and slight shifting up in the cpm
values.
This makes me wonder if any normalization methods exist which do
something like multiply the values by some value related to the
proportion of observed genes; and/or if this is a good/bad/indifferent
idea.
Also, just a note for me to remember: RPL22, not RPS22, for some
reason I keep thinking the small subunit.
Prove I
understood
hetkeeper_tx <- mm_normal_p8_ret_de$deseq$all_tables$wt_retina_vs_het_retina |>
filter(logFC <= -0.25 & adj.P.Val <= 0.05)
testthat::expect_true(nrow(hetkeeper_tx) == length(increased_het_genes))
taa_keepers <- sort(rownames(hetkeeper_tx))
atb_keepers <- sort(increased_het_genes)
testthat::expect_equal(taa_keepers, atb_keepers)
Yay! I can read! Now let us repeat for the KO vs wt
wt_ko_keeper <- list("ko_vs_wt" = c("ko_retina", "wt_retina"))
ko_wt_table <- combine_de_tables(
mm_normal_p8_ret_de, keepers = wt_ko_keeper, label_column = tx_label_column,
excel = "03theresa_comparison_excel_tx/ko_retina_control.xlsx")
## Looking for subscript invalid names, end of extract_keepers.
wanted_sig <- extract_significant_genes(
ko_wt_table, lfc = 0.25, according_to = "deseq",
excel = "03theresa_comparison_excel_tx/ko_retina_control-sig.xlsx")
wanted_ko_increased <- wanted_sig[["deseq"]][["ups"]][["ko_vs_wt"]]
increased_ko_genes <- rownames(wanted_ko_increased)
The next thing performed in Theresa’s document is a
unique(concatenation of these two gene groups), thus sucking up every
gene which was significantly higher in either the knockout or
heterzyous samples with respect to wild-type.
This was followed by a couple of merge operations of a little bit of
the annotation data; I am not sure I understand the goal yet…
Here is her code. I copied the annotation ‘mgi_symbol’ column to
‘external_gene_name’ so that I need not change any of her code. I am
assuming this is the appropriate column of interest, I do not know this
for certain, but it seems quite likely.
While I am at it, here is the set_sig_limma() function from Theresa’s
helpers.R
set_sig_limma <- function(limma_tbl, factors = NULL) {
if (is.null(factors)) {
#set significance for plotting colors
limma_tbl$Significance <- NA
limma_tbl[abs(limma_tbl$logFC) <= 1.0 | limma_tbl$adj.P.Val >= 0.05, "Significance"] <- "Not \nEnriched"
limma_tbl[limma_tbl$logFC >= 1.0 & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- "Disease \nUpregulated"
limma_tbl[limma_tbl$logFC <= -1.0 & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- "Disease \nDownregulated"
limma_tbl$Significance <- factor(limma_tbl$Significance, levels = c("Upregulated", "Downregulated", "Not \nEnriched"))
} else {
limma_tbl$Significance <- NA
limma_tbl[abs(limma_tbl$logFC) <= 1.0 | limma_tbl$adj.P.Val >= 0.05, "Significance"] <- "Not \nEnriched"
if(nrow(limma_tbl[limma_tbl$logFC >= 1.0 & limma_tbl$adj.P.Val <= 0.05, ]) != 0) {
limma_tbl[limma_tbl$logFC >= 1.0 & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- factors[1]
}
if (nrow(limma_tbl[limma_tbl$logFC <= -1.0 & limma_tbl$adj.P.Val <= 0.05, ]) != 0) {
limma_tbl[limma_tbl$logFC <= -1.0 & limma_tbl$adj.P.Val <= 0.05, ][["Significance"]] <- factors[2]
}
limma_tbl$Significance <- factor(limma_tbl$Significance, levels = c(factors, "Not \nEnriched"))
}
return(limma_tbl)
}
Combining het/wt
and ko/wt
keepertx <- unique(c(rownames(hetkeeper_tx), rownames(kokeeper_tx)))
length(keepertx)
## [1] 1806
df <- mm_de_normal_p8_ret$deseq$all_tables$ko_retina_vs_het_retina |>
dplyr::mutate(logFC = -logFC) |>
set_sig_limma(factors = c("Het Enriched", "KO Enriched"))
My version of the above task makes use of the excludes option of
combine_de_tabes. Given the set of unique gene IDs increased in the
het/ko, I can ask to exlude anything not in that set. I could also have
more parsimoniously directly excluded any gene ID increased in the wt
samples. But, Theresa already provided the code to do the former, so it
will be less typing/opportunity for silly mistakes to just do that.
both_increased_genes <- unique(c(increased_het_genes, increased_ko_genes))
## arbitrairly grab all genes from one of my data structures.
all_genes <- rownames(assay(mm38_hisat_tx))
exclude_idx <- all_genes %in% both_increased_genes
summary(exclude_idx)
## Mode FALSE TRUE
## logical 64077 1806
exclude_increased_genes <- all_genes[exclude_idx]
retina_keepers <- list(
"het_vs_wt" = c("het_retina", "wt_retina"),
"ko_vs_wt" = c("ko_retina", "wt_retina"),
"ko_vs_het" = c("ko_retina", "het_retina"))
## A reminder to myself: there is also a parameter 'wanted_genes'
## which does effectively the same thing as excludes in this context;
## excludes was originally written to allow flexible, keyword-based
## exclusion.
p8_retina_tables <- combine_de_tables(
mm_normal_p8_ret_de, keepers = retina_keepers,
wanted_genes = both_increased_genes, label_column = tx_label_column,
excel = glue("03theresa_comparison_excel_tx/p8_retina_kept_tx_increased_in_wt_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
p8_retina_sig <- extract_significant_genes(
p8_retina_tables, according_to = "deseq",
excel = glue("03theresa_comparison_excel_tx/p8_retina_kept_genes_increased_in_wt_sig-v{ver}.xlsx"))
opposite_p8_retina_tables <- combine_de_tables(
mm_normal_p8_ret_de, keepers = retina_keepers,
excludes = both_increased_genes, label_column = tx_label_column,
excel = glue("03theresa_comparison_excel_tx/p8_retina_removed_genes_increased_in_wt_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
opposite_p8_retina_sig <- extract_significant_genes(
p8_retina_tables, according_to = "deseq",
excel = glue("03theresa_comparison_excel_tx/p8_retina_removed_genes_increased_in_wt_sig-v{ver}.xlsx"))
TODO: Change the above
to subtract wt
Rashmi suggested we should do the above plot after subtracting the wt
counts. This is a good idea, but it will have to wait until we finish
the current set.
Set up the
contrasts
In the following few blocks I will set up the various comparisons of
interest. Starting with the set of genes to exclude because they were
observed to bind non-specifically in the wt samples.
Inclusion
contrasts
In each exclusion I will have the contrast first followed by the pair
of contrasts which will be used to define the gene set to exclude.
- p15_het_dlgn/p08_het_dlgn: p15_wt_dlgn/p15_het_dlgn,
p08_wt_dlgn/p08_het_dlgn; remove the genes increased in wt.
- p15_ko_scn/p08_ko_scn: p15_wt_scn/p15_ko_scn,
p08_wt_scn/p15_ko_scn
- p15_het_retina/p08_het_retina: I think you get it, wt/het for both
p15 retinas and p08 retinas…
Put slightly differently, for every term of interest I will create a
contrast with the wt as numerator and the desired term as denominator,
then pull out the genes increased in wt.
inclusions <- list(
## I like alphabetizing things, start with dlgn
"p15_het_dlgn" = c("p15_het_dlgn", "p15_wt_dlgn"),
"p08_het_dlgn" = c("p08_het_dlgn", "p08_wt_dlgn"),
"p15_ko_dlgn" = c("p15_ko_dlgn", "p15_wt_dlgn"),
"p08_ko_dlgn" = c("p08_ko_dlgn", "p08_wt_dlgn"),
## Then retinas
"p15_het_retina" = c("p15_het_retina", "p15_wt_retina"),
"p08_het_retina" = c("p08_het_retina", "p08_wt_retina"),
"p15_ko_retina" = c("p15_ko_retina", "p15_wt_retina"),
"p08_ko_retina" = c("p08_ko_retina", "p08_wt_retina"),
## Then scn
"p15_het_scn" = c("p15_het_scn", "p15_wt_scn"),
"p08_het_scn" = c("p08_het_scn", "p08_wt_scn"),
"p15_ko_scn" = c("p15_ko_scn", "p15_wt_scn"),
"p08_ko_scn" = c("p08_ko_scn", "p08_wt_scn"))
Time
contrasts
For each location/genotype of interest, let us compare p15/p08
time_keepers <- list(
## DLGN
"t_het_dlgn" = c("p15_het_dlgn", "p08_het_dlgn"),
"t_ko_dlgn" = c("p15_ko_dlgn", "p08_ko_dlgn"),
## Retina
"t_het_retina" = c("p15_het_retina", "p08_het_retina"),
"t_ko_retina" = c("p15_ko_retina", "p08_ko_retina"),
## SCN
"t_het_scn" = c("p15_het_scn", "p08_het_scn"),
"t_ko_scn" = c("p15_ko_scn", "p08_ko_scn"))
Location
contrasts
Compare locations and keep time/genotype consistent. I will use the
location initials to define numerator/denominator.
location_keepers <- list(
## dlgn/retina
"dr_p08_het" = c("p08_het_dlgn", "p08_het_retina"),
"dr_p15_het" = c("p15_het_dlgn", "p15_het_retina"),
"dr_p08_ko" = c("p08_ko_dlgn", "p08_ko_retina"),
"dr_p15_ko" = c("p15_ko_dlgn", "p15_ko_retina"),
## scn/retina
"sr_p08_het" = c("p08_het_scn", "p08_het_retina"),
"sr_p15_het" = c("p15_het_scn", "p15_het_retina"),
"sr_p08_ko" = c("p08_ko_scn", "p08_ko_retina"),
"sr_p15_ko" = c("p15_ko_scn", "p15_ko_retina"),
## dlgn/scn
"ds_p08_het" = c("p08_het_dlgn", "p08_het_scn"),
"ds_p15_het" = c("p15_het_dlgn", "p15_het_scn"),
"ds_p08_ko" = c("p08_ko_dlgn", "p08_ko_scn"),
"ds_p15_ko" = c("p15_ko_dlgn", "p15_ko_scn"))
Genotype
contrasts
Compare ko/het while keeping time/location constant. Similarly, use
the initials to denote numerator/denominator, which will always be
kh.
genotype_keepers <- list(
## DLGN
"kh_p08_dlgn" = c("p08_ko_dlgn", "p08_het_dlgn"),
"kh_p15_dlgn" = c("p15_ko_dlgn", "p15_het_dlgn"),
## Retina
"kh_p08_retina" = c("p08_ko_retina", "p08_het_retina"),
"kh_p15_retina" = c("p15_ko_retina", "p15_het_retina"),
## SCN
"kh_p08_scn" = c("p08_ko_scn", "p08_het_scn"),
"kh_p15_scn" = c("p15_ko_scn", "p15_het_scn"))
Perform the
exclusion comparison
My all_pairwise() function now has a parameter which allows me to
choose which contrasts to perform instead of literally doing every
possible comparison. That is well suited for these operations:
In a container, the following appears to fail with:
“error code 1 from Lapack routine ‘dgesdd’”
Running it manually outside the container results in it working
without error. I assume therefore that the problem lies in the
compilation flags of LAPACK in the container.
Note: This problem was fixed by removing some parallelization.
inclusion_de <- all_pairwise(
tx_pairwise_input, filter = "simple", model_fstring = default_fstring,
keepers = inclusions, model_svs = "svaseq")
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 50190 low-count genes (15693 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 393901 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 12 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2

## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 12 comparisons.
inclusion_tables <- combine_de_tables(
inclusion_de, keepers = inclusions, label_column = tx_label_column,
excel = glue("04inclusion_comparisons_tx/inclusion_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_wt_dlgn 316 428 384
## 2 p08_het_dlgn_vs_p08_wt_dlgn 40 116 73
## 3 p15_ko_dlgn_vs_p15_wt_dlgn 566 652 624
## 4 p08_ko_dlgn_vs_p08_wt_dlgn 179 271 171
## 5 p15_het_retina_vs_p15_wt_retina 89 28 143
## 6 p08_het_retina_vs_p08_wt_retina 275 113 325
## 7 p15_ko_retina_vs_p15_wt_retina 31 8 100
## 8 p08_ko_retina_vs_p08_wt_retina 288 88 337
## 9 p15_het_scn_vs_p15_wt_scn 3 4 47
## 10 p08_het_scn_vs_p08_wt_scn 2 1 42
## 11 p15_ko_scn_vs_p15_wt_scn 1 3 38
## 12 p08_ko_scn_vs_p08_wt_scn 1 2 63
## edger_sigdown limma_sigup limma_sigdown
## 1 496 436 586
## 2 145 149 134
## 3 785 540 668
## 4 338 244 495
## 5 56 56 23
## 6 197 182 57
## 7 44 21 10
## 8 157 183 50
## 9 25 43 172
## 10 34 37 23
## 11 37 246 208
## 12 29 75 70
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## i Please use tidy evaluation idioms with `aes()`.
## i See also `vignette("ggplot2-in-packages")` for more information.
## i The deprecated feature was likely used in the UpSetR package.
## Please report the issue at <https://github.com/hms-dbmi/UpSetR/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## i Please use the `linewidth` argument instead.
## i The deprecated feature was likely used in the UpSetR package.
## Please report the issue at <https://github.com/hms-dbmi/UpSetR/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Plot describing unique/shared genes in a differential expression table.

## 202603: I successfully recapitulated previous non-container result.
inclusion_sig <- extract_significant_genes(
inclusion_tables, lfc = filter_lfc_cutoff, p = filter_adjp_cutoff, according_to = "deseq",
excel = glue("04inclusion_comparisons_tx/inclusion_sig-v{ver}.xlsx"))
inclusion_sig
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 0.1 adj P cutoff: 0.1
## deseq_up deseq_down
## p15_het_dlgn 1004 1041
## p08_het_dlgn 178 318
## p15_ko_dlgn 1341 1267
## p08_ko_dlgn 517 488
## p15_het_retina 213 100
## p08_het_retina 537 343
## p15_ko_retina 66 16
## p08_ko_retina 573 265
## p15_het_scn 6 6
## p08_het_scn 11 8
## p15_ko_scn 2 3
## p08_ko_scn 7 5

202505: A strange thing happened here in this iteration: the plot of
the significant genes is the exact same as the previous iteration; but
the table of numbers of genes looks different.
For example, the previous table showed: p15_het_dlgn with 2067 up and
2381 down. The plot shows exactly that; but the new table shows 607 up
and 1229 down. Let us check the actual data structure and see what is
up?
I think I get it: when we do the extract_significant_genes above, we
explicitly set a non-standard p-value and logFC because we are
explicitly attempting to use a very loose definition of the set of genes
which are in greater abundance than their most similar wild-type.
However, when I create the barplot of significant genes; those values
are explicitly set to 0,1,2 logFCs and p-value 0.05. Therefore, what I
need to do, in order to check consistency, is to repeat this call but
with the default FC/p values and see what the numbers look like.
test_inclusion <- extract_significant_genes(
inclusion_tables, according_to = "deseq", excel = "04inclusion_comparisons_tx/default_inclusion_sig.xlsx")
test_inclusion
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## p15_het_dlgn 316 428
## p08_het_dlgn 40 116
## p15_ko_dlgn 566 652
## p08_ko_dlgn 179 271
## p15_het_retina 89 28
## p08_het_retina 275 113
## p15_ko_retina 31 8
## p08_ko_retina 288 88
## p15_het_scn 3 4
## p08_het_scn 2 1
## p15_ko_scn 1 3
## p08_ko_scn 1 2

Yeah, I think this makes sense; what I need to do: change the
significant bar plot so that it uses the lfc cutoff argument as the
second of its 3 cutoffs. That should ensure that these numbers are
consistent across analyses and parameters provided.
dim(inclusion_sig$deseq$ups$p15_het_dlgn)
## [1] 1004 83
test_all_up <- inclusion_tables$data$p15_het_dlgn[["deseq_logfc"]] >= 0.1 &
inclusion_tables$data$p15_het_dlgn[["deseq_adjp"]] <= 0.1
summary(test_all_up)
## Mode FALSE TRUE
## logical 14689 1004
Ohh, I get it, when I was testing this out manually, I set the logFC
to 1.0 instead of the very minimal 0.1 we have been using for this!
The strict ‘inclusion’
set
Time
time_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
time_keepers, all_genes)
## The set of unique genes higher in p15_het_dlgn vs. wt is 1004.
## The set of unique genes higher in p08_het_dlgn vs. wt is 178.
## The intersection of them is 137 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 1341.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 517.
## The intersection of them is 262 genes.
## The set of unique genes higher in p15_het_retina vs. wt is 213.
## The set of unique genes higher in p08_het_retina vs. wt is 537.
## The intersection of them is 145 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 66.
## The set of unique genes higher in p08_ko_retina vs. wt is 573.
## The intersection of them is 47 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 6.
## The set of unique genes higher in p08_het_scn vs. wt is 11.
## The intersection of them is 0 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 2.
## The set of unique genes higher in p08_ko_scn vs. wt is 7.
## The intersection of them is 1 genes.
Location
location_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
location_keepers, all_genes)
## The set of unique genes higher in p08_het_dlgn vs. wt is 178.
## The set of unique genes higher in p08_het_retina vs. wt is 537.
## The intersection of them is 22 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 1004.
## The set of unique genes higher in p15_het_retina vs. wt is 213.
## The intersection of them is 72 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 517.
## The set of unique genes higher in p08_ko_retina vs. wt is 573.
## The intersection of them is 75 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 1341.
## The set of unique genes higher in p15_ko_retina vs. wt is 66.
## The intersection of them is 16 genes.
## The set of unique genes higher in p08_het_scn vs. wt is 11.
## The set of unique genes higher in p08_het_retina vs. wt is 537.
## The intersection of them is 0 genes.
## The set of unique genes higher in p15_het_scn vs. wt is 6.
## The set of unique genes higher in p15_het_retina vs. wt is 213.
## The intersection of them is 0 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 7.
## The set of unique genes higher in p08_ko_retina vs. wt is 573.
## The intersection of them is 3 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 2.
## The set of unique genes higher in p15_ko_retina vs. wt is 66.
## The intersection of them is 1 genes.
## The set of unique genes higher in p08_het_dlgn vs. wt is 178.
## The set of unique genes higher in p08_het_scn vs. wt is 11.
## The intersection of them is 0 genes.
## The set of unique genes higher in p15_het_dlgn vs. wt is 1004.
## The set of unique genes higher in p15_het_scn vs. wt is 6.
## The intersection of them is 0 genes.
## The set of unique genes higher in p08_ko_dlgn vs. wt is 517.
## The set of unique genes higher in p08_ko_scn vs. wt is 7.
## The intersection of them is 4 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 1341.
## The set of unique genes higher in p15_ko_scn vs. wt is 2.
## The intersection of them is 1 genes.
Genotype
genotype_inclusions_strict <- extract_inclusions_strict(inclusion_sig, inclusion_tables, inclusions,
genotype_keepers, all_genes)
## The set of unique genes higher in p08_ko_dlgn vs. wt is 517.
## The set of unique genes higher in p08_het_dlgn vs. wt is 178.
## The intersection of them is 106 genes.
## The set of unique genes higher in p15_ko_dlgn vs. wt is 1341.
## The set of unique genes higher in p15_het_dlgn vs. wt is 1004.
## The intersection of them is 888 genes.
## The set of unique genes higher in p08_ko_retina vs. wt is 573.
## The set of unique genes higher in p08_het_retina vs. wt is 537.
## The intersection of them is 354 genes.
## The set of unique genes higher in p15_ko_retina vs. wt is 66.
## The set of unique genes higher in p15_het_retina vs. wt is 213.
## The intersection of them is 49 genes.
## The set of unique genes higher in p08_ko_scn vs. wt is 7.
## The set of unique genes higher in p08_het_scn vs. wt is 11.
## The intersection of them is 1 genes.
## The set of unique genes higher in p15_ko_scn vs. wt is 2.
## The set of unique genes higher in p15_het_scn vs. wt is 6.
## The intersection of them is 1 genes.
Check vs Theresa’s
filter
Up above Theresa performed a 0.25 log2FC and 0.05 adjp filter which
provided a set of 2,640 genes observed higher in the p08 het retinas
vs. wt retinas. I should see that in this inclusion_sig data
structure.
There is an important caveat though: in Theresa’s filter above, she
did a DE of only the retina samples but I did all samples. I
expected that this would result in basically the same result (I actually
assumed I would get a few more genes), but instead it appears to have
retrieved a significantly smaller number of genes (about 1/2, happily
they pretty much all appear in the previous filter). As a result, I am
going to try relaxing my constraints slightly to see if I can
recapitulate her filter (which would match Theresa’s later filter,
though I guess that in turn will lead to a smaller set of genes compared
to her later, relaxed 0.1 filter).
comparison <- inclusion_sig[["deseq"]][["ups"]][["p08_het_retina"]]
comp <- list(
"taa" = taa_keepers,
"new" = rownames(comparison))
test_comparison <- Vennerable::Venn(comp)
Vennerable::plot(test_comparison)

I want to have a little function which, given a contrast of interest,
will extract the gene sets which should be included/excluded given the
above.
write_all_cp <- function(all_cp, prefix = "12", suffix = "") {
all_written <- list()
for (g in seq_len(length(all_cp))) {
name <- names(all_cp)[g]
datum <- all_cp[[name]]
filename <- glue("{prefix}enrichment_excel_tx/{name}_cprofiler{suffix}-v{ver}.xlsx")
written <- sm(write_cp_data(datum, excel = filename))
all_written[[g]] <- written
}
return(all_written)
}
write_all_gp <- function(all_gp, prefix = "13", suffix = "") {
all_written <- list()
for (g in seq_len(length(all_gp))) {
name <- names(all_gp)[g]
datum <- all_gp[[name]]
filename <- glue("{prefix}enrichment_excel_tx/{name}_gprofiler{suffix}-v{ver}.xlsx")
written <- sm(write_gprofiler_data(datum, excel = filename))
all_written[[g]] <- written
}
return(all_written)
}
write_all_en <- function(all_en, prefix = "14", suffix = "") {
all_written <- list()
for (e in seq_len(length(all_en))) {
name <- names(all_en)[e]
datum <- all_en[[name]]
filename <- glue("{prefix}enrichment_excel_tx/{name}_enricher{suffix}-v{ver}.xlsx")
written <- sm(write_enricher_data(datum, excel = filename))
all_written[[e]] <- written
}
return(all_written)
}
Perform the DE
analyses and exclude the target genes
Genotype
genotype_de <- all_pairwise(tx_pairwise_input, filter = TRUE, model_fstring = default_fstring,
keepers = genotype_keepers, model_svs = "svaseq")
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 250859 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2

## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 6 comparisons.
Location
location_de <- all_pairwise(tx_pairwise_input, filter = TRUE, model_fstring = default_fstring,
keepers = location_keepers, model_svs = "svaseq")
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 250859 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2

## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 12 comparisons.
Time
time_de <- all_pairwise(tx_pairwise_input, filter = TRUE, model_fstring = default_fstring,
keepers = time_keepers, model_svs = "svaseq")
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## Basic step 0/3: Normalizing data.
## Basic step 0/3: Converting data.
## I think this is failing? SummarizedExperiment
## Basic step 0/3: Transforming data.
## Setting 250859 entries to zero.
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2

## A pairwise differential expression with results from: basic, deseq, ebseq, edger, limma, noiseq.
## This used a surrogate/batch estimate from: svaseq.
## The primary analysis performed 6 comparisons.
It is near here when the computer sometimes fails with no more
tempfiles. In another window I am messing with tempfile() in R to try to
understand where it is going off the rails…
Extract the relevant
tables and include genes lower in wt
Genotype
contrasts
I will start with the tables and no inclusions so I can check my
work.
In this first block I will explain a little more thoroughly what is
going on:
- Dump the full table of the contrasts I defined above comparing the 3
genotypes across time/location.
- Iterate over each of those contrasts and do the following:
- Extract the name of the contrast, ‘kh_p08_dlgn’ for example
- Yank out that specific entry from the keeper list and its name
- Yank out the corresponding set of genes to include from the
inclusions data structure.
- Create a filename given the name in (a) above and the logFC cutoff
chosen for the inclusions (I am assuming we may change this)
- Given (b), (c), and (d), extract the corresponding table from the
differential expression analysis and include the appropriate genes.
FIXME: my gprofiler function just assumes human and so if passed
mmusculus will incorrectly attempt to connect to non-existant databases.
Let us fix that now.
genotype_tables_full <- combine_de_tables(
genotype_de, keepers = genotype_keepers, label_column = tx_label_column,
fancy = TRUE,
excel = glue("08full_contrasts_excel_tx/genotype_full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_het_dlgn 27 11 57
## 2 p15_ko_dlgn_vs_p15_het_dlgn 35 1 69
## 3 p08_ko_retina_vs_p08_het_retina 9 2 30
## 4 p15_ko_retina_vs_p15_het_retina 3 5 30
## 5 p08_ko_scn_vs_p08_het_scn 5 19 43
## 6 p15_ko_scn_vs_p15_het_scn 3 17 29
## edger_sigdown limma_sigup limma_sigdown
## 1 45 35 46
## 2 16 35 11
## 3 30 3 2
## 4 41 1 4
## 5 88 32 20
## 6 57 9 6
## Plot describing unique/shared genes in a differential expression table.

genotype_sig_full <- extract_significant_genes(
genotype_tables_full, according_to = "deseq",
excel = glue("08full_contrasts_excel_tx/genotype_full_sig-v{ver}.xlsx"))
genotype_sig_full
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p08_dlgn 27 11
## kh_p15_dlgn 35 1
## kh_p08_retina 9 2
## kh_p15_retina 3 5
## kh_p08_scn 5 19
## kh_p15_scn 3 17

Search Enrichment
of these sets
In this run, we will search the full set of genes, next we will only
do the inclusions.
genotype_full_gp <- all_gprofiler(genotype_sig_full, species = "mmusculus",
excel = "09full_contrasts_enrich_tx/genotype_full_gprofiler.xlsx")
genotype_full_cp <- all_cprofiler(genotype_sig_full, genotype_tables_full,
orgdb = "org.Mm.eg.db", go_level = go_level, organism = "mouse",
orgdb_from = orgdb_from, max_groupsize = max_groupsize,
excel = "09full_contrasts_enrich_tx/genotype_full_cprofiler.xlsx")
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto), :
## Viewport has zero dimension(s)
## Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto), :
## Viewport has zero dimension(s)
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto), :
## Viewport has zero dimension(s)
## Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto), :
## Viewport has zero dimension(s)
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
genotype_full_upset <- upsetr_sig(genotype_sig_full)
genotype_full_intersects <- write_upset_groups(genotype_full_upset,
excel = "09full_contrasts_intersections_tx/genotype_full_gene_groups.xlsx")
Now separate the various genotype tables and perform the inclusions
of the genes with relatively low wt values.
Extract filtered
genes and pass to gprofiler2/clusterprofiler
genotype_tables <- list()
genotype_sig <- list()
genotype_gp <- list()
genotype_cp <- list()
genotype_en <- list()
for (k in seq_along(genotype_keepers)) {
name <- names(genotype_keepers)[k]
message("Examining ", name)
keeper <- genotype_keepers[name]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- genotype_inclusions[[include_df_name]]
includes <- genotype_inclusions[[include_name]]
summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
include_filename <- glue("10genotype_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("10genotype_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
genotype_tables[[name]] <- combine_de_tables(
genotype_de, extra_annot = include_df,
keepers = keeper, label_column = tx_label_column,
excel = include_filename, wanted_genes = includes)
print(genotype_tables[[name]])
genotype_sig[[name]] <- extract_significant_genes(
genotype_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(genotype_sig[[name]])
num_rows <- nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows >= 10) {
message("Performing gprofiler/clusterProfiler.")
genotype_gp[[name]] <- all_gprofiler(genotype_sig[[name]], species = "mmusculus")
genotype_cp[[name]] <- all_cprofiler(
genotype_sig[[name]], genotype_tables[[name]],
orgdb = "org.Mm.eg.db", orgdb_from = orgdb_from,
go_level = go_level, max_groupsize = max_groupsize, organism = "mouse")
#if (!is.null(get0("m2_gsc"))) {
# genotype_en[[name]] <- all_enricher(genotype_sig[[name]], gsc = m2_gsc,
# orgdb = "org.Mm.eg.db", from = "ENSEMBL", to = "SYMBOL")
#}
gp_written <- write_all_gp(genotype_gp[[name]], prefix = "11")
cp_written <- write_all_cp(genotype_cp[[name]], prefix = "11")
#en_written <- write_all_en(genotype_en[[name]])
} else {
warning("There are less than 10 genes up and down in the ", name, " comparison.")
message("There are less than 10 genes up and down in the ", name, " comparison.")
}
}
## Examining kh_p08_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_het_dlgn 22 1 21
## edger_sigdown limma_sigup limma_sigdown
## 1 0 8 0
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p08_dlgn 22 1

## There are 23 significant up and down genes.
## Performing gprofiler/clusterProfiler.
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in `.subset2()`:
## ! subscript out of bounds
Plot the results separately.
for (k in seq_along(genotype_keepers)) {
name <- names(genotype_keepers)[k]
message("Examining ", name)
keeper <- genotype_keepers[name]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- genotype_inclusions[[include_df_name]]
includes <- genotype_inclusions[[include_name]]
summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
num_rows <- nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
nrow(genotype_sig[[name]][["deseq"]][["ups"]][[name]])
nrow(genotype_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
## #1 is up and #2 is down, avoiding typeos here.
num_objects <- length(genotype_cp[[name]])
if (num_objects == 0) {
warning("Something went wrong in all_cprofiler.")
} else {
upp <- which(grepl(x = names(genotype_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(genotype_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- genotype_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- genotype_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- genotype_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig)
mf_tree_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("12clusterProfiler_plots_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- genotype_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- genotype_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- genotype_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, cateogories = go_categories)
bp_bar_down_filename <- glue("12clusterProfiler_plots_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining kh_p08_dlgn
## There are 23 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in pp(file = mf_tree_up_filename): The directory:
## 12clusterProfiler_plots_tx does not exist, will attempt to create it.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining kh_p15_dlgn
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_retina
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_retina
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_scn
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_scn
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
A few specific plots of interest: Colenso asked to label a few genes
for the knockout/het p08_retinas, p08_scn, and p08_dlgn: either the
top-15 or all significant. I am pretty sure if I tell it 15 and there
are not that many, it will just do the significant? Let us find out!
ko/het for p08
retinas
table_name <- "kh_p08_retina"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting <- c("Opn4", "Gm9008", "Lrr1", "Cnbd1")
kh_p08_retina_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
color_low = colors[["het_retina"]], color_high = colors[["ko_retina"]],
label_column = tx_label_column, label = interesting, alpha = 1.0,
outline = outline, size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p08_retina_volcano.pdf", width = 9, height = 9)
## Warning in pp(file = "13genotype_ma_volcano_tx/kh_p08_retina_volcano.pdf", :
## The directory: 13genotype_ma_volcano_tx does not exist, will attempt to create
## it.
kh_p08_retina_volcano[["plot"]]
## Error:
## ! object 'kh_p08_retina_volcano' not found
plotted <- dev.off()
kh_p08_retina_volcano[["plot"]]
## Error:
## ! object 'kh_p08_retina_volcano' not found
kh_p08_retina_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", outline = outline,
label = interesting)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p08_retina_ma.pdf", width = 9, height = 9)
kh_p08_retina_ma[["plot"]]
## Error:
## ! object 'kh_p08_retina_ma' not found
plotted <- dev.off()
kh_p08_retina_ma[["plot"]]
## Error:
## ! object 'kh_p08_retina_ma' not found
ko/het p08
SCN
I am going to make an executive decision for this plot, 15 is too
many and makes it crazy cluttered.
Repeat this with
two sets of genes
table_name <- "kh_p08_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Fign", "Nrn1", "Dpysl2", "Actb", "Fgf9", "Otx2", "Sec23",
"Ncam1", "Map4", "Sec22b", "Nlgn3", "Marcks", "Cd47",
"Dpysl3", "Lin7c", "Cadm1", "Snx12", "Rhoa", "Inpp5f",
"Atg12", "Set", "Gsk3b", "Pdcd4", "Gabra2", "Tmco1", "Anapc16")
kh_p08_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
label_column = "external_transcript_name", label = interesting_genes, size = 4, alpha = 1.0,
outline = outline, color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]])
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p08_scn_volcano.pdf", width = 9, height = 9)
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
plotted <- dev.off()
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
outline = outline, p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p08_scn_ma.pdf", width = 9, height = 9)
kh_p08_scn_ma[["plot"]]
## Error:
## ! object 'kh_p08_scn_ma' not found
plotted <- dev.off()
kh_p08_scn_ma[["plot"]]
## Error:
## ! object 'kh_p08_scn_ma' not found
Same plot but a
different set of labeled genes
table_name <- "kh_p08_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c(
"Anapc16", "Gabra2", "Tmco1", "Sod2", "Fgf9", "Pdcd4", "Rhoa", "Gsk3b", "Foxp1",
"Ncam1", "Marcks", "Fign", "Dpysl3", "Inpp5f", "Cadm1", "Map4", "Ugcg", "Elovl4",
"Elavl1", "Cfl2", "Tnnt1", "Gnb1", "Impact", "Nrn1", "Nlgn3", "Actb", "Cd47",
"Sec22b", "Slc17a7", "Vglut1", "Actb", "B4galt5", "Foxp1", "Otx2", "Lin7c",
"Snx12", "Atg12", "Set")
kh_p08_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
outline = outline, label_column = "external_transcript_name", label = interesting_genes, size = 4, alpha = 1.0)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p08_scn_volcano_v2.pdf", width = 9, height = 9)
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
plotted <- dev.off()
kh_p08_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p08_scn_volcano' not found
## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
outline = outline, p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p08_scn_ma_v2.pdf", width = 9, height = 9)
kh_p08_scn_ma[["plot"]]
## Error:
## ! object 'kh_p08_scn_ma' not found
plotted <- dev.off()
kh_p08_scn_ma[["plot"]]
## Error:
## ! object 'kh_p08_scn_ma' not found
ko/het p08
dLGN
table_name <- "kh_p08_dlgn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
kh_p08_dlgn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
outline = outline, label_column = "external_transcript_name", label = 10, size = 4, alpha = 1.0)
## Warning in ggrepel::geom_text_repel(data = df_subset, nudge_x = nudge_x, :
## Ignoring unknown parameters: `outline`
pp(file = "13genotype_ma_volcano_tx/kh_p08_dlgn_volcano.pdf", width = 9, height = 9)
kh_p08_dlgn_volcano[["plot"]]
plotted <- dev.off()
kh_p08_dlgn_volcano[["plot"]]

## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p08_dlgn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = 10, outline = outline)
pp(file = "13genotype_ma_volcano_tx/kh_p08_dlgn_ma.pdf", width = 9, height = 9)
kh_p08_dlgn_ma[["plot"]]
plotted <- dev.off()
kh_p08_dlgn_ma[["plot"]]

ko/het for p15
retinas
When last I ran this manually, it did not double-label, hopefully
that remains true in the container.
table_name <- "kh_p15_retina"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting <- c("Opn4", "Gm9008", "Lrr1", "Cnbd1")
kh_p15_retina_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp", fill = "black",
color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
label_column = "external_transcript_name", label = interesting, alpha = 1.0,
outline = outline, size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p15_retina_volcano.pdf", width = 9, height = 9)
kh_p15_retina_volcano[["plot"]]
## Error:
## ! object 'kh_p15_retina_volcano' not found
plotted <- dev.off()
kh_p15_retina_volcano[["plot"]]
## Error:
## ! object 'kh_p15_retina_volcano' not found
## why in the crap is it double-labelling!?
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p15_retina_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["het_retina"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p15_retina_ma.pdf", width = 9, height = 9)
kh_p15_retina_ma[["plot"]]
## Error:
## ! object 'kh_p15_retina_ma' not found
plotted <- dev.off()
kh_p15_retina_ma[["plot"]]
## Error:
## ! object 'kh_p15_retina_ma' not found
ko/het p15
SCN
Repeat this with
two sets of genes
table_name <- "kh_p15_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Fign", "Nrn1", "Dpysl2", "Actb", "Fgf9", "Otx2", "Sec23",
"Ncam1", "Map4", "Sec22b", "Nlgn3", "Marcks", "Cd47",
"Dpysl3", "Lin7c", "Cadm1", "Snx12", "Rhoa", "Inpp5f",
"Atg12", "Set", "Gsk3b", "Pdcd4", "Gabra2", "Tmco1", "Anapc16")
kh_p15_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
label_column = "external_transcript_name", size = 4, alpha = 1.0,
outline = outline, color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]])
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p15_scn_volcano.pdf", width = 9, height = 9)
kh_p15_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_scn_volcano' not found
plotted <- dev.off()
kh_p15_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_scn_volcano' not found
kh_p15_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p15_scn_ma.pdf", width = 9, height = 9)
kh_p15_scn_ma[["plot"]]
## Error:
## ! object 'kh_p15_scn_ma' not found
plotted <- dev.off()
kh_p15_scn_ma[["plot"]]
## Error:
## ! object 'kh_p15_scn_ma' not found
Round 2 with a separate gene set.
table_name <- "kh_p15_scn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
interesting_genes <- c(
"Anapc16", "Gabra2", "Tmco1", "Sod2", "Fgf9", "Pdcd4", "Rhoa", "Gsk3b", "Foxp1",
"Ncam1", "Marcks", "Fign", "Dpysl3", "Inpp5f", "Cadm1", "Map4", "Ugcg", "Elovl4",
"Elavl1", "Cfl2", "Tnnt1", "Gnb1", "Impact", "Nrn1", "Nlgn3", "Actb", "Cd47",
"Sec22b", "Slc17a7", "Vglut1", "Actb", "B4galt5", "Foxp1", "Otx2", "Lin7c",
"Snx12", "Atg12", "Set")
kh_p15_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
outline = outline, label_column = "external_transcript_name", label = interesting_genes, size = 4, alpha = 1.0)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p15_scn_volcano_v2.pdf", width = 9, height = 9)
kh_p15_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_scn_volcano' not found
plotted <- dev.off()
kh_p15_scn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_scn_volcano' not found
kh_p15_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_scn"]], color_high = colors[["het_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p15_scn_ma_v2.pdf", width = 9, height = 9)
kh_p15_scn_ma[["plot"]]
## Error:
## ! object 'kh_p15_scn_ma' not found
plotted <- dev.off()
kh_p15_scn_ma[["plot"]]
## Error:
## ! object 'kh_p15_scn_ma' not found
ko/het p15
dLGN
table_name <- "kh_p15_dlgn"
table_input <- genotype_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
kh_p15_dlgn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
outline = outline, label_column = "external_transcript_name", label = 10, size = 4, alpha = 1.0)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "13genotype_ma_volcano_tx/kh_p15_dlgn_volcano.pdf", width = 9, height = 9)
kh_p15_dlgn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_dlgn_volcano' not found
plotted <- dev.off()
kh_p15_dlgn_volcano[["plot"]]
## Error:
## ! object 'kh_p15_dlgn_volcano' not found
## My MA plotter isn't as smart as the volcano plotter, the genes are:
kh_p15_dlgn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_dlgn"]], color_high = colors[["het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = 10, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "13genotype_ma_volcano_tx/kh_p15_dlgn_ma.pdf", width = 9, height = 9)
kh_p15_dlgn_ma[["plot"]]
## Error:
## ! object 'kh_p15_dlgn_ma' not found
plotted <- dev.off()
kh_p15_dlgn_ma[["plot"]]
## Error:
## ! object 'kh_p15_dlgn_ma' not found
A query from Rashmi:
“I was discussing with Dr. Speer about the dLGN data and we found
mostly retinal genes in dLGN Het/KO or time point comparison. Please
check if those are not retina samples.”
I checked the samples etc and everything looks ok to me; perhaps I
can use the results to look at this question in another way:
I will therefore load the p08_het_dlgn/p08_ko_dlgn table and compare
it to the p08_het_retina/p08_ko_retina table directly. I think that if
these turn out to be identical, then the hypothesis suggested by this
query is correct.
Note, in order to do this, I must use the full tables, not the
post-inclusion tables because I cannot guarantee that they will have
identical gene IDs.
retina_table <- genotype_tables_full[["data"]][["kh_p08_retina"]]
dlgn_table <- genotype_tables_full[["data"]][["kh_p08_dlgn"]]
retina_subset <- retina_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(retina_subset) <- c("ID", "retina_logfc")
dlgn_subset <- dlgn_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(dlgn_subset) <- c("ID", "dlgn_logfc")
merged <- merge(retina_subset, dlgn_subset, by = "ID")
rownames(merged) <- make.names(merged[["ID"]], unique = TRUE)
merged[["ID"]] <- NULL
plotted <- plot_linear_scatter(merged)
pp(file = "images_tx/kh_p08_retina_vs_dlgn_deseq_logfc_values.png")
## Warning in pp(file = "images_tx/kh_p08_retina_vs_dlgn_deseq_logfc_values.png"):
## The directory: images_tx does not exist, will attempt to create it.
plotted[["scatter"]]
dev.off()
## png
## 2

Rashmi asked if we could also do the p15 for this comparison:
retina_table <- genotype_tables_full[["data"]][["kh_p15_retina"]]
dlgn_table <- genotype_tables_full[["data"]][["kh_p15_dlgn"]]
retina_subset <- retina_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(retina_subset) <- c("ID", "retina_logfc")
dlgn_subset <- dlgn_table[, c("ensembl_gene_id", "deseq_logfc")]
colnames(dlgn_subset) <- c("ID", "dlgn_logfc")
merged <- merge(retina_subset, dlgn_subset, by = "ID")
rownames(merged) <- make.names(merged[["ID"]], unique = TRUE)
merged[["ID"]] <- NULL
plotted <- plot_linear_scatter(merged)
pp(file = "images_tx/kh_p15_retina_vs_dlgn_deseq_logfc_values.png")
plotted[["scatter"]]
dev.off()
## png
## 2

Repeat with the
strict filter
genotype_strict_tables <- list()
genotype_strict_sig <- list()
genotype_strict_gp <- list()
genotype_strict_cp <- list()
genotype_strict_en <- list()
for (k in seq_along(genotype_keepers)) {
name <- names(genotype_keepers)[k]
message("Examining ", name)
keeper <- genotype_keepers[name]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_strict_df <- genotype_inclusions_strict[[include_df_name]]
includes_strict <- genotype_inclusions_strict[[include_name]]
summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes_strict)
include_filename <- glue("14genotype_strict_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("14genotype_strict_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
genotype_strict_tables[[name]] <- combine_de_tables(
genotype_de, extra_annot = include_strict_df,
keepers = keeper, label_column = tx_label_column,
excel = include_filename, wanted_genes = includes_strict)
print(genotype_strict_tables[[name]])
genotype_strict_sig[[name]] <- extract_significant_genes(
genotype_strict_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(genotype_strict_sig[[name]])
num_rows <- nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows >= 10) {
message("Performing gprofiler/clusterProfiler.")
genotype_strict_gp[[name]] <- all_gprofiler(genotype_strict_sig[[name]], species = "mmusculus")
genotype_strict_cp[[name]] <- all_cprofiler(
genotype_strict_sig[[name]], genotype_strict_tables[[name]],
orgdb = "org.Mm.eg.db", go_level = go_level,
orgdb_from = orgdb_from, max_groupsize = max_groupsize, organism = "mouse")
#if (!is.null(get0("m2_gsc"))) {
# genotype_strict_en[[name]] <- all_enricher(genotype_strict_sig[[name]], gsc = m2_gsc,
# orgdb = "org.Mm.eg.db", from = "ENSEMBL", to = "SYMBOL")
#}
gp_written <- write_all_gp(genotype_strict_gp[[name]], prefix = "15", suffix = "strict")
cp_written <- write_all_cp(genotype_strict_cp[[name]], prefix = "15", suffix = "strict")
#en_written <- write_all_en(genotype_strict_en[[name]])
} else {
warning("There are less than 10 genes up and down in the ", name, " comparison.")
message("There are less than 10 genes up and down in the ", name, " comparison.")
}
}
## Examining kh_p08_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_dlgn_vs_p08_het_dlgn 1 0 1
## edger_sigdown limma_sigup limma_sigdown
## 1 0 1 0
## Only kh_p08_dlgn_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p08_dlgn 1 0

## There are 1 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_dlgn
## comparison.
## There are less than 10 genes up and down in the kh_p08_dlgn comparison.
## Examining kh_p15_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p15_het_dlgn 0 0 0
## edger_sigdown limma_sigup limma_sigdown
## 1 0 0 0
## Only has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p15_dlgn 0 0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_dlgn
## comparison.
## There are less than 10 genes up and down in the kh_p15_dlgn comparison.
## Examining kh_p08_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_ko_retina_vs_p08_het_retina 1 0 1
## edger_sigdown limma_sigup limma_sigdown
## 1 0 0 0
## Only kh_p08_retina_up has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p08_retina 1 0

## There are 1 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_retina
## comparison.
## There are less than 10 genes up and down in the kh_p08_retina comparison.
## Examining kh_p15_retina
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 49.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_retina_vs_p15_het_retina 0 0 0
## edger_sigdown limma_sigup limma_sigdown
## 1 0 0 0
## Only has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p15_retina 0 0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_retina
## comparison.
## There are less than 10 genes up and down in the kh_p15_retina comparison.
## Examining kh_p08_scn
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 1.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p08_ko_scn_vs_p08_het_scn 0 0 0 0
## limma_sigup limma_sigdown
## 1 0 0
## Only has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p08_scn 0 0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p08_scn comparison.
## There are less than 10 genes up and down in the kh_p08_scn comparison.
## Examining kh_p15_scn
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 1.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup edger_sigdown
## 1 p15_ko_scn_vs_p15_het_scn 0 0 0 0
## limma_sigup limma_sigdown
## 1 0 0
## Only has information, cannot create an UpSet.
## Plot describing unique/shared genes in a differential expression table.
## NULL
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## kh_p15_scn 0 0
## There are 0 significant up and down genes.
## Warning: There are less than 10 genes up and down in the kh_p15_scn comparison.
## There are less than 10 genes up and down in the kh_p15_scn comparison.
Genotype Strict
plots
for (k in seq_along(genotype_keepers)) {
name <- names(genotype_keepers)[k]
message("Examining ", name)
keeper <- genotype_keepers[name]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_strict_df <- genotype_inclusions_strict[[include_df_name]]
includes_strict <- genotype_inclusions_strict[[include_name]]
summary(rownames(genotype_sig_full[["deseq"]][["ups"]][[name]]) %in% includes_strict)
num_rows <- nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
nrow(genotype_strict_sig[[name]][["deseq"]][["ups"]][[name]])
nrow(genotype_strict_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
## #1 is up and #2 is down, avoiding typeos here.
num_objects <- length(genotype_strict_cp[[name]])
if (num_objects == 0) {
warning("Something went wrong in all_cprofiler.")
} else {
upp <- which(grepl(x = names(genotype_strict_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(genotype_strict_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- genotype_strict_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("16clusterProfiler_plots_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- genotype_strict_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, cateogories = go_categories)
bp_bar_down_filename <- glue("16clusterProfiler_plots_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining kh_p08_dlgn
## There are 1 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_dlgn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_retina
## There are 1 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_retina
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p08_scn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining kh_p15_scn
## There are 0 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
Given this stricter filter, I think no genes pass in the genome
comparisons.
Location contrasts
with genes removed/kept
We will now repeat the above tasks seeking location differences
instead of genotype; essentially I copy/pasted the above with
s/genotype/location/g.
location_tables_full <- combine_de_tables(
location_de, keepers = location_keepers, label_column = tx_label_column,
excel = glue("17full_location_contrasts_tx/location_full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_retina 1138 1074 1324
## 2 p15_het_dlgn_vs_p15_het_retina 1001 1314 1149
## 3 p08_ko_dlgn_vs_p08_ko_retina 960 914 1087
## 4 p15_ko_dlgn_vs_p15_ko_retina 882 1107 1042
## 5 p08_het_scn_vs_p08_het_retina 1410 1414 1685
## 6 p15_het_scn_vs_p15_het_retina 1383 1460 1641
## 7 p08_ko_scn_vs_p08_ko_retina 1181 1184 1391
## 8 p15_ko_scn_vs_p15_ko_retina 939 1135 1156
## 9 p08_het_dlgn_vs_p08_het_scn 443 483 513
## 10 p15_het_dlgn_vs_p15_het_scn 1127 1422 1231
## 11 p08_ko_dlgn_vs_p08_ko_scn 446 483 501
## 12 p15_ko_dlgn_vs_p15_ko_scn 1237 1303 1427
## edger_sigdown limma_sigup limma_sigdown
## 1 1127 1027 976
## 2 1479 969 1110
## 3 996 824 994
## 4 1187 787 888
## 5 1516 1312 1239
## 6 1643 1362 1371
## 7 1265 1117 1103
## 8 1346 976 1018
## 9 612 402 478
## 10 1619 1268 1421
## 11 573 529 746
## 12 1448 1267 1329
## Plot describing unique/shared genes in a differential expression table.

location_sig_full <- extract_significant_genes(
location_tables_full, according_to = "deseq",
excel = glue("17full_location_contrasts_tx/location_full_sig-v{ver}.xlsx"))
location_sig_full
## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## dr_p08_het 1138 1074
## dr_p15_het 1001 1314
## dr_p08_ko 960 914
## dr_p15_ko 882 1107
## sr_p08_het 1410 1414
## sr_p15_het 1383 1460
## sr_p08_ko 1181 1184
## sr_p15_ko 939 1135
## ds_p08_het 443 483
## ds_p15_het 1127 1422
## ds_p08_ko 446 483
## ds_p15_ko 1237 1303

location_full_upset <- upsetr_sig(location_sig_full)
location_full_intersects <- write_upset_groups(
location_full_upset,
excel = "excel/17full_location_contrasts_tx/location_full_gene_groups.xlsx")
location_tables <- list()
location_sig <- list()
location_gp <- list()
location_cp <- list()
for (k in seq_along(location_keepers)) {
name <- names(location_keepers)[k]
message("Examining ", name)
keeper <- location_keepers[name]
includes <- location_inclusions[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- location_inclusions[[include_df_name]]
includes <- location_inclusions[[include_name]]
summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
include_filename <- glue("18location_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("18location_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
location_tables[[name]] <- combine_de_tables(
location_de, extra_annot = include_df,
keepers = keeper, label_column = tx_label_column,
excel = include_filename, wanted_genes = includes)
print(location_tables[[name]])
location_sig[[name]] <- extract_significant_genes(
location_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(location_sig[[name]])
num_rows <- nrow(location_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows > 10) {
location_gp[[name]] <- all_gprofiler(location_sig[[name]], species = "mmusculus")
location_cp[[name]] <- all_cprofiler(
location_sig[[name]], location_tables[[name]],
orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
max_groupsize = max_groupsize, organism = "mouse")
cp_written <- write_all_cp(location_cp[[name]], prefix = "19")
gp_written <- write_all_gp(location_gp[[name]], prefix = "19")
}
}
## Examining dr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_retina 110 96 124
## edger_sigdown limma_sigup limma_sigdown
## 1 90 109 81
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## dr_p08_het 110 96

## There are 206 significant up and down genes.
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in `.subset2()`:
## ! subscript out of bounds
Print out all the plots in a separate block.
for (k in seq_along(location_keepers)) {
name <- names(location_keepers)[k]
message("Examining ", name)
keeper <- location_keepers[name]
includes <- location_inclusions[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- location_inclusions[[include_df_name]]
includes <- location_inclusions[[include_name]]
summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
num_rows <- nrow(location_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
nrow(location_sig[[name]][["deseq"]][["ups"]][[name]])
nrow(location_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
num_objects <- length(location_cp[[name]])
if (num_objects == 0) {
warning("Something went wrong in all_cprofiler.")
} else {
upp <- which(grepl(x = names(location_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(location_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- location_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- location_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- location_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("19clusterProfiler_plots_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- location_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- location_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- location_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = 12)
cc_tree_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_down_filename <- glue("19clusterProfiler_plots_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining dr_p08_het
## There are 206 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in pp(file = mf_tree_up_filename): The directory:
## 19clusterProfiler_plots_tx does not exist, will attempt to create it.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining dr_p15_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining dr_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining dr_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p08_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p15_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
Colenso sent a specific query of interest, comparing SCN vs. Retinas
at p08 in the heterozygotes including a set of genes of particular
interest. Perhaps I can use some of these as markers to quality control
my work in the future?
Here are the genes:
Opn4, Eomes, Trpc7, Oprm1, Nr4a3, Tbx20, Irx6, AW551984, Pcdh19,
Adcyap1, Baiap3, Chl1, Grin3a, Igf1, Gria1, Grin2d, Grin3a, Chrna6,
Chrna3, Htr5a, Htr2a, Htr7, Irx4, PlxnC1, Sema6d, Sema4f, Sema4a,
Sema6b, Lrrc4b, Lrrc58, Lrrc3b, Wnt4, Wnt9b, Ctxn3, Tenm1, Gna14, Rgs4,
Rgs6, Rgs5
table_input <- location_tables[["sr_p08_het"]]
table_name <- "sr_p08_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
"Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
"Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
"Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
"PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
"Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
"Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p08_het_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "20location_ma_volcano_tx/sr_p08_het_volcano.pdf", width = 9, height = 9)
## Warning in pp(file = "20location_ma_volcano_tx/sr_p08_het_volcano.pdf", : The
## directory: 20location_ma_volcano_tx does not exist, will attempt to create it.
sr_p08_het_volcano[["plot"]]
## Error:
## ! object 'sr_p08_het_volcano' not found
plotted <- dev.off()
sr_p08_het_volcano[["plot"]]
## Error:
## ! object 'sr_p08_het_volcano' not found
sr_p08_het_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "20location_ma_volcano_tx/sr_p08_het_ma.pdf", width = 9, height = 9)
sr_p08_het_ma[["plot"]]
## Error:
## ! object 'sr_p08_het_ma' not found
plotted <- dev.off()
sr_p08_het_ma[["plot"]]
## Error:
## ! object 'sr_p08_het_ma' not found
Also the ko
table_input <- location_tables[["sr_p08_ko"]]
table_name <- "sr_p08_ko"
table <- table_input[["data"]][[table_name]]
sr_p08_ko_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "20location_ma_volcano_tx/sr_p08_ko_volcano.pdf", width = 9, height = 9)
sr_p08_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p08_ko_volcano' not found
plotted <- dev.off()
sr_p08_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p08_ko_volcano' not found
sr_p08_ko_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "20location_ma_volcano_tx/sr_p08_ko_ma.pdf", width = 9, height = 9)
sr_p08_ko_ma[["plot"]]
## Error:
## ! object 'sr_p08_ko_ma' not found
plotted <- dev.off()
sr_p08_ko_ma[["plot"]]
## Error:
## ! object 'sr_p08_ko_ma' not found
table_input <- location_tables[["sr_p15_het"]]
table_name <- "sr_p15_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
"Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
"Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
"Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
"PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
"Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
"Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p15_het_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "20location_ma_volcano_tx/sr_p15_het_volcano.pdf", width = 9, height = 9)
sr_p15_het_volcano[["plot"]]
## Error:
## ! object 'sr_p15_het_volcano' not found
plotted <- dev.off()
sr_p15_het_volcano[["plot"]]
## Error:
## ! object 'sr_p15_het_volcano' not found
sr_p15_het_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "20location_ma_volcano_tx/sr_p15_het_ma.pdf", width = 9, height = 9)
sr_p15_het_ma[["plot"]]
## Error:
## ! object 'sr_p15_het_ma' not found
plotted <- dev.off()
sr_p15_het_ma[["plot"]]
## Error:
## ! object 'sr_p15_het_ma' not found
Also the ko
table_input <- location_tables[["sr_p15_ko"]]
table_name <- "sr_p15_ko"
table <- table_input[["data"]][[table_name]]
sr_p15_ko_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "20location_ma_volcano_tx/sr_p15_ko_volcano.pdf", width = 12, height = 12)
sr_p15_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p15_ko_volcano' not found
plotted <- dev.off()
sr_p15_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p15_ko_volcano' not found
sr_p15_ko_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "20location_ma_volcano_tx/sr_p15_ko_ma.pdf", width = 9, height = 9)
sr_p15_ko_ma[["plot"]]
## Error:
## ! object 'sr_p15_ko_ma' not found
plotted <- dev.off()
sr_p15_ko_ma[["plot"]]
## Error:
## ! object 'sr_p15_ko_ma' not found
Test a specific
location query for duplicated IDs
Let us see if any Ensembl gene IDs and/or MGI IDs are shared in the
worksheet location_sr_p08_ko_including_wt_0.1_decreased_sig up/down.
test_table_up <- location_sig[["sr_p08_ko"]][["deseq"]][["ups"]][[1]]
test_table_down <- location_sig[["sr_p08_ko"]][["deseq"]][["downs"]][[1]]
query <- list("up" = rownames(test_table_up),
"down" = rownames(test_table_down))
query_upset <- UpSetR::fromList(query)
UpSetR::upset(query_upset)
## Error in `start_col:end_col`:
## ! argument of length 0
query <- list("up" = test_table_up[["external_transcript_name"]],
"down" = test_table_down[["external_transcript_name"]])
query_upset <- UpSetR::fromList(query)
UpSetR::upset(query_upset)
## Error in `start_col:end_col`:
## ! argument of length 0
Repeat with the
strict filter
location_strict_tables <- list()
location_strict_sig <- list()
location_strict_gp <- list()
location_strict_cp <- list()
for (k in seq_along(location_keepers)) {
name <- names(location_keepers)[k]
message("Examining ", name)
keeper <- location_keepers[name]
includes <- location_inclusions_strict[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- location_inclusions_strict[[include_df_name]]
includes <- location_inclusions_strict[[include_name]]
found_includes <- rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes
summary(found_includes)
if (sum(found_includes) == 0) {
next
}
include_filename <- glue("21location_strict_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("21location_strict_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
location_strict_tables[[name]] <- combine_de_tables(
location_de, extra_annot = include_df,
keepers = keeper, label_column = tx_label_column,
excel = include_filename, wanted_genes = includes)
print(location_strict_tables[[name]])
location_strict_sig[[name]] <- extract_significant_genes(
location_strict_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(location_strict_sig[[name]])
num_rows <- nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows > 10) {
location_strict_gp[[name]] <- all_gprofiler(location_strict_sig[[name]], species = "mmusculus")
location_strict_cp[[name]] <- all_cprofiler(
location_strict_sig[[name]], location_strict_tables[[name]],
orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
max_groupsize = max_groupsize, organism = "mouse")
cp_written <- write_all_cp(location_strict_cp[[name]], prefix = "22", suffix = "strict")
gp_written <- write_all_gp(location_strict_gp[[name]], prefix = "22", suffix = "strict")
}
}
## Examining dr_p08_het
## Looking for subscript invalid names, end of extract_keepers.
## The result table is too small for meaningful comparisons.
## The first table has only: 22.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p08_het_dlgn_vs_p08_het_retina 6 2 6
## edger_sigdown limma_sigup limma_sigdown
## 1 1 6 1
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## dr_p08_het 6 2

## There are 8 significant up and down genes.
## Examining dr_p15_het
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p15_het_retina 19 1 21
## edger_sigdown limma_sigup limma_sigdown
## 1 1 17 1
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## dr_p15_het 19 1

## There are 20 significant up and down genes.
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in `.subset2()`:
## ! subscript out of bounds
Print out all the plots in a separate block.
for (k in seq_along(location_keepers)) {
name <- names(location_keepers)[k]
message("Examining ", name)
keeper <- location_keepers[name]
includes <- location_inclusions_strict[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- location_inclusions_strict[[include_df_name]]
includes <- location_inclusions_strict[[include_name]]
summary(rownames(location_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
num_rows <- nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
nrow(location_strict_sig[[name]][["deseq"]][["ups"]][[name]])
nrow(location_strict_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
num_objects <- length(location_strict_cp[[name]])
if (num_objects == 0) {
warning("Something went wrong in all_cprofiler.")
} else {
upp <- which(grepl(x = names(location_strict_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(location_strict_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- location_strict_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("23clusterProfiler_plots_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- location_strict_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = 12)
cc_tree_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_down_filename <- glue("23clusterProfiler_plots_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining dr_p08_het
## There are 8 significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining dr_p15_het
## There are 20 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in pp(file = mf_tree_up_filename): The directory:
## 23clusterProfiler_plots_tx does not exist, will attempt to create it.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## NULL
## NULL
## NULL
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining dr_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining dr_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p08_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p15_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining sr_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_het
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p08_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
## Examining ds_p15_ko
## There are significant up and down genes.
## Warning: Something went wrong in all_cprofiler.
Colenso sent a specific query of interest, comparing SCN vs. Retinas
at p08 in the heterozygotes including a set of genes of particular
interest. Perhaps I can use some of these as markers to quality control
my work in the future?
Here are the genes:
Opn4, Eomes, Trpc7, Oprm1, Nr4a3, Tbx20, Irx6, AW551984, Pcdh19,
Adcyap1, Baiap3, Chl1, Grin3a, Igf1, Gria1, Grin2d, Grin3a, Chrna6,
Chrna3, Htr5a, Htr2a, Htr7, Irx4, PlxnC1, Sema6d, Sema4f, Sema4a,
Sema6b, Lrrc4b, Lrrc58, Lrrc3b, Wnt4, Wnt9b, Ctxn3, Tenm1, Gna14, Rgs4,
Rgs6, Rgs5
table_input <- location_strict_tables[["sr_p08_het"]]
table_name <- "sr_p08_het"
table <- table_input[["data"]][[table_name]]
interesting_genes <- c("Opn4", "Eomes", "Trpc7", "Oprm1", "Nr4a3", "Tbx20",
"Irx6", "AW551984", "Pcdh19", "Adcyap1r1", "Baiap3",
"Chl1", "Grin3a", "Igf1", "Gria1", "Grin2d", "Grin3a",
"Chrna6", "Chrna3", "Htr5a", "Htr2a", "Htr7", "Irx4",
"PlxnC1", "Sema6d", "Sema4f", "Sema4a", "Sema6b", "Lrrc4b",
"Lrrc58", "Lrrc3b", "Wnt4", "Wnt9b", "Ctxn3", "Tenm1", "Gna14",
"Rgs4", "Rgs6", "Rgs5", "Pou4f2", "Chrnb3", "Bcan")
sr_p08_het_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
label_column = tx_label_column, label = interesting_genes, alpha = 1.0,
size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "24location_ma_volcano_strict_tx/sr_p08_het_volcano.pdf", width = 9, height = 9)
## Warning in pp(file = "24location_ma_volcano_strict_tx/sr_p08_het_volcano.pdf",
## : The directory: 24location_ma_volcano_strict_tx does not exist, will attempt
## to create it.
sr_p08_het_volcano[["plot"]]
## Error:
## ! object 'sr_p08_het_volcano' not found
plotted <- dev.off()
sr_p08_het_volcano[["plot"]]
## Error:
## ! object 'sr_p08_het_volcano' not found
sr_p08_het_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["het_retina"]], color_high = colors[["het_scn"]],
p_col = "deseq_adjp", label_column = tx_label_column, label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "24location_ma_volcano_strict_tx/sr_p08_het_ma.pdf", width = 9, height = 9)
sr_p08_het_ma[["plot"]]
## Error:
## ! object 'sr_p08_het_ma' not found
plotted <- dev.off()
sr_p08_het_ma[["plot"]]
## Error:
## ! object 'sr_p08_het_ma' not found
Also the ko
table_input <- location_strict_tables[["sr_p08_ko"]]
table_name <- "sr_p08_ko"
table <- table_input[["data"]][[table_name]]
sr_p08_ko_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
label_column = tx_label_column, label = interesting_genes, alpha = 1.0,
size = 4)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "24location_ma_volcano_strict_tx/sr_p08_ko_volcano.pdf", width = 9, height = 9)
sr_p08_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p08_ko_volcano' not found
plotted <- dev.off()
sr_p08_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p08_ko_volcano' not found
sr_p08_ko_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
p_col = "deseq_adjp", label_column = tx_label_column, label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "24location_ma_volcano_strict_tx/sr_p08_ko_ma.pdf", width = 9, height = 9)
sr_p08_ko_ma[["plot"]]
## Error:
## ! object 'sr_p08_ko_ma' not found
plotted <- dev.off()
sr_p08_ko_ma[["plot"]]
## Error:
## ! object 'sr_p08_ko_ma' not found
Also the ko
table_input <- location_tables[["sr_p15_ko"]]
table_name <- "sr_p15_ko"
table <- table_input[["data"]][[table_name]]
sr_p15_ko_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
label_column = tx_label_column, label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "24location_ma_volcano_strict_tx/sr_p15_ko_volcano.pdf", width = 12, height = 12)
sr_p15_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p15_ko_volcano' not found
plotted <- dev.off()
sr_p15_ko_volcano[["plot"]]
## Error:
## ! object 'sr_p15_ko_volcano' not found
sr_p15_ko_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = colors[["ko_retina"]], color_high = colors[["ko_scn"]],
p_col = "deseq_adjp", label_column = tx_label_column, label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "24location_ma_volcano_strict_tx/sr_p15_ko_ma.pdf", width = 9, height = 9)
sr_p15_ko_ma[["plot"]]
## Error:
## ! object 'sr_p15_ko_ma' not found
plotted <- dev.off()
sr_p15_ko_ma[["plot"]]
## Error:
## ! object 'sr_p15_ko_ma' not found
And time
time_tables_full <- combine_de_tables(
time_de, keepers = time_keepers,
label_column = tx_label_column,
excel = glue("25full_contrasts_time_tx/full_tables-v{ver}.xlsx"))
## Looking for subscript invalid names, end of extract_keepers.
time_sig_full <- extract_significant_genes(
time_tables_full, according_to = "deseq",
excel = glue("25full_contrasts_time_tx/full_sig-v{ver}.xlsx"))
time_tables <- list()
time_sig <- list()
time_gp <- list()
time_cp <- list()
for (k in seq_along(time_keepers)) {
name <- names(time_keepers)[k]
message("Examining ", name)
keeper <- time_keepers[name]
includes <- time_inclusions[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- time_inclusions[[include_df_name]]
includes <- time_inclusions[[include_name]]
summary(rownames(time_sig_full[["deseq"]][["ups"]][[name]]) %in% includes)
include_filename <- glue("26time_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("26time_contrasts_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
time_tables[[name]] <- combine_de_tables(
time_de, extra_annot = include_df,
keepers = keeper, label_column = tx_label_column,
excel = include_filename, wanted_genes = includes)
print(time_tables[[name]])
time_sig[[name]] <- extract_significant_genes(
time_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(time_sig[[name]])
num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows > 10) {
time_gp[[name]] <- all_gprofiler(time_sig[[name]], species = "mmusculus")
gp_written <- write_all_gp(time_gp[[name]])
time_cp[[name]] <- all_cprofiler(
time_sig[[name]], time_tables[[name]], orgdb = "org.Mm.eg.db", organism = "mouse",
orgdb_from = orgdb_from, go_level = go_level, max_groupsize = max_groupsize)
cp_written <- write_all_cp(time_cp[[name]], prefix = "27")
gp_written <- write_all_gp(time_gp[[name]], prefix = "27")
}
}
## Examining t_het_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_dlgn_vs_p08_het_dlgn 281 9 255
## edger_sigdown limma_sigup limma_sigdown
## 1 9 197 8
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## t_het_dlgn 281 9

## There are 290 significant up and down genes.
## Examining t_ko_dlgn
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_ko_dlgn_vs_p08_ko_dlgn 357 89 390
## edger_sigdown limma_sigup limma_sigdown
## 1 87 338 73
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## t_ko_dlgn 357 89

## There are 446 significant up and down genes.
## Examining t_het_retina
## Looking for subscript invalid names, end of extract_keepers.
## A set of combined differential expression results.
## table deseq_sigup deseq_sigdown edger_sigup
## 1 p15_het_retina_vs_p08_het_retina 30 103 30
## edger_sigdown limma_sigup limma_sigdown
## 1 116 24 102
## `geom_line()`: Each group consists of only one observation.
## i Do you need to adjust the group aesthetic?
## Plot describing unique/shared genes in a differential expression table.

## A set of genes deemed significant according to deseq.
## The parameters defining significant were:
## LFC cutoff: 1 adj P cutoff: 0.05
## deseq_up deseq_down
## t_het_retina 30 103

## There are 133 significant up and down genes.
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in .subset2(x, i, exact = exact) : subscript out of bounds
## Error in `.subset2()`:
## ! subscript out of bounds
Send the plots separately.
for (k in seq_along(time_keepers)) {
name <- names(time_keepers)[k]
message("Examining ", name)
keeper <- time_keepers[name]
includes <- time_inclusions[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- time_inclusions[[include_df_name]]
includes <- time_inclusions[[include_name]]
num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
num_objects <- length(time_cp[[name]])
if (num_objects == 0) {
warning("Something failed in all_cprofiler.")
} else {
upp <- which(grepl(x = names(time_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(time_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- time_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- time_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- time_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("28clusterProfiler_plots_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- time_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- time_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- time_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_down_filename <- glue("28clusterProfiler_plots_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining t_het_dlgn
## There are 290 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in pp(file = mf_tree_up_filename): The directory:
## 28clusterProfiler_plots_tx does not exist, will attempt to create it.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_ko_dlgn
## There are 446 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_het_retina
## There are 133 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_ko_retina
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_het_scn
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_ko_scn
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
Volcano plots by
time
t_het_dlgn
table_name <- "t_het_dlgn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_dlgn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano_tx/t_het_dlgn_volcano.pdf", width = 12, height = 12)
## Warning in pp(file = "29time_ma_volcano_tx/t_het_dlgn_volcano.pdf", width = 12,
## : The directory: 29time_ma_volcano_tx does not exist, will attempt to create
## it.
t_het_dlgn_volcano[["plot"]]
plotted <- dev.off()
t_het_dlgn_volcano[["plot"]]

t_het_dlgn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
pp(file = "29time_ma_volcano_tx/t_het_dlgn_ma.pdf", width = 9, height = 9)
t_het_dlgn_ma[["plot"]]
plotted <- dev.off()
t_het_dlgn_ma[["plot"]]

t_ko_dlgn
table_name <- "t_ko_dlgn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_dlgn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano_tx/t_ko_dlgn_volcano.pdf", width = 12, height = 12)
t_ko_dlgn_volcano[["plot"]]
plotted <- dev.off()
t_ko_dlgn_volcano[["plot"]]

t_ko_dlgn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
pp(file = "29time_ma_volcano_tx/t_ko_dlgn_ma.pdf", width = 9, height = 9)
t_ko_dlgn_ma[["plot"]]
plotted <- dev.off()
t_ko_dlgn_ma[["plot"]]

t_het_retina
table_name <- "t_het_retina"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_retina_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_retina"]], color_high = time_colors[["p15_het_retina"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
pp(file = "29time_ma_volcano_tx/t_het_retina_volcano.pdf", width = 12, height = 12)
t_het_retina_volcano[["plot"]]
plotted <- dev.off()
t_het_retina_volcano[["plot"]]

t_het_retina_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_retina"]], color_high = time_colors[["p15_het_retina"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
pp(file = "29time_ma_volcano_tx/t_het_retina_ma.pdf", width = 9, height = 9)
t_het_retina_ma[["plot"]]
plotted <- dev.off()
t_het_retina_ma[["plot"]]

t_ko_retina
table_name <- "t_ko_retina"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_retina_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "29time_ma_volcano_tx/t_ko_retina_volcano.pdf", width = 12, height = 12)
t_ko_retina_volcano[["plot"]]
## Error:
## ! object 't_ko_retina_volcano' not found
plotted <- dev.off()
t_ko_retina_volcano[["plot"]]
## Error:
## ! object 't_ko_retina_volcano' not found
t_ko_retina_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "29time_ma_volcano_tx/t_ko_retina_ma.pdf", width = 9, height = 9)
t_ko_retina_ma[["plot"]]
## Error:
## ! object 't_ko_retina_ma' not found
plotted <- dev.off()
t_ko_retina_ma[["plot"]]
## Error:
## ! object 't_ko_retina_ma' not found
t_het_scn
table_name <- "t_het_scn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_het_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "29time_ma_volcano_tx/t_het_scn_volcano.pdf", width = 12, height = 12)
t_het_scn_volcano[["plot"]]
## Error:
## ! object 't_het_scn_volcano' not found
plotted <- dev.off()
t_het_scn_volcano[["plot"]]
## Error:
## ! object 't_het_scn_volcano' not found
t_het_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "29time_ma_volcano_tx/t_het_scn_ma.pdf", width = 9, height = 9)
t_het_scn_ma[["plot"]]
## Error:
## ! object 't_het_scn_ma' not found
plotted <- dev.off()
t_het_scn_ma[["plot"]]
## Error:
## ! object 't_het_scn_ma' not found
t_ko_scn
table_name <- "t_ko_scn"
table_input <- time_tables[[table_name]]
table <- table_input[["data"]][[table_name]]
t_ko_scn_volcano <- plot_volcano_condition_de(
table, table_name, fc_col = "deseq_logfc", p_col = "deseq_adjp",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
label_column = "external_transcript_name", label = interesting_genes, alpha = 1.0,
size = 4, min.segment.length = 0, point.padding = 0.2)
## Error in `plot_volcano_condition_de()`:
## ! Column: deseq_logfc is not in the table.
pp(file = "29time_ma_volcano_tx/t_ko_scn_volcano.pdf", width = 12, height = 12)
t_ko_scn_volcano[["plot"]]
## Error:
## ! object 't_ko_scn_volcano' not found
plotted <- dev.off()
t_ko_scn_volcano[["plot"]]
## Error:
## ! object 't_ko_scn_volcano' not found
t_ko_scn_ma <- plot_ma_condition_de(
table, table_name, expr_col = "deseq_basemean", fc_col = "deseq_logfc",
color_low = time_colors[["p08_het_dlgn"]], color_high = time_colors[["p15_het_dlgn"]],
p_col = "deseq_adjp", label_column = "external_transcript_name", label = interesting_genes, outline = outline)
## The column: external_transcript_name is not in the data, using rownames.
## Warning in max(newdf[["avg"]]): no non-missing arguments to max; returning -Inf
## Warning in plot_ma_condition_de(table, table_name, expr_col = "deseq_basemean",
## : NAs introduced by coercion
## Error in `[[<-.data.frame`:
## ! replacement has 1 row, data has 0
pp(file = "29time_ma_volcano_tx/t_ko_scn_ma.pdf", width = 9, height = 9)
t_ko_scn_ma[["plot"]]
## Error:
## ! object 't_ko_scn_ma' not found
plotted <- dev.off()
t_ko_scn_ma[["plot"]]
## Error:
## ! object 't_ko_scn_ma' not found
Repeat with the
strict filter
time_strict_tables <- list()
time_strict_sig <- list()
time_strict_gp <- list()
time_strict_cp <- list()
time_strict_en <- list()
for (k in seq_along(time_keepers)) {
name <- names(time_keepers)[k]
message("Examining ", name)
keeper <- time_keepers[name]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- time_inclusions_strict[[include_df_name]]
includes <- time_inclusions_strict[[include_name]]
found_includes <- rownames(time_sig_full[["deseq"]][["ups"]][[name]]) %in% includes
summary(found_includes)
if (sum(found_includes) == 0) {
next
}
include_filename <- glue("30time_strict_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_table-v{ver}.xlsx")
include_sig_filename <- glue("30time_strict_contrasts_excel_tx/{name}_including_wt_{lfc_cutoff}_decreased_sig-v{ver}.xlsx")
time_strict_tables[[name]] <- combine_de_tables(
time_de, extra_annot = include_df,
keepers = keeper, label_column = label_column,
excel = include_filename, wanted_genes = includes)
print(time_strict_tables[[name]])
time_strict_sig[[name]] <- extract_significant_genes(
time_strict_tables[[name]], according_to = "deseq",
excel = include_sig_filename)
print(time_strict_sig[[name]])
num_rows <- nrow(time_strict_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(time_strict_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
if (num_rows >= 10) {
message("Performing gprofiler/clusterProfiler.")
time_strict_gp[[name]] <- all_gprofiler(time_strict_sig[[name]], species = "mmusculus")
time_strict_cp[[name]] <- all_cprofiler(
time_strict_sig[[name]], time_strict_tables[[name]],
orgdb = "org.Mm.eg.db", go_level = go_level, orgdb_from = orgdb_from,
max_groupsize = max_groupsize, organism = "mouse")
#if (!is.null(get0("m2_gsc"))) {
# time_strict_en[[name]] <- all_enricher(time_strict_sig[[name]], gsc = m2_gsc,
# orgdb = "org.Mm.eg.db", from = "ENSEMBL", to = "SYMBOL")
#}
gp_written <- write_all_gp(time_strict_gp[[name]], prefix = "31", suffix = "strict")
cp_written <- write_all_cp(time_strict_cp[[name]], prefix = "31", suffix = "strict")
#en_written <- write_all_en(time_strict_en[[name]])
} else {
warning("There are less than 10 genes up and down in the ", name, " comparison.")
message("There are less than 10 genes up and down in the ", name, " comparison.")
}
}
## Examining t_het_dlgn
## Error:
## ! object 'label_column' not found
Send the plots separately.
for (k in seq_along(time_keepers)) {
name <- names(time_keepers)[k]
message("Examining ", name)
keeper <- time_keepers[name]
includes <- time_inclusions[[name]]
include_name <- paste0("inc_", name)
include_df_name <- paste0("df_", name)
include_df <- time_inclusions[[include_df_name]]
includes <- time_inclusions[[include_name]]
num_rows <- nrow(time_sig[[name]][["deseq"]][["ups"]][[name]]) +
nrow(time_sig[[name]][["deseq"]][["downs"]][[name]])
message("There are ", num_rows, " significant up and down genes.")
num_objects <- length(time_cp[[name]])
if (num_objects == 0) {
warning("Something failed in all_cprofiler.")
} else {
upp <- which(grepl(x = names(time_cp[[name]]), pattern = "_up$"))
downp <- which(grepl(x = names(time_cp[[name]]), pattern = "_down$"))
if (length(upp) > 0) {
mf_sig <- time_cp[[name]][[upp]][["go_data"]][["MF_enrich"]]
cc_sig <- time_cp[[name]][[upp]][["go_data"]][["CC_enrich"]]
bp_sig <- time_cp[[name]][[upp]][["go_data"]][["BP_enrich"]]
mf_plots_up <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_up_filename <- glue("32cp_trees_tx/{name}_up_mf_sig_tree.pdf")
pp(file = mf_tree_up_filename)
try(print(mf_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_up_filename <- glue("32cp_bar_tx/{name}_up_mf_sig_dot.pdf")
pp(file = mf_bar_up_filename)
try(print(mf_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_up <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_up_filename <- glue("32cp_trees_tx/{name}_up_cc_sig_tree.pdf")
pp(file = cc_tree_up_filename)
try(print(cc_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_up_filename <- glue("32cp_bar_tx/{name}_up_cc_sig_dot.pdf")
pp(file = cc_bar_up_filename)
try(print(cc_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_up_filename <- glue("32cp_trees_tx/{name}_up_bp_sig_tree.pdf")
pp(file = bp_tree_up_filename)
try(print(bp_plots_up[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_up <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_up_filename <- glue("32cp_bar_tx/{name}_up_bp_sig_dot.pdf")
pp(file = bp_bar_up_filename)
try(print(bp_plots_up[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
if (length(downp) > 0) {
mf_sig <- time_cp[[name]][[downp]][["go_data"]][["MF_enrich"]]
cc_sig <- time_cp[[name]][[downp]][["go_data"]][["CC_enrich"]]
bp_sig <- time_cp[[name]][[downp]][["go_data"]][["BP_enrich"]]
mf_plots_down <- plot_enrichresult(mf_sig, showCategory = go_categories)
mf_tree_down_filename <- glue("32cp_trees_tx/{name}_down_mf_sig_tree.pdf")
pp(file = mf_tree_down_filename)
try(print(mf_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
mf_bar_down_filename <- glue("32cp_bar_tx/{name}_down_mf_sig_dot.pdf")
pp(file = mf_bar_down_filename)
try(print(mf_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
cc_plots_down <- plot_enrichresult(cc_sig, showCategory = go_categories)
cc_tree_down_filename <- glue("32cp_trees_tx/{name}_down_cc_sig_tree.pdf")
pp(file = cc_tree_down_filename)
try(print(cc_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
cc_bar_down_filename <- glue("32cp_bar_tx/{name}_down_cc_sig_dot.pdf")
pp(file = cc_bar_down_filename)
try(print(cc_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_tree_down_filename <- glue("32cp_trees_tx/{name}_down_bp_sig_tree.pdf")
pp(file = bp_tree_down_filename)
try(print(bp_plots_down[["tree"]]), silent = TRUE)
plotted <- dev.off()
bp_plots_down <- plot_enrichresult(bp_sig, showCategory = go_categories)
bp_bar_down_filename <- glue("32cp_bar_tx/{name}_down_bp_sig_dot.pdf")
pp(file = bp_bar_down_filename)
try(print(bp_plots_down[["dot"]]), silent = TRUE)
plotted <- dev.off()
}
}
}
## Examining t_het_dlgn
## There are 290 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in pp(file = mf_tree_up_filename): The directory: 32cp_trees_tx does
## not exist, will attempt to create it.
## Warning in pp(file = mf_bar_up_filename): The directory: 32cp_bar_tx does not
## exist, will attempt to create it.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_ko_dlgn
## There are 446 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_het_retina
## There are 133 significant up and down genes.
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Warning in (function (model, data, ...) : Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Arguments in `...` must be used.
## x Problematic argument:
## * by = "Count"
## i Did you misspell an argument name?
## Examining t_ko_retina
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_het_scn
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
## Examining t_ko_scn
## There are significant up and down genes.
## Warning: Something failed in all_cprofiler.
Translatome
queries
In conversation with Colenso, he spoke about a series of contrasts
which would be interesting to attempt in order to query the changes
across both locations and genotypes and/or both locations and time,
thus:
(p08_het_scn / p08_het_retina) / (p08_ko_scn / p08_ko_retina)
as an example. We can definitely do these, but they do not work for
all methods employed (I think they work best with limma and edgeR).
Lets find out!
Two scn/retina
comparisons
- (p08_het_scn / p08_het_retina) / (p08_ko_scn / p08_ko_retina)
- (p15_het_scn / p15_het_retina) / (p15_ko_scn / p15_ko_retina)
scn_extra <- glue("\\
p08het = (conditionp08_het_scn - conditionp08_het_retina), \\
p08ko = (conditionp08_ko_scn - conditionp08_ko_retina), \\
p08het_vs_p08ko = (conditionp08_het_scn - conditionp08_het_retina) - (conditionp08_ko_scn - conditionp08_ko_retina), \\
p15het = (conditionp15_het_scn - conditionp15_het_retina), \\
p15ko = (conditionp15_ko_scn - conditionp15_ko_retina), \\
p15het_vs_p15ko = (conditionp15_het_scn - conditionp15_het_retina) - (conditionp15_ko_scn - conditionp15_ko_retina)")
scn_translatome_de_keepers <- list(
"p08het" = c("p08_het_scn", "p08_het_retina"),
"p08ko" = c("p08_ko_scn", "p08_ko_retina"),
"p15het" = c("p15_het_scn", "p15_het_retina"),
"p15ko" = c("p15_ko_scn", "p15_ko_retina"))
scn_translatome_keepers <- list(
"p08het" = c("p08_het_scn", "p08_het_retina"),
"p08ko" = c("p08_ko_scn", "p08_ko_retina"),
"p08_scn_translatome" = c("p08het", "p08ko"),
"p15het" = c("p15_het_scn", "p15_het_retina"),
"p15ko" = c("p15_ko_scn", "p15_ko_retina"),
"p15_scn_translatome" = c("p15het", "p15ko"))
filt <- normalize(tx_pairwise_input, filter = TRUE)
## Removing 52544 low-count genes (13339 remaining).
limma_test <- limma_pairwise(filt,
keepers = scn_translatome_de_keepers,
model_fstring = "~ 0 + condition",
model_svs = FALSE, extra_contrastrs = scn_extra)
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
edger_test <- edger_pairwise(filt,
keepers = scn_translatome_de_keepers,
model_fstring = "~ 0 + condition",
model_svs = FALSE, extra_contrasts = scn_extra)
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
scn_translatome_de <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = scn_translatome_de_keepers,
model_svs = FALSE,
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = scn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## scn_translatome_de_keepers, : This will likely fail because of how the keepers
## and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p15ko_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

scn_combined_test <- combine_de_tables(
scn_translatome_de, keepers = scn_translatome_keepers,
excel = glue("33translatome_xlsx_tx/test_scn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## coefficient edger did not find conditionp15ko or conditionp15het.
## coefficient limma did not find p15ko or p15het.
## Looking for subscript invalid names, end of extract_keepers.
scn_translatome_de_sva <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = scn_translatome_de_keepers,
model_svs = "svaseq",
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = scn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## scn_translatome_de_keepers, : This will likely fail because of how the keepers
## and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p15ko_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

scn_combined_test_sva <- combine_de_tables(
scn_translatome_de_sva, keepers = scn_translatome_keepers,
excel = glue("33translatome_xlsx_tx/test_scn_translatome_unfiltered_sva-v{ver}.xlsx"))
## coefficient edger did not find conditionp08ko or conditionp08het.
## coefficient limma did not find p08ko or p08het.
## coefficient edger did not find conditionp15ko or conditionp15het.
## coefficient limma did not find p15ko or p15het.
## Looking for subscript invalid names, end of extract_keepers.
Subtracting DESeq2
results: p08 scn het vs ko
p08_scn_combined_deseq <- subtract_de_results(
first_table = scn_combined_test[["data"]][["p08het"]],
second_table = scn_combined_test[["data"]][["p08ko"]],
first_lfc = "deseq_logfc", second_lfc = "deseq_logfc",
first_p = "deseq_adjp", second_p = "deseq_adjp",
first_name = "het", second_name = "ko",
excel = glue("33translatome_xlsx_tx/translatome_p08_scn_combined_deseq-v{ver}.xlsx"))
Subtracting DESeq2
results: p15 scn het vs ko
p15_scn_combined_deseq <- subtract_de_results(
first_table = scn_combined_test[["data"]][["p15het"]],
second_table = scn_combined_test[["data"]][["p15ko"]],
first_lfc = "deseq_logfc", second_lfc = "deseq_logfc",
first_p = "deseq_adjp", second_p = "deseq_adjp",
first_name = "het", second_name = "ko",
excel = glue("34translatome_deseqsub_xlsx_tx/translatome_p15_scn_combined_deseq-v{ver}.xlsx"))
One dlgn/retina
comparison
- (p08_het_dlgn / p08_het_retina) / (p08_ko_dlgn / p08_ko_retina)
p08_dlgn_extra <- "p08het_vs_p08ko = (conditionp08_het_dlgn - conditionp08_het_retina) - (conditionp08_ko_dlgn - conditionp08_ko_retina)"
p08_dlgn_translatome_de_keepers <- list(
"p08het" = c("p08_het_dlgn", "p08_het_retina"),
"p08ko" = c("p08_ko_dlgn", "p08_ko_retina"))
p08_dlgn_translatome_keepers <- list(
"p08_het_dlgn_vs_retina" = c("p08_het_dlgn", "p08_het_retina"),
"p08_ko_dlgn_vs_retina" = c("p08_ko_dlgn", "p08_ko_retina"),
"p08_dlgn_translatome" = c("p08het", "p08ko"))
p08_dlgn_translatome_de <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = p08_dlgn_translatome_de_keepers,
model_svs = FALSE,
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = p08_dlgn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## p08_dlgn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.
p08_dlgn_combined_test <- combine_de_tables(
p08_dlgn_translatome_de, keepers = p08_dlgn_translatome_keepers,
label_column = label_column,
excel = glue("33translatome_xlsx_tx/test_p08_dlgn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## Error:
## ! object 'label_column' not found
p08_dlgn_translatome_de_sva <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = p08_dlgn_translatome_de_keepers,
model_svs = "svaseq",
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = p08_dlgn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## p08_dlgn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_p08ko_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.
p08_dlgn_combined_test_sva <- combine_de_tables(
p08_dlgn_translatome_de_sva, keepers = p08_dlgn_translatome_keepers,
label_column = label_column,
excel = glue("33translatome_xlsx_tx/test_p08_dlgn_translatome_unfiltered_sva-v{ver}.xlsx"))
## Error:
## ! object 'label_column' not found
Subtracting the
DESeq2 results
Two scn/retina
comparisons (p15/p08 across het/ko)
- (p15_het_scn / p15_het_retina) / (p08_het_scn / p08_het_retina)
- (p15_ko_scn / p15_ko_retina) / (p08_ko_scn / p08_ko_retina)
time_scn_extra <- glue("\\
p15het = (conditionp15_het_scn - conditionp15_het_retina), \\
p08het = (conditionp08_het_scn - conditionp08_het_retina), \\
p15het_vs_p08het = (conditionp15_het_scn - conditionp15_het_retina) - (conditionp08_het_scn - conditionp08_het_retina),
p15ko = (conditionp15_ko_scn - conditionp15_ko_retina), \\
p08ko = (conditionp08_ko_scn - conditionp08_ko_retina), \\
p15ko_vs_p08ko = (conditionp15_ko_scn - conditionp15_ko_retina) - (conditionp08_ko_scn - conditionp08_ko_retina)")
time_scn_translatome_de_keepers <- list(
"p15het" = c("p15_het_scn", "p15_het_retina"),
"p08het" = c("p08_het_scn", "p08_het_retina"),
"p15ko" = c("p15_ko_scn", "p15_ko_retina"),
"p08ko" = c("p08_ko_scn", "p08_ko_retina"))
time_scn_translatome_keepers <- list(
"p15het" = c("p15_het_scn", "p15_het_retina"),
"p08het" = c("p08_het_scn", "p08_het_retina"),
"p15ko" = c("p15_ko_scn", "p15_ko_retina"),
"p08ko" = c("p08_ko_scn", "p08_ko_retina"),
"p15_het_sc_vs_retina" = c("p15_het_scn", "p15_het_retina"),
"p08_het_sc_vs_retina" = c("p08_het_scn", "p08_het_retina"),
"scn_het_translatome" = c("p15het", "p08het"),
"scn_ko_translatome" = c("p15ko", "p08ko"))
time_scn_translatome_de <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = time_scn_translatome_de_keepers,
model_svs = FALSE,
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = time_scn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## time_scn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08het_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

time_scn_translatome_test <- combine_de_tables(
time_scn_translatome_de,
keepers = time_scn_translatome_keepers,
label_column = label_column,
excel = glue("33translatome_xlsx_tx/test_time_scn_translatome_unfiltered_nosva-v{ver}.xlsx"))
## Error:
## ! object 'label_column' not found
time_scn_translatome_de_sva <- all_pairwise(tx_pairwise_input, filter = TRUE,
keepers = time_scn_translatome_de_keepers,
model_svs = "svaseq",
model_fstring = "~ 0 + condition",
do_basic = FALSE, do_dream = FALSE,
do_noiseq = FALSE, do_ebseq = FALSE,
extra_contrasts = time_scn_extra)
## Warning in all_pairwise(tx_pairwise_input, filter = TRUE, keepers =
## time_scn_translatome_de_keepers, : This will likely fail because of how the
## keepers and extra contrasts are evaluated.
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Removing 52544 low-count genes (13339 remaining).
## This received a matrix of SVs.
## converting counts to integer mode
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## 6 rows did not converge in beta, labelled in mcols(object)$betaConv. Use larger maxit argument with nbinomWaldTest
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## This contrast put the denominator first.
## The contrast condition_NA_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08het_vs_p15het is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_NA_vs_p08ko is not in the results.
## If this is not an extra contrast, then this is an error.
## The contrast condition_p08ko_vs_p15ko is not in the results.
## If this is not an extra contrast, then this is an error.
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## conditions
## p08_het_dlgn p08_het_retina p08_het_scn p08_ko_dlgn p08_ko_retina
## 3 3 3 3 3
## p08_ko_scn p08_wt_dlgn p08_wt_retina p08_wt_scn p15_het_dlgn
## 3 5 5 3 4
## p15_het_retina p15_het_scn p15_ko_dlgn p15_ko_retina p15_ko_scn
## 4 3 3 3 3
## p15_wt_dlgn p15_wt_retina p15_wt_scn
## 5 5 2
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The basic results are not of class hpgltools::basic_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The dream results are not of class hpgltools::dream_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The ebseq results are not of class hpgltools::ebseq_pairwise.
## Warning in correlate_de_tables(results, annot_df = annot_df, extra_contrasts =
## extra_contrasts): The noiseq results are not of class
## hpgltools::noiseq_pairwise.

time_scn_translatome_test_sva <- combine_de_tables(
time_scn_translatome_de_sva,
keepers = time_scn_translatome_keepers,
label_column = label_column,
excel = glue("33translatome_xlsx_tx/test_time_scn_translatome_unfiltered_sva-v{ver}.xlsx"))
## Error:
## ! object 'label_column' not found
Next step: Perform the retina filter; need to think about the proper
union/intersection of the retina/x expression values
In the previous block, we are making 2 global comparisons, here is
one of them:
(p15hetscn/p15hetret)/(p08hetscn/p08hetret)
I therefore want to extract the most logical set of genes higher in
some/all of these conditions with respect to the corresponding wt
conditions. Previously, in section ‘Extract genes included for each set
of contrasts’, I attempted to perform this operation for 2 specific wt
conditions. When this was performed, it took the unique(union) of the
two sets. Thus it stands to reason that I want to take the unique(union)
of all 4 in this instance? e.g.:
(p15hetscn > p15wtscn) | (p15hetret > p15wtret) | (p08hetscn
> p08wtscn) | (p08hetret > p08wtret)
I kind of think it should be:
((p15hetscn > p15wtscn) | (p15hetret > p15wtret)) &
((p08hetscn > p08wtscn) | (p08hetret > p08wtret))
gross, perhaps I should just do this manually, given that there are
only a few putative translatomes to query?
LS0tCnRpdGxlOiAiQW5hbHlzZXMgb2YgdGhlIElQUkdDIHRyYW5zY3JpcHQgYWJ1bmRhbmNlcy4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHplbmJ1cm4KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiAgZm9udC1zaXplOiAxNnB4Cn0KYm9keSAubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTYwMHB4Owp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGhwZ2x0b29scykKbGlicmFyeShkcGx5cikKbGlicmFyeShlbnJpY2hwbG90KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShncHJvZmlsZXIyKQp0dCA8LSB0cnkoZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpKQprbml0cjo6b3B0c19rbml0JHNldCgKICBwcm9ncmVzcyA9IFRSVUUsIHZlcmJvc2UgPSBUUlVFLCB3aWR0aCA9IDkwLCBlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVycm9yID0gVFJVRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDgsIGZpZy5yZXRpbmEgPSAyLAogIG91dC53aWR0aCA9ICIxMDAlIiwgZGV2ID0gInBuZyIsCiAgZGV2LmFyZ3MgPSBsaXN0KHBuZyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplID0gMTIpKQp2ZXIgPC0gIjIwMjQwOCIKcHJldmlvdXNfZmlsZSA8LSAiIgp2ZXIgPC0gZm9ybWF0KFN5cy5EYXRlKCksICIlWSVtJWQiKQoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCnJtZF9maWxlIDwtICJpcHJnY19hbmFseXNlc18yMDI0MDguUm1kIgpzYXZlZmlsZSA8LSBnc3ViKHBhdHRlcm4gPSAiXFwuUm1kIiwgcmVwbGFjZSA9ICJcXC5yZGFcXC54eiIsIHggPSBybWRfZmlsZSkKIyMgTm8gb25lIHdpbGwgZXZlciByZWFkIHRoaXMgSSBzdXNwZWN0LCBidXQgdGhpcyBoYXMgX25vXyBMTE0tcHJvZHVjZWQgdGV4dC4KYGBgCgojIFByaW1hcnkgdHJhbnNjcmlwdCBxdWVzdGlvbiBvZiBpbnRlcmVzdAoKV2hlbiBjb21wYXJpbmcgdGhlIGhldC9rbyBkYXRhLCBhIHNwZWNpZmljIHNldCBvZiBnZW5lcyB3YXMgb2JzZXJ2ZWQ7CndoYXQgYXJlIHRoZSBzZXQgb2YgdHJhbnNjcmlwdHMgaWNsdWRlZCBhbW9uZyB0aGVtIG9mIGludGVyZXN0PyBUaGlzCmlzIGluIGNvbnRyYXN0IHRvIE5hamliJ3MgcXVlc3Rpb246IGFyZSB0aGVyZSB0cmFuc2NyaXB0cyBub3QgaW5jbHVkZWQKYW1vbmcgdGhlIGdlbmVzIG9ic2VydmVkLgoKTGlrZWx5IGFubm90YXRpb24gY29sdW1uczogZW5zZW1ibF9nZW5lX2lkLCBlbnNlbWJsX3RyYW5zY3JpcHRfaWQsCmVuc2VtYmxfcGVwdGlkZV9pZCwgZW5zZW1ibF9leG9uX2lkLCBkZXNjcmlwdGlvbiwgY2hyb21vc29tZSwKdHJhbnNjcmlwdF9zdGFydCwgdHJhbnNjcmlwdF9lbmQsIHRyYW5zY3JpcHRfbGVuZ3RoLCBzdHJhbmQsCmV4dGVybmFsX2dlbmVfbmFtZSwgZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lLCBleHRlcm5hbF9zeW5vbnltLApwaGVub3R5cGVfZGVzY3JpcHRpb24sIHJlZnNlcV9tcm5hLgoKIyBTZXQgc29tZSBwYXJhbWV0ZXJzIHdoaWNoIHdpbGwgYmUgdXNlZCBsYXRlcgoKYGBge3J9CiMjIEFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmIHdoZW4gd29ya2luZyBvbiAnbm9ybWFsJyBjb250cmFzdHMuCmFkanBfY3V0b2ZmIDwtIDAuMDUKIyMgQWRqdXN0ZWQgcC12YWx1ZSBjdXRvZmYgd2hlbiB3b3JraW5nIG9uIHRoZSBpbmNsdXNpb24gc2V0cy4KZmlsdGVyX2FkanBfY3V0b2ZmIDwtIDAuMQpkZWZhdWx0X2ZzdHJpbmcgPC0gIn4gMCArIGNvbmRpdGlvbiIKIyMgQWxsb3cgMTAgR08gY2F0ZWdvcmllcyB0byBiZSBkaXNwbGF5ZWQgd2hlbiBwbG90dGluZy4KZ29fY2F0ZWdvcmllcyA8LSAxNAojIyBBbGxvdyBncm91cHMgaGlnaGVyIHVwIGluIHRoZSB0cmVlIGZvciBjbHVzdGVyUHJvZmlsZXIgcmVzdWx0cy4KZ29fbGV2ZWwgPC0gMgp0eF9sYWJlbF9jb2x1bW4gPC0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIgIyMgU2V0IHRoZSBjb2x1bW4gdXNlZCB0byBleHRyYWN0IGdlbmUgc3ltYm9scyByYXRoZXIgdGhhbiBFTlNHLi4uLi4KZ2VuZV9sYWJlbF9jb2x1bW4gPC0gImV4dGVybmFsX3N5bm9ueW0iCiMjIExvZ0ZDIGN1dG9mZiB3aGVuIHdvcmtpbmcgb24gdGhlIGluY2x1c2lvbiBzZXRzLgpmaWx0ZXJfbGZjX2N1dG9mZiA8LSAwLjEKIyMgTEZDIGN1dG9mZiBmb3IgJ25vcm1hbCcgY29udHJhc3RzLgpsZmNfY3V0b2ZmIDwtIDEuMAojIyBJbmNyZWFzZSB0aGUgbWF4aW11bSBhbGxvd2VkIGdyb3VwIHNpemUgd2hlbiB3b3JraW5nIHdpdGggY2x1c3RlclByb2ZpbGVyCiMjIFRoaXMgc2hvdWxkIGJyaW5nIG91dCBzb21lIG9mIHRoZSBtb3JlIGdlbmVyYWwgZ3JvdXBzIGxpa2UgJ2NlbGxib2R5JwptYXhfZ3JvdXBzaXplIDwtIDIwMDAKIyMgU3BlZWQgdXAgY2x1c3RlclByb2ZpbGVyIGJ5IGNob29zaW5nIHRoZSBjb3JyZWN0IGtleXR5cGVzCm9yZ2RiX2Zyb20gPC0gIkVOU0VNQkxUUkFOUyIKIyMgTUEgcGxvdCBwb2ludCBvdXRsaW5lcwpvdXRsaW5lIDwtIEZBTFNFCnNhbXBsZV9zaGVldCA8LSAic2FtcGxlX3NoZWV0cy8yMDI0MDYwNl9vbmx5X3VtZF9zZXF1ZW5jZWRfbW9kaWZpZWQueGxzeCIKI2Fubm90YXRpb25fY29sdW1ucyA8LSBjKAojICAiZW5zZW1ibF9nZW5lX2lkIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsImVuc2VtYmxfcGVwdGlkZV9pZCIsICJlbnNlbWJsX2V4b25faWQiLAojICAiZGVzY3JpcHRpb24iLCAiY2hyb21vc29tZV9uYW1lIiwgInRyYW5zY3JpcHRfc3RhcnQiLCAidHJhbnNjcmlwdF9lbmQiLCAidHJhbnNjcmlwdF9sZW5ndGgiLAojICAic3RyYW5kIiwgImV4dGVybmFsX2dlbmVfbmFtZSIsICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCAiZXh0ZXJuYWxfc3lub255bSIsCiMgICJwaGVub3R5cGVfZGVzY3JpcHRpb24iLCAicmVmc2VxX21ybmEiKQphbm5vdGF0aW9uX2NvbHVtbnMgPC0gYygiZW5zZW1ibF9nZW5lX2lkIiwgImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsICJkZXNjcmlwdGlvbiIsICJleHRlcm5hbF9zeW5vbnltIiwgImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgaXMgYSBjb3B5IG9mIHRoZSBpcHJnY19hbmFseXNlc18yMDI0MDguUm1kIGRvY3VtZW50LAp3aXRoIGEgZmV3IGltcG9ydGFudCBkaWZmZXJlbmNlczoKCjEuICBJIHdpbGwgbm90IGJlIHNwZW5kaW5nIHRpbWUgdG8gY29tcGFyZSB0aGUgdmFyaW91cyAoZGUpZHVwbGljYXRpb24KICAgIG1ldGhvZHMvcmVzdWx0cy4KMi4gIFRoaXMgd2lsbCBjcmVhdGUsIHZpc3VhbGl6ZSwgYW5kIGFuYWx5emUgdHJhbnNjcmlwdC1sZXZlbAogICAgYWJ1bmRhbmNlcyByYXRoZXIgdGhhbiBnZW5lcy4KMy4gIEkgaGF2ZSBub3QgeWV0IGRlY2lkZWQsIGJ1dCBJIG1pZ2h0IHBsYXkgd2l0aCB0aGUgd3QgZmlsdGVyaW5nIHRvCiAgICB0cnkgdG8gbWFrZSBpdCBjbGVhcmVyLgo0LiAgSSB3aWxsIGxpa2VseSByZW1vdmUgc29tZSBjb21tZW50cyBhbmQgdGV4dCBkZXNjcmliaW5nIHdoYXQKICAgIGlzIGdvaW5nIG9uLgo1LiAgQWxsIG91dHB1dCBkaXJlY3RvcmllcyBnZXQgYSBzdWZmaXggJ190eCcKCldpdGggdGhhdCBpbiBtaW5kLCB0aGUgZ29hbCBpcyB0byByZXBlYXQgb3VyIGdlbmUtbGV2ZWwgYW5hbHlzZXMsIGJ1dAp1c2luZyB0aGUgdHJhbnNjcmlwdCBxdWFudGlmaWNhdGlvbnMgZGVyaXZlZCBmcm9tIGZlYXR1cmVDb3VudHMuICBUaGlzCmlzIGluIHJlc3BvbnNlIHRvIGEgcmV2aWV3IHdobyBzdWdnZXN0ZWQgdGhhdCBzb21lIGdlbmVzIGhhdmUKcG90ZW50aWFsbHkgaW50ZXJlc3RpbmcgYW5kIHZhcmlhYmxlIHRyYW5zY3JpcHRzLiAgVGhhdCBpcyBhIHNpbXBsZQplbm91Z2ggcXVlcnkgdG8gYWRkcmVzcywgc28gbGV0IHVzIHNlZSB3aGF0IHdlIGdldCEKCiMgQSBub3RlIGFib3V0IGltcGxlbWVudGF0aW9uCgpJIHdvdWxkIGxpa2UgdG8gaW1wcm92ZSB0aGlzIGRvY3VtZW50IGJ5IGNvbXBhcmluZy9jb250cmFzdGluZyB0aGUKbWV0aG9kb2xvZ2llcyBwZXJmb3JtZWQgYnkgb3RoZXIgZ3JvdXBzIGFuZCB0aG9zZSBwZXJmb3JtZWQgYnkgbWUgaW4KaXQuICBJIG5ldmVyIGZ1bGx5IGFwcHJlY2lhdGVkIHRoZSBzdWl0ZSBvZiBjb21wdXRhdGlvbmFsIG1ldGhvZHMKYXBwbGllZCBieSBwcmV2aW91cyBncm91cHMgd2hlbiBleGFtaW5pbmcgVFJBUCBkYXRhOyBJIGluc3RlYWQgc2ltcGx5CmZvbGxvd2VkIFRoZXJlc2EncyBub3RlYm9vayB3aXRob3V0IGNvbnNpZGVyaW5nIG90aGVyIHBvc3NpYmlsaXRpZXMuCgpJIHRoZXJlZm9yZSBzcGVudCBhIGxpdHRsZSB0aW1lIHN0ZXBwaW5nIHRocm91Z2ggaGVyIHRoZXNpcyBhbmQKcHVsbGluZyBvdXQgdGhlIHJlbGV2YW50IHBhcGVycyBpbiB0aGUgaG9wZXMgb2YgbGVhcm5pbmcgdGhlc2UgdmFyaW91cwptZXRob2RzLiAgSSBzaG91bGQgdGhlcmVmb3JlIGJlIGFibGUgc29vbiB0byBjb21wYXJlL2NvbnRyYXN0IHRoZQp2YXJpb3VzIG1ldGhvZHMgZW1wbG95ZWQgYnkgb3RoZXIgbGFicyBpbiBhZGRpdGlvbiB0byBjb3B5aW5nClRoZXJlc2EncyBsb2dpYy4KCiMjIFRoZSBmb2xsb3dpbmcgYmxvY2sgY2Fubm90IHdvcmsgaW4gdGhlIGNvbnRhaW5lcgoKVGhlIGZvbGxvd2luZyBibG9jayBhc3N1bWVzIHRoZSBmdWxsIHRyZWUgb2YgcHJlcHJvY2Vzc2VkIGRhdGEgd2l0aAp0aGUgbG9ncyBmcm9tIHRoZSB0cmltbWVyLCBtYXBwaW5nLCB1bWkgZGVkdXBsaWNhdGlvbiwgY291bnRpbmcsIGV0Yy4KQXMgYSByZXN1bHQgaXQgY2Fubm90IHdvcmsgaW4gdGhlIGNvbnRhaW5lciB3aGljaCBoYXMgb25seSB0aGUgdmFyaW91cwpjb3VudCB0YWJsZXMuCgpBcyBhIHJlc3VsdCwgSSBhbSBpbmNsdWRpbmcgYSBjb3B5IG9mIHRoaXMgc2hlZXQgYWZ0ZXIgcnVubmluZyB0aGUKZm9sbG93aW5nIGJsb2NrIGluIG15IHdvcmtpbmcgdHJlZS4gIEkgc3VwcG9zZSBmb3IgdGhlIG1vbWVudCB5b3Ugd2lsbApoYXZlIHRvIHRydXN0IHRoYXQgaXQgd29ya2VkLiAgKGZvciByaWdodCBub3csIHdoZW4gdGVzdGluZyBvdXQgdGhpcwpjb250YWluZXIsIEkgYW0ganVzdCBzZW5kaW5nIHRoZSBSIHdvcmtpbmcgZGlyZWN0b3J5IHRvIG15IHRyZWUgZm9yCnRoaXMgYmxvY2ssIHRoZW4gbW92aW5nIGl0IGJhY2suCgpJIHdpbGwgbmVlZCB0byBtYW51YWxseSBlZGl0IG9uZSBjb2x1bW4gdGhvdWdoLCB0aGUgc3ltbGluayBjb2x1bW4KZnJvbSBUaGVyZXNhIGhhcyBhIHNlcmllcyBvZiBwYXRocyB3aGljaCBkbyBub3Qgd29yayBpbiB0aGUgY29udGFpbmVyLgoKCmBgYHtyLCBldmFsPUZBTFNFfQp1bWlfc3BlYyA8LSBtYWtlX3JuYXNlcV9zcGVjKHVtaSA9IFRSVUUpCmlwcmdjXzIwMjJfbWV0YSA8LSBnYXRoZXJfcHJlcHJvY2Vzc2luZ19tZXRhZGF0YSgic2FtcGxlX3NoZWV0cy8yMDI0MDYwNl9vbmx5X3VtZF9zZXF1ZW5jZWQueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjID0gdW1pX3NwZWMsIHNwZWNpZXMgPSAibW0zOV8xMTIiLCB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VkaXIgPSAicHJlcHJvY2Vzc2luZy91bWRfc2VxdWVuY2VkIikKY29sbmFtZXMoaXByZ2NfMjAyMl9tZXRhW1sibmV3X21ldGEiXV0pCmhlYWQoaXByZ2NfMjAyMl9tZXRhW1sibmV3X21ldGEiXV0pCmBgYAoKIyMgQ29sbGVjdCBtU2lnREIgZGF0YQoKYGBge3J9Cm1zaWdkYiA8LSAicmVmZXJlbmNlL21zaWdkYl92MjAyNC4xLk1tLmRiIgptc2lnX2RhdGEgPC0gTlVMTAptYWtlX3RyYW5zcGFyZW50IDwtIGZ1bmN0aW9uKCkgewogIGdncGxvdDI6OnRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3RyYW5zcGFyZW50JyksCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcsIGNvbG9yID0gTkEpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3RyYW5zcGFyZW50JyksCiAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd0cmFuc3BhcmVudCcpKQp9CmBgYAoKIyBDb2xsZWN0IHRoZSBjb3VudCB0YWJsZXMKCkkgdXNlZCBzYWxtb24vZmVhdHVyZWNvdW50cy9ldGMgd2l0aCBDRFMvbVJOQSBmZWF0dXJlcyBvbiBvdXIgY29tcHV0ZQpjbHVzdGVyIGFuZCB1c2VkIHRoZSBhYm92ZSBnYXRoZXIgZnVuY3Rpb24gdG8gYWRkIGEgY29sdW1uIHRvIHRoZQptZXRhZGF0YSBjb250YWluaW5nIHRoZSBmaWxlbmFtZXMgcHJvZHVjZWQuICBUaGUgZm9sbG93aW5nIHJlYWRzIHRoYXQKY29sdW1uIGFuZCBjcmVhdGVzIGEgdGFyYmFsbCBvZiB0aGUgZmlsZXMuICBPbmUgdGhpbmcgSSBuZWVkIHRvIGRvOgptb2RpZnkgdGhhdCB0byBhY2NlcHQgYSB2ZXRvciBvZiBjb2x1bW5zIHNvIEkgY2FuIGVhc2lseSBjb2xsZWN0IHIxK3IyCmFuZCBzdHVmZiBsaWtlIHRoYXQuCgpBcyB0aGUgbmFtZSBzdWdnZXN0cywgdGhlc2UgYXJlIG1STkEgY291bnRzIGZvbGxvd2luZyB0aGUKZGVkdXBsaWNhdGlvbiBtYXJraW5nIGFuZCByZW1vdmFsIGZyb20gdGhlIGluaXRpYWwgaGlzYXQgYWxpZ25tZW50cwp2aWEgdW1pdG9vbHMuCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyMgYWxsIHRoZSBpbnB1dCBmaWxlcyBhcmUgYWxyZWFkeSB4eiBjb21wcmVzc2VkCm1ybmFfY291bnRzIDwtIHRhcl9tZXRhX2NvbHVtbihzYW1wbGVfc2hlZXQsIGNvbHVtbiA9ICJ1bWlfZGVkdXBfbXJuYV9jb3VudCIsIGNvbXByZXNzID0gTlVMTCkKYGBgCgpJIHdpbGwgZmlndXJlIG91dCBpZiBJIGNhbiBsZWF2ZSBtU2lnREIgTTIgaW4gdGhpcyBpbWFnZTsgaWYgbm90LCB0aGVuCmFueSBhbmFseXNlcyBkZXBlbmRpbmcgb24gdGhvc2UgZ2VuZSBzZXRzIHdpbGwgZmFpbC4KCmBgYHtyfQptMl9nc2MgPC0gdHJ5KGxvYWRfZ210X3NpZ25hdHVyZXMoc2lnbmF0dXJlcyA9IG1zaWdkYiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJNMiIpLCBzaWxlbnQgPSBUUlVFKQojIyBJIGRvIG5vdCB0aGluayBJIGhhdmUgcGVybWlzc2lvbiB0byBsb2FkIHRoZSBtc2lnZGIgaW4gdGhlIGNvbnRhaW5lcgojIyBTbywgaWYgdGhpcyBmYWlscywganVzdCBsb2FkIGl0IGZyb20gR1NWQURhdGEsIG9oIHdhaXQgbm8sIEdTVkFkYXRhIGlzIGh1bWFuLgppZiAoInRyeS1lcnJvciIgJWluJSBjbGFzcyhtMl9nc2MpKSB7CiAgd2FybmluZygiVW5hYmxlIHRvIGxvYWQgdGhlIE0yIE1zaWdEQiBkYXRhLiIpCn0KYGBgCgojIEFubm90YXRpb24gZGF0YQoKSSBhbSBwdWxsaW5nIHRoaXMgZnJvbSBUaGVyZXNhJ3MgYW54b250cmFwUl9waXBlbGluZS5SbWQsIHByaW1hcmlseQpiZWNhdXNlIGl0IGxvb2tzIHNpbWlsYXIgdG8gdGhlIG90aGVyIGRvY3VtZW50cywgYnV0IHdhcyBtb2RpZmllZCBtb3JlCnJlY2VudGx5LiAgSSB3aWxsIGNoYW5nZSBpdCBzbGlnaHRseSwgcHJpbWFyaWx5IGJlY2F1c2UgSSBncmFiYmVkIGEKbmV3IG1tdXNjdWx1cyBhc3NlbWJseSBhbmQgdGhlcmVmb3JlIEkgd2lsbCBwdWxsIHRoZSBtbXVzY3VsdXMKYW5ub3RhdGlvbnMgZnJvbSBhIHNwZWNpZmljIGJpb21hcnQKKEBzbWVkbGV5QmlvTWFydEJpb2xvZ2ljYWxRdWVyaWVzMjAwOSkgYXJjaGl2ZSB0aGF0IHNob3VsZCBtYXRjaCBpdC4KCkEgbm90ZSBmcm9tIHRoZSBmdXR1cmU6IG11bHRpcGxlIGVuc2VtYmwgYXJjaGl2ZSBzZXJ2ZXJzIGhhdmUgYmVlbgp0YWtlbiBvZmZsaW5lIHNpbmNlIGxhc3QgSSByYW4gdGhpcy4gIExldCB1cyBzZWUgaWYgRmViLiAyMDIzIHN0aWxsCndvcmtzLgoKIyMgQW4gaW1wb3J0YW50IG5vdGUhCgpJbiB0aGUgcmVjZW50IHBhc3QsIGVuc2VtYmwgcXVlcmllcyBoYXZlIGJlY29tZSBpbmNvbnNpc3RlbnQsIGZhaWxpbmcKbXVjaCBtb3JlIG9mdGVuIHRoYW4gZXZlciBpbiB0aGUgcGFzdC4gIEkgZG8gbm90IHRoaW5rIHRoaXMgaXMgdGhlCmZhdWx0IG9mIGVuc2VtYmw7IGJ1dCBJIHRoaW5rIEkgbmVlZCBhIGZhbGxiYWNrIG1lY2hhbmlzbSBmb3IKY29sbGVjdGluZyBhbm5vdGF0aW9uIGluZm9ybWF0aW9uLgoKSW4gdGhlIGNhc2Ugb2YgZW5zZW1ibCwgaXQgc2hvdWxkIGJlIHRyaXZpYWwgKGJ1dCBsZXNzIGZ1bikgdG8gdXNlIGEKY29tYmluYXRpb24gb2YgdGhlIGxvY2FsbHkgaW5zdGFsbGVkIG9yZ2RiIGFuZCB0eGRiIGRhdGFiYXNlcy4KClRoaXMgZG9lcyBvcGVuIGEgcmlzayB0aGF0IHRoZSBzZXQgb2YgZ2VuZXMgd2l0aCBhbm5vdGF0aW9ucyB3aWxsIGJlCmRpZmZlcmVudCBkZXBlbmRpbmcgb24gd2hlbiB0aGUgY29udGFpbmVyIGlzIHJ1biBkdWUgdG8gZGlmZmVyZW5jZXMKYmV0d2VlbiB0aGUgb3JnZGIvdHhkYiBpbnN0YW5jZSBhbmQgdGhlIEZlYiAyMDIzIGJpb21hcnQuICBJIGFtIG5vdApzdXJlIHRoZXJlIGlzIG11Y2ggSSBjYW4gZG8gYWJvdXQgdGhhdCBleGNlcHQgdG8gYnVuZGxlIHRoZSBzZXQgb2YKYW5ub3RhdGlvbnMgSSBkb3dubG9hZGVkIGluIHRoZSBjb250YWluZXIgLS0gc2luY2UKbG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKCkgZG9lcyBzYXZlIGEgcmRhIGNvcHkgb2YgaXRzIGRvd25sb2FkLgoKb2ssIEkgZGlkIGJvdGguICBJZiB5b3UsIGRlYXIgcmVhZGVyLCB3aXNoIHRvIGRvd25sb2FkIHlvdXIgb3duCmFubm90YXRpb25zLCBhbmQgZW5zZW1ibCBpcyBoYXZpbmcgdHJvdWJsZXMsIHRoZSBmb2xsb3dpbmcgc2hvdWxkIHdvcmsKd2l0aG91dCBhIHByb2JsZW07IGluIGFkZGl0aW9uIHRoZSByZGEgYW5ub3RhdGlvbnMgYXJlIGluIC9kYXRhIG9mIHRoZQpjb250YWluZXIgYW5kIHNob3VsZCBnZXQgbG9hZGVkLgoKYGBge3J9CnR4X2dlbmVfbWFwIDwtIGRhdGEuZnJhbWUoKQptbV9hbm5vdCA8LSB0cnkobG9hZF9iaW9tYXJ0X2Fubm90YXRpb25zKHNwZWNpZXMgPSAibW11c2N1bHVzIiwgaG9zdCA9ICJ1c2Vhc3QuZW5zZW1ibC5vcmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyY2hpdmUgPSBGQUxTRSwgb3ZlcndyaXRlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9yZXF1ZXN0cyA9IGFubm90YXRpb25fY29sdW1ucykpCmZpZWxkcyA8LSBjKCJBQ0NOVU0iLCAiRU5TRU1CTCIsICJFTlNFTUJMVFJBTlMiLCAiRU5URVpJRCIsICJHRU5FTkFNRSIsICJTWU1CT0wiKQpvcmdkYl9hbm5vdCA8LSBsb2FkX29yZ2RiX2Fubm90YXRpb25zKCJvcmcuTW0uZWcuZGIiLCBmaWVsZHMgPSBmaWVsZHMpCmdlbmVfaW5mbyA8LSBvcmdkYl9hbm5vdFtbImdlbmVzIl1dCgojIyBOb3RlLCB0aGVyZSBhcmUgYSBidW5jaCBvZiB2YXJpYW50cyBvZiB0aGUgdHhkYiBwYWNrYWdlIG9uZSBtaWdodCB1c2UuCiMjIEkgZG8gbm90IHRoaW5rIGl0IG1hdHRlcnMgYSBsb3QgZm9yIG91ciBwdXJwb3NlcywgYnV0IEkgc3VzcGVjdCB0aGF0IGlmIHdlIHVzZWQKIyMgYSBtaXNtYXRjaGVkIEJTZ2Vub21lIGFuZCB0cmllZCB0byBwdWxsIENEUyBzZXF1ZW5jZXMsIHRoYXQgbWlnaHQgZW5kIGJhZGx5Lgpwa2cgPC0gIlR4RGIuTW11c2N1bHVzLlVDU0MubW0xMC5rbm93bkdlbmUiCnR4X2Fubm90IDwtIGxvYWRfdHhkYl9hbm5vdGF0aW9ucyhwa2cpCnRyYW5zY3JpcHRzIDwtIHR4X2Fubm90W1siVFgiXV0KdHJhbnNjcmlwdHNbWyJ0eCJdXSA8LSBnc3ViKHggPSB0cmFuc2NyaXB0c1tbIlRYTkFNRSJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiXFwuXFxkKyQiLCByZXBsYWNlbWVudCA9ICIiKQptbV9hbm5vdF9vcmdkYiA8LSBtZXJnZShnZW5lX2luZm8sIHRyYW5zY3JpcHRzLCBieS54ID0gImVuc2VtYmx0cmFucyIsIGJ5LnkgPSAidHgiKQpyb3duYW1lcyhtbV9hbm5vdF9vcmdkYikgPC0gbWFrZS5uYW1lcyhtbV9hbm5vdF9vcmdkYltbImVuc2VtYmwiXV0sIHVuaXF1ZSA9IFRSVUUpCgptbV9hbm5vdF9jb21iaW5lZCA8LSBtZXJnZShtbV9hbm5vdFtbImFubm90YXRpb24iXV0sIG1tX2Fubm90X29yZ2RiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBieS54ID0gImVuc2VtYmxfdHJhbnNjcmlwdF9pZCIsIGJ5LnkgPSAiZW5zZW1ibHRyYW5zIiwgYWxsLnggPSBUUlVFKQoKbW1fYW5ub3RfZ2VuZXMgPC0gbW1fYW5ub3RfY29tYmluZWQKcm93bmFtZXMobW1fYW5ub3RfZ2VuZXMpIDwtIG1ha2UubmFtZXMobW1fYW5ub3RfZ2VuZXNbWyJlbnNlbWJsX2dlbmVfaWQiXV0sIHVuaXF1ZSA9IFRSVUUpCgptbV90eF9hbm5vdCA8LSBtbV9hbm5vdF9jb21iaW5lZApyb3duYW1lcyhtbV90eF9hbm5vdCkgPC0gbWFrZS5uYW1lcyhtbV90eF9hbm5vdFtbImVuc2VtYmxfdHJhbnNjcmlwdF9pZCJdXSwgdW5pcXVlID0gVFJVRSkKdHhfZ2VuZV9tYXAgPC0gbW1fYW5ub3RfZ2VuZXNbLCBjKCJUWElEIiwgImVuc2VtYmxfZ2VuZV9pZCIpXQpgYGAKCiMgSGlzYXQyIHN1bW1hcml6ZWRFeHBlcmltZW50cyBieSB0cmFuc2NyaXB0CgojIyBDb2xvciBjaG9pY2VzIGFuZCByZXVzZWQgcGFyYW1ldGVycwoKYGBge3J9CmNvbG9yX2Nob2ljZXMgPC0gbGlzdCgKICAiYWxsIiA9IGxpc3QoCiAgICAicDA4X2hldF9kbGduIiA9ICIjRTcyOThBIiwKICAgICJwMTVfaGV0X2RsZ24iID0gIiNFNzI5OEEiLAogICAgInAwOF9oZXRfcmV0aW5hIiA9ICIjMjM4QjQ1IiwKICAgICJwMTVfaGV0X3JldGluYSIgPSAiIzIzOEI0NSIsCiAgICAicDA4X2hldF9zY24iID0gIiM0MjkyQzYiLAogICAgInAxNV9oZXRfc2NuIiA9ICIjNDI5MkM2IiwKICAgICJwMDhfa29fZGxnbiIgPSAiI0M5OTRDNyIsCiAgICAicDE1X2tvX2RsZ24iID0gIiNDOTk0QzciLAogICAgInAwOF9rb19yZXRpbmEiID0gIiM3NGM0NzYiLAogICAgInAxNV9rb19yZXRpbmEiID0gIiM3NGM0NzYiLAogICAgInAwOF9rb19zY24iID0gIiM5QkNBRTEiLAogICAgInAxNV9rb19zY24iID0gIiM5QkNBRTEiLAogICAgInAwOF93dF9kbGduIiA9ICIjOTgwMDQzIiwKICAgICJwMTVfd3RfZGxnbiIgPSAiIzk4MDA0MyIsCiAgICAicDA4X3d0X3JldGluYSIgPSAiIzAwNDAwOCIsCiAgICAicDE1X3d0X3JldGluYSIgPSAiIzAwNDAwOCIsCiAgICAicDA4X3d0X3NjbiIgPSAiIzA4NTE5QyIsCiAgICAicDE1X3d0X3NjbiIgPSAiIzA4NTE5QyIsCiAgICAicDYwX3d0X2RsZ24iID0gIiMzMzMzMzMiLAogICAgInA2MF93dF9yZXRpbmEiID0gIiMyMjIyMjIiLAogICAgInA2MF93dF9zY24iID0gIiMxMTExMTEiKSwKICAiZ2Vub19sb2MiID0gbGlzdCgKICAgICJoZXRfZGxnbiIgPSAiI0U3Mjk4QSIsCiAgICAiaGV0X3JldGluYSIgPSAiIzIzOEI0NSIsCiAgICAiaGV0X3NjbiIgPSAiIzQyOTJDNiIsCiAgICAia29fZGxnbiIgPSAiI0M5OTRDNyIsCiAgICAia29fcmV0aW5hIiA9ICIjNzRjNDc2IiwKICAgICJrb19zY24iID0gIiM5QkNBRTEiLAogICAgInd0X2RsZ24iID0gIiM5ODAwNDMiLAogICAgInd0X3JldGluYSIgPSAiIzAwNDAwOCIsCiAgICAid3Rfc2NuIiA9ICIjMDg1MTlDIiksCiAgImxvY2F0aW9uIiA9IGxpc3QoCiAgICAicmV0aW5hIiA9ICIjMDA0MDA4IiwKICAgICJkbGduIiA9ICIjOTgwMDQzIiwKICAgICJzY24iID0gIiMwODUxOUMiKSwKICAiZ2Vub3R5cGUiID0gbGlzdCgKICAgICJ3dCIgPSAiIzc0YzQ3NiIsCiAgICAiaGV0IiA9ICIjMjM4QjQ1IiwKICAgICJrbyIgPSAiIzAwNkQyQyIpLAogICJ0aW1lIiA9IGxpc3QoCiAgICAicDA4IiA9ICIjNUUxMDRCIiwKICAgICJwMTUiID0gIiM0RTkyMzEiKSkKY29sb3JzIDwtIGNvbG9yX2Nob2ljZXNbWyJnZW5vX2xvYyJdXQp0aW1lX2NvbG9ycyA8LSBsaXN0KAogICJwMDhfaGV0X2RsZ24iID0gIiNFNzI5OEEiLAogICJwMTVfaGV0X2RsZ24iID0gIiM4YTE4NTIiLAogICJwMDhfaGV0X3JldGluYSIgPSAiIzIzOEI0NSIsCiAgInAxNV9oZXRfcmV0aW5hIiA9ICIjMTU1MzI5IiwKICAicDA4X2hldF9zY24iID0gIiM0MjkyQzYiLAogICJwMTVfaGV0X3NjbiIgPSAiIzI3NTc3NiIsCiAgInAwOF9rb19kbGduIiA9ICIjQzk5NEM3IiwKICAicDE1X2tvX2RsZ24iID0gIiM3ODU4NzciLAogICJwMDhfa29fcmV0aW5hIiA9ICIjNzRDNDc2IiwKICAicDE1X2tvX3JldGluYSIgPSAiIzQ1NzU0NiIsCiAgInAwOF9rb19zY24iID0gIiM5QkNBRTEiLAogICJwMTVfa29fc2NuIiA9ICIjNWQ3OTg3IikKYGBgCgojIyBUaGUgVHJhbnNjcmlwdCBhYnVuZGFuY2VzCgpUaGlzIHBlcmhhcHMgZGVzZXJ2ZXMgYSBsaXR0bGUgYml0IG9mIGV4cGxhbmF0aW9uOiB0aGUgcHJvY2VzcyBmb3IKdXNpbmcgVU1JcyBnb2VzIGFzIGZvbGxvd3M6CgoxLiAgRXhhbWluZSBhbGwgdGhlIHJhdyByZWFkcywgZXh0cmFjdCB0aGUgVU1JIElEcywgYW5kIGFkZCB0aGVtIGFzCiAgICBjb21tZW50cyB0byB0aGUgZmFzdHEgZmlsZSAob3IgcmV3cml0ZSB0aGUgcmVhZCBJRCkKMi4gIEFsaWduIGFsbCByZWFkcyBhZ2FpbnN0IHRoZSBnZW5vbWUuCjMuICBUYWtlIHRoZSByZXN1bHRpbmcgYmFtIGZpbGUgYW5kIGZpbmQgcmVhZHMgYXQgdGhlIHNhbWUgbG9jYXRpb24KICAgIHdpdGggdGhlIHNhbWUgSUQocykgYW5kIGZpbHRlciB0aGUgYWxpZ25tZW50IHNvIHRoYXQgdGhlcmUgcmVtYWlucwogICAgb25seSAxIHJlcHJlc2VudGF0aXZlIGZyb20gZWFjaCBJRC4KNC4gIENvdW50IHVwIHRoZSBmZWF0dXJlcyBvZiBpbnRlcmVzdC4KCkkgdGhlcmVmb3JlIGludm9rZWQgZmVhdHVyZUNvdW50cyBvbiB0aGUgdW1pIGRlZHVwbGljYXRlZCBiYW0KYWxpZ25tZW50cyAoZm91bmQgaW4gY29sdW1uICd1bWlfZGVkdXBfb3V0cHV0X2JhbScgQlAgaW4gbXkgY29weSBvZgp0aGUgYXV0b21hZ2ljYWxseSBnZW5lcmF0ZWQgc2FtcGxlIHNoZWV0KSB1c2luZyB0aGUgcmVxdWlzaXRlIG1tMzggZ2ZmCmZpbGUgd2l0aCB0cmFuc2NyaXB0IGFzIHRoZSBmZWF0dXJlIHR5cGUgYW5kIElEIGFzIHRoZSB0YWcuCgpPaCwgdGhhdCByZW1pbmRzIG1lLCBJIG5lZWQgdG8gcmUta2V5IHRoZSBhbm5vdGF0aW9ucyB0byB1c2UgdGhhdCBhbmQKSSBtaWdodCBuZWVkIHRvIGNoZWNrIHRoYXQgdGhlIElEcyBkbyBvciBkbyBub3QgaGF2ZSBhIHByZWZpeCBsaWtlCid0cmFuc2NyaXB0Oicgb3Igd2hhdGV2ZXIuLi4KCmBgYHtyfQptbTM4X2hpc2F0X3R4IDwtIGNyZWF0ZV9zZShzYW1wbGVfc2hlZXQsIGdlbmVfaW5mbyA9IG1tX3R4X2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbiA9ICJ1bWlfZGVkdXBfbXJuYV9jb3VudCIpIHw+CiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vX2xvY19hdGIiKSB8PgogIHNldF9iYXRjaGVzKGZhY3QgPSAidGltZV9hdGIiKSB8PgogIHNldF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImdlbm9fbG9jIl1dKQptbTM4X2hpc2F0X3R4CgojIyBOb3cgdGhhdCB3ZSBjcmVhdGVkIHRoZSBkYXRhIHN0cnVjdHVyZSB3aXRoIElEcyB0aGF0IGluY2x1ZGUgdGhlIHRyYW5zY3JpcHQ6IHByZWZpeCwKIyMgcmVtb3ZlIGl0Li4uCm5ld19pZHMgPC0gZ3N1Yih4ID0gcm93bmFtZXMoYXNzYXkobW0zOF9oaXNhdF90eCkpLCBwYXR0ZXJuID0gIl50cmFuc2NyaXB0OiIsIHJlcGxhY2VtZW50ID0gIiIpCnJvd25hbWVzKG1tMzhfaGlzYXRfdHgpIDwtIG5ld19pZHMKcm93bmFtZXMobW1fdHhfYW5ub3QpIDwtIGdzdWIoeCA9IHJvd25hbWVzKG1tX3R4X2Fubm90KSwgcGF0dGVybiA9ICJedHJhbnNjcmlwdDoiLCByZXBsYWNlbWVudCA9ICIiKQphbGxfZmFjdCA8LSBwYXN0ZTAoY29sRGF0YShtbTM4X2hpc2F0X3R4KVtbInRpbWVfYXRiIl1dLCAiXyIsCiAgICAgICAgICAgICAgICAgICBjb2xEYXRhKG1tMzhfaGlzYXRfdHgpW1siZ2Vub19sb2NfYXRiIl1dKQpjb2xEYXRhKG1tMzhfaGlzYXRfdHgpW1sidGltZV9nZW5vX2xvYyJdXSA8LSBhbGxfZmFjdApkaW0oYXNzYXkobW0zOF9oaXNhdF90eCkpCmhlYWQoYXNzYXkobW0zOF9oaXNhdF90eCkpCmhlYWQocm93RGF0YShtbTM4X2hpc2F0X3R4KSkKYGBgCgojIE5vbi16ZXJvIENvdW50cyBwZXIgU2FtcGxlCgpBIG5lYXQgbGl0dGxlIGNoYW5nZSBJIGp1c3QgbWFkZTogd2hlbiBudWxsIHNldCB0aGUgeS1pbnRlcmNlcHQgdG8gdGhlCm1lYW4gcGVyY2VudGFnZSBvZiB1bml0cyBvYnNlcnZlZCAodHJhbnNjcmlwdHMgaW4gdGhpcyBjYXNlKS4KCmBgYHtyfQp0eF9ub256ZXJvICA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF90eCkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L25vbnplcm9fdHhfdW5maWx0ZXJlZC5wZGYiLCBpbWFnZSA9IHR4X25vbnplcm9bWyJwbG90Il1dKQoKdHhfbGlic2l6ZSA8LSBwbG90X2xpYnNpemUobW0zOF9oaXNhdF90eCkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L3F1YW50c2l6ZV91bmZpbHRlcmVkLnBkZiIsIGltYWdlID0gdHhfbGlic2l6ZVtbInBsb3QiXV0pCmBgYAoKIyMgRXhjbHVkZSBwNjAKCmBgYHtyfQptbTM4X2hpc2F0X3R4IDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3R4LCBzdWJzZXQgPSAidGltZV9hdGIhPSdwNjAnIikKYGBgCgojIyBSZXBsb3QgdGhlIG5vbnplcm8gZ2VuZSBwbG90cwoKYGBge3J9CnR4X25vbnplcm9fZmlsdCA8LSBwbG90X25vbnplcm8obW0zOF9oaXNhdF90eCwgcGxvdF9sYWJlbHMgPSBGQUxTRSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L25vbnplcm9fdHhfZmlsdC5wZGYiLCBpbWFnZSA9IHR4X25vbnplcm9fZmlsdFtbInBsb3QiXV0pCmBgYAoKIyBRdWljayBQQ0EsIHRoZW4gcmV0dXJuIHRvIFRoZXJlc2EncyBkb2N1bWVudAoKYGBge3J9CnR4X25vcm0gPC0gbm9ybWFsaXplKG1tMzhfaGlzYXRfdHgsIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICBub3JtID0gInF1YW50IiwgZmlsdGVyID0gVFJVRSkKdHhfbm9ybV9wY2EgPC0gcGxvdF9wY2EodHhfbm9ybSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L3R4X25vcm1fcGNhLnBkZiIsIGltYWdlID0gdHhfbm9ybV9wY2FbWyJwbG90Il1dKQpgYGAKCmBgYHtyfQp0eF9sb2NfZ2VubyA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3R4LCBmYWN0ID0gImxvY2F0aW9uX2F0YiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX2Nob2ljZXNbWyJsb2NhdGlvbiJdXSkgfD4KICBzZXRfYmF0Y2hlcyhmYWN0ID0gImdlbm90eXBlX2F0YiIpCmBgYAoKIyMgVGhlIGFzc29jaWF0ZWQgUENBCgpBdCBkaWZmZXJlbnQgdGltZXMsIGl0IGFwcGVhcnMgdG8gbWUgdGhhdCBUaGVyZXNhIGhhcyBwcmVmZXJyZWQKc2xpZ2h0bHkgZGlmZmVyZW50IG5vcm1hbGl6YXRpb24gbWV0aG9kcywgcHJpbWFyaWx5IGEgbWl4IG9mIFRNTSBhbmQKcXVhbnRpbGUuCgpUaHVzIEkgd2lsbCB1c2UgZGlmZmVyZW50IHN1ZmZpeCBsZXR0ZXJzIHRvIGRlbm90ZSB2YXJpb3VzCm5vcm1hbGl6YXRpb25zIGVtcGxveWVkLCBhbmQgaWYgdGhleSB0dXJuIG91dCB0aGUgc2FtZSBJIHdpbGwgcGljayBvbmUgYXJiaXRyYXJpbHkuCgpgYGB7cn0KbG9jX2dlbm9fbnEgPC0gbm9ybWFsaXplKHR4X2xvY19nZW5vLCB0cmFuc2Zvcm0gPSAibG9nMiIsIGNvbnZlcnQgPSAiY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiKQpsb2NhdGlvbl9nZW5vdHlwZV9wY2EgPC0gcGxvdF9wY2EobG9jX2dlbm9fbnEpCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlc190eC9sb2NhdGlvbl9nZW5vdHlwZV9ub3JtX3BjYS5wZGYiLAogICBpbWFnZSA9IGxvY2F0aW9uX2dlbm90eXBlX3BjYVtbInBsb3QiXV0pCgpsb2NfZ2Vub19udCA8LSBub3JtYWxpemUodHhfbG9jX2dlbm8sIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJ0bW0iKQpsb2NhdGlvbl9nZW5vdHlwZV90bW1fcGNhIDwtIHBsb3RfcGNhKGxvY19nZW5vX250KQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXNfdHgvbG9jYXRpb25fZ2Vub3R5cGVfdG1tX3BjYS5wZGYiLCBpbWFnZSA9IGxvY2F0aW9uX2dlbm90eXBlX3RtbV9wY2FbWyJwbG90Il1dKQpgYGAKCmBgYHtyfQpzYW1wbGVfc2Fua2V5IDwtIHBsb3RfbWV0YV9zYW5rZXkodHhfbG9jX2dlbm8sIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9ycyA9IGMoImdlbm90eXBlX2F0YiIsICJsb2NhdGlvbl9hdGIiLCAidGltZV9hdGIiKSkKcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L2Rlc2lnbl9zYW5rZXkucGRmIiwgaW1hZ2UgPSBzYW1wbGVfc2Fua2V5W1sicGxvdCJdXSkKYGBgCgpSZS1wdXJwb3NlIHRoZXNlIGV4cHJlc3Npb24gcGxvdHMgdG8gZXhhbWluZSBvbmUgT3BuNCB0cmFuc2NyaXB0LgpUaGlzIHdpbGwgYnkgc29tZSBuZWNlc3NpdHkgYmUgYXJiaXRyYXJ5LgoKSXQgaXMgYXQgdGhpcyBtb21lbnQgdGhhdCBJIHJlYWxpemVkIChhcyBJIGFtIGFsbW9zdCBjZXJ0YWluIEkgdG9sZApteXNlbGYgd2hlbiBJIHN0YXJ0ZWQpIHVzaW5nIHRoZSBoaXNhdC1kZXJpdmVkIHR4IGNvdW50cyBpcyB3cm9uZwpiZWNhdXNlIGhpc2F0LT5mZWF0dXJlQ291bnRzIGhhcyBubyBnb29kIHdheSB0byBhbGxvY2F0ZSBtdWx0aS1oaXRzIHRvCm11bHRpcGxlIHRyYW5zY3JpcHRzIGFuZCB3aWxsIHRoZXJlZm9yZSBkaXNjb3VudCB0aGVtLiAgSWYgSSB3YW50IHRvCmRvIHRoaXMgaW4gYW55IHNvcnQgb2YgcmVsaWFibGUgd2F5LCBJIHJlYWxseSBuZWVkIHRvIHJlLWV4dHJhY3QgdGhlCmRlZHVwbGljYXRlIHJlYWRzIGZyb20gdGhlIHVtaXRvb2xzIGJhbSBmaWxlIGFuZCBydW4gc2FsbW9uL2thbGxpc3RvLgpUaGlzIGlzIHNvbWV3aGF0IGFubm95aW5nIGJlY2F1c2UgdGhlIHZhcmlvdXMgdG9vbHMgSSBoYXZlIGZvciBleHRyYWN0CmJhbSByZWFkcyByZWFsbHkgaGF0ZSB0aGUgd2F5IHVtaXRvb2xzIGZvcm1hdHMgdGhlIGJhbSBmaWxlIGFuZCBmcmVhawpvdXQuICBJIGNhbiBmb3JjZSBpdCwgYnV0IEkgdGhpbmsgSSB3aWxsIGxvc2UgYSBwb3RlbnRpYWxseQpzaWduaWZpY2FudCBudW1iZXIgb2YgcmVhZHMsIGxldCB1cyBnbyBsb29rLi4uCgooSWYgeW91IHdpdGggdG8gZm9sbG93IGFsb25nLCBnbyBiYWNrIHRvIHRoZSBwcmVwcm9jZXNzaW5nIGRvY3VtZW50CndoaWNoIEkgc2hvdWxkIGhhdmUgaW5jbHVkZWQgaW4gdGhlIHNpbmd1bGFyaXR5IGNvbnRhaW5lcikgIEkgd2lsbCBkbwpvbmUgb2YgdGhlIGZvbGxvd2luZzoKCjEuICBVc2UgZ2F0ayBvciBiYW10b29scyB0byBjcmVhdGUgZGVkdXBsaWNhdGVkIGZhc3RxIGZpbGVzIGFuZCB1c2UKICAgIHRoZW0gd2l0aCBzYWxtb24uCjIuICBVc2Ugc2FsbW9uIHdpdGggdGhlIGRlZHVwbGljYXRlZCBiYW0gZmlsZXMgZnJvbSBoaXNhdC4KCkkgYW0gbm90IHN1cmUgcmlnaHQgbm93IHdoaWNoIEkgd2FudCB0byBkby4gIEkga2luZCBvZiBsaWtlIHRoZSBpZGVhCm9mIGhhdmluZyBkZWR1cGxpY2F0ZWQgZmFzdHEgZmlsZXMgc28gdGhhdCBJIGNhbiB0cnkgc29tZSBvdGhlciBzdHVmZgp3aXRoIHRoZW0gKGtyYWtlbiwgZm9yIGV4YW1wbGUpCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyMgZ2dzdGF0c3Bsb3QgaGFzIGFwcGVhcmVkIGFuZCBkaXNhcHBlYXJlZCBhIGZldyB0aW1lcyBmcm9tIGNyYW4gcmVjZW50bHksCiMjIEkgYW0gbm90IHN1cmUgaWYgaXQgd2lsbCB3b3JrIHRoZXJlZm9yZSwgc28gZmlndXJlZCBJIHNob3VsZCBkaXNhYmxlIHRoaXMgYmxvY2sKIyMgZm9yIHRoZSBtb21lbnQuCgojIyBJIGRpZCBhIHNlYXJjaCBhdCBlbnNlbWJsIGZvciB0aGUgdmFyaW91cyBvcG40IHRyYW5zY3JpcHQgSURzOgojIyBFTlNNVVNUMDAwMDAwMjIzMzEsIEVOU01VU1QwMDAwMDE2ODQ0NCwgRU5TTVVTVDAwMDAwMjI2ODA2CmlkcyA8LSBjKCJFTlNNVVNUMDAwMDAwMjIzMzEiLCAiRU5TTVVTVDAwMDAwMTY4NDQ0IiwgIkVOU01VU1QwMDAwMDIyNjgwNiIpCmlkcyAlaW4lIHJvd25hbWVzKGxvY19nZW5vX250KQppZHMgPC0gYygiRU5TTVVTVDAwMDAwMDIyMzMxIiwgIkVOU01VU1QwMDAwMDE2ODQ0NCIpCgpvcG40X2V4cHJzIDwtIGRhdGEuZnJhbWUoY29tYmluZWQgPSBjb2xEYXRhKGxvY19nZW5vX250KVtbImdlbm9fbG9jX2F0YiJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gY29sRGF0YShsb2NfZ2Vub19udClbWyJsb2NhdGlvbl9hdGIiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW5vdHlwZSA9IGNvbERhdGEobG9jX2dlbm9fbnQpW1siZ2Vub3R5cGVfYXRiIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgb3BuNCA9IGFzc2F5KHR4X2xvY19nZW5vKVtpZHNbMV0sIF0pCgpncm91cGVkc3RhdHM6Omdyb3VwZWRfc3VtbWFyeShvcG40X2V4cHJzLCBsb2NhdGlvbiwgb3BuKQpvcG40X2xvY2F0aW9uIDwtIGdnc3RhdHNwbG90OjpnZ2JldHdlZW5zdGF0cyhkYXRhID0gb3BuNF9leHBycywgeCA9IGxvY2F0aW9uLCB5ID0gb3BuKQpwcChmaWxlID0gImltYWdlc190eC9nZ2JldHdlZW5fbG9jYXRpb24ucGRmIikKb3BuNF9sb2NhdGlvbgpwbG90dGVkIDwtIGRldi5vZmYoKQpvcG40X2xvY2F0aW9uCmBgYAoKIyBUd28gbm90ZXdvcnRoeSBnZW5lcyB3aXRoIHBvdGVudGlhbGx5IGRpZmZlcmVudCB0cmFuc2NyaXB0IGFidW5kYW5jZXMKCk9uZSByZXZpZXdlciBzdWdnZXN0ZWQgY2hlY2tpbmcgb3V0IHRoZSB0cmFuc2NyaXB0LWxldmVsIGFidW5kYW5jZXMgYW5kIG5vdGVkIHR3bwpnZW5lcyBpbiBwYXJ0aWN1bGFyIGFzIHBvdGVudGlhbGx5IGludGVyZXN0aW5nOiBObGduMyBhbmQgTmNhbTEuICBMZXQgdXMgdGFrZSBhCm1vbWVudCBhbmQgc2VlIHdoYXQgdGhleSBsb29rIGxpa2UgYWNyb3NzIHRoZSB2YXJpb3VzIG1ldGFkYXRhIGZhY3RvcnMgb2YgaW50ZXJlc3QuCgojIyBHcmFiIHRoZSB0eCBhbm5vdGF0aW9ucyBmb3IgdGhlbQoKYGBge3IsIGV2YWw9RkFMU0V9Cm5sZ24zX2lkeCA8LSBncmVwbCh4ID0gcm93RGF0YShtbTM4X2hpc2F0X3R4KVtbImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSJdXSwgcGF0dGVybiA9ICJeTmxnbjNcXC0iKQpzdW0obmxnbjNfaWR4KQpubGduM19hbm5vdCA8LSByb3dEYXRhKG1tMzhfaGlzYXRfdHgpW25sZ24zX2lkeCwgXQpubGduM19pZHMgPC0gcm93bmFtZXMocm93RGF0YShtbTM4X2hpc2F0X3R4KSlbbmxnbjNfaWR4XQphc3NheShtbTM4X2hpc2F0X3R4KVtubGduM19pZHMsIF0KIyMgTG9va3MgbGlrZQoKbmNhbTFfaWR4IDwtIGdyZXBsKHggPSByb3dEYXRhKG1tMzhfaGlzYXRfdHgpW1siZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIl1dLCBwYXR0ZXJuID0gIl5OY2FtMVxcLSIpCnN1bShuY2FtMV9pZHgpCnJvd0RhdGEocm93RGF0YShtbTM4X2hpc2F0X3R4KSlbbmNhbTFfaWR4LCBdCm5jYW0xX2Fubm90IDwtIGFzLmRhdGEuZnJhbWUocm93RGF0YShtbTM4X2hpc2F0X3R4KSlbbmNhbTFfaWR4LCBdCm5jYW0xX2lkcyA8LSByb3duYW1lcyhyb3dEYXRhKG1tMzhfaGlzYXRfdHgpKVtuY2FtMV9pZHhdCmFzc2F5KG1tMzhfaGlzYXRfdHgpW25jYW0xX2lkcywgXQpgYGAKCm9rLCBzbyBJIHBsb3R0ZWQgdGhlIHF1ZXN0aW9uIGEgYml0IGRpZmZlcmVudGx5LCBidXQgZ290IHRoZSBzYW1lCmFuc3dlci4KCkhlcmUgaXMgdGhlIHRleHQgb2YgVGhlcmVzYSdzIG5vdGVib29rIGZvbGxvd2luZyB0aGlzIGFuYWx5c2lzOgoKIlVnaCBvaCwgbG9va3MgbGlrZSB0aGVyZSBpcyBhdCBsZWFzdCBvbmUgcmV0aW5hIEtPIHNhbXBsZSB0aGF0IGhhcwpzb21lIG1lbGFub3BzaW4gZXhwcmVzc2lvbiBpbiBpdC4gVHVybnMgb3V0IGlwUkdDXzA3IGlzIGEgYmFkIGVnZwp3aGljaCBpcyBzdXBwb3NlZCB0byBiZSBhIEtPIGJ1dCBoYXMgbWVsYW5vcHNpbiBleHByZXNzaW9uLiBJdOKAmXMKZnJpZW5kcyB3aGljaCB3ZXJlIHBvb2xlZCBmcm9tIHRoZSBzYW1lIG1pY2UgYXJlIGlwcmdjXzA2IGFuZAppcHJnY18wOCwgc28gd2UgbmVlZCB0byBleGNsdWRlIGFsbCB0aGVzZSBzYW1wbGVzLiIKCkkgYW0gYWxzbyBzZWVpbmcgc29tZSBrbm9ja291dCBleHByZXNzaW9uIHdpdGggc29tZSBjYXZlYXRzOiBJIGRvIG5vdApoYXZlIHRoZSBhZmZlY3RlZCBzYW1wbGVzIGluIG15IGRhdGFzZXQgKGlwcmdjXzA3KSBhbmQgdGhlIGxldmVscyBJIGFtCnNlZWluZyBhcmUgcXVpdGUgbG93IC0tIEkgd2lsbCBsb29rIGluIElHViB0byBkb3VibGUgY2hlY2ssIGJ1dCBJCnN0cm9uZ2x5IHN1c3BlY3QgdGhhdCB0aGVzZSBhcmUgc29tZSBwaWRkbHkgcmVhZHMgbmVhciB0aGUgVVRScy4KCk9ud2FyZCEKCiMgUENBIHBsb3RzCgojIyBQQ0Egb2YgYWxsIGdlbmVzIGJ5IGxvY2F0aW9uCgpUaGVyZXNhJ3MgZmlyc3QgcGNhIHdhcyBvZiBsb2cyIGNwbSB2YWx1ZXMuICBJIG1pZ2h0IGFkZCBxdWFudGlsZS90bW0KdG8gdGhpcz8KCmBgYHtyfQp0eF9sb2NhdGlvbiA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3R4LCBmYWN0ID0gImxvY2F0aW9uX2F0YiIpIHw+CiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJnZW5vdHlwZV9hdGIiKSB8PgogIHNldF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKQp0eF9sb2NhdGlvbl9ub3JtIDwtIG5vcm1hbGl6ZSh0eF9sb2NhdGlvbiwgZmlsdGVyID0gVFJVRSwgbm9ybSA9ICJxdWFudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gImxvZzIiLCBjb252ZXJ0ID0gImNwbSIpCnR4X2xvY2F0aW9uX3BjYSA8LSBwbG90X3BjYSh0eF9sb2NhdGlvbl9ub3JtKQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXNfdHgvdHhfbG9jYXRpb25fbm9ybV9wY2EucGRmIikKdHhfbG9jYXRpb25fcGNhCmRldi5vZmYoKQp0eF9sb2NhdGlvbl9wY2EKYGBgCgpPbmNlIGFnYWluIHdlIHNlZSB0aGF0IHNhbXBsZXMgaXByZ2NfNjYgYW5kIGlwcmdjXzEzMCBhcmUgbGlrZWx5CmFjdHVhbGx5IERMR04gYW5kIG5vdCBTQ04uICBJIGFtIHRoZXJlZm9yZSBnb2luZyB0byBhZGQgYSBjb2x1bW4gdG8KdGhlIHNhbXBsZSBzaGVldCBub3RpbmcgdGhpcywgYW5kIHJlbW92ZSB0aGVtIGZyb20gdGhlIGV4cHJlc3Npb25zZXQuCgpJIHdpbGwgdGh1cyByZXBsb3QgdGhlIGRhdGEgYWZ0ZXIgcmVtb3ZpbmcgdGhvc2UgdHdvLiAgSWYgd2Ugd2FudCB0bwpzZWUgd2hhdCBpdCBsb29rcyBsaWtlIHdpdGggdGhlIHJlLWF0dHJpYnV0ZWQgbG9jYXRpb25zLCB3ZSBjYW4gZG8gc28uCgpUaGVyZXNhIGhhcyBhIG5pY2UgY2hhbmdlIHRvIHRoZSBQQ0EgcGxvdHRlciBpbiB3aGljaCBzaGUgc2V0cyB0aGUKYWxwaGEgY2hhbm5lbCBhcyBhbiBhZGRpdGlvbmFsIHZpc3VhbCBxdWV1ZSBmb3IgYSBtZXRhZGF0YSBmYWN0b3IuLi4KCmBgYHtyfQptbTM4X2hpc2F0X3R4IDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3R4LCBzdWJzZXQ9InNhbXBsZWlkIT0naXByZ2NfMTMwJyIpIHw+CiAgc3Vic2V0X3NlKHN1YnNldD0ic2FtcGxlaWQhPSdpcHJnY182NiciKQp0eF9sb2NhdGlvbiA8LSBzZXRfY29uZGl0aW9ucyhtbTM4X2hpc2F0X3R4LCBmYWN0ID0gImxvY2F0aW9uX2F0YiIpIHw+CiAgc2V0X2JhdGNoZXMoZmFjdCA9ICJnZW5vdHlwZV9hdGIiKSB8PgogIHNldF9jb2xvcnMoY29sb3JfY2hvaWNlc1tbImxvY2F0aW9uIl1dKQoKdHhfbG9jYXRpb25fbm9ybSA8LSBub3JtYWxpemUodHhfbG9jYXRpb24sIGZpbHRlciA9IFRSVUUsIG5vcm0gPSAicXVhbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybSA9ICJsb2cyIiwgY29udmVydCA9ICJjcG0iKQpmaWx0ZXJlZF9sb2NhdGlvbl9wY2EgPC0gcGxvdF9wY2EodHhfbG9jYXRpb25fbm9ybSkKcHAoZmlsZSA9ICIwMmZpbHRlcmVkX2ltYWdlc190eC9maWx0ZXJlZF9sb2NhdGlvbl9wY2EucGRmIikKZmlsdGVyZWRfbG9jYXRpb25fcGNhW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpmaWx0ZXJlZF9sb2NhdGlvbl9wY2EKCnJlbW92ZWRfc2Fua2V5IDwtIHBsb3RfbWV0YV9zYW5rZXkodHhfbG9jYXRpb24sIGNvbG9yX2Nob2ljZXMgPSBjb2xvcl9jaG9pY2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3RvcnMgPSBjKCJnZW5vdHlwZV9hdGIiLCAibG9jYXRpb25fYXRiIiwgInRpbWVfYXRiIikpCnBwKGZpbGUgPSAiMDJmaWx0ZXJlZF9pbWFnZXNfdHgvZmlsdGVyZWRfc2Fua2V5LnBkZiIsIGltYWdlID0gcmVtb3ZlZF9zYW5rZXlbWyJwbG90Il1dKQpgYGAKCkhlcmUgaXMgVGhlcmVzYSdzIHRleHQsIHJlY2FsbCBvbmNlIGFnYWluIHRoYXQgSSBkbyBub3QgaGF2ZSBzb21lIG9mCnRoZXNlIG9sZGVyIHNhbXBsZXMgKGlwcmdjXzYyKToKClBDMSB2cyBQQzIgaWRlbnRpZmllcyByZXRpbmEgdnMgYXhvbiBpcyBzdGlsbCB0aGUgbWFpbiBjb21wb25lbnQgb2YKdmFyaWF0aW9uLiBXZSBkbyBzZWUgdGhvdWdoIHRoYXQgaW4gdGhlIFBDMiBkaXJlY3Rpb24sIHdlIHNlZSB3aXRoIHRoZQpuZXcgc2FtcGxlcyBhZGRlZCwgd2UgZG9u4oCZdCBzZWUgc2VwYXJhdGlvbiBiYXNlZCBvbiBheG9uYWwgdGFyZ2V0cwooZExHTiB2cyBTQ04pLiBJbiB0aGUgUEMxIHZzIFBDMyBwbG90LCB3ZSBzZWUgdGhhdCBpdOKAmXMgUEMzIHdoZXJlIHdlCnN0YXJ0IHRvIHNlZSB2YXJpYXRpb24gY29ycmVsYXRlZCB3aXRoIGF4b25hbCBjb21wYXJ0bWVudC4gTGV04oCZcyBsb29rCmF0IFBDMSB2cyBQQzIgY29sb3JlZCBieSBiYXRjaCAod2hlbiB0aGV5IHdlcmUgcHJvY2Vzc2VkL3NlcXVlbmNlZCkgdG8Kc2VlIGlmIHRoYXQgaXMgd2hhdCBpcyBjb250cmlidXRpbmcgc28gbXVjaCB2YXJpYXRpb24gaW4gUEMyLgoKU2lkZSBub3RlOiBpcFJHQyA2MiBzZWVtcyBsaWtlIGFuIG9kZCBiYWxsLiBUaGlzIHNlZW1zIHRvIG1lIGxpa2UgaXQKc2hvdWxkIGhhdmUgYmVlbiBhIGRMR04gUDA4IHNhbXBsZS4gSXMgdGhlcmUgYW55IHBvc3NpYmlsaXR5IHRoaXMgZ290Cm1pc2xhYmVsZWQgZWFybHkgb24/IEkgd2VudCBiYWNrIGFuZCBkb3VibGUgY2hlY2tlZCB0byBzZWUgaWYgYWxsIG15CnByb2Nlc3NpbmcgaXMgY29ycmVjdCBhbmQgaXQgaW5kZWVkIHdhcyBsYWJlbGVkIGFuIFNDTiBQMTUgZnJvbSB0aGUKdGltZSBJIGdvdCB0aGUgc2FtcGxlcywgYW5kIGl0IGlzIGluZGVlZC4KCiMgREUKCkkgbm93IHN3aXRjaGVkIHRvIFRoZXJlc2EncyBkb2N1bWVudCAnV09SS0lOR19heG9uVFJBUC4uLicgYW5kIHdpbGwKc3RhcnQgcHVsbGluZyBzZWN0aW9ucyBmcm9tIGl0LiAgSSBhbSByZWFzb25hYmx5IGNlcnRhaW4gSSBoYXZlCnJlYXNvbmFibHkgc2ltaWxhciBzYW1wbGUgZGlzdHJpYnV0aW9ucywgc28gSSBwcmVzdW1lIEkgY2FuIGludm9rZQpzaW1pbGFyL2lkZW50aWNhbCBjYWxscyBmb3IgREVTZXEgYW5kIGZyaWVuZHMuCgojIyBwOCByZXRpbmFzCgpJbiB0aGUgYmxvY2sgaW1tZWRpYXRlbHkgYmVmb3JlIHRoZSBERSBhbmFseXNlcywgVGhlcmVzYSBjcmVhdGVkIGEKc3Vic2V0IGV4cHJlc3Npb25zZXQgb2Ygb25seSBwMDggcmV0aW5hcy4gIFRodXMgdGhpcyBpbml0aWFsIERFIEkKYXNzdW1lIHdpbGwgYmUgdXNlZCB0byBzdWJ0cmFjdCBmb3IgdGhlIFNDTi9ETEdOIGFuYWx5c2VzIHRoYXQgZm9sbG93LgooSSBndWVzcyBJIGNvdWxkIHJlYWQgYWhlYWQgYW5kIGZpbmQgb3V0LCBidXQgbm8hIEkgd2FudCB0byBiZSBhCmJsYW5rIHNsYXRlKQoKVGhlcmVzYSdzIHByaW1hcnkgd29ya2Zsb3cgbWFrZXMgaGVhdnkgdXNlIG9mIERFU2VxMgooQGxvdmVNb2RlcmF0ZWRFc3RpbWF0aW9uRm9sZDIwMTQpIGFuZCBzdmEKKEBsZWVrU1ZBUGFja2FnZVJlbW92aW5nMjAxMikuICBJbiBzb21lKG1vc3Q/KSBvZiBUaGVyZXNhJ3MKaW52b2NhdGlvbnMgb2YgdGhlIGFsbF9wYWlyd2lzZSgpIGZ1bmN0aW9uLCBzaGUgZXhjbHVkZXMgdGhlIG90aGVyCm1ldGhvZHMgdGhhdCBpdCBwZXJmb3Jtcy4gIEluIHRoaXMgd29ya2Jvb2ssIEkgbGVmdCB0aG9zZSBtZXRob2RzIG9uLAp0aHVzIHdlIGNhbiBldmFsdWF0ZSB0aGUgcmVsYXRpdmUgcGVyZm9ybWFuY2UgREVTZXEyIHZzLiBzb21lIChhbGw/IEkKbWF5IGhhdmUgZGlzYWJsZWQgRUJTZXEvZHJlYW0gYmVjYXVzZSB0aGV5IHdlcmUgdGFraW5nIHRvbyBsb25nKQpvZiB0aGUgZm9sbG93aW5nOgoKKiBsaW1tYTogKEByaXRjaGllTGltbWFQb3dlcnNEaWZmZXJlbnRpYWwyMDE1KSAoYW1vbmcgb3RoZXIKICByZWZlcmVuY2VzKSBvcmlnaW5hbGx5IHdyaXR0ZW4gZm9yIG1pY3JvYXJyYXlzLgoqIEVkZ2VSOiAoQHJvYmluc29uRWRnZVJCaW9jb25kdWN0b3JQYWNrYWdlMjAxMCksIHdoaWNoIHNoYXJlcyBtYW55CiAgYXNzdW1wdGlvbnMgd2l0aCBERVNlcTIuCiogRUJTZXE6IChAbGVuZ0VCU2VxRW1waXJpY2FsQmF5ZXMyMDEzKSwgYmVjYXVzZSBJIGhhdmUgYSBzb2Z0IHNwb3QKICBmb3IgYW55IEJheWVzaWFuIG1ldGhvZC4KKiBOb2lzZXE6IChAdGFyYXpvbmFOT0lzZXFSTkFzZXFEaWZmZXJlbnRpYWwyMDExKSwgd2hpY2ggc2Vla3MgdG8KICBkaXJlY3RseSBtb2RlbCB2YXJpYW5jZSBpbiBhbiBSTkFTZXEgZGF0YXNldCBhbmQgdXNlIHRoYXQgdG8gaW1wcm92ZQogIHRoZSBzZW5zaXRpdml0eSBvZiB0aGUgcmVzdWx0LCBtdWNoIGxpa2U6CiogRHJlYW06IChAaG9mZm1hbkRyZWFtUG93ZXJmdWxEaWZmZXJlbnRpYWwyMDIwKSwgd3JpdHRlbiBieSB0aGUgc2FtZQogIGF1dGhvcnMgKGFuZCB1c2VzIHZlcnkgc2ltaWxhciBsb2dpYykgYXMgb25lIG9mIG15IGZhdm9yaXRlIHRvb2xzLAogIHZhcmlhbmNlUGFydGl0aW9uKEBob2ZmbWFuVmFyaWFuY2VQYXJ0aXRpb25JbnRlcnByZXRpbmdEcml2ZXJzMjAxNikuCgpgYGB7cn0KbW0zOF9wOF9yZXRpbmEgPC0gc3Vic2V0X3NlKG1tMzhfaGlzYXRfdHgsIHN1YnNldCA9ICJ0aW1lX2F0Yj09J3AwOCcgJiBsb2NhdGlvbl9hdGI9PSdyZXRpbmEnIikKbW1fbm9ybWFsX3A4X3JldF9kZSA8LSBhbGxfcGFpcndpc2UobW0zOF9wOF9yZXRpbmEsIG1vZGVsX3N2cyA9ICJzdmFzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsIGZpbHRlciA9IFRSVUUpCm1tX25vcm1hbF9wOF9yZXRfZGUKYGBgCgpUaGVyZSBzZWVtcyB0byBiZSBhIGRpc2NyZXBlbmN5IHdpdGggcHJldmlvdXMgaXRlcmF0aW9ucyBvZiB0aGlzLgpMZXQgdXMgc2ltcGxpZnkgdG8ganVzdCBkb2luZyBkZXNlcSBhbmQgZmluZCB3aGF0IGlzIGNhdXNpbmcgaXQuCkluIG15IHByZXZpb3VzIGl0ZXJhdGlvbiwgSSBnb3QgMzYzMiBnZW5lcyBpbiB0aGUgdW5pcXVlKGMoKSkgb3IgaGV0K2tvLgoKYGBge3J9CmRlc2VxX29ubHkgPC0gZGVzZXFfcGFpcndpc2UobW0zOF9wOF9yZXRpbmEsIG1vZGVsX3N2cyA9ICJzdmFzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSBkZWZhdWx0X2ZzdHJpbmcsIGZpbHRlciA9IFRSVUUpCmRlc2VxX2hldGtlZXBlcl90eCA8LSBkZXNlcV9vbmx5JGFsbF90YWJsZXMkd3RfcmV0aW5hX3ZzX2hldF9yZXRpbmEgfD4KICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKZGVzZXFfa29rZWVwZXJfdHggPC0gZGVzZXFfb25seSRhbGxfdGFibGVzJHd0X3JldGluYV92c19rb19yZXRpbmEgfD4KICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKZGVzZXFfa2VlcGVydHggPC0gdW5pcXVlKGMocm93bmFtZXMoZGVzZXFfaGV0a2VlcGVyX3R4KSwKICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoZGVzZXFfa29rZWVwZXJfdHgpKSkKbGVuZ3RoKGRlc2VxX2tlZXBlcnR4KQoKZGVzZXFfcGFpcl9oZXRrZWVwZXJfdHggPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0X3JldGluYV92c19oZXRfcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCmRlc2VxX3BhaXJfa29rZWVwZXJfdHggPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0X3JldGluYV92c19rb19yZXRpbmEgfD4KICBmaWx0ZXIobG9nRkMgPD0gLTAuMjUgJiBhZGouUC5WYWwgPD0gMC4wNSkKZGVzZXFfcGFpcl9rZWVwZXJ0eCA8LSB1bmlxdWUoYyhyb3duYW1lcyhkZXNlcV9wYWlyX2hldGtlZXBlcl90eCksCiAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKGRlc2VxX3BhaXJfa29rZWVwZXJfdHgpKSkKbGVuZ3RoKGRlc2VxX3BhaXJfa2VlcGVydHgpCmBgYAoKVGhlIGZvbGxvd2luZyBpbnZvY2F0aW9uIHBlcmZvcm1lZCBieSBUaGVyZXNhIGZpbHRlcnMgdGhlIHd0L2hldApjb21wYXJpc29uIGZvciBvbmx5IHRob3NlIGdlbmVzIHdoaWNoIGluY3JlYXNlZCBieSBhdCBsZWFzdCAwLjI1IGxvZ0ZDCndpdGggYSBzaWduaWZpY2FudCBhZGp1c3RlZCBwLXZhbHVlLiAgSSBhc3N1bWUgdGhhdCB0aGlzIGlzIHRvIHVzZSB0aGUKd3Qgc2FtcGxlcyBhcyBhIHRyYW5zbGF0aW9uYWwgY29udHJvbCBmb3IgdGhlIGtldC9rbyBjb21wYXJpc29uczsgSSBhbQp0aGVyZWZvcmUgdGhpbmtpbmcgdGhhdCBmb3IgbXkgcHVycG9zZXMsIEkgd2lsbCB0aGVyZWZvcmUgc2VwYXJhdGUgdGhlCmNvbnRyYXN0cyBmcm9tIGFsbF9wYWlyd2lzZSBkbyB0aGlzIGluIGEgc3RlcHdpc2UgZmFzaGlvbi4uLgoKVGhlIGJsb2NrIG9mIGNvZGUgaW1tZWRpYXRlbHkgZm9sbG93aW5nIFRoZXJlc2EncyBhbGxfcGFpcndpc2UoKQppbnZvY2F0aW9uIGlzIGEgbGl0dGxlIGNvbmZ1c2luZyBmb3IgbWUgYW5kIHdhcnJhbnRzIHNvbWUgZXhwbGFuYXRpb24KYnkgbWUgdG8gbWUgaW4gdGhlIGhvcGVzIHRoYXQgSSBkbyBub3QgbWlzdW5kZXJzdGFuZCB3aGF0IGlzIGhhcHBlbmluZwphbmQgdGhlIGdvYWxzIHRoZXJlaW4uCgpJIHRoaW5rIEkgY2FuIHNhZmVseSBhc3N1bWUgdGhhdCB0aGUgZ29hbCBoZXJlIGlzIHRvIHB1bGwgb3V0IHRoZSBJRHMKd2hpY2ggaW5jcmVhc2VkIGluIGhldCB3aXRoIHJlc3BlY3QgdG8gd2lsZCB0eXBlOyBldmVuIGlmIGJ5IGEgc21hbGwKbWFyZ2luLCBhcyBsb25nIGFzIGl0IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgdmlzIGEgdmlzIHRoZQphZGp1c3RlZCBwLXZhbHVlLgoKSSBhbSBnb2luZyB0byBwZXJmb3JtIHdoYXQgSSB0aGluayBpcyB0aGUgc2FtZSB0aGluZyBpbiBhIHNsaWdodGx5CmRpZmZlcmVudCBmYXNoaW9uIHNvIHRoYXQgSSBjYW4gc2hhcmUgYSBjb3B5IG9mIHRoZSByZXN1bHRzIHdpdGgKd2hvbWV2ZXIgaXMgaW50ZXJlc3RlZC4gIEkgd2lsbCBhbHNvIHJlcGVhdCBUaGVyZXNhJ3MgaW52b2NhdGlvbiBhbmQKcHJvdmUgdG8gbXlzZWxmIHRoYXQgSSB1bmRlcnN0b29kIGFuZCBnb3QgdGhlIHNhbWUgYW5zd2VyLgoKYGBge3J9Cnd0X2hldF9rZWVwZXIgPC0gbGlzdCgiaGV0X3ZzX3d0IiA9IGMoImhldF9yZXRpbmEiLCAid3RfcmV0aW5hIikpCmhldF93dF90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gd3RfaGV0X2tlZXBlciwgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gIjAzdGhlcmVzYV9jb21wYXJpc29uX2V4Y2VsX3R4L2hldF9yZXRpbmFfY29udHJvbC54bHN4IikKd2FudGVkX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGhldF93dF90YWJsZSwgbGZjID0gMC4yNSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbF90eC9oZXRfcmV0aW5hX2NvbnRyb2wtc2lnLnhsc3giKQp3YW50ZWRfaGV0X2luY3JlYXNlZCA8LSB3YW50ZWRfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJoZXRfdnNfd3QiXV0KaW5jcmVhc2VkX2hldF9nZW5lcyA8LSByb3duYW1lcyh3YW50ZWRfaGV0X2luY3JlYXNlZCkKYGBgCgpIZXJlIGFyZSBUaGVyZXNhJ3MgbmV4dCBsaW5lczoKCmBgYHtyfQptbV9kZV9ub3JtYWxfcDhfcmV0IDwtIG1tX25vcm1hbF9wOF9yZXRfZGUKaGV0a2VlcGVyX3R4IDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyR3dF9yZXRpbmFfdnNfaGV0X3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4yNSAmIGFkai5QLlZhbCA8PSAwLjA1KQprb2tlZXBlcl90eCA8LSBtbV9kZV9ub3JtYWxfcDhfcmV0JGRlc2VxJGFsbF90YWJsZXMkd3RfcmV0aW5hX3ZzX2tvX3JldGluYSB8PgogIGZpbHRlcihsb2dGQyA8PSAtMC4yNSAmIGFkai5QLlZhbCA8PSAwLjA1KQprZWVwZXJ0eCA8LSB1bmlxdWUoYyhyb3duYW1lcyhoZXRrZWVwZXJfdHgpLAogICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhrb2tlZXBlcl90eCkpKQojIyBXZSBrbm93IGEgcHJpb3JpIHRoYXQgT3BuNCBpcyBFTlNNVVNHMDAwMDAwMjE3OTkKIyMgSSBkbyBub3QgZXhwZWN0IHRvIHNlZSBpdCBpbiB0aGlzIHNldCwgaXQgc2hvdWxkIGJlIGhpZ2hlciBpbiB3dAojIyByZXRpbmEgdnMga28gcmV0aW5hIGJ5IGEgc2lnbmlmaWNhbnQgbWFyZ2luLgojIyAiRU5TTVVTRzAwMDAwMDIxNzk5IiAlaW4lIGtlZXBlcnR4CiMjIE9vb29oaGggYnV0IGl0IF9pc18gaGlnaGVyIGluIGhldCB2cy4gd3QsIGFzIHdlIHNhdyBpbgojIyB0aGUgdmlvbGluIHBsb3QgZWFybGllci4KYGBgCgpJIHRoaW5rIFJhc2htaSBtYWRlIGEgY29tcGVsbGluZyBwb2ludCB3aGljaCBpbGx1c3RyYXRlcyB3aHkgd2UgbGlrZWx5CnNob3VsZCBleHBlY3QgdGhlIGV4cHJlc3Npb24gb2YgT3BuNCB0byBzaWduaWZpY2FudGx5IGhpZ2hlciBpbiB0aGUKaGV0ZXJvenlnb3RlcyB2cyB3aWxkLXR5cGU6CgoxLiAgUmVjYWxsIHRoYXQgdGhlIGFzc2F5IGlzIHVzaW5nIHRoZSBpbW11bm9wdXJpZmljYXRpb24gdG8gZXh0cmFjdAogICAgdGhlIFJOQXMuCjIuICBUaGUgd3Qgc2FtcGxlcyBkbyBub3QgaGF2ZSB0aGUgY3JlIHJlY29tYmluYXNlIGFuZCB0aGVyZWZvcmUgbm8gSEEKICAgIGFuZCB0aGVyZWZvcmUgZXZlcnl0aGluZyB3ZSBvYnNlcnZlIGlzIGR1ZSB0byBub24tc3BlY2lmaWMKICAgIGJpbmRpbmcuCjMuICBUaGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGR1ZSB0byBub24tc3BlY2lmaWMgYmluZGluZyBpcyBkaWZmZXJlbnQKICAgIHRoYW4gaGV0L2tvIChwcmVzdW1hYmx5IGEgbGFyZ2VyIG51bWJlciBvZiByZWxhdGl2ZWx5IHNtYWxsCiAgICB2YWx1ZXMpLCB0aGVyZWZvcmUgdGhlIGRpdmlzb3IgcGVyZm9ybWVkIGluIHRoZSBjcG0gaXMgbGlrZWx5CiAgICByZWxhdGl2bHkgbGFyZ2UgcmVzdWx0aW5nIGluIG5vcm1hbGl6ZWQgdmFsdWVzIGdldHRpbmcgc2hpZnRlZAogICAgZG93biB0byBzb21lIGRlZ3JlZS4KNC4gIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgc2V0IG9mIGdlbmVzIG9ic2VydmVkIGluIGhldC9rbyBhcmUgbW9yZQogICAgbGlrZWx5IHRvIGJlIG9ubHkgdGhlIHNwZWNpZmljIGJpbmRlcnMgYW5kIHRoZXJlZm9yZSBzbWFsbGVyIChJCiAgICBjYW4gdGVzdCB0aGlzKSByZXN1bHRpbmcgaW4gYSBzbWFsbGVyIGRpdmlzb3IgYW5kIHNsaWdodCBzaGlmdGluZwogICAgdXAgaW4gdGhlIGNwbSB2YWx1ZXMuCgpUaGlzIG1ha2VzIG1lIHdvbmRlciBpZiBhbnkgbm9ybWFsaXphdGlvbiBtZXRob2RzIGV4aXN0IHdoaWNoIGRvCnNvbWV0aGluZyBsaWtlIG11bHRpcGx5IHRoZSB2YWx1ZXMgYnkgc29tZSB2YWx1ZSByZWxhdGVkIHRvIHRoZQpwcm9wb3J0aW9uIG9mIG9ic2VydmVkIGdlbmVzOyBhbmQvb3IgaWYgdGhpcyBpcyBhIGdvb2QvYmFkL2luZGlmZmVyZW50CmlkZWEuCgpBbHNvLCBqdXN0IGEgbm90ZSBmb3IgbWUgdG8gcmVtZW1iZXI6IFJQTDIyLCBub3QgUlBTMjIsIGZvciBzb21lCnJlYXNvbiBJIGtlZXAgdGhpbmtpbmcgdGhlIHNtYWxsIHN1YnVuaXQuCgojIyBQcm92ZSBJIHVuZGVyc3Rvb2QKCmBgYHtyfQpoZXRrZWVwZXJfdHggPC0gbW1fbm9ybWFsX3A4X3JldF9kZSRkZXNlcSRhbGxfdGFibGVzJHd0X3JldGluYV92c19oZXRfcmV0aW5hIHw+CiAgZmlsdGVyKGxvZ0ZDIDw9IC0wLjI1ICYgYWRqLlAuVmFsIDw9IDAuMDUpCnRlc3R0aGF0OjpleHBlY3RfdHJ1ZShucm93KGhldGtlZXBlcl90eCkgPT0gbGVuZ3RoKGluY3JlYXNlZF9oZXRfZ2VuZXMpKQp0YWFfa2VlcGVycyA8LSBzb3J0KHJvd25hbWVzKGhldGtlZXBlcl90eCkpCmF0Yl9rZWVwZXJzIDwtIHNvcnQoaW5jcmVhc2VkX2hldF9nZW5lcykKdGVzdHRoYXQ6OmV4cGVjdF9lcXVhbCh0YWFfa2VlcGVycywgYXRiX2tlZXBlcnMpCmBgYAoKWWF5ISBJIGNhbiByZWFkISAgTm93IGxldCB1cyByZXBlYXQgZm9yIHRoZSBLTyB2cyB3dAoKYGBge3J9Cnd0X2tvX2tlZXBlciA8LSBsaXN0KCJrb192c193dCIgPSBjKCJrb19yZXRpbmEiLCAid3RfcmV0aW5hIikpCmtvX3d0X3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIG1tX25vcm1hbF9wOF9yZXRfZGUsIGtlZXBlcnMgPSB3dF9rb19rZWVwZXIsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbF90eC9rb19yZXRpbmFfY29udHJvbC54bHN4IikKd2FudGVkX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIGtvX3d0X3RhYmxlLCBsZmMgPSAwLjI1LCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogIGV4Y2VsID0gIjAzdGhlcmVzYV9jb21wYXJpc29uX2V4Y2VsX3R4L2tvX3JldGluYV9jb250cm9sLXNpZy54bHN4IikKCndhbnRlZF9rb19pbmNyZWFzZWQgPC0gd2FudGVkX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sia29fdnNfd3QiXV0KaW5jcmVhc2VkX2tvX2dlbmVzIDwtIHJvd25hbWVzKHdhbnRlZF9rb19pbmNyZWFzZWQpCmBgYAoKVGhlIG5leHQgdGhpbmcgcGVyZm9ybWVkIGluIFRoZXJlc2EncyBkb2N1bWVudCBpcyBhIHVuaXF1ZShjb25jYXRlbmF0aW9uIG9mCnRoZXNlIHR3byBnZW5lIGdyb3VwcyksIHRodXMgc3Vja2luZyB1cCBldmVyeSBnZW5lIHdoaWNoIHdhcwpzaWduaWZpY2FudGx5IGhpZ2hlciBpbiBlaXRoZXIgdGhlIGtub2Nrb3V0IF9vcl8gaGV0ZXJ6eW91cyBzYW1wbGVzCndpdGggcmVzcGVjdCB0byB3aWxkLXR5cGUuCgpUaGlzIHdhcyBmb2xsb3dlZCBieSBhIGNvdXBsZSBvZiBtZXJnZSBvcGVyYXRpb25zIG9mIGEgbGl0dGxlIGJpdCBvZgp0aGUgYW5ub3RhdGlvbiBkYXRhOyBJIGFtIG5vdCBzdXJlIEkgdW5kZXJzdGFuZCB0aGUgZ29hbCB5ZXQuLi4KCkhlcmUgaXMgaGVyIGNvZGUuIEkgY29waWVkIHRoZSBhbm5vdGF0aW9uICdtZ2lfc3ltYm9sJyBjb2x1bW4gdG8KJ2V4dGVybmFsX2dlbmVfbmFtZScgc28gdGhhdCBJIG5lZWQgbm90IGNoYW5nZSBhbnkgb2YgaGVyIGNvZGUuICBJIGFtCmFzc3VtaW5nIHRoaXMgaXMgdGhlIGFwcHJvcHJpYXRlIGNvbHVtbiBvZiBpbnRlcmVzdCwgSSBkbyBub3Qga25vdwp0aGlzIGZvciBjZXJ0YWluLCBidXQgaXQgc2VlbXMgcXVpdGUgbGlrZWx5LgoKV2hpbGUgSSBhbSBhdCBpdCwgaGVyZSBpcyB0aGUgc2V0X3NpZ19saW1tYSgpIGZ1bmN0aW9uIGZyb20gVGhlcmVzYSdzIGhlbHBlcnMuUgoKYGBge3J9CnNldF9zaWdfbGltbWEgPC0gZnVuY3Rpb24obGltbWFfdGJsLCBmYWN0b3JzID0gTlVMTCkgewogIGlmIChpcy5udWxsKGZhY3RvcnMpKSB7CiAgICAjc2V0IHNpZ25pZmljYW5jZSBmb3IgcGxvdHRpbmcgY29sb3JzCiAgICBsaW1tYV90YmwkU2lnbmlmaWNhbmNlIDwtIE5BCiAgICBsaW1tYV90YmxbYWJzKGxpbW1hX3RibCRsb2dGQykgPD0gMS4wIHwgbGltbWFfdGJsJGFkai5QLlZhbCA+PSAwLjA1LCAiU2lnbmlmaWNhbmNlIl0gPC0gIk5vdCBcbkVucmljaGVkIgogICAgbGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA+PSAxLjAgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuVXByZWd1bGF0ZWQiCiAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDIDw9IC0xLjAgICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdW1siU2lnbmlmaWNhbmNlIl1dIDwtICJEaXNlYXNlIFxuRG93bnJlZ3VsYXRlZCIKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gZmFjdG9yKGxpbW1hX3RibCRTaWduaWZpY2FuY2UsIGxldmVscyA9IGMoIlVwcmVndWxhdGVkIiwgIkRvd25yZWd1bGF0ZWQiLCAgIk5vdCBcbkVucmljaGVkIikpCiAgfSBlbHNlIHsKICAgIGxpbW1hX3RibCRTaWduaWZpY2FuY2UgPC0gTkEKICAgIGxpbW1hX3RibFthYnMobGltbWFfdGJsJGxvZ0ZDKSA8PSAxLjAgfCBsaW1tYV90YmwkYWRqLlAuVmFsID49IDAuMDUsICJTaWduaWZpY2FuY2UiXSA8LSAiTm90IFxuRW5yaWNoZWQiCiAgICBpZihucm93KGxpbW1hX3RibFtsaW1tYV90YmwkbG9nRkMgPj0gMS4wICAmIGxpbW1hX3RibCRhZGouUC5WYWwgPD0gMC4wNSwgXSkgIT0gMCkgewogICAgICBsaW1tYV90YmxbbGltbWFfdGJsJGxvZ0ZDID49IDEuMCAgJiBsaW1tYV90YmwkYWRqLlAuVmFsIDw9IDAuMDUsIF1bWyJTaWduaWZpY2FuY2UiXV0gPC0gZmFjdG9yc1sxXQogICAgfQogICAgaWYgKG5yb3cobGltbWFfdGJsW2xpbW1hX3RibCRsb2dGQyA8PSAtMS4wICYgbGltbWFfdGJsJGFkai5QLlZhbCA8PSAwLjA1LCBdKSAhPSAwKSB7CiAgICAgIGxpbW1hX3RibFtsaW1tYV90YmwkbG9nRkMgPD0gLTEuMCAgJiBsaW1tYV90YmwkYWRqLlAuVmFsIDw9IDAuMDUsIF1bWyJTaWduaWZpY2FuY2UiXV0gPC0gZmFjdG9yc1syXQogICAgfQogICAgbGltbWFfdGJsJFNpZ25pZmljYW5jZSA8LSBmYWN0b3IobGltbWFfdGJsJFNpZ25pZmljYW5jZSwgbGV2ZWxzID0gYyhmYWN0b3JzLCAgIk5vdCBcbkVucmljaGVkIikpCiAgfQogIHJldHVybihsaW1tYV90YmwpCn0KYGBgCgojIyMgQ29tYmluaW5nIGhldC93dCBhbmQga28vd3QKCmBgYHtyfQprZWVwZXJ0eCA8LSB1bmlxdWUoYyhyb3duYW1lcyhoZXRrZWVwZXJfdHgpLCByb3duYW1lcyhrb2tlZXBlcl90eCkpKQpsZW5ndGgoa2VlcGVydHgpCmRmIDwtIG1tX2RlX25vcm1hbF9wOF9yZXQkZGVzZXEkYWxsX3RhYmxlcyRrb19yZXRpbmFfdnNfaGV0X3JldGluYSB8PgogIGRwbHlyOjptdXRhdGUobG9nRkMgPSAtbG9nRkMpIHw+CiAgc2V0X3NpZ19saW1tYShmYWN0b3JzID0gYygiSGV0IEVucmljaGVkIiwgIktPIEVucmljaGVkIikpCmBgYAoKTXkgdmVyc2lvbiBvZiB0aGUgYWJvdmUgdGFzayBtYWtlcyB1c2Ugb2YgdGhlIGV4Y2x1ZGVzIG9wdGlvbiBvZgpjb21iaW5lX2RlX3RhYmVzLiAgR2l2ZW4gdGhlIHNldCBvZiB1bmlxdWUgZ2VuZSBJRHMgaW5jcmVhc2VkIGluIHRoZQpoZXQva28sIEkgY2FuIGFzayB0byBleGx1ZGUgYW55dGhpbmcgbm90IGluIHRoYXQgc2V0LiAgSSBjb3VsZCBhbHNvCmhhdmUgbW9yZSBwYXJzaW1vbmlvdXNseSBkaXJlY3RseSBleGNsdWRlZCBhbnkgZ2VuZSBJRCBpbmNyZWFzZWQgaW4KdGhlIHd0IHNhbXBsZXMuICBCdXQsIFRoZXJlc2EgYWxyZWFkeSBwcm92aWRlZCB0aGUgY29kZSB0byBkbyB0aGUKZm9ybWVyLCBzbyBpdCB3aWxsIGJlIGxlc3MgdHlwaW5nL29wcG9ydHVuaXR5IGZvciBzaWxseSBtaXN0YWtlcyB0bwpqdXN0IGRvIHRoYXQuCgpgYGB7cn0KYm90aF9pbmNyZWFzZWRfZ2VuZXMgPC0gdW5pcXVlKGMoaW5jcmVhc2VkX2hldF9nZW5lcywgaW5jcmVhc2VkX2tvX2dlbmVzKSkKIyMgYXJiaXRyYWlybHkgZ3JhYiBhbGwgZ2VuZXMgZnJvbSBvbmUgb2YgbXkgZGF0YSBzdHJ1Y3R1cmVzLgphbGxfZ2VuZXMgPC0gcm93bmFtZXMoYXNzYXkobW0zOF9oaXNhdF90eCkpCmV4Y2x1ZGVfaWR4IDwtIGFsbF9nZW5lcyAlaW4lIGJvdGhfaW5jcmVhc2VkX2dlbmVzCnN1bW1hcnkoZXhjbHVkZV9pZHgpCmBgYAoKYGBge3J9CmV4Y2x1ZGVfaW5jcmVhc2VkX2dlbmVzIDwtIGFsbF9nZW5lc1tleGNsdWRlX2lkeF0KcmV0aW5hX2tlZXBlcnMgPC0gbGlzdCgKICAiaGV0X3ZzX3d0IiA9IGMoImhldF9yZXRpbmEiLCAid3RfcmV0aW5hIiksCiAgImtvX3ZzX3d0IiA9IGMoImtvX3JldGluYSIsICJ3dF9yZXRpbmEiKSwKICAia29fdnNfaGV0IiA9IGMoImtvX3JldGluYSIsICJoZXRfcmV0aW5hIikpCiMjIEEgcmVtaW5kZXIgdG8gbXlzZWxmOiB0aGVyZSBpcyBhbHNvIGEgcGFyYW1ldGVyICd3YW50ZWRfZ2VuZXMnCiMjIHdoaWNoIGRvZXMgZWZmZWN0aXZlbHkgdGhlIHNhbWUgdGhpbmcgYXMgZXhjbHVkZXMgaW4gdGhpcyBjb250ZXh0OwojIyBleGNsdWRlcyB3YXMgb3JpZ2luYWxseSB3cml0dGVuIHRvIGFsbG93IGZsZXhpYmxlLCBrZXl3b3JkLWJhc2VkCiMjIGV4Y2x1c2lvbi4KcDhfcmV0aW5hX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gcmV0aW5hX2tlZXBlcnMsCiAgd2FudGVkX2dlbmVzID0gYm90aF9pbmNyZWFzZWRfZ2VuZXMsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjAzdGhlcmVzYV9jb21wYXJpc29uX2V4Y2VsX3R4L3A4X3JldGluYV9rZXB0X3R4X2luY3JlYXNlZF9pbl93dF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKCnA4X3JldGluYV9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBwOF9yZXRpbmFfdGFibGVzLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogIGV4Y2VsID0gZ2x1ZSgiMDN0aGVyZXNhX2NvbXBhcmlzb25fZXhjZWxfdHgvcDhfcmV0aW5hX2tlcHRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3NpZy12e3Zlcn0ueGxzeCIpKQoKb3Bwb3NpdGVfcDhfcmV0aW5hX3RhYmxlcyA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBtbV9ub3JtYWxfcDhfcmV0X2RlLCBrZWVwZXJzID0gcmV0aW5hX2tlZXBlcnMsCiAgZXhjbHVkZXMgPSBib3RoX2luY3JlYXNlZF9nZW5lcywgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMDN0aGVyZXNhX2NvbXBhcmlzb25fZXhjZWxfdHgvcDhfcmV0aW5hX3JlbW92ZWRfZ2VuZXNfaW5jcmVhc2VkX2luX3d0X3RhYmxlcy12e3Zlcn0ueGxzeCIpKQoKb3Bwb3NpdGVfcDhfcmV0aW5hX3NpZyA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogIHA4X3JldGluYV90YWJsZXMsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbF90eC9wOF9yZXRpbmFfcmVtb3ZlZF9nZW5lc19pbmNyZWFzZWRfaW5fd3Rfc2lnLXZ7dmVyfS54bHN4IikpCmBgYAoKIyBGaWx0ZXJpbmcgb3V0IG5vbi1zcGVjaWZpYyBnZW5lcyBhbmQgZXhhbWluaW5nIHRoZSByZXN1bHRzCgpUaGUgZm9sbG93aW5nIGlzIGEgY29weS9wYXN0ZSBmcm9tIFRoZXJlc2EgY29udGFpbmluZyB0aGUgcmVtYWluaW5nCnRhc2tzIHNoZSBwZXJmb3JtZWQgYW5kIHdpbGwgcHJvdmlkZSB0aGUgdGVtcGxhdGUgZm9yIGltcGxlbWVudGF0aW9uCm9mIHRoZSBmaW5hbCB0YXNrcy4KClRoaXMgcGlja3MgdXAgd2l0aCB0aGUgbGluZXMgZnJvbSBoZXIgbm90ZWJvb2sgaW1tZWRpYXRlbHkgZm9sbG93aW5nCnRoZSBpbnZvY2F0aW9uIG9mICdzZXRfc2lnX2xpbW1hKGZhY3RvcnMgPSBjKCJIZXQgRW5yaWNoZWQiIC4uLicuCgpGb3IgYWxsIG9mIHRoZSByZW1haW5pbmcgYmxvY2tzIEkgd2lsbCBjb3B5IGluIGhlciBjb2RlLCB0dXJuIG9mZiBpdHMKZXZhbHVhdGlvbiwgcnVuIHRoZSBibG9ja3MgbWFudWFsbHksIGNvbXBhcmUgdGhlbSB0byBoZXIgbm90ZWJvb2sKb3V0cHV0LCB0aGVuIGVuYWJsZSBlYWNoIGJsb2NrIGFzIEkgZW5zdXJlIEkgdW5kZXJzdGFuZCBpdC4KCkkgd2lsbCBsaWtlbHkgdGhlcmVmb3JlIGludHJvZHVjZSBzb21lIHNtYWxsIGZvcm1hdHRpbmcgY2hhbmdlcyBhbmQKYWRkIHNvbWUgYWRkaXRpb25hbCBHU0VBL2VucmljaG1lbnQgdGFza3Mgb25jZSB0aGUgbm9uLXNwZWNpZmljCmZpbHRlcmluZyBpcyBjb21wbGV0ZS4KCmBgYHtyfQpkZiA8LSBkZiB8PgogIGZpbHRlcihyb3duYW1lcyhkZikgJWluJSBrZWVwZXJ0eCkKbGFiZWxzX3VwcyA8LSBkZiB8PgogIGZpbHRlcihhZGouUC5WYWwgPD0gMC4wNSAmIGFicyhsb2dGQykgPj0gMS4wKSB8PgogIGFycmFuZ2UobG9nRkMpIHw+CiAgaGVhZChuID0gOSkKbGFiZWxzX2Rvd25zIDwtIGRmIHw+CiAgZmlsdGVyKGFkai5QLlZhbCA8PSAwLjA1ICYgYWJzKGxvZ0ZDKSA+PSAxLjApIHw+CiAgYXJyYW5nZSgtbG9nRkMpIHw+CiAgaGVhZChuID0gMTEpCmxhYmVscyA8LSByYmluZChsYWJlbHNfdXBzLCBsYWJlbHNfZG93bnMpCnJlc190YmwgPC0gZGYKREVwbG90IDwtIGdncGxvdChyZXNfdGJsLCBhZXMoeCA9IGxvZ0ZDLCB5ID0gLWxvZzEwKGFkai5QLlZhbCkpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU2lnbmlmaWNhbmNlKSwgc2l6ZSA9IDQpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC0xLCAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjApICsKICB4bGFiKCJsb2cyKEZDKSIpICsKICB5bGFiKCItbG9nMTAocC12YWx1ZSkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjg3NjZEIiwgIiMwMEJGQzQiLCAiR3JleSIpKSArCiAgeGxpbShjKC0zLCA2KSkKCnBwKGZpbGUgPSAiMDN0aGVyZXNhX2NvbXBhcmlzb25faW1hZ2VzX3R4L3AwOF9yZXRpbmFfREVfMTMxMjAyNC5wZGYiKQpERXBsb3QKcGxvdHRlZCA8LSBkZXYub2ZmKCkKREVwbG90CndyaXRlX3hsc3goZGYsIGV4Y2VsID0gImV4Y2VsX3R4L3JldGluYWhldF92c19yZXRpbmFrb19XVGZpbHRlcmVkLnhsc3giKQpgYGAKCiMjIEhvdyBtYW55IHVwcy9kb3ducwoKYGBge3J9CmtvX2VucmljaGVkIDwtIGRmIHw+CiAgZmlsdGVyKFNpZ25pZmljYW5jZSA9PSAiS08gRW5yaWNoZWQiKQpucm93KGtvX2VucmljaGVkKQpoZXRfZW5yaWNoZWQgPC0gIGRmIHw+CiAgZmlsdGVyKFNpZ25pZmljYW5jZSA9PSAiSGV0IEVucmljaGVkIikKbnJvdyhoZXRfZW5yaWNoZWQpCmBgYAoKIyMgY2F0ZWdvcnkgZW5yaWNobWVudC9HU0VBCgpgYGB7cn0KcmVndWxhdGVkX2dlbmVzIDwtIHJlc190YmwgfD4KICBmaWx0ZXIoYWRqLlAuVmFsIDw9IDAuMDUpIHw+CiAgYXJyYW5nZShsb2dGQykgfD4KICBmaWx0ZXIoYWJzKGxvZ0ZDKSA+PSAxLjApCiMjIGdzZWFfcmVzdWx0X2tvIDwtIGdvc3QocXVlcnkgPSBrb19nZW5lcyRleHRlcm5hbF9nZW5lX25hbWUsCiMjICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKIyMgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKIyMgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKZ3NlYV9yZXN1bHRfaGV0IDwtIGdvc3QocXVlcnkgPSBoZXRfZW5yaWNoZWRbWyJSb3cubmFtZXMiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGV2Y29kZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKIyNnc2VhX3Jlc3VsdF9hbGxkeXNyZWd1bGF0ZWQgPC0gZ29zdChxdWVyeSA9IGFsbGR5c3JlZ3VsYXRlZF9nZW5lcyRleHRlcm5hbF9nZW5lX25hbWUsCiMjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAibW11c2N1bHVzIiwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmNvZGVzID0gVFJVRSwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkX3F1ZXJ5ID0gVFJVRSkKYGBgCgpJIGhhdmUgYSBmdW5jdGlvbiBpbiBteSBwYWNrYWdlIHdoaWNoIHNlZWtzIHRvIG1ha2UgZ1Byb2ZpbGVyIHF1ZXJpZXMKYSBiaXQgbW9yZSBjb21wbGV0ZSBhbmQgZWFzeS4gIExldCB1cyBzZWUgaG93IHNpbWlsYXIgdGhlIHJlc3VsdCBpcy4uLgoKYGBge3IsIGV2YWw9RkFMU0V9CnJvd25hbWVzKGFsbGR5c3JlZ3VsYXRlZF9nZW5lcykgPC0gYWxsZHlzcmVndWxhdGVkX2dlbmVzW1siUm93Lm5hbWVzIl1dCmFsbGR5c3JlZ3VsYXRlZF9nZW5lc1tbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCgpoZXRfZ3AgPC0gc2ltcGxlX2dwcm9maWxlcihyb3duYW1lcyhhbGxkeXNyZWd1bGF0ZWRfZ2VuZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzcGVjaWVzID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZSgiZXhjZWxfdHgvaGV0X2dwcm9maWxlci12e3Zlcn0ueGxzeCIpKQpoZXRfZ3AKZW5yaWNocGxvdDo6ZG90cGxvdChoZXRfZ3BbWyJCUF9lbnJpY2giXV0pCmdwX3BhaXIgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbShoZXRfZ3BbWyJCUF9lbnJpY2giXV0pCmVucmljaHBsb3Q6OmVtYXBwbG90KGdwX3BhaXIpCmVucmljaHBsb3Q6OnNzcGxvdChncF9wYWlyKQplbnJpY2hwbG90Ojp0cmVlcGxvdChncF9wYWlyKQp1cHNldHBsb3QoaGV0X2dwW1siQlBfZW5yaWNoIl1dKQoKZW5yaWNocGxvdDo6ZG90cGxvdChoZXRfZ3BbWyJSRUFDX2VucmljaCJdXSkKZ3BfcGFpciA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKGhldF9ncFtbIlJFQUNfZW5yaWNoIl1dKQplbnJpY2hwbG90OjplbWFwcGxvdChncF9wYWlyKQplbnJpY2hwbG90Ojpzc3Bsb3QoZ3BfcGFpcikKZW5yaWNocGxvdDo6dHJlZXBsb3QoZ3BfcGFpcikKdXBzZXRwbG90KGhldF9ncFtbIlJFQUNfZW5yaWNoIl1dKQpgYGAKCkkgbWFrZSBhIHNvbWV3aGF0IGFyYml0cmFyeSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZSBjb25jZXB0cyBvZgpvdmVyLWVucmljaG1lbnQgYW5hbHlzZXMgYW5kIEdTRUE6IHRoZSBmb3JtZXIgKGFzIHBlcmZvcm1lZCBieQpncHJvZmlsZXIpIChAcmF1ZHZlcmVQcm9maWxlcldlYlNlcnZlcjIwMTkpIHNlZWtzIHRvIGZpbmQgZ3JvdXBzIG9mCmdlbmVzIG92ZXJyZXByZXNlbnRlZCBpbiBHTy9yZWFjdG9tZS9ldGMuICBUaGVzZSBncm91cHMgb2YgZ2VuZXMgYXJlCnRha2VuIGV4Y2x1c2l2ZWx5IGZyb20gdGhlIHRvcC1uL2JvdHRvbS1uIGdlbmVzIHdpdGggcmVzcGVjdCB0bwpmb2xkLWNoYW5nZSBiZXR3ZWVuIGNvbmRpdGlvbnMgb2YgaW50ZXJlc3Q7IGluIHRoaXMgY2FzZSBtb3N0CmRpZmZlcmVudCB0aGFuIHd0IGluIHRoZSBwMDggcmV0aW5hIGtvIG9yIGhldCBzYW1wbGVzLgoKV2l0aCB0aGF0IGluIG1pbmQsIEkgY2FuIGludm9rZSBhIHNpbWlsYXIgZnVuY3Rpb24gdXNpbmcgdGhlIGZ1bGwKdGFibGUgb2YgREUgcmVzdWx0cyB0byBnZXQgd2hhdCBJIGNhbGwgdGhlIEdTRUEgcmVzdWx0IHVzaW5nCmNsdXN0ZXJQcm9maWxlciAoQHl1SW50cm9kdWN0aW9uQmlvbWVkaWNhbEtub3dsZWRnZSkuICBJbiB0aGUKZm9sbG93aW5nIGJsb2NrIEkgd2lsbCB1c2UgdGhlICdhbGxfY3Byb2ZpbGVyJyBmdW5jdGlvbiBvbiB0aGUgZGF0YQpzdHJ1Y3R1cmVzIG5hbWVkICdwOF9yZXRpbmFfdGFibGVzJyBhbmQgJ29wcG9zaXRlX3A4X3JldGluYV90YWJsZXMnIGluCm9yZGVyIHRvIGdldCB0aGVzZSBHU0VBIHJlc3VsdHMgZm9yIGVhY2ggY29udHJhc3QgcGVyZm9ybWVkIChoZXQvd3QsCmtvL3d0LCBoZXQva28pLiAgSSB3aWxsIGZvbGxvdyB0aGF0IHVwIHdpdGggJ2FsbF9ncHJvZmlsZXInIHdoaWNoIGRvZXMKdGhlIHNhbWUsIGJ1dCB1c2VzIGdQcm9maWxlcidzIGVucmljaG1lbnQgYW5hbHlzZXMgKGl0IHdpbGwgdGhlcmVmb3JlCmluY2x1ZGUgd2hhdCB3ZSBqdXN0IGxvb2tlZCBhdCkuCgpgYGB7cn0KcDA4X3JldGluYV9hbGxfY3AgPC0gYWxsX2Nwcm9maWxlcigKICBwOF9yZXRpbmFfc2lnLCBwOF9yZXRpbmFfdGFibGVzLCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICBleGNlbCA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9leGNlbF90eC9jcHJvZmlsZXJfcDA4X3JldGluYS54bHN4IikKCmVucmljaHBsb3Q6OmRvdHBsb3QocDA4X3JldGluYV9hbGxfY3BbWyJrb192c19oZXRfdXAiXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dKQpwMDhfdG9wbl9nc2VhIDwtIHBsb3RfdG9wbl9nc2VhKHAwOF9yZXRpbmFfYWxsX2NwKQoKcHAoZmlsZSA9ICIwM3RoZXJlc2FfY29tcGFyaXNvbl9pbWFnZXNfdHgvZ3NlYV9wMDhfcmV0aW5hX2tvX3ZzX2hldF90b3BfaGl0LnBkZiIsKQpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1sxXV0KZGV2Lm9mZigpCgpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1sxXV0KcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbMl1dCnAwOF90b3BuX2dzZWFbWyJHT19rb192c19oZXRfdXAiXV1bWzNdXQpwMDhfdG9wbl9nc2VhW1siR09fa29fdnNfaGV0X3VwIl1dW1s0XV0KcDA4X3RvcG5fZ3NlYVtbIkdPX2tvX3ZzX2hldF91cCJdXVtbNV1dCmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CiNnc2VhX2tvIDwtICBnc2VhX3Jlc3VsdF9rb1tbInJlc3VsdCJdXSB8PgojICAgIHNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pIHw+CiMgICAgYXJyYW5nZShkZXNjKHJlY2FsbCkpIHw+CiMgICAgaGVhZChuID0gMTApCiMgIGdzZWFfcGxvdHNfa28gPC0gZ2dwbG90KGdzZWFfa28sIGFlcyh4ID0gcmVjYWxsLCB5ID0gcmVvcmRlcih0ZXJtX25hbWUsIHJlY2FsbCksIGZpbGwgPSBwX3ZhbHVlKSkgKwojICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiMgIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIikgKwojICB0aGVtZV9idygpKwojICB5bGFiKCIiKSArCiMgIHhsYWIoIkdTRUEgU2NvcmUiKQpnc2VhX2hldCA8LSAgZ3NlYV9yZXN1bHRfaGV0W1sicmVzdWx0Il1dIHw+CiAgZHBseXI6OnNlbGVjdCh0ZXJtX25hbWUsIHBfdmFsdWUsIHRlcm1fc2l6ZSwgaW50ZXJzZWN0aW9uX3NpemUsIHJlY2FsbCwgc291cmNlLCBpbnRlcnNlY3Rpb24pIHw+CiAgYXJyYW5nZShkZXNjKHJlY2FsbCkpIHw+CiAgaGVhZChuID0gMTApCmdzZWFfcGxvdHNfaGV0IDwtIGdncGxvdChnc2VhX2hldCwgYWVzKHggPSByZWNhbGwsIHkgPSByZW9yZGVyKHRlcm1fbmFtZSwgcmVjYWxsKSwgZmlsbCA9IHBfdmFsdWUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICB0aGVtZV9idygpICsKICB5bGFiKCIiKSArCiAgeGxhYigiT3ZlciBSZXByZXNlbnRhdGlvbiBTY29yZSIpCnBwKGZpbGUgPSAiMDN0aGVyZXNhX2NvbXBhcmlzb25faW1hZ2VzX3R4L0dTRUFfcDA4X2F4b250cmFwX3JldGluYWhldF91cHJlZ3VsYXRlZF92c19yZXRpbmFrby5wZGYiKQpnc2VhX3Bsb3RzX2hldApwbG90dGVkIDwtIGRldi5vZmYoKQpnc2VhX3Bsb3RzX2hldApgYGAKCiMgU0NOIEhldCB2cyBLTwoKSXQgaXMgb25seSBub3cgdGhhdCBJIHJlYWxpemVkIHdlIGFyZSBzcGxpdHRpbmcgdGhlIGRhdGEgYnkgbG9jYXRpb24KZm9yIGVhY2ggc2V0IG9mIGNvbXBhcmlzb25zLiAgSSB0aGluayB0aGF0LCBsZWZ0IHRvIG15IG93biBkZXZpY2VzLCBJCndvdWxkIHByZWZlciB0byBrZWVwIHRoZSBpbnB1dCBkYXRhIHN0cnVjdHVyZSBpbnRhY3QsIHBlcmZvcm0gdGhlCnNvbWV3aGF0IGxhcmdlciBudW1iZXIgb2YgY29udHJhc3RzLCBhbmQgdGhlbiBzcGxpdCB1cCB0aGUgcmVzdWx0cy4KSWRlYWxseSB0aGlzIHdpbGwgc2xpZ2h0bHkgaW1wcm92ZSB0aGUgZmlkZWxpdHkgb2YgdGhlIHJlc3VsdHMKcmV0dXJuZWQgYnkgREVTZXEyIGFuZCBmcmllbmRzLiAgQnV0LCBJIHdpbGwgcnVuIHRoZSBzdGF0ZSBvZgpUaGVyZXNhJ3Mgbm90ZWJvb2sgd2l0aCBhcyBmZXcgY2hhbmdlcyBhcyBwb3NzaWJsZSBmaXJzdCwgdGhlbiBhZGQKdGhpcy4KCiMjIFBDQQoKSSBhbSBnb2luZyB0byBza2lwIHRoaXMgUENBIHBsb3QgZm9yIGEgY291cGxlIG9mIHJlYXNvbnM6IEkgYWxyZWFkeQpkaWQgYSBzdXBlcnNldCBvZiBpdCwgYW5kIHRoZSBzdWJzZXQgVGhlcmVzYSBwZXJmb3JtZWQgaXMgbm90IHZhbGlkCmdpdmVuIHRoZSBzZXQgb2Ygc2FtcGxlcyBpbmNsdWRlZCBpbiBteSBzYW1wbGUgc2hlZXQsIGFuZCBmaWd1cmluZyBvdXQKdGhlIGFjdHVhbGx5IGNvcnJlc3BvbmRpbmcgc3Vic2V0IHdpbGwgdGFrZSBtZSBmb3JldmVyLi4uICBJbgphZGRpdGlvbiwgSSB3YW50IHRvIHVzZSBteSBtbTM4X2hpc2F0X3R4IGZvciBldmVyeXRoaW5nLi4uCgoKYGBge3J9CnNjbl9zYW1wbGVzIDwtIHN1YnNldF9zZShtbTM4X2hpc2F0X3R4LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQgPSAibG9jYXRpb25fYXRiID09ICdzY24nIikgfD4KICBzZXRfYmF0Y2hlcyhmYWN0ID0gImxvY2F0aW9uX2F0YiIpIHw+CiAgc2V0X2NvbmRpdGlvbnMoZmFjdCA9ICJnZW5vdHlwZV9hdGIiLCBjb2xvcnMgPSBjb2xvcl9jaG9pY2VzW1siZ2Vub3R5cGUiXV0pCnNjbl9ub3JtIDwtIG5vcm1hbGl6ZShzY25fc2FtcGxlcywgZmlsdGVyID0gVFJVRSwgY29udmVydCA9ICJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSAibG9nMiIsIGJhdGNoID0gInN2YXNlcSIpCnNjbl9ub3JtX3BjYSA8LSBwbG90X3BjYShzY25fbm9ybSkKc2NuX25vcm1fcGNhCmBgYAoKIyBMaWJyYXJ5IHNpemVzIHBvc3QtZGVkdXBsaWNhdGlvbgoKVGhlcmVzYSdzIG5leHQgb3BlcmF0aW9uIHdhcyB0byBwZXJmb3JtIGxpYnNpemUvbm9uemVybyBwbG90cy4gIEkKYWxyZWFkeSBkaWQgdGhlIHByZS9wb3N0IGRlZHVwbGljYXRpb24gbm9uemVybywgaGVyZSBpcyB0aGUgYW5hbGFnb3VzCmxpYnNpemUuCgp2MiBpcyBwcmUtZGVkdXBsaWNhdGlvbiBhbmQgdjMgaXMgcG9zdC4KCmBgYHtyfQpwb3N0X2ZpbHRlcl9ub256ZXJvIDwtIHBsb3RfcXVhbnRyZWFkcyhtbTM4X2hpc2F0X3R4LCB0ZXh0ID0gRkFMU0UpCnBwKGZpbGUgPSAiMDFkaWFnbm9zdGljX2ltYWdlc190eC9wb3N0X2FsbF9maWx0ZXJlc19ub256ZXJvLnBkZiIpCnBvc3RfZmlsdGVyX25vbnplcm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnBvc3RfZmlsdGVyX25vbnplcm8KYGBgCgpUaGVyZXNhIGFsc28gcHJvZHVjZWQgYSBkZW5zaXR5L3NhbXBsZSBwbG90LCB0aGF0IG1pZ2h0IHByb3ZlIHF1aXRlCnVzZWZ1bCBmb3IgdGhlc2UgZHVlIHRvIHRoZWlyIHNpZ25pZmljYW50bHkgbGFyZ2VyIHZhcmlhbmNlIGFjcm9zcwpzYW1wbGVzIChkdWUgdG8gZGVkdXBsaWNhdGlvbikuCgpgYGB7cn0KcHAoZmlsZSA9ICIwMWRpYWdub3N0aWNfaW1hZ2VzX3R4L3NhbXBsZV9kZW5zaXR5LnBkZiIpCm1tMzhfZGVuc2l0eSA8LSBwbG90X2RlbnNpdHkobG9jX2dlbm9fbnQpCm1tMzhfZGVuc2l0eVtbInBsb3QiXV0gKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGxvdF9ib3hwbG90KGxvY19nZW5vX250KQpkZXYub2ZmKCkKbW0zOF9kZW5zaXR5W1sicGxvdCJdXSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpib3ggPC0gcGxvdF9ib3hwbG90KGxvY19nZW5vX250KQpwcChmaWxlID0gIjAxZGlhZ25vc3RpY19pbWFnZXNfdHgvc2FtcGxlX2JveHBsb3QucGRmIikKYm94CmRldi5vZmYoKQpib3gKYGBgCgpUaGVyZSBpcyBzb21lIGRpZmZlcmVuY2UgYWNyb3NzIHNhbXBsZSBkZW5zaXRpZXMsIGJ1dCBpdCBpcyBub3QgdG9vCmNyYXp5dG93bi4KCiMgRGl2ZXJnaW5nIGEgbGl0dGxlCgpBdCB0aGlzIHBvaW50IGluIHRoZSBkb2N1bWVudCBJIHJlYWQgYWhlYWQgYSBiaXQgYW5kIGNhbWUgdG8gdGhlCmNvbmNsdXNpb24gdGhhdCBpdCByZXBlYXRzIHRoZSBhYm92ZSBsb2dpYyBvZiB0YWtpbmcgdGhlIHVuaW9uIG9mIHd0CmNvbXBhcmlzb25zIHRvIHJlbW92ZSBnZW5lcyBmcm9tIHRoZSBhcHByb3ByaWF0ZSBoZXQva28gb3IgcDE1L3AwOCBvcgpsb2NhdGlvbiBjb21wYXJpc29ucy4gIFRoaXMgc2VlbXMgcXVpdGUgcmVhc29uYWJsZSB0byBtZSwgYnV0IEkgd291bGQKcHJlZmVyIHRvIG5vdCBzZXBhcmF0ZSBhbGwgdGhlIGRhdGEsIHNvIEkgd2lsbCBhdHRlbXB0IHRvIGR1cGxpY2F0ZQphbmQgc2xpZ2h0bHkgc3RyZWFtbGluZSB0aGlzIGxvZ2ljIG9uIHRoZSBmdWxsIGRhdGFzZXQuICBUaHVzIEkgYW0KZ29pbmcgdG8gc2tpcCBkb3duIHRvIHRoZSBlbmQgYW5kIGF0dGVtcHQgdG8gaW1wbGVtZW50IHRoaXMuCgojIE15IHZlcnNpb24gb2YgdGhlIGdsb2JhbCBhbmFseXNpcwoKSSB3YW50IHRvIGhhdmUgYW4gaW52b2NhdGlvbiBvZiBhbGxfcGFpcndpc2UoKSB3aGljaCB1c2VzIGFsbCBzYW1wbGVzLAppbiB0aGUgZm9sbG93aW5nIGJsb2NrIEkgd2lsbCBzZXQgdGhhdCB1cCB1c2luZyBhIHNldCBvZiAna2VlcGVycycKd2hpY2ggd2lsbCBiZSBuYW1lZCBieSB0aW1lLCBsb2NhdGlvbiwgdGhlbiAyIGxldHRlcnMgZm9yIHRoZQpudW1lcmF0b3IvZGVub21pbmF0b3I6IHcgZm9yIFdULCBoIGZvciBoZXQsIGQgZm9yIGRlbHRhOyB0aHVzCiJwMDhfcmV0aW5hX2h3IiBpcyBjb21wYXJpbmcgdGhlIGhldC93dCBmb3IgdGhlIHAwOCByZXRpbmEgc2FtcGxlcy4KCklmIHRoZXkgYXJlIG9mIGludGVyZXN0LCBJIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIHNldCB3aGljaCBmb2xsb3dzIHRoZQpzYW1lIGNvbnZlbnRpb24gd2l0aCBuYW1lcyBsaWtlICJwMDhfa29fc3IiIHRvIGNvbXBhcmUgcDA4IGRlbHRhcyB3aXRoClNDTiBhcyB0aGUgbnVtZXJhdG9yIGFuZCByZXRpbmEgYXMgdGhlIGRlbm9taW5hdG9yLgoKIyMgU2V0IHVwIHRoZSBleGNsdXNpb24gZGF0YXNldAoKVGhlIG1vc3QgcGVjdWxpYXIgYXNwZWN0IG9mIHRoaXMgYW5hbHlzaXMgcmVzaWRlcyBpbiB0aGUgY2hvaWNlcwphcm91bmQgY2hvb3Npbmcgd2hpY2ggZ2VuZXMgdG8gY29uc2lkZXIgd2hlbiBjb21wYXJpbmcgdGhlCmdlbm90eXBlcy9sb2NhdGlvbnMvdGltZXMuICBUaGUgZ2VuZXJhbCBpZGVhIGlzIHByZXR0eSBjbGVhcjogZmluZCB0aGUKZ2VuZXMgd2hpY2ggYXJlIG5vbi1zcGVjaWZpY2FsbHkgYmVpbmcgcHVsbGVkIGRvd24gaW4gdGhlIFdUIHNhbXBsZXMKYW5kIGVpdGhlciBleGNsdWRlIG9yIGRpc2NvdW50IHRoZW0uICBUaGUgdmFyaW91cyBwb3RlbnRpYWwgbWV0aG9kcwpmb3IgcGVyZm9ybWluZyB0aGlzIGFyZSBjb25mdXNpbmc6CgoxLiAgV2hpY2ggc2V0IG9mIGNvbXBhcmlzb25zIG9mIHd0L2tvIHd0L2hldCBkbyB3ZSB1c2UgdG8KICAgIGV4Y2x1ZGUvZGlzY291bnQgZ2VuZXM/CiAgICBhLiAgU2hvdWxkIGl0IGJlIGEgY29tYmluYXRpb24gb2YgYWxsIHNhbXBsZXMgd3QgdnMuIHg/CiAgICBiLiAgU2hvdWxkIGl0IGJlIG9ubHkgdGhlICdyZWxldmFudCcgY29tcGFyaXNvbiwgZS5nLiBpZiB3ZSBhcmUKICAgIGNvbXBhcmluZyBwMDhfZGxnbl9oZXQgdnMuIHAwOF9zY25faGV0OyBkbyB3ZSByZW1vdmUgZ2VuZXMKICAgIG9ic2VydmVkIGluIChwMDhfZGxnbl9oZXQvd3QgJiYgcDA4X3Njbl9oZXQvd3QpCjIuICBEbyB3ZSBpbnN0ZWFkIGF0dGVtcHQgdG8gdXNlIHRoaXMgeC93dCBpbmZvcm1hdGlvbiB0byBub3JtYWxpemUKICAgIHRoZSBleHByZXNzaW9uIHZhbHVlcyBpbiB0aGUgb3RoZXIgY29uZGl0aW9ucyBhbmQga2VlcCB0aG9zZQogICAgZ2VuZXM/CgpUaGVyZXNhJ3MgY3VycmVudCB3b3Jrc2hlZXQgaW1wbGVtZW50cyBhIHZlcnNpb24gb2YgMWIgaW4gd2hpY2ggc2hlCnNlcGFyYXRlZCB0aGUgdmFyaW91cyBpbnB1dCBnZW5lIHNldHMgdG8gZGVmaW5lIHRoZSBleGNsdXNpb24gZ2VuZXMuCkkgYW0gZ29pbmcgdG8gcmVwZWF0IHRoaXMsIGJ1dCBsZWF2ZSB0aGUgc3RhcnRpbmcgZGF0YSBzdHJ1Y3R1cmUKaW50YWN0LgoKSW4gdGhpcyBmaXJzdCBpdGVyYXRpb24sIEkgd2lsbCBkbyB0aGF0IGJ5IGNyZWF0aW5nIGEgc2ltcGxpZmllZCBtb2RlbApvZiB0aGUgZGF0YSB3aGljaCBjb21iaW5lcyB0aGUgdGltZS9nZW5vdHlwZS9sb2NhdGlvbiBhbmQgdXNpbmcgc3ZhLgpJbiBteSBuZXh0IGl0ZXJhdGlvbiBJIHdpbGwgdXNlIGEgZnVsbCBzdGF0aXN0aWNhbCBtb2RlbCBjb250YWluaW5nCmVhY2ggb2YgdGhvc2UgZmFjdG9ycyAoYW5kIHByb2JhYmx5IGFsc28gdXNpbmcgc3ZhKS4KCk5vdGU6IG15IGNvbG9yIGNob2ljZXMgYXJlIGtpbmQgb2YgZ2FyYmFnZS4KCkluIGFkZGl0aW9uLCB0aGUgZXhjbHVzaW9uIGRhdGFzZXQgaXMgdGhlIHNhbWUgYXMgdGhlIGFuYWx5c2lzCmRhdGFzZXQsIGl0IGlzIHJlYWxseSBvbmx5IHRoZSBjb250cmFzdHMgd2hpY2ggd2lsbCBiZSBkaWZmZXJlbnQuCgpgYGB7cn0KdHhfcGFpcndpc2VfaW5wdXQgPC0gc2V0X2NvbmRpdGlvbnMobW0zOF9oaXNhdF90eCwgZmFjdCA9ICJ0aW1lX2dlbm9fbG9jIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gY29sb3JfY2hvaWNlc1tbImFsbCJdXSkKYGBgCgojIyBBIGhlYXRtYXAgb2Ygc3BlY2lmaWMgZ2VuZXMgYWNyb3NzIGFsbCBjb25kaXRpb25zCgpgYGB7cn0KYWxsX2NvbmRfZ2VuZV9oZWF0bWFwX3N0YXJ0IDwtIG5vcm1hbGl6ZSh0eF9wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gInNpbXBsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoX2NvbHVtbiA9ICJjZHNfbGVuZ3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0ID0gInJwa20iLCB0cmFuc2Zvcm0gPSAibG9nMiIpCmFsbF9jb25kX2dlbmVfaGVhdG1hcF9pbnB1dCA8LSBtZWRpYW5fYnlfZmFjdG9yKGFsbF9jb25kX2dlbmVfaGVhdG1hcF9zdGFydCkKYWxsX2NvbmRfbXRyeCA8LSBhbGxfY29uZF9nZW5lX2hlYXRtYXBfaW5wdXRbWyJtZWRpYW5zIl1dCmNvbG9yX29yZGVyIDwtIGNvbG5hbWVzKGFsbF9jb25kX210cngpCm5hX2lkeCA8LSBpcy5uYShhbGxfY29uZF9tdHJ4KQphbGxfY29uZF9tdHJ4W25hX2lkeF0gPC0gMAp2YXJpYW5jZXMgPC0gbWF0cml4U3RhdHM6OnJvd1ZhcnMoYXMubWF0cml4KGFsbF9jb25kX210cngpKQp2YXJpYW50X2dlbmVzIDwtIHZhcmlhbmNlcyA+IDYuMgppbnB1dF9tdHJ4IDwtIGFsbF9jb25kX210cnhbdmFyaWFudF9nZW5lcywgXQpjb25kX2NvbG9ycyA8LSBnZXRfY29sb3JzX2J5X2NvbmRpdGlvbih0eF9wYWlyd2lzZV9pbnB1dCwgbGV2ZWxzID0gY29sb3Jfb3JkZXIpCmRpbShpbnB1dF9tdHJ4KQpwcChmaWxlID0gIjA0aW5jbHVzaW9uX2NvbXBhcmlzb25zX3R4L3RvcF8xMDRfdmFyaWFudF9ycGttX2dlbmVzX2hlYXRtYXAucGRmIikKZ3Bsb3RzOjpoZWF0bWFwLjIoYXMubWF0cml4KGlucHV0X210cngpLCBzY2FsZSA9ICJub25lIiwgdHJhY2UgPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgIENvbFNpZGVDb2xvcnMgPSBjb25kX2NvbG9ycykKZGV2Lm9mZigpCmBgYAoKIyBUT0RPOiBDaGFuZ2UgdGhlIGFib3ZlIHRvIHN1YnRyYWN0IHd0CgpSYXNobWkgc3VnZ2VzdGVkIHdlIHNob3VsZCBkbyB0aGUgYWJvdmUgcGxvdCBhZnRlciBzdWJ0cmFjdGluZyB0aGUgd3QKY291bnRzLiAgVGhpcyBpcyBhIGdvb2QgaWRlYSwgYnV0IGl0IHdpbGwgaGF2ZSB0byB3YWl0IHVudGlsIHdlIGZpbmlzaAp0aGUgY3VycmVudCBzZXQuCgojIyBTZXQgdXAgdGhlIGNvbnRyYXN0cwoKSW4gdGhlIGZvbGxvd2luZyBmZXcgYmxvY2tzIEkgd2lsbCBzZXQgdXAgdGhlIHZhcmlvdXMgY29tcGFyaXNvbnMgb2YKaW50ZXJlc3QuICBTdGFydGluZyB3aXRoIHRoZSBzZXQgb2YgZ2VuZXMgdG8gZXhjbHVkZSBiZWNhdXNlIHRoZXkgd2VyZQpvYnNlcnZlZCB0byBiaW5kIG5vbi1zcGVjaWZpY2FsbHkgaW4gdGhlIHd0IHNhbXBsZXMuCgojIyMgSW5jbHVzaW9uIGNvbnRyYXN0cwoKSW4gZWFjaCBleGNsdXNpb24gSSB3aWxsIGhhdmUgdGhlIGNvbnRyYXN0IGZpcnN0IGZvbGxvd2VkIGJ5IHRoZSBwYWlyCm9mIGNvbnRyYXN0cyB3aGljaCB3aWxsIGJlIHVzZWQgdG8gZGVmaW5lIHRoZSBnZW5lIHNldCB0byBleGNsdWRlLgoKKiBwMTVfaGV0X2RsZ24vcDA4X2hldF9kbGduOiBwMTVfd3RfZGxnbi9wMTVfaGV0X2RsZ24sCiAgcDA4X3d0X2RsZ24vcDA4X2hldF9kbGduOyByZW1vdmUgdGhlIGdlbmVzIGluY3JlYXNlZCBpbiB3dC4KKiBwMTVfa29fc2NuL3AwOF9rb19zY246IHAxNV93dF9zY24vcDE1X2tvX3NjbiwgcDA4X3d0X3Njbi9wMTVfa29fc2NuCiogcDE1X2hldF9yZXRpbmEvcDA4X2hldF9yZXRpbmE6IEkgdGhpbmsgeW91IGdldCBpdCwgd3QvaGV0IGZvciBib3RoCiAgcDE1IHJldGluYXMgYW5kIHAwOCByZXRpbmFzLi4uCgpQdXQgc2xpZ2h0bHkgZGlmZmVyZW50bHksIGZvciBldmVyeSB0ZXJtIG9mIGludGVyZXN0IEkgd2lsbCBjcmVhdGUgYQpjb250cmFzdCB3aXRoIHRoZSB3dCBhcyBudW1lcmF0b3IgYW5kIHRoZSBkZXNpcmVkIHRlcm0gYXMgZGVub21pbmF0b3IsCnRoZW4gcHVsbCBvdXQgdGhlIGdlbmVzIGluY3JlYXNlZCBpbiB3dC4KCmBgYHtyfQppbmNsdXNpb25zIDwtIGxpc3QoCiAgIyMgSSBsaWtlIGFscGhhYmV0aXppbmcgdGhpbmdzLCBzdGFydCB3aXRoIGRsZ24KICAicDE1X2hldF9kbGduIiA9IGMoInAxNV9oZXRfZGxnbiIsICJwMTVfd3RfZGxnbiIpLAogICJwMDhfaGV0X2RsZ24iID0gYygicDA4X2hldF9kbGduIiwgInAwOF93dF9kbGduIiksCiAgInAxNV9rb19kbGduIiA9IGMoInAxNV9rb19kbGduIiwgInAxNV93dF9kbGduIiksCiAgInAwOF9rb19kbGduIiA9IGMoInAwOF9rb19kbGduIiwgInAwOF93dF9kbGduIiksCiAgIyMgVGhlbiByZXRpbmFzCiAgInAxNV9oZXRfcmV0aW5hIiA9IGMoInAxNV9oZXRfcmV0aW5hIiwgInAxNV93dF9yZXRpbmEiKSwKICAicDA4X2hldF9yZXRpbmEiID0gYygicDA4X2hldF9yZXRpbmEiLCAicDA4X3d0X3JldGluYSIpLAogICJwMTVfa29fcmV0aW5hIiA9IGMoInAxNV9rb19yZXRpbmEiLCAicDE1X3d0X3JldGluYSIpLAogICJwMDhfa29fcmV0aW5hIiA9IGMoInAwOF9rb19yZXRpbmEiLCAicDA4X3d0X3JldGluYSIpLAogICMjIFRoZW4gc2NuCiAgInAxNV9oZXRfc2NuIiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV93dF9zY24iKSwKICAicDA4X2hldF9zY24iID0gYygicDA4X2hldF9zY24iLCAicDA4X3d0X3NjbiIpLAogICJwMTVfa29fc2NuIiA9IGMoInAxNV9rb19zY24iLCAicDE1X3d0X3NjbiIpLAogICJwMDhfa29fc2NuIiA9IGMoInAwOF9rb19zY24iLCAicDA4X3d0X3NjbiIpKQpgYGAKCiMjIyBUaW1lIGNvbnRyYXN0cwoKRm9yIGVhY2ggbG9jYXRpb24vZ2Vub3R5cGUgb2YgaW50ZXJlc3QsIGxldCB1cyBjb21wYXJlIHAxNS9wMDgKCmBgYHtyfQp0aW1lX2tlZXBlcnMgPC0gbGlzdCgKICAjIyBETEdOCiAgInRfaGV0X2RsZ24iID0gYygicDE1X2hldF9kbGduIiwgInAwOF9oZXRfZGxnbiIpLAogICJ0X2tvX2RsZ24iID0gYygicDE1X2tvX2RsZ24iLCAicDA4X2tvX2RsZ24iKSwKICAjIyBSZXRpbmEKICAidF9oZXRfcmV0aW5hIiA9IGMoInAxNV9oZXRfcmV0aW5hIiwgInAwOF9oZXRfcmV0aW5hIiksCiAgInRfa29fcmV0aW5hIiA9IGMoInAxNV9rb19yZXRpbmEiLCAicDA4X2tvX3JldGluYSIpLAogICMjIFNDTgogICJ0X2hldF9zY24iID0gYygicDE1X2hldF9zY24iLCAicDA4X2hldF9zY24iKSwKICAidF9rb19zY24iID0gYygicDE1X2tvX3NjbiIsICJwMDhfa29fc2NuIikpCmBgYAoKIyMjIExvY2F0aW9uIGNvbnRyYXN0cwoKQ29tcGFyZSBsb2NhdGlvbnMgYW5kIGtlZXAgdGltZS9nZW5vdHlwZSBjb25zaXN0ZW50LiAgSSB3aWxsIHVzZSB0aGUKbG9jYXRpb24gaW5pdGlhbHMgdG8gZGVmaW5lIG51bWVyYXRvci9kZW5vbWluYXRvci4KCmBgYHtyfQpsb2NhdGlvbl9rZWVwZXJzIDwtIGxpc3QoCiAgIyMgZGxnbi9yZXRpbmEKICAiZHJfcDA4X2hldCIgPSBjKCJwMDhfaGV0X2RsZ24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAiZHJfcDE1X2hldCIgPSBjKCJwMTVfaGV0X2RsZ24iLCAicDE1X2hldF9yZXRpbmEiKSwKICAiZHJfcDA4X2tvIiA9IGMoInAwOF9rb19kbGduIiwgInAwOF9rb19yZXRpbmEiKSwKICAiZHJfcDE1X2tvIiA9IGMoInAxNV9rb19kbGduIiwgInAxNV9rb19yZXRpbmEiKSwKICAjIyBzY24vcmV0aW5hCiAgInNyX3AwOF9oZXQiID0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAic3JfcDE1X2hldCIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJzcl9wMDhfa28iID0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIiksCiAgInNyX3AxNV9rbyIgPSBjKCJwMTVfa29fc2NuIiwgInAxNV9rb19yZXRpbmEiKSwKICAjIyBkbGduL3NjbgogICJkc19wMDhfaGV0IiA9IGMoInAwOF9oZXRfZGxnbiIsICJwMDhfaGV0X3NjbiIpLAogICJkc19wMTVfaGV0IiA9IGMoInAxNV9oZXRfZGxnbiIsICJwMTVfaGV0X3NjbiIpLAogICJkc19wMDhfa28iID0gYygicDA4X2tvX2RsZ24iLCAicDA4X2tvX3NjbiIpLAogICJkc19wMTVfa28iID0gYygicDE1X2tvX2RsZ24iLCAicDE1X2tvX3NjbiIpKQpgYGAKCiMjIyBHZW5vdHlwZSBjb250cmFzdHMKCkNvbXBhcmUga28vaGV0IHdoaWxlIGtlZXBpbmcgdGltZS9sb2NhdGlvbiBjb25zdGFudC4gIFNpbWlsYXJseSwgdXNlCnRoZSBpbml0aWFscyB0byBkZW5vdGUgbnVtZXJhdG9yL2Rlbm9taW5hdG9yLCB3aGljaCB3aWxsIGFsd2F5cyBiZSBraC4KCmBgYHtyfQpnZW5vdHlwZV9rZWVwZXJzIDwtIGxpc3QoCiAgIyMgRExHTgogICJraF9wMDhfZGxnbiIgPSBjKCJwMDhfa29fZGxnbiIsICJwMDhfaGV0X2RsZ24iKSwKICAia2hfcDE1X2RsZ24iID0gYygicDE1X2tvX2RsZ24iLCAicDE1X2hldF9kbGduIiksCiAgIyMgUmV0aW5hCiAgImtoX3AwOF9yZXRpbmEiID0gYygicDA4X2tvX3JldGluYSIsICJwMDhfaGV0X3JldGluYSIpLAogICJraF9wMTVfcmV0aW5hIiA9IGMoInAxNV9rb19yZXRpbmEiLCAicDE1X2hldF9yZXRpbmEiKSwKICAjIyBTQ04KICAia2hfcDA4X3NjbiIgPSBjKCJwMDhfa29fc2NuIiwgInAwOF9oZXRfc2NuIiksCiAgImtoX3AxNV9zY24iID0gYygicDE1X2tvX3NjbiIsICJwMTVfaGV0X3NjbiIpKQpgYGAKCiMjIFBlcmZvcm0gdGhlIGV4Y2x1c2lvbiBjb21wYXJpc29uCgpNeSBhbGxfcGFpcndpc2UoKSBmdW5jdGlvbiBub3cgaGFzIGEgcGFyYW1ldGVyIHdoaWNoIGFsbG93cyBtZSB0bwpjaG9vc2Ugd2hpY2ggY29udHJhc3RzIHRvIHBlcmZvcm0gaW5zdGVhZCBvZiBsaXRlcmFsbHkgZG9pbmcgZXZlcnkKcG9zc2libGUgY29tcGFyaXNvbi4gIFRoYXQgaXMgd2VsbCBzdWl0ZWQgZm9yIHRoZXNlIG9wZXJhdGlvbnM6CgpJbiBhIGNvbnRhaW5lciwgdGhlIGZvbGxvd2luZyBhcHBlYXJzIHRvIGZhaWwgd2l0aDoKCiJlcnJvciBjb2RlIDEgZnJvbSBMYXBhY2sgcm91dGluZSAnZGdlc2RkJyIKClJ1bm5pbmcgaXQgbWFudWFsbHkgb3V0c2lkZSB0aGUgY29udGFpbmVyIHJlc3VsdHMgaW4gaXQgd29ya2luZwp3aXRob3V0IGVycm9yLiAgSSBhc3N1bWUgdGhlcmVmb3JlIHRoYXQgdGhlIHByb2JsZW0gbGllcyBpbiB0aGUKY29tcGlsYXRpb24gZmxhZ3Mgb2YgTEFQQUNLIGluIHRoZSBjb250YWluZXIuCgpOb3RlOiBUaGlzIHByb2JsZW0gd2FzIGZpeGVkIGJ5IHJlbW92aW5nIHNvbWUgcGFyYWxsZWxpemF0aW9uLgoKYGBge3J9CmluY2x1c2lvbl9kZSA8LSBhbGxfcGFpcndpc2UoCiAgdHhfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9ICJzaW1wbGUiLCBtb2RlbF9mc3RyaW5nID0gZGVmYXVsdF9mc3RyaW5nLAogIGtlZXBlcnMgPSBpbmNsdXNpb25zLCBtb2RlbF9zdnMgPSAic3Zhc2VxIikKaW5jbHVzaW9uX2RlCgppbmNsdXNpb25fdGFibGVzIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIGluY2x1c2lvbl9kZSwga2VlcGVycyA9IGluY2x1c2lvbnMsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjA0aW5jbHVzaW9uX2NvbXBhcmlzb25zX3R4L2luY2x1c2lvbl90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKaW5jbHVzaW9uX3RhYmxlcwojIyAyMDI2MDM6IEkgc3VjY2Vzc2Z1bGx5IHJlY2FwaXR1bGF0ZWQgcHJldmlvdXMgbm9uLWNvbnRhaW5lciByZXN1bHQuCgppbmNsdXNpb25fc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgaW5jbHVzaW9uX3RhYmxlcywgbGZjID0gZmlsdGVyX2xmY19jdXRvZmYsIHAgPSBmaWx0ZXJfYWRqcF9jdXRvZmYsIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgZXhjZWwgPSBnbHVlKCIwNGluY2x1c2lvbl9jb21wYXJpc29uc190eC9pbmNsdXNpb25fc2lnLXZ7dmVyfS54bHN4IikpCmluY2x1c2lvbl9zaWcKYGBgCgoyMDI1MDU6IEEgc3RyYW5nZSB0aGluZyBoYXBwZW5lZCBoZXJlIGluIHRoaXMgaXRlcmF0aW9uOiB0aGUgcGxvdCBvZgp0aGUgc2lnbmlmaWNhbnQgZ2VuZXMgaXMgdGhlIGV4YWN0IHNhbWUgYXMgdGhlIHByZXZpb3VzIGl0ZXJhdGlvbjsgYnV0CnRoZSB0YWJsZSBvZiBudW1iZXJzIG9mIGdlbmVzIGxvb2tzIGRpZmZlcmVudC4KCkZvciBleGFtcGxlLCB0aGUgcHJldmlvdXMgdGFibGUgc2hvd2VkOiBwMTVfaGV0X2RsZ24gd2l0aCAyMDY3IHVwIGFuZAoyMzgxIGRvd24uICBUaGUgcGxvdCBzaG93cyBleGFjdGx5IHRoYXQ7IGJ1dCB0aGUgbmV3IHRhYmxlIHNob3dzIDYwNwp1cCBhbmQgMTIyOSBkb3duLiAgTGV0IHVzIGNoZWNrIHRoZSBhY3R1YWwgZGF0YSBzdHJ1Y3R1cmUgYW5kIHNlZSB3aGF0CmlzIHVwPwoKSSB0aGluayBJIGdldCBpdDogd2hlbiB3ZSBkbyB0aGUgZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyBhYm92ZSwgd2UKZXhwbGljaXRseSBzZXQgYSBub24tc3RhbmRhcmQgcC12YWx1ZSBhbmQgbG9nRkMgYmVjYXVzZSB3ZSBhcmUKZXhwbGljaXRseSBhdHRlbXB0aW5nIHRvIHVzZSBhIHZlcnkgbG9vc2UgZGVmaW5pdGlvbiBvZiB0aGUgc2V0IG9mCmdlbmVzIHdoaWNoIGFyZSBpbiBncmVhdGVyIGFidW5kYW5jZSB0aGFuIHRoZWlyIG1vc3Qgc2ltaWxhcgp3aWxkLXR5cGUuIEhvd2V2ZXIsIHdoZW4gSSBjcmVhdGUgdGhlIGJhcnBsb3Qgb2Ygc2lnbmlmaWNhbnQgZ2VuZXM7CnRob3NlIHZhbHVlcyBhcmUgZXhwbGljaXRseSBzZXQgdG8gMCwxLDIgbG9nRkNzIGFuZCBwLXZhbHVlIDAuMDUuClRoZXJlZm9yZSwgd2hhdCBJIG5lZWQgdG8gZG8sIGluIG9yZGVyIHRvIGNoZWNrIGNvbnNpc3RlbmN5LCBpcyB0bwpyZXBlYXQgdGhpcyBjYWxsIGJ1dCB3aXRoIHRoZSBkZWZhdWx0IEZDL3AgdmFsdWVzIGFuZCBzZWUgd2hhdCB0aGUKbnVtYmVycyBsb29rIGxpa2UuCgpgYGB7cn0KdGVzdF9pbmNsdXNpb24gPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBpbmNsdXNpb25fdGFibGVzLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLCBleGNlbCA9ICIwNGluY2x1c2lvbl9jb21wYXJpc29uc190eC9kZWZhdWx0X2luY2x1c2lvbl9zaWcueGxzeCIpCnRlc3RfaW5jbHVzaW9uCmBgYAoKWWVhaCwgSSB0aGluayB0aGlzIG1ha2VzIHNlbnNlOyB3aGF0IEkgbmVlZCB0byBkbzogY2hhbmdlIHRoZQpzaWduaWZpY2FudCBiYXIgcGxvdCBzbyB0aGF0IGl0IHVzZXMgdGhlIGxmYyBjdXRvZmYgYXJndW1lbnQgYXMgdGhlCnNlY29uZCBvZiBpdHMgMyBjdXRvZmZzLiAgVGhhdCBzaG91bGQgZW5zdXJlIHRoYXQgdGhlc2UgbnVtYmVycyBhcmUKY29uc2lzdGVudCBhY3Jvc3MgYW5hbHlzZXMgYW5kIHBhcmFtZXRlcnMgcHJvdmlkZWQuCgpgYGB7cn0KZGltKGluY2x1c2lvbl9zaWckZGVzZXEkdXBzJHAxNV9oZXRfZGxnbikKdGVzdF9hbGxfdXAgPC0gaW5jbHVzaW9uX3RhYmxlcyRkYXRhJHAxNV9oZXRfZGxnbltbImRlc2VxX2xvZ2ZjIl1dID49IDAuMSAmCiAgaW5jbHVzaW9uX3RhYmxlcyRkYXRhJHAxNV9oZXRfZGxnbltbImRlc2VxX2FkanAiXV0gPD0gMC4xCnN1bW1hcnkodGVzdF9hbGxfdXApCmBgYAoKT2hoLCBJIGdldCBpdCwgd2hlbiBJIHdhcyB0ZXN0aW5nIHRoaXMgb3V0IG1hbnVhbGx5LCBJIHNldCB0aGUgbG9nRkMKdG8gMS4wIGluc3RlYWQgb2YgdGhlIHZlcnkgbWluaW1hbCAwLjEgd2UgaGF2ZSBiZWVuIHVzaW5nIGZvciB0aGlzIQoKIyBNQS9Wb2xjYW5vIHBsb3RzIG9mIHggdnMgd3QKClJhc2htaSBhc2tlZCB0byBzZWUgdGhlIGNvbXBhcmlzb25zIGFnYWluc3Qgd3Q7IEkgd2lsbCBuYW1lIGVhY2ggZmlsZQp4dyB0byBzaG93IHRoYXQgaXQgaXMgeCB2cyB3dC4gZm9yIHdoYXRldmVyIG90aGVyIHBhcmFtZXRlcnMgYXJlIGJlaW5nCmV4YW1pbmVkLiAgSXQgaXMgbGlrZWx5IHRoYXQgc29tZSBjb2xvcnMgd2lsbCBiZSB3cm9uZyBiZWNhdXNlIHRoaXMgaXMKbXkgZmlyc3QgdGltZSBjcmVhdGluZyB0aGVzZSBwbG90cyBhbmQgd2UgYXJlIGRvaW5nIHRoZW0gbWFudWFsbHkuCgojIyBwMTVfaGV0X2RsZ24KCmBgYHtyfQphbGxjIDwtIGNvbG9yX2Nob2ljZXNbWyJhbGwiXV0KdGFibGVfbmFtZSA8LSAicDE1X2hldF9kbGduIgp0YWJsZSA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCm51bSA8LSAicDE1X2hldF9kbGduIgpkZW5vbSA8LSAicDE1X3d0X2RsZ24iCmh3X3AxNV9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCgpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmh3X3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCgpod19wMTVfZGxnbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIG91dGxpbmUgPSBvdXRsaW5lLAogIGxhYmVsID0gMTApCgpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpod19wMTVfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKaHdfcDE1X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2hldF9kbGduCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAicDA4X2hldF9kbGduIgp0YWJsZSA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCm51bSA8LSAicDA4X2hldF9kbGduIgpkZW5vbSA8LSAicDA4X3d0X2RsZ24iCmh3X3AwOF9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYV90eC9od19wMDhfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKaHdfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKaHdfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KaHdfcDA4X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDA4X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpod19wMDhfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKaHdfcDA4X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDE1X2tvX2RsZ24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMTVfa29fZGxnbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9rb19kbGduIgpkZW5vbSA8LSAicDE1X3d0X2RsZ24iCmt3X3AxNV9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYV90eC9rd19wMTVfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDE1X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa3dfcDE1X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0Ka3dfcDE1X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDE1X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQprd19wMTVfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa3dfcDE1X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2tvX2RsZ24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMDhfa29fZGxnbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAwOF9rb19kbGduIgpkZW5vbSA8LSAicDA4X3d0X2RsZ24iCmt3X3AwOF9kbGduX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGZpbGwgPSAiYmxhY2siLAogIGNvbG9yX2xvdyA9IGFsbGNbW2Rlbm9tXV0sIGNvbG9yX2hpZ2ggPSBhbGxjW1tudW1dXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSAxMCwgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMDVpbmNsdXNpb25fdm9sY2Fub19tYV90eC9rd19wMDhfZGxnbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa3dfcDA4X2RsZ25fdm9sY2Fub1tbInBsb3QiXV0Ka3dfcDA4X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDA4X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQprd19wMDhfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa3dfcDA4X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDE1X2hldF9yZXRpbmEKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMTVfaGV0X3JldGluYSIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9oZXRfcmV0aW5hIgpkZW5vbSA8LSAicDE1X3d0X3JldGluYSIKaHdfcDE1X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKaHdfcDE1X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpod19wMTVfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmh3X3AxNV9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AxNV9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmh3X3AxNV9yZXRpbmFfbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2hldF9yZXRpbmEKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMDhfaGV0X3JldGluYSIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAwOF9oZXRfcmV0aW5hIgpkZW5vbSA8LSAicDA4X3d0X3JldGluYSIKaHdfcDA4X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDA4X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKaHdfcDA4X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpod19wMDhfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmh3X3AwOF9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDA4X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmh3X3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCmBgYAoKIyMgcDE1X2tvX3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAxNV9rb19yZXRpbmEiCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMTVfa29fcmV0aW5hIgpkZW5vbSA8LSAicDE1X3d0X3JldGluYSIKa3dfcDE1X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDE1X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDE1X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQprd19wMTVfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmt3X3AxNV9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDE1X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmt3X3AxNV9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmt3X3AxNV9yZXRpbmFfbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2tvX3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAwOF9rb19yZXRpbmEiCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfa29fcmV0aW5hIgpkZW5vbSA8LSAicDA4X3d0X3JldGluYSIKa3dfcDA4X3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDA4X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDA4X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQprd19wMDhfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmt3X3AwOF9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDA4X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmt3X3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmt3X3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCmBgYAoKIyMgcDE1X2hldF9zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMTVfaGV0X3NjbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAxNV9oZXRfc2NuIgpkZW5vbSA8LSAicDE1X3d0X3NjbiIKaHdfcDE1X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKaHdfcDE1X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpod19wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCmh3X3AxNV9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDE1X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AxNV9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmh3X3AxNV9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2hldF9zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJwMDhfaGV0X3NjbiIKdGFibGUgPC0gaW5jbHVzaW9uX3RhYmxlc1tbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpudW0gPC0gInAwOF9oZXRfc2NuIgpkZW5vbSA8LSAicDA4X3d0X3NjbiIKaHdfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDA4X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKaHdfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpod19wMDhfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCmh3X3AwOF9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgvaHdfcDA4X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmh3X3AwOF9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmh3X3AwOF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDE1X2tvX3NjbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAxNV9rb19zY24iCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMTVfa29fc2NuIgpkZW5vbSA8LSAicDE1X3d0X3NjbiIKa3dfcDE1X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDE1X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDE1X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQprd19wMTVfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCmt3X3AxNV9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDE1X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmt3X3AxNV9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmt3X3AxNV9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMgcDA4X2tvX3NjbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInAwOF9rb19zY24iCnRhYmxlIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KbnVtIDwtICJwMDhfa29fc2NuIgpkZW5vbSA8LSAicDA4X3d0X3NjbiIKa3dfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLCBmaWxsID0gImJsYWNrIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDA4X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa3dfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQprd19wMDhfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCmt3X3AwOF9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBhbGxjW1tkZW5vbV1dLCBjb2xvcl9oaWdoID0gYWxsY1tbbnVtXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBvdXRsaW5lID0gb3V0bGluZSwKICBsYWJlbCA9IDEwKQpwcChmaWxlID0gIjA1aW5jbHVzaW9uX3ZvbGNhbm9fbWFfdHgva3dfcDA4X3Njbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmt3X3AwOF9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmt3X3AwOF9zY25fbWFbWyJwbG90Il1dCmBgYAoKU2VlIHRoZSBzaGFyZWQvdW5pcXVlIGdlbmVzIGluIHRoZXNlIHNldHMuCgpgYGB7cn0KaW5jbHVzaW9uX3Vwc2V0cyA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcpCmluY2x1c2lvbl9pbnRlcnNlY3RzIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcygKICBpbmNsdXNpb25fdXBzZXRzLCBleGNlbCA9ICIwNGluY2x1c2lvbl9jb21wYXJpc29uX3R4L2luY2x1c2lvbl9nZW5lX2dyb3Vwcy54bHN4IikKYGBgCgojIyMgRXh0cmFjdCBnZW5lcyBpbmNsdWRlZCBmb3IgZWFjaCBzZXQgb2YgY29udHJhc3RzCgpOb3csIHVzaW5nIHRoYXQgZnVuY3Rpb24sIHB1bGwgb3V0IHRoZSBnZW5lIElEcyBvZiBnZW5lcyB3ZSBkbyBub3QKdHJ1c3QgYmVjYXVzZSB0aGV5IHdlcmUgdG9vIGhpZ2ggaW4gd3QgZm9yIGV2ZXJ5IGNvbnRyYXN0IHdlIGFyZQpsaWtlbHkgdG8gcGVyZm9ybS4KClRoZSBmb2xsb3dpbmcgd2FzIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiB0aGUgaW5jbHVzaW9uIGZ1bmN0aW9uIHdoaWNoIGlzIHNvbWV3aGF0IG1vcmUgcmVzdHJpY3RpdmUuCgpgYGB7cn0KZXh0cmFjdF9pbmNsdXNpb25zX3N0cmljdCA8LSBmdW5jdGlvbihpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLCBrZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbF9nZW5lcywgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwgd2hpY2ggPSAidXBzIikgewogIHJldGxpc3QgPC0gbGlzdCgpCiAgdGFibGVfbmFtZXMgPC0gbmFtZXMoaW5jbHVzaW9uX3NpZ1tbYWNjb3JkaW5nX3RvXV1bW3doaWNoXV0pCiAgZm9yIChjX251bSBpbiBzZXFfYWxvbmcoa2VlcGVycykpIHsKICAgIGNvbnRyYXN0IDwtIG5hbWVzKGtlZXBlcnMpW2NfbnVtXQogICAgbnVtZXJhdG9yX25hbWUgPC0ga2VlcGVyc1tbY19udW1dXVsxXQogICAgZGVub21pbmF0b3JfbmFtZSA8LSBrZWVwZXJzW1tjX251bV1dWzJdCiAgICAjIyBJbiBteSBuZXcgYnJhbmNoIEkgY2xlYW5lZCB1cCB0aGUgc2FuaXRpemVyIGZ1bmN0aW9uIGZvciBjb250cmFzdHMgc28gdGhpcyBpcyBub3QgbmVlZGVkLgogICAgIyMgVGhlIGZvbGxvd2luZyB0d28gbGluZXMgYXJlIG5vIGxvbmdlciBuZWVkZWQgYmVjYXVzZSBvZiB0aGUgY2xlYW51cHMgSSBwZXJmb3JtZWQuCiAgICAjI251bWVyYXRvcl9uYW1lIDwtIGdzdWIoeCA9IG51bWVyYXRvcl9uYW1lLCBwYXR0ZXJuID0gIihoZXR8a298d3QpIiwgcmVwbGFjZW1lbnQgPSAiX1xcMV8iKQogICAgIyNkZW5vbWluYXRvcl9uYW1lIDwtIGdzdWIoeCA9IGRlbm9taW5hdG9yX25hbWUsIHBhdHRlcm4gPSAiKGhldHxrb3x3dCkiLCByZXBsYWNlbWVudCA9ICJfXFwxXyIpCiAgICBudW1lcmF0b3JfdGFibGUgPC0gaW5jbHVzaW9uX3NpZ1tbYWNjb3JkaW5nX3RvXV1bW3doaWNoXV1bW251bWVyYXRvcl9uYW1lXV0KICAgIG51bWVyYXRvcl9nZW5lcyA8LSByb3duYW1lcyhudW1lcmF0b3JfdGFibGUpCiAgICBkZW5vbWluYXRvcl90YWJsZSA8LSBpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXVtbZGVub21pbmF0b3JfbmFtZV1dCiAgICBkZW5vbWluYXRvcl9nZW5lcyA8LSByb3duYW1lcyhkZW5vbWluYXRvcl90YWJsZSkKICAgIGRmX2NvbHVtbnMgPC0gcGFzdGUwKCJkZXNlcV8iLCBjKCJsb2dmYyIsICJhZGpwIiwgImRlbiIpKQogICAgaW5jbHVkZWRfbnVtIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1tudW1lcmF0b3JfbmFtZV1dWywgZGZfY29sdW1uc10KICAgIGNvbG5hbWVzKGluY2x1ZGVkX251bSkgPC0gYygibnVtZXJhdG9yX3ZzX3d0X2xvZ2ZjIiwgIm51bWVyYXRvcl92c193dF9hZGpwIiwgIm51bV93dF9tZWFuX2V4cHJzIikKICAgIGluY2x1ZGVkX2RlbiA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbZGVub21pbmF0b3JfbmFtZV1dWywgZGZfY29sdW1uc10KICAgIGNvbG5hbWVzKGluY2x1ZGVkX2RlbikgPC0gYygiZGVub21pbmF0b3JfdnNfd3RfbG9nZmMiLCAiZGVub21pbmF0b3JfdnNfd3RfYWRqcCIsICJkZW5fd3RfbWVhbl9leHBycyIpCiAgICAjIyBJIHRoaW5rIHRoaXMgaXMgd2hlcmUgdGhpbmdzIHdlbnQgd3JvbmcsCiAgICAjIyBjb21wYXJlIHRoaXMgbW9kaWZpZWQgbGluZSB0byB0aGUgb3JpZ2luYWwgdG8gcHJvdmUgaXQuCiAgICBpbmNsdWRlZF9kZiA8LSBtZXJnZShpbmNsdWRlZF9udW0sIGluY2x1ZGVkX2RlbiwgYnkgPSAicm93Lm5hbWVzIikKICAgICMjIFByZXZpb3VzbHksIEkgZGlkIG5vdCBzcGVjaWZ5IHRoZSBtZXJnZSBhY3Rpb24sIGFsbCA9IEZBTFNFIGJ5IGRlZmF1bHQuCiAgICAjIyBUaGlzIHRoZW4gd2lsbCByZXN1bHQgaW4gYSBkaWZmZXJlbmNlIGluIHRoZSByb3dzIG9ic2VydmVkCiAgICAjIyBpbmNsdWRlZF9kZiA8LSBtZXJnZShpbmNsdWRlZF9udW0sIGluY2x1ZGVkX2RlbiwgYnkgPSAicm93Lm5hbWVzIiwgYWxsID0gRkFMU0UpCiAgICByb3duYW1lcyhpbmNsdWRlZF9kZikgPC0gaW5jbHVkZWRfZGZbWyJSb3cubmFtZXMiXV0KICAgIGluY2x1ZGVkX2RmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKICAgIGNvbmNhdGVuYXRlZF9nZW5lcyA8LSBjKG51bWVyYXRvcl9nZW5lcywgZGVub21pbmF0b3JfZ2VuZXMpCiAgICBib3RoX2dlbmVfaWR4IDwtIGR1cGxpY2F0ZWQoY29uY2F0ZW5hdGVkX2dlbmVzKQogICAgZ2VuZXNfaW5fYm90aCA8LSBjb25jYXRlbmF0ZWRfZ2VuZXNbYm90aF9nZW5lX2lkeF0KICAgIG1lc3NhZ2UoIlRoZSBzZXQgb2YgdW5pcXVlIGdlbmVzIGhpZ2hlciBpbiAiLCBudW1lcmF0b3JfbmFtZSwKICAgICAgICAgICAgIiB2cy4gd3QgaXMgIiwgbGVuZ3RoKG51bWVyYXRvcl9nZW5lcyksICIuIikKICAgIG1lc3NhZ2UoIlRoZSBzZXQgb2YgdW5pcXVlIGdlbmVzIGhpZ2hlciBpbiAiLCBkZW5vbWluYXRvcl9uYW1lLAogICAgICAgICAgICAiIHZzLiB3dCBpcyAiLCBsZW5ndGgoZGVub21pbmF0b3JfZ2VuZXMpLCAiLiIpCiAgICBtZXNzYWdlKCJUaGUgaW50ZXJzZWN0aW9uIG9mIHRoZW0gaXMgIiwgbGVuZ3RoKGdlbmVzX2luX2JvdGgpLCAiIGdlbmVzLiIpCiAgICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgY29udHJhc3QpCiAgICBpbmNsdWRlX2lkeCA8LSBhbGxfZ2VuZXMgJWluJSBnZW5lc19pbl9ib3RoCiAgICBpbmNsdWRlX2dlbmVzIDwtIGFsbF9nZW5lc1tpbmNsdWRlX2lkeF0KICAgIGRmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBjb250cmFzdCkKICAgIHJldGxpc3RbW2RmX25hbWVdXSA8LSBpbmNsdWRlZF9kZgogICAgd3JpdHRlbl9pbmNsdXNpb24gPC0gd3JpdGVfeGxzeCgKICAgICAgZGF0YSA9IGluY2x1ZGVkX2RmLAogICAgICBleGNlbCA9IGdsdWUoIjA3aW5jbHVkZWRfc3RyaWN0X2dlbmVzX2V4Y2VsX3R4L3tpbmNsdWRlX25hbWV9LXZ7dmVyfS54bHN4IikpCiAgICByZXRsaXN0W1tpbmNsdWRlX25hbWVdXSA8LSBpbmNsdWRlX2dlbmVzCiAgICByZXRsaXN0W1tjb250cmFzdF1dIDwtIGluY2x1ZGVfZ2VuZXMKICB9CiAgcmV0dXJuKHJldGxpc3QpCn0KYGBgCgpUaGlzIGlzIHRoZSBwcmUtMjAyNTA1IHZlcnNpb24gb2YgdGhpcyBmdW5jdGlvbi4KCmBgYHtyfQpleHRyYWN0X2luY2x1c2lvbnMgPC0gZnVuY3Rpb24oaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywga2VlcGVycywgYWxsX2dlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwgd2hpY2ggPSAidXBzIikgewogIHJldGxpc3QgPC0gbGlzdCgpCiAgdGFibGVfbmFtZXMgPC0gbmFtZXMoaW5jbHVzaW9uX3NpZ1tbYWNjb3JkaW5nX3RvXV1bW3doaWNoXV0pCiAgZm9yIChjX251bSBpbiBzZXFfYWxvbmcoa2VlcGVycykpIHsKICAgIGNvbnRyYXN0IDwtIG5hbWVzKGtlZXBlcnMpW2NfbnVtXQogICAgbnVtZXJhdG9yX25hbWUgPC0ga2VlcGVyc1tbY19udW1dXVsxXQogICAgZGVub21pbmF0b3JfbmFtZSA8LSBrZWVwZXJzW1tjX251bV1dWzJdCiAgICAjIyBJbiBteSBuZXcgYnJhbmNoIEkgY2xlYW5lZCB1cCB0aGUgc2FuaXRpemVyIGZ1bmN0aW9uIGZvciBjb250cmFzdHMgc28gdGhpcyBpcyBub3QgbmVlZGVkLgogICAgIyMgVGhlIGZvbGxvd2luZyB0d28gbGluZXMgYXJlIG5vIGxvbmdlciBuZWVkZWQgYmVjYXVzZSBvZiB0aGUgY2xlYW51cHMgSSBwZXJmb3JtZWQuCiAgICAjI251bWVyYXRvcl9uYW1lIDwtIGdzdWIoeCA9IG51bWVyYXRvcl9uYW1lLCBwYXR0ZXJuID0gIihoZXR8a298d3QpIiwgcmVwbGFjZW1lbnQgPSAiX1xcMV8iKQogICAgIyNkZW5vbWluYXRvcl9uYW1lIDwtIGdzdWIoeCA9IGRlbm9taW5hdG9yX25hbWUsIHBhdHRlcm4gPSAiKGhldHxrb3x3dCkiLCByZXBsYWNlbWVudCA9ICJfXFwxXyIpCiAgICBudW1lcmF0b3JfdGFibGUgPC0gaW5jbHVzaW9uX3NpZ1tbYWNjb3JkaW5nX3RvXV1bW3doaWNoXV1bW251bWVyYXRvcl9uYW1lXV0KICAgIG51bWVyYXRvcl9nZW5lcyA8LSByb3duYW1lcyhudW1lcmF0b3JfdGFibGUpCiAgICBkZW5vbWluYXRvcl90YWJsZSA8LSBpbmNsdXNpb25fc2lnW1thY2NvcmRpbmdfdG9dXVtbd2hpY2hdXVtbZGVub21pbmF0b3JfbmFtZV1dCiAgICBkZW5vbWluYXRvcl9nZW5lcyA8LSByb3duYW1lcyhkZW5vbWluYXRvcl90YWJsZSkKICAgIGRmX2NvbHVtbnMgPC0gcGFzdGUwKCJkZXNlcV8iLCBjKCJsb2dmYyIsICJhZGpwIiwgImRlbiIpKQogICAgaW5jbHVkZWRfbnVtIDwtIGluY2x1c2lvbl90YWJsZXNbWyJkYXRhIl1dW1tudW1lcmF0b3JfbmFtZV1dWywgZGZfY29sdW1uc10KICAgIGNvbG5hbWVzKGluY2x1ZGVkX251bSkgPC0gYygibnVtZXJhdG9yX3ZzX3d0X2xvZ2ZjIiwgIm51bWVyYXRvcl92c193dF9hZGpwIiwgIm51bV93dF9tZWFuX2V4cHJzIikKICAgIGluY2x1ZGVkX2RlbiA8LSBpbmNsdXNpb25fdGFibGVzW1siZGF0YSJdXVtbZGVub21pbmF0b3JfbmFtZV1dWywgZGZfY29sdW1uc10KICAgIGNvbG5hbWVzKGluY2x1ZGVkX2RlbikgPC0gYygiZGVub21pbmF0b3JfdnNfd3RfbG9nZmMiLCAiZGVub21pbmF0b3JfdnNfd3RfYWRqcCIsICJkZW5fd3RfbWVhbl9leHBycyIpCiAgICBpbmNsdWRlZF9kZiA8LSBtZXJnZShpbmNsdWRlZF9udW0sIGluY2x1ZGVkX2RlbiwgYnkgPSAicm93Lm5hbWVzIikKICAgIHJvd25hbWVzKGluY2x1ZGVkX2RmKSA8LSBpbmNsdWRlZF9kZltbIlJvdy5uYW1lcyJdXQogICAgaW5jbHVkZWRfZGZbWyJSb3cubmFtZXMiXV0gPC0gTlVMTAogICAgaW5jbHVkZV9nZW5lcyA8LSB1bmlxdWUoYyhudW1lcmF0b3JfZ2VuZXMsIGRlbm9taW5hdG9yX2dlbmVzKSkKICAgIG1lc3NhZ2UoIlRoZSBzZXQgb2YgdW5pcXVlIGdlbmVzIGhpZ2hlciBpbiAiLCBudW1lcmF0b3JfbmFtZSwKICAgICAgICAgICAgIiB2cy4gd3QgaXMgIiwgbGVuZ3RoKG51bWVyYXRvcl9nZW5lcyksICIuIikKICAgIG1lc3NhZ2UoIlRoZSBzZXQgb2YgdW5pcXVlIGdlbmVzIGhpZ2hlciBpbiAiLCBkZW5vbWluYXRvcl9uYW1lLAogICAgICAgICAgICAiIHZzLiB3dCBpcyAiLCBsZW5ndGgoZGVub21pbmF0b3JfZ2VuZXMpLCAiLiIpCiAgICBtZXNzYWdlKCJUaGUgdW5pcXVlIHVuaW9uIG9mIHRoZW0gaXMgIiwgbGVuZ3RoKGluY2x1ZGVfZ2VuZXMpLCAiIGdlbmVzLiIpCiAgICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgY29udHJhc3QpCiAgICBpbmNsdWRlX2lkeCA8LSBhbGxfZ2VuZXMgJWluJSBpbmNsdWRlX2dlbmVzCiAgICBpbmNsdWRlX2dlbmVzIDwtIGFsbF9nZW5lc1tpbmNsdWRlX2lkeF0KICAgIGRmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBjb250cmFzdCkKICAgIHJldGxpc3RbW2RmX25hbWVdXSA8LSBpbmNsdWRlZF9kZgogICAgd3JpdHRlbl9pbmNsdXNpb24gPC0gd3JpdGVfeGxzeChkYXRhID0gaW5jbHVkZWRfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gZ2x1ZSgiMDdpbmNsdWRlZF9nZW5lc190eC97aW5jbHVkZV9uYW1lfS12e3Zlcn0ueGxzeCIpKQogICAgcmV0bGlzdFtbaW5jbHVkZV9uYW1lXV0gPC0gaW5jbHVkZV9nZW5lcwogICAgcmV0bGlzdFtbY29udHJhc3RdXSA8LSBpbmNsdWRlX2dlbmVzCiAgfQogIHJldHVybihyZXRsaXN0KQp9CmBgYAoKIyAnTm9ybWFsJyBJbmNsdXNpb24gZXh0cmFjdGlvbgoKSGVyZSBpcyB0aGUgZnVsbCBzZXQgb2YgZ2VuZSBJRHMKCmBgYHtyfQphbGxfZ2VuZXMgPC0gcm93bmFtZXMoYXNzYXkodHhfcGFpcndpc2VfaW5wdXQpKQpgYGAKCkluIHRoZSBmb2xsb3dpbmcgYmxvY2tzIEkgYW0gaW5jbHVkaW5nIHRoZSB1bmlvbiBvZiBnZW5lcyBvYnNlcnZlZApoaWdoZXIgdGhhbiB3dCBpbiBlaXRoZXIgb2YgdGhlIG51bWVyYXRvciBvciBkZW5vbWluYXRvciBmb3IgZWFjaApjb250cmFzdC4KCiMjIFRpbWUKCmBgYHtyfQp0aW1lX2luY2x1c2lvbnMgPC0gZXh0cmFjdF9pbmNsdXNpb25zKGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyMgTG9jYXRpb24KCmBgYHtyfQpsb2NhdGlvbl9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhdGlvbl9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyMgR2Vub3R5cGUKCmBgYHtyfQpnZW5vdHlwZV9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5vdHlwZV9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyBUaGUgc3RyaWN0ICdpbmNsdXNpb24nIHNldAoKIyMgVGltZQoKYGBge3J9CnRpbWVfaW5jbHVzaW9uc19zdHJpY3QgPC0gZXh0cmFjdF9pbmNsdXNpb25zX3N0cmljdChpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyMgTG9jYXRpb24KCmBgYHtyfQpsb2NhdGlvbl9pbmNsdXNpb25zX3N0cmljdCA8LSBleHRyYWN0X2luY2x1c2lvbnNfc3RyaWN0KGluY2x1c2lvbl9zaWcsIGluY2x1c2lvbl90YWJsZXMsIGluY2x1c2lvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fa2VlcGVycywgYWxsX2dlbmVzKQpgYGAKCiMjIEdlbm90eXBlCgpgYGB7cn0KZ2Vub3R5cGVfaW5jbHVzaW9uc19zdHJpY3QgPC0gZXh0cmFjdF9pbmNsdXNpb25zX3N0cmljdChpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbm90eXBlX2tlZXBlcnMsIGFsbF9nZW5lcykKYGBgCgojIyMgQ2hlY2sgdnMgVGhlcmVzYSdzIGZpbHRlcgoKVXAgYWJvdmUgVGhlcmVzYSBwZXJmb3JtZWQgYSAwLjI1IGxvZzJGQyBhbmQgMC4wNSBhZGpwIGZpbHRlciB3aGljaApwcm92aWRlZCBhIHNldCBvZiAyLDY0MCBnZW5lcyBvYnNlcnZlZCBoaWdoZXIgaW4gdGhlIHAwOCBoZXQgcmV0aW5hcwp2cy4gd3QgcmV0aW5hcy4gIEkgc2hvdWxkIHNlZSB0aGF0IGluIHRoaXMgaW5jbHVzaW9uX3NpZyBkYXRhIHN0cnVjdHVyZS4KClRoZXJlIGlzIGFuIGltcG9ydGFudCBjYXZlYXQgdGhvdWdoOiBpbiBUaGVyZXNhJ3MgZmlsdGVyIGFib3ZlLCBzaGUKZGlkIGEgREUgb2YgX29ubHlfIHRoZSByZXRpbmEgc2FtcGxlcyBidXQgSSBkaWQgYWxsIHNhbXBsZXMuICBJCmV4cGVjdGVkIHRoYXQgdGhpcyB3b3VsZCByZXN1bHQgaW4gYmFzaWNhbGx5IHRoZSBzYW1lIHJlc3VsdCAoSQphY3R1YWxseSBhc3N1bWVkIEkgd291bGQgZ2V0IGEgZmV3IG1vcmUgZ2VuZXMpLCBidXQgaW5zdGVhZCBpdCBhcHBlYXJzCnRvIGhhdmUgcmV0cmlldmVkIGEgc2lnbmlmaWNhbnRseSBzbWFsbGVyIG51bWJlciBvZiBnZW5lcyAoYWJvdXQgMS8yLApoYXBwaWx5IHRoZXkgcHJldHR5IG11Y2ggYWxsIGFwcGVhciBpbiB0aGUgcHJldmlvdXMgZmlsdGVyKS4gIEFzIGEKcmVzdWx0LCBJIGFtIGdvaW5nIHRvIHRyeSByZWxheGluZyBteSBjb25zdHJhaW50cyBzbGlnaHRseSB0byBzZWUgaWYgSQpjYW4gcmVjYXBpdHVsYXRlIGhlciBmaWx0ZXIgKHdoaWNoIHdvdWxkIG1hdGNoIFRoZXJlc2EncyBsYXRlciBmaWx0ZXIsCnRob3VnaCBJIGd1ZXNzIHRoYXQgaW4gdHVybiB3aWxsIGxlYWQgdG8gYSBzbWFsbGVyIHNldCBvZiBnZW5lcwpjb21wYXJlZCB0byBoZXIgbGF0ZXIsIHJlbGF4ZWQgMC4xIGZpbHRlcikuCgpgYGB7cn0KY29tcGFyaXNvbiA8LSBpbmNsdXNpb25fc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJwMDhfaGV0X3JldGluYSJdXQpjb21wIDwtIGxpc3QoCiAgInRhYSIgPSB0YWFfa2VlcGVycywKICAibmV3IiA9IHJvd25hbWVzKGNvbXBhcmlzb24pKQp0ZXN0X2NvbXBhcmlzb24gPC0gVmVubmVyYWJsZTo6VmVubihjb21wKQpWZW5uZXJhYmxlOjpwbG90KHRlc3RfY29tcGFyaXNvbikKYGBgCgpJIHdhbnQgdG8gaGF2ZSBhIGxpdHRsZSBmdW5jdGlvbiB3aGljaCwgZ2l2ZW4gYSBjb250cmFzdCBvZiBpbnRlcmVzdCwKd2lsbCBleHRyYWN0IHRoZSBnZW5lIHNldHMgd2hpY2ggc2hvdWxkIGJlIGluY2x1ZGVkL2V4Y2x1ZGVkIGdpdmVuIHRoZQphYm92ZS4KCmBgYHtyfQp3cml0ZV9hbGxfY3AgPC0gZnVuY3Rpb24oYWxsX2NwLCBwcmVmaXggPSAiMTIiLCBzdWZmaXggPSAiIikgewogIGFsbF93cml0dGVuIDwtIGxpc3QoKQogIGZvciAoZyBpbiBzZXFfbGVuKGxlbmd0aChhbGxfY3ApKSkgewogICAgbmFtZSA8LSBuYW1lcyhhbGxfY3ApW2ddCiAgICBkYXR1bSA8LSBhbGxfY3BbW25hbWVdXQogICAgZmlsZW5hbWUgPC0gZ2x1ZSgie3ByZWZpeH1lbnJpY2htZW50X2V4Y2VsX3R4L3tuYW1lfV9jcHJvZmlsZXJ7c3VmZml4fS12e3Zlcn0ueGxzeCIpCiAgICB3cml0dGVuIDwtIHNtKHdyaXRlX2NwX2RhdGEoZGF0dW0sIGV4Y2VsID0gZmlsZW5hbWUpKQogICAgYWxsX3dyaXR0ZW5bW2ddXSA8LSB3cml0dGVuCiAgfQogIHJldHVybihhbGxfd3JpdHRlbikKfQp3cml0ZV9hbGxfZ3AgPC0gZnVuY3Rpb24oYWxsX2dwLCBwcmVmaXggPSAiMTMiLCBzdWZmaXggPSAiIikgewogIGFsbF93cml0dGVuIDwtIGxpc3QoKQogIGZvciAoZyBpbiBzZXFfbGVuKGxlbmd0aChhbGxfZ3ApKSkgewogICAgbmFtZSA8LSBuYW1lcyhhbGxfZ3ApW2ddCiAgICBkYXR1bSA8LSBhbGxfZ3BbW25hbWVdXQogICAgZmlsZW5hbWUgPC0gZ2x1ZSgie3ByZWZpeH1lbnJpY2htZW50X2V4Y2VsX3R4L3tuYW1lfV9ncHJvZmlsZXJ7c3VmZml4fS12e3Zlcn0ueGxzeCIpCiAgICB3cml0dGVuIDwtIHNtKHdyaXRlX2dwcm9maWxlcl9kYXRhKGRhdHVtLCBleGNlbCA9IGZpbGVuYW1lKSkKICAgIGFsbF93cml0dGVuW1tnXV0gPC0gd3JpdHRlbgogIH0KICByZXR1cm4oYWxsX3dyaXR0ZW4pCn0Kd3JpdGVfYWxsX2VuIDwtIGZ1bmN0aW9uKGFsbF9lbiwgcHJlZml4ID0gIjE0Iiwgc3VmZml4ID0gIiIpIHsKICBhbGxfd3JpdHRlbiA8LSBsaXN0KCkKICBmb3IgKGUgaW4gc2VxX2xlbihsZW5ndGgoYWxsX2VuKSkpIHsKICAgIG5hbWUgPC0gbmFtZXMoYWxsX2VuKVtlXQogICAgZGF0dW0gPC0gYWxsX2VuW1tuYW1lXV0KICAgIGZpbGVuYW1lIDwtIGdsdWUoIntwcmVmaXh9ZW5yaWNobWVudF9leGNlbF90eC97bmFtZX1fZW5yaWNoZXJ7c3VmZml4fS12e3Zlcn0ueGxzeCIpCiAgICB3cml0dGVuIDwtIHNtKHdyaXRlX2VucmljaGVyX2RhdGEoZGF0dW0sIGV4Y2VsID0gZmlsZW5hbWUpKQogICAgYWxsX3dyaXR0ZW5bW2VdXSA8LSB3cml0dGVuCiAgfQogIHJldHVybihhbGxfd3JpdHRlbikKfQpgYGAKCiMjIyBFeHRyYWN0IGdlbmVzIGluY2x1ZGVkIGZvciBlYWNoIHNldCBvZiBjb250cmFzdHMKCk5vdywgdXNpbmcgdGhhdCBmdW5jdGlvbiwgcHVsbCBvdXQgdGhlIGdlbmUgSURzIG9mIGdlbmVzIHdlIGRvIG5vdAp0cnVzdCBiZWNhdXNlIHRoZXkgd2VyZSB0b28gaGlnaCBpbiB3dCBmb3IgZXZlcnkgY29udHJhc3Qgd2UgYXJlCmxpa2VseSB0byBwZXJmb3JtLgoKYGBge3J9CmFsbF9nZW5lcyA8LSByb3duYW1lcyhhc3NheSh0eF9wYWlyd2lzZV9pbnB1dCkpCnRpbWVfaW5jbHVzaW9ucyA8LSBleHRyYWN0X2luY2x1c2lvbnMoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2tlZXBlcnMsIGFsbF9nZW5lcykKbG9jYXRpb25faW5jbHVzaW9ucyA8LSBleHRyYWN0X2luY2x1c2lvbnMoaW5jbHVzaW9uX3NpZywgaW5jbHVzaW9uX3RhYmxlcywgaW5jbHVzaW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYXRpb25fa2VlcGVycywgYWxsX2dlbmVzKQpnZW5vdHlwZV9pbmNsdXNpb25zIDwtIGV4dHJhY3RfaW5jbHVzaW9ucyhpbmNsdXNpb25fc2lnLCBpbmNsdXNpb25fdGFibGVzLCBpbmNsdXNpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5vdHlwZV9rZWVwZXJzLCBhbGxfZ2VuZXMpCmBgYAoKIyMgUGVyZm9ybSB0aGUgREUgYW5hbHlzZXMgYW5kIGV4Y2x1ZGUgdGhlIHRhcmdldCBnZW5lcwoKCiMjIyBHZW5vdHlwZQoKYGBge3J9Cmdlbm90eXBlX2RlIDwtIGFsbF9wYWlyd2lzZSh0eF9wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfZnN0cmluZyA9IGRlZmF1bHRfZnN0cmluZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBnZW5vdHlwZV9rZWVwZXJzLCBtb2RlbF9zdnMgPSAic3Zhc2VxIikKZ2Vub3R5cGVfZGUKYGBgCgojIyMgTG9jYXRpb24KCmBgYHtyfQpsb2NhdGlvbl9kZSA8LSBhbGxfcGFpcndpc2UodHhfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsIG1vZGVsX2ZzdHJpbmcgPSBkZWZhdWx0X2ZzdHJpbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gbG9jYXRpb25fa2VlcGVycywgbW9kZWxfc3ZzID0gInN2YXNlcSIpCmxvY2F0aW9uX2RlCmBgYAoKIyMjIFRpbWUKCmBgYHtyfQp0aW1lX2RlIDwtIGFsbF9wYWlyd2lzZSh0eF9wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwgbW9kZWxfZnN0cmluZyA9IGRlZmF1bHRfZnN0cmluZywKICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHRpbWVfa2VlcGVycywgbW9kZWxfc3ZzID0gInN2YXNlcSIpCnRpbWVfZGUKYGBgCgpJdCBpcyBuZWFyIGhlcmUgd2hlbiB0aGUgY29tcHV0ZXIgc29tZXRpbWVzIGZhaWxzIHdpdGggbm8gbW9yZQp0ZW1wZmlsZXMuICBJbiBhbm90aGVyIHdpbmRvdyBJIGFtIG1lc3Npbmcgd2l0aCB0ZW1wZmlsZSgpIGluIFIgdG8gdHJ5CnRvIHVuZGVyc3RhbmQgd2hlcmUgaXQgaXMgZ29pbmcgb2ZmIHRoZSByYWlscy4uLgoKIyMgRXh0cmFjdCB0aGUgcmVsZXZhbnQgdGFibGVzIGFuZCBpbmNsdWRlIGdlbmVzIGxvd2VyIGluIHd0CgojIyMgR2Vub3R5cGUgY29udHJhc3RzCgpJIHdpbGwgc3RhcnQgd2l0aCB0aGUgdGFibGVzIGFuZCBubyBpbmNsdXNpb25zIHNvIEkgY2FuIGNoZWNrIG15IHdvcmsuCgpJbiB0aGlzIGZpcnN0IGJsb2NrIEkgd2lsbCBleHBsYWluIGEgbGl0dGxlIG1vcmUgdGhvcm91Z2hseSB3aGF0IGlzCmdvaW5nIG9uOgoKMS4gIER1bXAgdGhlIGZ1bGwgdGFibGUgb2YgdGhlIGNvbnRyYXN0cyBJIGRlZmluZWQgYWJvdmUgY29tcGFyaW5nIHRoZQogICAgMyBnZW5vdHlwZXMgYWNyb3NzIHRpbWUvbG9jYXRpb24uCjIuICBJdGVyYXRlIG92ZXIgZWFjaCBvZiB0aG9zZSBjb250cmFzdHMgYW5kIGRvIHRoZSBmb2xsb3dpbmc6CiAgICBhLiAgRXh0cmFjdCB0aGUgbmFtZSBvZiB0aGUgY29udHJhc3QsICdraF9wMDhfZGxnbicgZm9yIGV4YW1wbGUKICAgIGIuICBZYW5rIG91dCB0aGF0IHNwZWNpZmljIGVudHJ5IGZyb20gdGhlIGtlZXBlciBsaXN0IGFuZCBpdHMgbmFtZQogICAgYy4gIFlhbmsgb3V0IHRoZSBjb3JyZXNwb25kaW5nIHNldCBvZiBnZW5lcyB0byBpbmNsdWRlIGZyb20gdGhlCiAgICAgICAgaW5jbHVzaW9ucyBkYXRhIHN0cnVjdHVyZS4KICAgIGQuICBDcmVhdGUgYSBmaWxlbmFtZSBnaXZlbiB0aGUgbmFtZSBpbiAoYSkgYWJvdmUgYW5kIHRoZSBsb2dGQwogICAgICAgIGN1dG9mZiBjaG9zZW4gZm9yIHRoZSBpbmNsdXNpb25zIChJIGFtIGFzc3VtaW5nIHdlIG1heSBjaGFuZ2UKICAgICAgICB0aGlzKQogICAgZS4gIEdpdmVuIChiKSwgKGMpLCBhbmQgKGQpLCBleHRyYWN0IHRoZSBjb3JyZXNwb25kaW5nIHRhYmxlIGZyb20KICAgICAgICB0aGUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgYW5kIGluY2x1ZGUgdGhlIGFwcHJvcHJpYXRlCiAgICAgICAgZ2VuZXMuCgogICAgRklYTUU6IG15IGdwcm9maWxlciBmdW5jdGlvbiBqdXN0IGFzc3VtZXMgaHVtYW4gYW5kIHNvIGlmIHBhc3NlZCBtbXVzY3VsdXMgd2lsbCBpbmNvcnJlY3RseQogICAgYXR0ZW1wdCB0byBjb25uZWN0IHRvIG5vbi1leGlzdGFudCBkYXRhYmFzZXMuICBMZXQgdXMgZml4IHRoYXQgbm93LgoKYGBge3J9Cmdlbm90eXBlX3RhYmxlc19mdWxsIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIGdlbm90eXBlX2RlLCBrZWVwZXJzID0gZ2Vub3R5cGVfa2VlcGVycywgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogIGZhbmN5ID0gVFJVRSwKICBleGNlbCA9IGdsdWUoIjA4ZnVsbF9jb250cmFzdHNfZXhjZWxfdHgvZ2Vub3R5cGVfZnVsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKZ2Vub3R5cGVfdGFibGVzX2Z1bGwKZ2Vub3R5cGVfc2lnX2Z1bGwgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBnZW5vdHlwZV90YWJsZXNfZnVsbCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoIjA4ZnVsbF9jb250cmFzdHNfZXhjZWxfdHgvZ2Vub3R5cGVfZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKZ2Vub3R5cGVfc2lnX2Z1bGwKYGBgCgojIyMgU2VhcmNoIEVucmljaG1lbnQgb2YgdGhlc2Ugc2V0cwoKSW4gdGhpcyBydW4sIHdlIHdpbGwgc2VhcmNoIHRoZSBmdWxsIHNldCBvZiBnZW5lcywgbmV4dCB3ZSB3aWxsIG9ubHkKZG8gdGhlIGluY2x1c2lvbnMuCgpgYGB7cn0KZ2Vub3R5cGVfZnVsbF9ncCA8LSBhbGxfZ3Byb2ZpbGVyKGdlbm90eXBlX3NpZ19mdWxsLCBzcGVjaWVzID0gIm1tdXNjdWx1cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIwOWZ1bGxfY29udHJhc3RzX2VucmljaF90eC9nZW5vdHlwZV9mdWxsX2dwcm9maWxlci54bHN4IikKZ2Vub3R5cGVfZnVsbF9jcCA8LSBhbGxfY3Byb2ZpbGVyKGdlbm90eXBlX3NpZ19mdWxsLCBnZW5vdHlwZV90YWJsZXNfZnVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGdvX2xldmVsID0gZ29fbGV2ZWwsIG9yZ2FuaXNtID0gIm1vdXNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLCBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsID0gIjA5ZnVsbF9jb250cmFzdHNfZW5yaWNoX3R4L2dlbm90eXBlX2Z1bGxfY3Byb2ZpbGVyLnhsc3giKQpnZW5vdHlwZV9mdWxsX3Vwc2V0IDwtIHVwc2V0cl9zaWcoZ2Vub3R5cGVfc2lnX2Z1bGwpCmdlbm90eXBlX2Z1bGxfaW50ZXJzZWN0cyA8LSB3cml0ZV91cHNldF9ncm91cHMoZ2Vub3R5cGVfZnVsbF91cHNldCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbCA9ICIwOWZ1bGxfY29udHJhc3RzX2ludGVyc2VjdGlvbnNfdHgvZ2Vub3R5cGVfZnVsbF9nZW5lX2dyb3Vwcy54bHN4IikKYGBgCgpOb3cgc2VwYXJhdGUgdGhlIHZhcmlvdXMgZ2Vub3R5cGUgdGFibGVzIGFuZCBwZXJmb3JtIHRoZSBpbmNsdXNpb25zIG9mCnRoZSBnZW5lcyB3aXRoIHJlbGF0aXZlbHkgbG93IHd0IHZhbHVlcy4KCiMjIyMgRXh0cmFjdCBmaWx0ZXJlZCBnZW5lcyBhbmQgcGFzcyB0byBncHJvZmlsZXIyL2NsdXN0ZXJwcm9maWxlcgoKYGBge3J9Cmdlbm90eXBlX3RhYmxlcyA8LSBsaXN0KCkKZ2Vub3R5cGVfc2lnIDwtIGxpc3QoKQpnZW5vdHlwZV9ncCA8LSBsaXN0KCkKZ2Vub3R5cGVfY3AgPC0gbGlzdCgpCmdlbm90eXBlX2VuIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKGdlbm90eXBlX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhnZW5vdHlwZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBnZW5vdHlwZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjEwZ2Vub3R5cGVfY29udHJhc3RzX2V4Y2VsX3R4L3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiMTBnZW5vdHlwZV9jb250cmFzdHNfZXhjZWxfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgZ2Vub3R5cGVfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBnZW5vdHlwZV9kZSwgZXh0cmFfYW5ub3QgPSBpbmNsdWRlX2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlcykKICBwcmludChnZW5vdHlwZV90YWJsZXNbW25hbWVdXSkKICBnZW5vdHlwZV9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgZ2Vub3R5cGVfdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KGdlbm90eXBlX3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3coZ2Vub3R5cGVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+PSAxMCkgewogICAgbWVzc2FnZSgiUGVyZm9ybWluZyBncHJvZmlsZXIvY2x1c3RlclByb2ZpbGVyLiIpCiAgICBnZW5vdHlwZV9ncFtbbmFtZV1dIDwtIGFsbF9ncHJvZmlsZXIoZ2Vub3R5cGVfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGdlbm90eXBlX2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgZ2Vub3R5cGVfc2lnW1tuYW1lXV0sIGdlbm90eXBlX3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICAgICAgZ29fbGV2ZWwgPSBnb19sZXZlbCwgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgICNpZiAoIWlzLm51bGwoZ2V0MCgibTJfZ3NjIikpKSB7CiAgICAjICBnZW5vdHlwZV9lbltbbmFtZV1dIDwtIGFsbF9lbnJpY2hlcihnZW5vdHlwZV9zaWdbW25hbWVdXSwgZ3NjID0gbTJfZ3NjLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgZnJvbSA9ICJFTlNFTUJMIiwgdG8gPSAiU1lNQk9MIikKICAgICN9CiAgICBncF93cml0dGVuIDwtIHdyaXRlX2FsbF9ncChnZW5vdHlwZV9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMTEiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AoZ2Vub3R5cGVfY3BbW25hbWVdXSwgcHJlZml4ID0gIjExIikKICAgICNlbl93cml0dGVuIDwtIHdyaXRlX2FsbF9lbihnZW5vdHlwZV9lbltbbmFtZV1dKQogIH0gZWxzZSB7CiAgICB3YXJuaW5nKCJUaGVyZSBhcmUgbGVzcyB0aGFuIDEwIGdlbmVzIHVwIGFuZCBkb3duIGluIHRoZSAiLCBuYW1lLCAiIGNvbXBhcmlzb24uIikKICAgIG1lc3NhZ2UoIlRoZXJlIGFyZSBsZXNzIHRoYW4gMTAgZ2VuZXMgdXAgYW5kIGRvd24gaW4gdGhlICIsIG5hbWUsICIgY29tcGFyaXNvbi4iKQogIH0KfQpgYGAKClBsb3QgdGhlIHJlc3VsdHMgc2VwYXJhdGVseS4KCmBgYHtyfQpmb3IgKGsgaW4gc2VxX2Fsb25nKGdlbm90eXBlX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhnZW5vdHlwZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBnZW5vdHlwZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBudW1fcm93cyA8LSBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhnZW5vdHlwZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogICMjICMxIGlzIHVwIGFuZCAjMiBpcyBkb3duLCBhdm9pZGluZyB0eXBlb3MgaGVyZS4KICBudW1fb2JqZWN0cyA8LSBsZW5ndGgoZ2Vub3R5cGVfY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIHdlbnQgd3JvbmcgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKGdlbm90eXBlX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhnZW5vdHlwZV9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfZG93biQiKSkKICAgIGlmIChsZW5ndGgodXBwKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIGdlbm90eXBlX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBnZW5vdHlwZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnKQogICAgICBtZl90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfbWZfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGNjX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9jY19zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfYnBfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogICAgaWYgKGxlbmd0aChkb3ducCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBnZW5vdHlwZV9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gZ2Vub3R5cGVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIGdlbm90eXBlX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTJjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fbWZfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGNjX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxMmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9jY19zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBjYXRlb2dvcmllcyA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjEyY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2JwX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKQSBmZXcgc3BlY2lmaWMgcGxvdHMgb2YgaW50ZXJlc3Q6IENvbGVuc28gYXNrZWQgdG8gbGFiZWwgYSBmZXcgZ2VuZXMKZm9yIHRoZSBrbm9ja291dC9oZXQgcDA4X3JldGluYXMsIHAwOF9zY24sIGFuZCBwMDhfZGxnbjogZWl0aGVyIHRoZQp0b3AtMTUgb3IgYWxsIHNpZ25pZmljYW50LiAgSSBhbSBwcmV0dHkgc3VyZSBpZiBJIHRlbGwgaXQgMTUgYW5kIHRoZXJlCmFyZSBub3QgdGhhdCBtYW55LCBpdCB3aWxsIGp1c3QgZG8gdGhlIHNpZ25pZmljYW50PyAgTGV0IHVzIGZpbmQgb3V0IQoKIyMjIyBrby9oZXQgZm9yIHAwOCByZXRpbmFzCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDA4X3JldGluYSIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmcgPC0gYygiT3BuNCIsICJHbTkwMDgiLCAiTHJyMSIsICJDbmJkMSIpCmtoX3AwOF9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwKICBsYWJlbF9jb2x1bW4gPSB0eF9sYWJlbF9jb2x1bW4sIGxhYmVsID0gaW50ZXJlc3RpbmcsIGFscGhhID0gMS4wLAogIG91dGxpbmUgPSBvdXRsaW5lLCBzaXplID0gNCkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDA4X3JldGluYV92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCmtoX3AwOF9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgb3V0bGluZSA9IG91dGxpbmUsCiAgbGFiZWwgPSBpbnRlcmVzdGluZykKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDA4X3JldGluYV9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AwOF9yZXRpbmFfbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBrby9oZXQgcDA4IFNDTgoKSSBhbSBnb2luZyB0byBtYWtlIGFuIGV4ZWN1dGl2ZSBkZWNpc2lvbiBmb3IgdGhpcyBwbG90LCAxNSBpcyB0b28gbWFueQphbmQgbWFrZXMgaXQgY3JhenkgY2x1dHRlcmVkLgoKIyMjIFJlcGVhdCB0aGlzIHdpdGggdHdvIHNldHMgb2YgZ2VuZXMKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMDhfc2NuIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKCJGaWduIiwgIk5ybjEiLCAiRHB5c2wyIiwgIkFjdGIiLCAiRmdmOSIsICJPdHgyIiwgIlNlYzIzIiwKICAgICAgICAgICAgICAgICAgICAgICAiTmNhbTEiLCAiTWFwNCIsICJTZWMyMmIiLCAiTmxnbjMiLCAiTWFyY2tzIiwgIkNkNDciLAogICAgICAgICAgICAgICAgICAgICAgICJEcHlzbDMiLCAiTGluN2MiLCAiQ2FkbTEiLCAiU254MTIiLCAiUmhvYSIsICJJbnBwNWYiLAogICAgICAgICAgICAgICAgICAgICAgICJBdGcxMiIsICJTZXQiLCAiR3NrM2IiLCAiUGRjZDQiLCAiR2FicmEyIiwgIlRtY28xIiwgIkFuYXBjMTYiKQpraF9wMDhfc2NuX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCwKICBvdXRsaW5lID0gb3V0bGluZSwgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDA4X3Njbl92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCiMjIHdoeSBpbiB0aGUgY3JhcCBpcyBpdCBkb3VibGUtbGFiZWxsaW5nIT8KIyMgTXkgTUEgcGxvdHRlciBpc24ndCBhcyBzbWFydCBhcyB0aGUgdm9sY2FubyBwbG90dGVyLCB0aGUgZ2VuZXMgYXJlOgpraF9wMDhfc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBvdXRsaW5lID0gb3V0bGluZSwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fub190eC9raF9wMDhfc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X3Njbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDA4X3Njbl9tYVtbInBsb3QiXV0KYGBgCgojIyMjIFNhbWUgcGxvdCBidXQgYSBkaWZmZXJlbnQgc2V0IG9mIGxhYmVsZWQgZ2VuZXMKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMDhfc2NuIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKAogICJBbmFwYzE2IiwgIkdhYnJhMiIsICJUbWNvMSIsICJTb2QyIiwgIkZnZjkiLCAiUGRjZDQiLCAiUmhvYSIsICJHc2szYiIsICJGb3hwMSIsCiAgIk5jYW0xIiwgIk1hcmNrcyIsICJGaWduIiwgIkRweXNsMyIsICJJbnBwNWYiLCAiQ2FkbTEiLCAiTWFwNCIsICJVZ2NnIiwgIkVsb3ZsNCIsCiAgIkVsYXZsMSIsICJDZmwyIiwgIlRubnQxIiwgIkduYjEiLCAiSW1wYWN0IiwgIk5ybjEiLCAiTmxnbjMiLCAiQWN0YiIsICJDZDQ3IiwKICAiU2VjMjJiIiwgIlNsYzE3YTciLCAiVmdsdXQxIiwgIkFjdGIiLCAiQjRnYWx0NSIsICJGb3hwMSIsICJPdHgyIiwgIkxpbjdjIiwKICAiU254MTIiLCAiQXRnMTIiLCAiU2V0IikKa2hfcDA4X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBzaXplID0gNCwgYWxwaGEgPSAxLjApCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AwOF9zY25fdm9sY2Fub192Mi5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AwOF9zY25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDA4X3Njbl92b2xjYW5vW1sicGxvdCJdXQojIyB3aHkgaW4gdGhlIGNyYXAgaXMgaXQgZG91YmxlLWxhYmVsbGluZyE/CiMjIE15IE1BIHBsb3R0ZXIgaXNuJ3QgYXMgc21hcnQgYXMgdGhlIHZvbGNhbm8gcGxvdHRlciwgdGhlIGdlbmVzIGFyZToKa2hfcDA4X3Njbl9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcykKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDA4X3Njbl9tYV92Mi5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AwOF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBrby9oZXQgcDA4IGRMR04KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMDhfZGxnbiIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0Ka2hfcDA4X2RsZ25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19kbGduIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X2RsZ24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IDEwLCBzaXplID0gNCwgYWxwaGEgPSAxLjApCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AwOF9kbGduX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMDhfZGxnbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMDhfZGxnbl92b2xjYW5vW1sicGxvdCJdXQojIyBNeSBNQSBwbG90dGVyIGlzbid0IGFzIHNtYXJ0IGFzIHRoZSB2b2xjYW5vIHBsb3R0ZXIsIHRoZSBnZW5lcyBhcmU6CmtoX3AwOF9kbGduX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fZGxnbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9kbGduIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSAxMCwgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AwOF9kbGduX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDA4X2RsZ25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AwOF9kbGduX21hW1sicGxvdCJdXQoKYGBgCgojIyMjIGtvL2hldCBmb3IgcDE1IHJldGluYXMKCldoZW4gbGFzdCBJIHJhbiB0aGlzIG1hbnVhbGx5LCBpdCBkaWQgbm90IGRvdWJsZS1sYWJlbCwgaG9wZWZ1bGx5IHRoYXQKcmVtYWlucyB0cnVlIGluIHRoZSBjb250YWluZXIuCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDE1X3JldGluYSIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmcgPC0gYygiT3BuNCIsICJHbTkwMDgiLCAiTHJyMSIsICJDbmJkMSIpCmtoX3AxNV9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgZmlsbCA9ICJibGFjayIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZywgYWxwaGEgPSAxLjAsCiAgb3V0bGluZSA9IG91dGxpbmUsIHNpemUgPSA0KQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fub190eC9raF9wMTVfcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0KIyMgd2h5IGluIHRoZSBjcmFwIGlzIGl0IGRvdWJsZS1sYWJlbGxpbmchPwojIyBNeSBNQSBwbG90dGVyIGlzbid0IGFzIHNtYXJ0IGFzIHRoZSB2b2xjYW5vIHBsb3R0ZXIsIHRoZSBnZW5lcyBhcmU6CmtoX3AxNV9yZXRpbmFfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AxNV9yZXRpbmFfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfcmV0aW5hX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpraF9wMTVfcmV0aW5hX21hW1sicGxvdCJdXQpgYGAKCiMjIyMga28vaGV0IHAxNSBTQ04KCiMjIyBSZXBlYXQgdGhpcyB3aXRoIHR3byBzZXRzIG9mIGdlbmVzCgpgYGB7cn0KdGFibGVfbmFtZSA8LSAia2hfcDE1X3NjbiIKdGFibGVfaW5wdXQgPC0gZ2Vub3R5cGVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmdfZ2VuZXMgPC0gYygiRmlnbiIsICJOcm4xIiwgIkRweXNsMiIsICJBY3RiIiwgIkZnZjkiLCAiT3R4MiIsICJTZWMyMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIk5jYW0xIiwgIk1hcDQiLCAiU2VjMjJiIiwgIk5sZ24zIiwgIk1hcmNrcyIsICJDZDQ3IiwKICAgICAgICAgICAgICAgICAgICAgICAiRHB5c2wzIiwgIkxpbjdjIiwgIkNhZG0xIiwgIlNueDEyIiwgIlJob2EiLCAiSW5wcDVmIiwKICAgICAgICAgICAgICAgICAgICAgICAiQXRnMTIiLCAiU2V0IiwgIkdzazNiIiwgIlBkY2Q0IiwgIkdhYnJhMiIsICJUbWNvMSIsICJBbmFwYzE2IikKa2hfcDE1X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBzaXplID0gNCwgYWxwaGEgPSAxLjAsCiAgb3V0bGluZSA9IG91dGxpbmUsIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0pCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AxNV9zY25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AxNV9zY25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3Njbl92b2xjYW5vW1sicGxvdCJdXQpraF9wMTVfc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fub190eC9raF9wMTVfc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KYGBgCgpSb3VuZCAyIHdpdGggYSBzZXBhcmF0ZSBnZW5lIHNldC4KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJraF9wMTVfc2NuIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKAogICJBbmFwYzE2IiwgIkdhYnJhMiIsICJUbWNvMSIsICJTb2QyIiwgIkZnZjkiLCAiUGRjZDQiLCAiUmhvYSIsICJHc2szYiIsICJGb3hwMSIsCiAgIk5jYW0xIiwgIk1hcmNrcyIsICJGaWduIiwgIkRweXNsMyIsICJJbnBwNWYiLCAiQ2FkbTEiLCAiTWFwNCIsICJVZ2NnIiwgIkVsb3ZsNCIsCiAgIkVsYXZsMSIsICJDZmwyIiwgIlRubnQxIiwgIkduYjEiLCAiSW1wYWN0IiwgIk5ybjEiLCAiTmxnbjMiLCAiQWN0YiIsICJDZDQ3IiwKICAiU2VjMjJiIiwgIlNsYzE3YTciLCAiVmdsdXQxIiwgIkFjdGIiLCAiQjRnYWx0NSIsICJGb3hwMSIsICJPdHgyIiwgIkxpbjdjIiwKICAiU254MTIiLCAiQXRnMTIiLCAiU2V0IikKa2hfcDE1X3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3NjbiJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgb3V0bGluZSA9IG91dGxpbmUsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBzaXplID0gNCwgYWxwaGEgPSAxLjApCnBwKGZpbGUgPSAiMTNnZW5vdHlwZV9tYV92b2xjYW5vX3R4L2toX3AxNV9zY25fdm9sY2Fub192Mi5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AxNV9zY25fdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3Njbl92b2xjYW5vW1sicGxvdCJdXQpraF9wMTVfc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fc2NuIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjEzZ2Vub3R5cGVfbWFfdm9sY2Fub190eC9raF9wMTVfc2NuX21hX3YyLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X3Njbl9tYVtbInBsb3QiXV0KYGBgCgojIyMjIGtvL2hldCBwMTUgZExHTgoKYGBge3J9CnRhYmxlX25hbWUgPC0gImtoX3AxNV9kbGduIgp0YWJsZV9pbnB1dCA8LSBnZW5vdHlwZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpraF9wMTVfZGxnbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfZGxnbiJdXSwKICBvdXRsaW5lID0gb3V0bGluZSwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gMTAsIHNpemUgPSA0LCBhbHBoYSA9IDEuMCkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDE1X2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCmtoX3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmtoX3AxNV9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCiMjIE15IE1BIHBsb3R0ZXIgaXNuJ3QgYXMgc21hcnQgYXMgdGhlIHZvbGNhbm8gcGxvdHRlciwgdGhlIGdlbmVzIGFyZToKa2hfcDE1X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19kbGduIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X2RsZ24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IDEwLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIxM2dlbm90eXBlX21hX3ZvbGNhbm9fdHgva2hfcDE1X2RsZ25fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpraF9wMTVfZGxnbl9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKa2hfcDE1X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKQSBxdWVyeSBmcm9tIFJhc2htaToKCiJJIHdhcyBkaXNjdXNzaW5nIHdpdGggRHIuIFNwZWVyIGFib3V0IHRoZSBkTEdOIGRhdGEgYW5kIHdlIGZvdW5kIG1vc3RseQpyZXRpbmFsIGdlbmVzIGluIGRMR04gSGV0L0tPIG9yIHRpbWUgcG9pbnQgY29tcGFyaXNvbi4gUGxlYXNlIGNoZWNrIGlmCnRob3NlIGFyZSBub3QgcmV0aW5hIHNhbXBsZXMuIgoKSSBjaGVja2VkIHRoZSBzYW1wbGVzIGV0YyBhbmQgZXZlcnl0aGluZyBsb29rcyBvayB0byBtZTsgcGVyaGFwcyBJIGNhbgp1c2UgdGhlIHJlc3VsdHMgdG8gbG9vayBhdCB0aGlzIHF1ZXN0aW9uIGluIGFub3RoZXIgd2F5OgoKSSB3aWxsIHRoZXJlZm9yZSBsb2FkIHRoZSBwMDhfaGV0X2RsZ24vcDA4X2tvX2RsZ24gdGFibGUgYW5kIGNvbXBhcmUKaXQgdG8gdGhlIHAwOF9oZXRfcmV0aW5hL3AwOF9rb19yZXRpbmEgdGFibGUgZGlyZWN0bHkuICBJIHRoaW5rIHRoYXQKaWYgdGhlc2UgdHVybiBvdXQgdG8gYmUgaWRlbnRpY2FsLCB0aGVuIHRoZSBoeXBvdGhlc2lzIHN1Z2dlc3RlZCBieQp0aGlzIHF1ZXJ5IGlzIGNvcnJlY3QuCgpOb3RlLCBpbiBvcmRlciB0byBkbyB0aGlzLCBJIG11c3QgdXNlIHRoZSBmdWxsIHRhYmxlcywgbm90IHRoZQpwb3N0LWluY2x1c2lvbiB0YWJsZXMgYmVjYXVzZSBJIGNhbm5vdCBndWFyYW50ZWUgdGhhdCB0aGV5IHdpbGwgaGF2ZQppZGVudGljYWwgZ2VuZSBJRHMuCgpgYGB7cn0KcmV0aW5hX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AwOF9yZXRpbmEiXV0KZGxnbl90YWJsZSA8LSBnZW5vdHlwZV90YWJsZXNfZnVsbFtbImRhdGEiXV1bWyJraF9wMDhfZGxnbiJdXQpyZXRpbmFfc3Vic2V0IDwtIHJldGluYV90YWJsZVssIGMoImVuc2VtYmxfZ2VuZV9pZCIsICJkZXNlcV9sb2dmYyIpXQpjb2xuYW1lcyhyZXRpbmFfc3Vic2V0KSA8LSBjKCJJRCIsICJyZXRpbmFfbG9nZmMiKQpkbGduX3N1YnNldCA8LSBkbGduX3RhYmxlWywgYygiZW5zZW1ibF9nZW5lX2lkIiwgImRlc2VxX2xvZ2ZjIildCmNvbG5hbWVzKGRsZ25fc3Vic2V0KSA8LSBjKCJJRCIsICJkbGduX2xvZ2ZjIikKbWVyZ2VkIDwtIG1lcmdlKHJldGluYV9zdWJzZXQsIGRsZ25fc3Vic2V0LCBieSA9ICJJRCIpCnJvd25hbWVzKG1lcmdlZCkgPC0gbWFrZS5uYW1lcyhtZXJnZWRbWyJJRCJdXSwgdW5pcXVlID0gVFJVRSkKbWVyZ2VkW1siSUQiXV0gPC0gTlVMTApwbG90dGVkIDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIobWVyZ2VkKQpwcChmaWxlID0gImltYWdlc190eC9raF9wMDhfcmV0aW5hX3ZzX2RsZ25fZGVzZXFfbG9nZmNfdmFsdWVzLnBuZyIpCnBsb3R0ZWRbWyJzY2F0dGVyIl1dCmRldi5vZmYoKQpwbG90dGVkW1sic2NhdHRlciJdXQpgYGAKClJhc2htaSBhc2tlZCBpZiB3ZSBjb3VsZCBhbHNvIGRvIHRoZSBwMTUgZm9yIHRoaXMgY29tcGFyaXNvbjoKCmBgYHtyfQpyZXRpbmFfdGFibGUgPC0gZ2Vub3R5cGVfdGFibGVzX2Z1bGxbWyJkYXRhIl1dW1sia2hfcDE1X3JldGluYSJdXQpkbGduX3RhYmxlIDwtIGdlbm90eXBlX3RhYmxlc19mdWxsW1siZGF0YSJdXVtbImtoX3AxNV9kbGduIl1dCnJldGluYV9zdWJzZXQgPC0gcmV0aW5hX3RhYmxlWywgYygiZW5zZW1ibF9nZW5lX2lkIiwgImRlc2VxX2xvZ2ZjIildCmNvbG5hbWVzKHJldGluYV9zdWJzZXQpIDwtIGMoIklEIiwgInJldGluYV9sb2dmYyIpCmRsZ25fc3Vic2V0IDwtIGRsZ25fdGFibGVbLCBjKCJlbnNlbWJsX2dlbmVfaWQiLCAiZGVzZXFfbG9nZmMiKV0KY29sbmFtZXMoZGxnbl9zdWJzZXQpIDwtIGMoIklEIiwgImRsZ25fbG9nZmMiKQptZXJnZWQgPC0gbWVyZ2UocmV0aW5hX3N1YnNldCwgZGxnbl9zdWJzZXQsIGJ5ID0gIklEIikKcm93bmFtZXMobWVyZ2VkKSA8LSBtYWtlLm5hbWVzKG1lcmdlZFtbIklEIl1dLCB1bmlxdWUgPSBUUlVFKQptZXJnZWRbWyJJRCJdXSA8LSBOVUxMCnBsb3R0ZWQgPC0gcGxvdF9saW5lYXJfc2NhdHRlcihtZXJnZWQpCnBwKGZpbGUgPSAiaW1hZ2VzX3R4L2toX3AxNV9yZXRpbmFfdnNfZGxnbl9kZXNlcV9sb2dmY192YWx1ZXMucG5nIikKcGxvdHRlZFtbInNjYXR0ZXIiXV0KZGV2Lm9mZigpCnBsb3R0ZWRbWyJzY2F0dGVyIl1dCmBgYAoKIyMjIyBSZXBlYXQgd2l0aCB0aGUgc3RyaWN0IGZpbHRlcgoKYGBge3J9Cmdlbm90eXBlX3N0cmljdF90YWJsZXMgPC0gbGlzdCgpCmdlbm90eXBlX3N0cmljdF9zaWcgPC0gbGlzdCgpCmdlbm90eXBlX3N0cmljdF9ncCA8LSBsaXN0KCkKZ2Vub3R5cGVfc3RyaWN0X2NwIDwtIGxpc3QoKQpnZW5vdHlwZV9zdHJpY3RfZW4gPC0gbGlzdCgpCmZvciAoayBpbiBzZXFfYWxvbmcoZ2Vub3R5cGVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGdlbm90eXBlX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGdlbm90eXBlX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfc3RyaWN0X2RmIDwtIGdlbm90eXBlX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzX3N0cmljdCA8LSBnZW5vdHlwZV9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGdlbm90eXBlX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlc19zdHJpY3QpCiAgaW5jbHVkZV9maWxlbmFtZSA8LSBnbHVlKCIxNGdlbm90eXBlX3N0cmljdF9jb250cmFzdHNfZXhjZWxfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3RhYmxlLXZ7dmVyfS54bHN4IikKICBpbmNsdWRlX3NpZ19maWxlbmFtZSA8LSBnbHVlKCIxNGdlbm90eXBlX3N0cmljdF9jb250cmFzdHNfZXhjZWxfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgZ2Vub3R5cGVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgZ2Vub3R5cGVfZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9zdHJpY3RfZGYsCiAgICBrZWVwZXJzID0ga2VlcGVyLCBsYWJlbF9jb2x1bW4gPSB0eF9sYWJlbF9jb2x1bW4sCiAgICBleGNlbCA9IGluY2x1ZGVfZmlsZW5hbWUsIHdhbnRlZF9nZW5lcyA9IGluY2x1ZGVzX3N0cmljdCkKICBwcmludChnZW5vdHlwZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0pCiAgZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMoCiAgICBnZW5vdHlwZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3coZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+PSAxMCkgewogICAgbWVzc2FnZSgiUGVyZm9ybWluZyBncHJvZmlsZXIvY2x1c3RlclByb2ZpbGVyLiIpCiAgICBnZW5vdHlwZV9zdHJpY3RfZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXSwgc3BlY2llcyA9ICJtbXVzY3VsdXMiKQogICAgZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dLCBnZW5vdHlwZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0sCiAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGdvX2xldmVsID0gZ29fbGV2ZWwsCiAgICAgIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLCBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSwgb3JnYW5pc20gPSAibW91c2UiKQogICAgI2lmICghaXMubnVsbChnZXQwKCJtMl9nc2MiKSkpIHsKICAgICMgIGdlbm90eXBlX3N0cmljdF9lbltbbmFtZV1dIDwtIGFsbF9lbnJpY2hlcihnZW5vdHlwZV9zdHJpY3Rfc2lnW1tuYW1lXV0sIGdzYyA9IG0yX2dzYywKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIGZyb20gPSAiRU5TRU1CTCIsIHRvID0gIlNZTUJPTCIpCiAgICAjfQogICAgZ3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfZ3AoZ2Vub3R5cGVfc3RyaWN0X2dwW1tuYW1lXV0sIHByZWZpeCA9ICIxNSIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogICAgY3Bfd3JpdHRlbiA8LSB3cml0ZV9hbGxfY3AoZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV0sIHByZWZpeCA9ICIxNSIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogICAgI2VuX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2VuKGdlbm90eXBlX3N0cmljdF9lbltbbmFtZV1dKQogIH0gZWxzZSB7CiAgICB3YXJuaW5nKCJUaGVyZSBhcmUgbGVzcyB0aGFuIDEwIGdlbmVzIHVwIGFuZCBkb3duIGluIHRoZSAiLCBuYW1lLCAiIGNvbXBhcmlzb24uIikKICAgIG1lc3NhZ2UoIlRoZXJlIGFyZSBsZXNzIHRoYW4gMTAgZ2VuZXMgdXAgYW5kIGRvd24gaW4gdGhlICIsIG5hbWUsICIgY29tcGFyaXNvbi4iKQogIH0KfQpgYGAKCiMgR2Vub3R5cGUgU3RyaWN0IHBsb3RzCgpgYGB7cn0KZm9yIChrIGluIHNlcV9hbG9uZyhnZW5vdHlwZV9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXMoZ2Vub3R5cGVfa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gZ2Vub3R5cGVfa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9zdHJpY3RfZGYgPC0gZ2Vub3R5cGVfaW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXNfc3RyaWN0IDwtIGdlbm90eXBlX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX25hbWVdXQogIHN1bW1hcnkocm93bmFtZXMoZ2Vub3R5cGVfc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzX3N0cmljdCkKICBudW1fcm93cyA8LSBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3coZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG5yb3coZ2Vub3R5cGVfc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkKICBucm93KGdlbm90eXBlX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICAjIyAjMSBpcyB1cCBhbmQgIzIgaXMgZG93biwgYXZvaWRpbmcgdHlwZW9zIGhlcmUuCiAgbnVtX29iamVjdHMgPC0gbGVuZ3RoKGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dKQogIGlmIChudW1fb2JqZWN0cyA9PSAwKSB7CiAgICB3YXJuaW5nKCJTb21ldGhpbmcgd2VudCB3cm9uZyBpbiBhbGxfY3Byb2ZpbGVyLiIpCiAgfSBlbHNlIHsKICAgIHVwcCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXMoZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXSksIHBhdHRlcm4gPSAiX2Rvd24kIikpCiAgICBpZiAobGVuZ3RoKHVwcCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSBnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX21mX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfY2Nfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2JwX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICAgIGlmIChsZW5ndGgoZG93bnApID4gMCkgewogICAgICBtZl9zaWcgPC0gZ2Vub3R5cGVfc3RyaWN0X2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSBnZW5vdHlwZV9zdHJpY3RfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIGdlbm90eXBlX3N0cmljdF9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KG1mX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgbWZfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjE2Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX21mX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoY2Nfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBjY190cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTZjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fY2Nfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgY2F0ZW9nb3JpZXMgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxNmNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9icF9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogIH0KfQpgYGAKCkdpdmVuIHRoaXMgc3RyaWN0ZXIgZmlsdGVyLCBJIHRoaW5rIG5vIGdlbmVzIHBhc3MgaW4gdGhlIGdlbm9tZQpjb21wYXJpc29ucy4KCiMjIyBMb2NhdGlvbiBjb250cmFzdHMgd2l0aCBnZW5lcyByZW1vdmVkL2tlcHQKCldlIHdpbGwgbm93IHJlcGVhdCB0aGUgYWJvdmUgdGFza3Mgc2Vla2luZyBsb2NhdGlvbiBkaWZmZXJlbmNlcwppbnN0ZWFkIG9mIGdlbm90eXBlOyBlc3NlbnRpYWxseSBJIGNvcHkvcGFzdGVkIHRoZSBhYm92ZSB3aXRoCnMvZ2Vub3R5cGUvbG9jYXRpb24vZy4KCmBgYHtyfQpsb2NhdGlvbl90YWJsZXNfZnVsbCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBsb2NhdGlvbl9kZSwga2VlcGVycyA9IGxvY2F0aW9uX2tlZXBlcnMsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjE3ZnVsbF9sb2NhdGlvbl9jb250cmFzdHNfdHgvbG9jYXRpb25fZnVsbF90YWJsZXMtdnt2ZXJ9Lnhsc3giKSkKbG9jYXRpb25fdGFibGVzX2Z1bGwKbG9jYXRpb25fc2lnX2Z1bGwgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICBsb2NhdGlvbl90YWJsZXNfZnVsbCwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICBleGNlbCA9IGdsdWUoIjE3ZnVsbF9sb2NhdGlvbl9jb250cmFzdHNfdHgvbG9jYXRpb25fZnVsbF9zaWctdnt2ZXJ9Lnhsc3giKSkKbG9jYXRpb25fc2lnX2Z1bGwKbG9jYXRpb25fZnVsbF91cHNldCA8LSB1cHNldHJfc2lnKGxvY2F0aW9uX3NpZ19mdWxsKQpsb2NhdGlvbl9mdWxsX2ludGVyc2VjdHMgPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKAogIGxvY2F0aW9uX2Z1bGxfdXBzZXQsCiAgZXhjZWwgPSAiZXhjZWwvMTdmdWxsX2xvY2F0aW9uX2NvbnRyYXN0c190eC9sb2NhdGlvbl9mdWxsX2dlbmVfZ3JvdXBzLnhsc3giKQpgYGAKCmBgYHtyfQpsb2NhdGlvbl90YWJsZXMgPC0gbGlzdCgpCmxvY2F0aW9uX3NpZyA8LSBsaXN0KCkKbG9jYXRpb25fZ3AgPC0gbGlzdCgpCmxvY2F0aW9uX2NwIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKGxvY2F0aW9uX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhsb2NhdGlvbl9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBsb2NhdGlvbl9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZXMgPC0gbG9jYXRpb25faW5jbHVzaW9uc1tbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gbG9jYXRpb25faW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBzdW1tYXJ5KHJvd25hbWVzKGxvY2F0aW9uX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjE4bG9jYXRpb25fY29udHJhc3RzX3R4L3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF90YWJsZS12e3Zlcn0ueGxzeCIpCiAgaW5jbHVkZV9zaWdfZmlsZW5hbWUgPC0gZ2x1ZSgiMThsb2NhdGlvbl9jb250cmFzdHNfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgbG9jYXRpb25fdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICBsb2NhdGlvbl9kZSwgZXh0cmFfYW5ub3QgPSBpbmNsdWRlX2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlcykKICBwcmludChsb2NhdGlvbl90YWJsZXNbW25hbWVdXSkKICBsb2NhdGlvbl9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgbG9jYXRpb25fdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KGxvY2F0aW9uX3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3cobG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+IDEwKSB7CiAgICBsb2NhdGlvbl9ncFtbbmFtZV1dIDwtIGFsbF9ncHJvZmlsZXIobG9jYXRpb25fc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGxvY2F0aW9uX2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgbG9jYXRpb25fc2lnW1tuYW1lXV0sIGxvY2F0aW9uX3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBnb19sZXZlbCA9IGdvX2xldmVsLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICAgICAgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKGxvY2F0aW9uX2NwW1tuYW1lXV0sIHByZWZpeCA9ICIxOSIpCiAgICBncF93cml0dGVuIDwtIHdyaXRlX2FsbF9ncChsb2NhdGlvbl9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMTkiKQogIH0KfQpgYGAKClByaW50IG91dCBhbGwgdGhlIHBsb3RzIGluIGEgc2VwYXJhdGUgYmxvY2suCgpgYGB7cn0KZm9yIChrIGluIHNlcV9hbG9uZyhsb2NhdGlvbl9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXMobG9jYXRpb25fa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gbG9jYXRpb25fa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNbW25hbWVdXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSBsb2NhdGlvbl9pbmNsdXNpb25zW1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyhsb2NhdGlvbl9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXMpCiAgbnVtX3Jvd3MgPC0gbnJvdyhsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3cobG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbnJvdyhsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pCiAgbnJvdyhsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBudW1fb2JqZWN0cyA8LSBsZW5ndGgobG9jYXRpb25fY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIHdlbnQgd3JvbmcgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKGxvY2F0aW9uX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyhsb2NhdGlvbl9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfZG93biQiKSkKICAgIGlmIChsZW5ndGgodXBwKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIGxvY2F0aW9uX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gbG9jYXRpb25fY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBsb2NhdGlvbl9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIG1mX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfbWZfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGNjX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjE5Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9jY19zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfYnBfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogICAgaWYgKGxlbmd0aChkb3ducCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSBsb2NhdGlvbl9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gbG9jYXRpb25fY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIGxvY2F0aW9uX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fbWZfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IG1mX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fbWZfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gbWZfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChjY19zaWcsIHNob3dDYXRlZ29yeSA9IDEyKQogICAgICBjY190cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fY2Nfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIxOWNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMTljbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fYnBfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgIH0KICB9Cn0KYGBgCgpDb2xlbnNvIHNlbnQgYSBzcGVjaWZpYyBxdWVyeSBvZiBpbnRlcmVzdCwgY29tcGFyaW5nIFNDTiB2cy4gUmV0aW5hcwphdCBwMDggaW4gdGhlIGhldGVyb3p5Z290ZXMgaW5jbHVkaW5nIGEgc2V0IG9mIGdlbmVzIG9mIHBhcnRpY3VsYXIKaW50ZXJlc3QuICBQZXJoYXBzIEkgY2FuIHVzZSBzb21lIG9mIHRoZXNlIGFzIG1hcmtlcnMgdG8gcXVhbGl0eQpjb250cm9sIG15IHdvcmsgaW4gdGhlIGZ1dHVyZT8KCkhlcmUgYXJlIHRoZSBnZW5lczoKCk9wbjQsIEVvbWVzLCBUcnBjNywgT3BybTEsIE5yNGEzLCBUYngyMCwgSXJ4NiwgQVc1NTE5ODQsIFBjZGgxOSwKQWRjeWFwMSwgQmFpYXAzLCBDaGwxLCBHcmluM2EsIElnZjEsIEdyaWExLCBHcmluMmQsIEdyaW4zYSwgQ2hybmE2LApDaHJuYTMsIEh0cjVhLCBIdHIyYSwgSHRyNywgSXJ4NCwgUGx4bkMxLCBTZW1hNmQsIFNlbWE0ZiwgU2VtYTRhLApTZW1hNmIsIExycmM0YiwgTHJyYzU4LCBMcnJjM2IsIFdudDQsIFdudDliLCBDdHhuMywgVGVubTEsIEduYTE0LApSZ3M0LCBSZ3M2LCBSZ3M1CgpgYGB7cn0KdGFibGVfaW5wdXQgPC0gbG9jYXRpb25fdGFibGVzW1sic3JfcDA4X2hldCJdXQp0YWJsZV9uYW1lIDwtICJzcl9wMDhfaGV0Igp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKCJPcG40IiwgIkVvbWVzIiwgIlRycGM3IiwgIk9wcm0xIiwgIk5yNGEzIiwgIlRieDIwIiwKICAgICAgICAgICAgICAgICAgICAgICAiSXJ4NiIsICJBVzU1MTk4NCIsICJQY2RoMTkiLCAiQWRjeWFwMXIxIiwgIkJhaWFwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNobDEiLCAiR3JpbjNhIiwgIklnZjEiLCAiR3JpYTEiLCAiR3JpbjJkIiwgIkdyaW4zYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNocm5hNiIsICJDaHJuYTMiLCAiSHRyNWEiLCAiSHRyMmEiLCAiSHRyNyIsICJJcng0IiwKICAgICAgICAgICAgICAgICAgICAgICAiUGx4bkMxIiwgIlNlbWE2ZCIsICJTZW1hNGYiLCAiU2VtYTRhIiwgIlNlbWE2YiIsICJMcnJjNGIiLAogICAgICAgICAgICAgICAgICAgICAgICJMcnJjNTgiLCAiTHJyYzNiIiwgIldudDQiLCAiV250OWIiLCAiQ3R4bjMiLCAiVGVubTEiLCAiR25hMTQiLAogICAgICAgICAgICAgICAgICAgICAgICJSZ3M0IiwgIlJnczYiLCAiUmdzNSIsICJQb3U0ZjIiLCAiQ2hybmIzIiwgIkJjYW4iKQpzcl9wMDhfaGV0X3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0KQpwcChmaWxlID0gIjIwbG9jYXRpb25fbWFfdm9sY2Fub190eC9zcl9wMDhfaGV0X3ZvbGNhbm8ucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfaGV0X3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AwOF9oZXRfdm9sY2Fub1tbInBsb3QiXV0Kc3JfcDA4X2hldF9tYSA8LSBwbG90X21hX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZXhwcl9jb2wgPSAiZGVzZXFfYmFzZW1lYW4iLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImhldF9yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfc2NuIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjBsb2NhdGlvbl9tYV92b2xjYW5vX3R4L3NyX3AwOF9oZXRfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfaGV0X21hW1sicGxvdCJdXQpgYGAKCiMjIyBBbHNvIHRoZSBrbwoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3RhYmxlc1tbInNyX3AwOF9rbyJdXQp0YWJsZV9uYW1lIDwtICJzcl9wMDhfa28iCnRhYmxlIDwtIHRhYmxlX2lucHV0W1siZGF0YSJdXVtbdGFibGVfbmFtZV1dCnNyX3AwOF9rb192b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImtvX3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImtvX3NjbiJdXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMjBsb2NhdGlvbl9tYV92b2xjYW5vX3R4L3NyX3AwOF9rb192b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AwOF9rb192b2xjYW5vW1sicGxvdCJdXQpzcl9wMDhfa29fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm9fdHgvc3JfcDA4X2tvX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2tvX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfa29fbWFbWyJwbG90Il1dCmBgYAoKYGBge3J9CnRhYmxlX2lucHV0IDwtIGxvY2F0aW9uX3RhYmxlc1tbInNyX3AxNV9oZXQiXV0KdGFibGVfbmFtZSA8LSAic3JfcDE1X2hldCIKdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KaW50ZXJlc3RpbmdfZ2VuZXMgPC0gYygiT3BuNCIsICJFb21lcyIsICJUcnBjNyIsICJPcHJtMSIsICJOcjRhMyIsICJUYngyMCIsCiAgICAgICAgICAgICAgICAgICAgICAgIklyeDYiLCAiQVc1NTE5ODQiLCAiUGNkaDE5IiwgIkFkY3lhcDFyMSIsICJCYWlhcDMiLAogICAgICAgICAgICAgICAgICAgICAgICJDaGwxIiwgIkdyaW4zYSIsICJJZ2YxIiwgIkdyaWExIiwgIkdyaW4yZCIsICJHcmluM2EiLAogICAgICAgICAgICAgICAgICAgICAgICJDaHJuYTYiLCAiQ2hybmEzIiwgIkh0cjVhIiwgIkh0cjJhIiwgIkh0cjciLCAiSXJ4NCIsCiAgICAgICAgICAgICAgICAgICAgICAgIlBseG5DMSIsICJTZW1hNmQiLCAiU2VtYTRmIiwgIlNlbWE0YSIsICJTZW1hNmIiLCAiTHJyYzRiIiwKICAgICAgICAgICAgICAgICAgICAgICAiTHJyYzU4IiwgIkxycmMzYiIsICJXbnQ0IiwgIldudDliIiwgIkN0eG4zIiwgIlRlbm0xIiwgIkduYTE0IiwKICAgICAgICAgICAgICAgICAgICAgICAiUmdzNCIsICJSZ3M2IiwgIlJnczUiLCAiUG91NGYyIiwgIkNocm5iMyIsICJCY2FuIikKc3JfcDE1X2hldF92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IGNvbG9yc1tbImhldF9yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJoZXRfc2NuIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm9fdHgvc3JfcDE1X2hldF92b2xjYW5vLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDE1X2hldF92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMTVfaGV0X3ZvbGNhbm9bWyJwbG90Il1dCnNyX3AxNV9oZXRfbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJoZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1siaGV0X3NjbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjIwbG9jYXRpb25fbWFfdm9sY2Fub190eC9zcl9wMTVfaGV0X21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDE1X2hldF9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDE1X2hldF9tYVtbInBsb3QiXV0KYGBgCgojIyMgQWxzbyB0aGUga28KCmBgYHtyfQp0YWJsZV9pbnB1dCA8LSBsb2NhdGlvbl90YWJsZXNbWyJzcl9wMTVfa28iXV0KdGFibGVfbmFtZSA8LSAic3JfcDE1X2tvIgp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQpzcl9wMTVfa29fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjIwbG9jYXRpb25fbWFfdm9sY2Fub190eC9zcl9wMTVfa29fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKc3JfcDE1X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AxNV9rb192b2xjYW5vW1sicGxvdCJdXQpzcl9wMTVfa29fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyMGxvY2F0aW9uX21hX3ZvbGNhbm9fdHgvc3JfcDE1X2tvX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDE1X2tvX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMTVfa29fbWFbWyJwbG90Il1dCmBgYAoKIyMjIyBUZXN0IGEgc3BlY2lmaWMgbG9jYXRpb24gcXVlcnkgZm9yIGR1cGxpY2F0ZWQgSURzCgpMZXQgdXMgc2VlIGlmIGFueSBFbnNlbWJsIGdlbmUgSURzIGFuZC9vciBNR0kgSURzIGFyZSBzaGFyZWQgaW4gdGhlCndvcmtzaGVldCBsb2NhdGlvbl9zcl9wMDhfa29faW5jbHVkaW5nX3d0XzAuMV9kZWNyZWFzZWRfc2lnIHVwL2Rvd24uCgpgYGB7cn0KdGVzdF90YWJsZV91cCA8LSBsb2NhdGlvbl9zaWdbWyJzcl9wMDhfa28iXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbMV1dCnRlc3RfdGFibGVfZG93biA8LSBsb2NhdGlvbl9zaWdbWyJzcl9wMDhfa28iXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1sxXV0KCnF1ZXJ5IDwtIGxpc3QoInVwIiA9IHJvd25hbWVzKHRlc3RfdGFibGVfdXApLAogICAgICAgICAgICAgICJkb3duIiA9IHJvd25hbWVzKHRlc3RfdGFibGVfZG93bikpCnF1ZXJ5X3Vwc2V0IDwtIFVwU2V0Ujo6ZnJvbUxpc3QocXVlcnkpClVwU2V0Ujo6dXBzZXQocXVlcnlfdXBzZXQpCgpxdWVyeSA8LSBsaXN0KCJ1cCIgPSB0ZXN0X3RhYmxlX3VwW1siZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIl1dLAogICAgICAgICAgICAgICJkb3duIiA9IHRlc3RfdGFibGVfZG93bltbImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSJdXSkKcXVlcnlfdXBzZXQgPC0gVXBTZXRSOjpmcm9tTGlzdChxdWVyeSkKVXBTZXRSOjp1cHNldChxdWVyeV91cHNldCkKIyMgb2ssIGdvb2QuCmBgYAoKIyMjIyBSZXBlYXQgd2l0aCB0aGUgc3RyaWN0IGZpbHRlcgoKYGBge3J9CmxvY2F0aW9uX3N0cmljdF90YWJsZXMgPC0gbGlzdCgpCmxvY2F0aW9uX3N0cmljdF9zaWcgPC0gbGlzdCgpCmxvY2F0aW9uX3N0cmljdF9ncCA8LSBsaXN0KCkKbG9jYXRpb25fc3RyaWN0X2NwIDwtIGxpc3QoKQpmb3IgKGsgaW4gc2VxX2Fsb25nKGxvY2F0aW9uX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyhsb2NhdGlvbl9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSBsb2NhdGlvbl9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZXMgPC0gbG9jYXRpb25faW5jbHVzaW9uc19zdHJpY3RbW25hbWVdXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSBsb2NhdGlvbl9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zX3N0cmljdFtbaW5jbHVkZV9uYW1lXV0KICBmb3VuZF9pbmNsdWRlcyA8LSByb3duYW1lcyhsb2NhdGlvbl9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXMKICBzdW1tYXJ5KGZvdW5kX2luY2x1ZGVzKQogIGlmIChzdW0oZm91bmRfaW5jbHVkZXMpID09IDApIHsKICAgIG5leHQKICB9CiAgaW5jbHVkZV9maWxlbmFtZSA8LSBnbHVlKCIyMWxvY2F0aW9uX3N0cmljdF9jb250cmFzdHNfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3RhYmxlLXZ7dmVyfS54bHN4IikKICBpbmNsdWRlX3NpZ19maWxlbmFtZSA8LSBnbHVlKCIyMWxvY2F0aW9uX3N0cmljdF9jb250cmFzdHNfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3NpZy12e3Zlcn0ueGxzeCIpCiAgbG9jYXRpb25fc3RyaWN0X3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgbG9jYXRpb25fZGUsIGV4dHJhX2Fubm90ID0gaW5jbHVkZV9kZiwKICAgIGtlZXBlcnMgPSBrZWVwZXIsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwKICAgIGV4Y2VsID0gaW5jbHVkZV9maWxlbmFtZSwgd2FudGVkX2dlbmVzID0gaW5jbHVkZXMpCiAgcHJpbnQobG9jYXRpb25fc3RyaWN0X3RhYmxlc1tbbmFtZV1dKQogIGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgbG9jYXRpb25fc3RyaWN0X3RhYmxlc1tbbmFtZV1dLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogICAgZXhjZWwgPSBpbmNsdWRlX3NpZ19maWxlbmFtZSkKICBwcmludChsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV0pCiAgbnVtX3Jvd3MgPC0gbnJvdyhsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBpZiAobnVtX3Jvd3MgPiAxMCkgewogICAgbG9jYXRpb25fc3RyaWN0X2dwW1tuYW1lXV0gPC0gYWxsX2dwcm9maWxlcihsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dIDwtIGFsbF9jcHJvZmlsZXIoCiAgICAgIGxvY2F0aW9uX3N0cmljdF9zaWdbW25hbWVdXSwgbG9jYXRpb25fc3RyaWN0X3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBnb19sZXZlbCA9IGdvX2xldmVsLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICAgICAgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dLCBwcmVmaXggPSAiMjIiLCBzdWZmaXggPSAic3RyaWN0IikKICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKGxvY2F0aW9uX3N0cmljdF9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMjIiLCBzdWZmaXggPSAic3RyaWN0IikKICB9Cn0KYGBgCgpQcmludCBvdXQgYWxsIHRoZSBwbG90cyBpbiBhIHNlcGFyYXRlIGJsb2NrLgoKYGBge3J9CmZvciAoayBpbiBzZXFfYWxvbmcobG9jYXRpb25fa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKGxvY2F0aW9uX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIGxvY2F0aW9uX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSBsb2NhdGlvbl9pbmNsdXNpb25zX3N0cmljdFtbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIGxvY2F0aW9uX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX25hbWVdXQogIHN1bW1hcnkocm93bmFtZXMobG9jYXRpb25fc2lnX2Z1bGxbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSAlaW4lIGluY2x1ZGVzKQogIG51bV9yb3dzIDwtIG5yb3cobG9jYXRpb25fc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgKwogICAgbnJvdyhsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbnJvdyhsb2NhdGlvbl9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKQogIG5yb3cobG9jYXRpb25fc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIG51bV9vYmplY3RzIDwtIGxlbmd0aChsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIHdlbnQgd3JvbmcgaW4gYWxsX2Nwcm9maWxlci4iKQogIH0gZWxzZSB7CiAgICB1cHAgPC0gd2hpY2goZ3JlcGwoeCA9IG5hbWVzKGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfdXAkIikpCiAgICBkb3ducCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXMobG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl9kb3duJCIpKQogICAgaWYgKGxlbmd0aCh1cHApID4gMCkgewogICAgICBtZl9zaWcgPC0gbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkNDX2VucmljaCJdXQogICAgICBicF9zaWcgPC0gbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjNjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2NjX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9icF9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgICBpZiAobGVuZ3RoKGRvd25wKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIGxvY2F0aW9uX3N0cmljdF9jcFtbbmFtZV1dW1tkb3ducF1dW1siZ29fZGF0YSJdXVtbIk1GX2VucmljaCJdXQogICAgICBjY19zaWcgPC0gbG9jYXRpb25fc3RyaWN0X2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSBsb2NhdGlvbl9zdHJpY3RfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gMTIpCiAgICAgIGNjX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9jY19zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY19iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjIzY2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyM2NsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9icF9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogIH0KfQpgYGAKCkNvbGVuc28gc2VudCBhIHNwZWNpZmljIHF1ZXJ5IG9mIGludGVyZXN0LCBjb21wYXJpbmcgU0NOIHZzLiBSZXRpbmFzCmF0IHAwOCBpbiB0aGUgaGV0ZXJvenlnb3RlcyBpbmNsdWRpbmcgYSBzZXQgb2YgZ2VuZXMgb2YgcGFydGljdWxhcgppbnRlcmVzdC4gIFBlcmhhcHMgSSBjYW4gdXNlIHNvbWUgb2YgdGhlc2UgYXMgbWFya2VycyB0byBxdWFsaXR5CmNvbnRyb2wgbXkgd29yayBpbiB0aGUgZnV0dXJlPwoKSGVyZSBhcmUgdGhlIGdlbmVzOgoKT3BuNCwgRW9tZXMsIFRycGM3LCBPcHJtMSwgTnI0YTMsIFRieDIwLCBJcng2LCBBVzU1MTk4NCwgUGNkaDE5LApBZGN5YXAxLCBCYWlhcDMsIENobDEsIEdyaW4zYSwgSWdmMSwgR3JpYTEsIEdyaW4yZCwgR3JpbjNhLCBDaHJuYTYsCkNocm5hMywgSHRyNWEsIEh0cjJhLCBIdHI3LCBJcng0LCBQbHhuQzEsIFNlbWE2ZCwgU2VtYTRmLCBTZW1hNGEsClNlbWE2YiwgTHJyYzRiLCBMcnJjNTgsIExycmMzYiwgV250NCwgV250OWIsIEN0eG4zLCBUZW5tMSwgR25hMTQsClJnczQsIFJnczYsIFJnczUKCmBgYHtyfQp0YWJsZV9pbnB1dCA8LSBsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1sic3JfcDA4X2hldCJdXQp0YWJsZV9uYW1lIDwtICJzcl9wMDhfaGV0Igp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQppbnRlcmVzdGluZ19nZW5lcyA8LSBjKCJPcG40IiwgIkVvbWVzIiwgIlRycGM3IiwgIk9wcm0xIiwgIk5yNGEzIiwgIlRieDIwIiwKICAgICAgICAgICAgICAgICAgICAgICAiSXJ4NiIsICJBVzU1MTk4NCIsICJQY2RoMTkiLCAiQWRjeWFwMXIxIiwgIkJhaWFwMyIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNobDEiLCAiR3JpbjNhIiwgIklnZjEiLCAiR3JpYTEiLCAiR3JpbjJkIiwgIkdyaW4zYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIkNocm5hNiIsICJDaHJuYTMiLCAiSHRyNWEiLCAiSHRyMmEiLCAiSHRyNyIsICJJcng0IiwKICAgICAgICAgICAgICAgICAgICAgICAiUGx4bkMxIiwgIlNlbWE2ZCIsICJTZW1hNGYiLCAiU2VtYTRhIiwgIlNlbWE2YiIsICJMcnJjNGIiLAogICAgICAgICAgICAgICAgICAgICAgICJMcnJjNTgiLCAiTHJyYzNiIiwgIldudDQiLCAiV250OWIiLCAiQ3R4bjMiLCAiVGVubTEiLCAiR25hMTQiLAogICAgICAgICAgICAgICAgICAgICAgICJSZ3M0IiwgIlJnczYiLCAiUmdzNSIsICJQb3U0ZjIiLCAiQ2hybmIzIiwgIkJjYW4iKQpzcl9wMDhfaGV0X3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCkKcHAoZmlsZSA9ICIyNGxvY2F0aW9uX21hX3ZvbGNhbm9fc3RyaWN0X3R4L3NyX3AwOF9oZXRfdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AwOF9oZXRfdm9sY2Fub1tbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDA4X2hldF92b2xjYW5vW1sicGxvdCJdXQpzcl9wMDhfaGV0X21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1siaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IGNvbG9yc1tbImhldF9zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjRsb2NhdGlvbl9tYV92b2xjYW5vX3N0cmljdF90eC9zcl9wMDhfaGV0X21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2hldF9tYVtbInBsb3QiXV0KcGxvdHRlZCA8LSBkZXYub2ZmKCkKc3JfcDA4X2hldF9tYVtbInBsb3QiXV0KYGBgCgojIyMgQWxzbyB0aGUga28KCmBgYHtyfQp0YWJsZV9pbnB1dCA8LSBsb2NhdGlvbl9zdHJpY3RfdGFibGVzW1sic3JfcDA4X2tvIl1dCnRhYmxlX25hbWUgPC0gInNyX3AwOF9rbyIKdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0Kc3JfcDA4X2tvX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1sia29fc2NuIl1dLAogIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQpCnBwKGZpbGUgPSAiMjRsb2NhdGlvbl9tYV92b2xjYW5vX3N0cmljdF90eC9zcl9wMDhfa29fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnNyX3AwOF9rb192b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfa29fdm9sY2Fub1tbInBsb3QiXV0Kc3JfcDA4X2tvX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1sia29fc2NuIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSB0eF9sYWJlbF9jb2x1bW4sIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjI0bG9jYXRpb25fbWFfdm9sY2Fub19zdHJpY3RfdHgvc3JfcDA4X2tvX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKc3JfcDA4X2tvX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQpzcl9wMDhfa29fbWFbWyJwbG90Il1dCmBgYAoKIyMjIEFsc28gdGhlIGtvCgpgYGB7cn0KdGFibGVfaW5wdXQgPC0gbG9jYXRpb25fdGFibGVzW1sic3JfcDE1X2tvIl1dCnRhYmxlX25hbWUgPC0gInNyX3AxNV9rbyIKdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0Kc3JfcDE1X2tvX3ZvbGNhbm8gPC0gcGxvdF92b2xjYW5vX2NvbmRpdGlvbl9kZSgKICB0YWJsZSwgdGFibGVfbmFtZSwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwgcF9jb2wgPSAiZGVzZXFfYWRqcCIsCiAgY29sb3JfbG93ID0gY29sb3JzW1sia29fcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gY29sb3JzW1sia29fc2NuIl1dLAogIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHBvaW50LnBhZGRpbmcgPSAwLjIpCnBwKGZpbGUgPSAiMjRsb2NhdGlvbl9tYV92b2xjYW5vX3N0cmljdF90eC9zcl9wMTVfa29fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKc3JfcDE1X2tvX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AxNV9rb192b2xjYW5vW1sicGxvdCJdXQpzcl9wMTVfa29fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSBjb2xvcnNbWyJrb19yZXRpbmEiXV0sIGNvbG9yX2hpZ2ggPSBjb2xvcnNbWyJrb19zY24iXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9IHR4X2xhYmVsX2NvbHVtbiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjRsb2NhdGlvbl9tYV92b2xjYW5vX3N0cmljdF90eC9zcl9wMTVfa29fbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQpzcl9wMTVfa29fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnNyX3AxNV9rb19tYVtbInBsb3QiXV0KYGBgCgojIyMgQW5kIHRpbWUKCmBgYHtyfQp0aW1lX3RhYmxlc19mdWxsIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHRpbWVfZGUsIGtlZXBlcnMgPSB0aW1lX2tlZXBlcnMsCiAgbGFiZWxfY29sdW1uID0gdHhfbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMjVmdWxsX2NvbnRyYXN0c190aW1lX3R4L2Z1bGxfdGFibGVzLXZ7dmVyfS54bHN4IikpCnRpbWVfc2lnX2Z1bGwgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcygKICB0aW1lX3RhYmxlc19mdWxsLCBhY2NvcmRpbmdfdG8gPSAiZGVzZXEiLAogIGV4Y2VsID0gZ2x1ZSgiMjVmdWxsX2NvbnRyYXN0c190aW1lX3R4L2Z1bGxfc2lnLXZ7dmVyfS54bHN4IikpCmBgYAoKYGBge3J9CnRpbWVfdGFibGVzIDwtIGxpc3QoKQp0aW1lX3NpZyA8LSBsaXN0KCkKdGltZV9ncCA8LSBsaXN0KCkKdGltZV9jcCA8LSBsaXN0KCkKZm9yIChrIGluIHNlcV9hbG9uZyh0aW1lX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyh0aW1lX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIHRpbWVfa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc1tbbmFtZV1dCiAgaW5jbHVkZV9uYW1lIDwtIHBhc3RlMCgiaW5jXyIsIG5hbWUpCiAgaW5jbHVkZV9kZl9uYW1lIDwtIHBhc3RlMCgiZGZfIiwgbmFtZSkKICBpbmNsdWRlX2RmIDwtIHRpbWVfaW5jbHVzaW9uc1tbaW5jbHVkZV9kZl9uYW1lXV0KICBpbmNsdWRlcyA8LSB0aW1lX2luY2x1c2lvbnNbW2luY2x1ZGVfbmFtZV1dCiAgc3VtbWFyeShyb3duYW1lcyh0aW1lX3NpZ19mdWxsW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXSkgJWluJSBpbmNsdWRlcykKICBpbmNsdWRlX2ZpbGVuYW1lIDwtIGdsdWUoIjI2dGltZV9jb250cmFzdHNfdHgve25hbWV9X2luY2x1ZGluZ193dF97bGZjX2N1dG9mZn1fZGVjcmVhc2VkX3RhYmxlLXZ7dmVyfS54bHN4IikKICBpbmNsdWRlX3NpZ19maWxlbmFtZSA8LSBnbHVlKCIyNnRpbWVfY29udHJhc3RzX3R4L3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIHRpbWVfdGFibGVzW1tuYW1lXV0gPC0gY29tYmluZV9kZV90YWJsZXMoCiAgICB0aW1lX2RlLCBleHRyYV9hbm5vdCA9IGluY2x1ZGVfZGYsCiAgICBrZWVwZXJzID0ga2VlcGVyLCBsYWJlbF9jb2x1bW4gPSB0eF9sYWJlbF9jb2x1bW4sCiAgICBleGNlbCA9IGluY2x1ZGVfZmlsZW5hbWUsIHdhbnRlZF9nZW5lcyA9IGluY2x1ZGVzKQogIHByaW50KHRpbWVfdGFibGVzW1tuYW1lXV0pCiAgdGltZV9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgdGltZV90YWJsZXNbW25hbWVdXSwgYWNjb3JkaW5nX3RvID0gImRlc2VxIiwKICAgIGV4Y2VsID0gaW5jbHVkZV9zaWdfZmlsZW5hbWUpCiAgcHJpbnQodGltZV9zaWdbW25hbWVdXSkKICBudW1fcm93cyA8LSBucm93KHRpbWVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KHRpbWVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgaWYgKG51bV9yb3dzID4gMTApIHsKICAgIHRpbWVfZ3BbW25hbWVdXSA8LSBhbGxfZ3Byb2ZpbGVyKHRpbWVfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKHRpbWVfZ3BbW25hbWVdXSkKICAgIHRpbWVfY3BbW25hbWVdXSA8LSBhbGxfY3Byb2ZpbGVyKAogICAgICB0aW1lX3NpZ1tbbmFtZV1dLCB0aW1lX3RhYmxlc1tbbmFtZV1dLCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBvcmdhbmlzbSA9ICJtb3VzZSIsCiAgICAgIG9yZ2RiX2Zyb20gPSBvcmdkYl9mcm9tLCBnb19sZXZlbCA9IGdvX2xldmVsLCBtYXhfZ3JvdXBzaXplID0gbWF4X2dyb3Vwc2l6ZSkKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKHRpbWVfY3BbW25hbWVdXSwgcHJlZml4ID0gIjI3IikKICAgIGdwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2dwKHRpbWVfZ3BbW25hbWVdXSwgcHJlZml4ID0gIjI3IikKICB9Cn0KYGBgCgpTZW5kIHRoZSBwbG90cyBzZXBhcmF0ZWx5LgoKYGBge3J9CmZvciAoayBpbiBzZXFfYWxvbmcodGltZV9rZWVwZXJzKSkgewogIG5hbWUgPC0gbmFtZXModGltZV9rZWVwZXJzKVtrXQogIG1lc3NhZ2UoIkV4YW1pbmluZyAiLCBuYW1lKQogIGtlZXBlciA8LSB0aW1lX2tlZXBlcnNbbmFtZV0KICBpbmNsdWRlcyA8LSB0aW1lX2luY2x1c2lvbnNbW25hbWVdXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSB0aW1lX2luY2x1c2lvbnNbW2luY2x1ZGVfZGZfbmFtZV1dCiAgaW5jbHVkZXMgPC0gdGltZV9pbmNsdXNpb25zW1tpbmNsdWRlX25hbWVdXQogIG51bV9yb3dzIDwtIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICsKICAgIG5yb3codGltZV9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSkKICBtZXNzYWdlKCJUaGVyZSBhcmUgIiwgbnVtX3Jvd3MsICIgc2lnbmlmaWNhbnQgdXAgYW5kIGRvd24gZ2VuZXMuIikKICBudW1fb2JqZWN0cyA8LSBsZW5ndGgodGltZV9jcFtbbmFtZV1dKQogIGlmIChudW1fb2JqZWN0cyA9PSAwKSB7CiAgICB3YXJuaW5nKCJTb21ldGhpbmcgZmFpbGVkIGluIGFsbF9jcHJvZmlsZXIuIikKICB9IGVsc2UgewogICAgdXBwIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyh0aW1lX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl91cCQiKSkKICAgIGRvd25wIDwtIHdoaWNoKGdyZXBsKHggPSBuYW1lcyh0aW1lX2NwW1tuYW1lXV0pLCBwYXR0ZXJuID0gIl9kb3duJCIpKQogICAgaWYgKGxlbmd0aCh1cHApID4gMCkgewogICAgICBtZl9zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkJQX2VucmljaCJdXQogICAgICBtZl9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fdXBfY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19iYXJfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X3VwX2NjX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9icF9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gYnBfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGJwX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgYnBfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV91cF9icF9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgICBpZiAobGVuZ3RoKGRvd25wKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJNRl9lbnJpY2giXV0KICAgICAgY2Nfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJDQ19lbnJpY2giXV0KICAgICAgYnBfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbZG93bnBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChtZl9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIG1mX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIyOGNsdXN0ZXJQcm9maWxlcl9wbG90c190eC97bmFtZX1fZG93bl9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2NjX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBjY190cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2NjX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMjhjbHVzdGVyUHJvZmlsZXJfcGxvdHNfdHgve25hbWV9X2Rvd25fYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjI4Y2x1c3RlclByb2ZpbGVyX3Bsb3RzX3R4L3tuYW1lfV9kb3duX2JwX3NpZ19kb3QucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX2Jhcl9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfZG93bltbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICB9CiAgfQp9CmBgYAoKIyMgVm9sY2FubyBwbG90cyBieSB0aW1lCgojIyMgdF9oZXRfZGxnbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfaGV0X2RsZ24iCnRhYmxlX2lucHV0IDwtIHRpbWVfdGFibGVzW1t0YWJsZV9uYW1lXV0KdGFibGUgPC0gdGFibGVfaW5wdXRbWyJkYXRhIl1dW1t0YWJsZV9uYW1lXV0KdF9oZXRfZGxnbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vX3R4L3RfaGV0X2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKdF9oZXRfZGxnbl92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnRfaGV0X2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm9fdHgvdF9oZXRfZGxnbl9tYS5wZGYiLCB3aWR0aCA9IDksIGhlaWdodCA9IDkpCnRfaGV0X2RsZ25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfaGV0X2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIHRfa29fZGxnbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfa29fZGxnbiIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2tvX2RsZ25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCwgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgcG9pbnQucGFkZGluZyA9IDAuMikKcHAoZmlsZSA9ICIyOXRpbWVfbWFfdm9sY2Fub190eC90X2tvX2RsZ25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKdF9rb19kbGduX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fZGxnbl92b2xjYW5vW1sicGxvdCJdXQp0X2tvX2RsZ25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm9fdHgvdF9rb19kbGduX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9rb19kbGduX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2tvX2RsZ25fbWFbWyJwbG90Il1dCmBgYAoKIyMjIHRfaGV0X3JldGluYQoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfaGV0X3JldGluYSIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2hldF9yZXRpbmFfdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfcmV0aW5hIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X3JldGluYSJdXSwKICBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgYWxwaGEgPSAxLjAsCiAgc2l6ZSA9IDQsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHBvaW50LnBhZGRpbmcgPSAwLjIpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm9fdHgvdF9oZXRfcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIpCnRfaGV0X3JldGluYV92b2xjYW5vW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9yZXRpbmFfdm9sY2Fub1tbInBsb3QiXV0KdF9oZXRfcmV0aW5hX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X3JldGluYSJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9yZXRpbmEiXV0sCiAgcF9jb2wgPSAiZGVzZXFfYWRqcCIsIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBvdXRsaW5lID0gb3V0bGluZSkKcHAoZmlsZSA9ICIyOXRpbWVfbWFfdm9sY2Fub190eC90X2hldF9yZXRpbmFfbWEucGRmIiwgd2lkdGggPSA5LCBoZWlnaHQgPSA5KQp0X2hldF9yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfaGV0X3JldGluYV9tYVtbInBsb3QiXV0KYGBgCgojIyMgdF9rb19yZXRpbmEKCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJ0X2tvX3JldGluYSIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2tvX3JldGluYV92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vX3R4L3Rfa29fcmV0aW5hX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIpCnRfa29fcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fcmV0aW5hX3ZvbGNhbm9bWyJwbG90Il1dCnRfa29fcmV0aW5hX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vX3R4L3Rfa29fcmV0aW5hX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9rb19yZXRpbmFfbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fcmV0aW5hX21hW1sicGxvdCJdXQpgYGAKCiMjIHRfaGV0X3NjbgoKYGBge3J9CnRhYmxlX25hbWUgPC0gInRfaGV0X3NjbiIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2hldF9zY25fdm9sY2FubyA8LSBwbG90X3ZvbGNhbm9fY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBmY19jb2wgPSAiZGVzZXFfbG9nZmMiLCBwX2NvbCA9ICJkZXNlcV9hZGpwIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIGxhYmVsX2NvbHVtbiA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiLCBsYWJlbCA9IGludGVyZXN0aW5nX2dlbmVzLCBhbHBoYSA9IDEuMCwKICBzaXplID0gNCwgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgcG9pbnQucGFkZGluZyA9IDAuMikKcHAoZmlsZSA9ICIyOXRpbWVfbWFfdm9sY2Fub190eC90X2hldF9zY25fdm9sY2Fuby5wZGYiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAxMikKdF9oZXRfc2NuX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfaGV0X3Njbl92b2xjYW5vW1sicGxvdCJdXQp0X2hldF9zY25fbWEgPC0gcGxvdF9tYV9jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGV4cHJfY29sID0gImRlc2VxX2Jhc2VtZWFuIiwgZmNfY29sID0gImRlc2VxX2xvZ2ZjIiwKICBjb2xvcl9sb3cgPSB0aW1lX2NvbG9yc1tbInAwOF9oZXRfZGxnbiJdXSwgY29sb3JfaGlnaCA9IHRpbWVfY29sb3JzW1sicDE1X2hldF9kbGduIl1dLAogIHBfY29sID0gImRlc2VxX2FkanAiLCBsYWJlbF9jb2x1bW4gPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIiwgbGFiZWwgPSBpbnRlcmVzdGluZ19nZW5lcywgb3V0bGluZSA9IG91dGxpbmUpCnBwKGZpbGUgPSAiMjl0aW1lX21hX3ZvbGNhbm9fdHgvdF9oZXRfc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9oZXRfc2NuX21hW1sicGxvdCJdXQpwbG90dGVkIDwtIGRldi5vZmYoKQp0X2hldF9zY25fbWFbWyJwbG90Il1dCmBgYAoKIyMgdF9rb19zY24KCmBgYHtyfQp0YWJsZV9uYW1lIDwtICJ0X2tvX3NjbiIKdGFibGVfaW5wdXQgPC0gdGltZV90YWJsZXNbW3RhYmxlX25hbWVdXQp0YWJsZSA8LSB0YWJsZV9pbnB1dFtbImRhdGEiXV1bW3RhYmxlX25hbWVdXQp0X2tvX3Njbl92b2xjYW5vIDwtIHBsb3Rfdm9sY2Fub19jb25kaXRpb25fZGUoCiAgdGFibGUsIHRhYmxlX25hbWUsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsIHBfY29sID0gImRlc2VxX2FkanAiLAogIGNvbG9yX2xvdyA9IHRpbWVfY29sb3JzW1sicDA4X2hldF9kbGduIl1dLCBjb2xvcl9oaWdoID0gdGltZV9jb2xvcnNbWyJwMTVfaGV0X2RsZ24iXV0sCiAgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIGFscGhhID0gMS4wLAogIHNpemUgPSA0LCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCBwb2ludC5wYWRkaW5nID0gMC4yKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vX3R4L3Rfa29fc2NuX3ZvbGNhbm8ucGRmIiwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gMTIpCnRfa29fc2NuX3ZvbGNhbm9bWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fc2NuX3ZvbGNhbm9bWyJwbG90Il1dCnRfa29fc2NuX21hIDwtIHBsb3RfbWFfY29uZGl0aW9uX2RlKAogIHRhYmxlLCB0YWJsZV9uYW1lLCBleHByX2NvbCA9ICJkZXNlcV9iYXNlbWVhbiIsIGZjX2NvbCA9ICJkZXNlcV9sb2dmYyIsCiAgY29sb3JfbG93ID0gdGltZV9jb2xvcnNbWyJwMDhfaGV0X2RsZ24iXV0sIGNvbG9yX2hpZ2ggPSB0aW1lX2NvbG9yc1tbInAxNV9oZXRfZGxnbiJdXSwKICBwX2NvbCA9ICJkZXNlcV9hZGpwIiwgbGFiZWxfY29sdW1uID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIsIGxhYmVsID0gaW50ZXJlc3RpbmdfZ2VuZXMsIG91dGxpbmUgPSBvdXRsaW5lKQpwcChmaWxlID0gIjI5dGltZV9tYV92b2xjYW5vX3R4L3Rfa29fc2NuX21hLnBkZiIsIHdpZHRoID0gOSwgaGVpZ2h0ID0gOSkKdF9rb19zY25fbWFbWyJwbG90Il1dCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCnRfa29fc2NuX21hW1sicGxvdCJdXQpgYGAKCiMjIyMgUmVwZWF0IHdpdGggdGhlIHN0cmljdCBmaWx0ZXIKCmBgYHtyfQp0aW1lX3N0cmljdF90YWJsZXMgPC0gbGlzdCgpCnRpbWVfc3RyaWN0X3NpZyA8LSBsaXN0KCkKdGltZV9zdHJpY3RfZ3AgPC0gbGlzdCgpCnRpbWVfc3RyaWN0X2NwIDwtIGxpc3QoKQp0aW1lX3N0cmljdF9lbiA8LSBsaXN0KCkKZm9yIChrIGluIHNlcV9hbG9uZyh0aW1lX2tlZXBlcnMpKSB7CiAgbmFtZSA8LSBuYW1lcyh0aW1lX2tlZXBlcnMpW2tdCiAgbWVzc2FnZSgiRXhhbWluaW5nICIsIG5hbWUpCiAga2VlcGVyIDwtIHRpbWVfa2VlcGVyc1tuYW1lXQogIGluY2x1ZGVfbmFtZSA8LSBwYXN0ZTAoImluY18iLCBuYW1lKQogIGluY2x1ZGVfZGZfbmFtZSA8LSBwYXN0ZTAoImRmXyIsIG5hbWUpCiAgaW5jbHVkZV9kZiA8LSB0aW1lX2luY2x1c2lvbnNfc3RyaWN0W1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc19zdHJpY3RbW2luY2x1ZGVfbmFtZV1dCiAgZm91bmRfaW5jbHVkZXMgPC0gcm93bmFtZXModGltZV9zaWdfZnVsbFtbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0pICVpbiUgaW5jbHVkZXMKICBzdW1tYXJ5KGZvdW5kX2luY2x1ZGVzKQogIGlmIChzdW0oZm91bmRfaW5jbHVkZXMpID09IDApIHsKICAgIG5leHQKICB9CiAgaW5jbHVkZV9maWxlbmFtZSA8LSBnbHVlKCIzMHRpbWVfc3RyaWN0X2NvbnRyYXN0c19leGNlbF90eC97bmFtZX1faW5jbHVkaW5nX3d0X3tsZmNfY3V0b2ZmfV9kZWNyZWFzZWRfdGFibGUtdnt2ZXJ9Lnhsc3giKQogIGluY2x1ZGVfc2lnX2ZpbGVuYW1lIDwtIGdsdWUoIjMwdGltZV9zdHJpY3RfY29udHJhc3RzX2V4Y2VsX3R4L3tuYW1lfV9pbmNsdWRpbmdfd3Rfe2xmY19jdXRvZmZ9X2RlY3JlYXNlZF9zaWctdnt2ZXJ9Lnhsc3giKQogIHRpbWVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogICAgdGltZV9kZSwgZXh0cmFfYW5ub3QgPSBpbmNsdWRlX2RmLAogICAga2VlcGVycyA9IGtlZXBlciwgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogICAgZXhjZWwgPSBpbmNsdWRlX2ZpbGVuYW1lLCB3YW50ZWRfZ2VuZXMgPSBpbmNsdWRlcykKICBwcmludCh0aW1lX3N0cmljdF90YWJsZXNbW25hbWVdXSkKICB0aW1lX3N0cmljdF9zaWdbW25hbWVdXSA8LSBleHRyYWN0X3NpZ25pZmljYW50X2dlbmVzKAogICAgdGltZV9zdHJpY3RfdGFibGVzW1tuYW1lXV0sIGFjY29yZGluZ190byA9ICJkZXNlcSIsCiAgICBleGNlbCA9IGluY2x1ZGVfc2lnX2ZpbGVuYW1lKQogIHByaW50KHRpbWVfc3RyaWN0X3NpZ1tbbmFtZV1dKQogIG51bV9yb3dzIDwtIG5yb3codGltZV9zdHJpY3Rfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KHRpbWVfc3RyaWN0X3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dKQogIG1lc3NhZ2UoIlRoZXJlIGFyZSAiLCBudW1fcm93cywgIiBzaWduaWZpY2FudCB1cCBhbmQgZG93biBnZW5lcy4iKQogIGlmIChudW1fcm93cyA+PSAxMCkgewogICAgbWVzc2FnZSgiUGVyZm9ybWluZyBncHJvZmlsZXIvY2x1c3RlclByb2ZpbGVyLiIpCiAgICB0aW1lX3N0cmljdF9ncFtbbmFtZV1dIDwtIGFsbF9ncHJvZmlsZXIodGltZV9zdHJpY3Rfc2lnW1tuYW1lXV0sIHNwZWNpZXMgPSAibW11c2N1bHVzIikKICAgIHRpbWVfc3RyaWN0X2NwW1tuYW1lXV0gPC0gYWxsX2Nwcm9maWxlcigKICAgICAgdGltZV9zdHJpY3Rfc2lnW1tuYW1lXV0sIHRpbWVfc3RyaWN0X3RhYmxlc1tbbmFtZV1dLAogICAgICBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBnb19sZXZlbCA9IGdvX2xldmVsLCBvcmdkYl9mcm9tID0gb3JnZGJfZnJvbSwKICAgICAgbWF4X2dyb3Vwc2l6ZSA9IG1heF9ncm91cHNpemUsIG9yZ2FuaXNtID0gIm1vdXNlIikKICAgICNpZiAoIWlzLm51bGwoZ2V0MCgibTJfZ3NjIikpKSB7CiAgICAjICB0aW1lX3N0cmljdF9lbltbbmFtZV1dIDwtIGFsbF9lbnJpY2hlcih0aW1lX3N0cmljdF9zaWdbW25hbWVdXSwgZ3NjID0gbTJfZ3NjLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgZnJvbSA9ICJFTlNFTUJMIiwgdG8gPSAiU1lNQk9MIikKICAgICN9CiAgICBncF93cml0dGVuIDwtIHdyaXRlX2FsbF9ncCh0aW1lX3N0cmljdF9ncFtbbmFtZV1dLCBwcmVmaXggPSAiMzEiLCBzdWZmaXggPSAic3RyaWN0IikKICAgIGNwX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2NwKHRpbWVfc3RyaWN0X2NwW1tuYW1lXV0sIHByZWZpeCA9ICIzMSIsIHN1ZmZpeCA9ICJzdHJpY3QiKQogICAgI2VuX3dyaXR0ZW4gPC0gd3JpdGVfYWxsX2VuKHRpbWVfc3RyaWN0X2VuW1tuYW1lXV0pCiAgfSBlbHNlIHsKICAgIHdhcm5pbmcoIlRoZXJlIGFyZSBsZXNzIHRoYW4gMTAgZ2VuZXMgdXAgYW5kIGRvd24gaW4gdGhlICIsIG5hbWUsICIgY29tcGFyaXNvbi4iKQogICAgbWVzc2FnZSgiVGhlcmUgYXJlIGxlc3MgdGhhbiAxMCBnZW5lcyB1cCBhbmQgZG93biBpbiB0aGUgIiwgbmFtZSwgIiBjb21wYXJpc29uLiIpCiAgfQp9CmBgYAoKU2VuZCB0aGUgcGxvdHMgc2VwYXJhdGVseS4KCmBgYHtyfQpmb3IgKGsgaW4gc2VxX2Fsb25nKHRpbWVfa2VlcGVycykpIHsKICBuYW1lIDwtIG5hbWVzKHRpbWVfa2VlcGVycylba10KICBtZXNzYWdlKCJFeGFtaW5pbmcgIiwgbmFtZSkKICBrZWVwZXIgPC0gdGltZV9rZWVwZXJzW25hbWVdCiAgaW5jbHVkZXMgPC0gdGltZV9pbmNsdXNpb25zW1tuYW1lXV0KICBpbmNsdWRlX25hbWUgPC0gcGFzdGUwKCJpbmNfIiwgbmFtZSkKICBpbmNsdWRlX2RmX25hbWUgPC0gcGFzdGUwKCJkZl8iLCBuYW1lKQogIGluY2x1ZGVfZGYgPC0gdGltZV9pbmNsdXNpb25zW1tpbmNsdWRlX2RmX25hbWVdXQogIGluY2x1ZGVzIDwtIHRpbWVfaW5jbHVzaW9uc1tbaW5jbHVkZV9uYW1lXV0KICBudW1fcm93cyA8LSBucm93KHRpbWVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dKSArCiAgICBucm93KHRpbWVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbImRvd25zIl1dW1tuYW1lXV0pCiAgbWVzc2FnZSgiVGhlcmUgYXJlICIsIG51bV9yb3dzLCAiIHNpZ25pZmljYW50IHVwIGFuZCBkb3duIGdlbmVzLiIpCiAgbnVtX29iamVjdHMgPC0gbGVuZ3RoKHRpbWVfY3BbW25hbWVdXSkKICBpZiAobnVtX29iamVjdHMgPT0gMCkgewogICAgd2FybmluZygiU29tZXRoaW5nIGZhaWxlZCBpbiBhbGxfY3Byb2ZpbGVyLiIpCiAgfSBlbHNlIHsKICAgIHVwcCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXModGltZV9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfdXAkIikpCiAgICBkb3ducCA8LSB3aGljaChncmVwbCh4ID0gbmFtZXModGltZV9jcFtbbmFtZV1dKSwgcGF0dGVybiA9ICJfZG93biQiKSkKICAgIGlmIChsZW5ndGgodXBwKSA+IDApIHsKICAgICAgbWZfc2lnIDwtIHRpbWVfY3BbW25hbWVdXVtbdXBwXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW3VwcF1dW1siZ29fZGF0YSJdXVtbIkNDX2VucmljaCJdXQogICAgICBicF9zaWcgPC0gdGltZV9jcFtbbmFtZV1dW1t1cHBdXVtbImdvX2RhdGEiXV1bWyJCUF9lbnJpY2giXV0KICAgICAgbWZfcGxvdHNfdXAgPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfdHJlZXNfdHgve25hbWV9X3VwX21mX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl90cmVlX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfdXBbWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgbWZfYmFyX3VwX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfYmFyX3R4L3tuYW1lfV91cF9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChtZl9wbG90c191cFtbImRvdCJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX3Bsb3RzX3VwIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV91cF9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX3RyZWVzX3R4L3tuYW1lfV91cF9jY19zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gY2NfdHJlZV91cF9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX3VwW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGNjX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX2Jhcl90eC97bmFtZX1fdXBfY2Nfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoY2NfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfdXBfZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF90cmVlc190eC97bmFtZX1fdXBfYnBfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGJwX3RyZWVfdXBfZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c191cFtbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBicF9wbG90c191cCA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX2Jhcl91cF9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX2Jhcl90eC97bmFtZX1fdXBfYnBfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gYnBfYmFyX3VwX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQoYnBfcGxvdHNfdXBbWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogICAgaWYgKGxlbmd0aChkb3ducCkgPiAwKSB7CiAgICAgIG1mX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siTUZfZW5yaWNoIl1dCiAgICAgIGNjX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQ0NfZW5yaWNoIl1dCiAgICAgIGJwX3NpZyA8LSB0aW1lX2NwW1tuYW1lXV1bW2Rvd25wXV1bWyJnb19kYXRhIl1dW1siQlBfZW5yaWNoIl1dCiAgICAgIG1mX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQobWZfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBtZl90cmVlX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF90cmVlc190eC97bmFtZX1fZG93bl9tZl9zaWdfdHJlZS5wZGYiKQogICAgICBwcChmaWxlID0gbWZfdHJlZV9kb3duX2ZpbGVuYW1lKQogICAgICB0cnkocHJpbnQobWZfcGxvdHNfZG93bltbInRyZWUiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBtZl9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX2Jhcl90eC97bmFtZX1fZG93bl9tZl9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBtZl9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KG1mX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgICBjY19wbG90c19kb3duIDwtIHBsb3RfZW5yaWNocmVzdWx0KGNjX3NpZywgc2hvd0NhdGVnb3J5ID0gZ29fY2F0ZWdvcmllcykKICAgICAgY2NfdHJlZV9kb3duX2ZpbGVuYW1lIDwtIGdsdWUoIjMyY3BfdHJlZXNfdHgve25hbWV9X2Rvd25fY2Nfc2lnX3RyZWUucGRmIikKICAgICAgcHAoZmlsZSA9IGNjX3RyZWVfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGNjX3Bsb3RzX2Rvd25bWyJ0cmVlIl1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgY2NfYmFyX2Rvd25fZmlsZW5hbWUgPC0gZ2x1ZSgiMzJjcF9iYXJfdHgve25hbWV9X2Rvd25fY2Nfc2lnX2RvdC5wZGYiKQogICAgICBwcChmaWxlID0gY2NfYmFyX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChjY19wbG90c19kb3duW1siZG90Il1dKSwgc2lsZW50ID0gVFJVRSkKICAgICAgcGxvdHRlZCA8LSBkZXYub2ZmKCkKICAgICAgYnBfcGxvdHNfZG93biA8LSBwbG90X2VucmljaHJlc3VsdChicF9zaWcsIHNob3dDYXRlZ29yeSA9IGdvX2NhdGVnb3JpZXMpCiAgICAgIGJwX3RyZWVfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX3RyZWVzX3R4L3tuYW1lfV9kb3duX2JwX3NpZ190cmVlLnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF90cmVlX2Rvd25fZmlsZW5hbWUpCiAgICAgIHRyeShwcmludChicF9wbG90c19kb3duW1sidHJlZSJdXSksIHNpbGVudCA9IFRSVUUpCiAgICAgIHBsb3R0ZWQgPC0gZGV2Lm9mZigpCiAgICAgIGJwX3Bsb3RzX2Rvd24gPC0gcGxvdF9lbnJpY2hyZXN1bHQoYnBfc2lnLCBzaG93Q2F0ZWdvcnkgPSBnb19jYXRlZ29yaWVzKQogICAgICBicF9iYXJfZG93bl9maWxlbmFtZSA8LSBnbHVlKCIzMmNwX2Jhcl90eC97bmFtZX1fZG93bl9icF9zaWdfZG90LnBkZiIpCiAgICAgIHBwKGZpbGUgPSBicF9iYXJfZG93bl9maWxlbmFtZSkKICAgICAgdHJ5KHByaW50KGJwX3Bsb3RzX2Rvd25bWyJkb3QiXV0pLCBzaWxlbnQgPSBUUlVFKQogICAgICBwbG90dGVkIDwtIGRldi5vZmYoKQogICAgfQogIH0KfQpgYGAKCiMgVHJhbnNsYXRvbWUgcXVlcmllcwoKSW4gY29udmVyc2F0aW9uIHdpdGggQ29sZW5zbywgaGUgc3Bva2UgYWJvdXQgYSBzZXJpZXMgb2YgY29udHJhc3RzCndoaWNoIHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGF0dGVtcHQgaW4gb3JkZXIgdG8gcXVlcnkgdGhlIGNoYW5nZXMKYWNyb3NzIGJvdGggbG9jYXRpb25zIGFuZCBnZW5vdHlwZXMgYW5kL29yIGJvdGggbG9jYXRpb25zIGFuZCB0aW1lLAp0aHVzOgoKKHAwOF9oZXRfc2NuIC8gcDA4X2hldF9yZXRpbmEpIC8gKHAwOF9rb19zY24gLyBwMDhfa29fcmV0aW5hKQoKYXMgYW4gZXhhbXBsZS4gIFdlIGNhbiBkZWZpbml0ZWx5IGRvIHRoZXNlLCBidXQgdGhleSBkbyBub3Qgd29yayBmb3IKYWxsIG1ldGhvZHMgZW1wbG95ZWQgKEkgdGhpbmsgdGhleSB3b3JrIGJlc3Qgd2l0aCBsaW1tYSBhbmQgZWRnZVIpLgoKTGV0cyBmaW5kIG91dCEKCiMjIFR3byBzY24vcmV0aW5hIGNvbXBhcmlzb25zCgoqIChwMDhfaGV0X3NjbiAvIHAwOF9oZXRfcmV0aW5hKSAvIChwMDhfa29fc2NuIC8gcDA4X2tvX3JldGluYSkKKiAocDE1X2hldF9zY24gLyBwMTVfaGV0X3JldGluYSkgLyAocDE1X2tvX3NjbiAvIHAxNV9rb19yZXRpbmEpCgpgYGB7cn0Kc2NuX2V4dHJhIDwtIGdsdWUoIlxcCiAgcDA4aGV0ID0gKGNvbmRpdGlvbnAwOF9oZXRfc2NuIC0gY29uZGl0aW9ucDA4X2hldF9yZXRpbmEpLCBcXAogIHAwOGtvID0gKGNvbmRpdGlvbnAwOF9rb19zY24gLSBjb25kaXRpb25wMDhfa29fcmV0aW5hKSwgXFwKICBwMDhoZXRfdnNfcDA4a28gPSAoY29uZGl0aW9ucDA4X2hldF9zY24gLSBjb25kaXRpb25wMDhfaGV0X3JldGluYSkgLSAoY29uZGl0aW9ucDA4X2tvX3NjbiAtIGNvbmRpdGlvbnAwOF9rb19yZXRpbmEpLCBcXAogIHAxNWhldCA9IChjb25kaXRpb25wMTVfaGV0X3NjbiAtIGNvbmRpdGlvbnAxNV9oZXRfcmV0aW5hKSwgXFwKICBwMTVrbyA9IChjb25kaXRpb25wMTVfa29fc2NuIC0gY29uZGl0aW9ucDE1X2tvX3JldGluYSksIFxcCiAgcDE1aGV0X3ZzX3AxNWtvID0gKGNvbmRpdGlvbnAxNV9oZXRfc2NuIC0gY29uZGl0aW9ucDE1X2hldF9yZXRpbmEpIC0gKGNvbmRpdGlvbnAxNV9rb19zY24gLSBjb25kaXRpb25wMTVfa29fcmV0aW5hKSIpCnNjbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzIDwtIGxpc3QoCiAgInAwOGhldCIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhrbyIgPSBjKCJwMDhfa29fc2NuIiwgInAwOF9rb19yZXRpbmEiKSwKICAicDE1aGV0IiA9IGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIiksCiAgInAxNWtvIiA9IGMoInAxNV9rb19zY24iLCAicDE1X2tvX3JldGluYSIpKQpzY25fdHJhbnNsYXRvbWVfa2VlcGVycyA8LSBsaXN0KAogICJwMDhoZXQiID0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAicDA4a28iID0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIiksCiAgInAwOF9zY25fdHJhbnNsYXRvbWUiID0gYygicDA4aGV0IiwgInAwOGtvIiksCiAgInAxNWhldCIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJwMTVrbyIgPSBjKCJwMTVfa29fc2NuIiwgInAxNV9rb19yZXRpbmEiKSwKICAicDE1X3Njbl90cmFuc2xhdG9tZSIgPSBjKCJwMTVoZXQiLCAicDE1a28iKSkKZmlsdCA8LSBub3JtYWxpemUodHhfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUpCmxpbW1hX3Rlc3QgPC0gbGltbWFfcGFpcndpc2UoZmlsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwZXJzID0gc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9IEZBTFNFLCBleHRyYV9jb250cmFzdHJzID0gc2NuX2V4dHJhKQplZGdlcl90ZXN0IDwtIGVkZ2VyX3BhaXJ3aXNlKGZpbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHNjbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSBGQUxTRSwgZXh0cmFfY29udHJhc3RzID0gc2NuX2V4dHJhKQpzY25fdHJhbnNsYXRvbWVfZGUgPC0gYWxsX3BhaXJ3aXNlKHR4X3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBzY25fdHJhbnNsYXRvbWVfZGVfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9zdnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fYmFzaWMgPSBGQUxTRSwgZG9fZHJlYW0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19ub2lzZXEgPSBGQUxTRSwgZG9fZWJzZXEgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9jb250cmFzdHMgPSBzY25fZXh0cmEpCnNjbl9jb21iaW5lZF90ZXN0IDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHNjbl90cmFuc2xhdG9tZV9kZSwga2VlcGVycyA9IHNjbl90cmFuc2xhdG9tZV9rZWVwZXJzLAogIGV4Y2VsID0gZ2x1ZSgiMzN0cmFuc2xhdG9tZV94bHN4X3R4L3Rlc3Rfc2NuX3RyYW5zbGF0b21lX3VuZmlsdGVyZWRfbm9zdmEtdnt2ZXJ9Lnhsc3giKSkKc2NuX3RyYW5zbGF0b21lX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UodHhfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBzY25fdHJhbnNsYXRvbWVfZGVfa2VlcGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fYmFzaWMgPSBGQUxTRSwgZG9fZHJlYW0gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IHNjbl9leHRyYSkKc2NuX2NvbWJpbmVkX3Rlc3Rfc3ZhIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHNjbl90cmFuc2xhdG9tZV9kZV9zdmEsIGtlZXBlcnMgPSBzY25fdHJhbnNsYXRvbWVfa2VlcGVycywKICBleGNlbCA9IGdsdWUoIjMzdHJhbnNsYXRvbWVfeGxzeF90eC90ZXN0X3Njbl90cmFuc2xhdG9tZV91bmZpbHRlcmVkX3N2YS12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBTdWJ0cmFjdGluZyBERVNlcTIgcmVzdWx0czogcDA4IHNjbiBoZXQgdnMga28KCmBgYHtyfQpwMDhfc2NuX2NvbWJpbmVkX2Rlc2VxIDwtIHN1YnRyYWN0X2RlX3Jlc3VsdHMoCiAgZmlyc3RfdGFibGUgPSBzY25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhoZXQiXV0sCiAgc2Vjb25kX3RhYmxlID0gc2NuX2NvbWJpbmVkX3Rlc3RbWyJkYXRhIl1dW1sicDA4a28iXV0sCiAgZmlyc3RfbGZjID0gImRlc2VxX2xvZ2ZjIiwgc2Vjb25kX2xmYyA9ICJkZXNlcV9sb2dmYyIsCiAgZmlyc3RfcCA9ICJkZXNlcV9hZGpwIiwgc2Vjb25kX3AgPSAiZGVzZXFfYWRqcCIsCiAgZmlyc3RfbmFtZSA9ICJoZXQiLCBzZWNvbmRfbmFtZSA9ICJrbyIsCiAgZXhjZWwgPSBnbHVlKCIzM3RyYW5zbGF0b21lX3hsc3hfdHgvdHJhbnNsYXRvbWVfcDA4X3Njbl9jb21iaW5lZF9kZXNlcS12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIyBTdWJ0cmFjdGluZyBERVNlcTIgcmVzdWx0czogcDE1IHNjbiBoZXQgdnMga28KCmBgYHtyfQpwMTVfc2NuX2NvbWJpbmVkX2Rlc2VxIDwtIHN1YnRyYWN0X2RlX3Jlc3VsdHMoCiAgZmlyc3RfdGFibGUgPSBzY25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMTVoZXQiXV0sCiAgc2Vjb25kX3RhYmxlID0gc2NuX2NvbWJpbmVkX3Rlc3RbWyJkYXRhIl1dW1sicDE1a28iXV0sCiAgZmlyc3RfbGZjID0gImRlc2VxX2xvZ2ZjIiwgc2Vjb25kX2xmYyA9ICJkZXNlcV9sb2dmYyIsCiAgZmlyc3RfcCA9ICJkZXNlcV9hZGpwIiwgc2Vjb25kX3AgPSAiZGVzZXFfYWRqcCIsCiAgZmlyc3RfbmFtZSA9ICJoZXQiLCBzZWNvbmRfbmFtZSA9ICJrbyIsCiAgZXhjZWwgPSBnbHVlKCIzNHRyYW5zbGF0b21lX2Rlc2Vxc3ViX3hsc3hfdHgvdHJhbnNsYXRvbWVfcDE1X3Njbl9jb21iaW5lZF9kZXNlcS12e3Zlcn0ueGxzeCIpKQpgYGAKCiMjIE9uZSBkbGduL3JldGluYSBjb21wYXJpc29uCgoqIChwMDhfaGV0X2RsZ24gLyBwMDhfaGV0X3JldGluYSkgLyAocDA4X2tvX2RsZ24gLyBwMDhfa29fcmV0aW5hKQoKYGBge3J9CnAwOF9kbGduX2V4dHJhIDwtICJwMDhoZXRfdnNfcDA4a28gPSAoY29uZGl0aW9ucDA4X2hldF9kbGduIC0gY29uZGl0aW9ucDA4X2hldF9yZXRpbmEpIC0gKGNvbmRpdGlvbnAwOF9rb19kbGduIC0gY29uZGl0aW9ucDA4X2tvX3JldGluYSkiCnAwOF9kbGduX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMgPC0gbGlzdCgKICAicDA4aGV0IiA9IGMoInAwOF9oZXRfZGxnbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJwMDhrbyIgPSBjKCJwMDhfa29fZGxnbiIsICJwMDhfa29fcmV0aW5hIikpCnAwOF9kbGduX3RyYW5zbGF0b21lX2tlZXBlcnMgPC0gbGlzdCgKICAicDA4X2hldF9kbGduX3ZzX3JldGluYSIgPSBjKCJwMDhfaGV0X2RsZ24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAicDA4X2tvX2RsZ25fdnNfcmV0aW5hIiA9IGMoInAwOF9rb19kbGduIiwgInAwOF9rb19yZXRpbmEiKSwKICAicDA4X2RsZ25fdHJhbnNsYXRvbWUiID0gYygicDA4aGV0IiwgInAwOGtvIikpCnAwOF9kbGduX3RyYW5zbGF0b21lX2RlIDwtIGFsbF9wYWlyd2lzZSh0eF9wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBwMDhfZGxnbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9jb250cmFzdHMgPSBwMDhfZGxnbl9leHRyYSkKcDA4X2RsZ25fY29tYmluZWRfdGVzdCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBwMDhfZGxnbl90cmFuc2xhdG9tZV9kZSwga2VlcGVycyA9IHAwOF9kbGduX3RyYW5zbGF0b21lX2tlZXBlcnMsCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMzN0cmFuc2xhdG9tZV94bHN4X3R4L3Rlc3RfcDA4X2RsZ25fdHJhbnNsYXRvbWVfdW5maWx0ZXJlZF9ub3N2YS12e3Zlcn0ueGxzeCIpKQpwMDhfZGxnbl90cmFuc2xhdG9tZV9kZV9zdmEgPC0gYWxsX3BhaXJ3aXNlKHR4X3BhaXJ3aXNlX2lucHV0LCBmaWx0ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSBwMDhfZGxnbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3N2cyA9ICJzdmFzZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX2ZzdHJpbmcgPSAifiAwICsgY29uZGl0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX25vaXNlcSA9IEZBTFNFLCBkb19lYnNlcSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX2NvbnRyYXN0cyA9IHAwOF9kbGduX2V4dHJhKQpwMDhfZGxnbl9jb21iaW5lZF90ZXN0X3N2YSA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBwMDhfZGxnbl90cmFuc2xhdG9tZV9kZV9zdmEsIGtlZXBlcnMgPSBwMDhfZGxnbl90cmFuc2xhdG9tZV9rZWVwZXJzLAogIGxhYmVsX2NvbHVtbiA9IGxhYmVsX2NvbHVtbiwKICBleGNlbCA9IGdsdWUoIjMzdHJhbnNsYXRvbWVfeGxzeF90eC90ZXN0X3AwOF9kbGduX3RyYW5zbGF0b21lX3VuZmlsdGVyZWRfc3ZhLXZ7dmVyfS54bHN4IikpCmBgYAoKIyMjIFN1YnRyYWN0aW5nIHRoZSBERVNlcTIgcmVzdWx0cwoKIyMgVHdvIHNjbi9yZXRpbmEgY29tcGFyaXNvbnMgKHAxNS9wMDggYWNyb3NzIGhldC9rbykKCiogKHAxNV9oZXRfc2NuIC8gcDE1X2hldF9yZXRpbmEpIC8gKHAwOF9oZXRfc2NuIC8gcDA4X2hldF9yZXRpbmEpCiogKHAxNV9rb19zY24gLyBwMTVfa29fcmV0aW5hKSAvIChwMDhfa29fc2NuIC8gcDA4X2tvX3JldGluYSkKCmBgYHtyfQp0aW1lX3Njbl9leHRyYSA8LSBnbHVlKCJcXAogIHAxNWhldCA9IChjb25kaXRpb25wMTVfaGV0X3NjbiAtIGNvbmRpdGlvbnAxNV9oZXRfcmV0aW5hKSwgXFwKICBwMDhoZXQgPSAoY29uZGl0aW9ucDA4X2hldF9zY24gLSBjb25kaXRpb25wMDhfaGV0X3JldGluYSksIFxcCiAgcDE1aGV0X3ZzX3AwOGhldCA9IChjb25kaXRpb25wMTVfaGV0X3NjbiAtIGNvbmRpdGlvbnAxNV9oZXRfcmV0aW5hKSAtIChjb25kaXRpb25wMDhfaGV0X3NjbiAtIGNvbmRpdGlvbnAwOF9oZXRfcmV0aW5hKSwKICBwMTVrbyA9IChjb25kaXRpb25wMTVfa29fc2NuIC0gY29uZGl0aW9ucDE1X2tvX3JldGluYSksIFxcCiAgcDA4a28gPSAoY29uZGl0aW9ucDA4X2tvX3NjbiAtIGNvbmRpdGlvbnAwOF9rb19yZXRpbmEpLCBcXAogIHAxNWtvX3ZzX3AwOGtvID0gKGNvbmRpdGlvbnAxNV9rb19zY24gLSBjb25kaXRpb25wMTVfa29fcmV0aW5hKSAtIChjb25kaXRpb25wMDhfa29fc2NuIC0gY29uZGl0aW9ucDA4X2tvX3JldGluYSkiKQp0aW1lX3Njbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzIDwtIGxpc3QoCiAgInAxNWhldCIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJwMDhoZXQiID0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAicDE1a28iID0gYygicDE1X2tvX3NjbiIsICJwMTVfa29fcmV0aW5hIiksCiAgInAwOGtvIiA9IGMoInAwOF9rb19zY24iLCAicDA4X2tvX3JldGluYSIpKQp0aW1lX3Njbl90cmFuc2xhdG9tZV9rZWVwZXJzIDwtIGxpc3QoCiAgInAxNWhldCIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJwMDhoZXQiID0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiKSwKICAicDE1a28iID0gYygicDE1X2tvX3NjbiIsICJwMTVfa29fcmV0aW5hIiksCiAgInAwOGtvIiA9IGMoInAwOF9rb19zY24iLCAicDA4X2tvX3JldGluYSIpLAogICJwMTVfaGV0X3NjX3ZzX3JldGluYSIgPSBjKCJwMTVfaGV0X3NjbiIsICJwMTVfaGV0X3JldGluYSIpLAogICJwMDhfaGV0X3NjX3ZzX3JldGluYSIgPSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpLAogICJzY25faGV0X3RyYW5zbGF0b21lIiA9IGMoInAxNWhldCIsICJwMDhoZXQiKSwKICAic2NuX2tvX3RyYW5zbGF0b21lIiA9IGMoInAxNWtvIiwgInAwOGtvIikpCnRpbWVfc2NuX3RyYW5zbGF0b21lX2RlIDwtIGFsbF9wYWlyd2lzZSh0eF9wYWlyd2lzZV9pbnB1dCwgZmlsdGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBlcnMgPSB0aW1lX3Njbl90cmFuc2xhdG9tZV9kZV9rZWVwZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9mc3RyaW5nID0gIn4gMCArIGNvbmRpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb19iYXNpYyA9IEZBTFNFLCBkb19kcmVhbSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9jb250cmFzdHMgPSB0aW1lX3Njbl9leHRyYSkKdGltZV9zY25fdHJhbnNsYXRvbWVfdGVzdCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICB0aW1lX3Njbl90cmFuc2xhdG9tZV9kZSwKICBrZWVwZXJzID0gdGltZV9zY25fdHJhbnNsYXRvbWVfa2VlcGVycywKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzM3RyYW5zbGF0b21lX3hsc3hfdHgvdGVzdF90aW1lX3Njbl90cmFuc2xhdG9tZV91bmZpbHRlcmVkX25vc3ZhLXZ7dmVyfS54bHN4IikpCnRpbWVfc2NuX3RyYW5zbGF0b21lX2RlX3N2YSA8LSBhbGxfcGFpcndpc2UodHhfcGFpcndpc2VfaW5wdXQsIGZpbHRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcGVycyA9IHRpbWVfc2NuX3RyYW5zbGF0b21lX2RlX2tlZXBlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfc3ZzID0gInN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZnN0cmluZyA9ICJ+IDAgKyBjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvX2Jhc2ljID0gRkFMU0UsIGRvX2RyZWFtID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9fbm9pc2VxID0gRkFMU0UsIGRvX2Vic2VxID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0cmFfY29udHJhc3RzID0gdGltZV9zY25fZXh0cmEpCnRpbWVfc2NuX3RyYW5zbGF0b21lX3Rlc3Rfc3ZhIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHRpbWVfc2NuX3RyYW5zbGF0b21lX2RlX3N2YSwKICBrZWVwZXJzID0gdGltZV9zY25fdHJhbnNsYXRvbWVfa2VlcGVycywKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzM3RyYW5zbGF0b21lX3hsc3hfdHgvdGVzdF90aW1lX3Njbl90cmFuc2xhdG9tZV91bmZpbHRlcmVkX3N2YS12e3Zlcn0ueGxzeCIpKQpgYGAKCk5leHQgc3RlcDogUGVyZm9ybSB0aGUgcmV0aW5hIGZpbHRlcjsgbmVlZCB0byB0aGluayBhYm91dCB0aGUgcHJvcGVyCnVuaW9uL2ludGVyc2VjdGlvbiBvZiB0aGUgcmV0aW5hL3ggZXhwcmVzc2lvbiB2YWx1ZXMKCkluIHRoZSBwcmV2aW91cyBibG9jaywgd2UgYXJlIG1ha2luZyAyIGdsb2JhbCBjb21wYXJpc29ucywgaGVyZSBpcyBvbmUKb2YgdGhlbToKCihwMTVoZXRzY24vcDE1aGV0cmV0KS8ocDA4aGV0c2NuL3AwOGhldHJldCkKCkkgdGhlcmVmb3JlIHdhbnQgdG8gZXh0cmFjdCB0aGUgbW9zdCBsb2dpY2FsIHNldCBvZiBnZW5lcyBoaWdoZXIgaW4Kc29tZS9hbGwgb2YgdGhlc2UgY29uZGl0aW9ucyB3aXRoIHJlc3BlY3QgdG8gdGhlIGNvcnJlc3BvbmRpbmcgd3QKY29uZGl0aW9ucy4gIFByZXZpb3VzbHksIGluIHNlY3Rpb24gJ0V4dHJhY3QgZ2VuZXMgaW5jbHVkZWQgZm9yIGVhY2gKc2V0IG9mIGNvbnRyYXN0cycsIEkgYXR0ZW1wdGVkIHRvIHBlcmZvcm0gdGhpcyBvcGVyYXRpb24gZm9yIDIKc3BlY2lmaWMgd3QgY29uZGl0aW9ucy4gIFdoZW4gdGhpcyB3YXMgcGVyZm9ybWVkLCBpdCB0b29rIHRoZQp1bmlxdWUodW5pb24pIG9mIHRoZSB0d28gc2V0cy4gIFRodXMgaXQgc3RhbmRzIHRvIHJlYXNvbiB0aGF0IEkgd2FudAp0byB0YWtlIHRoZSB1bmlxdWUodW5pb24pIG9mIGFsbCA0IGluIHRoaXMgaW5zdGFuY2U/ICBlLmcuOgoKKHAxNWhldHNjbiA+IHAxNXd0c2NuKSB8IChwMTVoZXRyZXQgPiBwMTV3dHJldCkgfAogIChwMDhoZXRzY24gPiBwMDh3dHNjbikgfCAocDA4aGV0cmV0ID4gcDA4d3RyZXQpCgpJIGtpbmQgb2YgdGhpbmsgaXQgc2hvdWxkIGJlOgoKKChwMTVoZXRzY24gPiBwMTV3dHNjbikgfCAocDE1aGV0cmV0ID4gcDE1d3RyZXQpKSAmCiAgKChwMDhoZXRzY24gPiBwMDh3dHNjbikgfCAocDA4aGV0cmV0ID4gcDA4d3RyZXQpKQoKZ3Jvc3MsIHBlcmhhcHMgSSBzaG91bGQganVzdCBkbyB0aGlzIG1hbnVhbGx5LCBnaXZlbiB0aGF0IHRoZXJlIGFyZQpvbmx5IGEgZmV3IHB1dGF0aXZlIHRyYW5zbGF0b21lcyB0byBxdWVyeT8KCiMgUXVpY2sgYW5kIGRpcnR5IERFU2VxMiBjb250cmFzdCBvZiBjb250cmFzdHMKCkluIGEgZmFzaGlvbiBzaW1pbGFyIHRvIGhvdyBIZWN0b3IgaGFuZGxlZCB0aGUgZWZmZWN0IG9mIHBoYWdvY3l0b3Npcwp3aXRoIExhdXJhIGFuZCBOYWppYiBhIGxvbmcgdGltZSBhZ28sIEkgcHJvcG9zZSB0byBkbyBhIHNpbXBsZQpzdWJ0cmFjdGlvbiBvZiB0aGUgcmVzdWx0cyBvZiBvdXIgdHdvIGNvbnRyYXN0cyB3aGljaCBjb21wcmlzZSB0aGUKdHJhbnNsYXRvbWUgcXVlcnkgKEkgd2FzIHRoaW5raW5nIGFib3V0IHRoaXMgbGFzdCB3ZWVrLCB0aHVzIHRoZQppbmNsdXNpb24gb2YgdGhlbSBpbiB0aGUgZGUgdGFibGVzIGFib3ZlKS4gIFNpbWlsYXJseSB0byB0aGUKcGhhZ29jeXRvc2lzIGVmZmVjdCwgSSB3aWxsIHNpbXBseSB0YWtlIHRoZSB3b3JzdCBwb3NpYmxlIGFkanVzdGVkCnAtdmFsdWUuICBJIHdpbGwgcmVwZWF0IHRoaXMgd2l0aCBsaW1tYS9FZGdlUiBhbmQgc2VlIGhvdyBzaW1pbGFyIHRoZQpmaW5hbCByZXN1bHRzIGFyZSB0byB3aGF0IHRob3NlIG1ldGhvZHMgcHJvdmlkZSBpbiB0aGUgKGEvYikvKGMvZCkKY29tcGFyaXNvbnMuICBJIGFtIHJlYXNvbmFibHkgY2VydGFpbiB0aGF0IERFU2VxMidzIHJlc3VsdHMoKSBmdW5jdGlvbgpoYXMgdGhlIGFiaWxpdHkgdG8gcGVyZm9ybSB0aGVzZSBvZGQgY29udHJhc3RzLCBidXQgSSBoYXZlIG5ldmVyCmZpZ3VyZWQgb3V0IGhvdzsgcGVyaGFwcyBJIHdpbGwgdXNlIHRoaXMgYXMgYSBjaGFuY2UgdG8gcmV2aXNpdCB0aGF0Li4uCgpMZXQgdXMgdGVzdCB0aGlzIGlkZWEgd2l0aCB0aGUgcDA4IGRsZ24gcXVlcnksIHdoaWNoIHNlZWtzIHRvIGNvbXBhcmU6CgoocDA4X2hldF9kbGduIC8gcDA4X2hldF9yZXRpbmEpIC8gKHAwOF9rb19kbGduIC8gcDA4X2tvX3JldGluYSkKClRoZXNlIGFyZSBtYWludGFpbmVkIGluIHRoZSBkZV90YWJsZSB3aXRoIHRoZSBuYW1lcwoncDA4X2hldF9kbGduX3ZzX3JldGluYScgYW5kICdwMDhfa29fZGxnbl92c19yZXRpbmEnCgojIyBwMDggZGxnbiBoZXQgdnMga28KCmBgYHtyfQpwMDhfZGxnbl9jb21iaW5lZF9kZXNlcSA8LSBzdWJ0cmFjdF9kZV9yZXN1bHRzKAogIGZpcnN0X3RhYmxlID0gcDA4X2RsZ25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhfaGV0X2RsZ25fdnNfcmV0aW5hIl1dLAogIHNlY29uZF90YWJsZSA9IHAwOF9kbGduX2NvbWJpbmVkX3Rlc3RbWyJkYXRhIl1dW1sicDA4X2tvX2RsZ25fdnNfcmV0aW5hIl1dLAogIGZpcnN0X2xmYyA9ICJkZXNlcV9sb2dmYyIsIHNlY29uZF9sZmMgPSAiZGVzZXFfbG9nZmMiLAogIGZpcnN0X3AgPSAiZGVzZXFfYWRqcCIsIHNlY29uZF9wID0gImRlc2VxX2FkanAiLAogIGZpcnN0X25hbWUgPSAiaGV0Iiwgc2Vjb25kX25hbWUgPSAia28iLAogIGV4Y2VsID0gZ2x1ZSgiMzR0cmFuc2xhdG9tZV9kZXNlcXN1Yl94bHN4X3R4L3RyYW5zbGF0b21lX3AwOF9kbGduX2NvbWJpbmVkX2Rlc2VxLXZ7dmVyfS54bHN4IikpCmBgYAoKU2VlIGhvdyBzaW1pbGFyIHRoZXNlIHJlc3VsdHMgYXJlIHRvIHRob3NlIG9idGFpbmVkIGZyb20gbGltbWEvZWRnZXIuCgpgYGB7cn0KdGVzdF9jb2x1bW5zIDwtIGMoImVkZ2VyX2xvZ2ZjIiwgImxpbW1hX2xvZ2ZjIiwgImVkZ2VyX2FkanAiLCAibGltbWFfYWRqcCIpCnRlc3RfZGYgPC0gcDA4X2RsZ25fY29tYmluZWRfdGVzdFtbImRhdGEiXV1bWyJwMDhfZGxnbl90cmFuc2xhdG9tZSJdXVssIHRlc3RfY29sdW1uc10KdGVzdF9kZiA8LSBtZXJnZSh0ZXN0X2RmLCBwMDhfZGxnbl9jb21iaW5lZF9kZXNlcSwgYnkgPSAicm93Lm5hbWVzIikKcm93bmFtZXModGVzdF9kZikgPC0gdGVzdF9kZltbIlJvdy5uYW1lcyJdXQp0ZXN0X2RmW1siUm93Lm5hbWVzIl1dIDwtIE5VTEwKY29yLnRlc3QodGVzdF9kZltbImxpbW1hX2xvZ2ZjIl1dLCB0ZXN0X2RmW1siaGV0X3ZzX2tvX2xvZ2ZjIl1dKQpjb3IudGVzdCh0ZXN0X2RmW1siZWRnZXJfbG9nZmMiXV0sIHRlc3RfZGZbWyJoZXRfdnNfa29fbG9nZmMiXV0pCnR0IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIodGVzdF9kZlssIGMoImxpbW1hX2xvZ2ZjIiwgImhldF92c19rb19sb2dmYyIpXSkKdHRbWyJzY2F0dGVyIl1dCnR0IDwtIHBsb3RfbGluZWFyX3NjYXR0ZXIodGVzdF9kZlssIGMoImVkZ2VyX2FkanAiLCAiaGV0X3ZzX2tvX3AiKV0pCnR0W1sic2NhdHRlciJdXQojIyBTbywgdXNpbmcgdGhlIG1heGltdW0gcC12YWx1ZSBpcyBhIGNvbXBsZXRlIGZhaWx1cmU7IGJ1dCB0aGUgZXh0cmVtZSBzaW1pbGFyaXRpZXMKIyMgYmV0d2VlbiB0aGlzIGFuZCBlZGdlUiBzdWdnZXN0IHRvIG1lIHRoYXQgaXQgaXMgbGlrZWx5IHBvc3NpYmxlIHRvIHVzZSB0aGUgcmVzdWx0cwojIyBmcm9tIGVkZ2VSIHdpdGhvdXQgY29uY2VybiAob3IgbGltbWEgZm9yIHRoYXQgbWF0dGVyLCBpdCB3YXMgYWxzbyBleHRyZW1lbHkgc2ltaWxhcikKIyMgT3IgSSBjYW4gc3BlbmQgYSBsaXR0bGUgdGltZSBhbmQgY29sbGVjdCB0aGUgbnVtYmVycyBvbiBlYWNoIHNpZGUgb2YgdGhlIGRpdmlzaW9uCiMjIGFuZCBjYWxjdWxhdGUgYSB0IHN0YXRpc3RpYyBteXNlbGYuCmBgYAoKIyBOb24tU3BlY2lmaWMgZmlsdGVyaW5nIG9mIHRoZSB0cmFuc2xhdG9tZSBkYXRhCgpJIGhhdmUgb24gaGFuZAoKKiBwMDhoZXRfdnNfcDA4a28gOiAocDA4X2hldF9zY24gLSBwMDhfaGV0X3JldGluYSkgLSAocDA4X2tvX3NjbiAtIHAwOF9rb19yZXRpbmEpCiogcDE1aGV0X3ZzX3AxNWtvIDogKHAxNV9oZXRfc2NuIC0gcDE1X2hldF9yZXRpbmEpIC0gKHAxNV9rb19zY24gLSBwMTVfa29fcmV0aW5hKQoqIHAwOGhldF92c19wMDhrbyA6IChwMDhfaGV0X2RsZ24gLSBwMDhfaGV0X3JldGluYSkgLSAocDA4X2tvX2RsZ24gLSBwMDhfa29fcmV0aW5hKQoqIHAxNWhldF92c19wMDhoZXQgOiAocDE1X2hldF9zY24gLSBwMTVfaGV0X3JldGluYSkgLSAocDA4X2hldF9zY24gLSBwMDhfaGV0X3JldGluYSkKKiBwMTVrb192c19wMDhrbyA6IChwMTVfa29fc2NuIC0gcDE1X2tvX3JldGluYSkgLSAocDA4X2tvX3NjbiAtIHAwOF9rb19yZXRpbmEpCgpJIGhhdmUgZ2VuZSBzZXRzIHVwIGFib3ZlIHdoaWNoIGRlZmluZSB0aGUgZ2VuZXMgc3VpdGFibGUgZm9yIGVhY2ggb2YKdGhlc2UgcGllY2VzLiAgVGhlcmUgYXJlIG9ubHkgNSBjb21wYXJpc29ucywgbGV0IHVzIHN0ZXAgdGhyb3VnaCB0aGVtLgoKIyMgU0NOIHRyYW5zbGF0b21lIGhldC9rbyBhdCBwMDgKClRoZSBkYXRhIGZvciB0aGlzIGNvbnRyYXN0IHJlc2lkZXMgaW4Kc2NuX2NvbWJpbmVkX3Rlc3QkZGF0YSRwMDhfc2NuX3RyYW5zbGF0b21lIG9yIHRoZSBzYW1lIHNsb3Qgb2YKc2NuX2NvbWJpbmVkX3Rlc3Rfc3ZhCgoqIHAwOF9oZXRfc2NuIC0gcDA4X2hldF9yZXRpbmEpIC0gKHAwOF9rb19zY24gLSBwMDhfa29fcmV0aW5hKQoKVGh1cywgdGhlIGluY2x1c2lvbl9zaWcgcG9ydGlvbnMgdG8gZXh0cmFjdCBhcmUgZm91bmQgaW46CmluY2x1c2lvbl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXSwgYW5kIGFyZSBuYW1lZCBleGFjdGx5IGFzIHdyaXR0ZW4gYWJvdmUhCgpgYGB7cn0KcDA4X2hldF92c19rb190cmFuc2xhdG9tZV91bmZpbHQgPC0gc2NuX2NvbWJpbmVkX3Rlc3RbWyJkYXRhIl1dW1sicDA4X3Njbl90cmFuc2xhdG9tZSJdXQpudW1fdW5pb24gPC0gdW5pcXVlKGMocm93bmFtZXMoaW5jbHVzaW9uX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sicDA4X2hldF9zY24iXV0pLAogICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoaW5jbHVzaW9uX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sicDA4X2hldF9yZXRpbmEiXV0pKSkKbGVuZ3RoKG51bV91bmlvbikKZGVuX3VuaW9uIDwtIHVuaXF1ZShjKHJvd25hbWVzKGluY2x1c2lvbl9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbInAwOF9rb19zY24iXV0pLAogICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMoaW5jbHVzaW9uX3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1sicDA4X2tvX3JldGluYSJdXSkpKQpsZW5ndGgoZGVuX3VuaW9uKQpib3RoX3VuaW9uIDwtIHVuaXF1ZShjKG51bV91bmlvbiwgZGVuX3VuaW9uKSkKbGVuZ3RoKGJvdGhfdW5pb24pCmJvdGhfaW50ZXJfaWR4IDwtIG51bV91bmlvbiAlaW4lIGRlbl91bmlvbgpib3RoX2ludGVyIDwtIG51bV91bmlvbltib3RoX2ludGVyX2lkeF0KbGVuZ3RoKGJvdGhfaW50ZXIpCmtlZXBlciA8LSBsaXN0KCJwMDhfc2NuX3RyYW5zbGF0b21lIiA9IGMoInAwOGhldCIsICJwMDhrbyIpKQpwMDhfc2NuX3RyYW5zbGF0b21lX3VuaW9uX2ZpbHRlcmVkIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHNjbl90cmFuc2xhdG9tZV9kZSwga2VlcGVycyA9IGtlZXBlciwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzNXRyYW5zbGF0b21lX3VuaW9uX3R4L3AwOF9zY25fdHJhbnNsYXRvbWVfdW5pb25fZmlsdGVyZWRfbm9zdmEtdnt2ZXJ9Lnhsc3giKSwKICB3YW50ZWRfZ2VuZXMgPSBib3RoX3VuaW9uKQpwMDhfc2NuX3RyYW5zbGF0b21lX2ludGVyX2ZpbHRlcmVkIDwtIGNvbWJpbmVfZGVfdGFibGVzKAogIHNjbl90cmFuc2xhdG9tZV9kZSwga2VlcGVycyA9IGtlZXBlciwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzNXRyYW5zbGF0b21lX3VuaW9uX3R4L3AwOF9zY25fdHJhbnNsYXRvbWVfaW50ZXJzZWN0X2ZpbHRlcmVkX25vc3ZhLXZ7dmVyfS54bHN4IiksCiAgd2FudGVkX2dlbmVzID0gYm90aF9pbnRlcikKcDA4X3Njbl90cmFuc2xhdG9tZV91bmlvbl9maWx0ZXJlZF9zdmEgPC0gY29tYmluZV9kZV90YWJsZXMoCiAgc2NuX3RyYW5zbGF0b21lX2RlX3N2YSwga2VlcGVycyA9IGtlZXBlciwKICBsYWJlbF9jb2x1bW4gPSBsYWJlbF9jb2x1bW4sCiAgZXhjZWwgPSBnbHVlKCIzNXRyYW5zbGF0b21lX3VuaW9uX3R4L3AwOF9zY25fdHJhbnNsYXRvbWVfdW5pb25fZmlsdGVyZWRfc3ZhLXZ7dmVyfS54bHN4IiksCiAgd2FudGVkX2dlbmVzID0gYm90aF91bmlvbikKcDA4X3Njbl90cmFuc2xhdG9tZV91bmlvbl9maWx0ZXJlZCA8LSBjb21iaW5lX2RlX3RhYmxlcygKICBzY25fdHJhbnNsYXRvbWVfZGUsIGtlZXBlcnMgPSBrZWVwZXIsCiAgbGFiZWxfY29sdW1uID0gbGFiZWxfY29sdW1uLAogIGV4Y2VsID0gZ2x1ZSgiMzV0cmFuc2xhdG9tZV91bmlvbl90eC9wMDhfc2NuX3RyYW5zbGF0b21lX2ludGVyc2VjdF9maWx0ZXJlZF9zdmEtdnt2ZXJ9Lnhsc3giKSwKICB3YW50ZWRfZ2VuZXMgPSBib3RoX2ludGVyKQpgYGAKCiMgVmVubi9VcFNldCBvZiBSZXRpbmEsIFNDTiwgYW5kIGRMR04gREUgR2VuZXMKCkhlcmUgaXMgYSBzbmlwcGV0IGZyb20gUmFzaG1pIHdoaWNoIGV4cHJlc3NlcyBuaWNlbHkgdGhlIERFLXJlc3VsdApjb21wYXJpc29ucyBzaGUgaXMgbW9zdCBpbnRlcmVzdGVkOgoKU2luY2UsIEkgd2FudCB0byBrbm93IHRoZSBudW1iZXIgb2YgREVHIGV4cHJlc3NlZCBpbiBSZXRpbmEsIFNDTiBhbmQKZExHTiB3aXRoIHJlc3BlY3QgdG8gZ2Vub3R5cGUsIExvY2F0aW9uIGFuZCB0aW1lLiBJIHByZXBhcmVkIHRoZSB2ZW5uCmRpYWdyYW0gZm9yIHRoZXNlIGNvbXBhcmlzb246CgoqIEdlbm90eXBlOiBQOCBSZXQgSGV0IHZzIEtPLCBQMTUgUmV0IEhldCB2cyBLTywgUDggU0NOIEhldCB2cyBLTywKICAgICAgICAgICAgUDE1IFNDTiBIZXQgdnMgS08sIFA4IGRMR04gSGV0IHZzIEtPLCBQMTUgZExHTiBIZXQgdnMgS08KKiBMb2NhdGlvbjogUDhfaGV0IFJldCB2cyBTQ04sIFA4X0tPIFJldCB2cyBTQ04sIFAxNV9oZXQgUmV0IHZzIFNDTiwKICAgICAgICAgICAgUDE1X0tPIFJldCB2cyBTQ04sIFA4X2hldCBSZXQgdnMgZExHTiwgUDhfS08gUmV0IHZzIGRMR04sCiAgICAgICAgICAgIFAxNV9oZXQgUmV0IHZzIGRMR04sIFAxNV9LTyBSZXQgdnMgZExHTiwgUDhfaGV0IFNDTiB2cyBkTEdOLAogICAgICAgICAgICBQOF9LTyBTQ04gdnMgZExHTiwgUDE1X2hldCBTQ04gdnMgZExHTiwgUDE1X0tPIFNDTiB2cyBkTEdOLgoKU2luY2UgSSB3YXMgaW50ZXJlc3RlZCBpbiB1bmRlcnN0YW5kaW5nIHRoZSBjaGFuZ2UgaW4gbG9jYWwgdHJhbnNsYXRvbWUKYWNjb3JkaW5nIHRvIExvY2F0aW9uIGZvciBkaWZmZXJlbnQgZGV2ZWxvcG1lbnRhbCB0aW1lIHBvaW50cyBmb3IgSGV0CmFuZCBLTy4gSGVuY2UsIEkgdHJpZWQgdG8gZ2VuZXJhdGUgYSB2ZW5uIGRpYWdyYW0gZm9yIExvY2F0aW9uIChSZXQKYW5kIFNDTikgYXQgZGV2ZWxvcG1lbnRhbCB0aW1lIHBvaW50cyBQOCBhbmQgUDE1IGZvciBnZW5vdHlwZSBoZXQgYW5kCktPLiAgU28gdGhlIHZlbm4gZGlhZ3JhbSAvIHVwc2V0IHBsb3Qgd2lsbCBiZSBmb3IgbG9jYXRpb24gd2hlcmUgc29tZQpnZW5lcyB3aWxsIGJlIHNoYXJlZC91bmlxdWUgZm9yIFA4X1JldF9oZXQsIFA4X1NDTl9IZXQsIFAxNV9SZXRfSEVULApQMTVfU0NOX0hFVC4gIFdlIGNhbiBwcmVwYXJlIGFuIHVwc2V0IHBsb3QgZm9yIFA4X1JldF9LTywKUDhfU0NOX0tPLCBQMTVfUmV0X0tPIGFuZCBQMTVfU0NOX0tPIGFsc28uIE9yIGNhbiBnZW5lcmF0ZSBhbiB1cHNldApwbG90IGJ5IGNvbWJpbmluZyBib3RoIFA4X1JldF9oZXQsIFA4X1NDTl9IZXQsIFAxNV9SZXRfSEVUIGFuZApQMTVfU0NOX0hFVCBhbmQgUDhfUmV0X0tPLCBQOF9TQ05fS08sIFAxNV9SZXRfS08gYW5kIFAxNV9TQ05fS08uCgpPaywgbGV0IHVzIHNlZSBpZiBJIGNhbiBpbXBsZW1lbnQgdGhpcywgc3RhcnRpbmcgd2l0aCB0aGUgZ2Vub3R5cGUgcXVlcnkKCiogR2Vub3R5cGU6IFA4IFJldCBIZXQgdnMgS08sIFAxNSBSZXQgSGV0IHZzIEtPLCBQOCBTQ04gSGV0IHZzIEtPLAogICAgICAgICAgICBQMTUgU0NOIEhldCB2cyBLTywgUDggZExHTiBIZXQgdnMgS08sIFAxNSBkTEdOIEhldCB2cyBLTwoKIyMga28gdnMgaGV0OyBhbGwgbG9jYXRpb25zIGFuZCB0aW1lcwoKYGBge3J9CiMjIFRoZSBhcHByb3ByaWF0ZSBkYXRhIHN0cnVjdHVyZSBpcyAnZ2Vub3R5cGVfdGFibGVzJywKIyMgYW5kIHRoZSB0YWJsZXMgb2YgaW50ZXJlc3QgYXJlOgp0YWJsZV9uYW1lcyA8LSBjKCJraF9wMDhfcmV0aW5hIiwgImtoX3AxNV9yZXRpbmEiLCAia2hfcDA4X3NjbiIsCiAgICAgICAgICAgICAgICAgImtoX3AxNV9zY24iLCAia2hfcDA4X2RsZ24iLCAia2hfcDE1X2RsZ24iKQp0YWJsZV9uYW1lcyAlaW4lIG5hbWVzKGdlbm90eXBlX3NpZykKbmV3c2lnIDwtIGdlbm90eXBlX3NpZ1tbMV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gZ2Vub3R5cGVfc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGdlbm90eXBlX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KZ2Vub3R5cGVfdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpnZW5vdHlwZV91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcyhnZW5vdHlwZV91cHNldHIsIGV4Y2VsID0gIjM2dXBzZXRfZ2Vub3R5cGVfdHgvZ2Vub3R5cGVfdXBzZXRfZ3JvdXBzLnhsc3giKQpnZW5vdHlwZV91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM2dXBzZXRfZ2Vub3R5cGVfdHgvdGVzdF9nZW5vdHlwZV91cHNldC5wZGYiKQpwcmludChnZW5vdHlwZV91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgpOb3cgbGV0IHVzIHRyeSB0aGUgbG9jYXRpb24tc3BlY2lmaWMgY29tcGFyaXNvbnMKCiMjIHNjbiB2cyByZXRpbmEsIHAwOAoKYGBge3J9CiMjIFRoZSBhcHByb3ByaWF0ZSBkYXRhIHN0cnVjdHVyZSBpcyAnZ2Vub3R5cGVfdGFibGVzJywKIyMgYW5kIHRoZSB0YWJsZXMgb2YgaW50ZXJlc3QgYXJlOgp0YWJsZV9uYW1lcyA8LSBjKCJzcl9wMDhfaGV0IiwgInNyX3AwOF9rbyIpCnRhYmxlX25hbWVzICVpbiUgbmFtZXMobG9jYXRpb25fc2lnKQpsb2NhdGlvbl91cHNldF9pbnB1dCA8LSBsaXN0KCkKZmlyc3RfdGFibGUgPC0gdGFibGVfbmFtZXNbMV0KbmV3c2lnIDwtIGxvY2F0aW9uX3NpZ1tbZmlyc3RfdGFibGVdXQpmb3IgKHNpZyBpbiAyOmxlbmd0aCh0YWJsZV9uYW1lcykpIHsKICBuYW1lIDwtIHRhYmxlX25hbWVzW3NpZ10KICBuZXdzaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJ1cHMiXV1bW25hbWVdXQogIG5ld3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXSA8LSBsb2NhdGlvbl9zaWdbW25hbWVdXVtbImRlc2VxIl1dW1siZG93bnMiXV1bW25hbWVdXQp9CmxvY2F0aW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKG5ld3NpZykKbG9jYXRpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMobG9jYXRpb25fdXBzZXRyLCBleGNlbCA9ICIzNnVwc2V0X2dlbm90eXBlX3R4L3NyX3AwOF9oZXRrb191cHNldF9ncm91cHMueGxzeCIpCmxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzZ1cHNldF9nZW5vdHlwZV90eC90ZXN0X2xvY2F0aW9uX3NyX3AwOF9oZXRrb191cHNldC5wZGYiKQpwcmludChsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgpJIGFtIHJlYXNvbmFibHkgY2VydGFpbiB0aGF0IFJhc2htaSB3b3VsZCBsaWtlIGEgdGFibGUgb2YgdGhlIGdlbmVzCnNoYXJlZCBhbW9uZyBpbmNyZWFzZWQgc2NuIGtvIGFuZCBoZXQgaW4gdGhlIGFib3ZlIHBsb3QgYWxvbmcgd2l0aCB0aGUKaW5jcmVhc2VkIHJldGluYSAoZS5nLiB0aGUgMjY5IGFuZCAxMDMgZ2VuZSBzZXRzKS4KCiMjIHNjbiB2cyByZXRpbmEsIHAxNQoKYGBge3J9CnRhYmxlX25hbWVzIDwtIGMoInNyX3AxNV9oZXQiLCAic3JfcDE1X2tvIikKdGFibGVfbmFtZXMgJWluJSBuYW1lcyhsb2NhdGlvbl9zaWcpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjM2dXBzZXRfZ2Vub3R5cGVfdHgvc3JfcDE1X2hldGtvX3Vwc2V0X2dyb3Vwcy54bHN4IikKbG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHJpbnQoc2NuX3JldGluYV9wMTVfdXBzZXRfcmVzdWx0KQpwcChmaWxlID0gIjM2dXBzZXRfZ2Vub3R5cGVfdHgvdGVzdF9sb2NhdGlvbl9zcl9wMTVfaGV0a29fdXBzZXQucGRmIikKcHJpbnQobG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgZGxnbiB2cyByZXRpbmEsIHAwOAoKYGBge3J9CiMjIFRoZSBhcHByb3ByaWF0ZSBkYXRhIHN0cnVjdHVyZSBpcyAnZ2Vub3R5cGVfdGFibGVzJywKIyMgYW5kIHRoZSB0YWJsZXMgb2YgaW50ZXJlc3QgYXJlOgp0YWJsZV9uYW1lcyA8LSBjKCJkcl9wMDhfaGV0IiwgImRyX3AwOF9rbyIpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjN1cHNldF9nZW5vdHlwZV90eC9kcl9wMDhfaGV0a29fdXBzZXRfZ3JvdXBzLnhsc3giKQpsb2NhdGlvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM2dXBzZXRfZ2Vub3R5cGVfdHgvdGVzdF9sb2NhdGlvbl9kcl9wMDhfaGV0a29fdXBzZXQucGRmIikKcHJpbnQobG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgZGxnbiB2cyByZXRpbmEsIHAxNQoKYGBge3J9CiMjIFRoZSBhcHByb3ByaWF0ZSBkYXRhIHN0cnVjdHVyZSBpcyAnZ2Vub3R5cGVfdGFibGVzJywKIyMgYW5kIHRoZSB0YWJsZXMgb2YgaW50ZXJlc3QgYXJlOgp0YWJsZV9uYW1lcyA8LSBjKCJkcl9wMTVfaGV0IiwgImRyX3AxNV9rbyIpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25fdHgvZHJfcDE1X2hldGtvX3Vwc2V0X2dyb3Vwcy54bHN4IikKbG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9uX3R4L3Rlc3RfbG9jYXRpb25fZHJfcDE1X2hldGtvX3Vwc2V0LnBkZiIpCnByaW50KGxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIGRsZ24gdnMgc2NuLCBwMDgKCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJkc19wMDhfaGV0IiwgImRzX3AwOF9rbyIpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25fdHgvZHNfcDA4X2hldGtvX3Vwc2V0X2dyb3Vwcy54bHN4IikKbG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9uX3R4L3Rlc3RfbG9jYXRpb25fZHNfcDA4X2hldGtvX3Vwc2V0LnBkZiIpCnByaW50KGxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIGRsZ24gdnMgc2NuLCBwMTUKCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJkc19wMTVfaGV0IiwgImRzX3AxNV9rbyIpCmxvY2F0aW9uX3Vwc2V0X2lucHV0IDwtIGxpc3QoKQpmaXJzdF90YWJsZSA8LSB0YWJsZV9uYW1lc1sxXQpuZXdzaWcgPC0gbG9jYXRpb25fc2lnW1tmaXJzdF90YWJsZV1dCmZvciAoc2lnIGluIDI6bGVuZ3RoKHRhYmxlX25hbWVzKSkgewogIG5hbWUgPC0gdGFibGVfbmFtZXNbc2lnXQogIG5ld3NpZ1tbImRlc2VxIl1dW1sidXBzIl1dW1tuYW1lXV0gPC0gbG9jYXRpb25fc2lnW1tuYW1lXV1bWyJkZXNlcSJdXVtbInVwcyJdXVtbbmFtZV1dCiAgbmV3c2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dIDwtIGxvY2F0aW9uX3NpZ1tbbmFtZV1dW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbbmFtZV1dCn0KbG9jYXRpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcobmV3c2lnKQpsb2NhdGlvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3Vwcyhsb2NhdGlvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25fdHgvZHNfcDE1X2hldGtvX3Vwc2V0X2dyb3Vwcy54bHN4IikKbG9jYXRpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9uX3R4L3Rlc3RfbG9jYXRpb25fZHNfcDE1X2hldGtvX3Vwc2V0LnBkZiIpCnByaW50KGxvY2F0aW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMgU2hhcmVkIGFuZCB1bmlxdWUgZ2VuZSBzZXRzIGFjcm9zcyB4L3d0CgpJbiB0aGlzIGJsb2NrIEkgd2FudCB0byBmaW5kIHRoZSB1bmlxdWUgYW5kIHNoYXJlZCBnZW5lcyBiZXR3ZWVuOgoKMS4gIHNjbiBwOCBoZXQvd3QgYW5kIHJldGluYSBwOCBoZXQvd3Q6IGh3cDA4c2NuaW5jLCBod3AwOHJldGluYywgaHdwMDhzY25kZWMsIGh3cDA4cmV0ZGVjCjIuICBzY24gcDE1IGhldC93dCBhbmQgcmV0aW5hIHAxNSBoZXQvd3Q6IGh3cDE1c2NuaW5jLCBod3AxNXJldGluYywgaHdwMTVzY25kZWMsIGh3cDE1cmV0ZGVjCjMuICAjMSBhbmQgIzIgdG9nZXRoZXI6ICA4IGNhdGdvcmllcyBhYm92ZQo0LiAgc2NuIHA4IGtvL3d0IGFuZCByZXRpbmEgcDgga28vd3QKNS4gIHNjbiBwMTUga28vd3QgYW5kIHJldGluYSBwMTUga28vd3QKNi4gICM0IGFuZCAjNSB0b2dldGhlcgoKVGhlIGNvbXBhcmlzb25zIG9mIGhldC93dCBhcmUgZm91bmQgaW4gdGhlICdpbmNsdXNpb25fc2lnJyBkYXRhc2V0OwpiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGluZyBvdXIgY3V0b2ZmcyBmb3Igbm9uc3BlY2lmaWMgYmluZGluZy4KCiMjIE51bWJlciAxIGFib3ZlOiBwMDhfaGV0IHZzIHd0IGZvciBzY24gYW5kIHJldGluYS4KCmBgYHtyfQp0YWJsZV9uYW1lcyA8LSBjKCJwMDhfaGV0X3NjbiIsICJwMDhfaGV0X3JldGluYSIpCmluY2x1c2lvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhpbmNsdXNpb25fc2lnLCBjb250cmFzdHMgPSB0YWJsZV9uYW1lcykKaW5jbHVzaW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGluY2x1c2lvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25zX3R4L3JzX3AwOF9oZXRfaW5jbHVzaW9uX3Vwc2V0X2dyb3Vwcy54bHN4IikKaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dCnBwKGZpbGUgPSAiMzd1cHNldF9sb2NhdGlvbnNfdHgvaW5jbHVzaW9uX3NyX3AwOF91cHNldC5wZGYiKQpwcmludChpbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0pCnBsb3R0ZWQgPC0gZGV2Lm9mZigpCmBgYAoKIyMgTnVtYmVyIDIgYWJvdmU6IHAxNV9oZXQgdnMgd3QgZm9yIHNjbiBhbmQgcmV0aW5hLgoKYGBge3J9CnRhYmxlX25hbWVzIDwtIGMoInAxNV9oZXRfc2NuIiwgInAxNV9oZXRfcmV0aW5hIikKaW5jbHVzaW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcsIGNvbnRyYXN0cyA9IHRhYmxlX25hbWVzKQppbmNsdXNpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMoaW5jbHVzaW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbnNfdHgvcnNfcDE1X2hldF9pbmNsdXNpb25fdXBzZXRfZ3JvdXBzLnhsc3giKQppbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9uc190eC9pbmNsdXNpb25fc3JfcDE1X3Vwc2V0LnBkZiIpCnByaW50KGluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgojIyBOdW1iZXIgMyBhYm92ZTogY29tYmluYXRpb24gb2YgIzEgYW5kICMyCgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygicDA4X2hldF9zY24iLCAicDA4X2hldF9yZXRpbmEiLCAicDE1X2hldF9zY24iLCAicDE1X2hldF9yZXRpbmEiKQppbmNsdXNpb25fdXBzZXRyIDwtIHVwc2V0cl9zaWcoaW5jbHVzaW9uX3NpZywgY29udHJhc3RzID0gdGFibGVfbmFtZXMpCmluY2x1c2lvbl91cHNldF93cml0dGVuIDwtIHdyaXRlX3Vwc2V0X2dyb3VwcyhpbmNsdXNpb25fdXBzZXRyLCBleGNlbCA9ICIzN3Vwc2V0X2xvY2F0aW9uc190eC9yc19wMDhwMTVfaGV0X2luY2x1c2lvbl91cHNldF9ncm91cHMueGxzeCIpCmluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb25zX3R4L2luY2x1c2lvbl9zcl9wMDhwMTVfdXBzZXQucGRmIikKcHJpbnQoaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIE51bWJlciA0IGFib3ZlIHAwOF9rbyB2cyB3dCBmb3Igc2NuIGFuZCByZXRpbmEuCgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIikKaW5jbHVzaW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcsIGNvbnRyYXN0cyA9IHRhYmxlX25hbWVzKQppbmNsdXNpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMoaW5jbHVzaW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbnNfdHgvcnNfcDA4X2tvX2luY2x1c2lvbl91cHNldF9ncm91cHMueGxzeCIpCmluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb25zX3R4L2luY2x1c2lvbl9zcl9wMDhfa29fdXBzZXQucGRmIikKcHJpbnQoaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIE51bWJlciA1IGFib3ZlIHAxNV9rbyB2cyB3dCBmb3Igc2NuIGFuZCByZXRpbmEuCgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygicDE1X2tvX3NjbiIsICJwMTVfa29fcmV0aW5hIikKaW5jbHVzaW9uX3Vwc2V0ciA8LSB1cHNldHJfc2lnKGluY2x1c2lvbl9zaWcsIGNvbnRyYXN0cyA9IHRhYmxlX25hbWVzKQppbmNsdXNpb25fdXBzZXRfd3JpdHRlbiA8LSB3cml0ZV91cHNldF9ncm91cHMoaW5jbHVzaW9uX3Vwc2V0ciwgZXhjZWwgPSAiMzd1cHNldF9sb2NhdGlvbnNfdHgvcnNfcDE1X2tvX2luY2x1c2lvbl91cHNldF9ncm91cHMueGxzeCIpCmluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXQpwcChmaWxlID0gIjM3dXBzZXRfbG9jYXRpb25zX3R4L2luY2x1c2lvbl9zcl9wMTVfa29fdXBzZXQucGRmIikKcHJpbnQoaW5jbHVzaW9uX3Vwc2V0cltbImFsbF9wbG90Il1dKQpwbG90dGVkIDwtIGRldi5vZmYoKQpgYGAKCiMjIE51bWJlciA2IGFib3ZlOiBDb21iaW5pbmcgIzQgYW5kICM1CgpgYGB7cn0KdGFibGVfbmFtZXMgPC0gYygicDA4X2tvX3NjbiIsICJwMDhfa29fcmV0aW5hIiwgInAxNV9rb19zY24iLCAicDE1X2tvX3JldGluYSIpCmluY2x1c2lvbl91cHNldHIgPC0gdXBzZXRyX3NpZyhpbmNsdXNpb25fc2lnLCBjb250cmFzdHMgPSB0YWJsZV9uYW1lcykKaW5jbHVzaW9uX3Vwc2V0X3dyaXR0ZW4gPC0gd3JpdGVfdXBzZXRfZ3JvdXBzKGluY2x1c2lvbl91cHNldHIsIGV4Y2VsID0gIjM3dXBzZXRfbG9jYXRpb25zX3R4L3JzX3AwOHAxNV9rb19pbmNsdXNpb25fdXBzZXRfZ3JvdXBzLnhsc3giKQppbmNsdXNpb25fdXBzZXRyW1siYWxsX3Bsb3QiXV0KcHAoZmlsZSA9ICIzN3Vwc2V0X2xvY2F0aW9uc190eC9pbmNsdXNpb25fc3JfcDA4cDE1X2tvX3Vwc2V0LnBkZiIpCnByaW50KGluY2x1c2lvbl91cHNldHJbWyJhbGxfcGxvdCJdXSkKcGxvdHRlZCA8LSBkZXYub2ZmKCkKYGBgCgojIEdTVkEKCmBgYHtyfQptc2lnZGIgPC0gInJlZmVyZW5jZS9tc2lnZGJfdjIwMjQuMS5NbS5kYiIKaWYgKGZpbGUuZXhpc3RzKG1zaWdkYikpIHsKICB0eF9oX2dzdmEgPC0gc2ltcGxlX2dzdmEodHhfcGFpcndpc2VfaW5wdXQsIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJtaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZXMgPSBtc2lnZGIsIGlkX3NvdXJjZSA9ICJmZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIpCiAgdHhfaF9nc3ZhCgogIHR4X2hfZ3N2YV9zaWcgPC0gZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICB0eF9oX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiX3R4L2dzdmFfc2lnX2hhbGxtYXJrX2NhdGVnb3JpZXMueGxzeCIpCiAgdHhfaF9nc3ZhX3NpZwoKICB0eF9tMV9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHR4X3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIpCiAgdHhfbTFfZ3N2YQogIHR4X20xX2dzdmFfc2lnIDwtIGdldF9zaWdfZ3N2YV9jYXRlZ29yaWVzKAogICAgdHhfbTFfZ3N2YSwgZXhjZWwgPSAiMzhtc2lnZGJfdHgvZ3N2YV9zaWdfcG9zaXRpb25hbF9jYXRlZ29yaWVzLnhsc3giKQogIHR4X20xX2dzdmFfc2lnCgogIHR4X20yX2dzdmEgPC0gc2ltcGxlX2dzdmEodHhfcGFpcndpc2VfaW5wdXQsIG9yZ2RiID0gIm9yZy5NbS5lZy5kYiIsIHNpZ25hdHVyZV9jYXRlZ29yeSA9ICJtMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduYXR1cmVzID0gbXNpZ2RiLCBpZF9zb3VyY2UgPSAiZmRhdGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZWRfaWQgPSAiZXh0ZXJuYWxfdHJhbnNjcmlwdF9uYW1lIikKICB0eF9tMl9nc3ZhCiAgdHhfbTJfZ3N2YV9zaWcgPC0gZ2V0X3NpZ19nc3ZhX2NhdGVnb3JpZXMoCiAgICB0eF9tMl9nc3ZhLCBleGNlbCA9ICIzOG1zaWdkYl90eC9nc3ZhX3NpZ19jdXJhdGVkX2NhdGVnb3JpZXMueGxzeCIpCiAgdHhfbTJfZ3N2YV9zaWcKCiAgdHhfbTNfZ3N2YSA8LSBzaW1wbGVfZ3N2YSh0eF9wYWlyd2lzZV9pbnB1dCwgb3JnZGIgPSAib3JnLk1tLmVnLmRiIiwgc2lnbmF0dXJlX2NhdGVnb3J5ID0gIm0zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ25hdHVyZXMgPSBtc2lnZGIsIGlkX3NvdXJjZSA9ICJmZGF0YSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXF1aXJlZF9pZCA9ICJleHRlcm5hbF90cmFuc2NyaXB0X25hbWUiKQogIHR4X20zX2dzdmEKICB0eF9tM19nc3ZhX3NpZyA8LSBnZXRfc2lnX2dzdmFfY2F0ZWdvcmllcygKICAgIHR4X20zX2dzdmEsIGV4Y2VsID0gIjM4bXNpZ2RiX3R4L2dzdmFfc2lnX3JlZ3VsYXRvcnlfY2F0ZWdvcmllcy54bHN4IikKICB0eF9tM19nc3ZhX3NpZwoKICB0eF9tNV9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHR4X3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIpCiAgdHhfbTVfZ3N2YQogIHR4X201X2dzdmFfc2lnIDwtIGdldF9zaWdfZ3N2YV9jYXRlZ29yaWVzKAogICAgdHhfbTVfZ3N2YSwgZXhjZWwgPSAiMzhtc2lnZGJfdHgvZ3N2YV9zaWdfb250b2xvZ3lfY2F0ZWdvcmllcy54bHN4IikKICB0eF9tNV9nc3ZhX3NpZwoKICB0eF9tOF9nc3ZhIDwtIHNpbXBsZV9nc3ZhKHR4X3BhaXJ3aXNlX2lucHV0LCBvcmdkYiA9ICJvcmcuTW0uZWcuZGIiLCBzaWduYXR1cmVfY2F0ZWdvcnkgPSAibTgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmF0dXJlcyA9IG1zaWdkYiwgaWRfc291cmNlID0gImZkYXRhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVpcmVkX2lkID0gImV4dGVybmFsX3RyYW5zY3JpcHRfbmFtZSIpCiAgdHhfbThfZ3N2YQogIHR4X204X2dzdmFfc2lnIDwtIGdldF9zaWdfZ3N2YV9jYXRlZ29yaWVzKAogICAgdHhfbThfZ3N2YSwgZXhjZWwgPSAiMzhtc2lnZGJfdHgvZ3N2YV9zaWdfY2VsbHR5cGVfY2F0ZWdvcmllcy54bHN4IikKICB0eF9tOF9nc3ZhX3NpZwp9CmBgYAoKIyBHU0VBIGltYWdlcwoKVXAgYWJvdmUgSSBjcmVhdGVkIGEgZmFpcmx5IGxhcmdlIHNldCBvZiBlbnJpY2htZW50L0dTRUEgYW5hbHlzZXMuCkxldCB1cyBwdWxsIHNvbWUgb2YgdGhlIG1vc3QgaW50ZXJlc3RpbmcgcmVzdWx0cyBoZXJlIGFuZCBsb29rIGF0CnRoZW0uCgpIZXJlIGFyZSB0aGUgc3BlY2lmaWMgcXVlcmllcyBmcm9tIFJhc2htaToKCiogR2Vub3R5cGUgKGhldCB2cyBrbyk6CiAgKiBQOCBoZXQgYW5kIGtvIGZvciBSZXQKICAqIFNDTiAoUDggaGV0IHZzIEtPIFNDTgogICogUDggaGV0IHZzIEtPIFJldCkKICAqIFAxNSBoZXQgYW5kIGtvIGZvciBSZXQKKiBMb2NhdGlvbiAoc29tYWwgdnMgYXhvbmFsKToKICAqIFNSX1AwOF9LTwogICogU1JfUDA4X0hldAogICogU1JfUDE1X0tPCiAgKiBTUl9QMTVfSGV0CiogVGltZShwOHZzIHAxNSk6CiAgKiB0X2hldF9SZXRfIHBvOC1wMTUKICAqIHRfS09fUmV0X0MgcG84LXAxNQogICogdF9oZXRfU0NOX3BvOC1wMTUKICAqIHRfS09fU0NOX3BvOC1wMTUKCiMjIEdlbm90eXBlCgpMZXQgdXMgdGFrZSBhIG1vbWVudCBhbmQgc2VlIGZvciB3aGljaCBjb250cmFzdHMgSSBhY3F1aXJlZCByZXN1bHRzOgoKSSBuZWVkIHRvIG1ha2UgYSBsaXR0bGUgc3VtbWFyeSBmb3IgY2x1c3RlcnByb2ZpbGVyIHRvbyBzbyB0aGF0IEkgY2FuIGVhc2lseSBzZWUgaG93IG1hbnkgaGl0cyB0aGVyZQphcmUgZm9yIGVhY2ggY29udHJhc3QuCgpgYGB7cn0Kc3VtbWFyeShnZW5vdHlwZV9mdWxsX2dwKQpmb3IgKGkgaW4gbmFtZXMoZ2Vub3R5cGVfZnVsbF9ncCkpIHsKICBwcmludChpKQogIHByaW50KGdlbm90eXBlX2Z1bGxfZ3BbW2ldXVtbIm51bV9oaXRzIl1dKQp9CnN1bW1hcnkoZ2Vub3R5cGVfZnVsbF9jcCkKZm9yIChpIGluIG5hbWVzKGdlbm90eXBlX2Z1bGxfY3ApKSB7CiAgcHJpbnQoaSkKICBwcmludChucm93KGdlbm90eXBlX2Z1bGxfY3BbW2ldXVtbImdzZV9nbyJdXSkpCn0KYGBgCgojIyMgcDggaGV0L2tvIGZvciByZXRpbmE6CgpUaGlzIGNvbnRyYXN0LCBldmVuIGJlZm9yZSBmaWx0ZXJpbmcgYXdheSB0aGUgaGlnaC13dCBnZW5lcywgb25seSBoYXMgOCBnZW5lcyBpbiB0aGUgc2V0IG9mIHVwIGFuZApkb3duIGdlbmVzIGNvbWJpbmVkLiAgQXMgYSByZXN1bHQsIG15IGZ1bmN0aW9uIHdoaWNoIHBlcmZvcm1zIGdQcm9maWxlci9jbHVzdGVyUHJvZmlsZXIgc2tpcHMgaXQsCmFuZCBhbHNvIHNraXBzIHRoZSBwMTUgaGV0L2tvIGZvciByZXRpbmEgc2FtcGxlcy4KCiMjIyBwOCBoZXQva28gZm9yIHNjbjoKClRoaXMgaGFzIGEgYnVuY2ggbW9yZSBnZW5lczogNTEgdXAgYW5kIDEyOCBkb3duLgpVbmZvcnR1bmF0ZWx5LCBnUHJvZmlsZXIgc2VlcyBubyBzaWduaWZpY2FudCBvdmVyLXJlcHJlc2VudGF0aW9uIGluIHRoZSB1cCBjYXRlZ29yeSBvZiBnZW5lcy4KVGhlIGRvd24gY2F0ZWdvcnkgaGFzCgpUaGUgdXAvZG93biBzZXRzIGZyb20gY2x1c3RlclByb2ZpbGVyIGhhdmUgZW5yaWNoX2dvLCBnc2VfZ28sIGFuZCBnb19kYXRhIHRvIGxvb2sgYXQuCgpgYGB7cn0KZ2Vub3R5cGVfZnVsbF9ncCRraF9wMDhfc2NuX3VwJG51bV9oaXRzCmdlbm90eXBlX2Z1bGxfZ3Aka2hfcDA4X3Njbl9kb3duJG51bV9oaXRzCgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChnZW5vdHlwZV9mdWxsX2dwJGtoX3AwOF9zY25fZG93bltbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KcGxvdHNbWyJ0cmVlIl1dCmBgYAoKUGVyaGFwcyBJIHNob3VsZCBqdXN0IGFzayB0aGUgcXVlc3Rpb246IGZvciB3aGljaCBjYXRlZ29yaWVzIGRpZCBJIGdldCByZXN1bHRzIGJhY2s/CgpgYGB7cn0Kc3VtbWFyeShnZW5vdHlwZV9mdWxsX2dwKQpgYGAKCmtoX3AwOF9kbGduX3VwOiBObyBzaWduaWZpY2FudCBnUHJvZmlsZXIgcmVzdWx0cy4Ka2hfcDE1X2RsZ25fdXA6IFNpZ25pZmljYW50IEJQLCBIUCwgS0VHRywgTUYsIFJFQUMsIFRGCmtoX3AwOF9zY25fdXA6IE5vIHNpZ25pZmljYW50IGdQcm9maWxlciByZXN1bHRzLgpraF9wMDhfc2NuX2Rvd246IFNpZ25pZmljYW50IEJQLCBNaVJOQSwgTUYsIFRGCmtoX3AxNV9zY25fZG93bjogU2lnbmlmaWNhbnQgQlAsIE1GCgoKYGBge3J9CnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGdlbm90eXBlX2Z1bGxfZ3BbWyJraF9wMTVfZGxnbl91cCJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KYGBgCgojIyBMb2NhdGlvbgoKIyMjIFNjbiB2cyByZXRpbmEga28sIHAwOAoKYGBge3J9CgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AwOF9rbyJdXVtbInNyX3AwOF9rb191cCJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDA4X2tvIl1dW1sic3JfcDA4X2tvX2Rvd24iXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCmBgYAoKIyMjIHNjbiB2cyByZXRpbmEsIGhldCwgcDA4CgpFbnJpY2hlZCBncm91cHM6IEJQLCBLRUdHLCBNRiwgVEYsIENDCgpgYGB7cn0Kc3VtbWFyeShsb2NhdGlvbl9ncFtbInNyX3AwOF9oZXQiXV1bWyJzcl9wMDhfaGV0X3VwIl1dKQpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AwOF9oZXQiXV1bWyJzcl9wMDhfaGV0X3VwIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQobG9jYXRpb25fZ3BbWyJzcl9wMDhfaGV0Il1dW1sic3JfcDA4X2hldF91cCJdXVtbIkNDX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDA4X2hldCJdXVtbInNyX3AwOF9oZXRfZG93biJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnNyX3AwOF9oZXRfdG9wbl9nc2VhIDwtIHBsb3RfdG9wbl9nc2VhKGxvY2F0aW9uX2NwW1siIl1dKQoKYGBgCgojIyMgU2NuIHZzIHJldGluYSBrbywgcDE1CgpgYGB7cn0KcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQobG9jYXRpb25fZ3BbWyJzcl9wMTVfa28iXV1bWyJzcl9wMTVfa29fdXAiXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AxNV9rbyJdXVtbInNyX3AxNV9rb19kb3duIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQpgYGAKCiMjIyBzY24gdnMgcmV0aW5hLCBoZXQsIHAxNQoKYGBge3J9CnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KGxvY2F0aW9uX2dwW1sic3JfcDE1X2hldCJdXVtbInNyX3AxNV9oZXRfdXAiXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCgpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdChsb2NhdGlvbl9ncFtbInNyX3AxNV9oZXQiXV1bWyJzcl9wMTVfaGV0X2Rvd24iXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCmBgYAoKIyMgVGltZQoKIyMjIGhldCByZXRpbmEKClVwczogc2lnbmlmaWNhbnQgcmVzdWx0cyBmb3IgQlAsIE1GLCBURgpEb3duczogQlAsIE1GLCBSRUFDLCBURiwgV1AKCmBgYHtyfQpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdCh0aW1lX2dwW1sidF9oZXRfcmV0aW5hIl1dW1sidF9oZXRfcmV0aW5hX3VwIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQoKcGxvdHMgPC0gcGxvdF9lbnJpY2hyZXN1bHQodGltZV9ncFtbInRfaGV0X3JldGluYSJdXVtbInRfaGV0X3JldGluYV9kb3duIl1dW1siQlBfZW5yaWNoIl1dKQpwbG90c1tbImRvdCJdXQpgYGAKCiMjIyBrbyByZXRpbmEKClVwOiBCUCwgTWlSTkEsIE1GCkRvd246IEJQLCBNRiwgUkVBQywgVEYKCmBgYHtyfQpwbG90cyA8LSBwbG90X2VucmljaHJlc3VsdCh0aW1lX2dwW1sidF9rb19yZXRpbmEiXV1bWyJ0X2tvX3JldGluYV91cCJdXVtbIkJQX2VucmljaCJdXSkKcGxvdHNbWyJkb3QiXV0KCnBsb3RzIDwtIHBsb3RfZW5yaWNocmVzdWx0KHRpbWVfZ3BbWyJ0X2tvX3JldGluYSJdXVtbInRfa29fcmV0aW5hX2Rvd24iXV1bWyJCUF9lbnJpY2giXV0pCnBsb3RzW1siZG90Il1dCmBgYAoKIyMjIGhldCBzY24KCk5laXRoZXIgb2YgdGhlIFNDTiBnUHJvZmlsZXIgcXVlcmllcyBwcm92aWRlZCBhbnkgcmVzdWx0cy4KCiMgQmlibGlvZ3JhcGh5CgpgYGB7ciBzYXZlbWUsIGV2YWw9RkFMU0V9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHNhdmVmaWxlKSkKdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZSA9IHNhdmVmaWxlKSkKYGBgCgpgYGB7ciBsb2FkbWVfYWZ0ZXIsIGV2YWw9RkFMU0V9CnRtcCA8LSBsb2FkbWUoZmlsZW5hbWUgPSBzYXZlZmlsZSkKYGBgCg==