• Load libraries
  • Load and filter progenitors data
  • Annotate ChP trajectory
  • Differentiating neurons trajectory
    • Pallial neurons
    • Combine the two trajectories’ data
  • Transfert all cell state annotatio to the full dataset
  • Session Info

Load libraries

library(Seurat)
library(princurve)
library(Matrix)
library(dplyr)
library(RColorBrewer)
library(ggplot2)
library(ggExtra)
library(cowplot)
library(wesanderson)

#Set ggplot theme as classic
theme_set(theme_classic())

Load and filter progenitors data

Hem.data <- readRDS("../QC.filtered.clustered.cells.RDS")
DimPlot(object = Hem.data,
        group.by = "Cell_ident",
        reduction = "spring",
        cols = c("#ebcb2e", #"ChP"
                 "#9ec22f", #"ChP_progenitors"
                 "#e7823a", # CR
                 "#cc3a1b", #"Dorso-Medial_pallium" 
                 "#d14c8d", #"Hem" 
                 "#4cabdc", #"Medial_pallium"
                 "#046c9a", # Pallial
                 "#4990c9" #"Thalamic_eminence"
                 )
        )

Annotate ChP trajectory

ChP.data <-  subset(Hem.data, idents = c("ChP"))

DimPlot(ChP.data,
        reduction = "spring",
        pt.size = 1,
        cols =  c("#83c3b8", "#009fda")) + NoAxes()

Trajectory.ChP <- ChP.data@meta.data %>%
                    select("Barcodes", "Spring_1", "Spring_2", "Cell_ident")
fit <- principal_curve(as.matrix(Trajectory.ChP[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 2305169233
## Iteration 1---distance^2: 1449991
## Iteration 2---distance^2: 1424111
## Iteration 3---distance^2: 1422674
## Iteration 4---distance^2: 1422096
#Pseudotime score
Trajectory.ChP$Pseudotime <- fit$lambda/max(fit$lambda)
cols <- brewer.pal(n =11, name = "Spectral")

ggplot(Trajectory.ChP, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=Pseudotime), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Pseudotime score')

Trajectory.ChP$Cell.state <- cut(Trajectory.ChP$Pseudotime,
                                       3,
                                       include.lowest = T,
                                       labels=c("Early","Mid","Late"))
Trajectory.ChP$Cell.state <- paste0(Trajectory.ChP$Cell_ident, "_", Trajectory.ChP$Cell.state)

ggplot(Trajectory.ChP, aes(Spring_1, Spring_2)) +
        geom_point(aes(color= Cell.state), size=0.5) +
        scale_color_manual(values= c("#68b041", "#e3c148", "#b7d174"))

Differentiating neurons trajectory

Neurons.data <-  subset(Hem.data, idents = c("Cajal-Retzius_neurons", "Pallial_neurons"))

DimPlot(Neurons.data ,
        reduction = "spring",
        pt.size = 1,
        cols =  c("#cc391b","#026c9a")
        ) + NoAxes()

## Cajal-Retzius cells

Trajectories.Hem <- Neurons.data@meta.data %>%
                    select("Barcodes", "Spring_1", "Spring_2", "Cell_ident") %>%
                    filter(Cell_ident == "Cajal-Retzius_neurons")
fit <- principal_curve(as.matrix(Trajectories.Hem[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 45804778678
## Iteration 1---distance^2: 27732113
## Iteration 2---distance^2: 27728318
#Pseudotime score
Trajectories.Hem$Pseudotime <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Hem$Pseudotime, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Hem$Barcodes]) > 0) {
  Trajectories.Hem$Pseudotime <- -(Trajectories.Hem$Pseudotime - max(Trajectories.Hem$Pseudotime))
}

Pallial neurons

Trajectories.Pallial <- Neurons.data@meta.data %>%
                        select("Barcodes", "Spring_1", "Spring_2", "Cell_ident") %>%
                        filter(Cell_ident == "Pallial_neurons")
fit <- principal_curve(as.matrix(Trajectories.Pallial[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 26984853690
## Iteration 1---distance^2: 22153700
## Iteration 2---distance^2: 22179462
## Iteration 3---distance^2: 22180297
#Pseudotime score
Trajectories.Pallial$Pseudotime <- fit$lambda/max(fit$lambda)
if (cor(Trajectories.Pallial$Pseudotime, Neurons.data@assays$SCT@data['Hmga2', Trajectories.Pallial$Barcodes]) > 0) {
  Trajectories.Pallial$Pseudotime <- -(Trajectories.Pallial$Pseudotime - max(Trajectories.Pallial$Pseudotime))
}

Combine the two trajectories’ data

Trajectories.neurons <- rbind(Trajectories.Pallial, Trajectories.Hem)
ggplot(Trajectories.neurons, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=Pseudotime), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Pseudotime score')

hist(Trajectories.neurons$Pseudotime, breaks = 100)
abline(v=c(0.4,0.68), col ="blue")

Trajectories.neurons$Cell.state <- cut(Trajectories.neurons$Pseudotime,
                                       c(0,0.4,0.68,1),
                                       include.lowest = T,
                                       labels=c("BP","EN","LN"))

ggplot(Trajectories.neurons, aes(Spring_1, Spring_2)) +
        geom_point(aes(color= Cell.state), size=0.5) +
        scale_color_manual(values= c("#68b041", "#e3c148", "#b7d174"))

Trajectories.neurons$Cell.state <- paste0(Trajectories.neurons$Cell_ident, "_", Trajectories.neurons$Cell.state)

Transfert all cell state annotatio to the full dataset

New.labels <- rbind(Trajectory.ChP,Trajectories.neurons)
Hem.data$Cell.state <- sapply(Hem.data$Barcodes,
                              FUN = function(x) {
                                if (x %in% New.labels$Barcodes) {
                                  x = New.labels[x, "Cell.state"]
                                } else {
                                  x = Hem.data@meta.data[x, "Cell_ident"]
                                  }
                              })
DimPlot(object = Hem.data,
        group.by = "Cell.state",
        reduction = "spring",
        cols = c("#7293c8", "#b79f0b", "#3ca73f","#31b6bd",
            "#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b", "#d14c8d", "#4cabdc", "#5ab793", "#e7823a", "#046c9a", "#4990c9"))

saveRDS(Hem.data, "../QC.filtered.clustered.cells.RDS")

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "26 avril, 2022, 11,57"
#Packages used
sessionInfo()
## R version 4.1.3 (2022-03-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.4 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
## 
## locale:
##  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8    
##  [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8   
##  [7] LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6  cowplot_1.1.1      ggExtra_0.9        ggplot2_3.3.5     
##  [5] RColorBrewer_1.1-2 dplyr_1.0.7        Matrix_1.4-1       princurve_2.1.6   
##  [9] SeuratObject_4.0.4 Seurat_4.0.5      
## 
## loaded via a namespace (and not attached):
##   [1] Rtsne_0.15            colorspace_2.0-2      deldir_1.0-6         
##   [4] ellipsis_0.3.2        ggridges_0.5.3        spatstat.data_2.1-0  
##   [7] farver_2.1.0          leiden_0.3.9          listenv_0.8.0        
##  [10] ggrepel_0.9.1         fansi_0.5.0           codetools_0.2-18     
##  [13] splines_4.1.3         knitr_1.36            polyclip_1.10-0      
##  [16] jsonlite_1.7.2        ica_1.0-2             cluster_2.1.3        
##  [19] png_0.1-7             uwot_0.1.10           shiny_1.7.1          
##  [22] sctransform_0.3.2     spatstat.sparse_2.0-0 compiler_4.1.3       
##  [25] httr_1.4.2            assertthat_0.2.1      fastmap_1.1.0        
##  [28] lazyeval_0.2.2        later_1.3.0           htmltools_0.5.2      
##  [31] tools_4.1.3           igraph_1.2.11         gtable_0.3.0         
##  [34] glue_1.5.1            RANN_2.6.1            reshape2_1.4.4       
##  [37] Rcpp_1.0.8            scattermore_0.7       jquerylib_0.1.4      
##  [40] vctrs_0.3.8           nlme_3.1-153          lmtest_0.9-39        
##  [43] xfun_0.28             stringr_1.4.0         globals_0.14.0       
##  [46] mime_0.12             miniUI_0.1.1.1        lifecycle_1.0.1      
##  [49] irlba_2.3.3           goftest_1.2-3         future_1.23.0        
##  [52] MASS_7.3-56           zoo_1.8-9             scales_1.1.1         
##  [55] spatstat.core_2.3-1   promises_1.2.0.1      spatstat.utils_2.2-0 
##  [58] parallel_4.1.3        yaml_2.2.1            reticulate_1.22      
##  [61] pbapply_1.5-0         gridExtra_2.3         sass_0.4.0           
##  [64] rpart_4.1.16          stringi_1.7.6         highr_0.9            
##  [67] rlang_0.4.12          pkgconfig_2.0.3       matrixStats_0.61.0   
##  [70] evaluate_0.14         lattice_0.20-45       ROCR_1.0-11          
##  [73] purrr_0.3.4           tensor_1.5            labeling_0.4.2       
##  [76] patchwork_1.1.1       htmlwidgets_1.5.4     tidyselect_1.1.1     
##  [79] parallelly_1.29.0     RcppAnnoy_0.0.19      plyr_1.8.6           
##  [82] magrittr_2.0.2        R6_2.5.1              generics_0.1.1       
##  [85] DBI_1.1.1             pillar_1.6.4          withr_2.4.3          
##  [88] mgcv_1.8-40           fitdistrplus_1.1-6    survival_3.2-13      
##  [91] abind_1.4-5           tibble_3.1.6          future.apply_1.8.1   
##  [94] crayon_1.4.2          KernSmooth_2.23-20    utf8_1.2.2           
##  [97] spatstat.geom_2.3-0   plotly_4.10.0         rmarkdown_2.11       
## [100] grid_4.1.3            data.table_1.14.2     digest_0.6.29        
## [103] xtable_1.8-4          tidyr_1.1.4           httpuv_1.6.3         
## [106] munsell_0.5.0         viridisLite_0.4.0     bslib_0.3.1

  1. Institute of Psychiatry and Neuroscience of Paris, INSERM U1266, 75014, Paris, France, ↩︎

LS0tCnRpdGxlOiAiUmUtYW5ub3RhdGUgV1QgZGF0YXNldCBmb3IgcHJvamVjdGlvbiBvbnRvIEtPIGRhdGF0c2V0IgphdXRob3I6CiAgIC0gTWF0dGhpZXUgTW9yZWF1XltJbnN0aXR1dGUgb2YgUHN5Y2hpYXRyeSBhbmQgTmV1cm9zY2llbmNlIG9mIFBhcmlzLCBJTlNFUk0gVTEyNjYsIDc1MDE0LCBQYXJpcywgRnJhbmNlLCBtYXR0aGlldS5tb3JlYXVAaW5zZXJtLmZyXSBbIVtdKGh0dHBzOi8vb3JjaWQub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvaW1hZ2VzL29yY2lkXzE2eDE2LnBuZyldKGh0dHBzOi8vb3JjaWQub3JnLzAwMDAtMDAwMi0yNTkyLTIzNzMpCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgZGZfcHJpbnQ6IHRpYmJsZQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICB0aGVtZTogY29zbW8KICAgIGNzczogIi4uL3N0eWxlLmNzcyIKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2FjaGUubGF6eSA9IEZBTFNFKQoKIyBUbyB1c2UgYmlvbWFydCAKbmV3X2NvbmZpZyA8LSBodHRyOjpjb25maWcoc3NsX3ZlcmlmeXBlZXIgPSBGQUxTRSkKaHR0cjo6c2V0X2NvbmZpZyhuZXdfY29uZmlnLCBvdmVycmlkZSA9IEZBTFNFKQpgYGAKCiMgTG9hZCBsaWJyYXJpZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHByaW5jdXJ2ZSkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dFeHRyYSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHdlc2FuZGVyc29uKQoKI1NldCBnZ3Bsb3QgdGhlbWUgYXMgY2xhc3NpYwp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpgYGAKCiMgTG9hZCBhbmQgZmlsdGVyIHByb2dlbml0b3JzIGRhdGEKCmBgYHtyfQpIZW0uZGF0YSA8LSByZWFkUkRTKCIuLi9RQy5maWx0ZXJlZC5jbHVzdGVyZWQuY2VsbHMuUkRTIikKYGBgCgpgYGB7cn0KRGltUGxvdChvYmplY3QgPSBIZW0uZGF0YSwKICAgICAgICBncm91cC5ieSA9ICJDZWxsX2lkZW50IiwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYygiI2ViY2IyZSIsICMiQ2hQIgogICAgICAgICAgICAgICAgICIjOWVjMjJmIiwgIyJDaFBfcHJvZ2VuaXRvcnMiCiAgICAgICAgICAgICAgICAgIiNlNzgyM2EiLCAjIENSCiAgICAgICAgICAgICAgICAgIiNjYzNhMWIiLCAjIkRvcnNvLU1lZGlhbF9wYWxsaXVtIiAKICAgICAgICAgICAgICAgICAiI2QxNGM4ZCIsICMiSGVtIiAKICAgICAgICAgICAgICAgICAiIzRjYWJkYyIsICMiTWVkaWFsX3BhbGxpdW0iCiAgICAgICAgICAgICAgICAgIiMwNDZjOWEiLCAjIFBhbGxpYWwKICAgICAgICAgICAgICAgICAiIzQ5OTBjOSIgIyJUaGFsYW1pY19lbWluZW5jZSIKICAgICAgICAgICAgICAgICApCiAgICAgICAgKQpgYGAKCiMgQW5ub3RhdGUgQ2hQIHRyYWplY3RvcnkKCmBgYHtyfQpDaFAuZGF0YSA8LSAgc3Vic2V0KEhlbS5kYXRhLCBpZGVudHMgPSBjKCJDaFAiKSkKCkRpbVBsb3QoQ2hQLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgcHQuc2l6ZSA9IDEsCiAgICAgICAgY29scyA9ICBjKCIjODNjM2I4IiwgIiMwMDlmZGEiKSkgKyBOb0F4ZXMoKQpgYGAKCmBgYHtyfQpUcmFqZWN0b3J5LkNoUCA8LSBDaFAuZGF0YUBtZXRhLmRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KCJCYXJjb2RlcyIsICJTcHJpbmdfMSIsICJTcHJpbmdfMiIsICJDZWxsX2lkZW50IikKYGBgCgpgYGB7cn0KZml0IDwtIHByaW5jaXBhbF9jdXJ2ZShhcy5tYXRyaXgoVHJhamVjdG9yeS5DaFBbLGMoIlNwcmluZ18xIiwgIlNwcmluZ18yIildKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAuNywKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3J5LkNoUCRQc2V1ZG90aW1lIDwtIGZpdCRsYW1iZGEvbWF4KGZpdCRsYW1iZGEpCmBgYApgYGB7cn0KY29scyA8LSBicmV3ZXIucGFsKG4gPTExLCBuYW1lID0gIlNwZWN0cmFsIikKCmdncGxvdChUcmFqZWN0b3J5LkNoUCwgYWVzKFNwcmluZ18xLCBTcHJpbmdfMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1Qc2V1ZG90aW1lKSwgc2l6ZT0yLCBzaGFwZT0xNikgKyAKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoY29scyksIG5hbWU9J1BzZXVkb3RpbWUgc2NvcmUnKQpgYGAKYGBge3J9ClRyYWplY3RvcnkuQ2hQJENlbGwuc3RhdGUgPC0gY3V0KFRyYWplY3RvcnkuQ2hQJFBzZXVkb3RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIkVhcmx5IiwiTWlkIiwiTGF0ZSIpKQpgYGAKCmBgYHtyfQpUcmFqZWN0b3J5LkNoUCRDZWxsLnN0YXRlIDwtIHBhc3RlMChUcmFqZWN0b3J5LkNoUCRDZWxsX2lkZW50LCAiXyIsIFRyYWplY3RvcnkuQ2hQJENlbGwuc3RhdGUpCgpnZ3Bsb3QoVHJhamVjdG9yeS5DaFAsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IENlbGwuc3RhdGUpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiM2OGIwNDEiLCAiI2UzYzE0OCIsICIjYjdkMTc0IikpCmBgYAoKIyBEaWZmZXJlbnRpYXRpbmcgbmV1cm9ucyB0cmFqZWN0b3J5CgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtICBzdWJzZXQoSGVtLmRhdGEsIGlkZW50cyA9IGMoIkNhamFsLVJldHppdXNfbmV1cm9ucyIsICJQYWxsaWFsX25ldXJvbnMiKSkKCkRpbVBsb3QoTmV1cm9ucy5kYXRhICwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBwdC5zaXplID0gMSwKICAgICAgICBjb2xzID0gIGMoIiNjYzM5MWIiLCIjMDI2YzlhIikKICAgICAgICApICsgTm9BeGVzKCkKYGBgCiMjIENhamFsLVJldHppdXMgY2VsbHMKCmBgYHtyfQpUcmFqZWN0b3JpZXMuSGVtIDwtIE5ldXJvbnMuZGF0YUBtZXRhLmRhdGEgJT4lCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KCJCYXJjb2RlcyIsICJTcHJpbmdfMSIsICJTcHJpbmdfMiIsICJDZWxsX2lkZW50IikgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENlbGxfaWRlbnQgPT0gIkNhamFsLVJldHppdXNfbmV1cm9ucyIpCmBgYAoKYGBge3J9CmZpdCA8LSBwcmluY2lwYWxfY3VydmUoYXMubWF0cml4KFRyYWplY3Rvcmllcy5IZW1bLGMoIlNwcmluZ18xIiwgIlNwcmluZ18yIildKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAuNywKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWUgPC0gZml0JGxhbWJkYS9tYXgoZml0JGxhbWJkYSkKYGBgCgpgYGB7cn0KaWYgKGNvcihUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWUsIE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbJ0htZ2EyJywgVHJhamVjdG9yaWVzLkhlbSRCYXJjb2Rlc10pID4gMCkgewogIFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZSA8LSAtKFRyYWplY3Rvcmllcy5IZW0kUHNldWRvdGltZSAtIG1heChUcmFqZWN0b3JpZXMuSGVtJFBzZXVkb3RpbWUpKQp9CmBgYAoKIyMgUGFsbGlhbCBuZXVyb25zCgpgYGB7cn0KVHJhamVjdG9yaWVzLlBhbGxpYWwgPC0gTmV1cm9ucy5kYXRhQG1ldGEuZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KCJCYXJjb2RlcyIsICJTcHJpbmdfMSIsICJTcHJpbmdfMiIsICJDZWxsX2lkZW50IikgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihDZWxsX2lkZW50ID09ICJQYWxsaWFsX25ldXJvbnMiKQogICAgICAgICAgICAgICAgICAKYGBgCgpgYGB7cn0KZml0IDwtIHByaW5jaXBhbF9jdXJ2ZShhcy5tYXRyaXgoVHJhamVjdG9yaWVzLlBhbGxpYWxbLGMoIlNwcmluZ18xIiwgIlNwcmluZ18yIildKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAuNywKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCgojUHNldWRvdGltZSBzY29yZQpUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lIDwtIGZpdCRsYW1iZGEvbWF4KGZpdCRsYW1iZGEpCmBgYAoKYGBge3J9CmlmIChjb3IoVHJhamVjdG9yaWVzLlBhbGxpYWwkUHNldWRvdGltZSwgTmV1cm9ucy5kYXRhQGFzc2F5cyRTQ1RAZGF0YVsnSG1nYTInLCBUcmFqZWN0b3JpZXMuUGFsbGlhbCRCYXJjb2Rlc10pID4gMCkgewogIFRyYWplY3Rvcmllcy5QYWxsaWFsJFBzZXVkb3RpbWUgPC0gLShUcmFqZWN0b3JpZXMuUGFsbGlhbCRQc2V1ZG90aW1lIC0gbWF4KFRyYWplY3Rvcmllcy5QYWxsaWFsJFBzZXVkb3RpbWUpKQp9CmBgYAoKIyMgQ29tYmluZSB0aGUgdHdvIHRyYWplY3RvcmllcycgZGF0YQoKYGBge3J9ClRyYWplY3Rvcmllcy5uZXVyb25zIDwtIHJiaW5kKFRyYWplY3Rvcmllcy5QYWxsaWFsLCBUcmFqZWN0b3JpZXMuSGVtKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UHNldWRvdGltZSksIHNpemU9Miwgc2hhcGU9MTYpICsgCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnM9cmV2KGNvbHMpLCBuYW1lPSdQc2V1ZG90aW1lIHNjb3JlJykKYGBgCgpgYGB7cn0KaGlzdChUcmFqZWN0b3JpZXMubmV1cm9ucyRQc2V1ZG90aW1lLCBicmVha3MgPSAxMDApCmFibGluZSh2PWMoMC40LDAuNjgpLCBjb2wgPSJibHVlIikKYGBgCgoKYGBge3J9ClRyYWplY3Rvcmllcy5uZXVyb25zJENlbGwuc3RhdGUgPC0gY3V0KFRyYWplY3Rvcmllcy5uZXVyb25zJFBzZXVkb3RpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoMCwwLjQsMC42OCwxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiQlAiLCJFTiIsIkxOIikpCgpnZ3Bsb3QoVHJhamVjdG9yaWVzLm5ldXJvbnMsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IENlbGwuc3RhdGUpLCBzaXplPTAuNSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IGMoIiM2OGIwNDEiLCAiI2UzYzE0OCIsICIjYjdkMTc0IikpCmBgYAoKYGBge3J9ClRyYWplY3Rvcmllcy5uZXVyb25zJENlbGwuc3RhdGUgPC0gcGFzdGUwKFRyYWplY3Rvcmllcy5uZXVyb25zJENlbGxfaWRlbnQsICJfIiwgVHJhamVjdG9yaWVzLm5ldXJvbnMkQ2VsbC5zdGF0ZSkKYGBgCgojIFRyYW5zZmVydCBhbGwgY2VsbCBzdGF0ZSBhbm5vdGF0aW8gdG8gdGhlIGZ1bGwgZGF0YXNldAoKYGBge3J9Ck5ldy5sYWJlbHMgPC0gcmJpbmQoVHJhamVjdG9yeS5DaFAsVHJhamVjdG9yaWVzLm5ldXJvbnMpCmBgYAoKCmBgYHtyfQpIZW0uZGF0YSRDZWxsLnN0YXRlIDwtIHNhcHBseShIZW0uZGF0YSRCYXJjb2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh4ICVpbiUgTmV3LmxhYmVscyRCYXJjb2RlcykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IE5ldy5sYWJlbHNbeCwgIkNlbGwuc3RhdGUiXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gSGVtLmRhdGFAbWV0YS5kYXRhW3gsICJDZWxsX2lkZW50Il0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkKYGBgCgpgYGB7cn0KRGltUGxvdChvYmplY3QgPSBIZW0uZGF0YSwKICAgICAgICBncm91cC5ieSA9ICJDZWxsLnN0YXRlIiwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYygiIzcyOTNjOCIsICIjYjc5ZjBiIiwgIiMzY2E3M2YiLCIjMzFiNmJkIiwKICAgICAgICAgICAgIiNlYmNiMmUiLCAiIzllYzIyZiIsICIjYTk5NjFiIiwgIiNjYzNhMWIiLCAiI2QxNGM4ZCIsICIjNGNhYmRjIiwgIiM1YWI3OTMiLCAiI2U3ODIzYSIsICIjMDQ2YzlhIiwgIiM0OTkwYzkiKSkKYGBgCmBgYHtyfQpzYXZlUkRTKEhlbS5kYXRhLCAiLi4vUUMuZmlsdGVyZWQuY2x1c3RlcmVkLmNlbGxzLlJEUyIpCmBgYAoKCiMgU2Vzc2lvbiBJbmZvCgpgYGB7cn0KI2RhdGUKZm9ybWF0KFN5cy50aW1lKCksICIlZCAlQiwgJVksICVILCVNIikKCiNQYWNrYWdlcyB1c2VkCnNlc3Npb25JbmZvKCkKYGBg