Introduction
The following workflow was used to analyze the CITE-seq data and generate the CITE-seq related figures for our paper “Broad immune activation underlies shared set point signatures for vaccine responsiveness in healthy individuals and disease activity in lupus patients” published in Nature Medicine in 2020.
Prepare the working directory
Some steps of the workflow require data generated for the first part of the analysis of flow cytometry and microarrays data (see Workflow.Rmd).
Before running the workflow make sure you have the following subfloders in the working directory:
data
citeseq
--data
--figures
--R
--results
generated_data
- Download the archived CITE-seq data folder from and unpack it into the
citeseq/data folder
.
- Download the archived directory
citeseq
with R code and unpack it into the citeseq folder.
- Make sure you have the
.Rprofile
file in the working directory. Modify the PROJECT_DIR
variable with the full path to the working directory.
- Create empty folders generated_data and figure_generation.
- If you are going to use the Singularity container download it from . It should be located outside of the working directory.
R packages used
Our pipeline requires the following R packages:
# CRAN:
install.packages(c("plyr", "tidyverse", "data.table", "pROC", "MASS", "limma", "mclust", "corrplot", "ggraph", "circlize", "pals", "ggsignif", "ggridges", "viridis", "clustree", "cowplot"))
# Bioconductor:
install.packages("BiocManager")
BiocManager::install()
BiocManager::install(c("SingleCellExperiment", "scater", "scran", "fgsea", "tmod", "ComplexHeatmap"))
# Seurat ver. 2.3.4
source("https://z.umn.edu/archived-seurat")
Notes
If while running some scripts you get X11 forwarding related error, check if you have X11 forwarding turned on (in Putty it is in Connection-SSH-X11) and turn it off. Sometime an error may appear due to a conflict between R packages. In this case restart R and rerun the script that previously returned the error.
0. Before running this workflow always change the working directory to citeseq
.
```r
source(\R/remove_doublet_clusters.r\)
<!-- rnb-source-end -->
<!-- rnb-chunk-end -->
<!-- rnb-text-begin -->
<br/>
# 1. Read Seurat object with demultiplexed data and filtered for singlet cells from H1N1 day0 samples only
Input data are stored in ```data``` folder. These files or other RDS files generated on further steps can be downloaded from the [Figshare repository](https://doi.org/10.35092/yhjc.c.4753772).
* RDS file with Seurat object
* ```data/H1_day0_demultilexed_singlets.RDS```
* RDS file with negative control cells
* ```data/neg_control_object.rds```
<!-- rnb-text-end -->
<!-- rnb-chunk-begin -->
<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc291cmNlKFxcUi9hZHRfY2x1c3RlcmluZ19jbHVzdGVyYXZlcmFnZXNfM2xldmVsc19maWd1cmUuclxcKVxuYGBgXG5gYGAifQ== -->
```r
```r
source(\R/adt_clustering_clusteraverages_3levels_figure.r\)
<!-- rnb-source-end -->
<!-- rnb-chunk-end -->
<!-- rnb-text-begin -->
Intermediate RDS files containing lists of Seurat objects with normalized data for individual batches are stored in ```data/normalization_data```.
Output RDS file is stored as ```data/H1_day0_scranNorm_adtbatchNorm.rds```.
<br/>
# 2. Clustering all cells by ADT data at multiple resolution
The clustering was performed using as an input the matrix of distances between cells using ADT data only.
## Input data
Input data are stored in ```data``` folder:
* RDS file with Seurat object with RNA-seq data SCRAN-normalized and ADT data batch-normalized and batch-corrected * ```data/H1_day0_scranNorm_adtbatchNorm.rds```
The calculations require OVER 64gb of RAM and was run on a high-performance cluster. The output file can be downloaded from the [Figshare repository](https://doi.org/10.35092/yhjc.c.4753772).
<!-- rnb-text-end -->
<!-- rnb-chunk-begin -->
<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc291cmNlKFxcUi9jb21wdXRlX3BjYS5yXFwpXG5gYGBcbmBgYCJ9 -->
```r
```r
source(\R/compute_pca.r\)
<!-- rnb-source-end -->
<!-- rnb-chunk-end -->
<!-- rnb-text-begin -->
Output:
* Table of clusters assignment for each cell:
* ```./data/H1N1_full_clustered_p3dist_multires_metadata.rds```.
* Seurat object with clustering assignment:
* ```./data/H1_day0_scranNorm_adtbatchNorm_dist_clustered.rds```.
<br/>
# 3. Clusters annotation
Generate a heatmap of average expression of selected protein markers in each of the cell clusters derived from the three different clustering resolutions
<!-- rnb-text-end -->
<!-- rnb-chunk-begin -->
<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc291cmNlKFxcUi9jb21wdXRlX3RzbmUuclxcKVxuYGBgXG5gYGAifQ== -->
```r
```r
source(\R/compute_tsne.r\)
<!-- rnb-source-end -->
<!-- rnb-chunk-end -->
<!-- rnb-text-begin -->
The generated table in ```results/cluster_nodes.txt``` is used add cluster labelse and manual annotation of cluster cell types.
The generated figures are stored in ```figures/cluster_annotation``` and used for cluster labeling and annotation.
<br/>
# 4. Filter cells and generate final heatmap
After annotating the clusters we found that at resolution=3 clusters 34, 36, 38, 39 contain mostly doublet cells. We remove cells in these clusters from the Seurat object.
<!-- rnb-text-end -->
<!-- rnb-chunk-begin -->
<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuc291cmNlKFxcUi9jbHVzdHJlZV9sYWJlbHMuclxcKVxuYGBgXG5gYGAifQ== -->
```r
```r
source(\R/clustree_labels.r\)
<!-- rnb-source-end -->
<!-- rnb-chunk-end -->
<!-- rnb-text-begin -->
Output file:
```./data/H1_day0_scranNorm_adtbatchNorm_dist_clustered_filtered.rds```
<br/>
The following script uses manual annottion table in ```data/clustree_node_labels_withCellTypeLabels.txt``` and clusters at first three resolutions to generate Figure 4c.
<!-- rnb-text-end -->
<!-- rnb-chunk-begin -->
<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuc291cmNlKFwiUi9hZHRfY2x1c3RlcmluZ19jbHVzdGVyYXZlcmFnZXNfM2xldmVsc19maWd1cmUuclwiKVxuYGBgIn0= -->
```r
source("R/adt_clustering_clusteraverages_3levels_figure.r")
The generated heatmap is stored in figures/cluster_annotation
.
5. PCA and tSNE analysis of the ADT data
source("R/compute_pca.r")
Output file: ./data/H1_day0_scranNorm_adtbatchNorm_dist_clustered_PCA.rds
PCA elbow plot is stored in figures/TSNE
. Using this plot We determined the number of principal components to use for tSNE as 7.
source("R/compute_tsne.r")
This script for tSNE computation at multiple perplexity was run on high-performance cluster. The output file can be downloaded from the Figshare repository.
Output file: ./data/H1_day0_scranNorm_adtbatchNorm_dist_clustered_TSNE.rds
6. Label and visualise the clusters
Re-label the clusters and create the final object.
source("R/clustree_labels.r")
Output file: ./data/H1_day0_scranNorm_adtbatchNorm_dist_clustered_TSNE_labels.rds
. The output file can be downloaded from the Figshare repository.
This Seurat object was used for all further analysis.
Generate tSNE plots to check for batch effect and show the first-level clusters for Figure 4a
source("R/tsne_figures.r")
The generated figures are stored in figures/TSNE
.
Generate the clustree for Figure 4b with nodes colored by level 1 cluters
source("R/clustree_vertical_clr_level1.r")
The generated figure is stored in figures/cluster_annotation
.
Generate the supplemental figure with the distribution of denoised and background rescaled counts for the surface proteins
source("R/adt_clustering_protein_distribution.r")
The generated figures are stored in figures/cluster_annotation
.
7. Test various gene signatures comparing low and high responders
Generate the list of signatures:
source("R/make_list_of_signatures.r")
Output file with the list of signatures is saved as sig/sig.list.RDS
.
Check enrichemnt of BTM modules in CD40act gene signature:
source("R/CD40act_genes_HG.test.r")
Output plot is saved in figures/CD40act
.
Test gene signatures comparing low vs. high responders using cells in pseudo-bulk and all cell clusters:
source("R/test_sigs_clusters.r")
Output file with the list of signatures is saved as results/test_sig.genes_in_clusters_high_vs_low_responders.txt
.
Compute scores for selected gene signatures in pseudo-bulk and all cell clusters:
source("R/sig_scores_calc_by_cluster.r")
Output files are saved in results/sig_scores
.
8. Visualize the results of gene signatures tests
Generate box-plot for pseudo-bulk for gene signatures with significant difference between low and high responders:
source("R/sig_scores_boxplot_pseudobulk.r")
Output plots (for Figure 4d,e) are saved in results/sig_test_boxplots
.
Generate box-plot for level 1 clusters for gene signatures with significant difference between low and high responders:
source("R/sig_scores_boxplot_by_clusters.r")
Output plots (for Fig. 5a,b,e and Ext. Data Fig. 8f) are saved in results/sig_test_boxplots
.
Generate clustree plots for selected gene signatures indicating significance of difference between low and high responders:
source("R/clustree_vertical_test_sigs.r")
Output plots (for Fig. 5a,b,e and Ext. Data Fig. 8f) are saved in results/sig_test_clustree
.
Generate box-plots for cluster C9 (pDC) for selected gene signatures:
source("R/sig_scores_boxplot_C9.r")
Output plots (for Fig. 5c) are saved in results/sig_test_boxplots
.
Drop-out test for selected gene signatures and selected cluster combinations:
source("R/test_sigs_clusters_OUT.r")
Result table is saved as results/test_sig.genes_in_clusters_high_vs_low_responders_OUT.txt
.
Output plots (for Ext. Data Fig. 8g) are saved in figures/drop_out_test
.
9. Manual gating of CD20+CD38++ B cells
source("R/hand_gating.r")
Output table of cell frequencies is saved as results/CITEseq_CD38hi_cell_data.txt
. Output plots (for Ext. Data Fig. 8d,e) are saved in results/hand_gating
.
11. Differential Expression of selected surface proteins in pDC between low and high responders
source("R/CD86_HLA-DR_vs_response.r")
Output plot is saved in figures/adt_vs_response
.
12. Comparing the TGSig and SLE-Sig scores in females versus males
source("R/TGSig_SLE.sig_vs_sex.r")
Output plot is saved in figures/male_vs_female
.
LS0tDQp0aXRsZTogIlJlcHJvZHVjaWJsZSB3b3JrZmxvdyBmb3IgdGhlIGFuYWx5c2lzIG9mICoqQ0lURS1zZXEgZGF0YSoqIGZvciB0aGUgcHJvamVjdCINCnN1YnRpdGxlOiAiXCJCcm9hZCBpbW11bmUgYWN0aXZhdGlvbiB1bmRlcmxpZXMgc2hhcmVkIHNldCBwb2ludCBzaWduYXR1cmVzIGZvciB2YWNjaW5lIHJlc3BvbnNpdmVuZXNzIGluIGhlYWx0aHkgaW5kaXZpZHVhbHMgYW5kIGRpc2Vhc2UgYWN0aXZpdHkgaW4gcGF0aWVudHMgd2l0aCBsdXB1c1wiIg0KYXV0aG9yOiAiWXVyaSBLb3RsaWFyb3YsIE1hdHRoZXcgTXVsZSwgQW5kcmV3IE1hcnRpbnMsIEpvaG4gUy4gVHNhbmciDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQotLS0NCg0KIyMgSW50cm9kdWN0aW9uDQoNClRoZSBmb2xsb3dpbmcgd29ya2Zsb3cgd2FzIHVzZWQgdG8gYW5hbHl6ZSB0aGUgQ0lURS1zZXEgZGF0YSBhbmQgZ2VuZXJhdGUgdGhlIENJVEUtc2VxIHJlbGF0ZWQgZmlndXJlcyBmb3Igb3VyIHBhcGVyICJCcm9hZCBpbW11bmUgYWN0aXZhdGlvbiB1bmRlcmxpZXMgc2hhcmVkIHNldCBwb2ludCBzaWduYXR1cmVzIGZvciB2YWNjaW5lIHJlc3BvbnNpdmVuZXNzIGluIGhlYWx0aHkgaW5kaXZpZHVhbHMgYW5kIGRpc2Vhc2UgYWN0aXZpdHkgaW4gbHVwdXMgcGF0aWVudHMiIHB1Ymxpc2hlZCBpbiBOYXR1cmUgTWVkaWNpbmUgaW4gMjAyMC4NCjxici8+DQoNCiMjIFByZXBhcmUgdGhlIHdvcmtpbmcgZGlyZWN0b3J5DQoNClNvbWUgc3RlcHMgb2YgdGhlIHdvcmtmbG93IHJlcXVpcmUgZGF0YSBnZW5lcmF0ZWQgZm9yIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBhbmFseXNpcyBvZiBmbG93IGN5dG9tZXRyeSBhbmQgbWljcm9hcnJheXMgZGF0YSAoc2VlIFdvcmtmbG93LlJtZCkuDQoNCkJlZm9yZSBydW5uaW5nIHRoZSB3b3JrZmxvdyBtYWtlIHN1cmUgeW91IGhhdmUgdGhlIGZvbGxvd2luZyBzdWJmbG9kZXJzIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeToNCg0KYGBgDQpkYXRhDQpjaXRlc2VxDQotLWRhdGENCi0tZmlndXJlcw0KLS1SDQotLXJlc3VsdHMNCmdlbmVyYXRlZF9kYXRhDQoNCmBgYA0KDQoqIERvd25sb2FkIHRoZSBhcmNoaXZlZCBDSVRFLXNlcSBkYXRhIGZvbGRlciBmcm9tIGFuZCB1bnBhY2sgaXQgaW50byB0aGUgYGBgY2l0ZXNlcS9kYXRhIGZvbGRlcmBgYC4gDQoqIERvd25sb2FkIHRoZSBhcmNoaXZlZCBkaXJlY3RvcnkgYGBgY2l0ZXNlcWBgYCB3aXRoIFIgY29kZSBhbmQgdW5wYWNrIGl0IGludG8gdGhlIGNpdGVzZXEgZm9sZGVyLiANCiogTWFrZSBzdXJlIHlvdSBoYXZlIHRoZSBgYGAuUnByb2ZpbGVgYGAgZmlsZSBpbiB0aGUgd29ya2luZyBkaXJlY3RvcnkuIE1vZGlmeSB0aGUgYGBgUFJPSkVDVF9ESVJgYGAgdmFyaWFibGUgd2l0aCB0aGUgZnVsbCBwYXRoIHRvIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4NCiogQ3JlYXRlIGVtcHR5IGZvbGRlcnMgZ2VuZXJhdGVkX2RhdGEgYW5kIGZpZ3VyZV9nZW5lcmF0aW9uLg0KKiBJZiB5b3UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgU2luZ3VsYXJpdHkgY29udGFpbmVyIGRvd25sb2FkIGl0IGZyb20gLiBJdCBzaG91bGQgYmUgbG9jYXRlZCBvdXRzaWRlIG9mIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4gDQoNCiMjIFIgcGFja2FnZXMgdXNlZA0KDQpPdXIgcGlwZWxpbmUgcmVxdWlyZXMgdGhlIGZvbGxvd2luZyBSIHBhY2thZ2VzOg0KDQpgYGANCiMgQ1JBTjoNCmluc3RhbGwucGFja2FnZXMoYygicGx5ciIsICJ0aWR5dmVyc2UiLCAiZGF0YS50YWJsZSIsICJwUk9DIiwgIk1BU1MiLCAibGltbWEiLCAibWNsdXN0IiwgImNvcnJwbG90IiwgImdncmFwaCIsICJjaXJjbGl6ZSIsICJwYWxzIiwgImdnc2lnbmlmIiwgImdncmlkZ2VzIiwgInZpcmlkaXMiLCAiY2x1c3RyZWUiLCAiY293cGxvdCIpKQ0KDQojIEJpb2NvbmR1Y3RvcjoNCmluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCkJpb2NNYW5hZ2VyOjppbnN0YWxsKCkNCkJpb2NNYW5hZ2VyOjppbnN0YWxsKGMoIlNpbmdsZUNlbGxFeHBlcmltZW50IiwgInNjYXRlciIsICJzY3JhbiIsICJmZ3NlYSIsICJ0bW9kIiwgIkNvbXBsZXhIZWF0bWFwIikpDQoNCiMgU2V1cmF0IHZlci4gMi4zLjQNCnNvdXJjZSgiaHR0cHM6Ly96LnVtbi5lZHUvYXJjaGl2ZWQtc2V1cmF0IikNCg0KYGBgDQo8YnIvPg0KDQoNCiMjIyBOb3Rlcw0KSWYgd2hpbGUgcnVubmluZyBzb21lIHNjcmlwdHMgeW91IGdldCBYMTEgZm9yd2FyZGluZyByZWxhdGVkIGVycm9yLCBjaGVjayBpZiB5b3UgaGF2ZSBYMTEgZm9yd2FyZGluZyB0dXJuZWQgb24gKGluIFB1dHR5IGl0IGlzIGluIENvbm5lY3Rpb24tU1NILVgxMSkgYW5kIHR1cm4gaXQgb2ZmLiANClNvbWV0aW1lIGFuIGVycm9yIG1heSBhcHBlYXIgZHVlIHRvIGEgY29uZmxpY3QgYmV0d2VlbiBSIHBhY2thZ2VzLiBJbiB0aGlzIGNhc2UgcmVzdGFydCBSIGFuZCByZXJ1biB0aGUgc2NyaXB0IHRoYXQgcHJldmlvdXNseSByZXR1cm5lZCB0aGUgZXJyb3IuDQo8YnIvPg0KDQotLS0NCjxici8+DQoNCg0KIyAqKjAuIEJlZm9yZSBydW5uaW5nIHRoaXMgd29ya2Zsb3cgYWx3YXlzIGNoYW5nZSB0aGUgd29ya2luZyBkaXJlY3RvcnkgdG8gYGBgY2l0ZXNlcWBgYCoqLg0KDQpgYGB7cn0NCnNldHdkKCJjaXRlc2VxIikNCmBgYA0KPGJyLz4NCg0KIyAxLiBSZWFkIFNldXJhdCBvYmplY3Qgd2l0aCBkZW11bHRpcGxleGVkIGRhdGEgYW5kIGZpbHRlcmVkIGZvciBzaW5nbGV0IGNlbGxzIGZyb20gSDFOMSBkYXkwIHNhbXBsZXMgb25seQ0KDQpJbnB1dCBkYXRhIGFyZSBzdG9yZWQgaW4gYGBgZGF0YWBgYCBmb2xkZXIuIFRoZXNlIGZpbGVzIG9yIG90aGVyIFJEUyBmaWxlcyBnZW5lcmF0ZWQgb24gZnVydGhlciBzdGVwcyBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIHRoZSBbRmlnc2hhcmUgcmVwb3NpdG9yeV0oaHR0cHM6Ly9kb2kub3JnLzEwLjM1MDkyL3loamMuYy40NzUzNzcyKS4gDQoNCiAgKiBSRFMgZmlsZSB3aXRoIFNldXJhdCBvYmplY3QNCiAgICAqIGBgYGRhdGEvSDFfZGF5MF9kZW11bHRpbGV4ZWRfc2luZ2xldHMuUkRTYGBgDQogICogUkRTIGZpbGUgd2l0aCBuZWdhdGl2ZSBjb250cm9sIGNlbGxzDQogICAgKiBgYGBkYXRhL25lZ19jb250cm9sX29iamVjdC5yZHNgYGANCg0KYGBge3J9DQpzb3VyY2UoIlIvZHNibm9ybV9wcm90X3NjcmFubm9ybV9ybmEuUiIpDQpgYGANCkludGVybWVkaWF0ZSBSRFMgZmlsZXMgY29udGFpbmluZyBsaXN0cyBvZiBTZXVyYXQgb2JqZWN0cyB3aXRoIG5vcm1hbGl6ZWQgZGF0YSBmb3IgaW5kaXZpZHVhbCBiYXRjaGVzIGFyZSBzdG9yZWQgaW4gYGBgZGF0YS9ub3JtYWxpemF0aW9uX2RhdGFgYGAuDQoNCk91dHB1dCBSRFMgZmlsZSBpcyBzdG9yZWQgYXMgYGBgZGF0YS9IMV9kYXkwX3NjcmFuTm9ybV9hZHRiYXRjaE5vcm0ucmRzYGBgLg0KPGJyLz4NCg0KDQojIDIuIENsdXN0ZXJpbmcgYWxsIGNlbGxzIGJ5IEFEVCBkYXRhIGF0IG11bHRpcGxlIHJlc29sdXRpb24NCg0KVGhlIGNsdXN0ZXJpbmcgd2FzIHBlcmZvcm1lZCB1c2luZyBhcyBhbiBpbnB1dCB0aGUgbWF0cml4IG9mIGRpc3RhbmNlcyBiZXR3ZWVuIGNlbGxzIHVzaW5nIEFEVCBkYXRhIG9ubHkuIA0KDQojIyBJbnB1dCBkYXRhDQoNCklucHV0IGRhdGEgYXJlIHN0b3JlZCBpbiBgYGBkYXRhYGBgIGZvbGRlcjoNCg0KICAqIFJEUyBmaWxlIHdpdGggU2V1cmF0IG9iamVjdCB3aXRoIFJOQS1zZXEgZGF0YSBTQ1JBTi1ub3JtYWxpemVkIGFuZCBBRFQgZGF0YSBiYXRjaC1ub3JtYWxpemVkIGFuZCBiYXRjaC1jb3JyZWN0ZWQgICAgICAqIGBgYGRhdGEvSDFfZGF5MF9zY3Jhbk5vcm1fYWR0YmF0Y2hOb3JtLnJkc2BgYA0KDQpUaGUgY2FsY3VsYXRpb25zIHJlcXVpcmUgT1ZFUiA2NGdiIG9mIFJBTSBhbmQgd2FzIHJ1biBvbiBhIGhpZ2gtcGVyZm9ybWFuY2UgY2x1c3Rlci4gVGhlIG91dHB1dCBmaWxlIGNhbiBiZSBkb3dubG9hZGVkIGZyb20gdGhlIFtGaWdzaGFyZSByZXBvc2l0b3J5XShodHRwczovL2RvaS5vcmcvMTAuMzUwOTIveWhqYy5jLjQ3NTM3NzIpLg0KDQpgYGB7cn0NCnNvdXJjZSgiUi9jbHVzdGVyX2NlbGxzX0FEVF9kaXN0YW5jZV9tYXRyaXguciIpDQpgYGANCg0KT3V0cHV0OiANCg0KICAqIFRhYmxlIG9mIGNsdXN0ZXJzIGFzc2lnbm1lbnQgZm9yIGVhY2ggY2VsbDogDQogICAgKiBgYGAuL2RhdGEvSDFOMV9mdWxsX2NsdXN0ZXJlZF9wM2Rpc3RfbXVsdGlyZXNfbWV0YWRhdGEucmRzYGBgLg0KICAqIFNldXJhdCBvYmplY3Qgd2l0aCBjbHVzdGVyaW5nIGFzc2lnbm1lbnQ6DQogICAgKiBgYGAuL2RhdGEvSDFfZGF5MF9zY3Jhbk5vcm1fYWR0YmF0Y2hOb3JtX2Rpc3RfY2x1c3RlcmVkLnJkc2BgYC4NCiAgDQo8YnIvPg0KDQoNCiMgMy4gQ2x1c3RlcnMgYW5ub3RhdGlvbg0KDQpHZW5lcmF0ZSBhIGhlYXRtYXAgb2YgYXZlcmFnZSBleHByZXNzaW9uIG9mIHNlbGVjdGVkIHByb3RlaW4gbWFya2VycyBpbiBlYWNoIG9mIHRoZSBjZWxsIGNsdXN0ZXJzIGRlcml2ZWQgZnJvbSB0aGUgdGhyZWUgZGlmZmVyZW50IGNsdXN0ZXJpbmcgcmVzb2x1dGlvbnMNCg0KYGBge3J9DQpzb3VyY2UoIlIvYWR0X2NsdXN0ZXJpbmdfY2x1c3RlcmF2ZXJhZ2VzX2FsbC5sZXZlbHMuciIpDQpgYGANCg0KVGhlIGdlbmVyYXRlZCB0YWJsZSBpbiBgYGByZXN1bHRzL2NsdXN0ZXJfbm9kZXMudHh0YGBgIGlzIHVzZWQgYWRkIGNsdXN0ZXIgbGFiZWxzZSBhbmQgbWFudWFsIGFubm90YXRpb24gb2YgY2x1c3RlciBjZWxsIHR5cGVzLg0KDQpUaGUgZ2VuZXJhdGVkIGZpZ3VyZXMgYXJlIHN0b3JlZCBpbiBgYGBmaWd1cmVzL2NsdXN0ZXJfYW5ub3RhdGlvbmBgYCBhbmQgdXNlZCBmb3IgY2x1c3RlciBsYWJlbGluZyBhbmQgYW5ub3RhdGlvbi4NCg0KPGJyLz4NCg0KDQojIDQuIEZpbHRlciBjZWxscyBhbmQgZ2VuZXJhdGUgZmluYWwgaGVhdG1hcA0KDQpBZnRlciBhbm5vdGF0aW5nIHRoZSBjbHVzdGVycyB3ZSBmb3VuZCB0aGF0IGF0IHJlc29sdXRpb249MyBjbHVzdGVycyAzNCwgMzYsIDM4LCAzOSBjb250YWluIG1vc3RseSBkb3VibGV0IGNlbGxzLiBXZSByZW1vdmUgY2VsbHMgaW4gdGhlc2UgY2x1c3RlcnMgZnJvbSB0aGUgU2V1cmF0IG9iamVjdC4NCg0KYGBge3J9DQpzb3VyY2UoIlIvcmVtb3ZlX2RvdWJsZXRfY2x1c3RlcnMuciIpDQpgYGANCg0KT3V0cHV0IGZpbGU6DQogIGBgYC4vZGF0YS9IMV9kYXkwX3NjcmFuTm9ybV9hZHRiYXRjaE5vcm1fZGlzdF9jbHVzdGVyZWRfZmlsdGVyZWQucmRzYGBgDQoNCjxici8+DQoNClRoZSBmb2xsb3dpbmcgc2NyaXB0IHVzZXMgbWFudWFsIGFubm90dGlvbiB0YWJsZSBpbiBgYGBkYXRhL2NsdXN0cmVlX25vZGVfbGFiZWxzX3dpdGhDZWxsVHlwZUxhYmVscy50eHRgYGAgYW5kIGNsdXN0ZXJzIGF0IGZpcnN0IHRocmVlIHJlc29sdXRpb25zIHRvIGdlbmVyYXRlIEZpZ3VyZSA0Yy4NCg0KYGBge3J9DQpzb3VyY2UoIlIvYWR0X2NsdXN0ZXJpbmdfY2x1c3RlcmF2ZXJhZ2VzXzNsZXZlbHNfZmlndXJlLnIiKQ0KYGBgDQoNClRoZSBnZW5lcmF0ZWQgaGVhdG1hcCBpcyBzdG9yZWQgaW4gYGBgZmlndXJlcy9jbHVzdGVyX2Fubm90YXRpb25gYGAuDQoNCjxici8+DQoNCg0KIyA1LiBQQ0EgYW5kIHRTTkUgYW5hbHlzaXMgb2YgdGhlIEFEVCBkYXRhIA0KDQpgYGB7cn0NCnNvdXJjZSgiUi9jb21wdXRlX3BjYS5yIikNCmBgYA0KDQpPdXRwdXQgZmlsZTogYGBgLi9kYXRhL0gxX2RheTBfc2NyYW5Ob3JtX2FkdGJhdGNoTm9ybV9kaXN0X2NsdXN0ZXJlZF9QQ0EucmRzYGBgDQoNClBDQSBlbGJvdyBwbG90IGlzIHN0b3JlZCBpbiBgYGBmaWd1cmVzL1RTTkVgYGAuIFVzaW5nIHRoaXMgcGxvdCBXZSBkZXRlcm1pbmVkIHRoZSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gdXNlIGZvciB0U05FIGFzICoqNyoqLg0KDQo8YnIvPg0KDQpgYGB7cn0NCnNvdXJjZSgiUi9jb21wdXRlX3RzbmUuciIpDQpgYGANCg0KVGhpcyBzY3JpcHQgZm9yIHRTTkUgY29tcHV0YXRpb24gYXQgbXVsdGlwbGUgcGVycGxleGl0eSB3YXMgcnVuIG9uIGhpZ2gtcGVyZm9ybWFuY2UgY2x1c3Rlci4gVGhlIG91dHB1dCBmaWxlIGNhbiBiZSBkb3dubG9hZGVkIGZyb20gdGhlIFtGaWdzaGFyZSByZXBvc2l0b3J5XShodHRwczovL2RvaS5vcmcvMTAuMzUwOTIveWhqYy5jLjQ3NTM3NzIpLg0KDQpPdXRwdXQgZmlsZTogYGBgLi9kYXRhL0gxX2RheTBfc2NyYW5Ob3JtX2FkdGJhdGNoTm9ybV9kaXN0X2NsdXN0ZXJlZF9UU05FLnJkc2BgYA0KDQo8YnIvPg0KDQojIDYuIExhYmVsIGFuZCB2aXN1YWxpc2UgdGhlIGNsdXN0ZXJzDQoNClJlLWxhYmVsIHRoZSBjbHVzdGVycyBhbmQgY3JlYXRlIHRoZSBmaW5hbCBvYmplY3QuDQoNCmBgYHtyfQ0Kc291cmNlKCJSL2NsdXN0cmVlX2xhYmVscy5yIikNCmBgYA0KDQpPdXRwdXQgZmlsZTogYGBgLi9kYXRhL0gxX2RheTBfc2NyYW5Ob3JtX2FkdGJhdGNoTm9ybV9kaXN0X2NsdXN0ZXJlZF9UU05FX2xhYmVscy5yZHNgYGAuDQpUaGUgb3V0cHV0IGZpbGUgY2FuIGJlIGRvd25sb2FkZWQgZnJvbSB0aGUgW0ZpZ3NoYXJlIHJlcG9zaXRvcnldKGh0dHBzOi8vZG9pLm9yZy8xMC4zNTA5Mi95aGpjLmMuNDc1Mzc3MikuDQoNCipUaGlzIFNldXJhdCBvYmplY3Qgd2FzIHVzZWQgZm9yIGFsbCBmdXJ0aGVyIGFuYWx5c2lzLioNCg0KPGJyLz4NCg0KR2VuZXJhdGUgdFNORSBwbG90cyB0byBjaGVjayBmb3IgYmF0Y2ggZWZmZWN0IGFuZCBzaG93IHRoZSBmaXJzdC1sZXZlbCBjbHVzdGVycyBmb3IgRmlndXJlIDRhDQoNCmBgYHtyfQ0Kc291cmNlKCJSL3RzbmVfZmlndXJlcy5yIikNCmBgYA0KDQpUaGUgZ2VuZXJhdGVkIGZpZ3VyZXMgYXJlIHN0b3JlZCBpbiBgYGBmaWd1cmVzL1RTTkVgYGAuDQoNCjxici8+DQoNCkdlbmVyYXRlIHRoZSBjbHVzdHJlZSBmb3IgRmlndXJlIDRiIHdpdGggbm9kZXMgY29sb3JlZCBieSBsZXZlbCAxIGNsdXRlcnMNCg0KYGBge3J9DQpzb3VyY2UoIlIvY2x1c3RyZWVfdmVydGljYWxfY2xyX2xldmVsMS5yIikNCmBgYA0KDQpUaGUgZ2VuZXJhdGVkIGZpZ3VyZSBpcyBzdG9yZWQgaW4gYGBgZmlndXJlcy9jbHVzdGVyX2Fubm90YXRpb25gYGAuDQoNCjxici8+DQoNCkdlbmVyYXRlIHRoZSBzdXBwbGVtZW50YWwgZmlndXJlIHdpdGggdGhlIGRpc3RyaWJ1dGlvbiBvZiBkZW5vaXNlZCBhbmQgYmFja2dyb3VuZCByZXNjYWxlZCBjb3VudHMgZm9yIHRoZSBzdXJmYWNlIHByb3RlaW5zDQoNCmBgYHtyfQ0Kc291cmNlKCJSL2FkdF9jbHVzdGVyaW5nX3Byb3RlaW5fZGlzdHJpYnV0aW9uLnIiKQ0KYGBgDQoNClRoZSBnZW5lcmF0ZWQgZmlndXJlcyBhcmUgc3RvcmVkIGluIGBgYGZpZ3VyZXMvY2x1c3Rlcl9hbm5vdGF0aW9uYGBgLg0KDQo8YnIvPg0KDQoNCiMgNy4gVGVzdCB2YXJpb3VzIGdlbmUgc2lnbmF0dXJlcyBjb21wYXJpbmcgbG93IGFuZCBoaWdoIHJlc3BvbmRlcnMNCg0KR2VuZXJhdGUgdGhlIGxpc3Qgb2Ygc2lnbmF0dXJlczoNCg0KYGBge3J9DQpzb3VyY2UoIlIvbWFrZV9saXN0X29mX3NpZ25hdHVyZXMuciIpDQpgYGANCk91dHB1dCBmaWxlIHdpdGggdGhlIGxpc3Qgb2Ygc2lnbmF0dXJlcyBpcyBzYXZlZCBhcyBgYGBzaWcvc2lnLmxpc3QuUkRTYGBgLg0KDQo8YnIvPg0KDQpDaGVjayBlbnJpY2hlbW50IG9mIEJUTSBtb2R1bGVzIGluIENENDBhY3QgZ2VuZSBzaWduYXR1cmU6DQoNCmBgYHtyfQ0Kc291cmNlKCJSL0NENDBhY3RfZ2VuZXNfSEcudGVzdC5yIikNCmBgYA0KT3V0cHV0IHBsb3QgaXMgc2F2ZWQgaW4gYGBgZmlndXJlcy9DRDQwYWN0YGBgLg0KDQo8YnIvPg0KDQpUZXN0IGdlbmUgc2lnbmF0dXJlcyBjb21wYXJpbmcgbG93IHZzLiBoaWdoIHJlc3BvbmRlcnMgdXNpbmcgY2VsbHMgaW4gcHNldWRvLWJ1bGsgYW5kIGFsbCBjZWxsIGNsdXN0ZXJzOiANCg0KYGBge3J9DQpzb3VyY2UoIlIvdGVzdF9zaWdzX2NsdXN0ZXJzLnIiKQ0KYGBgDQpPdXRwdXQgZmlsZSB3aXRoIHRoZSBsaXN0IG9mIHNpZ25hdHVyZXMgaXMgc2F2ZWQgYXMgYGBgcmVzdWx0cy90ZXN0X3NpZy5nZW5lc19pbl9jbHVzdGVyc19oaWdoX3ZzX2xvd19yZXNwb25kZXJzLnR4dGBgYC4NCg0KPGJyLz4NCg0KQ29tcHV0ZSBzY29yZXMgZm9yIHNlbGVjdGVkIGdlbmUgc2lnbmF0dXJlcyBpbiBwc2V1ZG8tYnVsayBhbmQgYWxsIGNlbGwgY2x1c3RlcnM6IA0KDQpgYGB7cn0NCnNvdXJjZSgiUi9zaWdfc2NvcmVzX2NhbGNfYnlfY2x1c3Rlci5yIikNCmBgYA0KT3V0cHV0IGZpbGVzIGFyZSBzYXZlZCBpbiBgYGByZXN1bHRzL3NpZ19zY29yZXNgYGAuDQoNCjxici8+DQoNCg0KIyA4LiBWaXN1YWxpemUgdGhlIHJlc3VsdHMgb2YgZ2VuZSBzaWduYXR1cmVzIHRlc3RzDQoNCkdlbmVyYXRlIGJveC1wbG90IGZvciBwc2V1ZG8tYnVsayBmb3IgZ2VuZSBzaWduYXR1cmVzIHdpdGggc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIGxvdyBhbmQgaGlnaCByZXNwb25kZXJzOiANCg0KYGBge3J9DQpzb3VyY2UoIlIvc2lnX3Njb3Jlc19ib3hwbG90X3BzZXVkb2J1bGsuciIpDQpgYGANCg0KT3V0cHV0IHBsb3RzIChmb3IgRmlndXJlIDRkLGUpIGFyZSBzYXZlZCBpbiBgYGByZXN1bHRzL3NpZ190ZXN0X2JveHBsb3RzYGBgLg0KDQo8YnIvPg0KDQoNCkdlbmVyYXRlIGJveC1wbG90IGZvciBsZXZlbCAxIGNsdXN0ZXJzIGZvciBnZW5lIHNpZ25hdHVyZXMgd2l0aCBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gbG93IGFuZCBoaWdoIHJlc3BvbmRlcnM6IA0KDQpgYGB7cn0NCnNvdXJjZSgiUi9zaWdfc2NvcmVzX2JveHBsb3RfYnlfY2x1c3RlcnMuciIpDQpgYGANCg0KT3V0cHV0IHBsb3RzIChmb3IgRmlnLiA1YSxiLGUgYW5kIEV4dC4gRGF0YSBGaWcuIDhmKSBhcmUgc2F2ZWQgaW4gYGBgcmVzdWx0cy9zaWdfdGVzdF9ib3hwbG90c2BgYC4NCg0KPGJyLz4NCg0KDQpHZW5lcmF0ZSBjbHVzdHJlZSBwbG90cyBmb3Igc2VsZWN0ZWQgZ2VuZSBzaWduYXR1cmVzIGluZGljYXRpbmcgc2lnbmlmaWNhbmNlIG9mIGRpZmZlcmVuY2UgYmV0d2VlbiBsb3cgYW5kIGhpZ2ggcmVzcG9uZGVyczogDQoNCmBgYHtyfQ0Kc291cmNlKCJSL2NsdXN0cmVlX3ZlcnRpY2FsX3Rlc3Rfc2lncy5yIikNCmBgYA0KDQpPdXRwdXQgcGxvdHMgKGZvciBGaWcuIDVhLGIsZSBhbmQgRXh0LiBEYXRhIEZpZy4gOGYpIGFyZSBzYXZlZCBpbiBgYGByZXN1bHRzL3NpZ190ZXN0X2NsdXN0cmVlYGBgLg0KDQo8YnIvPg0KDQoNCkdlbmVyYXRlIGJveC1wbG90cyBmb3IgY2x1c3RlciBDOSAocERDKSBmb3Igc2VsZWN0ZWQgZ2VuZSBzaWduYXR1cmVzOiANCg0KYGBge3J9DQpzb3VyY2UoIlIvc2lnX3Njb3Jlc19ib3hwbG90X0M5LnIiKQ0KYGBgDQoNCk91dHB1dCBwbG90cyAoZm9yIEZpZy4gNWMpIGFyZSBzYXZlZCBpbiBgYGByZXN1bHRzL3NpZ190ZXN0X2JveHBsb3RzYGBgLg0KDQo8YnIvPg0KDQpEcm9wLW91dCB0ZXN0IGZvciBzZWxlY3RlZCBnZW5lIHNpZ25hdHVyZXMgYW5kIHNlbGVjdGVkIGNsdXN0ZXIgY29tYmluYXRpb25zOiANCg0KYGBge3J9DQpzb3VyY2UoIlIvdGVzdF9zaWdzX2NsdXN0ZXJzX09VVC5yIikNCmBgYA0KDQpSZXN1bHQgdGFibGUgaXMgc2F2ZWQgYXMgYGBgcmVzdWx0cy90ZXN0X3NpZy5nZW5lc19pbl9jbHVzdGVyc19oaWdoX3ZzX2xvd19yZXNwb25kZXJzX09VVC50eHRgYGAuDQoNCk91dHB1dCBwbG90cyAoZm9yIEV4dC4gRGF0YSBGaWcuIDhnKSBhcmUgc2F2ZWQgaW4gYGBgZmlndXJlcy9kcm9wX291dF90ZXN0YGBgLg0KDQo8YnIvPg0KDQoNCiMgOS4gTWFudWFsIGdhdGluZyBvZiBDRDIwK0NEMzgrKyBCIGNlbGxzDQoNCmBgYHtyfQ0Kc291cmNlKCJSL2hhbmRfZ2F0aW5nLnIiKQ0KYGBgDQoNCk91dHB1dCB0YWJsZSBvZiBjZWxsIGZyZXF1ZW5jaWVzIGlzIHNhdmVkIGFzIGBgYHJlc3VsdHMvQ0lURXNlcV9DRDM4aGlfY2VsbF9kYXRhLnR4dGBgYC4NCk91dHB1dCBwbG90cyAoZm9yIEV4dC4gRGF0YSBGaWcuIDhkLGUpIGFyZSBzYXZlZCBpbiBgYGByZXN1bHRzL2hhbmRfZ2F0aW5nYGBgLg0KDQo8YnIvPg0KDQoNCiMgMTAuIENvbXBpbGUgc2NvcmVzIGZvciBtdWx0aXBsZSBzaWduYXR1cmVzIGFuZCBwZXJmb3JtIGNvcnJlbGF0aW9uIGFuYWx5c2lzDQoNCkNvbXB1dGUgc2NvcmVzIG9mIFNMRS1TaWcgc2lnbmF0dXJlIGZvciBtaWNyb2FycmF5IGRheSAwIGRhdGE6DQoNCmBgYHtyfQ0Kc291cmNlKCJSL1NMRS5zaWdfTUFfc2lnX3Njb3JlLnIiKQ0KYGBgDQoNCk91dHB1dCBmaWxlIGlzIHNhdmVkIGFzIGBgYHJlc3VsdHMvc2lnX3Njb3Jlcy9zY29yZXNfU0xFLnNpZ19NQS50eHRgYGAuDQoNCjxici8+DQoNCkNvbXBpbGUgc2NvcmVzIGZvciBzZWxlY3RlZCBnZW5lIHNpZ25hdHVyZXMgZm9yIENJVEUtc2VxIGFuZCBtaWNyb2FycmF5IGRhdGEgcGx1cyBDRDM4KysgY2VsbCBmcmVxdWVuY3kgZnJvbSBmbG93IGN5dG9tZXRyeSBkYXRhOg0KDQoNCmBgYHtyfQ0Kc291cmNlKCJSL3Njb3Jlc19mb3JfY29ycmVsYXRpb24uciIpDQpgYGANCg0KT3V0cHV0IHRhYmxlIG9mIGNlbGwgZnJlcXVlbmNpZXMgaXMgc2F2ZWQgYXMgYGBgcmVzdWx0cy9DSVRFc2VxX0NEMzhoaV9jZWxsX2RhdGEudHh0YGBgLg0KDQo8YnIvPg0KDQpHZW5lcmF0ZSBzY2F0dGVyIHBsb3Qgb2YgQ0Q0MGFjdCBzY29yZSBpbiBDMy4xLjAgY2VsbCBjbHVzdGVyIHZzLiBDRDIwPUNEMzgrKyBCIGNlbGxzIGZyZXF1ZW5jeSBmcm9tIGZsb3cgY3l0b21ldHJ5IChGaWd1cmUgNWYpOg0KDQpgYGB7cn0NCnNvdXJjZSgiUi9DRDQwYWN0X3ZzX0NEMzhoaS5mbG93LnIiKQ0KYGBgDQoNCk91dHB1dCBwbG90IGlzIHNhdmVkIGluIGBgYGZpZ3VyZXMvc2lnX3JhbmtlZF9jb3JyZWxhdGlvbmBgYC4NCg0KPGJyLz4NCg0KR2VuZXJhdGUgc2NhdHRlciBwbG90cyBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNlbGVjdGVkIHNpZ25hdHVyZSBzY29yZXMgaW4gc2VsZWN0ZWQgY2x1c3RlcnMgKGZvciBGaWd1cmUgNmEpOg0KDQpgYGB7cn0NCnNvdXJjZSgiUi9zaWdfY29ycmVsYXRpb25fc2NhdHRlcnBsb3RzLnIiKQ0KYGBgDQoNCk91dHB1dCBwbG90cyBhcmUgc2F2ZWQgaW4gYGBgZmlndXJlcy9zaWdfcmFua2VkX2NvcnJlbGF0aW9uYGBgLg0KDQo8YnIvPg0KDQpHZW5lcmF0ZSBhIGNvcnJlbGF0aW9uIHBsb3QgKGZvciBGSWd1cmUgNmEpOg0KDQpgYGB7cn0NCnNvdXJjZSgiUi9zY29yZXNfY29ycmVsYXRpb25faGVhdG1hcF9jdXN0b21fb3JkZXIuciIpDQpgYGANCg0KT3V0cHV0IHBsb3QgaXMgc2F2ZWQgaW4gYGBgZmlndXJlcy9zaWdfcmFua2VkX2NvcnJlbGF0aW9uYGBgLg0KDQo8YnIvPg0KDQoNCiMgMTEuIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIG9mIHNlbGVjdGVkIHN1cmZhY2UgcHJvdGVpbnMgaW4gcERDIGJldHdlZW4gbG93IGFuZCBoaWdoIHJlc3BvbmRlcnMNCg0KYGBge3J9DQpzb3VyY2UoIlIvQ0Q4Nl9ITEEtRFJfdnNfcmVzcG9uc2UuciIpDQpgYGANCg0KT3V0cHV0IHBsb3QgaXMgc2F2ZWQgaW4gYGBgZmlndXJlcy9hZHRfdnNfcmVzcG9uc2VgYGAuDQoNCjxici8+DQoNCg0KIyAxMi4gQ29tcGFyaW5nIHRoZSBUR1NpZyBhbmQgU0xFLVNpZyBzY29yZXMgaW4gZmVtYWxlcyB2ZXJzdXMgbWFsZXMNCg0KYGBge3J9DQpzb3VyY2UoIlIvVEdTaWdfU0xFLnNpZ192c19zZXguciIpDQpgYGANCg0KT3V0cHV0IHBsb3QgaXMgc2F2ZWQgaW4gYGBgZmlndXJlcy9tYWxlX3ZzX2ZlbWFsZWBgYC4NCg0KPGJyLz4NCjxici8+DQo8YnIvPg0KDQoNCg0K