index.html annotation.html

This document is intended to provide an opportunity to compare the samples and ensure that they are all of sufficient quality to be included in the final differential expression analyses. In addition, this should provide an opportunity to compare the results from the alignments to the esmeraldo, nonesmeraldo, and combined haplotypes. In addition, with the recent inclusion of all the human alignments, it may be used to quantify them as well.

1 Create testing subsets

For some analyses, we might want to consider only the samples of types CL14 or CLBrener.

I am going to use the following convention when working with the various subsets:

  1. Names of data sets begin with the data included:
  1. cl_ means include all samples.
  2. clbr_ means the clbrener samples.
  3. cl14_ means the cl14 samples.
  4. kcl_,kclbr_,kcl14_ means the ‘kept’ samples respectively after excluding outliers.
  1. The following portion refers to the haplotype used for mapping the reads.
  1. esmer_ means the alignments mapped against the Esmeraldo haplotype.
  2. nonesmer_ means those against NonEsmeraldo.
  3. all_ means the combined haplotypes including Esmeraldo+NonEsmeraldo+Unassigned.
  1. The final portion refers to the data type created.
  1. expt means the expt object which contains the annotation data, sample data, read counts.
  2. metrics means the set of plots describing the data.
  3. xxxnorm means normalized data using xxx where xxx is defined by an abbreviation of the normalization used
    1. lqcf: log2(quantile(cpm(filtered(data))))
    2. clqcf: combat(log2(quantile(cpm(filtered(data)))))
    3. slqcf: sva(log2(quantile(cpm(filtered(data)))))
    4. Other letters may be added as needed in each slot.
## I am going to copy the original expts to names which follow the conventions below
cl_esmer_expt <- esmer_expt
cl_nonesmer_expt <- nonesmer_expt
cl_all_expt <- all_expt
## Split the esmer data into CLBR/CL14
clbr_esmer_expt <- expt_subset(esmer_expt, "type=='CLBr'")
cl14_esmer_expt <- expt_subset(esmer_expt, "type=='CL14'")
## Split the nonesmer data into CLBR/CL14
clbr_nonesmer_expt <- expt_subset(nonesmer_expt, "type=='CLBr'")
cl14_nonesmer_expt <- expt_subset(nonesmer_expt, "type=='CL14'")
## And the combined data
clbr_all_expt <- expt_subset(all_expt, "type=='CLBr'")
cl14_all_expt <- expt_subset(all_expt, "type=='CL14'")

Now we have 9 expt objects, one for each haplotype (esmer, nonesmer, combined(all)) for each subset (all data, cl14 data, and clbr data)

cl_esmer_metrics <- sm(graph_metrics(esmer_expt))
cl_nonesmer_metrics <- sm(graph_metrics(nonesmer_expt))
cl_all_metrics <- sm(graph_metrics(all_expt))
clbr_esmer_metrics <- sm(graph_metrics(clbr_esmer_expt))
clbr_nonesmer_metrics <- sm(graph_metrics(clbr_nonesmer_expt))
clbr_all_metrics <- sm(graph_metrics(clbr_all_expt))
cl14_esmer_metrics <- sm(graph_metrics(cl14_esmer_expt))
cl14_nonesmer_metrics <- sm(graph_metrics(cl14_nonesmer_expt))
cl14_all_metrics <- sm(graph_metrics(cl14_all_expt))

1.1 Quick check the library sizes

I find myself thinking I should plot these together in a single plot somehow. They are kind of fascinating, as there are more reads on the nonesmer mappings than esmer for all samples. Why is this?

cl_esmer_metrics$libsize

cl_nonesmer_metrics$libsize

## NonEsmeraldo often gets >= 10% more reads.
cl_all_metrics$libsize

1.2 Check global data distributions across subsets

As a starting point, let us see how similar the data distributions are across subsets/haplotypes.

This will be printed in order: esmer mapping:, all-data, clbr-data, cl14-data nonesmer mappings, all-data, clbr-data, cl14-data all mappings: all-data, clbr-data, cl14-data human-data: all

library(directlabels)
library(ggplot2)
directlabels::direct.label(cl_esmer_metrics$density)

## The distribusions mostly look good but hpgl0125 and hpgl 476/475/482 are a
## little off as I think we will see more clearly in the smaller dataset plots
directlabels::direct.label(clbr_esmer_metrics$density)

## Ahh the lower density samples are the amastigote 60 hours, that makes sense:
## 476,482,475 are all A60.
directlabels::direct.label(cl14_esmer_metrics$density)

## This is similarly true for the cl14 samples, but at both time points, 60 and
## 96 hours.

directlabels::direct.label(cl_nonesmer_metrics$density)

directlabels::direct.label(clbr_nonesmer_metrics$density)

directlabels::direct.label(cl14_nonesmer_metrics$density)

## Surprisingly to me, the nonesmer and esmer density plots are different for
## some samples.

directlabels::direct.label(cl_all_metrics$density)

directlabels::direct.label(clbr_all_metrics$density)

## Ahh the lower density samples are the amastigote 60 hours, that makes sense:
## 476,482,475 are all A60.
directlabels::direct.label(cl14_nonesmer_metrics$density)

## Surprisingly to me, the nonesmer and esmer density plots are different for
## some samples.

cl_esmer_metrics$boxplot

cl_nonesmer_metrics$boxplot

cl_all_metrics$boxplot

We could in theory print out the pca, heatmaps etc now, but I think I want first to perform a default normalization of the data and see the trends in the data a bit more clearly.

cl_esmer_lqcf <- default_norm(cl_esmer_expt, transform="log2")
cl_nonesmer_lqcf <- default_norm(cl_nonesmer_expt, transform="log2")
cl_all_lqcf <- default_norm(cl_all_expt, transform="log2")
clbr_esmer_lqcf <- default_norm(clbr_esmer_expt, transform="log2")
clbr_nonesmer_lqcf <- default_norm(clbr_nonesmer_expt, transform="log2")
clbr_all_lqcf <- default_norm(clbr_all_expt, transform="log2")
cl14_esmer_lqcf <- default_norm(cl14_esmer_expt, transform="log2")
cl14_nonesmer_lqcf <- default_norm(cl14_nonesmer_expt, transform="log2")
cl14_all_lqcf <- default_norm(cl14_all_expt, transform="log2")

2 Redo metric plotting on normalized data

cl_esmer_lqcf_metrics <- sm(graph_metrics(cl_esmer_lqcf))
cl_nonesmer_lqcf_metrics <- sm(graph_metrics(cl_nonesmer_lqcf))
cl_all_lqcf_metrics <- sm(graph_metrics(cl_all_lqcf))
clbr_esmer_lqcf_metrics <- sm(graph_metrics(clbr_esmer_lqcf))
clbr_nonesmer_lqcf_metrics <- sm(graph_metrics(clbr_nonesmer_lqcf))
clbr_all_lqcf_metrics <- sm(graph_metrics(clbr_all_lqcf))
cl14_esmer_lqcf_metrics <- sm(graph_metrics(cl14_esmer_lqcf))
cl14_nonesmer_lqcf_metrics <- sm(graph_metrics(cl14_nonesmer_lqcf))
cl14_all_lqcf_metrics <- sm(graph_metrics(cl14_all_lqcf))

For the following plots, I think I will focus on the combined data unless there is something which is unclear unless it is separated.

2.1 Correlation heatmaps

The correlations in these plots are exceedingly high, 0.7<x<1.0.

cl_esmer_lqcf_metrics$corheat

cl_nonesmer_lqcf_metrics$corheat

## Once again the differences between esmer and nonesmer are striking
cl_all_lqcf_metrics$corheat

## HPGL0485 (cl14 epimastigote) is clearly the strangest sample of all.
## Its cohorts, HPGL0128 looks most like a CL14 60 hour sample; while HPGL0129
## looks like a CLBr epimastigote.
## HPGL0490 is also problematic, as it looks very similar to the CLBr 96 hour samples.

cl_esmer_lqcf_metrics$disheat

cl_nonesmer_lqcf_metrics$disheat

cl_all_lqcf_metrics$disheat

## Same story as above I think, but the problematic samples HPGL0485 is even
## starker to my eyes.

cl_all_lqcf_metrics$smc

Once again, I see that the nonesmer mappings are surprisingly (to me) different than the esmer. So much so that in the most pathologically difficult samples, we get pretty big shifts in clustering for the epimastigote and trypomastigote samples. This is starting to make me think that a large number of the genes attributed to the ‘Unassigned’ haplotype are actually Esmeraldo.

2.2 PCA

For the PCA plots, I think it might prove useful to look at the CLBr and CL14 samples separately. However I will start out with the entire set like the heatmaps.

cl_esmer_lqcf_metrics$pcaplot

cl_nonesmer_lqcf_metrics$pcaplot

cl_all_lqcf_metrics$pcaplot

cl14_esmer_lqcf_metrics$pcaplot

cl14_nonesmer_lqcf_metrics$pcaplot

cl14_all_lqcf_metrics$pcaplot

clbr_esmer_lqcf_metrics$pcaplot

clbr_nonesmer_lqcf_metrics$pcaplot

clbr_all_lqcf_metrics$pcaplot

2.3 A separate, simpler Figure S02A:

Note that this figure must be generated before removing troubling samples because I reused the names of some of the expressionsets.

## 20170214 This is causing a segmentation fault. hmm it seems fixed now...
## All I did was restart the computer, R worries my sometimes.
cl_all_written <- write_expt(cl_all_expt,
                             excel=paste0("excel/testing-v", ver, ".xlsx"))
svg(file="images/figS02a_atb_v2.3.svg")
cl_all_lqcf_metrics$corheat
dev.off()
testing <- normalize_expt(cl_all_expt, filter=FALSE, convert="cpm",
                          norm="quant", transform="log2")
testing_disheat <- plot_disheat(testing)
testing_pca <- plot_pca(testing, plot_labels=FALSE)
pdf(file="images/figS02a_atb_v2.2_all_samples.pdf")
testing_disheat$plot
dev.off()
svg(file="images/figS02b_atb_v2.2_all_samples.svg")
testing_pca$plot
dev.off()

## I think therefore we want:
## 1.  A PCA of all samples log2(cpm(quant(filt(sva())))) (not in that order)
## 2.  Corresponding correlation heatmap, distance, and smc.
test_data <- normalize_expt(cl_all_expt, transform="log2", norm="quant",
                            convert="cpm", filter=TRUE)
##test_write <- write_expt(cl_all_expt, transform="log2", norm="quant",
##                         convert="cpm", filter=TRUE,
##                         excel=paste0("excel/cl_all_expt-v", ver, ".xlsx"))
fig_pca <- plot_pca(test_data)
fig_cd <- plot_corheat(test_data)
fig_dd <- plot_disheat(test_data)
fig_smc <- plot_sm(test_data)
svg(file="images/figS02v2a_atb_v2.0.svg")
fig_pca$plot
dev.off()
pdf(file="images/figS02v2b_atb_v2.0.pdf")
fig_cd$plot
dev.off()
pdf(file="images/figS02v2c_atb_v2.0.pdf")
fig_dd$plot
dev.off()
svg(file="images/figS02v2d_atb_v2.0.svg")
fig_smc
dev.off()

2.4 A couple of possible implementations of Figure 2

The text introducing Figure 2 is as follows:

“Mapped sequencing data derived from all libraries were analyzed using two methods to inspect the relationships between samples and to identify outliers. Samples were subjected to principal component analysis (PCA) as well as hierarchical clustering. The resulting heat map and PCA plot (Figure 2) showed a clear separation between samples as well as the expected clustering between biological triplicates, except for one library generated from RNA isolated from CL Brener trypomastigotes, which was identified as an outlier and was excluded from further analyses (Figure 2C). Of the 24887 genes analyzed, 23191 were expressed at a level of at least 1 count per million in at least 2 samples.”

I take this to mean that we are performing a heatmap and PCA of all samples.

The heat map provided in the powerpoint, appears to me to not have all samples, but is instead missing the CL14 epimastigotes. While it is true we remove them, this piece of text does say we are looking at all samples – which is it?

library(Biobase)
## Loading required package: BiocGenerics
## Loading required package: parallel
##
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:parallel':
##
##     clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport,
##     clusterMap, parApply, parCapply, parLapply, parLapplyLB, parRapply,
##     parSapply, parSapplyLB
## The following objects are masked from 'package:stats':
##
##     IQR, mad, xtabs
## The following objects are masked from 'package:base':
##
##     anyDuplicated, append, as.data.frame, cbind, colnames, do.call, duplicated,
##     eval, evalq, Filter, Find, get, grep, grepl, intersect, is.unsorted, lapply,
##     lengths, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin,
##     pmin.int, Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
##     table, tapply, union, unique, unsplit, which, which.max, which.min
## Welcome to Bioconductor
##
##     Vignettes contain introductory material; view with 'browseVignettes()'. To
##     cite Bioconductor, see 'citation("Biobase")', and for packages
##     'citation("pkgname")'.
new_names <- paste0(rownames(pData(cl_all_lqcf$expressionset)), "_",
                    pData(cl_all_lqcf$expressionset)$originalcond, "_",
                    pData(cl_all_lqcf$expressionset)$batch)
distance_plot <- plot_disheat(cl_all_lqcf, expt_names=new_names)

correlation_plot <- plot_corheat(cl_all_lqcf, expt_names=new_names)

library(Heatplus)
row_correlations <- hpgl_cor(exprs(cl_all_lqcf$expressionset))
row_design <- as.data.frame(pData(cl_all_lqcf$expressionset))
## Reorder the design to match the correlation clustering order
row_design <- row_design[rownames(row_correlations), ]

column_distances <- as.matrix(dist(t(exprs(cl_all_lqcf$expressionset))))
column_design <- as.data.frame(pData(cl_all_lqcf$expressionset))
## Reorder these according to the distance clustering
column_design <- column_design[rownames(column_distances), ]

## Now choose the columns of the design to add as annotations
row_design <- row_design[, c("batch","replicate")]
row_design$replicate <- as.factor(row_design$replicate)
column_design <- column_design[, c("type","stage")]

my_annotations <- list(Row=list(data=row_design),
                       Col=list(data=column_design))
my_labels <- list(Row=list(nrow=5),
                  Col=list(nrow=5))
my_cluster_distances <- list(Row=list(cuth=2),
                             Col=list(cuth=100))
cordist <- column_distances
for (r in 1:nrow(row_correlations)) {
    for (c in 1:ncol(row_correlations)) {
        if (c > r) {
            cordist[r,c] <- row_correlations[r,c]
        } else if (r == c) {
            cordist[r,c] <- 0
        }
    }
}
## ok, so now we go from -1 (highest correlation) to 0 (lowest correlation),
## then up to high numbers (distance)
map1 <- annHeatmap2(cordist, scale="none",
                    cluster=my_cluster_distances,
                    ann=my_annotations,
                    labels=my_labels)
## heatmap.2 heatmaps have: $breaks (color breaks), $col (colors by breaks),
## and $colorTable (low,high,color assignments)
## annHeatmap2 has $breaks and $col -- perhaps I can use that.
map2 <- map1
cor_breaks <- rev(correlation_plot[["map"]][["breaks"]])
dist_breaks <- distance_plot[["map"]][["breaks"]]
dist_breaks <- dist_breaks[2:length(dist_breaks)]
total_breaks <- append(cor_breaks, dist_breaks)
map2[["data"]][["col"]] <- append(correlation_plot[["map"]][["col"]], distance_plot[["map"]][["col"]])
map2[["data"]][["breaks"]] <- total_breaks
##map2$data$x2 <- map2$data$x
plot(map2)
## Warning in image.default(1:nc, 1:nr, t(x2), axes = FALSE, xlim = c(0.5, : unsorted
## 'breaks' will be sorted before use

3 Remove troubled samples

My previous notes, and the plots above suggest strongly that the samples HPGL0485, HPGL0490, and HPGL0163 are problematic. I have already excluded HPGL0163, so now I just want to drop the other two.

I am going to therefore create new base kexpt objects and overwrite the normalized data with the new normalized data.

old_subset <- "sampleid!='HPGL0485'&sampleid!='HPGL0490'&sampleid!='HPGL0129'&sampleid!='HPGL0128'"
##new_subset <- "sampleid!='HPGL0128'&sampleid!='HPGL0129'&sampleid!='HPGL0483'&sampleid!='HPGL0485'&sampleid!='HPGL0486'&sampleid!='HPGL0487'&sampleid!='HPGL0490'"
##new_subset <- "stage!='Epi'&sampleid!='HPGL0490'"
outlier_subset <- "sampleid!='HPGL0490'"
noepi_subset <- "stage!='Epi'"
cl_all_kexptv1 <- expt_subset(cl_all_expt, subset=outlier_subset)
cl_all_kexpt <- expt_subset(cl_all_kexptv1, subset=noepi_subset)
expt_filename <- paste0("excel/cl_all_kexptv1-", ver, ".xlsx")
printed_expt <- write_expt(cl_all_kexptv1, violin=FALSE,
                           excel=expt_filename,
                           filter=TRUE, transform="log2", norm="quant",
                           convert="raw", batch="sva")
## Writing the legend.
## The sheet: legend is in legend.
## Writing the raw reads.
## Graphing the raw reads.
## There is just one batch in this data.
## The sheet: raw_graphs is in legend, raw_reads, raw_graphs.
## The sheet: raw_graphs is in legend, raw_reads, raw_graphs.
## Writing the normalized reads.
## Graphing the normalized reads.
## The sheet: norm_graphs is in legend, raw_reads, raw_graphs, norm_data, norm_graphs.
## The sheet: norm_graphs is in legend, raw_reads, raw_graphs, norm_data, norm_graphs.
## Writing the median reads by factor.
## The factor CL14.A60 has 3 rows.
## The factor CL14.A96 has 3 rows.
## The factor CL14.Tryp has 3 rows.
## The factor CLBr.A60 has 3 rows.
## The factor CLBr.A96 has 3 rows.
## The factor CLBr.Tryp has 2 rows.
cl_esmer_kexpt <- expt_subset(cl_esmer_expt, subset=outlier_subset)
cl_nonesmer_kexpt <- expt_subset(cl_nonesmer_expt, subset=outlier_subset)
cl_all_kexpt <- expt_subset(cl_all_expt, subset=outlier_subset)
clbr_esmer_kexpt <- expt_subset(clbr_esmer_expt, subset=outlier_subset)
clbr_nonesmer_kexpt <- expt_subset(clbr_nonesmer_expt, subset=outlier_subset)
clbr_all_kexpt <- expt_subset(clbr_all_expt, subset=outlier_subset)
cl14_esmer_kexpt <- expt_subset(cl14_esmer_expt, subset=outlier_subset)
cl14_nonesmer_kexpt <- expt_subset(cl14_nonesmer_expt, subset=outlier_subset)
cl14_all_kexpt <- expt_subset(cl14_all_expt, subset=outlier_subset)
cl_esmer_lqcf <- default_norm(cl_esmer_kexpt, transform="log2")
cl_nonesmer_lqcf <- default_norm(cl_nonesmer_kexpt, transform="log2")
cl_all_lqcf <- default_norm(cl_all_kexpt, transform="log2")
clbr_esmer_lqcf <- default_norm(clbr_esmer_kexpt, transform="log2")
clbr_nonesmer_lqcf <- default_norm(clbr_nonesmer_kexpt, transform="log2")
clbr_all_lqcf <- default_norm(clbr_all_kexpt, transform="log2")
cl14_esmer_lqcf <- default_norm(cl14_esmer_kexpt, transform="log2")
cl14_nonesmer_lqcf <- default_norm(cl14_nonesmer_kexpt, transform="log2")
cl14_all_lqcf <- default_norm(cl14_all_kexpt, transform="log2")

cl_esmer_lqcf_metrics <- sm(graph_metrics(cl_esmer_lqcf))
cl_nonesmer_lqcf_metrics <- sm(graph_metrics(cl_nonesmer_lqcf))
cl_all_lqcf_metrics <- sm(graph_metrics(cl_all_lqcf))
clbr_esmer_lqcf_metrics <- sm(graph_metrics(clbr_esmer_lqcf))
clbr_nonesmer_lqcf_metrics <- sm(graph_metrics(clbr_nonesmer_lqcf))
clbr_all_lqcf_metrics <- sm(graph_metrics(clbr_all_lqcf))
cl14_esmer_lqcf_metrics <- sm(graph_metrics(cl14_esmer_lqcf))
cl14_nonesmer_lqcf_metrics <- sm(graph_metrics(cl14_nonesmer_lqcf))
cl14_all_lqcf_metrics <- sm(graph_metrics(cl14_all_lqcf))

3.1 A separate, simpler Figure 02A:

distance_plot <- plot_disheat(cl_all_lqcf)

testing_data <- normalize_expt(cl_all_kexpt, transform="log2", convert="cpm",
                               filter=TRUE, batch="ssva")
## This function will replace the expt$expressionset slot with:
## log2(ssva(cpm(cbcb(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
## Leaving the data unnormalized.  This is necessary for DESeq, but
##  EdgeR/limma might benefit from normalization.  Good choices include quantile,
##  size-factor, tmm, etc.
## Step 1: performing count filter with option: cbcb
## Removing 1049 low-count genes (22256 remaining).
## Step 2: not normalizing the data.
## Step 3: converting the data with cpm.
## Step 4: transforming the data with log2.
## transform_counts: Found 2268 values equal to 0, adding 1 to the matrix.
## Step 5: doing batch correction with ssva.
## Note to self:  If you get an error like 'x contains missing values'; I think this
##  means that the data has too many 0's and needs to have a better low-count filter applied.
## batch_counts: Before batch correction, 9511 entries 0<x<1.
## batch_counts: Before batch correction, 2268 entries are >= 0.
## Passing the batch method to get_model_adjust().
## It understands a few additional batch methods.
## Not able to discern the state of the data.
## Going to use a simplistic metric to guess if it is log scale.
## The be method chose 4 surrogate variable(s).
## Did not understand ssva, assuming supervised sva.
## sva warning: controls provided so supervised sva is being performed.
## Number of significant surrogate variables is:  4
## The number of elements which are < 0 after batch correction is: 8165
## The variable low_to_zero sets whether to change <0 values to 0 and is: FALSE
correlation_plot <- plot_corheat(testing_data, keysize=1.5)

pdf(file="images/fig02a_atb_v2.3.pdf")
correlation_plot$plot
dev.off()
## png
##   2
pca_plot <- plot_pca(testing_data, plot_labels=FALSE)
## There is just one batch in this data.
## Not putting labels on the plot.
svg(file="images/fig02b_atb_v2.3.svg")
pca_plot$plot
dev.off()
## png
##   2

4 Re-visualize chosen normalized metrics

Now the visualizations should be maximally pretty.

cl_nonesmer_lqcf_metrics$corheat

clbr_nonesmer_lqcf_metrics$corheat

cl14_nonesmer_lqcf_metrics$corheat

cl_nonesmer_lqcf_metrics$pcaplot

clbr_nonesmer_lqcf_metrics$pcaplot

cl14_nonesmer_lqcf_metrics$pcaplot

5 Violins!

Lets see if my new violin function works.

clbr_filt <- normalize_expt(clbr_all_kexpt, filter="cbcb")
varpart_b <- varpart(clbr_filt, predictor=NULL, factors=c("actualbatch"))
varpart_b$partition_plot
varpart_c <- varpart(clbr_filt, predictor=NULL, factors=c("condition"))
varpart_c$partition_plot
varpart_cb <- varpart(clbr_filt, predictor=NULL,
                      factors=c("condition","actualbatch"))
varpart_cb$partition_plot
tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiUk5Bc2VxIG9mIFQuY3J1emkgQ0wxNC9DTEJyOiBTYW1wbGUgRXN0aW1hdGlvbiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICA8IS0tIERvY3VtZW50IHByZWx1ZGUgcmV2aXNpb24gMjAxNi0xMCAtLT4KYm9keSAubWFpbi1jb250YWluZXIgewptYXgtd2lkdGg6IDE2MDBweDsKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KIyMgVGhlc2UgYXJlIHRoZSBvcHRpb25zIEkgdGVuZCB0byBmYXZvcgpsaWJyYXJ5KCJocGdsdG9vbHMiKQp0dCA8LSBzbShkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHByb2dyZXNzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgd2lkdGg9OTAsCiAgICAgICAgICAgICAgICAgICAgIGVjaG89VFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogICAgZmlnLndpZHRoPTgsCiAgICBmaWcuaGVpZ2h0PTgsCiAgICBkcGk9OTYpCm9sZF9vcHRpb25zIDwtIG9wdGlvbnMoCiAgICBlcnJvciA9IE5VTEwsCiAgICBkaWdpdHMgPSA0LAogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAga25pdHIuZHVwbGljYXRlLmxhYmVsID0gImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnNldC5zZWVkKDEpCnByZXZpb3VzX2ZpbGUgPC0gImFubm90YXRpb24uUm1kIgpybWRfZmlsZSA8LSAic2FtcGxlX2VzdGltYXRpb24uUm1kIgp2ZXIgPC0gIjIwMTcwMzAxIgpwcmV2aW91c19zYXZlIDwtIHBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9Ii5yZGEueHoiLCB4PXByZXZpb3VzX2ZpbGUpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iLnJkYS54eiIsIHg9cm1kX2ZpbGUpKQpgYGAKCltpbmRleC5odG1sXShpbmRleC5odG1sKSBbYW5ub3RhdGlvbi5odG1sXShhbm5vdGF0aW9uLmh0bWwpCgpgYGB7ciByZW5kZXJpbmcsIGluY2x1ZGU9RkFMU0UsIGV2YWw9RkFMU0V9CiMjIFRoaXMgYmxvY2sgaXMgdXNlZCB0byByZW5kZXIgYSBkb2N1bWVudCBmcm9tIHdpdGhpbiBpdC4Kcm1hcmtkb3duOjpyZW5kZXIocm1kX2ZpbGUpCgojIyBBbiBleHRyYSByZW5kZXJlciBmb3IgcGRmIG91dHB1dApybWFya2Rvd246OnJlbmRlcihybWRfZmlsZSwgb3V0cHV0X2Zvcm1hdD0icGRmX2RvY3VtZW50Iiwgb3V0cHV0X29wdGlvbnM9Yygic2tpcF9odG1sIikpCiMjIE9yIHRvIHNhdmUvbG9hZCBsYXJnZSBSZGF0YSBmaWxlcy4KaHBnbHRvb2xzOjo6c2F2ZW1lKCkKaHBnbHRvb2xzOjo6bG9hZG1lKCkKcm0obGlzdD1scygpKQpgYGAKCmBgYHtyIGxvYWRtZSwgaW5jbHVkZT1GQUxTRX0KdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wcmV2aW91c19zYXZlKSkKYGBgCgpUaGlzIGRvY3VtZW50IGlzIGludGVuZGVkIHRvIHByb3ZpZGUgYW4gb3Bwb3J0dW5pdHkgdG8gY29tcGFyZSB0aGUgc2FtcGxlcyBhbmQgZW5zdXJlIHRoYXQgdGhleSBhcmUKYWxsIG9mIHN1ZmZpY2llbnQgcXVhbGl0eSB0byBiZSBpbmNsdWRlZCBpbiB0aGUgZmluYWwgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzZXMuICBJbgphZGRpdGlvbiwgdGhpcyBzaG91bGQgcHJvdmlkZSBhbiBvcHBvcnR1bml0eSB0byBjb21wYXJlIHRoZSByZXN1bHRzIGZyb20gdGhlIGFsaWdubWVudHMgdG8gdGhlCmVzbWVyYWxkbywgbm9uZXNtZXJhbGRvLCBhbmQgY29tYmluZWQgaGFwbG90eXBlcy4gIEluIGFkZGl0aW9uLCB3aXRoIHRoZSByZWNlbnQgaW5jbHVzaW9uIG9mIGFsbCB0aGUKaHVtYW4gYWxpZ25tZW50cywgaXQgbWF5IGJlIHVzZWQgdG8gcXVhbnRpZnkgdGhlbSBhcyB3ZWxsLgoKIyBDcmVhdGUgdGVzdGluZyBzdWJzZXRzCgpGb3Igc29tZSBhbmFseXNlcywgd2UgbWlnaHQgd2FudCB0byBjb25zaWRlciBvbmx5IHRoZSBzYW1wbGVzIG9mIHR5cGVzIENMMTQgb3IgQ0xCcmVuZXIuCgpJIGFtIGdvaW5nIHRvIHVzZSB0aGUgZm9sbG93aW5nIGNvbnZlbnRpb24gd2hlbiB3b3JraW5nIHdpdGggdGhlIHZhcmlvdXMgc3Vic2V0czoKCjEuICBOYW1lcyBvZiBkYXRhIHNldHMgYmVnaW4gd2l0aCB0aGUgZGF0YSBpbmNsdWRlZDoKICBhLiBjbF8gbWVhbnMgaW5jbHVkZSBhbGwgc2FtcGxlcy4KICBiLiBjbGJyXyBtZWFucyB0aGUgY2xicmVuZXIgc2FtcGxlcy4KICBjLiBjbDE0XyBtZWFucyB0aGUgY2wxNCBzYW1wbGVzLgogIGQuIGtjbF8sa2NsYnJfLGtjbDE0XyBtZWFucyB0aGUgJ2tlcHQnIHNhbXBsZXMgcmVzcGVjdGl2ZWx5IGFmdGVyIGV4Y2x1ZGluZyBvdXRsaWVycy4KMi4gIFRoZSBmb2xsb3dpbmcgcG9ydGlvbiByZWZlcnMgdG8gdGhlIGhhcGxvdHlwZSB1c2VkIGZvciBtYXBwaW5nIHRoZSByZWFkcy4KICBhLiBlc21lcl8gbWVhbnMgdGhlIGFsaWdubWVudHMgbWFwcGVkIGFnYWluc3QgdGhlIEVzbWVyYWxkbyBoYXBsb3R5cGUuCiAgYi4gbm9uZXNtZXJfIG1lYW5zIHRob3NlIGFnYWluc3QgTm9uRXNtZXJhbGRvLgogIGMuIGFsbF8gbWVhbnMgdGhlIGNvbWJpbmVkIGhhcGxvdHlwZXMgaW5jbHVkaW5nIEVzbWVyYWxkbytOb25Fc21lcmFsZG8rVW5hc3NpZ25lZC4KMy4gIFRoZSBmaW5hbCBwb3J0aW9uIHJlZmVycyB0byB0aGUgZGF0YSB0eXBlIGNyZWF0ZWQuCiAgYS4gZXhwdCBtZWFucyB0aGUgZXhwdCBvYmplY3Qgd2hpY2ggY29udGFpbnMgdGhlIGFubm90YXRpb24gZGF0YSwgc2FtcGxlIGRhdGEsIHJlYWQgY291bnRzLgogIGIuIG1ldHJpY3MgbWVhbnMgdGhlIHNldCBvZiBwbG90cyBkZXNjcmliaW5nIHRoZSBkYXRhLgogIGMuIHh4eG5vcm0gbWVhbnMgbm9ybWFsaXplZCBkYXRhIHVzaW5nIHh4eCB3aGVyZSB4eHggaXMgZGVmaW5lZCBieSBhbiBhYmJyZXZpYXRpb24gb2YgdGhlIG5vcm1hbGl6YXRpb24gdXNlZAogICAgaS4gICBscWNmOiBsb2cyKHF1YW50aWxlKGNwbShmaWx0ZXJlZChkYXRhKSkpKQogICAgaWkuICBjbHFjZjogY29tYmF0KGxvZzIocXVhbnRpbGUoY3BtKGZpbHRlcmVkKGRhdGEpKSkpKQogICAgaWlpLiBzbHFjZjogc3ZhKGxvZzIocXVhbnRpbGUoY3BtKGZpbHRlcmVkKGRhdGEpKSkpKQogICAgaXYuICBPdGhlciBsZXR0ZXJzIG1heSBiZSBhZGRlZCBhcyBuZWVkZWQgaW4gZWFjaCBzbG90LgoKYGBge3IgY3JlYXRlX3N1YnNldHN9CiMjIEkgYW0gZ29pbmcgdG8gY29weSB0aGUgb3JpZ2luYWwgZXhwdHMgdG8gbmFtZXMgd2hpY2ggZm9sbG93IHRoZSBjb252ZW50aW9ucyBiZWxvdwpjbF9lc21lcl9leHB0IDwtIGVzbWVyX2V4cHQKY2xfbm9uZXNtZXJfZXhwdCA8LSBub25lc21lcl9leHB0CmNsX2FsbF9leHB0IDwtIGFsbF9leHB0CiMjIFNwbGl0IHRoZSBlc21lciBkYXRhIGludG8gQ0xCUi9DTDE0CmNsYnJfZXNtZXJfZXhwdCA8LSBleHB0X3N1YnNldChlc21lcl9leHB0LCAidHlwZT09J0NMQnInIikKY2wxNF9lc21lcl9leHB0IDwtIGV4cHRfc3Vic2V0KGVzbWVyX2V4cHQsICJ0eXBlPT0nQ0wxNCciKQojIyBTcGxpdCB0aGUgbm9uZXNtZXIgZGF0YSBpbnRvIENMQlIvQ0wxNApjbGJyX25vbmVzbWVyX2V4cHQgPC0gZXhwdF9zdWJzZXQobm9uZXNtZXJfZXhwdCwgInR5cGU9PSdDTEJyJyIpCmNsMTRfbm9uZXNtZXJfZXhwdCA8LSBleHB0X3N1YnNldChub25lc21lcl9leHB0LCAidHlwZT09J0NMMTQnIikKIyMgQW5kIHRoZSBjb21iaW5lZCBkYXRhCmNsYnJfYWxsX2V4cHQgPC0gZXhwdF9zdWJzZXQoYWxsX2V4cHQsICJ0eXBlPT0nQ0xCciciKQpjbDE0X2FsbF9leHB0IDwtIGV4cHRfc3Vic2V0KGFsbF9leHB0LCAidHlwZT09J0NMMTQnIikKYGBgCgpOb3cgd2UgaGF2ZSA5IGV4cHQgb2JqZWN0cywgb25lIGZvciBlYWNoIGhhcGxvdHlwZSAoZXNtZXIsIG5vbmVzbWVyLCBjb21iaW5lZChhbGwpKQpmb3IgZWFjaCBzdWJzZXQgKGFsbCBkYXRhLCBjbDE0IGRhdGEsIGFuZCBjbGJyIGRhdGEpCgpgYGB7ciBpbml0aWFsX2dyYXBoc19oaWRkZW4xLCBmaWcuc2hvdz0iaGlkZSJ9CmNsX2VzbWVyX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhlc21lcl9leHB0KSkKY2xfbm9uZXNtZXJfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG5vbmVzbWVyX2V4cHQpKQpjbF9hbGxfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGFsbF9leHB0KSkKY2xicl9lc21lcl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9lc21lcl9leHB0KSkKY2xicl9ub25lc21lcl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9ub25lc21lcl9leHB0KSkKY2xicl9hbGxfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGNsYnJfYWxsX2V4cHQpKQpjbDE0X2VzbWVyX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X2VzbWVyX2V4cHQpKQpjbDE0X25vbmVzbWVyX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X25vbmVzbWVyX2V4cHQpKQpjbDE0X2FsbF9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2wxNF9hbGxfZXhwdCkpCmBgYAoKIyMgUXVpY2sgY2hlY2sgdGhlIGxpYnJhcnkgc2l6ZXMKCkkgZmluZCBteXNlbGYgdGhpbmtpbmcgSSBzaG91bGQgcGxvdCB0aGVzZSB0b2dldGhlciBpbiBhIHNpbmdsZSBwbG90IHNvbWVob3cuClRoZXkgYXJlIGtpbmQgb2YgZmFzY2luYXRpbmcsIGFzIHRoZXJlIGFyZSBtb3JlIHJlYWRzIG9uIHRoZSBub25lc21lciBtYXBwaW5ncyB0aGFuIGVzbWVyIGZvciBhbGwKc2FtcGxlcy4gIFdoeSBpcyB0aGlzPwoKYGBge3IgbGlic2l6ZXN9CmNsX2VzbWVyX21ldHJpY3MkbGlic2l6ZQpjbF9ub25lc21lcl9tZXRyaWNzJGxpYnNpemUKIyMgTm9uRXNtZXJhbGRvIG9mdGVuIGdldHMgPj0gMTAlIG1vcmUgcmVhZHMuCmNsX2FsbF9tZXRyaWNzJGxpYnNpemUKYGBgCgojIyBDaGVjayBnbG9iYWwgZGF0YSBkaXN0cmlidXRpb25zIGFjcm9zcyBzdWJzZXRzCgpBcyBhIHN0YXJ0aW5nIHBvaW50LCBsZXQgdXMgc2VlIGhvdyBzaW1pbGFyIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbnMgYXJlIGFjcm9zcyBzdWJzZXRzL2hhcGxvdHlwZXMuCgpUaGlzIHdpbGwgYmUgcHJpbnRlZCBpbiBvcmRlcjoKZXNtZXIgbWFwcGluZzosIGFsbC1kYXRhLCBjbGJyLWRhdGEsIGNsMTQtZGF0YQpub25lc21lciBtYXBwaW5ncywgYWxsLWRhdGEsIGNsYnItZGF0YSwgY2wxNC1kYXRhCmFsbCBtYXBwaW5nczogYWxsLWRhdGEsIGNsYnItZGF0YSwgY2wxNC1kYXRhCmh1bWFuLWRhdGE6IGFsbAoKYGBge3IgZGVuc2l0aWVzfQpsaWJyYXJ5KGRpcmVjdGxhYmVscykKbGlicmFyeShnZ3Bsb3QyKQpkaXJlY3RsYWJlbHM6OmRpcmVjdC5sYWJlbChjbF9lc21lcl9tZXRyaWNzJGRlbnNpdHkpCiMjIFRoZSBkaXN0cmlidXNpb25zIG1vc3RseSBsb29rIGdvb2QgYnV0IGhwZ2wwMTI1IGFuZCBocGdsIDQ3Ni80NzUvNDgyIGFyZSBhCiMjIGxpdHRsZSBvZmYgYXMgSSB0aGluayB3ZSB3aWxsIHNlZSBtb3JlIGNsZWFybHkgaW4gdGhlIHNtYWxsZXIgZGF0YXNldCBwbG90cwpkaXJlY3RsYWJlbHM6OmRpcmVjdC5sYWJlbChjbGJyX2VzbWVyX21ldHJpY3MkZGVuc2l0eSkKIyMgQWhoIHRoZSBsb3dlciBkZW5zaXR5IHNhbXBsZXMgYXJlIHRoZSBhbWFzdGlnb3RlIDYwIGhvdXJzLCB0aGF0IG1ha2VzIHNlbnNlOgojIyA0NzYsNDgyLDQ3NSBhcmUgYWxsIEE2MC4KZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwoY2wxNF9lc21lcl9tZXRyaWNzJGRlbnNpdHkpCiMjIFRoaXMgaXMgc2ltaWxhcmx5IHRydWUgZm9yIHRoZSBjbDE0IHNhbXBsZXMsIGJ1dCBhdCBib3RoIHRpbWUgcG9pbnRzLCA2MCBhbmQKIyMgOTYgaG91cnMuCgpkaXJlY3RsYWJlbHM6OmRpcmVjdC5sYWJlbChjbF9ub25lc21lcl9tZXRyaWNzJGRlbnNpdHkpCmRpcmVjdGxhYmVsczo6ZGlyZWN0LmxhYmVsKGNsYnJfbm9uZXNtZXJfbWV0cmljcyRkZW5zaXR5KQpkaXJlY3RsYWJlbHM6OmRpcmVjdC5sYWJlbChjbDE0X25vbmVzbWVyX21ldHJpY3MkZGVuc2l0eSkKIyMgU3VycHJpc2luZ2x5IHRvIG1lLCB0aGUgbm9uZXNtZXIgYW5kIGVzbWVyIGRlbnNpdHkgcGxvdHMgYXJlIGRpZmZlcmVudCBmb3IKIyMgc29tZSBzYW1wbGVzLgoKZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwoY2xfYWxsX21ldHJpY3MkZGVuc2l0eSkKZGlyZWN0bGFiZWxzOjpkaXJlY3QubGFiZWwoY2xicl9hbGxfbWV0cmljcyRkZW5zaXR5KQojIyBBaGggdGhlIGxvd2VyIGRlbnNpdHkgc2FtcGxlcyBhcmUgdGhlIGFtYXN0aWdvdGUgNjAgaG91cnMsIHRoYXQgbWFrZXMgc2Vuc2U6CiMjIDQ3Niw0ODIsNDc1IGFyZSBhbGwgQTYwLgpkaXJlY3RsYWJlbHM6OmRpcmVjdC5sYWJlbChjbDE0X25vbmVzbWVyX21ldHJpY3MkZGVuc2l0eSkKIyMgU3VycHJpc2luZ2x5IHRvIG1lLCB0aGUgbm9uZXNtZXIgYW5kIGVzbWVyIGRlbnNpdHkgcGxvdHMgYXJlIGRpZmZlcmVudCBmb3IKIyMgc29tZSBzYW1wbGVzLgoKY2xfZXNtZXJfbWV0cmljcyRib3hwbG90CmNsX25vbmVzbWVyX21ldHJpY3MkYm94cGxvdApjbF9hbGxfbWV0cmljcyRib3hwbG90CmBgYAoKV2UgY291bGQgaW4gdGhlb3J5IHByaW50IG91dCB0aGUgcGNhLCBoZWF0bWFwcyBldGMgbm93LCBidXQgSSB0aGluayBJIHdhbnQgZmlyc3QgdG8gcGVyZm9ybSBhCmRlZmF1bHQgbm9ybWFsaXphdGlvbiBvZiB0aGUgZGF0YSBhbmQgc2VlIHRoZSB0cmVuZHMgaW4gdGhlIGRhdGEgYSBiaXQgbW9yZSBjbGVhcmx5LgoKYGBge3IgZGVmYXVsdF9ub3JtfQpjbF9lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbF9lc21lcl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbF9ub25lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbF9ub25lc21lcl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbF9hbGxfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2xfYWxsX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIpCmNsYnJfZXNtZXJfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2xicl9lc21lcl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbGJyX25vbmVzbWVyX2xxY2YgPC0gZGVmYXVsdF9ub3JtKGNsYnJfbm9uZXNtZXJfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIikKY2xicl9hbGxfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2xicl9hbGxfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIikKY2wxNF9lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbDE0X2VzbWVyX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIpCmNsMTRfbm9uZXNtZXJfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2wxNF9ub25lc21lcl9leHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbDE0X2FsbF9scWNmIDwtIGRlZmF1bHRfbm9ybShjbDE0X2FsbF9leHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpgYGAKCiMgUmVkbyBtZXRyaWMgcGxvdHRpbmcgb24gbm9ybWFsaXplZCBkYXRhCgpgYGB7ciBpbml0aWFsX2dyYXBoc19oaWRkZW4sIGZpZy5zaG93PSJoaWRlIn0KY2xfZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xfZXNtZXJfbHFjZikpCmNsX25vbmVzbWVyX2xxY2ZfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGNsX25vbmVzbWVyX2xxY2YpKQpjbF9hbGxfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xfYWxsX2xxY2YpKQpjbGJyX2VzbWVyX2xxY2ZfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGNsYnJfZXNtZXJfbHFjZikpCmNsYnJfbm9uZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9ub25lc21lcl9scWNmKSkKY2xicl9hbGxfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9hbGxfbHFjZikpCmNsMTRfZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2wxNF9lc21lcl9scWNmKSkKY2wxNF9ub25lc21lcl9scWNmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X25vbmVzbWVyX2xxY2YpKQpjbDE0X2FsbF9scWNmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X2FsbF9scWNmKSkKYGBgCgpGb3IgdGhlIGZvbGxvd2luZyBwbG90cywgSSB0aGluayBJIHdpbGwgZm9jdXMgb24gdGhlIGNvbWJpbmVkIGRhdGEgdW5sZXNzIHRoZXJlIGlzIHNvbWV0aGluZyB3aGljaAppcyB1bmNsZWFyIHVubGVzcyBpdCBpcyBzZXBhcmF0ZWQuCgojIyBDb3JyZWxhdGlvbiBoZWF0bWFwcwoKVGhlIGNvcnJlbGF0aW9ucyBpbiB0aGVzZSBwbG90cyBhcmUgZXhjZWVkaW5nbHkgaGlnaCwgMC43PHg8MS4wLgoKYGBge3IgYWxsX2hlYXRtYXBzfQpjbF9lc21lcl9scWNmX21ldHJpY3MkY29yaGVhdApjbF9ub25lc21lcl9scWNmX21ldHJpY3MkY29yaGVhdAojIyBPbmNlIGFnYWluIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGVzbWVyIGFuZCBub25lc21lciBhcmUgc3RyaWtpbmcKY2xfYWxsX2xxY2ZfbWV0cmljcyRjb3JoZWF0CiMjIEhQR0wwNDg1IChjbDE0IGVwaW1hc3RpZ290ZSkgaXMgY2xlYXJseSB0aGUgc3RyYW5nZXN0IHNhbXBsZSBvZiBhbGwuCiMjIEl0cyBjb2hvcnRzLCBIUEdMMDEyOCBsb29rcyBtb3N0IGxpa2UgYSBDTDE0IDYwIGhvdXIgc2FtcGxlOyB3aGlsZSBIUEdMMDEyOQojIyBsb29rcyBsaWtlIGEgQ0xCciBlcGltYXN0aWdvdGUuCiMjIEhQR0wwNDkwIGlzIGFsc28gcHJvYmxlbWF0aWMsIGFzIGl0IGxvb2tzIHZlcnkgc2ltaWxhciB0byB0aGUgQ0xCciA5NiBob3VyIHNhbXBsZXMuCgpjbF9lc21lcl9scWNmX21ldHJpY3MkZGlzaGVhdApjbF9ub25lc21lcl9scWNmX21ldHJpY3MkZGlzaGVhdApjbF9hbGxfbHFjZl9tZXRyaWNzJGRpc2hlYXQKIyMgU2FtZSBzdG9yeSBhcyBhYm92ZSBJIHRoaW5rLCBidXQgdGhlIHByb2JsZW1hdGljIHNhbXBsZXMgSFBHTDA0ODUgaXMgZXZlbgojIyBzdGFya2VyIHRvIG15IGV5ZXMuCgpjbF9hbGxfbHFjZl9tZXRyaWNzJHNtYwpgYGAKCk9uY2UgYWdhaW4sIEkgc2VlIHRoYXQgdGhlIG5vbmVzbWVyIG1hcHBpbmdzIGFyZSBzdXJwcmlzaW5nbHkgKHRvIG1lKSBkaWZmZXJlbnQgdGhhbiB0aGUKZXNtZXIuICBTbyBtdWNoIHNvIHRoYXQgaW4gdGhlIG1vc3QgcGF0aG9sb2dpY2FsbHkgZGlmZmljdWx0IHNhbXBsZXMsIHdlIGdldCBwcmV0dHkgYmlnIHNoaWZ0cwppbiBjbHVzdGVyaW5nIGZvciB0aGUgZXBpbWFzdGlnb3RlIGFuZCB0cnlwb21hc3RpZ290ZSBzYW1wbGVzLiAgVGhpcyBpcyBzdGFydGluZyB0byBtYWtlIG1lIHRoaW5rCnRoYXQgYSBsYXJnZSBudW1iZXIgb2YgdGhlIGdlbmVzIGF0dHJpYnV0ZWQgdG8gdGhlICdVbmFzc2lnbmVkJyBoYXBsb3R5cGUgYXJlIGFjdHVhbGx5IEVzbWVyYWxkby4KCiMjIFBDQQoKRm9yIHRoZSBQQ0EgcGxvdHMsIEkgdGhpbmsgaXQgbWlnaHQgcHJvdmUgdXNlZnVsIHRvIGxvb2sgYXQgdGhlIENMQnIgYW5kIENMMTQgc2FtcGxlcyBzZXBhcmF0ZWx5LgpIb3dldmVyIEkgd2lsbCBzdGFydCBvdXQgd2l0aCB0aGUgZW50aXJlIHNldCBsaWtlIHRoZSBoZWF0bWFwcy4KCmBgYHtyIHBjYV9wbG90c30KY2xfZXNtZXJfbHFjZl9tZXRyaWNzJHBjYXBsb3QKY2xfbm9uZXNtZXJfbHFjZl9tZXRyaWNzJHBjYXBsb3QKY2xfYWxsX2xxY2ZfbWV0cmljcyRwY2FwbG90CmNsMTRfZXNtZXJfbHFjZl9tZXRyaWNzJHBjYXBsb3QKY2wxNF9ub25lc21lcl9scWNmX21ldHJpY3MkcGNhcGxvdApjbDE0X2FsbF9scWNmX21ldHJpY3MkcGNhcGxvdApjbGJyX2VzbWVyX2xxY2ZfbWV0cmljcyRwY2FwbG90CmNsYnJfbm9uZXNtZXJfbHFjZl9tZXRyaWNzJHBjYXBsb3QKY2xicl9hbGxfbHFjZl9tZXRyaWNzJHBjYXBsb3QKYGBgCgojIyBBIHNlcGFyYXRlLCBzaW1wbGVyIEZpZ3VyZSBTMDJBOgoKTm90ZSB0aGF0IHRoaXMgZmlndXJlIG11c3QgYmUgZ2VuZXJhdGVkIGJlZm9yZSByZW1vdmluZyB0cm91Ymxpbmcgc2FtcGxlcyBiZWNhdXNlIEkgcmV1c2VkIHRoZSBuYW1lcwpvZiBzb21lIG9mIHRoZSBleHByZXNzaW9uc2V0cy4KCmBgYHtyIGZpZ3VyZV9zMDJhX3NpbXBsZXIsIGV2YWw9RkFMU0V9CiMjIDIwMTcwMjE0IFRoaXMgaXMgY2F1c2luZyBhIHNlZ21lbnRhdGlvbiBmYXVsdC4gaG1tIGl0IHNlZW1zIGZpeGVkIG5vdy4uLgojIyBBbGwgSSBkaWQgd2FzIHJlc3RhcnQgdGhlIGNvbXB1dGVyLCBSIHdvcnJpZXMgbXkgc29tZXRpbWVzLgpjbF9hbGxfd3JpdHRlbiA8LSB3cml0ZV9leHB0KGNsX2FsbF9leHB0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2VsPXBhc3RlMCgiZXhjZWwvdGVzdGluZy12IiwgdmVyLCAiLnhsc3giKSkKc3ZnKGZpbGU9ImltYWdlcy9maWdTMDJhX2F0Yl92Mi4zLnN2ZyIpCmNsX2FsbF9scWNmX21ldHJpY3MkY29yaGVhdApkZXYub2ZmKCkKdGVzdGluZyA8LSBub3JtYWxpemVfZXhwdChjbF9hbGxfZXhwdCwgZmlsdGVyPUZBTFNFLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm09InF1YW50IiwgdHJhbnNmb3JtPSJsb2cyIikKdGVzdGluZ19kaXNoZWF0IDwtIHBsb3RfZGlzaGVhdCh0ZXN0aW5nKQp0ZXN0aW5nX3BjYSA8LSBwbG90X3BjYSh0ZXN0aW5nLCBwbG90X2xhYmVscz1GQUxTRSkKcGRmKGZpbGU9ImltYWdlcy9maWdTMDJhX2F0Yl92Mi4yX2FsbF9zYW1wbGVzLnBkZiIpCnRlc3RpbmdfZGlzaGVhdCRwbG90CmRldi5vZmYoKQpzdmcoZmlsZT0iaW1hZ2VzL2ZpZ1MwMmJfYXRiX3YyLjJfYWxsX3NhbXBsZXMuc3ZnIikKdGVzdGluZ19wY2EkcGxvdApkZXYub2ZmKCkKCiMjIEkgdGhpbmsgdGhlcmVmb3JlIHdlIHdhbnQ6CiMjIDEuICBBIFBDQSBvZiBhbGwgc2FtcGxlcyBsb2cyKGNwbShxdWFudChmaWx0KHN2YSgpKSkpKSAobm90IGluIHRoYXQgb3JkZXIpCiMjIDIuICBDb3JyZXNwb25kaW5nIGNvcnJlbGF0aW9uIGhlYXRtYXAsIGRpc3RhbmNlLCBhbmQgc21jLgp0ZXN0X2RhdGEgPC0gbm9ybWFsaXplX2V4cHQoY2xfYWxsX2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIsIG5vcm09InF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnZlcnQ9ImNwbSIsIGZpbHRlcj1UUlVFKQojI3Rlc3Rfd3JpdGUgPC0gd3JpdGVfZXhwdChjbF9hbGxfZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgbm9ybT0icXVhbnQiLAojIyAgICAgICAgICAgICAgICAgICAgICAgICBjb252ZXJ0PSJjcG0iLCBmaWx0ZXI9VFJVRSwKIyMgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9cGFzdGUwKCJleGNlbC9jbF9hbGxfZXhwdC12IiwgdmVyLCAiLnhsc3giKSkKZmlnX3BjYSA8LSBwbG90X3BjYSh0ZXN0X2RhdGEpCmZpZ19jZCA8LSBwbG90X2NvcmhlYXQodGVzdF9kYXRhKQpmaWdfZGQgPC0gcGxvdF9kaXNoZWF0KHRlc3RfZGF0YSkKZmlnX3NtYyA8LSBwbG90X3NtKHRlc3RfZGF0YSkKc3ZnKGZpbGU9ImltYWdlcy9maWdTMDJ2MmFfYXRiX3YyLjAuc3ZnIikKZmlnX3BjYSRwbG90CmRldi5vZmYoKQpwZGYoZmlsZT0iaW1hZ2VzL2ZpZ1MwMnYyYl9hdGJfdjIuMC5wZGYiKQpmaWdfY2QkcGxvdApkZXYub2ZmKCkKcGRmKGZpbGU9ImltYWdlcy9maWdTMDJ2MmNfYXRiX3YyLjAucGRmIikKZmlnX2RkJHBsb3QKZGV2Lm9mZigpCnN2ZyhmaWxlPSJpbWFnZXMvZmlnUzAydjJkX2F0Yl92Mi4wLnN2ZyIpCmZpZ19zbWMKZGV2Lm9mZigpCmBgYAoKIyMgQSBjb3VwbGUgb2YgcG9zc2libGUgaW1wbGVtZW50YXRpb25zIG9mIEZpZ3VyZSAyCgpUaGUgdGV4dCBpbnRyb2R1Y2luZyBGaWd1cmUgMiBpcyBhcyBmb2xsb3dzOgoKIk1hcHBlZCBzZXF1ZW5jaW5nIGRhdGEgZGVyaXZlZCBmcm9tIGFsbCBsaWJyYXJpZXMgd2VyZSBhbmFseXplZCB1c2luZyB0d28gbWV0aG9kcyB0byBpbnNwZWN0IHRoZQpyZWxhdGlvbnNoaXBzIGJldHdlZW4gc2FtcGxlcyBhbmQgdG8gaWRlbnRpZnkgb3V0bGllcnMuIFNhbXBsZXMgd2VyZSBzdWJqZWN0ZWQgdG8gcHJpbmNpcGFsCmNvbXBvbmVudCBhbmFseXNpcyAoUENBKSBhcyB3ZWxsIGFzIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nLiBUaGUgcmVzdWx0aW5nIGhlYXQgbWFwIGFuZCBQQ0EgcGxvdAooRmlndXJlIDIpIHNob3dlZCBhIGNsZWFyIHNlcGFyYXRpb24gYmV0d2VlbiBzYW1wbGVzIGFzIHdlbGwgYXMgdGhlIGV4cGVjdGVkIGNsdXN0ZXJpbmcgYmV0d2VlbgpiaW9sb2dpY2FsIHRyaXBsaWNhdGVzLCBleGNlcHQgZm9yIG9uZSBsaWJyYXJ5IGdlbmVyYXRlZCBmcm9tIFJOQSBpc29sYXRlZCBmcm9tIENMIEJyZW5lcgp0cnlwb21hc3RpZ290ZXMsIHdoaWNoIHdhcyBpZGVudGlmaWVkIGFzIGFuIG91dGxpZXIgYW5kIHdhcyBleGNsdWRlZCBmcm9tIGZ1cnRoZXIgYW5hbHlzZXMgKEZpZ3VyZQoyQykuIE9mIHRoZSAyNDg4NyBnZW5lcyBhbmFseXplZCwgMjMxOTEgd2VyZSBleHByZXNzZWQgYXQgYSBsZXZlbCBvZiAgYXQgbGVhc3QgMSBjb3VudCBwZXIgbWlsbGlvbgppbiBhdCBsZWFzdCAyIHNhbXBsZXMuIgoKSSB0YWtlIHRoaXMgdG8gbWVhbiB0aGF0IHdlIGFyZSBwZXJmb3JtaW5nIGEgaGVhdG1hcCBhbmQgUENBIG9mIF9hbGxfIHNhbXBsZXMuCgpUaGUgaGVhdCBtYXAgcHJvdmlkZWQgaW4gdGhlIHBvd2VycG9pbnQsIGFwcGVhcnMgdG8gbWUgdG8gbm90IGhhdmUgYWxsIHNhbXBsZXMsIGJ1dCBpcyBpbnN0ZWFkCm1pc3NpbmcgdGhlIENMMTQgZXBpbWFzdGlnb3Rlcy4gIFdoaWxlIGl0IGlzIHRydWUgd2UgcmVtb3ZlIHRoZW0sIHRoaXMgcGllY2Ugb2YgdGV4dCBkb2VzIHNheSB3ZSBhcmUKbG9va2luZyBhdCBhbGwgc2FtcGxlcyAtLSB3aGljaCBpcyBpdD8KCmBgYHtyIGZpZ3VyZTJfc2lsbHl9CmxpYnJhcnkoQmlvYmFzZSkKbmV3X25hbWVzIDwtIHBhc3RlMChyb3duYW1lcyhwRGF0YShjbF9hbGxfbHFjZiRleHByZXNzaW9uc2V0KSksICJfIiwKICAgICAgICAgICAgICAgICAgICBwRGF0YShjbF9hbGxfbHFjZiRleHByZXNzaW9uc2V0KSRvcmlnaW5hbGNvbmQsICJfIiwKICAgICAgICAgICAgICAgICAgICBwRGF0YShjbF9hbGxfbHFjZiRleHByZXNzaW9uc2V0KSRiYXRjaCkKZGlzdGFuY2VfcGxvdCA8LSBwbG90X2Rpc2hlYXQoY2xfYWxsX2xxY2YsIGV4cHRfbmFtZXM9bmV3X25hbWVzKQpjb3JyZWxhdGlvbl9wbG90IDwtIHBsb3RfY29yaGVhdChjbF9hbGxfbHFjZiwgZXhwdF9uYW1lcz1uZXdfbmFtZXMpCgpsaWJyYXJ5KEhlYXRwbHVzKQpyb3dfY29ycmVsYXRpb25zIDwtIGhwZ2xfY29yKGV4cHJzKGNsX2FsbF9scWNmJGV4cHJlc3Npb25zZXQpKQpyb3dfZGVzaWduIDwtIGFzLmRhdGEuZnJhbWUocERhdGEoY2xfYWxsX2xxY2YkZXhwcmVzc2lvbnNldCkpCiMjIFJlb3JkZXIgdGhlIGRlc2lnbiB0byBtYXRjaCB0aGUgY29ycmVsYXRpb24gY2x1c3RlcmluZyBvcmRlcgpyb3dfZGVzaWduIDwtIHJvd19kZXNpZ25bcm93bmFtZXMocm93X2NvcnJlbGF0aW9ucyksIF0KCmNvbHVtbl9kaXN0YW5jZXMgPC0gYXMubWF0cml4KGRpc3QodChleHBycyhjbF9hbGxfbHFjZiRleHByZXNzaW9uc2V0KSkpKQpjb2x1bW5fZGVzaWduIDwtIGFzLmRhdGEuZnJhbWUocERhdGEoY2xfYWxsX2xxY2YkZXhwcmVzc2lvbnNldCkpCiMjIFJlb3JkZXIgdGhlc2UgYWNjb3JkaW5nIHRvIHRoZSBkaXN0YW5jZSBjbHVzdGVyaW5nCmNvbHVtbl9kZXNpZ24gPC0gY29sdW1uX2Rlc2lnbltyb3duYW1lcyhjb2x1bW5fZGlzdGFuY2VzKSwgXQoKIyMgTm93IGNob29zZSB0aGUgY29sdW1ucyBvZiB0aGUgZGVzaWduIHRvIGFkZCBhcyBhbm5vdGF0aW9ucwpyb3dfZGVzaWduIDwtIHJvd19kZXNpZ25bLCBjKCJiYXRjaCIsInJlcGxpY2F0ZSIpXQpyb3dfZGVzaWduJHJlcGxpY2F0ZSA8LSBhcy5mYWN0b3Iocm93X2Rlc2lnbiRyZXBsaWNhdGUpCmNvbHVtbl9kZXNpZ24gPC0gY29sdW1uX2Rlc2lnblssIGMoInR5cGUiLCJzdGFnZSIpXQoKbXlfYW5ub3RhdGlvbnMgPC0gbGlzdChSb3c9bGlzdChkYXRhPXJvd19kZXNpZ24pLAogICAgICAgICAgICAgICAgICAgICAgIENvbD1saXN0KGRhdGE9Y29sdW1uX2Rlc2lnbikpCm15X2xhYmVscyA8LSBsaXN0KFJvdz1saXN0KG5yb3c9NSksCiAgICAgICAgICAgICAgICAgIENvbD1saXN0KG5yb3c9NSkpCm15X2NsdXN0ZXJfZGlzdGFuY2VzIDwtIGxpc3QoUm93PWxpc3QoY3V0aD0yKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2w9bGlzdChjdXRoPTEwMCkpCmNvcmRpc3QgPC0gY29sdW1uX2Rpc3RhbmNlcwpmb3IgKHIgaW4gMTpucm93KHJvd19jb3JyZWxhdGlvbnMpKSB7CiAgICBmb3IgKGMgaW4gMTpuY29sKHJvd19jb3JyZWxhdGlvbnMpKSB7CiAgICAgICAgaWYgKGMgPiByKSB7CiAgICAgICAgICAgIGNvcmRpc3RbcixjXSA8LSByb3dfY29ycmVsYXRpb25zW3IsY10KICAgICAgICB9IGVsc2UgaWYgKHIgPT0gYykgewogICAgICAgICAgICBjb3JkaXN0W3IsY10gPC0gMAogICAgICAgIH0KICAgIH0KfQojIyBvaywgc28gbm93IHdlIGdvIGZyb20gLTEgKGhpZ2hlc3QgY29ycmVsYXRpb24pIHRvIDAgKGxvd2VzdCBjb3JyZWxhdGlvbiksCiMjIHRoZW4gdXAgdG8gaGlnaCBudW1iZXJzIChkaXN0YW5jZSkKbWFwMSA8LSBhbm5IZWF0bWFwMihjb3JkaXN0LCBzY2FsZT0ibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcj1teV9jbHVzdGVyX2Rpc3RhbmNlcywKICAgICAgICAgICAgICAgICAgICBhbm49bXlfYW5ub3RhdGlvbnMsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzPW15X2xhYmVscykKIyMgaGVhdG1hcC4yIGhlYXRtYXBzIGhhdmU6ICRicmVha3MgKGNvbG9yIGJyZWFrcyksICRjb2wgKGNvbG9ycyBieSBicmVha3MpLAojIyBhbmQgJGNvbG9yVGFibGUgKGxvdyxoaWdoLGNvbG9yIGFzc2lnbm1lbnRzKQojIyBhbm5IZWF0bWFwMiBoYXMgJGJyZWFrcyBhbmQgJGNvbCAtLSBwZXJoYXBzIEkgY2FuIHVzZSB0aGF0LgptYXAyIDwtIG1hcDEKY29yX2JyZWFrcyA8LSByZXYoY29ycmVsYXRpb25fcGxvdFtbIm1hcCJdXVtbImJyZWFrcyJdXSkKZGlzdF9icmVha3MgPC0gZGlzdGFuY2VfcGxvdFtbIm1hcCJdXVtbImJyZWFrcyJdXQpkaXN0X2JyZWFrcyA8LSBkaXN0X2JyZWFrc1syOmxlbmd0aChkaXN0X2JyZWFrcyldCnRvdGFsX2JyZWFrcyA8LSBhcHBlbmQoY29yX2JyZWFrcywgZGlzdF9icmVha3MpCm1hcDJbWyJkYXRhIl1dW1siY29sIl1dIDwtIGFwcGVuZChjb3JyZWxhdGlvbl9wbG90W1sibWFwIl1dW1siY29sIl1dLCBkaXN0YW5jZV9wbG90W1sibWFwIl1dW1siY29sIl1dKQptYXAyW1siZGF0YSJdXVtbImJyZWFrcyJdXSA8LSB0b3RhbF9icmVha3MKIyNtYXAyJGRhdGEkeDIgPC0gbWFwMiRkYXRhJHgKcGxvdChtYXAyKQpgYGAKCiMgUmVtb3ZlIHRyb3VibGVkIHNhbXBsZXMKCk15IHByZXZpb3VzIG5vdGVzLCBhbmQgdGhlIHBsb3RzIGFib3ZlIHN1Z2dlc3Qgc3Ryb25nbHkgdGhhdCB0aGUgc2FtcGxlcyBIUEdMMDQ4NSwgSFBHTDA0OTAsIGFuZCBIUEdMMDE2MyBhcmUgcHJvYmxlbWF0aWMuCkkgaGF2ZSBhbHJlYWR5IGV4Y2x1ZGVkIEhQR0wwMTYzLCBzbyBub3cgSSBqdXN0IHdhbnQgdG8gZHJvcCB0aGUgb3RoZXIgdHdvLgoKSSBhbSBnb2luZyB0byB0aGVyZWZvcmUgY3JlYXRlIG5ldyBiYXNlIGtleHB0IG9iamVjdHMgYW5kIG92ZXJ3cml0ZSB0aGUgbm9ybWFsaXplZCBkYXRhIHdpdGggdGhlIG5ldyBub3JtYWxpemVkIGRhdGEuCgpgYGB7ciBzYW1wbGVfcmVtb3ZhbCwgZmlnLnNob3c9ImhpZGUifQpvbGRfc3Vic2V0IDwtICJzYW1wbGVpZCE9J0hQR0wwNDg1JyZzYW1wbGVpZCE9J0hQR0wwNDkwJyZzYW1wbGVpZCE9J0hQR0wwMTI5JyZzYW1wbGVpZCE9J0hQR0wwMTI4JyIKIyNuZXdfc3Vic2V0IDwtICJzYW1wbGVpZCE9J0hQR0wwMTI4JyZzYW1wbGVpZCE9J0hQR0wwMTI5JyZzYW1wbGVpZCE9J0hQR0wwNDgzJyZzYW1wbGVpZCE9J0hQR0wwNDg1JyZzYW1wbGVpZCE9J0hQR0wwNDg2JyZzYW1wbGVpZCE9J0hQR0wwNDg3JyZzYW1wbGVpZCE9J0hQR0wwNDkwJyIKIyNuZXdfc3Vic2V0IDwtICJzdGFnZSE9J0VwaScmc2FtcGxlaWQhPSdIUEdMMDQ5MCciCm91dGxpZXJfc3Vic2V0IDwtICJzYW1wbGVpZCE9J0hQR0wwNDkwJyIKbm9lcGlfc3Vic2V0IDwtICJzdGFnZSE9J0VwaSciCmNsX2FsbF9rZXhwdHYxIDwtIGV4cHRfc3Vic2V0KGNsX2FsbF9leHB0LCBzdWJzZXQ9b3V0bGllcl9zdWJzZXQpCmNsX2FsbF9rZXhwdCA8LSBleHB0X3N1YnNldChjbF9hbGxfa2V4cHR2MSwgc3Vic2V0PW5vZXBpX3N1YnNldCkKZXhwdF9maWxlbmFtZSA8LSBwYXN0ZTAoImV4Y2VsL2NsX2FsbF9rZXhwdHYxLSIsIHZlciwgIi54bHN4IikKcHJpbnRlZF9leHB0IDwtIHdyaXRlX2V4cHQoY2xfYWxsX2tleHB0djEsIHZpb2xpbj1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjZWw9ZXhwdF9maWxlbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIHRyYW5zZm9ybT0ibG9nMiIsIG5vcm09InF1YW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udmVydD0icmF3IiwgYmF0Y2g9InN2YSIpCgpjbF9lc21lcl9rZXhwdCA8LSBleHB0X3N1YnNldChjbF9lc21lcl9leHB0LCBzdWJzZXQ9b3V0bGllcl9zdWJzZXQpCmNsX25vbmVzbWVyX2tleHB0IDwtIGV4cHRfc3Vic2V0KGNsX25vbmVzbWVyX2V4cHQsIHN1YnNldD1vdXRsaWVyX3N1YnNldCkKY2xfYWxsX2tleHB0IDwtIGV4cHRfc3Vic2V0KGNsX2FsbF9leHB0LCBzdWJzZXQ9b3V0bGllcl9zdWJzZXQpCmNsYnJfZXNtZXJfa2V4cHQgPC0gZXhwdF9zdWJzZXQoY2xicl9lc21lcl9leHB0LCBzdWJzZXQ9b3V0bGllcl9zdWJzZXQpCmNsYnJfbm9uZXNtZXJfa2V4cHQgPC0gZXhwdF9zdWJzZXQoY2xicl9ub25lc21lcl9leHB0LCBzdWJzZXQ9b3V0bGllcl9zdWJzZXQpCmNsYnJfYWxsX2tleHB0IDwtIGV4cHRfc3Vic2V0KGNsYnJfYWxsX2V4cHQsIHN1YnNldD1vdXRsaWVyX3N1YnNldCkKY2wxNF9lc21lcl9rZXhwdCA8LSBleHB0X3N1YnNldChjbDE0X2VzbWVyX2V4cHQsIHN1YnNldD1vdXRsaWVyX3N1YnNldCkKY2wxNF9ub25lc21lcl9rZXhwdCA8LSBleHB0X3N1YnNldChjbDE0X25vbmVzbWVyX2V4cHQsIHN1YnNldD1vdXRsaWVyX3N1YnNldCkKY2wxNF9hbGxfa2V4cHQgPC0gZXhwdF9zdWJzZXQoY2wxNF9hbGxfZXhwdCwgc3Vic2V0PW91dGxpZXJfc3Vic2V0KQpjbF9lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbF9lc21lcl9rZXhwdCwgdHJhbnNmb3JtPSJsb2cyIikKY2xfbm9uZXNtZXJfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2xfbm9uZXNtZXJfa2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIpCmNsX2FsbF9scWNmIDwtIGRlZmF1bHRfbm9ybShjbF9hbGxfa2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIpCmNsYnJfZXNtZXJfbHFjZiA8LSBkZWZhdWx0X25vcm0oY2xicl9lc21lcl9rZXhwdCwgdHJhbnNmb3JtPSJsb2cyIikKY2xicl9ub25lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbGJyX25vbmVzbWVyX2tleHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbGJyX2FsbF9scWNmIDwtIGRlZmF1bHRfbm9ybShjbGJyX2FsbF9rZXhwdCwgdHJhbnNmb3JtPSJsb2cyIikKY2wxNF9lc21lcl9scWNmIDwtIGRlZmF1bHRfbm9ybShjbDE0X2VzbWVyX2tleHB0LCB0cmFuc2Zvcm09ImxvZzIiKQpjbDE0X25vbmVzbWVyX2xxY2YgPC0gZGVmYXVsdF9ub3JtKGNsMTRfbm9uZXNtZXJfa2V4cHQsIHRyYW5zZm9ybT0ibG9nMiIpCmNsMTRfYWxsX2xxY2YgPC0gZGVmYXVsdF9ub3JtKGNsMTRfYWxsX2tleHB0LCB0cmFuc2Zvcm09ImxvZzIiKQoKY2xfZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xfZXNtZXJfbHFjZikpCmNsX25vbmVzbWVyX2xxY2ZfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGNsX25vbmVzbWVyX2xxY2YpKQpjbF9hbGxfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xfYWxsX2xxY2YpKQpjbGJyX2VzbWVyX2xxY2ZfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKGNsYnJfZXNtZXJfbHFjZikpCmNsYnJfbm9uZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9ub25lc21lcl9scWNmKSkKY2xicl9hbGxfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2xicl9hbGxfbHFjZikpCmNsMTRfZXNtZXJfbHFjZl9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MoY2wxNF9lc21lcl9scWNmKSkKY2wxNF9ub25lc21lcl9scWNmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X25vbmVzbWVyX2xxY2YpKQpjbDE0X2FsbF9scWNmX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhjbDE0X2FsbF9scWNmKSkKYGBgCgojIyBBIHNlcGFyYXRlLCBzaW1wbGVyIEZpZ3VyZSAwMkE6CgpgYGB7ciBmaWd1cmVfMDJhX3NpbXBsZXJ9CmRpc3RhbmNlX3Bsb3QgPC0gcGxvdF9kaXNoZWF0KGNsX2FsbF9scWNmKQoKdGVzdGluZ19kYXRhIDwtIG5vcm1hbGl6ZV9leHB0KGNsX2FsbF9rZXhwdCwgdHJhbnNmb3JtPSJsb2cyIiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcj1UUlVFLCBiYXRjaD0ic3N2YSIpCmNvcnJlbGF0aW9uX3Bsb3QgPC0gcGxvdF9jb3JoZWF0KHRlc3RpbmdfZGF0YSwga2V5c2l6ZT0xLjUpCnBkZihmaWxlPSJpbWFnZXMvZmlnMDJhX2F0Yl92Mi4zLnBkZiIpCmNvcnJlbGF0aW9uX3Bsb3QkcGxvdApkZXYub2ZmKCkKcGNhX3Bsb3QgPC0gcGxvdF9wY2EodGVzdGluZ19kYXRhLCBwbG90X2xhYmVscz1GQUxTRSkKc3ZnKGZpbGU9ImltYWdlcy9maWcwMmJfYXRiX3YyLjMuc3ZnIikKcGNhX3Bsb3QkcGxvdApkZXYub2ZmKCkKYGBgCgojIFJlLXZpc3VhbGl6ZSBjaG9zZW4gbm9ybWFsaXplZCBtZXRyaWNzCgpOb3cgdGhlIHZpc3VhbGl6YXRpb25zIHNob3VsZCBiZSBtYXhpbWFsbHkgcHJldHR5LgoKYGBge3IgdmlzX3ByZXR0eX0KY2xfbm9uZXNtZXJfbHFjZl9tZXRyaWNzJGNvcmhlYXQKY2xicl9ub25lc21lcl9scWNmX21ldHJpY3MkY29yaGVhdApjbDE0X25vbmVzbWVyX2xxY2ZfbWV0cmljcyRjb3JoZWF0CmNsX25vbmVzbWVyX2xxY2ZfbWV0cmljcyRwY2FwbG90CmNsYnJfbm9uZXNtZXJfbHFjZl9tZXRyaWNzJHBjYXBsb3QKY2wxNF9ub25lc21lcl9scWNmX21ldHJpY3MkcGNhcGxvdApgYGAKCiMgVmlvbGlucyEKCkxldHMgc2VlIGlmIG15IG5ldyB2aW9saW4gZnVuY3Rpb24gd29ya3MuCgpgYGB7ciB2aW9saW4sIGV2YWw9RkFMU0V9CmNsYnJfZmlsdCA8LSBub3JtYWxpemVfZXhwdChjbGJyX2FsbF9rZXhwdCwgZmlsdGVyPSJjYmNiIikKdmFycGFydF9iIDwtIHZhcnBhcnQoY2xicl9maWx0LCBwcmVkaWN0b3I9TlVMTCwgZmFjdG9ycz1jKCJhY3R1YWxiYXRjaCIpKQp2YXJwYXJ0X2IkcGFydGl0aW9uX3Bsb3QKdmFycGFydF9jIDwtIHZhcnBhcnQoY2xicl9maWx0LCBwcmVkaWN0b3I9TlVMTCwgZmFjdG9ycz1jKCJjb25kaXRpb24iKSkKdmFycGFydF9jJHBhcnRpdGlvbl9wbG90CnZhcnBhcnRfY2IgPC0gdmFycGFydChjbGJyX2ZpbHQsIHByZWRpY3Rvcj1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgZmFjdG9ycz1jKCJjb25kaXRpb24iLCJhY3R1YWxiYXRjaCIpKQp2YXJwYXJ0X2NiJHBhcnRpdGlvbl9wbG90CmBgYAoKYGBge3Igc2F2ZV9lc3RpbWF0aW9ufQp0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCmBgYAo=