In this document, I will attempt to visualize the relationships among the various samples in this experiment. In the process, I will examine the samples to (hopefully) ensure that they are consistent and that there is not a fatal batch effect or other weakness in the data.

To start, I will print some simple metrics of the entire data set, then split it into more tractable pieces and examine them more thoroughly.

1 Raw global metrics

With the above in mind, here are a couple global plots showing the state of the data.

1.1 mi vs tx

When processing the data, I did 1 alignment of the reads from all samples against a database of miRNAs and then separately against a database of all transcripts. All the samples of library type ‘small’ are really only intended to be compared against the miRNA library while those of type ‘large’ are intended only to search against the transcripts. This is primarily because of the different ways the RNA samples were treated at the beginning of the library preparation. Despite this, I perform both types of alignments for all samples so that I may now look and see that the distributions are different. If everything worked as planned, then the large RNA libraries should have a very different distribution of reads in the miRNA databases and vice-versa. If this is not true, then something might be very wrong.

With that in mind, the following block is going to do some of the graphs and normalize the data. In the following blocks I will print some of the results and consider what they mean.

The following block will serve to generate all the likely subsets of the data.

Lets lay down a couple rules of thumb now:

  1. In all following analyses, do the miRNA first, then transcripts.
  2. All miRNA datasets will start with ‘mmmi’ and transcripts will be ‘mmtx’
## Graph the raw metrics of all samples mapped against the transcripts and miRNAs
##mm_mir <- expt_subset(mm_mir, subset="genotype!='apop'")
##mm_txr <- expt_subset(mm_txr, subset="genotype!='apop'")
mm_mi_metrics <- sm(graph_metrics(mm_mir))
mm_tx_metrics <- sm(graph_metrics(mm_txr))
mmmi_small_metrics <- sm(graph_metrics(mmmi_small))
mmtx_large_metrics <- sm(graph_metrics(mmtx_large))

1.2 A Legend!

First, do not forget to print a legend showing the colors used and what they mean:

mm_mi_metrics$legend$plot

## This should be the same for the mm_mi and mm_tx objects.

1.3 Start with some global metrics

mm_mi_metrics$libsize

Hahah I am a doofus. For a moment I thought this was a total disaster. The first 8 libraries are small RNA libraries of which the first 4 are exosomes. The important thing to remember is that these are mapped against only the 1978 miRNA features in the mouse Ensembl genome, as such we see that the first 4 are highly enriched in miRNAs, which is excellent.

Therefore, as one would expect, the small exosome RNA libraries have fewer reads than the total cell small RNA libraries, which comprise the set from 5-8. I of course focused immediately upon the last 8 without thinking. These are all the polyA RNA samples, of which the miRNA features are only a small proportion and therefore we see them as <10% the depth of the small RNA samples. I would therefore expect something like the opposite for the transcriptome samples, which are next.

mm_tx_metrics$libsize

Ahh excellent. Once again, the exosome samples have fewer reads than the cells and have many fewer for the small RNA samples than transcript samples, which is good.

2 Sample distributions

From here on, I think I will examine only the small RNA samples and large RNA samples as 2 separate groups.

mmmi_small_metrics$density

mmmi_small_metrics$boxplot

## The sample densities among the small RNA samples look reasonable to me.
mmtx_large_metrics$density

mmtx_large_metrics$boxplot

## This is more problematic from the perspective of the data distributions; but not suprising and
## encouraging from a biological perspective.  The large RNA exosomes have many more genes with 0
## counts.

Considering the heterologous sources of these samples, I think these actually make sense, lets move on and see what else pops up.

2.1 Normalized Metrics

2.1.1 Something is messed up

tt <- sm(library(Biobase))
older_data <- sm(normalize_expt(mmmi_small, filter="cbcb", batch="svaseq", transform="log2", convert="cpm", norm="quant"))
tt <- read.csv("current_norm_counts.csv")
rownames(tt) <- tt$row.names_1
tt <- tt[, -1]
colnames(tt) <- colnames(exprs(older_data$expressionset))
tt <- as.matrix(tt)
exprs(older_data$expressionset) <- tt
plot_pca(older_data)$plot

newer_data <- sm(normalize_expt(mmmi_small, filter=TRUE))
newer_data <- sm(normalize_expt(newer_data, transform="log2"))
newer_data <- sm(normalize_expt(newer_data, batch="svaseq"))
plot_pca(newer_data)$plot

head(exprs(newer_data$expressionset))
##                          HPGL0673  HPGL0674 HPGL0675 HPGL0676 HPGL0677 HPGL0678 HPGL0679
## chr10_ENSMUSG00000065406 13.68362 14.356512 14.22133 13.05992  13.2824   11.747   12.579
## chr10_ENSMUSG00000065430 15.40259 14.460674 15.44751 14.88549  14.8038   13.664   13.783
## chr10_ENSMUSG00000065607  3.84900  3.304276  3.41267  4.52450   5.0937    5.153    5.573
## chr10_ENSMUSG00000072837 -0.03828 -0.004397 -0.02086  0.05697   0.1767    0.200    1.160
## chr10_ENSMUSG00000076282  3.90750  3.540230  4.19327  4.52894   3.3235    3.272    3.771
## chr10_ENSMUSG00000076377  3.24159  3.169939  1.63295  2.87267   0.5068    3.424    2.424
##                          HPGL0680 HPGL0523 HPGL0524 HPGL0525 HPGL0555 HPGL0556  HPGL0557
## chr10_ENSMUSG00000065406   12.609  14.0610  12.6006  11.5508  13.2688 14.90448 12.921425
## chr10_ENSMUSG00000065430   14.548  15.0392  14.3152  14.5733  14.9921 14.96946 14.933262
## chr10_ENSMUSG00000065607    4.770   3.7294   6.2637   6.4215   4.1248  6.26584  6.601161
## chr10_ENSMUSG00000072837    1.185   0.8603  -0.1125  -0.1865  -0.1375  0.07877 -0.006403
## chr10_ENSMUSG00000076282    3.215   3.4830   2.6182   4.3736   4.4009  1.91238  2.989641
## chr10_ENSMUSG00000076377    2.326   1.9453   0.7421   0.7456   2.2778  1.43283  1.833683
##                          HPGL0558 HPGL0559 HPGL0560
## chr10_ENSMUSG00000065406  10.8910 11.58183  12.2112
## chr10_ENSMUSG00000065430  15.0328 16.09648  16.5378
## chr10_ENSMUSG00000065607   6.2635  5.70732   4.3671
## chr10_ENSMUSG00000072837   0.9327 -0.04588   2.2239
## chr10_ENSMUSG00000076282   3.1016  2.82909   4.6733
## chr10_ENSMUSG00000076377   2.4565 -0.27303   0.2501
newer_data <- sm(normalize_expt(mmmi_small, filter=TRUE, transform="log2",
                                batch="svaseq", norm="quant"))
plot_pca(newer_data)$plot

head(exprs(newer_data$expressionset))
##                          HPGL0673 HPGL0674 HPGL0675 HPGL0676 HPGL0677 HPGL0678 HPGL0679
## chr10_ENSMUSG00000065406  14.3892   15.183  14.7172  14.6155  14.1600  13.0178  13.9433
## chr10_ENSMUSG00000065430  17.5851   15.481  16.8497  16.9851  15.6866  15.8460  15.0628
## chr10_ENSMUSG00000065607   5.5268    5.044   5.8579   5.3218   4.4953   4.1794   5.4221
## chr10_ENSMUSG00000072837   0.7435    1.150   0.9354   0.7889   0.5968   0.6424   0.9229
## chr10_ENSMUSG00000076282   3.6269    2.908   3.4527   3.5106   4.7548   4.0961   4.8982
## chr10_ENSMUSG00000076377   3.1827    3.205   1.8553   2.0704   0.8876   2.7625   2.1457
##                          HPGL0680 HPGL0523 HPGL0524 HPGL0525 HPGL0555 HPGL0556 HPGL0557
## chr10_ENSMUSG00000065406   13.264   14.428  13.4813  14.5400   14.506  14.8595  13.8445
## chr10_ENSMUSG00000065430   16.309   15.292  15.1815  17.4366   16.299  16.5851  16.4371
## chr10_ENSMUSG00000065607    3.974    3.994   7.2001   6.4671    4.748   5.8259   6.8290
## chr10_ENSMUSG00000072837    1.294    0.984  -0.2465   0.6387    1.506   0.2668  -0.7884
## chr10_ENSMUSG00000076282    4.278    4.376   2.8431   3.7180    3.353   4.5176   5.2178
## chr10_ENSMUSG00000076377    1.928    1.680   0.7907   1.9127    2.443   0.7774   2.0949
##                          HPGL0558 HPGL0559 HPGL0560
## chr10_ENSMUSG00000065406  14.1788   14.335   14.376
## chr10_ENSMUSG00000065430  15.9038   17.190   16.380
## chr10_ENSMUSG00000065607   7.9194    6.574    5.493
## chr10_ENSMUSG00000072837  -0.6324   -1.601    1.611
## chr10_ENSMUSG00000076282   2.6632    2.037    3.662
## chr10_ENSMUSG00000076377   3.9966    0.872    1.249
newer_data <- sm(normalize_expt(mmmi_small, filter=TRUE))
newer_data <- sm(normalize_expt(newer_data, batch="svaseq", low_to_zero=TRUE))
newer_data <- sm(normalize_expt(newer_data, transform="log2"))
plot_pca(newer_data)$plot

head(exprs(newer_data$expressionset))
##                          HPGL0673 HPGL0674 HPGL0675 HPGL0676 HPGL0677 HPGL0678 HPGL0679
## chr10_ENSMUSG00000065406  14.9122 14.97679 14.70103  16.4748   16.080   14.878  15.2253
## chr10_ENSMUSG00000065430  15.6170 14.74830 15.45856  17.9794   19.187   18.555  17.8190
## chr10_ENSMUSG00000065607   4.1440  3.63404  3.26691   6.1509    7.965    8.398   8.1909
## chr10_ENSMUSG00000072837   0.1169  0.04338  0.01136   0.2666    0.000    0.000   0.9651
## chr10_ENSMUSG00000076282   4.4091  3.69143  4.48934   5.8866    4.485    4.520   4.7684
## chr10_ENSMUSG00000076377   3.9625  3.39092  1.95152   3.2642    1.054    3.038   2.2624
##                          HPGL0680 HPGL0523 HPGL0524 HPGL0525 HPGL0555 HPGL0556 HPGL0557
## chr10_ENSMUSG00000065406  15.0695   12.616   8.0299   0.0000   13.177   15.704   12.893
## chr10_ENSMUSG00000065430  18.7755   10.237   0.0000   0.0000   13.856   16.658   14.626
## chr10_ENSMUSG00000065607   7.6941    3.095   5.0732   4.7389    0.000    7.413    6.290
## chr10_ENSMUSG00000072837   0.9356    1.050   0.1663   0.2612    0.000    0.000    0.000
## chr10_ENSMUSG00000076282   4.3184    2.637   0.0000   0.5565    4.156    3.609    3.561
## chr10_ENSMUSG00000076377   2.1567    2.543   0.0000   0.0000    2.358    2.004    2.145
##                          HPGL0558 HPGL0559 HPGL0560
## chr10_ENSMUSG00000065406    6.656  9.91391  11.5147
## chr10_ENSMUSG00000065430   13.427 15.11901  13.6559
## chr10_ENSMUSG00000065607    5.300  5.13317   0.1647
## chr10_ENSMUSG00000072837    1.022  0.05534   2.3040
## chr10_ENSMUSG00000076282    2.571  2.11567   3.9264
## chr10_ENSMUSG00000076377    2.699  0.00000   1.0219
old <- exprs(older_data$expressionset)
new <- exprs(newer_data$expressionset)
##mmmi_small_norm <- normalize_expt(mmmi_small, transform="log2", norm="quant", convert="cpm", batch="svaseq", filter=TRUE)
mmmi_small_norm <- sm(normalize_expt(mmmi_small, norm="quant", convert="cpm", batch="svaseq"))
mmmi_small_norm_metrics <- graph_metrics(mmmi_small_norm)
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## Graphing a boxplot.
## 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, setting them to 0.5.
## Changed 21087 zero count features.
## 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.
## Plotting a density plot.
## 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, setting them to 0.5.
## Changed 21087 zero count features.
## Printing a color to condition legend.

mmmi_small_norm_metrics$corheat

mmmi_small_norm_metrics$disheat

mmmi_small_norm_metrics$smc

mmmi_small_norm_metrics$pcaplot

mmmi_small_noapop <- subset_expt(mmmi_small, subset="genotype!='apop'")
mmmi_small_noapop_metrics <- graph_metrics(mmmi_small_noapop)
## Graphing number of non-zero genes with respect to CPM by library.
## Graphing library sizes.
## The scale difference between the smallest and largest
##    libraries is > 10. Assuming a log10 scale is better, set scale=FALSE if not.
## Graphing a boxplot.
## 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, setting them to 0.5.
## Changed 17300 zero count features.
## 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.
## Plotting a density plot.
## 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, setting them to 0.5.
## Changed 17300 zero count features.
## Printing a color to condition legend.

mmmi_small_noapop_metrics$pcaplot

mmmi_small_sva <- sm(normalize_expt(mmmi_small, transform="log2",
                                    norm="quant", convert="raw",
                                    filter=TRUE, batch="fsva"))
plot_pca(mmmi_small_sva)$plot

## The exosome and cell samples split nicely, and the wt/mutants split nicely among them!
## holy asscrackers that is nice!
## newer_data <- normalize_expt(mmmi_small, filter=TRUE, transform="log2", batch="svaseq", norm="quant")
printed_expt <- write_expt(mmmi_small, violin=TRUE,
                           excel=paste0("excel/mmmi_state_withapop-", ver, ".xlsx"),
                           filter=TRUE, transform="log2", norm="quant", convert="raw", batch="fsva")
## Writing the legend.
## The sheet: legend is in legend.
## Writing the raw reads.
## Graphing the raw reads.

## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 0.07 min
## 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.

## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 0.07 min
## 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 cell_mirna_apop has 3 rows.
## The factor cell_mirna_mut has 5 rows.
## The factor cell_mirna_wt has 2 rows.
## The factor exo_mirna_mut has 5 rows.
## The factor exo_mirna_wt has 2 rows.

It appears that the cellular mRNA samples are a little more problematic; shockingly to me at least, the problematic sample proved to be one of the cellular RNA samples and not an exosome sample! I almost can’t believe that. I think that, given this, I will try an sva/combat adjustment of the data and see what happens, if for nothing else, then to satisfy my curiosity.

tx_colors <- c("#AA0000", "#AA8888", "#0000AA", "#8888AA")
names(tx_colors) <- c("exo_polya_mut", "exo_polya_wt", "cell_polya_mut", "cell_polya_wt")
mmtx_new <- set_expt_colors(mmtx_large, colors=tx_colors)
##mmtx_new <- expt_subset(mmtx_new, subset="sampleid!='HPGL0688'")

mmtx_large_sva <- sm(normalize_expt(mmtx_new, transform="log2",
                                    norm="raw", convert="cpm",
                                    filter=TRUE, batch="fsva"))
plot_pca(mmtx_large_sva)$plot

printed_expt <- write_expt(mmtx_new, excel=paste0("excel/mmtx_state-", ver, ".xlsx"),
                           batch="fsva", norm="raw", convert="cpm", filter=TRUE, violin=TRUE)
## Writing the legend.
## The sheet: legend is in legend.
## Warning in max(nchar(as.character(data[[data_col]])), na.rm = TRUE): no non-missing
## arguments to max; returning -Inf
## Writing the raw reads.
## Graphing the raw reads.

## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 3 min
## 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.

## Attempting mixed linear model with: ~  (1|condition) + (1|batch)
## Fitting the expressionset to the model, this is slow.
## Projected run time: ~ 3 min
## 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 cell_polya_mut has 3 rows.
## The factor cell_polya_wt has 2 rows.
## The factor exo_polya_mut has 4 rows.
## The factor exo_polya_wt has 2 rows.

## wow, ummm, ok, so it appears that sva sees a significant surrogate variable.
mmtx_new_combat <- sm(normalize_expt(mmtx_new, transform="log2",
                                       norm="quant", convert="cpm",
                                       filter=TRUE, batch="combat_scale"))

plot_pca(mmtx_new_combat)$plot

## But according to this plot, the surrogate varaible is at least not entirely 'batch'
## oh wait, 98.62% of the remaining variance is now on the x-axis!

It appears that there is a significant but not crippling batch effect notable primarily in the large RNA libraries. I suspect that this will be sufficiently ameliorated by just adding batch into the experimental model.

index.html annotation.html

LS0tCnRpdGxlOiAiU2FtcGxlIEVzdGltYXRpb24gb2YgTS5tdXNjdWx1cyBzYW1wbGVzLiIKYXV0aG9yOiAiYXRiIGFiZWxld0BnbWFpbC5jb20iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogaHRtbF9kb2N1bWVudDoKICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgY29kZV9mb2xkaW5nOiBzaG93CiAgZmlnX2NhcHRpb246IHRydWUKICBmaWdfaGVpZ2h0OiA3CiAgZmlnX3dpZHRoOiA3CiAgaGlnaGxpZ2h0OiBkZWZhdWx0CiAga2VlcF9tZDogZmFsc2UKICBtb2RlOiBzZWxmY29udGFpbmVkCiAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgc2VsZl9jb250YWluZWQ6IHRydWUKICB0aGVtZTogcmVhZGFibGUKICB0b2M6IHRydWUKICB0b2NfZmxvYXQ6CiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCjxzdHlsZT4KICA8IS0tIERvY3VtZW50IHByZWx1ZGUgcmV2aXNpb24gMjAxNy0wMiAtLT4KICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICBtYXgtd2lkdGg6IDE2MDBweDsKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KIyMgVGhlc2UgYXJlIHRoZSBvcHRpb25zIEkgdGVuZCB0byBmYXZvcgpsaWJyYXJ5KCJocGdsdG9vbHMiKQp0dCA8LSBzbShkZXZ0b29sczo6bG9hZF9hbGwoIn4vaHBnbHRvb2xzIikpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KAogICAgcHJvZ3Jlc3MgPSBUUlVFLAogICAgdmVyYm9zZSA9IFRSVUUsCiAgICB3aWR0aCA9IDkwLAogICAgZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAgIGVycm9yID0gVFJVRSwKICAgIGZpZy53aWR0aCA9IDgsCiAgICBmaWcuaGVpZ2h0ID0gOCwKICAgIGRwaSA9IDk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKAogICAgZGlnaXRzID0gNCwKICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgIGtuaXRyLmR1cGxpY2F0ZS5sYWJlbCA9ICJhbGxvdyIpCnNldC5zZWVkKDEpCnByZXZpb3VzX2ZpbGUgPC0gImFubm90YXRpb24uUm1kIgpybWRfZmlsZSA8LSAic2FtcGxlX2VzdGltYXRpb24uUm1kIgp2ZXIgPC0gIjIwMTcwMjIwIgpwcmV2aW91c19zYXZlIDwtIHBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9Ii5yZGEueHoiLCB4PXByZXZpb3VzX2ZpbGUpKQp0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iLnJkYS54eiIsIHg9cm1kX2ZpbGUpKQpgYGAKCmBgYHtyIHJlbmRlcmluZywgaW5jbHVkZT1GQUxTRSwgZXZhbD1GQUxTRX0KIyMgVGhpcyBibG9jayBpcyB1c2VkIHRvIHJlbmRlciBhIGRvY3VtZW50IGZyb20gd2l0aGluIGl0LgpybWFya2Rvd246OnJlbmRlcihybWRfZmlsZSkKCiMjIEFuIGV4dHJhIHJlbmRlcmVyIGZvciBwZGYgb3V0cHV0cgptYXJrZG93bjo6cmVuZGVyKHJtZF9maWxlLCBvdXRwdXRfZm9ybWF0PSJwZGZfZG9jdW1lbnQiLCBvdXRwdXRfb3B0aW9ucz1jKCJza2lwX2h0bWwiKSkKIyMgT3IgdG8gc2F2ZS9sb2FkIGxhcmdlIFJkYXRhIGZpbGVzLgpocGdsdG9vbHM6OjpzYXZlbWUoKQpocGdsdG9vbHM6Ojpsb2FkbWUoKQpybShsaXN0PWxzKCkpCmBgYAoKYGBge3IgbG9hZG1lLCBpbmNsdWRlPUZBTFNFLCBldmFsPUZBTFNFfQp0bXAgPC0gc20obG9hZG1lKGZpbGVuYW1lPXByZXZpb3VzX3NhdmUpKQpgYGAKCkluIHRoaXMgZG9jdW1lbnQsIEkgd2lsbCBhdHRlbXB0IHRvIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgdmFyaW91cyBzYW1wbGVzIGluIHRoaXMKZXhwZXJpbWVudC4gIEluIHRoZSBwcm9jZXNzLCBJIHdpbGwgZXhhbWluZSB0aGUgc2FtcGxlcyB0byAoaG9wZWZ1bGx5KSBlbnN1cmUgdGhhdCB0aGV5IGFyZQpjb25zaXN0ZW50IGFuZCB0aGF0IHRoZXJlIGlzIG5vdCBhIGZhdGFsIGJhdGNoIGVmZmVjdCBvciBvdGhlciB3ZWFrbmVzcyBpbiB0aGUgZGF0YS4KClRvIHN0YXJ0LCBJIHdpbGwgcHJpbnQgc29tZSBzaW1wbGUgbWV0cmljcyBvZiB0aGUgZW50aXJlIGRhdGEgc2V0LCB0aGVuIHNwbGl0IGl0IGludG8gbW9yZSB0cmFjdGFibGUKcGllY2VzIGFuZCBleGFtaW5lIHRoZW0gbW9yZSB0aG9yb3VnaGx5LgoKIyBSYXcgZ2xvYmFsIG1ldHJpY3MKCldpdGggdGhlIGFib3ZlIGluIG1pbmQsIGhlcmUgYXJlIGEgY291cGxlIGdsb2JhbCBwbG90cyBzaG93aW5nIHRoZSBzdGF0ZSBvZiB0aGUgZGF0YS4KCiMjIG1pIHZzIHR4CgpXaGVuIHByb2Nlc3NpbmcgdGhlIGRhdGEsIEkgZGlkIDEgYWxpZ25tZW50IG9mIHRoZSByZWFkcyBmcm9tIGFsbCBzYW1wbGVzIGFnYWluc3QgYSBkYXRhYmFzZSBvZgptaVJOQXMgYW5kIHRoZW4gc2VwYXJhdGVseSBhZ2FpbnN0IGEgZGF0YWJhc2Ugb2YgYWxsIHRyYW5zY3JpcHRzLiAgQWxsIHRoZSBzYW1wbGVzIG9mIGxpYnJhcnkgdHlwZQonc21hbGwnIGFyZSByZWFsbHkgb25seSBpbnRlbmRlZCB0byBiZSBjb21wYXJlZCBhZ2FpbnN0IHRoZSBtaVJOQSBsaWJyYXJ5IHdoaWxlIHRob3NlIG9mIHR5cGUKJ2xhcmdlJyBhcmUgaW50ZW5kZWQgb25seSB0byBzZWFyY2ggYWdhaW5zdCB0aGUgdHJhbnNjcmlwdHMuICBUaGlzIGlzIHByaW1hcmlseSBiZWNhdXNlIG9mIHRoZQpkaWZmZXJlbnQgd2F5cyB0aGUgUk5BIHNhbXBsZXMgd2VyZSB0cmVhdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGxpYnJhcnkgcHJlcGFyYXRpb24uICBEZXNwaXRlCnRoaXMsIEkgcGVyZm9ybSBib3RoIHR5cGVzIG9mIGFsaWdubWVudHMgZm9yIGFsbCBzYW1wbGVzIHNvIHRoYXQgSSBtYXkgbm93IGxvb2sgYW5kIHNlZSB0aGF0IHRoZQpkaXN0cmlidXRpb25zIGFyZSBkaWZmZXJlbnQuICBJZiBldmVyeXRoaW5nIHdvcmtlZCBhcyBwbGFubmVkLCB0aGVuIHRoZSBsYXJnZSBSTkEgbGlicmFyaWVzIHNob3VsZApoYXZlIGEgdmVyeSBkaWZmZXJlbnQgZGlzdHJpYnV0aW9uIG9mIHJlYWRzIGluIHRoZSBtaVJOQSBkYXRhYmFzZXMgYW5kIHZpY2UtdmVyc2EuICBJZiB0aGlzIGlzIG5vdAp0cnVlLCB0aGVuIHNvbWV0aGluZyBtaWdodCBiZSB2ZXJ5IHdyb25nLgoKV2l0aCB0aGF0IGluIG1pbmQsIHRoZSBmb2xsb3dpbmcgYmxvY2sgaXMgZ29pbmcgdG8gZG8gc29tZSBvZiB0aGUgZ3JhcGhzIGFuZCBub3JtYWxpemUgdGhlIGRhdGEuICBJbgp0aGUgZm9sbG93aW5nIGJsb2NrcyBJIHdpbGwgcHJpbnQgc29tZSBvZiB0aGUgcmVzdWx0cyBhbmQgY29uc2lkZXIgd2hhdCB0aGV5IG1lYW4uCgpUaGUgZm9sbG93aW5nIGJsb2NrIHdpbGwgc2VydmUgdG8gZ2VuZXJhdGUgYWxsIHRoZSBsaWtlbHkgc3Vic2V0cyBvZiB0aGUgZGF0YS4KCkxldHMgbGF5IGRvd24gYSBjb3VwbGUgcnVsZXMgb2YgdGh1bWIgbm93OgoKMS4gIEluIGFsbCBmb2xsb3dpbmcgYW5hbHlzZXMsIGRvIHRoZSBtaVJOQSBmaXJzdCwgdGhlbiB0cmFuc2NyaXB0cy4KMi4gIEFsbCBtaVJOQSBkYXRhc2V0cyB3aWxsIHN0YXJ0IHdpdGggJ21tbWknIGFuZCB0cmFuc2NyaXB0cyB3aWxsIGJlICdtbXR4JwoKYGBge3IgYmFzZV9tZXRyaWNzLCBmaWcuc2hvdz0iaGlkZSJ9CiMjIEdyYXBoIHRoZSByYXcgbWV0cmljcyBvZiBhbGwgc2FtcGxlcyBtYXBwZWQgYWdhaW5zdCB0aGUgdHJhbnNjcmlwdHMgYW5kIG1pUk5BcwojI21tX21pciA8LSBleHB0X3N1YnNldChtbV9taXIsIHN1YnNldD0iZ2Vub3R5cGUhPSdhcG9wJyIpCiMjbW1fdHhyIDwtIGV4cHRfc3Vic2V0KG1tX3R4ciwgc3Vic2V0PSJnZW5vdHlwZSE9J2Fwb3AnIikKbW1fbWlfbWV0cmljcyA8LSBzbShncmFwaF9tZXRyaWNzKG1tX21pcikpCm1tX3R4X21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtbV90eHIpKQptbW1pX3NtYWxsX21ldHJpY3MgPC0gc20oZ3JhcGhfbWV0cmljcyhtbW1pX3NtYWxsKSkKbW10eF9sYXJnZV9tZXRyaWNzIDwtIHNtKGdyYXBoX21ldHJpY3MobW10eF9sYXJnZSkpCmBgYAoKIyMgQSBMZWdlbmQhCgpGaXJzdCwgZG8gbm90IGZvcmdldCB0byBwcmludCBhIGxlZ2VuZCBzaG93aW5nIHRoZSBjb2xvcnMgdXNlZCBhbmQgd2hhdCB0aGV5IG1lYW46CgpgYGB7ciBsZWdlbmR9Cm1tX21pX21ldHJpY3MkbGVnZW5kJHBsb3QKIyMgVGhpcyBzaG91bGQgYmUgdGhlIHNhbWUgZm9yIHRoZSBtbV9taSBhbmQgbW1fdHggb2JqZWN0cy4KYGBgCgojIyBTdGFydCB3aXRoIHNvbWUgZ2xvYmFsIG1ldHJpY3MKCmBgYHtyIGxpYnNpemVfbWl9Cm1tX21pX21ldHJpY3MkbGlic2l6ZQpgYGAKCkhhaGFoIEkgYW0gYSBkb29mdXMuICBGb3IgYSBtb21lbnQgSSB0aG91Z2h0IHRoaXMgd2FzIGEgdG90YWwgZGlzYXN0ZXIuClRoZSBmaXJzdCA4IGxpYnJhcmllcyBhcmUgc21hbGwgUk5BIGxpYnJhcmllcyBvZiB3aGljaCB0aGUgZmlyc3QgNCBhcmUgZXhvc29tZXMuClRoZSBpbXBvcnRhbnQgdGhpbmcgdG8gcmVtZW1iZXIgaXMgdGhhdCB0aGVzZSBhcmUgbWFwcGVkIGFnYWluc3Qgb25seSB0aGUgMTk3OCBtaVJOQSBmZWF0dXJlcyBpbgp0aGUgbW91c2UgRW5zZW1ibCBnZW5vbWUsIGFzIHN1Y2ggd2Ugc2VlIHRoYXQgdGhlIGZpcnN0IDQgYXJlIGhpZ2hseSBlbnJpY2hlZCBpbiBtaVJOQXMsIHdoaWNoIGlzCmV4Y2VsbGVudC4KClRoZXJlZm9yZSwgYXMgb25lIHdvdWxkIGV4cGVjdCwgdGhlIHNtYWxsIGV4b3NvbWUgUk5BIGxpYnJhcmllcyBoYXZlIGZld2VyIHJlYWRzIHRoYW4gdGhlIHRvdGFsCmNlbGwgc21hbGwgUk5BIGxpYnJhcmllcywgd2hpY2ggY29tcHJpc2UgdGhlIHNldCBmcm9tIDUtOC4KSSBvZiBjb3Vyc2UgZm9jdXNlZCBpbW1lZGlhdGVseSB1cG9uIHRoZSBsYXN0IDggd2l0aG91dCB0aGlua2luZy4gIFRoZXNlIGFyZSBhbGwgdGhlIHBvbHlBIFJOQQpzYW1wbGVzLCBvZiB3aGljaCB0aGUgbWlSTkEgZmVhdHVyZXMgYXJlIG9ubHkgYSBzbWFsbCBwcm9wb3J0aW9uIGFuZCB0aGVyZWZvcmUgd2Ugc2VlIHRoZW0gYXMKPDEwJSB0aGUgZGVwdGggb2YgdGhlIHNtYWxsIFJOQSBzYW1wbGVzLgpJIHdvdWxkIHRoZXJlZm9yZSBleHBlY3Qgc29tZXRoaW5nIGxpa2UgdGhlIG9wcG9zaXRlIGZvciB0aGUgdHJhbnNjcmlwdG9tZSBzYW1wbGVzLCB3aGljaCBhcmUgbmV4dC4KCmBgYHtyIGxpYnNpemVfdHh9Cm1tX3R4X21ldHJpY3MkbGlic2l6ZQpgYGAKCkFoaCBleGNlbGxlbnQuICBPbmNlIGFnYWluLCB0aGUgZXhvc29tZSBzYW1wbGVzIGhhdmUgZmV3ZXIgcmVhZHMgdGhhbiB0aGUgY2VsbHMgYW5kIGhhdmUgbWFueQpmZXdlciBmb3IgdGhlIHNtYWxsIFJOQSBzYW1wbGVzIHRoYW4gdHJhbnNjcmlwdCBzYW1wbGVzLCB3aGljaCBpcyBnb29kLgoKIyBTYW1wbGUgZGlzdHJpYnV0aW9ucwoKRnJvbSBoZXJlIG9uLCBJIHRoaW5rIEkgd2lsbCBleGFtaW5lIG9ubHkgdGhlIHNtYWxsIFJOQSBzYW1wbGVzIGFuZCBsYXJnZSBSTkEgc2FtcGxlcyBhcyAyIHNlcGFyYXRlCmdyb3Vwcy4KCmBgYHtyIGRlbnNpdGllc30KbW1taV9zbWFsbF9tZXRyaWNzJGRlbnNpdHkKbW1taV9zbWFsbF9tZXRyaWNzJGJveHBsb3QKIyMgVGhlIHNhbXBsZSBkZW5zaXRpZXMgYW1vbmcgdGhlIHNtYWxsIFJOQSBzYW1wbGVzIGxvb2sgcmVhc29uYWJsZSB0byBtZS4KbW10eF9sYXJnZV9tZXRyaWNzJGRlbnNpdHkKbW10eF9sYXJnZV9tZXRyaWNzJGJveHBsb3QKIyMgVGhpcyBpcyBtb3JlIHByb2JsZW1hdGljIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbnM7IGJ1dCBub3Qgc3VwcmlzaW5nIGFuZAojIyBlbmNvdXJhZ2luZyBmcm9tIGEgYmlvbG9naWNhbCBwZXJzcGVjdGl2ZS4gIFRoZSBsYXJnZSBSTkEgZXhvc29tZXMgaGF2ZSBtYW55IG1vcmUgZ2VuZXMgd2l0aCAwCiMjIGNvdW50cy4KYGBgCgpDb25zaWRlcmluZyB0aGUgaGV0ZXJvbG9nb3VzIHNvdXJjZXMgb2YgdGhlc2Ugc2FtcGxlcywgSSB0aGluayB0aGVzZSBhY3R1YWxseSBtYWtlIHNlbnNlLCBsZXRzIG1vdmUKb24gYW5kIHNlZSB3aGF0IGVsc2UgcG9wcyB1cC4KCgojIyBOb3JtYWxpemVkIE1ldHJpY3MKCiMjIyBTb21ldGhpbmcgaXMgbWVzc2VkIHVwCgpgYGB7ciB0ZXN0X3Byb2JsZW19CnR0IDwtIHNtKGxpYnJhcnkoQmlvYmFzZSkpCm9sZGVyX2RhdGEgPC0gc20obm9ybWFsaXplX2V4cHQobW1taV9zbWFsbCwgZmlsdGVyPSJjYmNiIiwgYmF0Y2g9InN2YXNlcSIsIHRyYW5zZm9ybT0ibG9nMiIsIGNvbnZlcnQ9ImNwbSIsIG5vcm09InF1YW50IikpCnR0IDwtIHJlYWQuY3N2KCJjdXJyZW50X25vcm1fY291bnRzLmNzdiIpCnJvd25hbWVzKHR0KSA8LSB0dCRyb3cubmFtZXNfMQp0dCA8LSB0dFssIC0xXQpjb2xuYW1lcyh0dCkgPC0gY29sbmFtZXMoZXhwcnMob2xkZXJfZGF0YSRleHByZXNzaW9uc2V0KSkKdHQgPC0gYXMubWF0cml4KHR0KQpleHBycyhvbGRlcl9kYXRhJGV4cHJlc3Npb25zZXQpIDwtIHR0CnBsb3RfcGNhKG9sZGVyX2RhdGEpJHBsb3QKCm5ld2VyX2RhdGEgPC0gc20obm9ybWFsaXplX2V4cHQobW1taV9zbWFsbCwgZmlsdGVyPVRSVUUpKQpuZXdlcl9kYXRhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ld2VyX2RhdGEsIHRyYW5zZm9ybT0ibG9nMiIpKQpuZXdlcl9kYXRhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ld2VyX2RhdGEsIGJhdGNoPSJzdmFzZXEiKSkKcGxvdF9wY2EobmV3ZXJfZGF0YSkkcGxvdApoZWFkKGV4cHJzKG5ld2VyX2RhdGEkZXhwcmVzc2lvbnNldCkpCgpuZXdlcl9kYXRhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1tbWlfc21hbGwsIGZpbHRlcj1UUlVFLCB0cmFuc2Zvcm09ImxvZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJzdmFzZXEiLCBub3JtPSJxdWFudCIpKQpwbG90X3BjYShuZXdlcl9kYXRhKSRwbG90CmhlYWQoZXhwcnMobmV3ZXJfZGF0YSRleHByZXNzaW9uc2V0KSkKCm5ld2VyX2RhdGEgPC0gc20obm9ybWFsaXplX2V4cHQobW1taV9zbWFsbCwgZmlsdGVyPVRSVUUpKQpuZXdlcl9kYXRhIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG5ld2VyX2RhdGEsIGJhdGNoPSJzdmFzZXEiLCBsb3dfdG9femVybz1UUlVFKSkKbmV3ZXJfZGF0YSA8LSBzbShub3JtYWxpemVfZXhwdChuZXdlcl9kYXRhLCB0cmFuc2Zvcm09ImxvZzIiKSkKcGxvdF9wY2EobmV3ZXJfZGF0YSkkcGxvdApoZWFkKGV4cHJzKG5ld2VyX2RhdGEkZXhwcmVzc2lvbnNldCkpCgpvbGQgPC0gZXhwcnMob2xkZXJfZGF0YSRleHByZXNzaW9uc2V0KQpuZXcgPC0gZXhwcnMobmV3ZXJfZGF0YSRleHByZXNzaW9uc2V0KQpgYGAKCmBgYHtyIHZpZXdfbm9ybV9tZXRyaWNzfQojI21tbWlfc21hbGxfbm9ybSA8LSBub3JtYWxpemVfZXhwdChtbW1pX3NtYWxsLCB0cmFuc2Zvcm09ImxvZzIiLCBub3JtPSJxdWFudCIsIGNvbnZlcnQ9ImNwbSIsIGJhdGNoPSJzdmFzZXEiLCBmaWx0ZXI9VFJVRSkKbW1taV9zbWFsbF9ub3JtIDwtIHNtKG5vcm1hbGl6ZV9leHB0KG1tbWlfc21hbGwsIG5vcm09InF1YW50IiwgY29udmVydD0iY3BtIiwgYmF0Y2g9InN2YXNlcSIpKQptbW1pX3NtYWxsX25vcm1fbWV0cmljcyA8LSBncmFwaF9tZXRyaWNzKG1tbWlfc21hbGxfbm9ybSkKbW1taV9zbWFsbF9ub3JtX21ldHJpY3MkY29yaGVhdAptbW1pX3NtYWxsX25vcm1fbWV0cmljcyRkaXNoZWF0Cm1tbWlfc21hbGxfbm9ybV9tZXRyaWNzJHNtYwptbW1pX3NtYWxsX25vcm1fbWV0cmljcyRwY2FwbG90CgptbW1pX3NtYWxsX25vYXBvcCA8LSBzdWJzZXRfZXhwdChtbW1pX3NtYWxsLCBzdWJzZXQ9Imdlbm90eXBlIT0nYXBvcCciKQptbW1pX3NtYWxsX25vYXBvcF9tZXRyaWNzIDwtIGdyYXBoX21ldHJpY3MobW1taV9zbWFsbF9ub2Fwb3ApCm1tbWlfc21hbGxfbm9hcG9wX21ldHJpY3MkcGNhcGxvdAoKbW1taV9zbWFsbF9zdmEgPC0gc20obm9ybWFsaXplX2V4cHQobW1taV9zbWFsbCwgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJyYXciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImZzdmEiKSkKcGxvdF9wY2EobW1taV9zbWFsbF9zdmEpJHBsb3QKIyMgVGhlIGV4b3NvbWUgYW5kIGNlbGwgc2FtcGxlcyBzcGxpdCBuaWNlbHksIGFuZCB0aGUgd3QvbXV0YW50cyBzcGxpdCBuaWNlbHkgYW1vbmcgdGhlbSEKIyMgaG9seSBhc3NjcmFja2VycyB0aGF0IGlzIG5pY2UhCiMjIG5ld2VyX2RhdGEgPC0gbm9ybWFsaXplX2V4cHQobW1taV9zbWFsbCwgZmlsdGVyPVRSVUUsIHRyYW5zZm9ybT0ibG9nMiIsIGJhdGNoPSJzdmFzZXEiLCBub3JtPSJxdWFudCIpCnByaW50ZWRfZXhwdCA8LSB3cml0ZV9leHB0KG1tbWlfc21hbGwsIHZpb2xpbj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICBleGNlbD1wYXN0ZTAoImV4Y2VsL21tbWlfc3RhdGVfd2l0aGFwb3AtIiwgdmVyLCAiLnhsc3giKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIHRyYW5zZm9ybT0ibG9nMiIsIG5vcm09InF1YW50IiwgY29udmVydD0icmF3IiwgYmF0Y2g9ImZzdmEiKQpgYGAKCkl0IGFwcGVhcnMgdGhhdCB0aGUgY2VsbHVsYXIgbVJOQSBzYW1wbGVzIGFyZSBhIGxpdHRsZSBtb3JlIHByb2JsZW1hdGljOyBzaG9ja2luZ2x5IHRvIG1lIGF0IGxlYXN0LAp0aGUgcHJvYmxlbWF0aWMgc2FtcGxlIHByb3ZlZCB0byBiZSBvbmUgb2YgdGhlIGNlbGx1bGFyIFJOQSBzYW1wbGVzIGFuZCBub3QgYW4gZXhvc29tZSBzYW1wbGUhICBJCmFsbW9zdCBjYW4ndCBiZWxpZXZlIHRoYXQuICBJIHRoaW5rIHRoYXQsIGdpdmVuIHRoaXMsIEkgd2lsbCB0cnkgYW4gc3ZhL2NvbWJhdCBhZGp1c3RtZW50IG9mIHRoZSBkYXRhIGFuZApzZWUgd2hhdCBoYXBwZW5zLCBpZiBmb3Igbm90aGluZyBlbHNlLCB0aGVuIHRvIHNhdGlzZnkgbXkgY3VyaW9zaXR5LgoKYGBge3Igc3ZhX3JuYX0KdHhfY29sb3JzIDwtIGMoIiNBQTAwMDAiLCAiI0FBODg4OCIsICIjMDAwMEFBIiwgIiM4ODg4QUEiKQpuYW1lcyh0eF9jb2xvcnMpIDwtIGMoImV4b19wb2x5YV9tdXQiLCAiZXhvX3BvbHlhX3d0IiwgImNlbGxfcG9seWFfbXV0IiwgImNlbGxfcG9seWFfd3QiKQptbXR4X25ldyA8LSBzZXRfZXhwdF9jb2xvcnMobW10eF9sYXJnZSwgY29sb3JzPXR4X2NvbG9ycykKIyNtbXR4X25ldyA8LSBleHB0X3N1YnNldChtbXR4X25ldywgc3Vic2V0PSJzYW1wbGVpZCE9J0hQR0wwNjg4JyIpCgptbXR4X2xhcmdlX3N2YSA8LSBzbShub3JtYWxpemVfZXhwdChtbXR4X25ldywgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icmF3IiwgY29udmVydD0iY3BtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyPVRSVUUsIGJhdGNoPSJmc3ZhIikpCnBsb3RfcGNhKG1tdHhfbGFyZ2Vfc3ZhKSRwbG90CgpwcmludGVkX2V4cHQgPC0gd3JpdGVfZXhwdChtbXR4X25ldywgZXhjZWw9cGFzdGUwKCJleGNlbC9tbXR4X3N0YXRlLSIsIHZlciwgIi54bHN4IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoPSJmc3ZhIiwgbm9ybT0icmF3IiwgY29udmVydD0iY3BtIiwgZmlsdGVyPVRSVUUsIHZpb2xpbj1UUlVFKQojIyB3b3csIHVtbW0sIG9rLCBzbyBpdCBhcHBlYXJzIHRoYXQgc3ZhIHNlZXMgYSBzaWduaWZpY2FudCBzdXJyb2dhdGUgdmFyaWFibGUuCm1tdHhfbmV3X2NvbWJhdCA8LSBzbShub3JtYWxpemVfZXhwdChtbXR4X25ldywgdHJhbnNmb3JtPSJsb2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybT0icXVhbnQiLCBjb252ZXJ0PSJjcG0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXI9VFJVRSwgYmF0Y2g9ImNvbWJhdF9zY2FsZSIpKQpwbG90X3BjYShtbXR4X25ld19jb21iYXQpJHBsb3QKIyMgQnV0IGFjY29yZGluZyB0byB0aGlzIHBsb3QsIHRoZSBzdXJyb2dhdGUgdmFyYWlibGUgaXMgYXQgbGVhc3Qgbm90IGVudGlyZWx5ICdiYXRjaCcKIyMgb2ggd2FpdCwgOTguNjIlIG9mIHRoZSByZW1haW5pbmcgdmFyaWFuY2UgaXMgbm93IG9uIHRoZSB4LWF4aXMhCmBgYAoKSXQgYXBwZWFycyB0aGF0IHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgYnV0IG5vdCBjcmlwcGxpbmcgYmF0Y2ggZWZmZWN0IG5vdGFibGUgcHJpbWFyaWx5IGluIHRoZSBsYXJnZQpSTkEgbGlicmFyaWVzLiAgSSBzdXNwZWN0IHRoYXQgdGhpcyB3aWxsIGJlIHN1ZmZpY2llbnRseSBhbWVsaW9yYXRlZCBieSBqdXN0IGFkZGluZyBiYXRjaCBpbnRvIHRoZQpleHBlcmltZW50YWwgbW9kZWwuCgpgYGB7ciBzYXZlX2VzdGltYXRpb24sIGluY2x1ZGU9RkFMU0V9CnRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKYGBgCgpbaW5kZXguaHRtbF0oaW5kZXguaHRtbCkgW2Fubm90YXRpb24uaHRtbF0oYW5ub3RhdGlvbi5odG1sKQo=