In this workbook, we are starting our analysis with normalized HCA data and perform integration, clustering and dimensionality reduction. Our aim is to extract T-cells from this dataset and proceed with pseudotime analysis in the next workbook.

These are the libraries we will need in this workbook

library(SingleCellExperiment)
library(scran)
library(scater)
library(batchelor)
library(cowplot)
library(pheatmap)
library(tidyverse)
library(SingleR)
library(destiny)
library(gam)
library(viridis)
library(msigdbr)
library(clusterProfiler)

1 Extract T-cells from HCA Dataset

We are going to work with HCA data. This data set has been pre-processed and normalized before.

sce<-readRDS(file="~/Course_Materials/scRNAseq/pseudotime/hca_sce.bone.RDS")

We use symbols in place of ENSEMBL IDs for easier interpretation later.

#rowData(sce)$Chr <- mapIds(EnsDb.Hsapiens.v86, keys=rownames(sce), column="SEQNAME", keytype="GENEID")
#rownames(sce) <- uniquifyFeatureNames(rowData(sce)$ensembl_gene_id, names = rowData(sce)$Symbol)

1.1 Variance modeling

We block on the donor of origin to mitigate batch effects during highly variable gene (HVG) selection. We select a larger number of HVGs to capture any batch-specific variation that might be present.

#dec.hca <- modelGeneVar(sce, block=sce$Sample.Name)
#top.hca <- getTopHVGs(dec.hca, n=5000)

1.2 Data integration

The batchelor package provides an implementation of the MNN approach via the fastMNN() function. We apply it to our HCA data to remove the donor specific effects across the highly variable genes in top.hca. To reduce computational work and technical noise, all cells in all samples are projected into the low-dimensional space defined by the top d principal components. Identification of MNNs and calculation of correction vectors are then performed in this low-dimensional space. The corrected matrix in the reducedDims() contains the low-dimensional corrected coordinates for all cells, which we will use in place of the PCs in our downstream analyses. We store it in ‘MNN’ slot in the main sce object.

#set.seed(1010001)
#merged.hca <- fastMNN(sce, batch = sce$Sample.Name, subset.row = top.hca)
#reducedDim(sce, 'MNN') <- reducedDim(merged.hca, 'corrected')

1.3 Dimensionality Reduction

We cluster on the low-dimensional corrected coordinates to obtain a partitioning of the cells that serves as a proxy for the population structure. If the batch effect is successfully corrected, clusters corresponding to shared cell types or states should contain cells from multiple samples. We see that all clusters contain contributions from each sample after correction.

#set.seed(01010100)
#sce <- runUMAP(sce, dimred="MNN")
#sce <- runTSNE(sce, dimred="MNN")
plotPCA(sce, colour_by="Sample.Name") + ggtitle("PCA")

plotUMAP(sce, colour_by="Sample.Name") + ggtitle("UMAP")

plotTSNE(sce, colour_by="Sample.Name") + ggtitle("tSNE")

1.4 Clustering

Graph-based clustering generates an excessively large intermediate graph so we will instead use a two-step approach with k-means. We generate 1000 small clusters that are subsequently aggregated into more interpretable groups with a graph-based method.

#set.seed(1000)
#clust.hca <- clusterSNNGraph(sce, use.dimred="MNN", 
#    use.kmeans=TRUE, kmeans.centers=1000)
#colLabels(sce) <- factor(clust.hca)
table(colLabels(sce))

    1     2     3     4     5     6     7     8     9    10    11    12 
 4790  6056  2036  2422  2600  2435 11586   707  4684   936  1191   557 
plotPCA(sce, colour_by="label") + ggtitle("PCA")

plotUMAP(sce, colour_by="label") + ggtitle("UMAP")

plotTSNE(sce, colour_by="label") + ggtitle("tSNE")

1.5 Cell type classification

We perform automated cell type classification using a reference dataset to annotate each cluster based on its pseudo-bulk profile. This is for a quick assignment of cluster identity. We are going to use Human Primary Cell Atlas (HPCA) data for that. HumanPrimaryCellAtlasData function provides normalized expression values for 713 microarray samples from HPCA (Mabbott et al., 2013). These 713 samples were processed and normalized as described in Aran, Looney and Liu et al. (2019). Each sample has been assigned to one of 37 main cell types and 157 subtypes.

se.aggregated <- sumCountsAcrossCells(sce, id=colLabels(sce))
hpc <- HumanPrimaryCellAtlasData()
anno.hca <- SingleR(se.aggregated, ref = hpc, labels = hpc$label.main, assay.type.test="sum")

anno.hca
DataFrame with 12 rows and 5 columns
                            scores     first.labels      tuning.scores           labels    pruned.labels
                          <matrix>      <character>        <DataFrame>      <character>      <character>
1   0.281120:0.580521:0.490323:...          NK_cell  0.595425:0.426528          T_cells          T_cells
2   0.269576:0.720264:0.502810:... Pre-B_cell_CD34-  0.390449:0.180455         Monocyte         Monocyte
3   0.269360:0.605466:0.465618:...           B_cell  0.648661:0.257872           B_cell           B_cell
4   0.383672:0.647291:0.789261:...              MEP  0.360240:0.346833              MEP              MEP
5   0.284526:0.591911:0.468152:...           B_cell  0.762421:0.658735           B_cell           B_cell
...                            ...              ...                ...              ...              ...
8   0.256000:0.645332:0.441369:...         Monocyte 0.582277: 0.257172         Monocyte         Monocyte
9   0.290154:0.579078:0.499469:...          T_cells 0.719841:-0.114850          T_cells          T_cells
10  0.381632:0.670836:0.597980:... Pro-B_cell_CD34+ 0.834774: 0.745602 Pro-B_cell_CD34+ Pro-B_cell_CD34+
11  0.291531:0.592682:0.506481:...          NK_cell 0.810637: 0.729778          NK_cell          NK_cell
12  0.331348:0.596984:0.525463:...           B_cell 0.468819: 0.284846           B_cell           B_cell
tab <- table(anno.hca$labels, colnames(se.aggregated))
# Adding a pseudo-count of 10 to avoid strong color jumps with just 1 cell.
pheatmap(log10(tab+10))

sce$cell_type<-recode(sce$label, "1" = "T_cells", 
       "2" = "Monocyte", 
       "3"="B_cell",
       "4"="MEP", 
       "5"="B_cell", 
       "6"="CMP", 
       "7"="T_cells",
      "8"="Monocyte",
      "9"="T_cells",
      "10"="Pro-B_cell_CD34+",
      "11"="NK_cell",
      "12"="B_cell")

We can now use the predicted cell types to color PCA, UMAP and tSNE.

plotPCA(sce, colour_by="cell_type", text_by="cell_type") + ggtitle("PCA")

plotUMAP(sce, colour_by="cell_type", text_by="cell_type") + ggtitle("UMAP")

plotTSNE(sce, colour_by="cell_type", text_by="cell_type") + ggtitle("tSNE")

We can also check expression of some marker genes.

CD3D and TRAC are used as marker genes for T-cells Szabo et al. 2019.

plotExpression(sce, features=c("CD3D"), x="label", colour_by="cell_type")

plotExpression(sce, features=c("TRAC"), x="label", colour_by="cell_type")

1.6 Extract T-cells

We will now extract T-cells and store in a new SCE object to use in pseudotime analysis.

Pull barcodes for T-cells

tcell.bc <- colData(sce) %>%
    data.frame() %>%
    group_by(cell_type) %>%
    dplyr::filter(cell_type == "T_cells") %>%
    pull(Barcode)

table(colData(sce)$Barcode %in% tcell.bc)

FALSE  TRUE 
18940 21060 

Create a new SingleCellExperiment object for T-cells

tmpInd <- which(colData(sce)$Barcode %in% tcell.bc)
sce.tcell <- sce[,tmpInd]
saveRDS(sce.tcell,"~/Course_Materials/scRNAseq/pseudotime/sce.tcell.RDS")

2 Ackowledgements

This notebook uses material from SVI course, OSCA Book, Broad Institute Workshop and Hemberg Group Course.

sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C         LC_TIME=C            LC_COLLATE=C         LC_MONETARY=C        LC_MESSAGES=C       
 [7] LC_PAPER=C           LC_NAME=C            LC_ADDRESS=C         LC_TELEPHONE=C       LC_MEASUREMENT=C     LC_IDENTIFICATION=C 

attached base packages:
 [1] splines   parallel  stats4    stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] scRNAseq_2.2.0              knitr_1.29                  cellAlign_0.1.0             clusterProfiler_3.16.0     
 [5] msigdbr_7.1.1               viridis_0.5.1               viridisLite_0.3.0           gam_1.20                   
 [9] foreach_1.5.0               destiny_3.2.0               SingleR_1.2.4               forcats_0.5.0              
[13] stringr_1.4.0               dplyr_1.0.0                 purrr_0.3.4                 readr_1.3.1                
[17] tidyr_1.1.0                 tibble_3.0.3                tidyverse_1.3.0             pheatmap_1.0.12            
[21] cowplot_1.0.0               batchelor_1.4.0             scater_1.16.2               ggplot2_3.3.2              
[25] scran_1.16.0                SingleCellExperiment_1.10.1 SummarizedExperiment_1.18.2 DelayedArray_0.14.1        
[29] matrixStats_0.56.0          Biobase_2.48.0              GenomicRanges_1.40.0        GenomeInfoDb_1.24.2        
[33] IRanges_2.22.2              S4Vectors_0.26.1            BiocGenerics_0.34.0        

loaded via a namespace (and not attached):
  [1] rappdirs_0.3.1                ggthemes_4.2.0                bit64_0.9-7.1                 irlba_2.3.3                  
  [5] data.table_1.12.8             RCurl_1.98-1.2                generics_0.0.2                RSQLite_2.2.0                
  [9] europepmc_0.4                 proxy_0.4-24                  bit_1.1-15.2                  enrichplot_1.8.1             
 [13] xml2_1.3.2                    lubridate_1.7.9               httpuv_1.5.4                  assertthat_0.2.1             
 [17] xfun_0.15                     hms_0.5.3                     evaluate_0.14                 promises_1.1.1               
 [21] DEoptimR_1.0-8                fansi_0.4.1                   progress_1.2.2                dbplyr_1.4.4                 
 [25] readxl_1.3.1                  igraph_1.2.5                  DBI_1.1.0                     ellipsis_0.3.1               
 [29] RSpectra_0.16-0               backports_1.1.8               bookdown_0.20                 vctrs_0.3.2                  
 [33] TTR_0.23-6                    abind_1.4-5                   RcppEigen_0.3.3.7.0           withr_2.2.0                  
 [37] ggforce_0.3.2                 packrat_0.5.0                 triebeard_0.3.0               robustbase_0.93-6            
 [41] vcd_1.4-7                     xts_0.12-0                    prettyunits_1.1.1             DOSE_3.14.0                  
 [45] ExperimentHub_1.14.0          laeken_0.5.1                  crayon_1.3.4                  labeling_0.3                 
 [49] edgeR_3.30.3                  pkgconfig_2.0.3               tweenr_1.0.1                  vipor_0.4.5                  
 [53] nnet_7.3-14                   rlang_0.4.7                   lifecycle_0.2.0               downloader_0.4               
 [57] BiocFileCache_1.12.0          modelr_0.1.8                  rsvd_1.0.3                    AnnotationHub_2.20.0         
 [61] cellranger_1.1.0              polyclip_1.10-0               RcppHNSW_0.2.0                lmtest_0.9-37                
 [65] Matrix_1.2-18                 urltools_1.7.3                carData_3.0-4                 boot_1.3-25                  
 [69] zoo_1.8-8                     reprex_0.3.0                  base64enc_0.1-3               beeswarm_0.2.3               
 [73] ggridges_0.5.2                bitops_1.0-6                  blob_1.2.1                    DelayedMatrixStats_1.10.1    
 [77] qvalue_2.20.0                 gridGraphics_0.5-0            scales_1.1.1                  memoise_1.1.0                
 [81] magrittr_1.5                  plyr_1.8.6                    hexbin_1.28.1                 zlibbioc_1.34.0              
 [85] compiler_4.0.2                scatterpie_0.1.4              dqrng_0.2.1                   RColorBrewer_1.1-2           
 [89] pcaMethods_1.80.0             cli_2.0.2                     dtw_1.21-3                    XVector_0.28.0               
 [93] ggplot.multistats_1.0.0       MASS_7.3-51.6                 tidyselect_1.1.0              stringi_1.4.6                
 [97] yaml_2.2.1                    GOSemSim_2.14.0               BiocSingular_1.4.0            locfit_1.5-9.4               
[101] ggrepel_0.8.2                 grid_4.0.2                    fastmatch_1.1-0               tools_4.0.2                  
[105] rio_0.5.16                    rstudioapi_0.11               foreign_0.8-80                gridExtra_2.3                
[109] smoother_1.1                  scatterplot3d_0.3-41          farver_2.0.3                  ggraph_2.0.3                 
[113] digest_0.6.25                 rvcheck_0.1.8                 BiocManager_1.30.10           shiny_1.5.0                  
[117] Rcpp_1.0.5                    car_3.0-8                     broom_0.7.0                   BiocVersion_3.11.1           
[121] later_1.1.0.1                 httr_1.4.1                    AnnotationDbi_1.50.1          colorspace_1.4-1             
[125] rvest_0.3.5                   fs_1.4.2                      ranger_0.12.1                 statmod_1.4.34               
[129] graphlayouts_0.7.0            sp_1.4-2                      ggplotify_0.0.5               xtable_1.8-4                 
[133] jsonlite_1.7.0                tidygraph_1.2.0               R6_2.4.1                      pillar_1.4.6                 
[137] htmltools_0.5.0               mime_0.9                      glue_1.4.1                    fastmap_1.0.1                
[141] VIM_6.0.0                     BiocParallel_1.22.0           BiocNeighbors_1.6.0           class_7.3-17                 
[145] interactiveDisplayBase_1.26.3 codetools_0.2-16              fgsea_1.14.0                  lattice_0.20-41              
[149] curl_4.3                      ggbeeswarm_0.6.0              zip_2.0.4                     GO.db_3.11.4                 
[153] openxlsx_4.1.5                limma_3.44.3                  rmarkdown_2.3                 munsell_0.5.0                
[157] e1071_1.7-3                   DO.db_2.9                     GenomeInfoDbData_1.2.3        iterators_1.0.12             
[161] haven_2.3.1                   reshape2_1.4.4                gtable_0.3.0                 
LS0tCnRpdGxlOiAiQ1JVSyBDSSBTdW1tZXIgU2Nob29sIDIwMjAiCnN1YnRpdGxlOiAnUHNldWRvdGltZSBBbmFseXNpcycKCmF1dGhvcjogIlpleW5lcCBLYWxlbmRlci1BdGFrLCBTdGVwaGFuZSBCYWxsZXJlYXUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogIGh0bWxfYm9vazoKICAgIGNvZGVfZm9sZGluZzogc2hvdwotLS0KCkluIHRoaXMgd29ya2Jvb2ssIHdlIGFyZSBzdGFydGluZyBvdXIgYW5hbHlzaXMgd2l0aCBub3JtYWxpemVkIFtIQ0FdKGh0dHBzOi8vcHJldmlldy5kYXRhLmh1bWFuY2VsbGF0bGFzLm9yZykgZGF0YSBhbmQgcGVyZm9ybSBpbnRlZ3JhdGlvbiwgY2x1c3RlcmluZyBhbmQgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uLiBPdXIgYWltIGlzIHRvIGV4dHJhY3QgVC1jZWxscyBmcm9tIHRoaXMgZGF0YXNldCBhbmQgcHJvY2VlZCB3aXRoIHBzZXVkb3RpbWUgYW5hbHlzaXMgaW4gdGhlIG5leHQgd29ya2Jvb2suIAoKVGhlc2UgYXJlIHRoZSBsaWJyYXJpZXMgd2Ugd2lsbCBuZWVkIGluIHRoaXMgd29ya2Jvb2sgCmBgYHtyfQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQpsaWJyYXJ5KHNjcmFuKQpsaWJyYXJ5KHNjYXRlcikKbGlicmFyeShiYXRjaGVsb3IpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoU2luZ2xlUikKbGlicmFyeShkZXN0aW55KQpsaWJyYXJ5KGdhbSkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KG1zaWdkYnIpCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpgYGAKCiMgRXh0cmFjdCBULWNlbGxzIGZyb20gSENBIERhdGFzZXQKCmBgYHtyIHNlcVF1YWwua25pdHJfb3B0aW9ucywgZWNobz1GQUxTRSwgcmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0V9CnJlcXVpcmUoa25pdHIpCiNvcHRzX2NodW5rJHNldChlcnJvcj1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRSkKb3B0c19jaHVuayRzZXQoZXJyb3I9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPUZBTFNFKQpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NywgZmlnLmhlaWdodD03KSAKYGBgCgpXZSBhcmUgZ29pbmcgdG8gd29yayB3aXRoIEhDQSBkYXRhLiBUaGlzIGRhdGEgc2V0IGhhcyBiZWVuIHByZS1wcm9jZXNzZWQgYW5kIG5vcm1hbGl6ZWQgYmVmb3JlLiAKYGBge3J9CnNjZTwtcmVhZFJEUyhmaWxlPSJ+L0NvdXJzZV9NYXRlcmlhbHMvc2NSTkFzZXEvcHNldWRvdGltZS9oY2Ffc2NlLmJvbmUuUkRTIikKYGBgCgpXZSB1c2Ugc3ltYm9scyBpbiBwbGFjZSBvZiBFTlNFTUJMIElEcyBmb3IgZWFzaWVyIGludGVycHJldGF0aW9uIGxhdGVyLgpgYGB7cn0KI3Jvd0RhdGEoc2NlKSRDaHIgPC0gbWFwSWRzKEVuc0RiLkhzYXBpZW5zLnY4Niwga2V5cz1yb3duYW1lcyhzY2UpLCBjb2x1bW49IlNFUU5BTUUiLCBrZXl0eXBlPSJHRU5FSUQiKQojcm93bmFtZXMoc2NlKSA8LSB1bmlxdWlmeUZlYXR1cmVOYW1lcyhyb3dEYXRhKHNjZSkkZW5zZW1ibF9nZW5lX2lkLCBuYW1lcyA9IHJvd0RhdGEoc2NlKSRTeW1ib2wpCmBgYAoKIyMgVmFyaWFuY2UgbW9kZWxpbmcKCldlIGJsb2NrIG9uIHRoZSBkb25vciBvZiBvcmlnaW4gdG8gbWl0aWdhdGUgYmF0Y2ggZWZmZWN0cyBkdXJpbmcgaGlnaGx5IHZhcmlhYmxlIGdlbmUgKEhWRykgc2VsZWN0aW9uLiBXZSBzZWxlY3QgYSBsYXJnZXIgbnVtYmVyIG9mIEhWR3MgdG8gY2FwdHVyZSBhbnkgYmF0Y2gtc3BlY2lmaWMgdmFyaWF0aW9uIHRoYXQgbWlnaHQgYmUgcHJlc2VudC4KYGBge3J9CiNkZWMuaGNhIDwtIG1vZGVsR2VuZVZhcihzY2UsIGJsb2NrPXNjZSRTYW1wbGUuTmFtZSkKI3RvcC5oY2EgPC0gZ2V0VG9wSFZHcyhkZWMuaGNhLCBuPTUwMDApCmBgYAoKIyMgRGF0YSBpbnRlZ3JhdGlvbgoKVGhlIGBiYXRjaGVsb3JgIHBhY2thZ2UgcHJvdmlkZXMgYW4gaW1wbGVtZW50YXRpb24gb2YgdGhlIE1OTiBhcHByb2FjaCB2aWEgdGhlIGZhc3RNTk4oKSBmdW5jdGlvbi4gV2UgYXBwbHkgaXQgdG8gb3VyIEhDQSBkYXRhIHRvIHJlbW92ZSB0aGUgZG9ub3Igc3BlY2lmaWMgZWZmZWN0cyBhY3Jvc3MgdGhlIGhpZ2hseSB2YXJpYWJsZSBnZW5lcyBpbiBgdG9wLmhjYWAuIFRvIHJlZHVjZSBjb21wdXRhdGlvbmFsIHdvcmsgYW5kIHRlY2huaWNhbCBub2lzZSwgYWxsIGNlbGxzIGluIGFsbCBzYW1wbGVzIGFyZSBwcm9qZWN0ZWQgaW50byB0aGUgbG93LWRpbWVuc2lvbmFsIHNwYWNlIGRlZmluZWQgYnkgdGhlIHRvcCBkIHByaW5jaXBhbCBjb21wb25lbnRzLiBJZGVudGlmaWNhdGlvbiBvZiBNTk5zIGFuZCBjYWxjdWxhdGlvbiBvZiBjb3JyZWN0aW9uIHZlY3RvcnMgYXJlIHRoZW4gcGVyZm9ybWVkIGluIHRoaXMgbG93LWRpbWVuc2lvbmFsIHNwYWNlLgpUaGUgY29ycmVjdGVkIG1hdHJpeCBpbiB0aGUgcmVkdWNlZERpbXMoKSBjb250YWlucyB0aGUgbG93LWRpbWVuc2lvbmFsIGNvcnJlY3RlZCBjb29yZGluYXRlcyBmb3IgYWxsIGNlbGxzLCB3aGljaCB3ZSB3aWxsIHVzZSBpbiBwbGFjZSBvZiB0aGUgUENzIGluIG91ciBkb3duc3RyZWFtIGFuYWx5c2VzLiBXZSBzdG9yZSBpdCBpbiAnTU5OJyBzbG90IGluIHRoZSBtYWluIHNjZSBvYmplY3QuIAoKYGBge3J9CiNzZXQuc2VlZCgxMDEwMDAxKQojbWVyZ2VkLmhjYSA8LSBmYXN0TU5OKHNjZSwgYmF0Y2ggPSBzY2UkU2FtcGxlLk5hbWUsIHN1YnNldC5yb3cgPSB0b3AuaGNhKQojcmVkdWNlZERpbShzY2UsICdNTk4nKSA8LSByZWR1Y2VkRGltKG1lcmdlZC5oY2EsICdjb3JyZWN0ZWQnKQpgYGAKCiMjIERpbWVuc2lvbmFsaXR5IFJlZHVjdGlvbgoKV2UgY2x1c3RlciBvbiB0aGUgbG93LWRpbWVuc2lvbmFsIGNvcnJlY3RlZCBjb29yZGluYXRlcyB0byBvYnRhaW4gYSBwYXJ0aXRpb25pbmcgb2YgdGhlIGNlbGxzIHRoYXQgc2VydmVzIGFzIGEgcHJveHkgZm9yIHRoZSBwb3B1bGF0aW9uIHN0cnVjdHVyZS4gSWYgdGhlIGJhdGNoIGVmZmVjdCBpcyBzdWNjZXNzZnVsbHkgY29ycmVjdGVkLCBjbHVzdGVycyBjb3JyZXNwb25kaW5nIHRvIHNoYXJlZCBjZWxsIHR5cGVzIG9yIHN0YXRlcyBzaG91bGQgY29udGFpbiBjZWxscyBmcm9tIG11bHRpcGxlIHNhbXBsZXMuIFdlIHNlZSB0aGF0IGFsbCBjbHVzdGVycyBjb250YWluIGNvbnRyaWJ1dGlvbnMgZnJvbSBlYWNoIHNhbXBsZSBhZnRlciBjb3JyZWN0aW9uLgoKYGBge3J9CiNzZXQuc2VlZCgwMTAxMDEwMCkKI3NjZSA8LSBydW5VTUFQKHNjZSwgZGltcmVkPSJNTk4iKQojc2NlIDwtIHJ1blRTTkUoc2NlLCBkaW1yZWQ9Ik1OTiIpCmBgYAoKYGBge3J9CnBsb3RQQ0Eoc2NlLCBjb2xvdXJfYnk9IlNhbXBsZS5OYW1lIikgKyBnZ3RpdGxlKCJQQ0EiKQpwbG90VU1BUChzY2UsIGNvbG91cl9ieT0iU2FtcGxlLk5hbWUiKSArIGdndGl0bGUoIlVNQVAiKQpwbG90VFNORShzY2UsIGNvbG91cl9ieT0iU2FtcGxlLk5hbWUiKSArIGdndGl0bGUoInRTTkUiKQpgYGAKCiMjIENsdXN0ZXJpbmcKCkdyYXBoLWJhc2VkIGNsdXN0ZXJpbmcgZ2VuZXJhdGVzIGFuIGV4Y2Vzc2l2ZWx5IGxhcmdlIGludGVybWVkaWF0ZSBncmFwaCBzbyB3ZSB3aWxsIGluc3RlYWQgdXNlIGEgdHdvLXN0ZXAgYXBwcm9hY2ggd2l0aCBrLW1lYW5zLiBXZSBnZW5lcmF0ZSAxMDAwIHNtYWxsIGNsdXN0ZXJzIHRoYXQgYXJlIHN1YnNlcXVlbnRseSBhZ2dyZWdhdGVkIGludG8gbW9yZSBpbnRlcnByZXRhYmxlIGdyb3VwcyB3aXRoIGEgZ3JhcGgtYmFzZWQgbWV0aG9kLgpgYGB7cn0KI3NldC5zZWVkKDEwMDApCiNjbHVzdC5oY2EgPC0gY2x1c3RlclNOTkdyYXBoKHNjZSwgdXNlLmRpbXJlZD0iTU5OIiwgCiMgICAgdXNlLmttZWFucz1UUlVFLCBrbWVhbnMuY2VudGVycz0xMDAwKQojY29sTGFiZWxzKHNjZSkgPC0gZmFjdG9yKGNsdXN0LmhjYSkKdGFibGUoY29sTGFiZWxzKHNjZSkpCmBgYAoKCmBgYHtyfQpwbG90UENBKHNjZSwgY29sb3VyX2J5PSJsYWJlbCIpICsgZ2d0aXRsZSgiUENBIikKcGxvdFVNQVAoc2NlLCBjb2xvdXJfYnk9ImxhYmVsIikgKyBnZ3RpdGxlKCJVTUFQIikKcGxvdFRTTkUoc2NlLCBjb2xvdXJfYnk9ImxhYmVsIikgKyBnZ3RpdGxlKCJ0U05FIikKYGBgCgoKIyMgQ2VsbCB0eXBlIGNsYXNzaWZpY2F0aW9uCgpXZSBwZXJmb3JtIGF1dG9tYXRlZCBjZWxsIHR5cGUgY2xhc3NpZmljYXRpb24gdXNpbmcgYSByZWZlcmVuY2UgZGF0YXNldCB0byBhbm5vdGF0ZSBlYWNoIGNsdXN0ZXIgYmFzZWQgb24gaXRzIHBzZXVkby1idWxrIHByb2ZpbGUuIFRoaXMgaXMgZm9yIGEgcXVpY2sgYXNzaWdubWVudCBvZiBjbHVzdGVyIGlkZW50aXR5LiBXZSBhcmUgZ29pbmcgdG8gdXNlIEh1bWFuIFByaW1hcnkgQ2VsbCBBdGxhcyAoSFBDQSkgZGF0YSBmb3IgdGhhdC4gYEh1bWFuUHJpbWFyeUNlbGxBdGxhc0RhdGFgIGZ1bmN0aW9uIHByb3ZpZGVzIG5vcm1hbGl6ZWQgZXhwcmVzc2lvbiB2YWx1ZXMgZm9yIDcxMyBtaWNyb2FycmF5IHNhbXBsZXMgZnJvbSBIUENBIChbTWFiYm90dCBldCBhbC4sIDIwMTNdKGh0dHBzOi8vYm1jZ2Vub21pY3MuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni8xNDcxLTIxNjQtMTQtNjMyKSkuIFRoZXNlIDcxMyBzYW1wbGVzIHdlcmUgcHJvY2Vzc2VkIGFuZCBub3JtYWxpemVkIGFzIGRlc2NyaWJlZCBpbiBbQXJhbiwgTG9vbmV5IGFuZCBMaXUgZXQgYWwuICgyMDE5KV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1OTAtMDE4LTAyNzYteSkuIEVhY2ggc2FtcGxlIGhhcyBiZWVuIGFzc2lnbmVkIHRvIG9uZSBvZiAzNyBtYWluIGNlbGwgdHlwZXMgYW5kIDE1NyBzdWJ0eXBlcy4KCmBgYHtyfQpzZS5hZ2dyZWdhdGVkIDwtIHN1bUNvdW50c0Fjcm9zc0NlbGxzKHNjZSwgaWQ9Y29sTGFiZWxzKHNjZSkpCmhwYyA8LSBIdW1hblByaW1hcnlDZWxsQXRsYXNEYXRhKCkKYW5uby5oY2EgPC0gU2luZ2xlUihzZS5hZ2dyZWdhdGVkLCByZWYgPSBocGMsIGxhYmVscyA9IGhwYyRsYWJlbC5tYWluLCBhc3NheS50eXBlLnRlc3Q9InN1bSIpCgphbm5vLmhjYQpgYGAKCgpgYGB7cn0KdGFiIDwtIHRhYmxlKGFubm8uaGNhJGxhYmVscywgY29sbmFtZXMoc2UuYWdncmVnYXRlZCkpCiMgQWRkaW5nIGEgcHNldWRvLWNvdW50IG9mIDEwIHRvIGF2b2lkIHN0cm9uZyBjb2xvciBqdW1wcyB3aXRoIGp1c3QgMSBjZWxsLgpwaGVhdG1hcChsb2cxMCh0YWIrMTApKQpgYGAKCmBgYHtyfQpzY2UkY2VsbF90eXBlPC1yZWNvZGUoc2NlJGxhYmVsLCAiMSIgPSAiVF9jZWxscyIsIAogICAgICAgIjIiID0gIk1vbm9jeXRlIiwgCiAgICAgICAiMyI9IkJfY2VsbCIsCiAgICAgICAiNCI9Ik1FUCIsIAogICAgICAgIjUiPSJCX2NlbGwiLCAKICAgICAgICI2Ij0iQ01QIiwgCiAgICAgICAiNyI9IlRfY2VsbHMiLAogICAgICAiOCI9Ik1vbm9jeXRlIiwKICAgICAgIjkiPSJUX2NlbGxzIiwKICAgICAgIjEwIj0iUHJvLUJfY2VsbF9DRDM0KyIsCiAgICAgICIxMSI9Ik5LX2NlbGwiLAogICAgICAiMTIiPSJCX2NlbGwiKQpgYGAKCldlIGNhbiBub3cgdXNlIHRoZSBwcmVkaWN0ZWQgY2VsbCB0eXBlcyB0byBjb2xvciBQQ0EsIFVNQVAgYW5kIHRTTkUuIAoKYGBge3J9CnBsb3RQQ0Eoc2NlLCBjb2xvdXJfYnk9ImNlbGxfdHlwZSIsIHRleHRfYnk9ImNlbGxfdHlwZSIpICsgZ2d0aXRsZSgiUENBIikKcGxvdFVNQVAoc2NlLCBjb2xvdXJfYnk9ImNlbGxfdHlwZSIsIHRleHRfYnk9ImNlbGxfdHlwZSIpICsgZ2d0aXRsZSgiVU1BUCIpCnBsb3RUU05FKHNjZSwgY29sb3VyX2J5PSJjZWxsX3R5cGUiLCB0ZXh0X2J5PSJjZWxsX3R5cGUiKSArIGdndGl0bGUoInRTTkUiKQpgYGAKCgpXZSBjYW4gYWxzbyBjaGVjayBleHByZXNzaW9uIG9mIHNvbWUgbWFya2VyIGdlbmVzLiAKCkNEM0QgYW5kIFRSQUMgYXJlIHVzZWQgYXMgbWFya2VyIGdlbmVzIGZvciBULWNlbGxzIFtTemFibyBldCBhbC4gMjAxOV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE0NjctMDE5LTEyNDY0LTMpLiAKCmBgYHtyfQpwbG90RXhwcmVzc2lvbihzY2UsIGZlYXR1cmVzPWMoIkNEM0QiKSwgeD0ibGFiZWwiLCBjb2xvdXJfYnk9ImNlbGxfdHlwZSIpCmBgYAoKYGBge3J9CnBsb3RFeHByZXNzaW9uKHNjZSwgZmVhdHVyZXM9YygiVFJBQyIpLCB4PSJsYWJlbCIsIGNvbG91cl9ieT0iY2VsbF90eXBlIikKYGBgCgoKIyMgRXh0cmFjdCBULWNlbGxzCldlIHdpbGwgbm93IGV4dHJhY3QgVC1jZWxscyBhbmQgc3RvcmUgaW4gYSBuZXcgU0NFIG9iamVjdCB0byB1c2UgaW4gcHNldWRvdGltZSBhbmFseXNpcy4gCgoKUHVsbCBiYXJjb2RlcyBmb3IgVC1jZWxscyAKYGBge3J9CnRjZWxsLmJjIDwtIGNvbERhdGEoc2NlKSAlPiUKICAgIGRhdGEuZnJhbWUoKSAlPiUKICAgIGdyb3VwX2J5KGNlbGxfdHlwZSkgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKGNlbGxfdHlwZSA9PSAiVF9jZWxscyIpICU+JQogICAgcHVsbChCYXJjb2RlKQoKdGFibGUoY29sRGF0YShzY2UpJEJhcmNvZGUgJWluJSB0Y2VsbC5iYykKYGBgCgpDcmVhdGUgYSBuZXcgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgb2JqZWN0IGZvciBULWNlbGxzIAoKYGBge3J9CnRtcEluZCA8LSB3aGljaChjb2xEYXRhKHNjZSkkQmFyY29kZSAlaW4lIHRjZWxsLmJjKQpzY2UudGNlbGwgPC0gc2NlWyx0bXBJbmRdCmBgYAoKYGBge3J9CnNhdmVSRFMoc2NlLnRjZWxsLCJ+L0NvdXJzZV9NYXRlcmlhbHMvc2NSTkFzZXEvcHNldWRvdGltZS9zY2UudGNlbGwuUkRTIikKYGBgCgojIEFja293bGVkZ2VtZW50cwpUaGlzIG5vdGVib29rIHVzZXMgbWF0ZXJpYWwgZnJvbSBbU1ZJIGNvdXJzZV0oaHR0cHM6Ly9iaW9jZWxsZ2VuLXB1YmxpYy5zdmkuZWR1LmF1L21pZ18yMDE5X3Njcm5hc2VxLXdvcmtzaG9wL3B1YmxpYy9pbmRleC5odG1sKSwgW09TQ0EgQm9va10oaHR0cHM6Ly9vc2NhLmJpb2NvbmR1Y3Rvci5vcmcpLCBbQnJvYWQgSW5zdGl0dXRlIFdvcmtzaG9wXShodHRwczovL2Jyb2FkaW5zdGl0dXRlLmdpdGh1Yi5pby8yMDIwX3NjV29ya3Nob3AvKSBhbmQgIFtIZW1iZXJnIEdyb3VwIENvdXJzZV0oaHR0cHM6Ly9zY3JuYXNlcS1jb3Vyc2UuY29nLnNhbmdlci5hYy51ay93ZWJzaXRlL2luZGV4Lmh0bWwpLiAKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCg==