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

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.


10. Compile scores for multiple signatures and perform correlation analysis

Compute scores of SLE-Sig signature for microarray day 0 data:

source("R/SLE.sig_MA_sig_score.r")

Output file is saved as results/sig_scores/scores_SLE.sig_MA.txt.


Compile scores for selected gene signatures for CITE-seq and microarray data plus CD38++ cell frequency from flow cytometry data:

source("R/scores_for_correlation.r")

Output table of cell frequencies is saved as results/CITEseq_CD38hi_cell_data.txt.


Generate scatter plot of CD40act score in C3.1.0 cell cluster vs. CD20=CD38++ B cells frequency from flow cytometry (Figure 5f):

source("R/CD40act_vs_CD38hi.flow.r")

Output plot is saved in figures/sig_ranked_correlation.


Generate scatter plots of correlation between selected signature scores in selected clusters (for Figure 6a):

source("R/sig_correlation_scatterplots.r")

Output plots are saved in figures/sig_ranked_correlation.


Generate a correlation plot (for FIgure 6a):

source("R/scores_correlation_heatmap_custom_order.r")

Output plot is saved in figures/sig_ranked_correlation.


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