index.html preprocessing.html 01_annotation.html

1 Sample Estimation version: 20171102

Since I used kallisto for this work, I want to figure out tximport.

In 01_annotation.Rmd, I decided to open up a few lines of inquiry:

  • k10_raw: All samples using the full set of putative annotations.
  • k8_raw: Samples excluding hpgl1003 with the full set of annotations.
  • k10_count: All samples, removing those with < ‘threshold (5)’ counts/gene.
  • k8_count: 8 samples, ibid.
  • k10_conf: All samples, but removing transcripts with annotations less confident than 1e-10 blastx e-value and less identity than 60 percent to some other known gene.
  • k8_conf: 8 samples, ibid.
  • k10_count_conf: A combination of the count filter and confidence filter.
  • k8_count_conf: ibid, but with the 8 samples.

2 Examine these data sets

2.1 Raw data

Start with the full data set. This will take a rather long time to perform all the graphs, and since we are not likely to use it, I will limit myself to just plotting 1-2 graphs.

2.1.1 k10

k10_libsize <- plot_libsize(k10_raw)
k10_libsize$plot

k10_density <- sm(plot_density(k10_raw))
sm(k10_density$plot + ggplot2::scale_x_continuous(limits=c(1,100)))

k10_boxplot <- sm(plot_boxplot(k10_raw))
k10_boxplot

k10_corheat <- plot_corheat(k10_raw)

k10_tsne <- plot_tsne(k10_raw)
k10_tsne$plot

2.1.2 k8

k8_libsize <- plot_libsize(k8_raw)
k8_libsize$plot

k8_density <- sm(plot_density(k8_raw))
sm(k8_density$plot + ggplot2::scale_x_continuous(limits=c(1,100)))

k8_boxplot <- sm(plot_boxplot(k8_raw))
k8_boxplot

k8_corheat <- plot_corheat(k8_raw)

k8_tsne <- plot_tsne(k8_raw)
k8_tsne$plot

2.2 Count filtered data

When we get to the count filtered data, I suspect things will be more interesting. Therefore let us look at the full spectrum of plots before/after normalization.

2.2.1 k10

k10_count_raw_plots <- sm(graph_metrics(k10_count))
k10_count_norm <- sm(normalize_expt(k10_count, transform="log2", norm="quant", convert="cpm"))
k10_count_norm_plots <- sm(graph_metrics(k10_count_norm))
k10_count_normbatch <- sm(normalize_expt(k10_count, batch="svaseq", transform="log2", convert="cpm"))
k10_count_normbatch_plots <- graph_metrics(k10_count_normbatch)
## Closing the pdf plotting device(s) before printing plots.
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Graphing a boxplot.
## Graphing a correlation heatmap.
## Graphing a standard median correlation.
## Performing correlation.
## Graphing a distance heatmap.
## Graphing a standard median distance.
## Performing distance.
## Graphing a PCA plot.
## Graphing a T-SNE plot.
## Plotting a density plot.
## Plotting the representation of the top-n genes.
## Printing a color to condition legend.

2.2.1.1 Look at some plots

Let us see how the k10 count data appears

k10_count_raw_plots$libsize

sm(k10_count_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,200)))

k10_count_raw_plots$boxplot

k10_count_norm_plots$corheat
k10_count_norm_plots$smc

k10_count_norm_plots$disheat
k10_count_norm_plots$smd

k10_count_norm_plots$pcaplot

## See if the additional information in the 'batch' factor made a difference
k10_count_normbatch_plots$pcaplot

2.2.2 k8

k8_count_raw_plots <- sm(graph_metrics(k8_count))
k8_count_norm <- sm(normalize_expt(k8_count, transform="log2", norm="quant", convert="cpm"))
k8_count_norm_plots <- sm(graph_metrics(k8_count_norm))
k8_count_normbatch <- sm(normalize_expt(k8_count, batch="svaseq", transform="log2", convert="cpm"))
k8_count_normbatch_plots <- sm(graph_metrics(k8_count_normbatch))

2.2.2.1 Look at some plots

Let us see how the k8 count data appears

k8_count_raw_plots$libsize

sm(k8_count_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,200)))

k8_count_raw_plots$boxplot

k8_count_norm_plots$corheat
k8_count_norm_plots$smc

k8_count_norm_plots$disheat
k8_count_norm_plots$smd

k8_count_norm_plots$pcaplot

## See if the additional information in the 'batch' factor made a difference
k8_count_normbatch_plots$pcaplot

k8_count_normbatch_plots$tsneplot

2.3 Conf filtered data

When we get to the conf filtered data, I suspect things will be more interesting. Therefore let us look at the full spectrum of plots before/after normalization.

2.3.1 k10

k10_conf_raw_plots <- sm(graph_metrics(k10_conf))
k10_conf_norm <- sm(normalize_expt(k10_conf, transform="log2", norm="quant", convert="cpm"))
k10_conf_norm_plots <- sm(graph_metrics(k10_conf_norm))
k10_conf_normbatch <- sm(normalize_expt(k10_conf, batch="svaseq", transform="log2",
                                        convert="cpm", filter=TRUE))
k10_conf_normbatch_plots <- sm(graph_metrics(k10_conf_normbatch))

2.3.1.1 Look at some plots

Let us see how the k10 conf data appears

k10_conf_raw_plots$libsize

sm(k10_conf_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,100)))

k10_conf_raw_plots$boxplot

k10_conf_norm_plots$corheat
k10_conf_norm_plots$smc

k10_conf_norm_plots$disheat
k10_conf_norm_plots$smd

k10_conf_norm_plots$pcaplot

## See if the additional information in the 'batch' factor made a difference
k10_conf_normbatch_plots$pcaplot

2.3.2 k8

k8_conf_raw_plots <- sm(graph_metrics(k8_conf))
k8_conf_norm <- sm(normalize_expt(k8_conf, transform="log2", norm="quant", convert="cpm"))
k8_conf_norm_plots <- sm(graph_metrics(k8_conf_norm))
k8_conf_normbatch <- sm(normalize_expt(k8_conf, batch="svaseq", transform="log2",
                                       convert="cpm", filter=TRUE))
k8_conf_normbatch_plots <- sm(graph_metrics(k8_conf_normbatch))

2.3.2.1 Look at some plots

Let us see how the k8 conf data appears

k8_conf_raw_plots$libsize

sm(k8_conf_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,100)))

k8_conf_raw_plots$boxplot

k8_conf_norm_plots$corheat
k8_conf_norm_plots$smc

k8_conf_norm_plots$disheat
k8_conf_norm_plots$smd

k8_conf_norm_plots$pcaplot

k8_conf_norm_plots$tsneplot

## See if the additional information in the 'batch' factor made a difference
k8_conf_normbatch_plots$pcaplot

k8_conf_normbatch_plots$tsneplot

2.4 Count_Conf filtered data

