1 Introduction

I still need to do some reading to understand this series of experiments; but I believe the idea was to use a short-hairpin to lower expression of hdac5 in some cases, and an adenovirus overexpression vector in others.

The overarching goals I do not yet understand.

2 Preprocessing

I passed these samples to my default preprocessing pipeline on the umiacs cluster with the following command:

cd preprocessing
start=$(pwd)
for i in $(/bin/ls -d *); do
    cd $i
    cyoa --task pipe --method prnaseq --species rnorvegicus_7.2_107 --gff_type gene \
         --stranded reverse --gff_tag ID \
         --input $(/bin/ls *.fastq.gz | tr '\n' ':' | sed 's/:$//g')
    cd $start
done

The above command iterates over every directory of raw data I created and runs my rnaseq (–method prnaseq) pipeline (–task pipe) using a new copy of the ensembl Rattus norvegicus genome (version 7.2) from ensembl’s release 107 (–species rnorvegicus_7.2_107). When I downloaded it, I saved a gene feature file and the fasta genome with the same prefix and therefore htseq will use the gene annotations (–gff_type gene) by identifier ‘ID’ (–gff_tag ID).

I did not provide any instructions for trimming nor mapping, so it will use my defaults. All of the scripts run on the cluster are therefore located in the preprocessing/*/scripts/ directories in files named lexically in the order they were performed.

3 Genome Annotation

I will extract annotations from ensembl, since it is my favorite. My load_biomart_annotation() function attempts to find an archive server from one year ago, this may be made explicit if one wishes.

One important caveat, when creating the expressionset data structure, the gene IDs must match and the gff usually uses IDs which are a specific combination of columns from the ensembl table. It usually takes a moment to figure out how the two data sources line up; as a result sometimes it is easier to just extract annotations directly from the gff file.

rn_annot <- load_biomart_annotations(species="rnorvegicus")
## The biomart annotations file already exists, loading from it.

4 Metadata collection

I often just copy/paste the relevant fields from the output files created by trimomatic/htseq/hisat/etc. However, I did make a fun function: gather_preprocessing_metadata() which in theory at least can fill out a metadata xlsx file.

written <- gather_preprocessing_metadata("sample_sheets/all_samples.xlsx")

I noticed a couple problems with my function:

  1. It does not like dates in the MM/DD/YYYY format. There are a couple reasons for which this may have happened.
  2. It did not save the condition/batch columns I created, so I copy/pasted them from the previous sheet.

5 Initial Data Structure

Let us create an expression set of the metadata and annotations. Note that the

annot <- rn_annot[["annotation"]]
rownames(annot) <- make.names(paste0("gene:", annot[["ensembl_gene_id"]]), unique=TRUE)
rownames(annot) <- gsub(pattern="\\.", replacement=":", x=rownames(annot))
rn_expt <- create_expt(metadata="sample_sheets/all_samples_modified.xlsx",
                       gene_info=annot, file_column="hisatcounttable")
## Reading the sample metadata.
## The sample definitions comprises: 24 rows(samples) and 27 columns(metadata fields).
## Matched 18641 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 23139 features and 24 samples.
written <- write_expt(rn_expt, excel="excel/rn_expt.xlsx")
## Deleting the file excel/rn_expt.xlsx before writing the tables.
## Writing the first sheet, containing a legend and some summary data.
## `geom_smooth()` using formula 'y ~ x'
## Error in checkModelStatus(fit, showWarnings = showWarnings, colinearityCutoff = colinearityCutoff,  : 
##   The variables specified in this model are redundant,
## so the design matrix is not full rank
## Retrying with only condition in the model.
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## The following object is masked from 'package:S4Vectors':
## 
##     expand
## 
## Total:84 s
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## `geom_smooth()` using formula 'y ~ x'
## Error in checkModelStatus(fit, showWarnings = showWarnings, colinearityCutoff = colinearityCutoff,  : 
##   The variables specified in this model are redundant,
## so the design matrix is not full rank
## Retrying with only condition in the model.
## 
## Total:64 s

6 Initial plots

Let us look briefly at a couple of likely plots of the data.

plot_libsize(rn_expt)$plot

plot_nonzero(rn_expt)$plot
## Scale for 'colour' is already present. Adding another scale for 'colour',
## which will replace the existing scale.
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.

This is worrisome. The trimming kept ~95% of the reads, which is awesome. Mapping appears to have been in the 90%s. I would therefore have assumed the numbers of reads mapped to genes to be higher than 1.1<x<3.7 million.

My first place to look into this is the fastqc output. My initial hypothesis is that the sequence duplication file will show a huge number of reads mapping to rRNA or some other ncRNA. It appears that guess was incorrect, there do not appear to be significantly over represented sequences in this data. Maybe lets look at the reads in IGV?

rn_norm <- normalize_expt(rn_expt, filter=TRUE, convert="cpm",
                          norm="quant", transform="log2")
## Removing 8998 low-count genes (14141 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(rn_norm)$plot
## Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

rn_nbsva <- normalize_expt(rn_expt, filter=TRUE, convert="cpm",
                           batch="svaseq", transform="log2")
## Removing 8998 low-count genes (14141 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 2953 values equal to 0, adding 1 to the matrix.
plot_pca(rn_nbsva)$plot
## Warning: ggrepel: 11 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

6.1 Test other factors

The sample metadata is a little limited vis a vis the ways in which the samples are categorized. We have, in effect, 4 primary factors:

  • The expression method used: either (I am assuming this from the sample name) a short hairpin which was presumably transfected, or an adenovirus overexpression transfection.
  • The perturbation goal: There are three goals used in these transfections, either do nothing, over-express HDAC5, or lower its expression.
  • The target of the transfection: This is either luc (luciferase I assume), GFP, or histone deacetylase 5 (which of course has its own tremendous set of changes it causes to the transcriptional landscape).
  • The combination of the above: There are at least two which one may express this, I chose 4 categories: control_kd, hdac5_kd, control_over, and hdac5_over. One may instead choose to combine the controls into one category, though I would argue (and the data agrees with me) that doing so is wrong; but in the ideal world the perturbation of the luciferase/GFP targets would do nothing and these categories would be identical.

With the above in mind, let us consider some of the other categorizations of the data and see if any make sense. I know already from the first picture that knockdown and overexpression are the two primary sources of variance.

kd_over <- set_expt_conditions(rn_expt, fact="insertion")
## This will, by definition, just be the exact plot as before colored differently.
kd_over_norm <- normalize_expt(kd_over, transform="log2", convert="cpm",
                               filter=TRUE, norm="quant")
## Removing 8998 low-count genes (14141 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(kd_over_norm)$plot
## Warning: ggrepel: 5 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

perturb <- set_expt_conditions(rn_expt, fact="perturbation")
## This will, by definition, just be the exact plot as before colored differently.
perturb_norm <- normalize_expt(perturb, transform="log2", convert="cpm",
                               filter=TRUE, norm="quant")
## Removing 8998 low-count genes (14141 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(perturb_norm)$plot
## Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

perturb_nb <- normalize_expt(perturb, transform="log2", convert="cpm",
                             filter=TRUE, batch="svaseq")
## Removing 8998 low-count genes (14141 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 2953 values equal to 0, adding 1 to the matrix.
plot_pca(perturb_nb)$plot
## Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

target <- set_expt_conditions(rn_expt, fact="target")
## This will, by definition, just be the exact plot as before colored differently.
target_norm <- normalize_expt(target, transform="log2", convert="cpm",
                              filter=TRUE, norm="quant")
## Removing 8998 low-count genes (14141 remaining).
## transform_counts: Found 2 values equal to 0, adding 1 to the matrix.
plot_pca(target_norm)$plot

target_nb <- normalize_expt(target, transform="log2", convert="cpm",
                            filter=TRUE, batch="svaseq")
## Removing 8998 low-count genes (14141 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 2953 values equal to 0, adding 1 to the matrix.
plot_pca(target_nb)$plot

7 Separate sets

kd <- subset_expt(rn_expt, subset="insertion=='short_hairpin'")
## subset_expt(): There were 24, now there are 10 samples.
kd_norm <- normalize_expt(kd, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 9136 low-count genes (14003 remaining).
## transform_counts: Found 1 values equal to 0, adding 1 to the matrix.
plot_pca(kd_norm)$plot

kd_nb <- normalize_expt(kd, transform="log2", convert="cpm", batch="svaseq", filter=TRUE)
## Removing 9136 low-count genes (14003 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 575 values equal to 0, adding 1 to the matrix.
plot_pca(kd_nb)$plot

oe <- subset_expt(rn_expt, subset="insertion=='adeno_assoc'")
## subset_expt(): There were 24, now there are 14 samples.
oe_norm <- normalize_expt(oe, transform="log2", convert="cpm", norm="quant", filter=TRUE)
## Removing 9977 low-count genes (13162 remaining).
## transform_counts: Found 4 values equal to 0, adding 1 to the matrix.
plot_pca(oe_norm)$plot

oe_nb <- normalize_expt(oe, transform="log2", convert="cpm", batch="svaseq", filter=TRUE)
## Removing 9977 low-count genes (13162 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 233 values equal to 0, adding 1 to the matrix.
plot_pca(oe_nb)$plot

8 Attempt a perturbation differential expression.

kd_de <- all_pairwise(kd, model_batch="svaseq", filter=TRUE)
## This DE analysis will perform all pairwise comparisons among:
## 
## control_kd   hdac5_kd 
##          5          5
## This analysis will include surrogate estimates from: svaseq.
## This will pre-filter the input data using normalize_expt's: TRUE argument.
## Removing 0 low-count genes (14003 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 575 values equal to 0, adding 1 to the matrix.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
kd_keeper <- list("down_control" = c("hdac5kd", "controlkd"))
kd_table <- combine_de_tables(kd_de, keepers=kd_keeper, excel="excel/kd_table.xlsx")
kd_sig <- extract_significant_genes(kd_table, according_to="deseq", p=0.1,
                                    excel="excel/kd_sig.xlsx")
## Using p column: deseq_adjp.
oe_de <- all_pairwise(oe, model_batch="svaseq", filter=TRUE)
## This DE analysis will perform all pairwise comparisons among:
## 
## control_over   hdac5_over 
##            7            7
## This analysis will include surrogate estimates from: svaseq.
## This will pre-filter the input data using normalize_expt's: TRUE argument.
## Removing 0 low-count genes (13162 remaining).
## Error in if (grep(pattern = "combat", x = method)) { : 
##   argument is of length zero
## Warning in do_batch(count_table, method = batch, expt_design = expt_design, :
## The batch_counts call failed. Returning non-batch reduced data.
## transform_counts: Found 233 values equal to 0, adding 1 to the matrix.
## Finished running DE analyses, collecting outputs.
## Comparing analyses.
oe_keeper <- list("up_control" = c("hdac5over", "controlover"))
oe_table <- combine_de_tables(oe_de, keepers=oe_keeper, excel="excel/oe_table.xlsx")
oe_sig <- extract_significant_genes(oe_table, according_to="deseq", p=0.1,
                                    excel="excel/oe_sig.xlsx")
## Using p column: deseq_adjp.
kd_up <- kd_sig[["deseq"]][["ups"]][["down_control"]]
nrow(kd_up)
## [1] 74
kd_down <- kd_sig[["deseq"]][["downs"]][["down_control"]]
nrow(kd_down)
## [1] 74
oe_up <- oe_sig[["deseq"]][["ups"]][["up_control"]]
nrow(oe_up)
## [1] 84
oe_down <- oe_sig[["deseq"]][["downs"]][["up_control"]]
nrow(oe_down)
## [1] 5
up_lst <- list(
    "kd_up" = rownames(kd_up),
    "oe_down" = rownames(oe_down))
Vennerable::Venn(up_lst)
## A Venn object on 2 sets named
## kd_up,oe_down 
## 00 10 01 11 
##  0 73  4  1
down_lst <- list(
    "kd_down" = rownames(kd_down),
    "oe_up" = rownames(oe_up))
first <- Vennerable::Venn(down_lst)


up_up <- list(
    "kd_up" = rownames(kd_up),
    "oe_up" = rownames(oe_up))
Vennerable::Venn(up_up)
## A Venn object on 2 sets named
## kd_up,oe_up 
## 00 10 01 11 
##  0 72 82  2
down_down <- list(
    "kd_down" = rownames(kd_down),
    "oe_down" = rownames(oe_down))
Vennerable::Venn(down_down)
## A Venn object on 2 sets named
## kd_down,oe_down 
## 00 10 01 11 
##  0 74  5  0
pander::pander(sessionInfo())

R version 4.2.1 (2022-06-23)

Platform: x86_64-pc-linux-gnu (64-bit)

locale: LC_CTYPE=en_US.UTF-8, LC_NUMERIC=C, LC_TIME=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, LC_MONETARY=en_US.UTF-8, LC_MESSAGES=en_US.UTF-8, LC_PAPER=en_US.UTF-8, LC_NAME=C, LC_ADDRESS=C, LC_TELEPHONE=C, LC_MEASUREMENT=en_US.UTF-8 and LC_IDENTIFICATION=C

attached base packages: splines, stats4, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: ruv(v.0.9.7.1), lme4(v.1.1-30), Matrix(v.1.4-1), BiocParallel(v.1.30.3), variancePartition(v.1.26.0), hpgltools(v.1.0), testthat(v.3.1.4), reticulate(v.1.25), SummarizedExperiment(v.1.26.1), GenomicRanges(v.1.48.0), GenomeInfoDb(v.1.32.2), IRanges(v.2.30.0), S4Vectors(v.0.34.0), MatrixGenerics(v.1.8.1), matrixStats(v.0.62.0), Biobase(v.2.56.0) and BiocGenerics(v.0.42.0)

loaded via a namespace (and not attached): rappdirs(v.0.3.3), rtracklayer(v.1.56.1), R.methodsS3(v.1.8.2), tidyr(v.1.2.0), ggplot2(v.3.3.6), bit64(v.4.0.5), knitr(v.1.39), R.utils(v.2.12.0), DelayedArray(v.0.22.0), data.table(v.1.14.2), KEGGREST(v.1.36.3), RCurl(v.1.98-1.7), doParallel(v.1.0.17), generics(v.0.1.3), GenomicFeatures(v.1.48.3), preprocessCore(v.1.58.0), callr(v.3.7.1), RhpcBLASctl(v.0.21-247.1), usethis(v.2.1.6), RSQLite(v.2.2.15), shadowtext(v.0.1.2), bit(v.4.0.4), enrichplot(v.1.16.1), xml2(v.1.3.3), httpuv(v.1.6.5), assertthat(v.0.2.1), viridis(v.0.6.2), xfun(v.0.31), hms(v.1.1.1), jquerylib(v.0.1.4), IHW(v.1.24.0), evaluate(v.0.15), promises(v.1.2.0.1), DEoptimR(v.1.0-11), fansi(v.1.0.3), restfulr(v.0.0.15), progress(v.1.2.2), caTools(v.1.18.2), dbplyr(v.2.2.1), geneplotter(v.1.74.0), igraph(v.1.3.4), DBI(v.1.1.3), htmlwidgets(v.1.5.4), purrr(v.0.3.4), ellipsis(v.0.3.2), dplyr(v.1.0.9), backports(v.1.4.1), annotate(v.1.74.0), aod(v.1.3.2), biomaRt(v.2.52.0), vctrs(v.0.4.1), remotes(v.2.4.2), cachem(v.1.0.6), withr(v.2.5.0), ggforce(v.0.3.3), robustbase(v.0.95-0), GenomicAlignments(v.1.32.1), treeio(v.1.20.1), fdrtool(v.1.2.17), prettyunits(v.1.1.1), DOSE(v.3.22.0), ape(v.5.6-2), lazyeval(v.0.2.2), crayon(v.1.5.1), genefilter(v.1.78.0), slam(v.0.1-50), edgeR(v.3.38.1), pkgconfig(v.2.0.3), labeling(v.0.4.2), tweenr(v.1.0.2), nlme(v.3.1-158), pkgload(v.1.3.0), devtools(v.2.4.4), rlang(v.1.0.4), lifecycle(v.1.0.1), miniUI(v.0.1.1.1), downloader(v.0.4), filelock(v.1.0.2), BiocFileCache(v.2.4.0), directlabels(v.2021.1.13), rprojroot(v.2.0.3), polyclip(v.1.10-0), graph(v.1.74.0), aplot(v.0.1.6), lpsymphony(v.1.24.0), boot(v.1.3-28), processx(v.3.7.0), png(v.0.1-7), viridisLite(v.0.4.0), rjson(v.0.2.21), bitops(v.1.0-7), R.oo(v.1.25.0), KernSmooth(v.2.23-20), pander(v.0.6.5), Biostrings(v.2.64.0), blob(v.1.2.3), stringr(v.1.4.0), qvalue(v.2.28.0), gridGraphics(v.0.5-1), scales(v.1.2.0), memoise(v.2.0.1), magrittr(v.2.0.3), plyr(v.1.8.7), gplots(v.3.1.3), zlibbioc(v.1.42.0), compiler(v.4.2.1), scatterpie(v.0.1.7), BiocIO(v.1.6.0), RColorBrewer(v.1.1-3), DESeq2(v.1.36.0), Rsamtools(v.2.12.0), cli(v.3.3.0), XVector(v.0.36.0), urlchecker(v.1.0.1), patchwork(v.1.1.1), ps(v.1.7.1), MASS(v.7.3-58), mgcv(v.1.8-40), tidyselect(v.1.1.2), stringi(v.1.7.8), highr(v.0.9), yaml(v.2.3.5), GOSemSim(v.2.22.0), locfit(v.1.5-9.6), ggrepel(v.0.9.1), grid(v.4.2.1), sass(v.0.4.2), fastmatch(v.1.1-3), tools(v.4.2.1), parallel(v.4.2.1), rstudioapi(v.0.13), foreach(v.1.5.2), gridExtra(v.2.3), farver(v.2.1.1), Rtsne(v.0.16), ggraph(v.2.0.5), digest(v.0.6.29), shiny(v.1.7.2), quadprog(v.1.5-8), Rcpp(v.1.0.9), broom(v.1.0.0), later(v.1.3.0), httr(v.1.4.3), AnnotationDbi(v.1.58.0), Rdpack(v.2.4), colorspace(v.2.0-3), brio(v.1.1.3), XML(v.3.99-0.10), fs(v.1.5.2), RBGL(v.1.72.0), yulab.utils(v.0.0.5), PROPER(v.1.28.0), tidytree(v.0.3.9), graphlayouts(v.0.8.0), ggplotify(v.0.1.0), plotly(v.4.10.0), sessioninfo(v.1.2.2), xtable(v.1.8-4), jsonlite(v.1.8.0), nloptr(v.2.0.3), ggtree(v.3.4.1), tidygraph(v.1.2.1), corpcor(v.1.6.10), ggfun(v.0.0.6), Vennerable(v.3.1.0.9000), R6(v.2.5.1), profvis(v.0.3.7), pillar(v.1.8.0), htmltools(v.0.5.3), mime(v.0.12), glue(v.1.6.2), fastmap(v.1.1.0), minqa(v.1.2.4), clusterProfiler(v.4.4.4), codetools(v.0.2-18), fgsea(v.1.22.0), pkgbuild(v.1.3.1), utf8(v.1.2.2), lattice(v.0.20-45), bslib(v.0.4.0), tibble(v.3.1.8), sva(v.3.44.0), pbkrtest(v.0.5.1), curl(v.4.3.2), gtools(v.3.9.3), zip(v.2.2.0), GO.db(v.3.15.0), openxlsx(v.4.2.5), survival(v.3.3-1), limma(v.3.52.2), rmarkdown(v.2.14), desc(v.1.4.1), munsell(v.0.5.0), DO.db(v.2.9), fastcluster(v.1.2.3), GenomeInfoDbData(v.1.2.8), iterators(v.1.0.14), reshape2(v.1.4.4), gtable(v.0.3.0) and rbibutils(v.2.2.8)

message(paste0("This is hpgltools commit: ", get_git_commit()))
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 86f725d3ee8482b45960e3a4541f1d4ade97a406
## This is hpgltools commit: Thu Jul 21 11:08:25 2022 -0400: 86f725d3ee8482b45960e3a4541f1d4ade97a406
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
## Saving to index-v202208.rda.xz
tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiSGlzdG9uZSBEZWFjZXR5bGFzZSA1IHVuZGVyL292ZXIgZXhwcmVzc2lvbiBpbiBSLm5vcm5lZ2ljdXMuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB3aWR0aDogMzAwCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgQmlvY1N0eWxlOjpodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKbGlicmFyeSgicmV0aWN1bGF0ZSIpCnR0IDwtIGRldnRvb2xzOjpsb2FkX2FsbCgifi9ocGdsdG9vbHMiKQprbml0cjo6b3B0c19rbml0JHNldCh3aWR0aD0xMjAsCiAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgZWNobz1UUlVFKQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3I9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplPTEwKSkKcnVuZGF0ZSA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgZm9ybWF0PSIlWSVtJWQiKQpwcmV2aW91c19maWxlIDwtICIiCnZlciA8LSBmb3JtYXQoU3lzLkRhdGUoKSwgIiVZJW0iKQoKIyN0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpCnJtZF9maWxlIDwtICJpbmRleC5SbWQiCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkkgc3RpbGwgbmVlZCB0byBkbyBzb21lIHJlYWRpbmcgdG8gdW5kZXJzdGFuZCB0aGlzIHNlcmllcyBvZgpleHBlcmltZW50czsgYnV0IEkgYmVsaWV2ZSB0aGUgaWRlYSB3YXMgdG8gdXNlIGEgc2hvcnQtaGFpcnBpbiB0bwpsb3dlciBleHByZXNzaW9uIG9mIGhkYWM1IGluIHNvbWUgY2FzZXMsIGFuZCBhbiBhZGVub3ZpcnVzCm92ZXJleHByZXNzaW9uIHZlY3RvciBpbiBvdGhlcnMuCgpUaGUgb3ZlcmFyY2hpbmcgZ29hbHMgSSBkbyBub3QgeWV0IHVuZGVyc3RhbmQuCgojIFByZXByb2Nlc3NpbmcKCkkgcGFzc2VkIHRoZXNlIHNhbXBsZXMgdG8gbXkgZGVmYXVsdCBwcmVwcm9jZXNzaW5nIHBpcGVsaW5lIG9uIHRoZQp1bWlhY3MgY2x1c3RlciB3aXRoIHRoZSBmb2xsb3dpbmcgY29tbWFuZDoKCmBgYHtiYXNoIHByZXByb2Nlc3MsIGV2YWw9RkFMU0V9CmNkIHByZXByb2Nlc3NpbmcKc3RhcnQ9JChwd2QpCmZvciBpIGluICQoL2Jpbi9scyAtZCAqKTsgZG8KICAgIGNkICRpCiAgICBjeW9hIC0tdGFzayBwaXBlIC0tbWV0aG9kIHBybmFzZXEgLS1zcGVjaWVzIHJub3J2ZWdpY3VzXzcuMl8xMDcgLS1nZmZfdHlwZSBnZW5lIFwKICAgICAgICAgLS1zdHJhbmRlZCByZXZlcnNlIC0tZ2ZmX3RhZyBJRCBcCiAgICAgICAgIC0taW5wdXQgJCgvYmluL2xzICouZmFzdHEuZ3ogfCB0ciAnXG4nICc6JyB8IHNlZCAncy86JC8vZycpCiAgICBjZCAkc3RhcnQKZG9uZQpgYGAKClRoZSBhYm92ZSBjb21tYW5kIGl0ZXJhdGVzIG92ZXIgZXZlcnkgZGlyZWN0b3J5IG9mIHJhdyBkYXRhIEkgY3JlYXRlZAphbmQgcnVucyBteSBybmFzZXEgKC0tbWV0aG9kIHBybmFzZXEpIHBpcGVsaW5lICgtLXRhc2sgcGlwZSkgdXNpbmcgYQpuZXcgY29weSBvZiB0aGUgZW5zZW1ibCBSYXR0dXMgbm9ydmVnaWN1cyBnZW5vbWUgKHZlcnNpb24gNy4yKSBmcm9tCmVuc2VtYmwncyByZWxlYXNlIDEwNyAoLS1zcGVjaWVzIHJub3J2ZWdpY3VzXzcuMl8xMDcpLiAgV2hlbiBJCmRvd25sb2FkZWQgaXQsIEkgc2F2ZWQgYSBnZW5lIGZlYXR1cmUgZmlsZSBhbmQgdGhlIGZhc3RhIGdlbm9tZSB3aXRoCnRoZSBzYW1lIHByZWZpeCBhbmQgdGhlcmVmb3JlIGh0c2VxIHdpbGwgdXNlIHRoZSBnZW5lIGFubm90YXRpb25zCigtLWdmZl90eXBlIGdlbmUpIGJ5IGlkZW50aWZpZXIgJ0lEJyAoLS1nZmZfdGFnIElEKS4KCkkgZGlkIG5vdCBwcm92aWRlIGFueSBpbnN0cnVjdGlvbnMgZm9yIHRyaW1taW5nIG5vciBtYXBwaW5nLCBzbyBpdAp3aWxsIHVzZSBteSBkZWZhdWx0cy4gIEFsbCBvZiB0aGUgc2NyaXB0cyBydW4gb24gdGhlIGNsdXN0ZXIgYXJlCnRoZXJlZm9yZSBsb2NhdGVkIGluIHRoZSBwcmVwcm9jZXNzaW5nLyovc2NyaXB0cy8gZGlyZWN0b3JpZXMgaW4gZmlsZXMKbmFtZWQgbGV4aWNhbGx5IGluIHRoZSBvcmRlciB0aGV5IHdlcmUgcGVyZm9ybWVkLgoKIyBHZW5vbWUgQW5ub3RhdGlvbgoKSSB3aWxsIGV4dHJhY3QgYW5ub3RhdGlvbnMgZnJvbSBlbnNlbWJsLCBzaW5jZSBpdCBpcyBteSBmYXZvcml0ZS4gIE15CmxvYWRfYmlvbWFydF9hbm5vdGF0aW9uKCkgZnVuY3Rpb24gYXR0ZW1wdHMgdG8gZmluZCBhbiBhcmNoaXZlIHNlcnZlcgpmcm9tIG9uZSB5ZWFyIGFnbywgdGhpcyBtYXkgYmUgbWFkZSBleHBsaWNpdCBpZiBvbmUgd2lzaGVzLgoKT25lIGltcG9ydGFudCBjYXZlYXQsIHdoZW4gY3JlYXRpbmcgdGhlIGV4cHJlc3Npb25zZXQgZGF0YSBzdHJ1Y3R1cmUsCnRoZSBnZW5lIElEcyBtdXN0IG1hdGNoIGFuZCB0aGUgZ2ZmIHVzdWFsbHkgdXNlcyBJRHMgd2hpY2ggYXJlIGEKc3BlY2lmaWMgY29tYmluYXRpb24gb2YgY29sdW1ucyBmcm9tIHRoZSBlbnNlbWJsIHRhYmxlLiAgSXQgdXN1YWxseQp0YWtlcyBhIG1vbWVudCB0byBmaWd1cmUgb3V0IGhvdyB0aGUgdHdvIGRhdGEgc291cmNlcyBsaW5lIHVwOyBhcyBhCnJlc3VsdCBzb21ldGltZXMgaXQgaXMgZWFzaWVyIHRvIGp1c3QgZXh0cmFjdCBhbm5vdGF0aW9ucyBkaXJlY3RseQpmcm9tIHRoZSBnZmYgZmlsZS4KCmBgYHtyIGFubm90YXRpb259CnJuX2Fubm90IDwtIGxvYWRfYmlvbWFydF9hbm5vdGF0aW9ucyhzcGVjaWVzPSJybm9ydmVnaWN1cyIpCmBgYAoKIyBNZXRhZGF0YSBjb2xsZWN0aW9uCgpJIG9mdGVuIGp1c3QgY29weS9wYXN0ZSB0aGUgcmVsZXZhbnQgZmllbGRzIGZyb20gdGhlIG91dHB1dCBmaWxlcwpjcmVhdGVkIGJ5IHRyaW1vbWF0aWMvaHRzZXEvaGlzYXQvZXRjLiAgSG93ZXZlciwgSSBkaWQgbWFrZSBhIGZ1bgpmdW5jdGlvbjogZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoKSB3aGljaCBpbiB0aGVvcnkgYXQgbGVhc3QgY2FuCmZpbGwgb3V0IGEgbWV0YWRhdGEgeGxzeCBmaWxlLgoKYGBge3IgbWV0YWRhdGEsIGV2YWw9RkFMU0V9CndyaXR0ZW4gPC0gZ2F0aGVyX3ByZXByb2Nlc3NpbmdfbWV0YWRhdGEoInNhbXBsZV9zaGVldHMvYWxsX3NhbXBsZXMueGxzeCIpCmBgYAoKSSBub3RpY2VkIGEgY291cGxlIHByb2JsZW1zIHdpdGggbXkgZnVuY3Rpb246CgoxLiAgSXQgZG9lcyBub3QgbGlrZSBkYXRlcyBpbiB0aGUgTU0vREQvWVlZWSBmb3JtYXQuICBUaGVyZSBhcmUgYQogICAgY291cGxlIHJlYXNvbnMgZm9yIHdoaWNoIHRoaXMgbWF5IGhhdmUgaGFwcGVuZWQuCjIuICBJdCBkaWQgbm90IHNhdmUgdGhlIGNvbmRpdGlvbi9iYXRjaCBjb2x1bW5zIEkgY3JlYXRlZCwgc28gSQogICAgY29weS9wYXN0ZWQgdGhlbSBmcm9tIHRoZSBwcmV2aW91cyBzaGVldC4KCiMgSW5pdGlhbCBEYXRhIFN0cnVjdHVyZQoKTGV0IHVzIGNyZWF0ZSBhbiBleHByZXNzaW9uIHNldCBvZiB0aGUgbWV0YWRhdGEgYW5kIGFubm90YXRpb25zLiAgTm90ZQp0aGF0IHRoZQoKYGBge3IgZXhwdH0KYW5ub3QgPC0gcm5fYW5ub3RbWyJhbm5vdGF0aW9uIl1dCnJvd25hbWVzKGFubm90KSA8LSBtYWtlLm5hbWVzKHBhc3RlMCgiZ2VuZToiLCBhbm5vdFtbImVuc2VtYmxfZ2VuZV9pZCJdXSksIHVuaXF1ZT1UUlVFKQpyb3duYW1lcyhhbm5vdCkgPC0gZ3N1YihwYXR0ZXJuPSJcXC4iLCByZXBsYWNlbWVudD0iOiIsIHg9cm93bmFtZXMoYW5ub3QpKQpybl9leHB0IDwtIGNyZWF0ZV9leHB0KG1ldGFkYXRhPSJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzX21vZGlmaWVkLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgIGdlbmVfaW5mbz1hbm5vdCwgZmlsZV9jb2x1bW49Imhpc2F0Y291bnR0YWJsZSIpCgp3cml0dGVuIDwtIHdyaXRlX2V4cHQocm5fZXhwdCwgZXhjZWw9ImV4Y2VsL3JuX2V4cHQueGxzeCIpCmBgYAoKIyBJbml0aWFsIHBsb3RzCgpMZXQgdXMgbG9vayBicmllZmx5IGF0IGEgY291cGxlIG9mIGxpa2VseSBwbG90cyBvZiB0aGUgZGF0YS4KCmBgYHtyIGluaXRpYWx9CnBsb3RfbGlic2l6ZShybl9leHB0KSRwbG90CgpwbG90X25vbnplcm8ocm5fZXhwdCkkcGxvdApgYGAKClRoaXMgaXMgd29ycmlzb21lLiAgVGhlIHRyaW1taW5nIGtlcHQgfjk1JSBvZiB0aGUgcmVhZHMsIHdoaWNoIGlzCmF3ZXNvbWUuICBNYXBwaW5nIGFwcGVhcnMgdG8gaGF2ZSBiZWVuIGluIHRoZSA5MCVzLiAgSSB3b3VsZCB0aGVyZWZvcmUKaGF2ZSBhc3N1bWVkIHRoZSBudW1iZXJzIG9mIHJlYWRzIG1hcHBlZCB0byBnZW5lcyB0byBiZSBoaWdoZXIgdGhhbgoxLjE8eDwzLjcgbWlsbGlvbi4KCk15IGZpcnN0IHBsYWNlIHRvIGxvb2sgaW50byB0aGlzIGlzIHRoZSBmYXN0cWMgb3V0cHV0LiAgTXkgaW5pdGlhbApoeXBvdGhlc2lzIGlzIHRoYXQgdGhlIHNlcXVlbmNlIGR1cGxpY2F0aW9uIGZpbGUgd2lsbCBzaG93IGEgaHVnZQpudW1iZXIgb2YgcmVhZHMgbWFwcGluZyB0byByUk5BIG9yIHNvbWUgb3RoZXIgbmNSTkEuICBJdCBhcHBlYXJzIHRoYXQKZ3Vlc3Mgd2FzIGluY29ycmVjdCwgdGhlcmUgZG8gbm90IGFwcGVhciB0byBiZSBzaWduaWZpY2FudGx5IG92ZXIKcmVwcmVzZW50ZWQgc2VxdWVuY2VzIGluIHRoaXMgZGF0YS4gIE1heWJlIGxldHMgbG9vayBhdCB0aGUgcmVhZHMgaW4gSUdWPwoKYGBge3Igb3RoZXJfcGxvdHN9CnJuX25vcm0gPC0gbm9ybWFsaXplX2V4cHQocm5fZXhwdCwgZmlsdGVyPVRSVUUsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCB0cmFuc2Zvcm09ImxvZzIiKQpwbG90X3BjYShybl9ub3JtKSRwbG90Cgpybl9uYnN2YSA8LSBub3JtYWxpemVfZXhwdChybl9leHB0LCBmaWx0ZXI9VFJVRSwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIpCnBsb3RfcGNhKHJuX25ic3ZhKSRwbG90CmBgYAoKIyMgVGVzdCBvdGhlciBmYWN0b3JzCgpUaGUgc2FtcGxlIG1ldGFkYXRhIGlzIGEgbGl0dGxlIGxpbWl0ZWQgdmlzIGEgdmlzIHRoZSB3YXlzIGluIHdoaWNoCnRoZSBzYW1wbGVzIGFyZSBjYXRlZ29yaXplZC4gIFdlIGhhdmUsIGluIGVmZmVjdCwgNCBwcmltYXJ5IGZhY3RvcnM6CgoqIFRoZSBleHByZXNzaW9uIG1ldGhvZCB1c2VkOiBlaXRoZXIgKEkgYW0gYXNzdW1pbmcgdGhpcyBmcm9tIHRoZQogIHNhbXBsZSBuYW1lKSBhIHNob3J0IGhhaXJwaW4gd2hpY2ggd2FzIHByZXN1bWFibHkgdHJhbnNmZWN0ZWQsIG9yIGFuCiAgYWRlbm92aXJ1cyBvdmVyZXhwcmVzc2lvbiB0cmFuc2ZlY3Rpb24uCiogVGhlIHBlcnR1cmJhdGlvbiBnb2FsOiBUaGVyZSBhcmUgdGhyZWUgZ29hbHMgdXNlZCBpbiB0aGVzZQogIHRyYW5zZmVjdGlvbnMsIGVpdGhlciBkbyBub3RoaW5nLCBvdmVyLWV4cHJlc3MgSERBQzUsIG9yIGxvd2VyIGl0cwogIGV4cHJlc3Npb24uCiogVGhlIHRhcmdldCBvZiB0aGUgdHJhbnNmZWN0aW9uOiBUaGlzIGlzIGVpdGhlciBsdWMgKGx1Y2lmZXJhc2UgSQogIGFzc3VtZSksIEdGUCwgb3IgaGlzdG9uZSBkZWFjZXR5bGFzZSA1ICh3aGljaCBvZiBjb3Vyc2UgaGFzIGl0cyBvd24KICB0cmVtZW5kb3VzIHNldCBvZiBjaGFuZ2VzIGl0IGNhdXNlcyB0byB0aGUgdHJhbnNjcmlwdGlvbmFsCiAgbGFuZHNjYXBlKS4KKiBUaGUgY29tYmluYXRpb24gb2YgdGhlIGFib3ZlOiBUaGVyZSBhcmUgYXQgbGVhc3QgdHdvIHdoaWNoIG9uZSBtYXkKICBleHByZXNzIHRoaXMsIEkgY2hvc2UgNCBjYXRlZ29yaWVzOiBjb250cm9sX2tkLCBoZGFjNV9rZCwKICBjb250cm9sX292ZXIsIGFuZCBoZGFjNV9vdmVyLiAgT25lIG1heSBpbnN0ZWFkIGNob29zZSB0byBjb21iaW5lIHRoZQogIGNvbnRyb2xzIGludG8gb25lIGNhdGVnb3J5LCB0aG91Z2ggSSB3b3VsZCBhcmd1ZSAoYW5kIHRoZSBkYXRhCiAgYWdyZWVzIHdpdGggbWUpIHRoYXQgZG9pbmcgc28gaXMgd3Jvbmc7IGJ1dCBpbiB0aGUgaWRlYWwgd29ybGQgdGhlCiAgcGVydHVyYmF0aW9uIG9mIHRoZSBsdWNpZmVyYXNlL0dGUCB0YXJnZXRzIHdvdWxkIGRvIG5vdGhpbmcgYW5kCiAgdGhlc2UgY2F0ZWdvcmllcyB3b3VsZCBiZSBpZGVudGljYWwuCgpXaXRoIHRoZSBhYm92ZSBpbiBtaW5kLCBsZXQgdXMgY29uc2lkZXIgc29tZSBvZiB0aGUgb3RoZXIKY2F0ZWdvcml6YXRpb25zIG9mIHRoZSBkYXRhIGFuZCBzZWUgaWYgYW55IG1ha2Ugc2Vuc2UuICBJIGtub3cgYWxyZWFkeQpmcm9tIHRoZSBmaXJzdCBwaWN0dXJlIHRoYXQga25vY2tkb3duIGFuZCBvdmVyZXhwcmVzc2lvbiBhcmUgdGhlIHR3bwpwcmltYXJ5IHNvdXJjZXMgb2YgdmFyaWFuY2UuCgpgYGB7ciBvdGhlcl9jb2xvcnN9CmtkX292ZXIgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhybl9leHB0LCBmYWN0PSJpbnNlcnRpb24iKQojIyBUaGlzIHdpbGwsIGJ5IGRlZmluaXRpb24sIGp1c3QgYmUgdGhlIGV4YWN0IHBsb3QgYXMgYmVmb3JlIGNvbG9yZWQgZGlmZmVyZW50bHkuCmtkX292ZXJfbm9ybSA8LSBub3JtYWxpemVfZXhwdChrZF9vdmVyLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IikKcGxvdF9wY2Eoa2Rfb3Zlcl9ub3JtKSRwbG90CgpwZXJ0dXJiIDwtIHNldF9leHB0X2NvbmRpdGlvbnMocm5fZXhwdCwgZmFjdD0icGVydHVyYmF0aW9uIikKIyMgVGhpcyB3aWxsLCBieSBkZWZpbml0aW9uLCBqdXN0IGJlIHRoZSBleGFjdCBwbG90IGFzIGJlZm9yZSBjb2xvcmVkIGRpZmZlcmVudGx5LgpwZXJ0dXJiX25vcm0gPC0gbm9ybWFsaXplX2V4cHQocGVydHVyYiwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBub3JtPSJxdWFudCIpCnBsb3RfcGNhKHBlcnR1cmJfbm9ybSkkcGxvdApwZXJ0dXJiX25iIDwtIG5vcm1hbGl6ZV9leHB0KHBlcnR1cmIsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJzdmFzZXEiKQpwbG90X3BjYShwZXJ0dXJiX25iKSRwbG90Cgp0YXJnZXQgPC0gc2V0X2V4cHRfY29uZGl0aW9ucyhybl9leHB0LCBmYWN0PSJ0YXJnZXQiKQojIyBUaGlzIHdpbGwsIGJ5IGRlZmluaXRpb24sIGp1c3QgYmUgdGhlIGV4YWN0IHBsb3QgYXMgYmVmb3JlIGNvbG9yZWQgZGlmZmVyZW50bHkuCnRhcmdldF9ub3JtIDwtIG5vcm1hbGl6ZV9leHB0KHRhcmdldCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIG5vcm09InF1YW50IikKcGxvdF9wY2EodGFyZ2V0X25vcm0pJHBsb3QKdGFyZ2V0X25iIDwtIG5vcm1hbGl6ZV9leHB0KHRhcmdldCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3Zhc2VxIikKcGxvdF9wY2EodGFyZ2V0X25iKSRwbG90CmBgYAoKIyBTZXBhcmF0ZSBzZXRzCgpgYGB7ciBrZF9leHBlcmltZW50fQprZCA8LSBzdWJzZXRfZXhwdChybl9leHB0LCBzdWJzZXQ9Imluc2VydGlvbj09J3Nob3J0X2hhaXJwaW4nIikKCmtkX25vcm0gPC0gbm9ybWFsaXplX2V4cHQoa2QsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IiwgZmlsdGVyPVRSVUUpCnBsb3RfcGNhKGtkX25vcm0pJHBsb3QKa2RfbmIgPC0gbm9ybWFsaXplX2V4cHQoa2QsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIGJhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKcGxvdF9wY2Eoa2RfbmIpJHBsb3QKCm9lIDwtIHN1YnNldF9leHB0KHJuX2V4cHQsIHN1YnNldD0iaW5zZXJ0aW9uPT0nYWRlbm9fYXNzb2MnIikKb2Vfbm9ybSA8LSBub3JtYWxpemVfZXhwdChvZSwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgbm9ybT0icXVhbnQiLCBmaWx0ZXI9VFJVRSkKcGxvdF9wY2Eob2Vfbm9ybSkkcGxvdApvZV9uYiA8LSBub3JtYWxpemVfZXhwdChvZSwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwgYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQpwbG90X3BjYShvZV9uYikkcGxvdApgYGAKCiMgQXR0ZW1wdCBhIHBlcnR1cmJhdGlvbiBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4KCmBgYHtyIHBlcnR1cmJfZGV9CmtkX2RlIDwtIGFsbF9wYWlyd2lzZShrZCwgbW9kZWxfYmF0Y2g9InN2YXNlcSIsIGZpbHRlcj1UUlVFKQprZF9rZWVwZXIgPC0gbGlzdCgiZG93bl9jb250cm9sIiA9IGMoImhkYWM1a2QiLCAiY29udHJvbGtkIikpCmtkX3RhYmxlIDwtIGNvbWJpbmVfZGVfdGFibGVzKGtkX2RlLCBrZWVwZXJzPWtkX2tlZXBlciwgZXhjZWw9ImV4Y2VsL2tkX3RhYmxlLnhsc3giKQprZF9zaWcgPC0gZXh0cmFjdF9zaWduaWZpY2FudF9nZW5lcyhrZF90YWJsZSwgYWNjb3JkaW5nX3RvPSJkZXNlcSIsIHA9MC4xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD0iZXhjZWwva2Rfc2lnLnhsc3giKQoKb2VfZGUgPC0gYWxsX3BhaXJ3aXNlKG9lLCBtb2RlbF9iYXRjaD0ic3Zhc2VxIiwgZmlsdGVyPVRSVUUpCm9lX2tlZXBlciA8LSBsaXN0KCJ1cF9jb250cm9sIiA9IGMoImhkYWM1b3ZlciIsICJjb250cm9sb3ZlciIpKQpvZV90YWJsZSA8LSBjb21iaW5lX2RlX3RhYmxlcyhvZV9kZSwga2VlcGVycz1vZV9rZWVwZXIsIGV4Y2VsPSJleGNlbC9vZV90YWJsZS54bHN4IikKb2Vfc2lnIDwtIGV4dHJhY3Rfc2lnbmlmaWNhbnRfZ2VuZXMob2VfdGFibGUsIGFjY29yZGluZ190bz0iZGVzZXEiLCBwPTAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ImV4Y2VsL29lX3NpZy54bHN4IikKCgprZF91cCA8LSBrZF9zaWdbWyJkZXNlcSJdXVtbInVwcyJdXVtbImRvd25fY29udHJvbCJdXQpucm93KGtkX3VwKQprZF9kb3duIDwtIGtkX3NpZ1tbImRlc2VxIl1dW1siZG93bnMiXV1bWyJkb3duX2NvbnRyb2wiXV0KbnJvdyhrZF9kb3duKQoKb2VfdXAgPC0gb2Vfc2lnW1siZGVzZXEiXV1bWyJ1cHMiXV1bWyJ1cF9jb250cm9sIl1dCm5yb3cob2VfdXApCm9lX2Rvd24gPC0gb2Vfc2lnW1siZGVzZXEiXV1bWyJkb3ducyJdXVtbInVwX2NvbnRyb2wiXV0KbnJvdyhvZV9kb3duKQoKdXBfbHN0IDwtIGxpc3QoCiAgICAia2RfdXAiID0gcm93bmFtZXMoa2RfdXApLAogICAgIm9lX2Rvd24iID0gcm93bmFtZXMob2VfZG93bikpClZlbm5lcmFibGU6OlZlbm4odXBfbHN0KQoKZG93bl9sc3QgPC0gbGlzdCgKICAgICJrZF9kb3duIiA9IHJvd25hbWVzKGtkX2Rvd24pLAogICAgIm9lX3VwIiA9IHJvd25hbWVzKG9lX3VwKSkKZmlyc3QgPC0gVmVubmVyYWJsZTo6VmVubihkb3duX2xzdCkKCgp1cF91cCA8LSBsaXN0KAogICAgImtkX3VwIiA9IHJvd25hbWVzKGtkX3VwKSwKICAgICJvZV91cCIgPSByb3duYW1lcyhvZV91cCkpClZlbm5lcmFibGU6OlZlbm4odXBfdXApCgpkb3duX2Rvd24gPC0gbGlzdCgKICAgICJrZF9kb3duIiA9IHJvd25hbWVzKGtkX2Rvd24pLAogICAgIm9lX2Rvd24iID0gcm93bmFtZXMob2VfZG93bikpClZlbm5lcmFibGU6OlZlbm4oZG93bl9kb3duKQpgYGAKCgpgYGB7ciBzYXZlbWV9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCg==