Dimensionality reduction

Paulo Czarnewski


Data preparation


First, let’s load all necessary libraries and the QC-filtered dataset from the previous step.


Z-score transformation

Now that the data is prepared, we now proceed with PCA. Since each gene has a different expression level, it means that genes with higher expression values will naturally have higher variation that will be captured by PCA. This means that we need to somehow give each gene a similar weight when performing PCA (see below). The common practice is to center and scale each gene before performing PCA. This exact scaling is called Z-score normalization it is very useful for PCA, clustering and plotting heatmaps. Additionally, we can use this function to remove any unwanted sources of variation from the dataset, such as cell cycle, sequencing depth, percent mitocondria. This is achieved by doing a generalized linear regression using these parameters as covariates in the model. Then the residuals of the model are taken as the “regressed data”. Although not in the best way, batch effect regression can also be done here.


PCA


Performing PCA has many useful applications and interpretations, which much depends on the data used. In the case of life sciences, we want to segregate samples based on gene expression patterns in the data.

As said above, we use the logcounts and then set scale_features to TRUE in order to scale each gene.

We can plot the first 6 dimensions like so.

To identify which genes (Seurat) or metadata paramters (Scater/Scran) contribute the most to each PC, one can retreive the loading matrix information. Unfortunatelly this is not implemented in Scater/Scran, so you will need to compute PCA using logcounts.

We can also plot the amount of variance explained by each PC.

Based on this plot, we can see that the top 10 PCs retain a lot of information, while other PCs contain pregressivelly less. However, it is still advisable to use more PCs since they might contain informaktion about rare cell types (such as platelets and DCs in this dataset)


tSNE


We can now run BH-tSNE.

We can now plot the tSNE colored per dataset. We can start now clearly see the effect of batches present in the dataset.


Using ScaledData and graphs for DR


Althought running a sencond dimmensionality reduction (i.e tSNE or UMAP) on PCA would be a standard approach (because it allows higher computation efficiency), the options are actually limiteless. Below we will show a couple of other common options such as running directly on the scaled data (which was used for PCA) or on a graph built from scaled data. We will show from now on only UMAP, but the same applies for tSNE.


### Using ScaledData for UMAP

To run tSNE or UMAP on the scaled data, one firts needs to select the number of variables to use. This is because including dimentions that do contribute to the separation of your cell types will in the end mask those differences. Another reason for it is because running with all genes/features also will take longer or might be computationally unfeasible. Therefore we will use the scaled data of the highly variable genes.

To run tSNE or UMAP on the a graph, we first need to build a graph from the data. In fact, both tSNE and UMAP first build a graph from the data using a specified distance metrix and then optimize the embedding. Since a graph is just a matrix containing distances from cell to cell and as such, you can run either UMAP or tSNE using any other distance metric desired. Euclidean and Correlation are ususally the most commonly used.


### Using a Graph for UMAP

Error in (function (X, n_neighbors = 15, n_components = 2, metric = "euclidean",  : 
  unused argument (dist = TRUE)

We can now plot the UMAP comparing both on PCA vs ScaledSata vs Graph.


Ploting genes of interest


Let’s plot some marker genes for different celltypes onto the embedding. Some genes are:

Markers Cell Type
CD3E T cells
CD3E CD4 CD4+ T cells
CD3E CD8A CD8+ T cells
GNLY, NKG7 NK cells
MS4A1 B cells
CD14, LYZ, CST3, MS4A7 CD14+ Monocytes
FCGR3A, LYZ, CST3, MS4A7 FCGR3A+ Monocytes
FCER1A, CST3 DCs

We can finally save the object for use in future steps.

LS0tCnRpdGxlOiAiU2NhdGVyL1NjcmFuOiBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24iCmF1dGhvcjogIsOFc2EgQmrDtnJrbHVuZCAgJiAgUGF1bG8gQ3phcm5ld3NraSIKZGF0ZTogIlNlcHQgMTMsIDIwMTkiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGtlZXBfbWQ6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogMwotLS0KCiMgRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uCgpQYXVsbyBDemFybmV3c2tpCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdD0naG9sZCcsZmlnLndpZHRoPTE2KQpgYGAKCjxici8+CgojIyBEYXRhIHByZXBhcmF0aW9uCioqKgoKRmlyc3QsIGxldCdzIGxvYWQgYWxsIG5lY2Vzc2FyeSBsaWJyYXJpZXMgYW5kIHRoZSBRQy1maWx0ZXJlZCBkYXRhc2V0IGZyb20gdGhlIHByZXZpb3VzIHN0ZXAuCgpgYGB7ciwgbWVzc2FnZT0naGlkZScsd2FybmluZz0naGlkZScscmVzdWx0cz0naG9sZCd9CnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKHNjYXRlcikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMocmVxdWlyZShzY3JhbikpKQpzdXBwcmVzc1dhcm5pbmdzKHN1cHByZXNzTWVzc2FnZXMocmVxdWlyZShjb3dwbG90KSkpCnN1cHByZXNzV2FybmluZ3Moc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGNvd3Bsb3QpKSkKc3VwcHJlc3NXYXJuaW5ncyhzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUoZ2dwbG90MikpKQoKc2NlIDwtIGxvYWRIREY1U3VtbWFyaXplZEV4cGVyaW1lbnQoIi4uL3Nlc3Npb24tcWMvZGF0YS9zZSIpCmBgYAoKPGJyLz4KCiMjIyBGZWF0dXJlIHNlbGVjdGlvbgoKTmV4dCwgd2UgZmlyc3QgbmVlZCB0byBkZWZpbmUgd2hpY2ggZmVhdHVyZXMvZ2VuZXMgYXJlIGltcG9ydGFudCBpbiBvdXIgZGF0YXNldCB0byBkaXN0aW5ndWlzaCBjZWxsIHR5cGVzLiBGb3IgdGhpcyBwdXJwb3NlLCB3ZSBuZWVkIHRvIGZpbmQgZ2VuZXMgdGhhdCBhcmUgaGlnaGx5IHZhcmlhYmxlIGFjcm9zcyBjZWxscywgd2hpY2ggaW4gdHVybiB3aWxsIGFsc28gcHJvdmlkZSBhIGdvb2Qgc2VwYXJhdGlvbiBvZiB0aGUgY2VsbCBjbHVzdGVycy4KCmBgYHtyfQp2YXIuZml0IDwtIHRyZW5kVmFyKHNjZSwgdXNlLnNwaWtlcz1GQUxTRSxtZXRob2Q9ImxvZXNzIixsb2Vzcy5hcmdzPWxpc3Qoc3Bhbj0wLjAyKSkKdmFyLm91dCA8LSBkZWNvbXBvc2VWYXIoc2NlLCB2YXIuZml0KQoKcGFyKG1mcm89YygxLDIpKQojcGxvdCBtZWFuIG92ZXIgVE9UQUwgdmFyaWFuY2UKcGxvdCh2YXIub3V0JG1lYW4sIHZhci5vdXQkdG90YWwsIHBjaD0xNiwgY2V4PTAuNCwgeGxhYj0iTWVhbiBsb2ctZXhwcmVzc2lvbiIsCiAgICAgeWxhYj0iVmFyaWFuY2Ugb2YgbG9nLWV4cHJlc3Npb24iKQpvIDwtIG9yZGVyKHZhci5vdXQkbWVhbikKbGluZXModmFyLm91dCRtZWFuW29dLCB2YXIub3V0JHRlY2hbb10sIGNvbD0iZG9kZ2VyYmx1ZSIsIGx3ZD0yKQoKY3V0b2ZmX3ZhbHVlIDwtIDAuMQpjdXRvZmYgPC0gdmFyLm91dCRiaW8gPiBjdXRvZmZfdmFsdWUKcG9pbnRzKHZhci5vdXQkbWVhbltjdXRvZmZdLCB2YXIub3V0JHRvdGFsW2N1dG9mZl0sIGNvbD0icmVkIiwgcGNoPTE2LGNleD0uNikKCiNwbG90IG1lYW4gb3ZlciBCSU9MT0dJQ0FMIHZhcmlhbmNlCnBsb3QodmFyLm91dCRtZWFuLCB2YXIub3V0JGJpbywgcGNoPTE2LCBjZXg9MC40LCB4bGFiPSJNZWFuIGxvZy1leHByZXNzaW9uIiwKICAgICB5bGFiPSJWYXJpYW5jZSBvZiBsb2ctZXhwcmVzc2lvbiIpCmxpbmVzKGMobWluKHZhci5vdXQkbWVhbiksbWF4KHZhci5vdXQkbWVhbikpLCBjKDAsMCksIGNvbD0iZG9kZ2VyYmx1ZSIsIGx3ZD0yKQpwb2ludHModmFyLm91dCRtZWFuW2N1dG9mZl0sIHZhci5vdXQkYmlvW2N1dG9mZl0sIGNvbD0icmVkIiwgcGNoPTE2LGNleD0uNikKCmh2Zy5vdXQgPC0gdmFyLm91dFt3aGljaCh2YXIub3V0JEZEUiA8PSAwLjA1ICYgdmFyLm91dCRiaW8gPj0gY3V0b2ZmX3ZhbHVlKSxdCmh2Zy5vdXQgPC0gaHZnLm91dFtvcmRlcihodmcub3V0JGJpbywgZGVjcmVhc2luZz1UUlVFKSxdCmBgYAoKPGJyLz4KCiMjIyBaLXNjb3JlIHRyYW5zZm9ybWF0aW9uCgpOb3cgdGhhdCB0aGUgZGF0YSBpcyBwcmVwYXJlZCwgd2Ugbm93IHByb2NlZWQgd2l0aCBQQ0EuIFNpbmNlIGVhY2ggZ2VuZSBoYXMgYSBkaWZmZXJlbnQgZXhwcmVzc2lvbiBsZXZlbCwgaXQgbWVhbnMgdGhhdCBnZW5lcyB3aXRoIGhpZ2hlciBleHByZXNzaW9uIHZhbHVlcyB3aWxsIG5hdHVyYWxseSBoYXZlIGhpZ2hlciB2YXJpYXRpb24gdGhhdCB3aWxsIGJlIGNhcHR1cmVkIGJ5IFBDQS4gVGhpcyBtZWFucyB0aGF0IHdlIG5lZWQgdG8gc29tZWhvdyBnaXZlIGVhY2ggZ2VuZSBhIHNpbWlsYXIgd2VpZ2h0IHdoZW4gcGVyZm9ybWluZyBQQ0EgKHNlZSBiZWxvdykuIFRoZSBjb21tb24gcHJhY3RpY2UgaXMgdG8gY2VudGVyIGFuZCBzY2FsZSBlYWNoIGdlbmUgYmVmb3JlIHBlcmZvcm1pbmcgUENBLiBUaGlzIGV4YWN0IHNjYWxpbmcgaXMgY2FsbGVkIFotc2NvcmUgbm9ybWFsaXphdGlvbiBpdCBpcyB2ZXJ5IHVzZWZ1bCBmb3IgUENBLCBjbHVzdGVyaW5nIGFuZCBwbG90dGluZyBoZWF0bWFwcy4gQWRkaXRpb25hbGx5LCB3ZSBjYW4gdXNlIHRoaXMgZnVuY3Rpb24gdG8gcmVtb3ZlIGFueSB1bndhbnRlZCBzb3VyY2VzIG9mIHZhcmlhdGlvbiBmcm9tIHRoZSBkYXRhc2V0LCBzdWNoIGFzIGBjZWxsIGN5Y2xlYCwgYHNlcXVlbmNpbmcgZGVwdGhgLCBgcGVyY2VudCBtaXRvY29uZHJpYWAuIFRoaXMgaXMgYWNoaWV2ZWQgYnkgZG9pbmcgYSBnZW5lcmFsaXplZCBsaW5lYXIgcmVncmVzc2lvbiB1c2luZyB0aGVzZSBwYXJhbWV0ZXJzIGFzIGNvdmFyaWF0ZXMgaW4gdGhlIG1vZGVsLiBUaGVuIHRoZSByZXNpZHVhbHMgb2YgdGhlIG1vZGVsIGFyZSB0YWtlbiBhcyB0aGUgInJlZ3Jlc3NlZCBkYXRhIi4gQWx0aG91Z2ggbm90IGluIHRoZSBiZXN0IHdheSwgYmF0Y2ggZWZmZWN0IHJlZ3Jlc3Npb24gY2FuIGFsc28gYmUgZG9uZSBoZXJlLgoKYGBge3J9CiMgc2NlQGFzc2F5cyRkYXRhQGxpc3REYXRhJHNjYWxlZC5kYXRhIDwtIGFwcGx5KGV4cHJzKHNjZSlbcm93bmFtZXMoaHZnLm91dCksLGRyb3A9RkFMU0VdLDIsZnVuY3Rpb24oeCkgc2NhbGUoeCxULFQpKQojIHJvd25hbWVzKHNjZUBhc3NheXMkZGF0YUBsaXN0RGF0YSRzY2FsZWQuZGF0YSkgPC0gcm93bmFtZXMoaHZnLm91dCkKYGBgCgoKPGJyLz4KCiMjIFBDQQoqKioKClBlcmZvcm1pbmcgUENBIGhhcyBtYW55IHVzZWZ1bCBhcHBsaWNhdGlvbnMgYW5kIGludGVycHJldGF0aW9ucywgd2hpY2ggbXVjaCBkZXBlbmRzIG9uIHRoZSBkYXRhIHVzZWQuIEluIHRoZSBjYXNlIG9mIGxpZmUgc2NpZW5jZXMsIHdlIHdhbnQgdG8gc2VncmVnYXRlIHNhbXBsZXMgYmFzZWQgb24gZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIGluIHRoZSBkYXRhLgoKQXMgc2FpZCBhYm92ZSwgd2UgdXNlIHRoZSBgbG9nY291bnRzYCBhbmQgdGhlbiBzZXQgYHNjYWxlX2ZlYXR1cmVzYCB0byBUUlVFIGluIG9yZGVyIHRvIHNjYWxlIGVhY2ggZ2VuZS4KCmBgYHtyfQojRGVmYXVsdCBTY2F0ZXIgd2F5CnNjZSA8LSBydW5QQ0Eoc2NlLCBleHByc192YWx1ZXMgPSAibG9nY291bnRzIiwgIHNjYWxlX2ZlYXR1cmVzID0gVCwKICAgICAgICAgICAgICBuY29tcG9uZW50cyA9IDMwLCBmZWF0dXJlX3NldCA9IHJvd25hbWVzKGh2Zy5vdXQpLG1ldGhvZCA9ICJwcmNvbXAiKQoKI0ZvciBzb21lIHJlYXNvbiBTY2F0ZXIgcmVtb3ZlcyB0aGUgZGltbmFtZXMgb2YgImxvZ2NvdW50cyIgYWZ0ZXIgUENBLCBzbyB3ZSBwdXQgaXQgYmFjawpkaW1uYW1lcyhzY2VAYXNzYXlzJGRhdGFAbGlzdERhdGEkbG9nY291bnRzKSA8LSBkaW1uYW1lcyhzY2VAYXNzYXlzJGRhdGFAbGlzdERhdGEkY291bnRzKQoKIzJuZCB3YXk6CiNzY2UgPC0gcnVuUENBKHNjZSwgZXhwcnNfdmFsdWVzID0gInNjYWxlZC5kYXRhIiwgc2NhbGVfZmVhdHVyZXMgPSBGQUxTRSwKIyAgICAgICAgICAgICAgbmNvbXBvbmVudHMgPSAzMCwgZmVhdHVyZV9zZXQgPSByb3duYW1lcyhodmcub3V0KSApCgpgYGAKCldlIGNhbiBwbG90IHRoZSBmaXJzdCA2IGRpbWVuc2lvbnMgbGlrZSBzby4KCmBgYHtyLCBmaWcuYXNwPS4yOH0KcGxvdF9ncmlkKG5jb2wgPSAzLAogIHBsb3RSZWR1Y2VkRGltKHNjZSx1c2VfZGltcmVkID0gIlBDQSIsY29sb3VyX2J5ID0gIkNoZW1pc3RyeSIsbmNvbXBvbmVudHMgPSAxOjIpLAogIHBsb3RSZWR1Y2VkRGltKHNjZSx1c2VfZGltcmVkID0gIlBDQSIsY29sb3VyX2J5ID0gIkNoZW1pc3RyeSIsbmNvbXBvbmVudHMgPSAzOjQpLAogIHBsb3RSZWR1Y2VkRGltKHNjZSx1c2VfZGltcmVkID0gIlBDQSIsY29sb3VyX2J5ID0gIkNoZW1pc3RyeSIsbmNvbXBvbmVudHMgPSA1OjYpICkKCmBgYAoKVG8gaWRlbnRpZnkgd2hpY2ggZ2VuZXMgKFNldXJhdCkgb3IgbWV0YWRhdGEgcGFyYW10ZXJzIChTY2F0ZXIvU2NyYW4pIGNvbnRyaWJ1dGUgdGhlIG1vc3QgdG8gZWFjaCBQQywgb25lIGNhbiByZXRyZWl2ZSB0aGUgbG9hZGluZyBtYXRyaXggaW5mb3JtYXRpb24uIFVuZm9ydHVuYXRlbGx5IHRoaXMgaXMgbm90IGltcGxlbWVudGVkIGluIFNjYXRlci9TY3Jhbiwgc28geW91IHdpbGwgbmVlZCB0byBjb21wdXRlIFBDQSB1c2luZyBgbG9nY291bnRzYC4KCmBgYHtyLGZpZy5hc3A9LjR9CiNUaGlzIHN0ZXAgdGFrZXMgc29tZSB0aW1lLCB5b3UgbWF5IHNraXAgaXQgZm9yIG5vdyBhbmQgcnVuIGl0IGxhdGVyLgojcGxvdF9ncmlkKG5jb2wgPSAyLCBwbG90RXhwbGFuYXRvcnlQQ3Moc2NlKSkKYGBgCgpXZSBjYW4gYWxzbyBwbG90IHRoZSBhbW91bnQgb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggUEMuCgpgYGB7cixmaWcuYXNwPS40fQpwYXIobWZyb3c9YygxLDIpKQpwbG90KGF0dHIoc2NlQHJlZHVjZWREaW1zJFBDQSwicGVyY2VudFZhciIpWzE6MzBdKjEwMCx0eXBlPSJsIix5bGFiPSIlIHZhcmlhbmNlIix4bGFiPSJQcmluY2lwYWwgY29tcG9uZW50ICMiKQpwb2ludHMoYXR0cihzY2VAcmVkdWNlZERpbXMkUENBLCJwZXJjZW50VmFyIilbMTozMF0qMTAwLHBjaD0yMSxiZz0iZ3JleSIsY2V4PS41KQpgYGAKCkJhc2VkIG9uIHRoaXMgcGxvdCwgd2UgY2FuIHNlZSB0aGF0IHRoZSB0b3AgMTAgUENzIHJldGFpbiBhIGxvdCBvZiBpbmZvcm1hdGlvbiwgd2hpbGUgb3RoZXIgUENzIGNvbnRhaW4gcHJlZ3Jlc3NpdmVsbHkgbGVzcy4gSG93ZXZlciwgaXQgaXMgc3RpbGwgYWR2aXNhYmxlIHRvIHVzZSBtb3JlIFBDcyBzaW5jZSB0aGV5IG1pZ2h0IGNvbnRhaW4gaW5mb3JtYWt0aW9uIGFib3V0IHJhcmUgY2VsbCB0eXBlcyAoc3VjaCBhcyBwbGF0ZWxldHMgYW5kIERDcyBpbiB0aGlzIGRhdGFzZXQpCgo8YnIvPgoKIyMgdFNORQoqKioKCldlIGNhbiBub3cgcnVuIFtCSC10U05FXShodHRwczovL2FyeGl2Lm9yZy9hYnMvMTMwMS4zMzQyKS4KCmBgYHtyLCBmaWcuYXNwPTF9CnNldC5zZWVkKDQyKQpzY2UgPC0gcnVuVFNORShzY2UsIHVzZV9kaW1yZWQgPSAiUENBIiwgbl9kaW1yZWQgPSAzMCwgCiAgICAgICAgICAgICAgIHBlcnBsZXhpdHkgPSAzMCkKI3NlZSA/UnRzbmUgYW5kID9ydW5UU05FIGZvciBtb3JlIGluZm8KYGBgCgpXZSBjYW4gbm93IHBsb3QgdGhlIHRTTkUgY29sb3JlZCBwZXIgZGF0YXNldC4gV2UgY2FuIHN0YXJ0IG5vdyBjbGVhcmx5IHNlZSB0aGUgZWZmZWN0IG9mIGJhdGNoZXMgcHJlc2VudCBpbiB0aGUgZGF0YXNldC4KCmBgYHtyLGZpZy5hc3A9LjI4fQpwbG90X2dyaWQobmNvbCA9IDMscGxvdFJlZHVjZWREaW0oc2NlLHVzZV9kaW1yZWQgPSAiVFNORSIsY29sb3VyX2J5ID0gIkNoZW1pc3RyeSIpKQpgYGAKCgo8YnIvPgoKIyMgVU1BUAoqKioKCldlIGNhbiBub3cgcnVuIFtVTUFQXShodHRwczovL2FyeGl2Lm9yZy9hYnMvMTgwMi4wMzQyNikuCgpgYGB7cn0Kc2NlIDwtIHJ1blVNQVAoc2NlLHVzZV9kaW1yZWQgPSAiUENBIiwgbl9kaW1yZWQgPSAzMCwgICBuY29tcG9uZW50cyA9IDIpCgojV2UgbmVlZCB0byByZW5hbWUgaXQgdG8gbm90IG92ZXJpZGUgd2l0aCBvdGhlciBVTUFQIGNvbXB1dGF0aW9ucwp0cnkoc2NlQHJlZHVjZWREaW1zJFVNQVBfb25fUk5BIDwtIE5VTEwpCnJlZHVjZWREaW1OYW1lcyhzY2UpW3JlZHVjZWREaW1OYW1lcyhzY2UpPT0iVU1BUCJdIDwtICJVTUFQX29uX1JOQSIKI3NlZSA/dW1hcCBhbmQgP3J1blVNQVAgZm9yIG1vcmUgaW5mbwpgYGAKCkFub3RoZXIgdXNlZnVsbG5lc3Mgb2YgVU1BUCBpcyB0aGF0IGl0IGlzIG5vdCBsaW1pdHRlZCBieSB0aGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMgdGhlIGRhdGEgY2FuIGJlIHJlZHVjZWQgaW50byAodW5saWtlIHRTTkUpLiBXZSBjYW4gc2ltcGx5IHJlZHVjZSB0aGUgZGltZW50aW9ucyBhbHRlcmluZyB0aGUgYG4uY29tcG9uZW50c2AgcGFyYW1ldGVyLgoKYGBge3J9CnNjZSA8LSBydW5VTUFQKHNjZSx1c2VfZGltcmVkID0gIlBDQSIsIG5fZGltcmVkID0gMzAsICAgbmNvbXBvbmVudHMgPSAxMCkKI3NlZSA/dW1hcCBhbmQgP3J1blVNQVAgZm9yIG1vcmUgaW5mbwoKI1dlIG5lZWQgdG8gcmVuYW1lIGl0IHRvIG5vdCBvdmVyaWRlIHdpdGggb3RoZXIgVU1BUCBjb21wdXRhdGlvbnMKdHJ5KHNjZUByZWR1Y2VkRGltcyRVTUFQMTBfb25fUk5BIDwtIE5VTEwpCnJlZHVjZWREaW1OYW1lcyhzY2UpW3JlZHVjZWREaW1OYW1lcyhzY2UpPT0iVU1BUCJdIDwtICJVTUFQMTBfb25fUk5BIgpgYGAKCldlIGNhbiBub3cgcGxvdCB0aGUgVU1BUCBjb2xvcmVkIHBlciBkYXRhc2V0LiBBbHRob3VnaCBsZXNzIGRpc3RpbmN0IGFzIGluIHRoZSB0U05FLCB3ZSBzdGlsbCBzZWUgcXVpdGUgYW4gZWZmZWN0IG9mIHRoZSBkaWZmZXJlbnQgYmF0Y2hlcyBpbiB0aGUgZGF0YS4KCmBgYHtyLGZpZy5hc3A9LjI4fQpwbG90X2dyaWQobmNvbCA9IDMsCiAgICAgICAgICBwbG90UmVkdWNlZERpbShzY2UsdXNlX2RpbXJlZCA9ICJVTUFQX29uX1JOQSIsY29sb3VyX2J5ID0gIkNoZW1pc3RyeSIpKyBnZ3Bsb3QyOjpnZ3RpdGxlKGxhYmVsID0iVU1BUF9vbl9STkEiKSwKICAgICAgICAgIHBsb3RSZWR1Y2VkRGltKHNjZSx1c2VfZGltcmVkID0gIlVNQVAxMF9vbl9STkEiLGNvbG91cl9ieSA9ICJDaGVtaXN0cnkiLG5jb21wb25lbnRzID0gMToyKSsgZ2dwbG90Mjo6Z2d0aXRsZShsYWJlbCA9IlVNQVAxMF9vbl9STkEiKSwKICAgICAgICAgIHBsb3RSZWR1Y2VkRGltKHNjZSx1c2VfZGltcmVkID0gIlVNQVAxMF9vbl9STkEiLGNvbG91cl9ieSA9ICJDaGVtaXN0cnkiLG5jb21wb25lbnRzID0gMzo0KSsgZ2dwbG90Mjo6Z2d0aXRsZShsYWJlbCA9IlVNQVAxMF9vbl9STkEiKQopCmBgYAoKCjxici8+CgojIyBVc2luZyBTY2FsZWREYXRhIGFuZCBncmFwaHMgZm9yIERSCioqKgoKQWx0aG91Z2h0IHJ1bm5pbmcgYSBzZW5jb25kIGRpbW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gKGkuZSB0U05FIG9yIFVNQVApIG9uIFBDQSB3b3VsZCBiZSBhIHN0YW5kYXJkIGFwcHJvYWNoIChiZWNhdXNlIGl0IGFsbG93cyBoaWdoZXIgY29tcHV0YXRpb24gZWZmaWNpZW5jeSksIHRoZSBvcHRpb25zIGFyZSBhY3R1YWxseSBsaW1pdGVsZXNzLiBCZWxvdyB3ZSB3aWxsIHNob3cgYSBjb3VwbGUgb2Ygb3RoZXIgY29tbW9uIG9wdGlvbnMgc3VjaCBhcyBydW5uaW5nIGRpcmVjdGx5IG9uIHRoZSBzY2FsZWQgZGF0YSAod2hpY2ggd2FzIHVzZWQgZm9yIFBDQSkgb3Igb24gYSBncmFwaCBidWlsdCBmcm9tIHNjYWxlZCBkYXRhLiBXZSB3aWxsIHNob3cgZnJvbSBub3cgb24gb25seSBVTUFQLCBidXQgdGhlIHNhbWUgYXBwbGllcyBmb3IgdFNORS4KCjxici8+CiMjIyBVc2luZyBTY2FsZWREYXRhIGZvciBVTUFQCgpUbyBydW4gdFNORSBvciBVTUFQIG9uIHRoZSBzY2FsZWQgZGF0YSwgb25lIGZpcnRzIG5lZWRzIHRvIHNlbGVjdCB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byB1c2UuIFRoaXMgaXMgYmVjYXVzZSBpbmNsdWRpbmcgZGltZW50aW9ucyB0aGF0IGRvIGNvbnRyaWJ1dGUgdG8gdGhlIHNlcGFyYXRpb24gb2YgeW91ciBjZWxsIHR5cGVzIHdpbGwgaW4gdGhlIGVuZCBtYXNrIHRob3NlIGRpZmZlcmVuY2VzLiBBbm90aGVyIHJlYXNvbiBmb3IgaXQgaXMgYmVjYXVzZSBydW5uaW5nIHdpdGggYWxsIGdlbmVzL2ZlYXR1cmVzIGFsc28gd2lsbCB0YWtlIGxvbmdlciBvciBtaWdodCBiZSBjb21wdXRhdGlvbmFsbHkgdW5mZWFzaWJsZS4gVGhlcmVmb3JlIHdlIHdpbGwgdXNlIHRoZSBzY2FsZWQgZGF0YSBvZiB0aGUgaGlnaGx5IHZhcmlhYmxlIGdlbmVzLgoKYGBge3IsZmlnLmFzcD0uMjh9CnNjZSA8LSBydW5VTUFQKHNjZSwgZXhwcnNfdmFsdWVzPSdsb2djb3VudHMnLCBmZWF0dXJlX3NldCA9IHJvd25hbWVzKGh2Zy5vdXQpKQoKI1dlIG5lZWQgdG8gcmVuYW1lIGl0IHRvIG5vdCBvdmVyaWRlIHdpdGggb3RoZXIgVU1BUCBjb21wdXRhdGlvbnMKdHJ5KHNjZUByZWR1Y2VkRGltcyRVTUFQX29uX1NjYWxlRGF0YSA8LSBOVUxMKQpyZWR1Y2VkRGltTmFtZXMoc2NlKVtyZWR1Y2VkRGltTmFtZXMoc2NlKT09IlVNQVAiXSA8LSAiVU1BUF9vbl9TY2FsZURhdGEiCmBgYAoKVG8gcnVuIHRTTkUgb3IgVU1BUCBvbiB0aGUgYSBncmFwaCwgd2UgZmlyc3QgbmVlZCB0byBidWlsZCBhIGdyYXBoIGZyb20gdGhlIGRhdGEuIEluIGZhY3QsIGJvdGggdFNORSBhbmQgVU1BUCBmaXJzdCBidWlsZCBhIGdyYXBoIGZyb20gdGhlIGRhdGEgdXNpbmcgYSBzcGVjaWZpZWQgZGlzdGFuY2UgbWV0cml4IGFuZCB0aGVuIG9wdGltaXplIHRoZSBlbWJlZGRpbmcuIFNpbmNlIGEgZ3JhcGggaXMganVzdCBhIG1hdHJpeCBjb250YWluaW5nIGRpc3RhbmNlcyBmcm9tIGNlbGwgdG8gY2VsbCBhbmQgYXMgc3VjaCwgeW91IGNhbiBydW4gZWl0aGVyIFVNQVAgb3IgdFNORSB1c2luZyBhbnkgb3RoZXIgZGlzdGFuY2UgbWV0cmljIGRlc2lyZWQuIEV1Y2xpZGVhbiBhbmQgQ29ycmVsYXRpb24gYXJlIHVzdXNhbGx5IHRoZSBtb3N0IGNvbW1vbmx5IHVzZWQuCgo8YnIvPgojIyMgVXNpbmcgYSBHcmFwaCBmb3IgVU1BUAoKYGBge3IsZmlnLmFzcD0uMjh9CiNCdWlsZCBHcmFwaApnIDwtIGJ1aWxkS05OR3JhcGgoc2NlLGs9MzAsdXNlLmRpbXJlZD0iUENBIixhc3NheS50eXBlPSJSTkEiKQpzY2VAcmVkdWNlZERpbXMkS05OIDwtIGlncmFwaDo6YXNfYWRqYWNlbmN5X21hdHJpeChnKQoKCiNSdW4gVU1BUCBhbmQgcmVuYW1lIGl0IGZvciBjb21wYXJpc3NvbgpzY2UgPC0gcnVuVU1BUChzY2UsdXNlX2RpbXJlZCA9ICJLTk4iLCBuY29tcG9uZW50cyA9IDIpCnRyeShzY2VAcmVkdWNlZERpbXMkVU1BUF9vbl9HcmFwaCA8LSBOVUxMKQpyZWR1Y2VkRGltTmFtZXMoc2NlKVtyZWR1Y2VkRGltTmFtZXMoc2NlKT09IlVNQVAiXSA8LSAiVU1BUF9vbl9HcmFwaCIKYGBgCgoKV2UgY2FuIG5vdyBwbG90IHRoZSBVTUFQIGNvbXBhcmluZyBib3RoIG9uIFBDQSB2cyBTY2FsZWRTYXRhIHZzIEdyYXBoLgoKYGBge3IsZmlnLmFzcD0uMjh9CnBsb3RfZ3JpZChuY29sID0gMywKICBwbG90UmVkdWNlZERpbShzY2UsIHVzZV9kaW1yZWQgPSAiVU1BUF9vbl9STkEiLCBjb2xvdXJfYnkgPSAiQ2hlbWlzdHJ5IikrIGdncGxvdDI6OmdndGl0bGUobGFiZWwgPSJVTUFQX29uX1JOQSIpLAogIHBsb3RSZWR1Y2VkRGltKHNjZSwgdXNlX2RpbXJlZCA9ICJVTUFQX29uX1NjYWxlRGF0YSIsIGNvbG91cl9ieSA9ICJDaGVtaXN0cnkiKSsgZ2dwbG90Mjo6Z2d0aXRsZShsYWJlbCA9IlVNQVBfb25fU2NhbGVEYXRhIiksCiAgcGxvdFJlZHVjZWREaW0oc2NlLCB1c2VfZGltcmVkID0gIlVNQVBfb25fR3JhcGgiLCBjb2xvdXJfYnkgPSAiQ2hlbWlzdHJ5IikrIGdncGxvdDI6OmdndGl0bGUobGFiZWwgPSJVTUFQX29uX0dyYXBoIikKKQpgYGAKCjxici8+CgojIyBQbG90aW5nIGdlbmVzIG9mIGludGVyZXN0CioqKgoKCkxldCdzIHBsb3Qgc29tZSBtYXJrZXIgZ2VuZXMgZm9yIGRpZmZlcmVudCBjZWxsdHlwZXMgb250byB0aGUgZW1iZWRkaW5nLiBTb21lIGdlbmVzIGFyZToKCk1hcmtlcnMJfCBDZWxsIFR5cGUKLS0tIHwgLS0tCkNEM0UJfCBUIGNlbGxzCkNEM0UgQ0Q0CXwgQ0Q0KyBUIGNlbGxzCkNEM0UgQ0Q4QQl8IENEOCsgVCBjZWxscwpHTkxZLCBOS0c3CXwgTksgY2VsbHMKTVM0QTEJfCBCIGNlbGxzCkNEMTQsIExZWiwgQ1NUMywgTVM0QTcJfCBDRDE0KyBNb25vY3l0ZXMKRkNHUjNBLCBMWVosIENTVDMsIE1TNEE3CXwgRkNHUjNBKyAgTW9ub2N5dGVzCkZDRVIxQSwgQ1NUMyB8IERDcwoKYGBge3IsZmlnLmFzcD0uOX0KcGxvdGxpc3QgPC0gbGlzdCgpCmZvcihpIGluIGMoIkNEM0UiLCJDRDQiLCJDRDhBIiwiTktHNyIsIkdOTFkiLCJNUzRBMSIsIkNEMTQiLCJMWVoiLCJNUzRBNyIsIkZDR1IzQSIsIkNTVDMiLCJGQ0VSMUEiKSl7CiAgcGxvdGxpc3RbW2ldXSA8LSBwbG90UmVkdWNlZERpbShzY2UsdXNlX2RpbXJlZCA9ICJVTUFQX29uX1JOQSIsY29sb3VyX2J5ID0gaSxieV9leHByc192YWx1ZXMgPSAibG9nY291bnRzIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnMgPSBjb2xvclJhbXBQYWxldHRlKGMoImdyZXk5MCIsIm9yYW5nZTMiLCJmaXJlYnJpY2siLCJmaXJlYnJpY2siLCJyZWQiLCJyZWQiLCJyZWQiLCJyZWQiICkpKDEwKSkgKwogIGdndGl0bGUobGFiZWwgPSBpKSsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkgfQpwbG90X2dyaWQobmNvbD0zLCBwbG90bGlzdCA9IHBsb3RsaXN0KQoKCmBgYAoKCldlIGNhbiBmaW5hbGx5IHNhdmUgdGhlIG9iamVjdCBmb3IgdXNlIGluIGZ1dHVyZSBzdGVwcy4KCmBgYHtyfQpzYXZlSERGNVN1bW1hcml6ZWRFeHBlcmltZW50KHNjZSwgZGlyPSJkYXRhL3NlIiwgcmVwbGFjZSA9IFRSVUUpCmBgYAoKCgoKCgoKCgoKCgoKCgoKCgo=