When we get to the count_conf filtered data, I suspect things will be more interesting. Therefore let us look at the full spectrum of plots before/after normalization.

2.4.1 k10

k10_conf_count_raw_plots <- sm(graph_metrics(k10_conf_count))
k10_conf_count_norm <- sm(normalize_expt(k10_conf_count, transform="log2",
                                         norm="quant", convert="cpm"))
k10_conf_count_norm_plots <- sm(graph_metrics(k10_conf_count_norm))
k10_conf_count_normbatch <- sm(normalize_expt(k10_conf_count, batch="svaseq", transform="log2",
                                              convert="cpm", filter=TRUE))
k10_conf_count_normbatch_plots <- sm(graph_metrics(k10_conf_count_normbatch))

2.4.1.1 Look at some plots

Let us see how the k10 count_conf data appears

k10_conf_count_raw_plots$libsize

sm(k10_conf_count_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,100)))

k10_conf_count_raw_plots$boxplot

k10_conf_count_norm_plots$corheat
k10_conf_count_norm_plots$smc

k10_conf_count_norm_plots$disheat
k10_conf_count_norm_plots$smd

k10_conf_count_norm_plots$pcaplot

## See if the additional information in the 'batch' factor made a difference
k10_conf_count_normbatch_plots$pcaplot

k10_conf_count_normbatch_plots$tsneplot

2.4.2 k8

k8_conf_count_raw_plots <- sm(graph_metrics(k8_conf_count))
k8_conf_count_norm <- sm(normalize_expt(k8_conf_count, transform="log2",
                                        norm="quant", convert="cpm"))
k8_conf_count_norm_plots <- sm(graph_metrics(k8_conf_count_norm))
k8_conf_count_normbatch <- sm(normalize_expt(k8_conf_count, batch="svaseq",
                                             transform="log2", convert="cpm"))
k8_conf_count_normbatch_plots <- sm(graph_metrics(k8_conf_count_normbatch))

2.4.2.1 Look at some plots

Let us see how the k8 count_conf data appears

k8_conf_count_raw_plots$libsize

sm(k8_conf_count_raw_plots$density + ggplot2::scale_x_continuous(limits=c(1,100)))

k8_conf_count_raw_plots$boxplot

k8_conf_count_norm_plots$corheat
k8_conf_count_norm_plots$smc

k8_conf_count_norm_plots$disheat
k8_conf_count_norm_plots$smd

k8_conf_count_norm_plots$pcaplot

## See if the additional information in the 'batch' factor made a difference
k8_conf_count_normbatch_plots$pcaplot

k8_conf_count_normbatch_plots$tsneplot

3 Make a nice stacked libsize barplot

library(ggplot2)
maximum <- plot_libsize(k8_raw, text=FALSE)
maximum_alpha <- maximum$table
maximum_alpha$alpha <- alpha(maximum_alpha$colors, 0.4)
conf <- plot_libsize(k8_conf, text=FALSE)
conf_alpha <- conf$table
conf_alpha$alpha <- alpha(conf_alpha$colors, 0.6)
count <- plot_libsize(k8_count, text=FALSE)
count_alpha <- count$table
count_alpha$alpha <- alpha(count_alpha$colors, 0.8)
conf_count <- plot_libsize(k8_conf_count, text=FALSE)
conf_count_alpha <- conf_count$table
conf_count_alpha$alpha <- alpha(conf_count_alpha$colors, 1.0)

all <- rbind(maximum_alpha, conf_alpha,
             count_alpha, conf_count_alpha)

## The following will stack the library sizes from each subset one on top of the other.
## This is likely not desired, but it does provide sufficient room to print the library
## sizes if one wishes.
stacked <- ggplot(all, aes(x=id)) +
  geom_bar(aes(weight=sum, alpha=alpha, fill=colors), color="black") +
  scale_fill_manual(values=c(levels(as.factor(all$colors)))) +
  theme(axis.text=ggplot2::element_text(size=10, colour="black"),
        axis.text.x=ggplot2::element_text(angle=90, vjust=0.5),
        legend.position="none")
stacked

## In this instance, they are stacked on top of 0, which I suspect is the goal.
columns <- ggplot(all, aes(x=id, y=sum)) +
  geom_col(position="identity", aes(fill=colors, alpha=alpha), color="black") +
  scale_fill_manual(values=c(levels(as.factor(all$colors)))) +
  theme(axis.text=ggplot2::element_text(size=10, colour="black"),
        axis.text.x=ggplot2::element_text(angle=90, vjust=0.5),
        legend.position="none")
columns

4 Write up the favorites

Let us assume for a moment that we will choose a couple of the above for looking at more closely. I suspect k8_count_conf, k10_count_conf, and k8_count and k8_conf are good candidates.

output <- paste0("excel/k8_conf_count_by_tx-v", ver, ".xlsx")
if (!file.exists(output)) {
  k8_conf_count_written <- sm(write_expt(k8_conf_count, excel=output))
}
output <- paste0("excel/k10_conf_count_by_tx-v", ver, ".xlsx")
if (!file.exists(output)) {
  k10_conf_count_written <- sm(write_expt(k10_conf_count, excel=output))
}
output <- paste0("excel/k8_count_by_tx-v", ver, ".xlsx")
if (!file.exists(output)) {
  k8_count_written <- sm(write_expt(k8_count, excel=output))
}
output <- paste0("excel/k8_conf_by_tx-v", ver, ".xlsx")
if (!file.exists(output)) {
  k8_conf_written <- sm(write_expt(k8_conf, excel=output))
}

5 Quantify tx/gene

I want to see if there are some changes in the number of reads/tx between the embryogenic/nonembryogenic. I am not entirely certain how to do this, so I will poke about and see what happens.

I do have a data structure telling me the mapping of tx->gene.

transcript_gene_map <- putative_annotations[, c("transcript_id", "gene_id")]
mappings <- data.table::as.data.table(transcript_gene_map)
mappings[["num"]] <- 1
num_tx <- mappings[, list(num_tx=sum(num)), by="gene_id"]

tx_hist <- plot_histogram(num_tx$num_tx)
tx_hist

start <- normalize_expt(k8_raw, convert="cpm")
## This function will replace the expt$expressionset slot with:
## cpm(data)
## It backs up the current data into a slot named:
##  expt$backup_expressionset. It will also save copies of each step along the way
##  in expt$normalized with the corresponding libsizes. Keep the libsizes in mind
##  when invoking limma.  The appropriate libsize is the non-log(cpm(normalized)).
##  This is most likely kept at:
##  'new_expt$normalized$intermediate_counts$normalization$libsizes'
##  A copy of this may also be found at:
##  new_expt$best_libsize
## Filter is false, this should likely be set to something, good
##  choices include cbcb, kofa, pofa (anything but FALSE).  If you want this to
##  stay FALSE, keep in mind that if other normalizations are performed, then the
##  resulting libsizes are likely to be strange (potentially negative!)
## Leaving the data in its current base format, keep in mind that
##  some metrics are easier to see when the data is log2 transformed, but
##  EdgeR/DESeq do not accept transformed data.
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Not correcting the count-data for batch effects.  If batch is
##  included in EdgerR/limma's model, then this is probably wise; but in extreme
##  batch effects this is a good parameter to play with.
## Step 1: not doing count filtering.
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: not transforming the data.
## Step 5: not doing batch correction.
embryo <- subset_expt(start, subset="condition=='embryogenic'")
nonembryo <- subset_expt(start, subset="condition=='nonembryogenic'")
embryo_df <- as.data.frame(exprs(embryo))
embryo_df$em_mean <- rowMeans(embryo_df)
non_df <- as.data.frame(exprs(nonembryo))
non_df$non_mean <- rowMeans(non_df)
e <- as.data.frame(embryo_df[["em_mean"]])
rownames(e) <- rownames(embryo_df)
colnames(e) <- "em_mean"
n <- as.data.frame(non_df[["non_mean"]])
rownames(n) <- rownames(non_df)
colnames(n) <- "non_mean"
means <- merge(x=e, y=n, by="row.names")
rownames(means) <- means[["Row.names"]]
means <- means[, -1]
near_zero <- means <= 0.001
embryo_near_zero <- sum(near_zero[, "em_mean"])
embryo_near_zero
## [1] 35080
non_near_zero <- sum(near_zero[, "non_mean"])
non_near_zero
## [1] 52196
plot_boxplot(embryo)
## This data will benefit from being displayed on the log scale.
## If this is not desired, set scale='raw'
## Some entries are 0.  We are on log scale, adding 1 to the data.
## Changed 391753 zero count features.

plot_boxplot(nonembryo)
## This data will benefit from being displayed on the log scale.
## If this is not desired, set scale='raw'
## Some entries are 0.  We are on log scale, adding 1 to the data.
## Changed 508520 zero count features.

6 Note to self

I decided to not save the state of this file, because it is huge. The differential expression analyses do not need this, but need only the result of the annotation worksheet.

pander::pander(sessionInfo())

R version 3.4.4 RC (2018-03-09 r74380)

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

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

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

other attached packages: hpgltools(v.2017.10), ruv(v.0.9.6), data.table(v.1.10.4-3), beanplot(v.1.2), plyr(v.1.8.4) and ggplot2(v.2.2.1)

loaded via a namespace (and not attached): nlme(v.3.1-131.1), bitops(v.1.0-6), matrixStats(v.0.53.1), devtools(v.1.13.5), bit64(v.0.9-7), RColorBrewer(v.1.1-2), rprojroot(v.1.3-2), tools(v.3.4.4), backports(v.1.1.2), R6(v.2.2.2), KernSmooth(v.2.23-15), DBI(v.0.7), lazyeval(v.0.2.1), BiocGenerics(v.0.24.0), mgcv(v.1.8-23), colorspace(v.1.3-2), withr(v.2.1.1), tidyselect(v.0.2.4), bit(v.1.1-12), compiler(v.3.4.4), preprocessCore(v.1.40.0), Biobase(v.2.38.0), xml2(v.1.2.0), labeling(v.0.3), scales(v.0.5.0), readr(v.1.1.1), genefilter(v.1.60.0), quadprog(v.1.5-5), commonmark(v.1.4), stringr(v.1.3.0), digest(v.0.6.15), rmarkdown(v.1.8), base64enc(v.0.1-3), pkgconfig(v.2.0.1), htmltools(v.0.3.6), limma(v.3.34.9), rlang(v.0.2.0), RSQLite(v.2.0), bindr(v.0.1), BiocParallel(v.1.12.0), gtools(v.3.5.0), dplyr(v.0.7.4), RCurl(v.1.95-4.10), magrittr(v.1.5), Matrix(v.1.2-12), Rcpp(v.0.12.15), munsell(v.0.4.3), S4Vectors(v.0.16.0), stringi(v.1.1.6), yaml(v.2.1.16), edgeR(v.3.20.8), MASS(v.7.3-49), zlibbioc(v.1.24.0), rhdf5(v.2.22.0), Rtsne(v.0.13), grid(v.3.4.4), blob(v.1.1.0), parallel(v.3.4.4), ggrepel(v.0.7.0), lattice(v.0.20-35), splines(v.3.4.4), annotate(v.1.56.1), pander(v.0.6.1), hms(v.0.4.1), locfit(v.1.5-9.1), knitr(v.1.20), pillar(v.1.2.1), corpcor(v.1.6.9), reshape2(v.1.4.3), codetools(v.0.2-15), stats4(v.3.4.4), XML(v.3.98-1.10), glue(v.1.2.0), evaluate(v.0.10.1), foreach(v.1.4.4), gtable(v.0.2.0), purrr(v.0.2.4), tidyr(v.0.8.0), assertthat(v.0.2.0), openxlsx(v.4.0.17), xtable(v.1.8-2), roxygen2(v.6.0.1), survival(v.2.41-3), tibble(v.1.4.2), iterators(v.1.0.9), AnnotationDbi(v.1.40.0), memoise(v.1.1.0), IRanges(v.2.12.0), tximport(v.1.6.0), bindrcpp(v.0.2), sva(v.3.26.0) and directlabels(v.2017.03.31)

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 e3a7f13d63d6906d825dbfad37273ddd71e44e86
## R> packrat::restore()
## This is hpgltools commit: Mon Mar 12 12:11:17 2018 -0400: e3a7f13d63d6906d825dbfad37273ddd71e44e86
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
## Saving to 02_sample_estimation_tx-v20171102.rda.xz
## tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiU29sYW51bSBiZXRhY2V1bSBzYW1wbGUgZXN0aW1hdGlvbi4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKIGh0bWxfZG9jdW1lbnQ6CiAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGNvZGVfZm9sZGluZzogc2hvdwogIGZpZ19jYXB0aW9uOiB0cnVlCiAgZmlnX2hlaWdodDogNwogIGZpZ193aWR0aDogNwogIGhpZ2hsaWdodDogZGVmYXVsdAogIGtlZXBfbWQ6IGZhbHNlCiAgbW9kZTogc2VsZmNvbnRhaW5lZAogIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgdGhlbWU6IHJlYWRhYmxlCiAgdG9jOiB0cnVlCiAgdG9jX2Zsb2F0OgogICAgY29sbGFwc2VkOiBmYWxzZQogICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGU+CiAgYm9keSAubWFpbi1jb250YWluZXIgewogICAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGg9OTAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGg9OCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9OCwKICAgICAgICAgICAgICAgICAgICAgIGRwaT05NikKb2xkX29wdGlvbnMgPC0gb3B0aW9ucyhkaWdpdHM9NCwKICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbD0iYWxsb3ciKQpnZ3Bsb3QyOjp0aGVtZV9zZXQoZ2dwbG90Mjo6dGhlbWVfYncoYmFzZV9zaXplPTEwKSkKc2V0LnNlZWQoMSkKdmVyIDwtICIyMDE3MTEwMiIKcHJldmlvdXNfZmlsZSA8LSAiMDFfYW5ub3RhdGlvbl90eC5SbWQiCgp0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKSkKcm1kX2ZpbGUgPC0gIjAyX3NhbXBsZV9lc3RpbWF0aW9uX3R4LlJtZCIKYGBgCgpbaW5kZXguaHRtbF0oaW5kZXguaHRtbCkKW3ByZXByb2Nlc3NpbmcuaHRtbF0ocHJlcHJvY2Vzc2luZy5odG1sKQpbMDFfYW5ub3RhdGlvbi5odG1sXSgwMV9hbm5vdGF0aW9uLmh0bWwpCgojIFNhbXBsZSBFc3RpbWF0aW9uIHZlcnNpb246IGByIHZlcmAKClNpbmNlIEkgdXNlZCBrYWxsaXN0byBmb3IgdGhpcyB3b3JrLCBJIHdhbnQgdG8gZmlndXJlIG91dCB0eGltcG9ydC4KCkluIDAxX2Fubm90YXRpb24uUm1kLCBJIGRlY2lkZWQgdG8gb3BlbiB1cCBhIGZldyBsaW5lcyBvZiBpbnF1aXJ5OgoKKiBrMTBfcmF3OiAgIEFsbCBzYW1wbGVzIHVzaW5nIHRoZSBmdWxsIHNldCBvZiBwdXRhdGl2ZSBhbm5vdGF0aW9ucy4KKiBrOF9yYXc6ICBTYW1wbGVzIGV4Y2x1ZGluZyBocGdsMTAwMyB3aXRoIHRoZSBmdWxsIHNldCBvZiBhbm5vdGF0aW9ucy4KKiBrMTBfY291bnQ6IEFsbCBzYW1wbGVzLCByZW1vdmluZyB0aG9zZSB3aXRoIDwgJ3RocmVzaG9sZCAoNSknIGNvdW50cy9nZW5lLgoqIGs4X2NvdW50OiAgOCBzYW1wbGVzLCBpYmlkLgoqIGsxMF9jb25mOiAgQWxsIHNhbXBsZXMsIGJ1dCByZW1vdmluZyB0cmFuc2NyaXB0cyB3aXRoIGFubm90YXRpb25zIGxlc3MgY29uZmlkZW50IHRoYW4KICAgIDFlLTEwIGJsYXN0eCBlLXZhbHVlIGFuZCBsZXNzIGlkZW50aXR5IHRoYW4gNjAgcGVyY2VudCB0byBzb21lIG90aGVyIGtub3duIGdlbmUuCiogazhfY29uZjogIDggc2FtcGxlcywgaWJpZC4KKiBrMTBfY291bnRfY29uZjogIEEgY29tYmluYXRpb24gb2YgdGhlIGNvdW50IGZpbHRlciBhbmQgY29uZmlkZW5jZSBmaWx0ZXIuCiogazhfY291bnRfY29uZjogIGliaWQsIGJ1dCB3aXRoIHRoZSA4IHNhbXBsZXMuCgojIEV4YW1pbmUgdGhlc2UgZGF0YSBzZXRzCgojIyBSYXcgZGF0YQoKU3RhcnQgd2l0aCB0aGUgZnVsbCBkYXRhIHNldC4gIFRoaXMgd2lsbCB0YWtlIGEgcmF0aGVyIGxvbmcgdGltZSB0byBwZXJmb3JtIGFsbCB0aGUgZ3JhcGhzLAphbmQgc2luY2Ugd2UgYXJlIG5vdCBsaWtlbHkgdG8gdXNlIGl0LCBJIHdpbGwgbGltaXQgbXlzZWxmIHRvIGp1c3QgcGxvdHRpbmcgMS0yIGdyYXBocy4KCiMjIyBrMTAKCmBgYHtyIGsxMF9yYXd9CmsxMF9saWJzaXplIDwtIHBsb3RfbGlic2l6ZShrMTBfcmF3KQprMTBfbGlic2l6ZSRwbG90CmsxMF9kZW5zaXR5IDwtIHNtKHBsb3RfZGVuc2l0eShrMTBfcmF3KSkKc20oazEwX2RlbnNpdHkkcGxvdCArIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxLDEwMCkpKQprMTBfYm94cGxvdCA8LSBzbShwbG90X2JveHBsb3QoazEwX3JhdykpCmsxMF9ib3hwbG90CmsxMF9jb3JoZWF0IDwtIHBsb3RfY29yaGVhdChrMTBfcmF3KQprMTBfdHNuZSA8LSBwbG90X3RzbmUoazEwX3JhdykKazEwX3RzbmUkcGxvdApgYGAKCiMjIyBrOAoKYGBge3IgazhfcmF3fQprOF9saWJzaXplIDwtIHBsb3RfbGlic2l6ZShrOF9yYXcpCms4X2xpYnNpemUkcGxvdAprOF9kZW5zaXR5IDwtIHNtKHBsb3RfZGVuc2l0eShrOF9yYXcpKQpzbShrOF9kZW5zaXR5JHBsb3QgKyBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMSwxMDApKSkKazhfYm94cGxvdCA8LSBzbShwbG90X2JveHBsb3QoazhfcmF3KSkKazhfYm94cGxvdAprOF9jb3JoZWF0IDwtIHBsb3RfY29yaGVhdChrOF9yYXcpCms4X3RzbmUgPC0gcGxvdF90c25lKGs4X3JhdykKazhfdHNuZSRwbG90CmBgYAoKIyMgQ291bnQgZmlsdGVyZWQgZGF0YQoKV2hlbiB3ZSBnZXQgdG8gdGhlIGNvdW50IGZpbHRlcmVkIGRhdGEsIEkgc3VzcGVjdCB0aGluZ3Mgd2lsbCBiZSBtb3JlIGludGVyZXN0aW5nLgpUaGVyZWZvcmUgbGV0IHVzIGxvb2sgYXQgdGhlIGZ1bGwgc3BlY3RydW0gb2YgcGxvdHMgYmVmb3JlL2FmdGVyIG5vcm1hbGl6YXRpb24uCgojIyMgazEwCgpgYGB7ciBrMTBfY291bnQsIGZpZy5zaG93PSJoaWRlIn0KazEwX2NvdW50X3Jhd19wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGsxMF9jb3VudCkpCmsxMF9jb3VudF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGsxMF9jb3VudCwgdHJhbnNmb3JtPSJsb2cyIiwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iKSkKazEwX2NvdW50X25vcm1fcGxvdHMgPC0gc20oZ3JhcGhfbWV0cmljcyhrMTBfY291bnRfbm9ybSkpCmsxMF9jb3VudF9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQoazEwX2NvdW50LCBiYXRjaD0ic3Zhc2VxIiwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIikpCmsxMF9jb3VudF9ub3JtYmF0Y2hfcGxvdHMgPC0gZ3JhcGhfbWV0cmljcyhrMTBfY291bnRfbm9ybWJhdGNoKQpgYGAKCiMjIyMgTG9vayBhdCBzb21lIHBsb3RzCgpMZXQgdXMgc2VlIGhvdyB0aGUgazEwIGNvdW50IGRhdGEgYXBwZWFycwoKYGBge3Igc2hvd19rMTBfY291bnR9CmsxMF9jb3VudF9yYXdfcGxvdHMkbGlic2l6ZQpzbShrMTBfY291bnRfcmF3X3Bsb3RzJGRlbnNpdHkgKyBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMSwyMDApKSkKazEwX2NvdW50X3Jhd19wbG90cyRib3hwbG90CmsxMF9jb3VudF9ub3JtX3Bsb3RzJGNvcmhlYXQKazEwX2NvdW50X25vcm1fcGxvdHMkc21jCmsxMF9jb3VudF9ub3JtX3Bsb3RzJGRpc2hlYXQKazEwX2NvdW50X25vcm1fcGxvdHMkc21kCmsxMF9jb3VudF9ub3JtX3Bsb3RzJHBjYXBsb3QKIyMgU2VlIGlmIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGluIHRoZSAnYmF0Y2gnIGZhY3RvciBtYWRlIGEgZGlmZmVyZW5jZQprMTBfY291bnRfbm9ybWJhdGNoX3Bsb3RzJHBjYXBsb3QKYGBgCgojIyMgazgKCmBgYHtyIGs4X2NvdW50LCBmaWcuc2hvdz0iaGlkZSJ9Cms4X2NvdW50X3Jhd19wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGs4X2NvdW50KSkKazhfY291bnRfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChrOF9jb3VudCwgdHJhbnNmb3JtPSJsb2cyIiwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iKSkKazhfY291bnRfbm9ybV9wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGs4X2NvdW50X25vcm0pKQprOF9jb3VudF9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQoazhfY291bnQsIGJhdGNoPSJzdmFzZXEiLCB0cmFuc2Zvcm09ImxvZzIiLCBjb252ZXJ0PSJjcG0iKSkKazhfY291bnRfbm9ybWJhdGNoX3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazhfY291bnRfbm9ybWJhdGNoKSkKYGBgCgojIyMjIExvb2sgYXQgc29tZSBwbG90cwoKTGV0IHVzIHNlZSBob3cgdGhlIGs4IGNvdW50IGRhdGEgYXBwZWFycwoKYGBge3Igc2hvd19rOF9jb3VudH0KazhfY291bnRfcmF3X3Bsb3RzJGxpYnNpemUKc20oazhfY291bnRfcmF3X3Bsb3RzJGRlbnNpdHkgKyBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMSwyMDApKSkKazhfY291bnRfcmF3X3Bsb3RzJGJveHBsb3QKazhfY291bnRfbm9ybV9wbG90cyRjb3JoZWF0Cms4X2NvdW50X25vcm1fcGxvdHMkc21jCms4X2NvdW50X25vcm1fcGxvdHMkZGlzaGVhdAprOF9jb3VudF9ub3JtX3Bsb3RzJHNtZAprOF9jb3VudF9ub3JtX3Bsb3RzJHBjYXBsb3QKIyMgU2VlIGlmIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGluIHRoZSAnYmF0Y2gnIGZhY3RvciBtYWRlIGEgZGlmZmVyZW5jZQprOF9jb3VudF9ub3JtYmF0Y2hfcGxvdHMkcGNhcGxvdAprOF9jb3VudF9ub3JtYmF0Y2hfcGxvdHMkdHNuZXBsb3QKYGBgCgojIyBDb25mIGZpbHRlcmVkIGRhdGEKCldoZW4gd2UgZ2V0IHRvIHRoZSBjb25mIGZpbHRlcmVkIGRhdGEsIEkgc3VzcGVjdCB0aGluZ3Mgd2lsbCBiZSBtb3JlIGludGVyZXN0aW5nLgpUaGVyZWZvcmUgbGV0IHVzIGxvb2sgYXQgdGhlIGZ1bGwgc3BlY3RydW0gb2YgcGxvdHMgYmVmb3JlL2FmdGVyIG5vcm1hbGl6YXRpb24uCgojIyMgazEwCgpgYGB7ciBrMTBfY29uZiwgZmlnLnNob3c9ImhpZGUifQprMTBfY29uZl9yYXdfcGxvdHMgPC0gc20oZ3JhcGhfbWV0cmljcyhrMTBfY29uZikpCmsxMF9jb25mX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoazEwX2NvbmYsIHRyYW5zZm9ybT0ibG9nMiIsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIikpCmsxMF9jb25mX25vcm1fcGxvdHMgPC0gc20oZ3JhcGhfbWV0cmljcyhrMTBfY29uZl9ub3JtKSkKazEwX2NvbmZfbm9ybWJhdGNoIDwtIHNtKG5vcm1hbGl6ZV9leHB0KGsxMF9jb25mLCBiYXRjaD0ic3Zhc2VxIiwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFKSkKazEwX2NvbmZfbm9ybWJhdGNoX3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazEwX2NvbmZfbm9ybWJhdGNoKSkKYGBgCgojIyMjIExvb2sgYXQgc29tZSBwbG90cwoKTGV0IHVzIHNlZSBob3cgdGhlIGsxMCBjb25mIGRhdGEgYXBwZWFycwoKYGBge3Igc2hvd19rMTBfY29uZn0KazEwX2NvbmZfcmF3X3Bsb3RzJGxpYnNpemUKc20oazEwX2NvbmZfcmF3X3Bsb3RzJGRlbnNpdHkgKyBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMSwxMDApKSkKazEwX2NvbmZfcmF3X3Bsb3RzJGJveHBsb3QKazEwX2NvbmZfbm9ybV9wbG90cyRjb3JoZWF0CmsxMF9jb25mX25vcm1fcGxvdHMkc21jCmsxMF9jb25mX25vcm1fcGxvdHMkZGlzaGVhdAprMTBfY29uZl9ub3JtX3Bsb3RzJHNtZAprMTBfY29uZl9ub3JtX3Bsb3RzJHBjYXBsb3QKIyMgU2VlIGlmIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGluIHRoZSAnYmF0Y2gnIGZhY3RvciBtYWRlIGEgZGlmZmVyZW5jZQprMTBfY29uZl9ub3JtYmF0Y2hfcGxvdHMkcGNhcGxvdApgYGAKCiMjIyBrOAoKYGBge3IgazhfY29uZiwgZmlnLnNob3c9ImhpZGUifQprOF9jb25mX3Jhd19wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGs4X2NvbmYpKQprOF9jb25mX25vcm0gPC0gc20obm9ybWFsaXplX2V4cHQoazhfY29uZiwgdHJhbnNmb3JtPSJsb2cyIiwgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iKSkKazhfY29uZl9ub3JtX3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazhfY29uZl9ub3JtKSkKazhfY29uZl9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQoazhfY29uZiwgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFKSkKazhfY29uZl9ub3JtYmF0Y2hfcGxvdHMgPC0gc20oZ3JhcGhfbWV0cmljcyhrOF9jb25mX25vcm1iYXRjaCkpCmBgYAoKIyMjIyBMb29rIGF0IHNvbWUgcGxvdHMKCkxldCB1cyBzZWUgaG93IHRoZSBrOCBjb25mIGRhdGEgYXBwZWFycwoKYGBge3Igc2hvd19rOF9jb25mfQprOF9jb25mX3Jhd19wbG90cyRsaWJzaXplCnNtKGs4X2NvbmZfcmF3X3Bsb3RzJGRlbnNpdHkgKyBnZ3Bsb3QyOjpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMSwxMDApKSkKazhfY29uZl9yYXdfcGxvdHMkYm94cGxvdAprOF9jb25mX25vcm1fcGxvdHMkY29yaGVhdAprOF9jb25mX25vcm1fcGxvdHMkc21jCms4X2NvbmZfbm9ybV9wbG90cyRkaXNoZWF0Cms4X2NvbmZfbm9ybV9wbG90cyRzbWQKazhfY29uZl9ub3JtX3Bsb3RzJHBjYXBsb3QKazhfY29uZl9ub3JtX3Bsb3RzJHRzbmVwbG90CiMjIFNlZSBpZiB0aGUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBpbiB0aGUgJ2JhdGNoJyBmYWN0b3IgbWFkZSBhIGRpZmZlcmVuY2UKazhfY29uZl9ub3JtYmF0Y2hfcGxvdHMkcGNhcGxvdAprOF9jb25mX25vcm1iYXRjaF9wbG90cyR0c25lcGxvdApgYGAKCiMjIENvdW50X0NvbmYgZmlsdGVyZWQgZGF0YQoKV2hlbiB3ZSBnZXQgdG8gdGhlIGNvdW50X2NvbmYgZmlsdGVyZWQgZGF0YSwgSSBzdXNwZWN0IHRoaW5ncyB3aWxsIGJlIG1vcmUgaW50ZXJlc3RpbmcuClRoZXJlZm9yZSBsZXQgdXMgbG9vayBhdCB0aGUgZnVsbCBzcGVjdHJ1bSBvZiBwbG90cyBiZWZvcmUvYWZ0ZXIgbm9ybWFsaXphdGlvbi4KCiMjIyBrMTAKCmBgYHtyIGsxMF9jb3VudF9jb25mLCBmaWcuc2hvdz0iaGlkZSJ9CmsxMF9jb25mX2NvdW50X3Jhd19wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGsxMF9jb25mX2NvdW50KSkKazEwX2NvbmZfY291bnRfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChrMTBfY29uZl9jb3VudCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtPSJxdWFudCIsIGNvbnZlcnQ9ImNwbSIpKQprMTBfY29uZl9jb3VudF9ub3JtX3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazEwX2NvbmZfY291bnRfbm9ybSkpCmsxMF9jb25mX2NvdW50X25vcm1iYXRjaCA8LSBzbShub3JtYWxpemVfZXhwdChrMTBfY29uZl9jb3VudCwgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBmaWx0ZXI9VFJVRSkpCmsxMF9jb25mX2NvdW50X25vcm1iYXRjaF9wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGsxMF9jb25mX2NvdW50X25vcm1iYXRjaCkpCmBgYAoKIyMjIyBMb29rIGF0IHNvbWUgcGxvdHMKCkxldCB1cyBzZWUgaG93IHRoZSBrMTAgY291bnRfY29uZiBkYXRhIGFwcGVhcnMKCmBgYHtyIHNob3dfazEwX2NvdW50X2NvbmZ9CmsxMF9jb25mX2NvdW50X3Jhd19wbG90cyRsaWJzaXplCnNtKGsxMF9jb25mX2NvdW50X3Jhd19wbG90cyRkZW5zaXR5ICsgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKDEsMTAwKSkpCmsxMF9jb25mX2NvdW50X3Jhd19wbG90cyRib3hwbG90CmsxMF9jb25mX2NvdW50X25vcm1fcGxvdHMkY29yaGVhdAprMTBfY29uZl9jb3VudF9ub3JtX3Bsb3RzJHNtYwprMTBfY29uZl9jb3VudF9ub3JtX3Bsb3RzJGRpc2hlYXQKazEwX2NvbmZfY291bnRfbm9ybV9wbG90cyRzbWQKazEwX2NvbmZfY291bnRfbm9ybV9wbG90cyRwY2FwbG90CiMjIFNlZSBpZiB0aGUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBpbiB0aGUgJ2JhdGNoJyBmYWN0b3IgbWFkZSBhIGRpZmZlcmVuY2UKazEwX2NvbmZfY291bnRfbm9ybWJhdGNoX3Bsb3RzJHBjYXBsb3QKazEwX2NvbmZfY291bnRfbm9ybWJhdGNoX3Bsb3RzJHRzbmVwbG90CmBgYAoKIyMjIGs4CgpgYGB7ciBrOF9jb3VudF9jb25mLCBmaWcuc2hvdz0iaGlkZSJ9Cms4X2NvbmZfY291bnRfcmF3X3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazhfY29uZl9jb3VudCkpCms4X2NvbmZfY291bnRfbm9ybSA8LSBzbShub3JtYWxpemVfZXhwdChrOF9jb25mX2NvdW50LCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iKSkKazhfY29uZl9jb3VudF9ub3JtX3Bsb3RzIDwtIHNtKGdyYXBoX21ldHJpY3MoazhfY29uZl9jb3VudF9ub3JtKSkKazhfY29uZl9jb3VudF9ub3JtYmF0Y2ggPC0gc20obm9ybWFsaXplX2V4cHQoazhfY29uZl9jb3VudCwgYmF0Y2g9InN2YXNlcSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIpKQprOF9jb25mX2NvdW50X25vcm1iYXRjaF9wbG90cyA8LSBzbShncmFwaF9tZXRyaWNzKGs4X2NvbmZfY291bnRfbm9ybWJhdGNoKSkKYGBgCgojIyMjIExvb2sgYXQgc29tZSBwbG90cwoKTGV0IHVzIHNlZSBob3cgdGhlIGs4IGNvdW50X2NvbmYgZGF0YSBhcHBlYXJzCgpgYGB7ciBzaG93X2s4X2NvdW50X2NvbmZ9Cms4X2NvbmZfY291bnRfcmF3X3Bsb3RzJGxpYnNpemUKc20oazhfY29uZl9jb3VudF9yYXdfcGxvdHMkZGVuc2l0eSArIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxLDEwMCkpKQprOF9jb25mX2NvdW50X3Jhd19wbG90cyRib3hwbG90Cms4X2NvbmZfY291bnRfbm9ybV9wbG90cyRjb3JoZWF0Cms4X2NvbmZfY291bnRfbm9ybV9wbG90cyRzbWMKazhfY29uZl9jb3VudF9ub3JtX3Bsb3RzJGRpc2hlYXQKazhfY29uZl9jb3VudF9ub3JtX3Bsb3RzJHNtZAprOF9jb25mX2NvdW50X25vcm1fcGxvdHMkcGNhcGxvdAojIyBTZWUgaWYgdGhlIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gaW4gdGhlICdiYXRjaCcgZmFjdG9yIG1hZGUgYSBkaWZmZXJlbmNlCms4X2NvbmZfY291bnRfbm9ybWJhdGNoX3Bsb3RzJHBjYXBsb3QKazhfY29uZl9jb3VudF9ub3JtYmF0Y2hfcGxvdHMkdHNuZXBsb3QKYGBgCgojIE1ha2UgYSBuaWNlIHN0YWNrZWQgbGlic2l6ZSBiYXJwbG90CgpgYGB7ciB0ZXN0X2JhcnBsb3R9CmxpYnJhcnkoZ2dwbG90MikKbWF4aW11bSA8LSBwbG90X2xpYnNpemUoazhfcmF3LCB0ZXh0PUZBTFNFKQptYXhpbXVtX2FscGhhIDwtIG1heGltdW0kdGFibGUKbWF4aW11bV9hbHBoYSRhbHBoYSA8LSBhbHBoYShtYXhpbXVtX2FscGhhJGNvbG9ycywgMC40KQpjb25mIDwtIHBsb3RfbGlic2l6ZShrOF9jb25mLCB0ZXh0PUZBTFNFKQpjb25mX2FscGhhIDwtIGNvbmYkdGFibGUKY29uZl9hbHBoYSRhbHBoYSA8LSBhbHBoYShjb25mX2FscGhhJGNvbG9ycywgMC42KQpjb3VudCA8LSBwbG90X2xpYnNpemUoazhfY291bnQsIHRleHQ9RkFMU0UpCmNvdW50X2FscGhhIDwtIGNvdW50JHRhYmxlCmNvdW50X2FscGhhJGFscGhhIDwtIGFscGhhKGNvdW50X2FscGhhJGNvbG9ycywgMC44KQpjb25mX2NvdW50IDwtIHBsb3RfbGlic2l6ZShrOF9jb25mX2NvdW50LCB0ZXh0PUZBTFNFKQpjb25mX2NvdW50X2FscGhhIDwtIGNvbmZfY291bnQkdGFibGUKY29uZl9jb3VudF9hbHBoYSRhbHBoYSA8LSBhbHBoYShjb25mX2NvdW50X2FscGhhJGNvbG9ycywgMS4wKQoKYWxsIDwtIHJiaW5kKG1heGltdW1fYWxwaGEsIGNvbmZfYWxwaGEsCiAgICAgICAgICAgICBjb3VudF9hbHBoYSwgY29uZl9jb3VudF9hbHBoYSkKCiMjIFRoZSBmb2xsb3dpbmcgd2lsbCBzdGFjayB0aGUgbGlicmFyeSBzaXplcyBmcm9tIGVhY2ggc3Vic2V0IG9uZSBvbiB0b3Agb2YgdGhlIG90aGVyLgojIyBUaGlzIGlzIGxpa2VseSBub3QgZGVzaXJlZCwgYnV0IGl0IGRvZXMgcHJvdmlkZSBzdWZmaWNpZW50IHJvb20gdG8gcHJpbnQgdGhlIGxpYnJhcnkKIyMgc2l6ZXMgaWYgb25lIHdpc2hlcy4Kc3RhY2tlZCA8LSBnZ3Bsb3QoYWxsLCBhZXMoeD1pZCkpICsKICBnZW9tX2JhcihhZXMod2VpZ2h0PXN1bSwgYWxwaGE9YWxwaGEsIGZpbGw9Y29sb3JzKSwgY29sb3I9ImJsYWNrIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKGxldmVscyhhcy5mYWN0b3IoYWxsJGNvbG9ycykpKSkgKwogIHRoZW1lKGF4aXMudGV4dD1nZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZT0xMCwgY29sb3VyPSJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC54PWdncGxvdDI6OmVsZW1lbnRfdGV4dChhbmdsZT05MCwgdmp1c3Q9MC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiKQpzdGFja2VkCgojIyBJbiB0aGlzIGluc3RhbmNlLCB0aGV5IGFyZSBzdGFja2VkIG9uIHRvcCBvZiAwLCB3aGljaCBJIHN1c3BlY3QgaXMgdGhlIGdvYWwuCmNvbHVtbnMgPC0gZ2dwbG90KGFsbCwgYWVzKHg9aWQsIHk9c3VtKSkgKwogIGdlb21fY29sKHBvc2l0aW9uPSJpZGVudGl0eSIsIGFlcyhmaWxsPWNvbG9ycywgYWxwaGE9YWxwaGEpLCBjb2xvcj0iYmxhY2siKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMobGV2ZWxzKGFzLmZhY3RvcihhbGwkY29sb3JzKSkpKSArCiAgdGhlbWUoYXhpcy50ZXh0PWdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplPTEwLCBjb2xvdXI9ImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0Lng9Z2dwbG90Mjo6ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCB2anVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmNvbHVtbnMKYGBgCgojIFdyaXRlIHVwIHRoZSBmYXZvcml0ZXMKCkxldCB1cyBhc3N1bWUgZm9yIGEgbW9tZW50IHRoYXQgd2Ugd2lsbCBjaG9vc2UgYSBjb3VwbGUgb2YgdGhlIGFib3ZlIGZvciBsb29raW5nIGF0IG1vcmUKY2xvc2VseS4gIEkgc3VzcGVjdCBrOF9jb3VudF9jb25mLCBrMTBfY291bnRfY29uZiwgYW5kIGs4X2NvdW50IGFuZCBrOF9jb25mIGFyZSBnb29kIGNhbmRpZGF0ZXMuCgpgYGB7ciB3cml0ZV9zb21lfQpvdXRwdXQgPC0gcGFzdGUwKCJleGNlbC9rOF9jb25mX2NvdW50X2J5X3R4LXYiLCB2ZXIsICIueGxzeCIpCmlmICghZmlsZS5leGlzdHMob3V0cHV0KSkgewogIGs4X2NvbmZfY291bnRfd3JpdHRlbiA8LSBzbSh3cml0ZV9leHB0KGs4X2NvbmZfY291bnQsIGV4Y2VsPW91dHB1dCkpCn0Kb3V0cHV0IDwtIHBhc3RlMCgiZXhjZWwvazEwX2NvbmZfY291bnRfYnlfdHgtdiIsIHZlciwgIi54bHN4IikKaWYgKCFmaWxlLmV4aXN0cyhvdXRwdXQpKSB7CiAgazEwX2NvbmZfY291bnRfd3JpdHRlbiA8LSBzbSh3cml0ZV9leHB0KGsxMF9jb25mX2NvdW50LCBleGNlbD1vdXRwdXQpKQp9Cm91dHB1dCA8LSBwYXN0ZTAoImV4Y2VsL2s4X2NvdW50X2J5X3R4LXYiLCB2ZXIsICIueGxzeCIpCmlmICghZmlsZS5leGlzdHMob3V0cHV0KSkgewogIGs4X2NvdW50X3dyaXR0ZW4gPC0gc20od3JpdGVfZXhwdChrOF9jb3VudCwgZXhjZWw9b3V0cHV0KSkKfQpvdXRwdXQgPC0gcGFzdGUwKCJleGNlbC9rOF9jb25mX2J5X3R4LXYiLCB2ZXIsICIueGxzeCIpCmlmICghZmlsZS5leGlzdHMob3V0cHV0KSkgewogIGs4X2NvbmZfd3JpdHRlbiA8LSBzbSh3cml0ZV9leHB0KGs4X2NvbmYsIGV4Y2VsPW91dHB1dCkpCn0KYGBgCgojIFF1YW50aWZ5IHR4L2dlbmUKCkkgd2FudCB0byBzZWUgaWYgdGhlcmUgYXJlIHNvbWUgY2hhbmdlcyBpbiB0aGUgbnVtYmVyIG9mIHJlYWRzL3R4IGJldHdlZW4gdGhlCmVtYnJ5b2dlbmljL25vbmVtYnJ5b2dlbmljLiAgSSBhbSBub3QgZW50aXJlbHkgY2VydGFpbiBob3cgdG8gZG8gdGhpcywgc28gSSB3aWxsCnBva2UgYWJvdXQgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCgpJIGRvIGhhdmUgYSBkYXRhIHN0cnVjdHVyZSB0ZWxsaW5nIG1lIHRoZSBtYXBwaW5nIG9mIHR4LT5nZW5lLgoKYGBge3IgdHhfcGVyX2dlbmVfZGlzdHJpYnV0aW9ufQp0cmFuc2NyaXB0X2dlbmVfbWFwIDwtIHB1dGF0aXZlX2Fubm90YXRpb25zWywgYygidHJhbnNjcmlwdF9pZCIsICJnZW5lX2lkIildCm1hcHBpbmdzIDwtIGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUodHJhbnNjcmlwdF9nZW5lX21hcCkKbWFwcGluZ3NbWyJudW0iXV0gPC0gMQpudW1fdHggPC0gbWFwcGluZ3NbLCBsaXN0KG51bV90eD1zdW0obnVtKSksIGJ5PSJnZW5lX2lkIl0KCnR4X2hpc3QgPC0gcGxvdF9oaXN0b2dyYW0obnVtX3R4JG51bV90eCkKdHhfaGlzdAoKc3RhcnQgPC0gbm9ybWFsaXplX2V4cHQoazhfcmF3LCBjb252ZXJ0PSJjcG0iKQplbWJyeW8gPC0gc3Vic2V0X2V4cHQoc3RhcnQsIHN1YnNldD0iY29uZGl0aW9uPT0nZW1icnlvZ2VuaWMnIikKbm9uZW1icnlvIDwtIHN1YnNldF9leHB0KHN0YXJ0LCBzdWJzZXQ9ImNvbmRpdGlvbj09J25vbmVtYnJ5b2dlbmljJyIpCmVtYnJ5b19kZiA8LSBhcy5kYXRhLmZyYW1lKGV4cHJzKGVtYnJ5bykpCmVtYnJ5b19kZiRlbV9tZWFuIDwtIHJvd01lYW5zKGVtYnJ5b19kZikKbm9uX2RmIDwtIGFzLmRhdGEuZnJhbWUoZXhwcnMobm9uZW1icnlvKSkKbm9uX2RmJG5vbl9tZWFuIDwtIHJvd01lYW5zKG5vbl9kZikKZSA8LSBhcy5kYXRhLmZyYW1lKGVtYnJ5b19kZltbImVtX21lYW4iXV0pCnJvd25hbWVzKGUpIDwtIHJvd25hbWVzKGVtYnJ5b19kZikKY29sbmFtZXMoZSkgPC0gImVtX21lYW4iCm4gPC0gYXMuZGF0YS5mcmFtZShub25fZGZbWyJub25fbWVhbiJdXSkKcm93bmFtZXMobikgPC0gcm93bmFtZXMobm9uX2RmKQpjb2xuYW1lcyhuKSA8LSAibm9uX21lYW4iCm1lYW5zIDwtIG1lcmdlKHg9ZSwgeT1uLCBieT0icm93Lm5hbWVzIikKcm93bmFtZXMobWVhbnMpIDwtIG1lYW5zW1siUm93Lm5hbWVzIl1dCm1lYW5zIDwtIG1lYW5zWywgLTFdCm5lYXJfemVybyA8LSBtZWFucyA8PSAwLjAwMQplbWJyeW9fbmVhcl96ZXJvIDwtIHN1bShuZWFyX3plcm9bLCAiZW1fbWVhbiJdKQplbWJyeW9fbmVhcl96ZXJvCm5vbl9uZWFyX3plcm8gPC0gc3VtKG5lYXJfemVyb1ssICJub25fbWVhbiJdKQpub25fbmVhcl96ZXJvCgpwbG90X2JveHBsb3QoZW1icnlvKQpwbG90X2JveHBsb3Qobm9uZW1icnlvKQpgYGAKCgojIE5vdGUgdG8gc2VsZgoKSSBkZWNpZGVkIHRvIG5vdCBzYXZlIHRoZSBzdGF0ZSBvZiB0aGlzIGZpbGUsIGJlY2F1c2UgaXQgaXMgaHVnZS4KVGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2VzIGRvIG5vdCBuZWVkIHRoaXMsIGJ1dCBuZWVkIG9ubHkgdGhlIHJlc3VsdCBvZiB0aGUKYW5ub3RhdGlvbiB3b3Jrc2hlZXQuCgpgYGB7ciBzYXZlbWV9CnBhbmRlcjo6cGFuZGVyKHNlc3Npb25JbmZvKCkpCm1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQptZXNzYWdlKHBhc3RlMCgiU2F2aW5nIHRvICIsIHRoaXNfc2F2ZSkpCiMjIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCg==