Load libraries and the dataset

# Load library
library(Seurat)
library(princurve)
library(monocle)
library(parallel)
library(seriation)

library(dplyr)
library(reshape2)

library(ggplot2)
library(cowplot)
library(ggExtra)
library(patchwork)
library(RColorBrewer)
library(wesanderson)

#Set ggplot theme as classic
theme_set(theme_classic())
# Load the full annotated dataset
Allcells.data <- readRDS("./Clustered.cells.RDS")
colors <-  c("#969696", "#68b041", "#e3c148", "#b7d174", "#83c3b8", "#009fda", "#3E69ac", "#e46b6b",
              "#ec756d", "#c773a7", "#7293c8", "#b79f0b", "#3ca73f","#31b6bd", "#ebcb2e", "#9ec22f",
             "#a9961b", "#cc3a1b", "#cc8778" , "#d14c8d", "#4cabdc", "#5ab793", "#e7823a","#e6bb9b",
             "#046c9a", "#4784a2" , "#4990c9")

DimPlot(Allcells.data,
        reduction.use = "spring", 
        dim.1 = 1,
        dim.2 = 2,
        do.label=T,
        label.size = 2,
        no.legend = T,
        no.axes = T,
        cols.use = colors)

Pallial and Subpallial transition state cells

# Calculate pallial BP scores
Pal.BP.genes <- c("Eomes", "Neurog2", "Neurog1", "Prmt8", "Nrp1")
genes.list <- list(Pal.BP.genes)
enrich.name <- "Pal.BP_signature"
Allcells.data <- AddModuleScore(Allcells.data, genes.list = genes.list, genes.pool = NULL, n.bin = 5,
                          seed.use = 1, ctrl.size = length(genes.list), use.k = FALSE, enrich.name = enrich.name ,
                          random.seed = 1)

# Calculate subpallial BP scores
SP.BP.genes <- c("Dlx1", "Dlx2", "Dlx5","Ascl1", "Gsx2")
genes.list <- list(SP.BP.genes)
enrich.name <- "SP.BP_signature"
Allcells.data <- AddModuleScore(Allcells.data, genes.list = genes.list, genes.pool = NULL, n.bin = 5,
                          seed.use = 1, ctrl.size = length(genes.list), use.k = FALSE, enrich.name = enrich.name ,
                          random.seed = 1)
set.seed(100)
# Run Kmeans clustering
cl <- kmeans(cbind(Allcells.data@meta.data$SP_signature1,
                   Allcells.data@meta.data$Pal_signature1,
                   Allcells.data@meta.data$SP.BP_signature1,
                   Allcells.data@meta.data$Pal.BP_signature1), 4)

Allcells.data@meta.data$kmeanClust <- paste0("Clust.",cl$cluster)
col.pal <- wes_palette("GrandBudapest1", 4, type = "discrete")

p1 <- ggplot(Allcells.data@meta.data, aes(x=SP_signature1, y=Pal_signature1, colour = kmeanClust)) +
  scale_color_manual(values=col.pal) +
  geom_point() + 
  theme(legend.position="none")
ggMarginal(p1, type = "histogram", fill="lightgrey")

DimPlot(Allcells.data,
        group.by = "kmeanClust",
        reduction.use = "spring",
        cols.use = col.pal,
        dim.1 = 1,
        dim.2 = 2,
        do.label=T,
        no.axes = T,
        label.size = 4,
        no.legend = F)

Align pallial and subpallial cells along pseudotime

Extract Pallial and Subpallial lineages

# Extract subpallial cells
meankclust.sp.score <- aggregate(SP_signature1 ~ kmeanClust, Allcells.data@meta.data, mean)
SPclust <- meankclust.sp.score %>% filter(SP_signature1 == max(SP_signature1)) %>% pull(kmeanClust)

SPcells <- Allcells.data@meta.data %>%
                  filter( kmeanClust == SPclust ) %>%
                  pull(Barcodes)

SubPalldata <- as.data.frame(Allcells.data@dr$spring@cell.embeddings[SPcells, 1:2])
SubPalldata$Lineage <- "SubPallial"
# Extract Pallial cells
meankclust.p.score <- aggregate(Pal_signature1 ~ kmeanClust, Allcells.data@meta.data, mean)
Pclust <- meankclust.p.score %>% filter(Pal_signature1 == max(Pal_signature1)) %>% pull(kmeanClust)

meankclust.pbp.score <- aggregate(Pal.BP_signature1 ~ kmeanClust, Allcells.data@meta.data, mean)
Pbpclust <- meankclust.pbp.score%>% filter(Pal.BP_signature1 == max(Pal.BP_signature1)) %>% pull(kmeanClust)

Palcells <- Allcells.data@meta.data %>%
                  filter(kmeanClust %in% c(Pclust,Pbpclust)) %>%
                  pull(Barcodes)

Pal.data <- as.data.frame(Allcells.data@dr$spring@cell.embeddings[Palcells,1:2])
Pal.data$Lineage <- "Pallial"
# Extract AP cells
APcells <- Allcells.data@meta.data %>%
                  filter(Cluster.ident %in% grep("*AP", unique(Allcells.data@meta.data$Cluster.ident), value = T)) %>%
                  filter(!Barcodes %in% c(rownames(Pal.data), rownames(SubPalldata))) %>%
                  select(Barcodes,Cluster.ident)

AP.data <- as.data.frame(Allcells.data@dr$spring@cell.embeddings[APcells$Barcodes,1:2])

AP.data$Lineage <- sapply(as.character(APcells$Cluster.ident),
                          function(x) if(x %in% c("AP.Dorsal.Pallium", "AP.lateral.Pallium.1", "AP.lateral.Pallium.2", "AP.Ventral.Pallium")){x= "Pallial"}
                          else{x= "SubPallial"})
Pseudotime.data <- rbind(AP.data,
                         Pal.data,
                         SubPalldata)

Allcells.data <- SubsetData(Allcells.data, cells.use = rownames(Pseudotime.data), subset.raw = T,  do.clean = F)

Pseudotime.data <- Pseudotime.data[rownames(Allcells.data@meta.data),]
Pseudotime.data$Barcode <- rownames(Pseudotime.data)


Allcells.data@meta.data$Lineage <- Pseudotime.data$Lineage
DimPlot(Allcells.data,
        reduction.use = "spring",
        group.by = "Lineage",
        dim.1 = 1,
        dim.2 = 2,
        do.label=T,
        label.size = 2,
        no.legend = T,
        no.axes = T)

Fit the pallial principal curves

#Fit a principal curve to the global trajectory
Pal.data <- Pseudotime.data %>%
              filter(Lineage == "Pallial")

fit <- principal_curve(as.matrix(Pal.data[,1:2]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 77550139277
## Iteration 1---distance^2: 14983435
## Iteration 2---distance^2: 14563895
## Iteration 3---distance^2: 14248808
## Iteration 4---distance^2: 14111673
## Iteration 5---distance^2: 14101215
pc.line <- as.data.frame(fit$s[order(fit$lambda),])

Pal.data$PseudotimeScore <- fit$lambda/max(fit$lambda)



# Direction of the maturation score using Hmga2 expression (revert if positive correlation)
if (cor(Pal.data$PseudotimeScore, Allcells.data@data['Hmga2', Pal.data$Barcode]) > 0) {
  Pal.data$PseudotimeScore <- -(Pal.data$PseudotimeScore - max(Pal.data$PseudotimeScore))
}

Fit the suballial principal curve

#Fit a principal curve to the global trajectory
SubPal.data <- Pseudotime.data %>%
              filter(Lineage == "SubPallial")

fit <- principal_curve(as.matrix(SubPal.data[,1:2]),
                       smoother='lowess',
                       trace=TRUE,
                       f = .7,
                       stretch=0)
## Starting curve---distance^2: 24540041253
## Iteration 1---distance^2: 9085033
## Iteration 2---distance^2: 8834074
## Iteration 3---distance^2: 8940886
## Iteration 4---distance^2: 9103039
## Iteration 5---distance^2: 9215219
## Iteration 6---distance^2: 9230882
## Iteration 7---distance^2: 9204650
## Iteration 8---distance^2: 9183524
## Iteration 9---distance^2: 9164620
## Iteration 10---distance^2: 9159798
pc.line <- as.data.frame(fit$s[order(fit$lambda),])

SubPal.data$PseudotimeScore <- fit$lambda/max(fit$lambda)



# Direction of the maturation score using Hmga2 expression (revert if positive correlation)
if (cor(SubPal.data$PseudotimeScore, Allcells.data@data['Hmga2', SubPal.data$Barcode]) > 0) {
  SubPal.data$PseudotimeScore <- -(SubPal.data$PseudotimeScore - max(SubPal.data$PseudotimeScore))
}
Pseudotime.data <- rbind(Pal.data,
                         SubPal.data)

rownames(Pseudotime.data) <- Pseudotime.data$Barcode
Pseudotime.data <- Pseudotime.data[rownames(Allcells.data@meta.data),]

Allcells.data@meta.data$PseudotimeScore <- Pseudotime.data$PseudotimeScore
FeaturePlot(object = Allcells.data,
            features.plot = c("PseudotimeScore"),
            cols.use = rev(colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)),
            no.axes = T,
            reduction.use = "spring",
            no.legend = T)

Filter all cells dataset

Filter the gene counts matrix

# Keep only genes detected in more than 300 cells
num.cells <- Matrix::rowSums(Allcells.data@raw.data > 0)
genes.use <- names(x = num.cells[which(x = num.cells >= 300)])
Allcells.data@raw.data <- Allcells.data@raw.data[genes.use, ]

# Normalization and variable genes selection
Allcells.data <- NormalizeData(object = Allcells.data,
                         normalization.method = "LogNormalize", 
                         scale.factor = round(median(Allcells.data@meta.data$nUMI)),
                         display.progress = F)

Allcells.data <- FindVariableGenes(object = Allcells.data,
                             mean.function = ExpMean,
                             dispersion.function = LogVMR,
                             x.low.cutoff = 0.03,
                             x.high.cutoff = 4,
                             y.cutoff = 0.9, do.plot = F,
                             display.progress = F)
rm(list = ls()[!ls() %in% "Allcells.data"])

Find common transcriptional trajectory

Initialize a monocle object

# Transfer metadata
meta.data <- data.frame(barcode = rownames(Allcells.data@meta.data),
                        Cluster = Allcells.data@meta.data$Cluster.ident,
                        Lineage = Allcells.data@meta.data$Lineage,
                        Pseudotime.Score = Allcells.data@meta.data$PseudotimeScore,
                        row.names = rownames(Allcells.data@meta.data))

Annot.data  <- new('AnnotatedDataFrame', data = meta.data)

# Transfer counts data
count.data = data.frame(gene_short_name = rownames(Allcells.data@raw.data),
                        row.names = rownames(Allcells.data@raw.data))

feature.data <- new('AnnotatedDataFrame', data = count.data)

# Create the CellDataSet object
gbm_cds <- newCellDataSet(as.matrix(Allcells.data@raw.data),
                          phenoData = Annot.data,
                          featureData = feature.data,
                          lowerDetectionLimit = 1,
                          expressionFamily = negbinomial())
gbm_cds <- estimateSizeFactors(gbm_cds)
gbm_cds <- estimateDispersions(gbm_cds)
gbm_cds <- detectGenes(gbm_cds, min_expr = 0.1)
rm(list = ls()[!ls() %in% c("Allcells.data", "gbm_cds")])

Test each gene over pseudotime

# Exclude cell cycle associated genes
CCgenes <- as.character(read.table("./Progenitors/CellCycleGenes.csv", sep = "\t", header = F)[,1])
Input.genes <- Allcells.data@var.genes[!Allcells.data@var.genes %in% CCgenes]
# Split pallial and subpallial cells for gene expression fitting
#Pallial cells
Pallialcells <- Allcells.data@meta.data %>%
                  filter(Lineage == "Pallial") %>%
                  pull(Barcodes)

# Sub-pallial cells
SubPallialcells <- Allcells.data@meta.data %>%
                  filter(Lineage == "SubPallial") %>%
                  pull(Barcodes)

Pallial cells

Pseudotime.diff.Pall <- differentialGeneTest(gbm_cds[Input.genes, Pallialcells],
                                                 fullModelFormulaStr = "~sm.ns(Pseudotime.Score, df = 3)",
                                                 reducedModelFormulaStr = "~1",
                                                 cores = detectCores() - 2)

#Filter based on FDR
Pseudotime.diff.Pall.filtered <- Pseudotime.diff.Pall %>% filter(qval < 1e-3)

Subpallial cells

Pseudotime.diff.SubPallial <- differentialGeneTest(gbm_cds[Input.genes, SubPallialcells],
                                                 fullModelFormulaStr = "~sm.ns(Pseudotime.Score, df = 3)",
                                                 reducedModelFormulaStr = "~1",
                                                 cores = detectCores() - 2)

#Filter based on FDR
Pseudotime.diff.SubPallial.filtered <- Pseudotime.diff.SubPallial  %>% filter(qval < 1e-3)

Intersect the two gene lists

commonGenes <- intersect(Pseudotime.diff.Pall.filtered$gene_short_name, Pseudotime.diff.SubPallial.filtered$gene_short_name)

Smooth common genes expression along the two trajectories

# Create a new pseudo-DV vector of 200 points
nPoints <- 200

new_data = list()
for (Lineage in unique(pData(gbm_cds)$Lineage)){
  new_data[[length(new_data) + 1]] = data.frame(Pseudotime.Score = seq(min(pData(gbm_cds)$Pseudotime.Score), max(pData(gbm_cds)$Pseudotime.Score), length.out = nPoints), Lineage=Lineage)
}

new_data = do.call(rbind, new_data)

# Smooth gene expression
curve_matrix <- genSmoothCurves(gbm_cds[as.character(commonGenes),],
                                trend_formula = "~sm.ns(Pseudotime.Score, df = 3)*Lineage",
                                relative_expr = TRUE,
                                new_data = new_data,
                                cores= detectCores() - 2)

Find DEG along the panGlutamatergic and panGABAergic trajectories

Pseudotime.lineages.diff <- differentialGeneTest(gbm_cds[Input.genes,], 
                                                 fullModelFormulaStr = "~sm.ns(Pseudotime.Score, df = 3)*Lineage", 
                                                 reducedModelFormulaStr = "~sm.ns(Pseudotime.Score, df = 3)", 
                                                 cores = detectCores() - 2)

# Filter genes based on FDR
Pseudotime.lineages.diff.filtered <- Pseudotime.lineages.diff %>% filter(qval < 1e-3)

Direction of the DEG by calculating the area between curves (ABC)

Smooth common genes along the two trajectories

# Create a new pseudo-DV vector of 200 points
nPoints <- 200

new_data = list()
for (Lineage in unique(pData(gbm_cds)$Lineage)){
  new_data[[length(new_data) + 1]] = data.frame(Pseudotime.Score = seq(min(pData(gbm_cds)$Pseudotime.Score), max(pData(gbm_cds)$Pseudotime.Score), length.out = nPoints), Lineage=Lineage)
}

new_data = do.call(rbind, new_data)

# Smooth gene expression
Diff.curve_matrix <- genSmoothCurves(gbm_cds[as.character(Pseudotime.lineages.diff.filtered$gene_short_name),],
                                      trend_formula = "~sm.ns(Pseudotime.Score, df = 3)*Lineage",
                                      relative_expr = TRUE,
                                      new_data = new_data,
                                      cores= detectCores() - 2)

Compute the ABC for each gene

SubPallial_curve_matrix <- Diff.curve_matrix[, 1:nPoints] #SubPallial points
Pallial_curve_matrix <- Diff.curve_matrix[, (nPoints + 1):(2 * nPoints)] #Pallial points
  
ABCs_res <- SubPallial_curve_matrix - Pallial_curve_matrix # Direction of the comparison : postive ABCs <=> Upregulated in SubPallial lineage
ILR_res <- log2(SubPallial_curve_matrix/ (Pallial_curve_matrix + 0.1)) # Average logFC between the 2 curves
  
ABCs_res <- apply(ABCs_res, 1, function(x, nPoints) {
                  avg_delta_x <- (x[1:(nPoints - 1)] + x[2:(nPoints)])/2
                  step <- (100/(nPoints - 1))
                  res <- round(sum(avg_delta_x * step), 3)
                  return(res)},
                  nPoints = nPoints) # Compute the area below the curve
  
ABCs_res <- cbind(ABCs_res, ILR_res[,ncol(ILR_res)])
colnames(ABCs_res)<- c("ABCs", "Endpoint_ILR")

# Import ABC values into the DE test results table
Pseudotime.lineages.diff.filtered <- cbind(Pseudotime.lineages.diff.filtered[,1:4],
                                           ABCs_res,
                                           Pseudotime.lineages.diff.filtered[,5:6])

Plot pallial specific trajectory

# Extract Pallial neurons trajectory genes
Pallial.res <- as.data.frame(Pseudotime.lineages.diff.filtered[Pseudotime.lineages.diff.filtered$ABCs < 0,])
Pallial.genes <- row.names(Pallial.res)

# We further filter genes detected in less than 300 and more than 250 cells among Pallial and Subpallial lineages, respectively
num.cells <- Matrix::rowSums(Allcells.data@raw.data[Pallial.genes, Pallialcells] > 0)
Pallial.genes <- names(x = num.cells[which(x = num.cells >= 300)])

num.cells <- Matrix::rowSums(Allcells.data@raw.data[Pallial.genes, SubPallialcells] > 0)
filtered <- names(x = num.cells[which(x = num.cells >= 250)])

Pallial.genes <- Pallial.genes[!Pallial.genes %in% filtered]

Pallial_curve_matrix <- Pallial_curve_matrix[Pallial.genes, ]
# Order rows using seriation
dst <- as.dist((1-cor(scale(t(Pallial_curve_matrix)), method = "pearson")))
row.ser <- seriate(dst, method ="GW")
gene.order <- rownames(Pallial_curve_matrix[get_order(row.ser),])

anno.colors <- list(lineage = c(Pallial="#026c9a",SubPallial="#cc391b"))


pheatmap::pheatmap(Diff.curve_matrix[gene.order,
                                c(400:201, #Pallial points
                                  1:200)], #SubPallial points
                   scale = "row",
                   cluster_rows = F,
                   cluster_cols = F,
                   annotation_col = data.frame(lineage = rep(c("SubPallial","Pallial"), each=200)),
                   annotation_colors = anno.colors,
                   show_colnames = F,
                   show_rownames = T,
                   fontsize_row = 8,
                   color =  viridis::viridis(9),
                   breaks = seq(-2.5,2.5, length.out = 9),
                   main = "")

Pallial.Common <- Pseudotime.lineages.diff.filtered[Pseudotime.lineages.diff.filtered$gene_short_name %in% Pallial.genes, ]

write.table(Pallial.Common[gene.order,], "./Trajectories/Pallial_Common_Genes.csv", sep = ";", quote = F)

Plot SubPallial specific trajectory

# Extract subPallial neurons trajectory genes
SubPallial.res <- as.data.frame(Pseudotime.lineages.diff.filtered[Pseudotime.lineages.diff.filtered$ABCs > 0,])
SubPallial.genes <- row.names(SubPallial.res)
SubPallial_curve_matrix <- SubPallial_curve_matrix[SubPallial.genes, ]
# Extract subPallial neurons trajectory genes
SubPallial.res <- as.data.frame(Pseudotime.lineages.diff.filtered[Pseudotime.lineages.diff.filtered$ABCs > 0,])
SubPallial.genes <- row.names(SubPallial.res)

# We further filter genes detected in less than 100 and more than 300 cells among Subpallial and Pallial lineages, respectively
num.cells <- Matrix::rowSums(Allcells.data@raw.data[SubPallial.genes, SubPallialcells] > 0)
SubPallial.genes <- names(x = num.cells[which(x = num.cells >= 100)])

num.cells <- Matrix::rowSums(Allcells.data@raw.data[SubPallial.genes, Pallialcells] > 0)
filtered <- names(x = num.cells[which(x = num.cells >= 300)])

SubPallial.genes <- SubPallial.genes[!SubPallial.genes%in% filtered]

SubPallial_curve_matrix <- SubPallial_curve_matrix[SubPallial.genes, ]
# Order rows using seriation
dst <- as.dist((1-cor(scale(t(SubPallial_curve_matrix)), method = "pearson")))
row.ser <- seriate(dst, method ="GW")
gene.order <- rownames(SubPallial_curve_matrix[get_order(row.ser),])

anno.colors <- list(lineage = c(Pallial="#026c9a",SubPallial="#cc391b"))


pheatmap::pheatmap(Diff.curve_matrix[gene.order,
                                c(400:201, #Pallial points
                                  1:200)], #SubPallial points
                   scale = "row",
                   cluster_rows = F,
                   cluster_cols = F,
                   annotation_col = data.frame(lineage = rep(c("SubPallial","Pallial"), each=200)),
                   annotation_colors = anno.colors,
                   show_colnames = F,
                   show_rownames = T,
                   fontsize_row = 8,
                   color =  viridis::viridis(9),
                   breaks = seq(-2.5,2.5, length.out = 9),
                   main = "")

SubPallial.Common <- Pseudotime.lineages.diff.filtered[Pseudotime.lineages.diff.filtered$gene_short_name %in% SubPallial.genes, ]

write.table(SubPallial.Common[gene.order,], "./Trajectories/SubPallial_Common_Genes.csv", sep = ";", quote = F)

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "03 mai, 2021, 11,51"
#Packages used
sessionInfo()
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.5 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3.10.3
## LAPACK: /usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3.10.3
## 
## 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] splines   stats4    parallel  stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] wesanderson_0.3.6   RColorBrewer_1.1-2  patchwork_0.0.1    
##  [4] ggExtra_0.9         reshape2_1.4.3      dplyr_0.8.3        
##  [7] seriation_1.2-9     monocle_2.14.0      DDRTree_0.1.5      
## [10] irlba_2.3.3         VGAM_1.1-2          Biobase_2.46.0     
## [13] BiocGenerics_0.32.0 princurve_2.1.4     Seurat_2.3.4       
## [16] Matrix_1.2-17       cowplot_1.0.0       ggplot2_3.2.1      
## 
## loaded via a namespace (and not attached):
##   [1] snow_0.4-3           backports_1.1.5      Hmisc_4.3-0         
##   [4] plyr_1.8.4           igraph_1.2.5         lazyeval_0.2.2      
##   [7] densityClust_0.3     fastICA_1.2-2        digest_0.6.25       
##  [10] foreach_1.4.7        htmltools_0.5.0      viridis_0.5.1       
##  [13] lars_1.2             gdata_2.18.0         magrittr_1.5        
##  [16] checkmate_1.9.4      cluster_2.1.0        gclus_1.3.2         
##  [19] mixtools_1.1.0       ROCR_1.0-7           limma_3.42.0        
##  [22] matrixStats_0.55.0   R.utils_2.9.0        docopt_0.6.1        
##  [25] colorspace_1.4-1     ggrepel_0.8.1        xfun_0.18           
##  [28] sparsesvd_0.2        crayon_1.4.0         jsonlite_1.7.0      
##  [31] zeallot_0.1.0        survival_2.44-1.1    zoo_1.8-6           
##  [34] iterators_1.0.12     ape_5.3              glue_1.4.1          
##  [37] registry_0.5-1       gtable_0.3.0         kernlab_0.9-29      
##  [40] prabclus_2.3-1       DEoptimR_1.0-8       scales_1.1.0        
##  [43] pheatmap_1.0.12      bibtex_0.4.2         miniUI_0.1.1.1      
##  [46] Rcpp_1.0.5           metap_1.1            dtw_1.21-3          
##  [49] xtable_1.8-4         viridisLite_0.3.0    htmlTable_1.13.2    
##  [52] reticulate_1.18      foreign_0.8-72       bit_4.0.4           
##  [55] proxy_0.4-23         mclust_5.4.5         SDMTools_1.1-221.1  
##  [58] Formula_1.2-3        tsne_0.1-3           htmlwidgets_1.5.1   
##  [61] httr_1.4.1           FNN_1.1.3            gplots_3.0.1.1      
##  [64] fpc_2.2-3            acepack_1.4.1        modeltools_0.2-22   
##  [67] ica_1.0-2            farver_2.0.1         pkgconfig_2.0.3     
##  [70] R.methodsS3_1.7.1    flexmix_2.3-15       nnet_7.3-14         
##  [73] labeling_0.3         later_1.0.0          tidyselect_0.2.5    
##  [76] rlang_0.4.7          munsell_0.5.0        tools_3.6.3         
##  [79] ggridges_0.5.1       fastmap_1.0.1        evaluate_0.14       
##  [82] stringr_1.4.0        yaml_2.2.1           npsurv_0.4-0        
##  [85] knitr_1.26           bit64_4.0.2          fitdistrplus_1.0-14 
##  [88] robustbase_0.93-5    caTools_1.17.1.2     purrr_0.3.3         
##  [91] RANN_2.6.1           pbapply_1.4-2        nlme_3.1-141        
##  [94] mime_0.7             slam_0.1-46          R.oo_1.23.0         
##  [97] hdf5r_1.3.2.9000     compiler_3.6.3       rstudioapi_0.11     
## [100] png_0.1-7            lsei_1.2-0           tibble_2.1.3        
## [103] stringi_1.4.6        lattice_0.20-41      HSMMSingleCell_1.6.0
## [106] vctrs_0.2.0          pillar_1.4.2         lifecycle_0.1.0     
## [109] combinat_0.0-8       Rdpack_0.11-0        lmtest_0.9-37       
## [112] data.table_1.12.6    bitops_1.0-6         gbRd_0.4-11         
## [115] httpuv_1.5.2         R6_2.4.1             latticeExtra_0.6-28 
## [118] promises_1.1.0       TSP_1.1-10           KernSmooth_2.23-15  
## [121] gridExtra_2.3        codetools_0.2-16     MASS_7.3-53         
## [124] gtools_3.8.1         assertthat_0.2.1     withr_2.1.2         
## [127] qlcMatrix_0.9.7      diptest_0.75-7       doSNOW_1.0.18       
## [130] grid_3.6.3           rpart_4.1-15         tidyr_1.0.0         
## [133] class_7.3-17         rmarkdown_2.5        segmented_1.0-0     
## [136] Rtsne_0.15           shiny_1.4.0          base64enc_0.1-3

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

LS0tCnRpdGxlOiAnQ29tcGFyaXNvbiBvZiBwYWxsaWFsIGFuZCBzdWJwYWxsaWFsIG5ldXJvZ2VuZXNpcycKYXV0aG9yOgogICAtIE1hdHRoaWV1IE1vcmVhdV5bSW5zdGl0dXRlIG9mIFBzeWNoaWF0cnkgYW5kIE5ldXJvc2NpZW5jZSBvZiBQYXJpcywgSU5TRVJNIFUxMjY2LCA3NTAxNCwgUGFyaXMsIEZyYW5jZSwgbWF0dGhpZXUubW9yZWF1QGluc2VybS5mcl0gWyFbXShodHRwczovL29yY2lkLm9yZy9zaXRlcy9kZWZhdWx0L2ZpbGVzL2ltYWdlcy9vcmNpZF8xNngxNi5wbmcpXShodHRwczovL29yY2lkLm9yZy8wMDAwLTAwMDItMjU5Mi0yMzczKQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGRmX3ByaW50OiB0aWJibGUKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgaW5jbHVkZXM6CiAgICAgIGluX2hlYWRlcjogaGVhZGVyLmh0bWwKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwotLS0KCmBgYHtjc3MsIGVjaG89RkFMU0V9CmgxIHsKICBmb250LXNpemU6IDM0cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjZTY0ZDAwOwogIHRleHQtZGVjb3JhdGlvbjogbm9uZTsKfQpoMS50aXRsZSB7CiAgZm9udC1zaXplOiA0MHB4OwogIG1hcmdpbi10b3A6IDJyZW07CiAgbWFyZ2luLWJvdHRvbTogMXJlbTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwogIGNvbG9yOiAjMDAwMDAwOwp9CmgyIHsKICBmb250LXNpemU6IDMwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9CmgzIHsKICBmb250LXNpemU6IDI0cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cmg0IHsKICBmb250LXNpemU6IDIwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cmg1IHsKICBmb250LXNpemU6IDE4cHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIGNvbG9yOiAjMDAwMDAwOwp9Cgouc2Nyb2xsLTEwMCB7CiAgbWF4LWhlaWdodDogMjAwcHg7CiAgb3ZlcmZsb3cteTogYXV0bzsKICBiYWNrZ3JvdW5kLWNvbG9yOiBpbmhlcml0Owp9CgpwIHsKICBmb250LXNpemU6IDE2cHg7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSkKYGBgCgojIExvYWQgbGlicmFyaWVzIGFuZCB0aGUgZGF0YXNldAoKYGBge3IgfQojIExvYWQgbGlicmFyeQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShwcmluY3VydmUpCmxpYnJhcnkobW9ub2NsZSkKbGlicmFyeShwYXJhbGxlbCkKbGlicmFyeShzZXJpYXRpb24pCgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJlc2hhcGUyKQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dFeHRyYSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQoKI1NldCBnZ3Bsb3QgdGhlbWUgYXMgY2xhc3NpYwp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpgYGAKCmBgYHtyfQojIExvYWQgdGhlIGZ1bGwgYW5ub3RhdGVkIGRhdGFzZXQKQWxsY2VsbHMuZGF0YSA8LSByZWFkUkRTKCIuL0NsdXN0ZXJlZC5jZWxscy5SRFMiKQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg4LCA2KX0KY29sb3JzIDwtICBjKCIjOTY5Njk2IiwgIiM2OGIwNDEiLCAiI2UzYzE0OCIsICIjYjdkMTc0IiwgIiM4M2MzYjgiLCAiIzAwOWZkYSIsICIjM0U2OWFjIiwgIiNlNDZiNmIiLAogICAgICAgICAgICAgICIjZWM3NTZkIiwgIiNjNzczYTciLCAiIzcyOTNjOCIsICIjYjc5ZjBiIiwgIiMzY2E3M2YiLCIjMzFiNmJkIiwgIiNlYmNiMmUiLCAiIzllYzIyZiIsCiAgICAgICAgICAgICAiI2E5OTYxYiIsICIjY2MzYTFiIiwgIiNjYzg3NzgiICwgIiNkMTRjOGQiLCAiIzRjYWJkYyIsICIjNWFiNzkzIiwgIiNlNzgyM2EiLCIjZTZiYjliIiwKICAgICAgICAgICAgICIjMDQ2YzlhIiwgIiM0Nzg0YTIiICwgIiM0OTkwYzkiKQoKRGltUGxvdChBbGxjZWxscy5kYXRhLAogICAgICAgIHJlZHVjdGlvbi51c2UgPSAic3ByaW5nIiwgCiAgICAgICAgZGltLjEgPSAxLAogICAgICAgIGRpbS4yID0gMiwKICAgICAgICBkby5sYWJlbD1ULAogICAgICAgIGxhYmVsLnNpemUgPSAyLAogICAgICAgIG5vLmxlZ2VuZCA9IFQsCiAgICAgICAgbm8uYXhlcyA9IFQsCiAgICAgICAgY29scy51c2UgPSBjb2xvcnMpCmBgYAoKIyBQYWxsaWFsIGFuZCBTdWJwYWxsaWFsIHRyYW5zaXRpb24gc3RhdGUgY2VsbHMKCmBgYHtyfQojIENhbGN1bGF0ZSBwYWxsaWFsIEJQIHNjb3JlcwpQYWwuQlAuZ2VuZXMgPC0gYygiRW9tZXMiLCAiTmV1cm9nMiIsICJOZXVyb2cxIiwgIlBybXQ4IiwgIk5ycDEiKQpnZW5lcy5saXN0IDwtIGxpc3QoUGFsLkJQLmdlbmVzKQplbnJpY2gubmFtZSA8LSAiUGFsLkJQX3NpZ25hdHVyZSIKQWxsY2VsbHMuZGF0YSA8LSBBZGRNb2R1bGVTY29yZShBbGxjZWxscy5kYXRhLCBnZW5lcy5saXN0ID0gZ2VuZXMubGlzdCwgZ2VuZXMucG9vbCA9IE5VTEwsIG4uYmluID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkLnVzZSA9IDEsIGN0cmwuc2l6ZSA9IGxlbmd0aChnZW5lcy5saXN0KSwgdXNlLmsgPSBGQUxTRSwgZW5yaWNoLm5hbWUgPSBlbnJpY2gubmFtZSAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSAxKQoKIyBDYWxjdWxhdGUgc3VicGFsbGlhbCBCUCBzY29yZXMKU1AuQlAuZ2VuZXMgPC0gYygiRGx4MSIsICJEbHgyIiwgIkRseDUiLCJBc2NsMSIsICJHc3gyIikKZ2VuZXMubGlzdCA8LSBsaXN0KFNQLkJQLmdlbmVzKQplbnJpY2gubmFtZSA8LSAiU1AuQlBfc2lnbmF0dXJlIgpBbGxjZWxscy5kYXRhIDwtIEFkZE1vZHVsZVNjb3JlKEFsbGNlbGxzLmRhdGEsIGdlbmVzLmxpc3QgPSBnZW5lcy5saXN0LCBnZW5lcy5wb29sID0gTlVMTCwgbi5iaW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQudXNlID0gMSwgY3RybC5zaXplID0gbGVuZ3RoKGdlbmVzLmxpc3QpLCB1c2UuayA9IEZBTFNFLCBlbnJpY2gubmFtZSA9IGVucmljaC5uYW1lICwKICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDEpCmBgYAoKYGBge3J9CnNldC5zZWVkKDEwMCkKIyBSdW4gS21lYW5zIGNsdXN0ZXJpbmcKY2wgPC0ga21lYW5zKGNiaW5kKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJFNQX3NpZ25hdHVyZTEsCiAgICAgICAgICAgICAgICAgICBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRQYWxfc2lnbmF0dXJlMSwKICAgICAgICAgICAgICAgICAgIEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJFNQLkJQX3NpZ25hdHVyZTEsCiAgICAgICAgICAgICAgICAgICBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRQYWwuQlBfc2lnbmF0dXJlMSksIDQpCgpBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRrbWVhbkNsdXN0IDwtIHBhc3RlMCgiQ2x1c3QuIixjbCRjbHVzdGVyKQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg1LjMsIDQpfQpjb2wucGFsIDwtIHdlc19wYWxldHRlKCJHcmFuZEJ1ZGFwZXN0MSIsIDQsIHR5cGUgPSAiZGlzY3JldGUiKQoKcDEgPC0gZ2dwbG90KEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhLCBhZXMoeD1TUF9zaWduYXR1cmUxLCB5PVBhbF9zaWduYXR1cmUxLCBjb2xvdXIgPSBrbWVhbkNsdXN0KSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sLnBhbCkgKwogIGdlb21fcG9pbnQoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmdnTWFyZ2luYWwocDEsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikKCkRpbVBsb3QoQWxsY2VsbHMuZGF0YSwKICAgICAgICBncm91cC5ieSA9ICJrbWVhbkNsdXN0IiwKICAgICAgICByZWR1Y3Rpb24udXNlID0gInNwcmluZyIsCiAgICAgICAgY29scy51c2UgPSBjb2wucGFsLAogICAgICAgIGRpbS4xID0gMSwKICAgICAgICBkaW0uMiA9IDIsCiAgICAgICAgZG8ubGFiZWw9VCwKICAgICAgICBuby5heGVzID0gVCwKICAgICAgICBsYWJlbC5zaXplID0gNCwKICAgICAgICBuby5sZWdlbmQgPSBGKQpgYGAKCiMgQWxpZ24gcGFsbGlhbCBhbmQgc3VicGFsbGlhbCBjZWxscyBhbG9uZyBwc2V1ZG90aW1lCgojIyBFeHRyYWN0IFBhbGxpYWwgYW5kIFN1YnBhbGxpYWwgbGluZWFnZXMKCmBgYHtyfQojIEV4dHJhY3Qgc3VicGFsbGlhbCBjZWxscwptZWFua2NsdXN0LnNwLnNjb3JlIDwtIGFnZ3JlZ2F0ZShTUF9zaWduYXR1cmUxIH4ga21lYW5DbHVzdCwgQWxsY2VsbHMuZGF0YUBtZXRhLmRhdGEsIG1lYW4pClNQY2x1c3QgPC0gbWVhbmtjbHVzdC5zcC5zY29yZSAlPiUgZmlsdGVyKFNQX3NpZ25hdHVyZTEgPT0gbWF4KFNQX3NpZ25hdHVyZTEpKSAlPiUgcHVsbChrbWVhbkNsdXN0KQoKU1BjZWxscyA8LSBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKCBrbWVhbkNsdXN0ID09IFNQY2x1c3QgKSAlPiUKICAgICAgICAgICAgICAgICAgcHVsbChCYXJjb2RlcykKClN1YlBhbGxkYXRhIDwtIGFzLmRhdGEuZnJhbWUoQWxsY2VsbHMuZGF0YUBkciRzcHJpbmdAY2VsbC5lbWJlZGRpbmdzW1NQY2VsbHMsIDE6Ml0pClN1YlBhbGxkYXRhJExpbmVhZ2UgPC0gIlN1YlBhbGxpYWwiCmBgYAoKYGBge3J9CiMgRXh0cmFjdCBQYWxsaWFsIGNlbGxzCm1lYW5rY2x1c3QucC5zY29yZSA8LSBhZ2dyZWdhdGUoUGFsX3NpZ25hdHVyZTEgfiBrbWVhbkNsdXN0LCBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSwgbWVhbikKUGNsdXN0IDwtIG1lYW5rY2x1c3QucC5zY29yZSAlPiUgZmlsdGVyKFBhbF9zaWduYXR1cmUxID09IG1heChQYWxfc2lnbmF0dXJlMSkpICU+JSBwdWxsKGttZWFuQ2x1c3QpCgptZWFua2NsdXN0LnBicC5zY29yZSA8LSBhZ2dyZWdhdGUoUGFsLkJQX3NpZ25hdHVyZTEgfiBrbWVhbkNsdXN0LCBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSwgbWVhbikKUGJwY2x1c3QgPC0gbWVhbmtjbHVzdC5wYnAuc2NvcmUlPiUgZmlsdGVyKFBhbC5CUF9zaWduYXR1cmUxID09IG1heChQYWwuQlBfc2lnbmF0dXJlMSkpICU+JSBwdWxsKGttZWFuQ2x1c3QpCgpQYWxjZWxscyA8LSBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGttZWFuQ2x1c3QgJWluJSBjKFBjbHVzdCxQYnBjbHVzdCkpICU+JQogICAgICAgICAgICAgICAgICBwdWxsKEJhcmNvZGVzKQoKUGFsLmRhdGEgPC0gYXMuZGF0YS5mcmFtZShBbGxjZWxscy5kYXRhQGRyJHNwcmluZ0BjZWxsLmVtYmVkZGluZ3NbUGFsY2VsbHMsMToyXSkKUGFsLmRhdGEkTGluZWFnZSA8LSAiUGFsbGlhbCIKYGBgCgpgYGB7cn0KIyBFeHRyYWN0IEFQIGNlbGxzCkFQY2VsbHMgPC0gQWxsY2VsbHMuZGF0YUBtZXRhLmRhdGEgJT4lCiAgICAgICAgICAgICAgICAgIGZpbHRlcihDbHVzdGVyLmlkZW50ICVpbiUgZ3JlcCgiKkFQIiwgdW5pcXVlKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJENsdXN0ZXIuaWRlbnQpLCB2YWx1ZSA9IFQpKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKCFCYXJjb2RlcyAlaW4lIGMocm93bmFtZXMoUGFsLmRhdGEpLCByb3duYW1lcyhTdWJQYWxsZGF0YSkpKSAlPiUKICAgICAgICAgICAgICAgICAgc2VsZWN0KEJhcmNvZGVzLENsdXN0ZXIuaWRlbnQpCgpBUC5kYXRhIDwtIGFzLmRhdGEuZnJhbWUoQWxsY2VsbHMuZGF0YUBkciRzcHJpbmdAY2VsbC5lbWJlZGRpbmdzW0FQY2VsbHMkQmFyY29kZXMsMToyXSkKCkFQLmRhdGEkTGluZWFnZSA8LSBzYXBwbHkoYXMuY2hhcmFjdGVyKEFQY2VsbHMkQ2x1c3Rlci5pZGVudCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgaWYoeCAlaW4lIGMoIkFQLkRvcnNhbC5QYWxsaXVtIiwgIkFQLmxhdGVyYWwuUGFsbGl1bS4xIiwgIkFQLmxhdGVyYWwuUGFsbGl1bS4yIiwgIkFQLlZlbnRyYWwuUGFsbGl1bSIpKXt4PSAiUGFsbGlhbCJ9CiAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZXt4PSAiU3ViUGFsbGlhbCJ9KQpgYGAKCmBgYHtyfQpQc2V1ZG90aW1lLmRhdGEgPC0gcmJpbmQoQVAuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIFBhbC5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgU3ViUGFsbGRhdGEpCgpBbGxjZWxscy5kYXRhIDwtIFN1YnNldERhdGEoQWxsY2VsbHMuZGF0YSwgY2VsbHMudXNlID0gcm93bmFtZXMoUHNldWRvdGltZS5kYXRhKSwgc3Vic2V0LnJhdyA9IFQsICBkby5jbGVhbiA9IEYpCgpQc2V1ZG90aW1lLmRhdGEgPC0gUHNldWRvdGltZS5kYXRhW3Jvd25hbWVzKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhKSxdClBzZXVkb3RpbWUuZGF0YSRCYXJjb2RlIDwtIHJvd25hbWVzKFBzZXVkb3RpbWUuZGF0YSkKCgpBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRMaW5lYWdlIDwtIFBzZXVkb3RpbWUuZGF0YSRMaW5lYWdlCmBgYAoKYGBge3IgZmlnLmRpbT1jKDgsIDYpfQpEaW1QbG90KEFsbGNlbGxzLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uLnVzZSA9ICJzcHJpbmciLAogICAgICAgIGdyb3VwLmJ5ID0gIkxpbmVhZ2UiLAogICAgICAgIGRpbS4xID0gMSwKICAgICAgICBkaW0uMiA9IDIsCiAgICAgICAgZG8ubGFiZWw9VCwKICAgICAgICBsYWJlbC5zaXplID0gMiwKICAgICAgICBuby5sZWdlbmQgPSBULAogICAgICAgIG5vLmF4ZXMgPSBUKQpgYGAKCiMjIEZpdCB0aGUgcGFsbGlhbCBwcmluY2lwYWwgY3VydmVzCgpgYGB7cn0KI0ZpdCBhIHByaW5jaXBhbCBjdXJ2ZSB0byB0aGUgZ2xvYmFsIHRyYWplY3RvcnkKUGFsLmRhdGEgPC0gUHNldWRvdGltZS5kYXRhICU+JQogICAgICAgICAgICAgIGZpbHRlcihMaW5lYWdlID09ICJQYWxsaWFsIikKCmZpdCA8LSBwcmluY2lwYWxfY3VydmUoYXMubWF0cml4KFBhbC5kYXRhWywxOjJdKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAuNywKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCgpwYy5saW5lIDwtIGFzLmRhdGEuZnJhbWUoZml0JHNbb3JkZXIoZml0JGxhbWJkYSksXSkKClBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQoKCgojIERpcmVjdGlvbiBvZiB0aGUgbWF0dXJhdGlvbiBzY29yZSB1c2luZyBIbWdhMiBleHByZXNzaW9uIChyZXZlcnQgaWYgcG9zaXRpdmUgY29ycmVsYXRpb24pCmlmIChjb3IoUGFsLmRhdGEkUHNldWRvdGltZVNjb3JlLCBBbGxjZWxscy5kYXRhQGRhdGFbJ0htZ2EyJywgUGFsLmRhdGEkQmFyY29kZV0pID4gMCkgewogIFBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSAtKFBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSAtIG1heChQYWwuZGF0YSRQc2V1ZG90aW1lU2NvcmUpKQp9CmBgYAoKIyMgRml0IHRoZSBzdWJhbGxpYWwgcHJpbmNpcGFsIGN1cnZlCgpgYGB7cn0KI0ZpdCBhIHByaW5jaXBhbCBjdXJ2ZSB0byB0aGUgZ2xvYmFsIHRyYWplY3RvcnkKU3ViUGFsLmRhdGEgPC0gUHNldWRvdGltZS5kYXRhICU+JQogICAgICAgICAgICAgIGZpbHRlcihMaW5lYWdlID09ICJTdWJQYWxsaWFsIikKCmZpdCA8LSBwcmluY2lwYWxfY3VydmUoYXMubWF0cml4KFN1YlBhbC5kYXRhWywxOjJdKSwKICAgICAgICAgICAgICAgICAgICAgICBzbW9vdGhlcj0nbG93ZXNzJywKICAgICAgICAgICAgICAgICAgICAgICB0cmFjZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGYgPSAuNywKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCgpwYy5saW5lIDwtIGFzLmRhdGEuZnJhbWUoZml0JHNbb3JkZXIoZml0JGxhbWJkYSksXSkKClN1YlBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQoKCgojIERpcmVjdGlvbiBvZiB0aGUgbWF0dXJhdGlvbiBzY29yZSB1c2luZyBIbWdhMiBleHByZXNzaW9uIChyZXZlcnQgaWYgcG9zaXRpdmUgY29ycmVsYXRpb24pCmlmIChjb3IoU3ViUGFsLmRhdGEkUHNldWRvdGltZVNjb3JlLCBBbGxjZWxscy5kYXRhQGRhdGFbJ0htZ2EyJywgU3ViUGFsLmRhdGEkQmFyY29kZV0pID4gMCkgewogIFN1YlBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSAtKFN1YlBhbC5kYXRhJFBzZXVkb3RpbWVTY29yZSAtIG1heChTdWJQYWwuZGF0YSRQc2V1ZG90aW1lU2NvcmUpKQp9CmBgYAoKYGBge3J9ClBzZXVkb3RpbWUuZGF0YSA8LSByYmluZChQYWwuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIFN1YlBhbC5kYXRhKQoKcm93bmFtZXMoUHNldWRvdGltZS5kYXRhKSA8LSBQc2V1ZG90aW1lLmRhdGEkQmFyY29kZQpQc2V1ZG90aW1lLmRhdGEgPC0gUHNldWRvdGltZS5kYXRhW3Jvd25hbWVzKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhKSxdCgpBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRQc2V1ZG90aW1lU2NvcmUgPC0gUHNldWRvdGltZS5kYXRhJFBzZXVkb3RpbWVTY29yZQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg4LCA2KX0KRmVhdHVyZVBsb3Qob2JqZWN0ID0gQWxsY2VsbHMuZGF0YSwKICAgICAgICAgICAgZmVhdHVyZXMucGxvdCA9IGMoIlBzZXVkb3RpbWVTY29yZSIpLAogICAgICAgICAgICBjb2xzLnVzZSA9IHJldihjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKSkoMTAwKSksCiAgICAgICAgICAgIG5vLmF4ZXMgPSBULAogICAgICAgICAgICByZWR1Y3Rpb24udXNlID0gInNwcmluZyIsCiAgICAgICAgICAgIG5vLmxlZ2VuZCA9IFQpCmBgYAoKIyBGaWx0ZXIgYWxsIGNlbGxzIGRhdGFzZXQKCiMjIEZpbHRlciB0aGUgZ2VuZSBjb3VudHMgbWF0cml4CgpgYGB7cn0KIyBLZWVwIG9ubHkgZ2VuZXMgZGV0ZWN0ZWQgaW4gbW9yZSB0aGFuIDMwMCBjZWxscwpudW0uY2VsbHMgPC0gTWF0cml4Ojpyb3dTdW1zKEFsbGNlbGxzLmRhdGFAcmF3LmRhdGEgPiAwKQpnZW5lcy51c2UgPC0gbmFtZXMoeCA9IG51bS5jZWxsc1t3aGljaCh4ID0gbnVtLmNlbGxzID49IDMwMCldKQpBbGxjZWxscy5kYXRhQHJhdy5kYXRhIDwtIEFsbGNlbGxzLmRhdGFAcmF3LmRhdGFbZ2VuZXMudXNlLCBdCgojIE5vcm1hbGl6YXRpb24gYW5kIHZhcmlhYmxlIGdlbmVzIHNlbGVjdGlvbgpBbGxjZWxscy5kYXRhIDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gQWxsY2VsbHMuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUuZmFjdG9yID0gcm91bmQobWVkaWFuKEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJG5VTUkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXkucHJvZ3Jlc3MgPSBGKQoKQWxsY2VsbHMuZGF0YSA8LSBGaW5kVmFyaWFibGVHZW5lcyhvYmplY3QgPSBBbGxjZWxscy5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4uZnVuY3Rpb24gPSBFeHBNZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BlcnNpb24uZnVuY3Rpb24gPSBMb2dWTVIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeC5sb3cuY3V0b2ZmID0gMC4wMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4LmhpZ2guY3V0b2ZmID0gNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5LmN1dG9mZiA9IDAuOSwgZG8ucGxvdCA9IEYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheS5wcm9ncmVzcyA9IEYpCmBgYAoKYGBge3J9CnJtKGxpc3QgPSBscygpWyFscygpICVpbiUgIkFsbGNlbGxzLmRhdGEiXSkKYGBgCgojIEZpbmQgY29tbW9uIHRyYW5zY3JpcHRpb25hbCB0cmFqZWN0b3J5CgojIyBJbml0aWFsaXplIGEgbW9ub2NsZSBvYmplY3QKCmBgYHtyfQojIFRyYW5zZmVyIG1ldGFkYXRhCm1ldGEuZGF0YSA8LSBkYXRhLmZyYW1lKGJhcmNvZGUgPSByb3duYW1lcyhBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSksCiAgICAgICAgICAgICAgICAgICAgICAgIENsdXN0ZXIgPSBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSRDbHVzdGVyLmlkZW50LAogICAgICAgICAgICAgICAgICAgICAgICBMaW5lYWdlID0gQWxsY2VsbHMuZGF0YUBtZXRhLmRhdGEkTGluZWFnZSwKICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZS5TY29yZSA9IEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhJFBzZXVkb3RpbWVTY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gcm93bmFtZXMoQWxsY2VsbHMuZGF0YUBtZXRhLmRhdGEpKQoKQW5ub3QuZGF0YSAgPC0gbmV3KCdBbm5vdGF0ZWREYXRhRnJhbWUnLCBkYXRhID0gbWV0YS5kYXRhKQoKIyBUcmFuc2ZlciBjb3VudHMgZGF0YQpjb3VudC5kYXRhID0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3duYW1lcyhBbGxjZWxscy5kYXRhQHJhdy5kYXRhKSwKICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gcm93bmFtZXMoQWxsY2VsbHMuZGF0YUByYXcuZGF0YSkpCgpmZWF0dXJlLmRhdGEgPC0gbmV3KCdBbm5vdGF0ZWREYXRhRnJhbWUnLCBkYXRhID0gY291bnQuZGF0YSkKCiMgQ3JlYXRlIHRoZSBDZWxsRGF0YVNldCBvYmplY3QKZ2JtX2NkcyA8LSBuZXdDZWxsRGF0YVNldChhcy5tYXRyaXgoQWxsY2VsbHMuZGF0YUByYXcuZGF0YSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGhlbm9EYXRhID0gQW5ub3QuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlRGF0YSA9IGZlYXR1cmUuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlckRldGVjdGlvbkxpbWl0ID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uRmFtaWx5ID0gbmVnYmlub21pYWwoKSkKYGBgCgpgYGB7cn0KZ2JtX2NkcyA8LSBlc3RpbWF0ZVNpemVGYWN0b3JzKGdibV9jZHMpCmdibV9jZHMgPC0gZXN0aW1hdGVEaXNwZXJzaW9ucyhnYm1fY2RzKQpnYm1fY2RzIDwtIGRldGVjdEdlbmVzKGdibV9jZHMsIG1pbl9leHByID0gMC4xKQpgYGAKCmBgYHtyfQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIGMoIkFsbGNlbGxzLmRhdGEiLCAiZ2JtX2NkcyIpXSkKYGBgCgojIyBUZXN0IGVhY2ggZ2VuZSBvdmVyIHBzZXVkb3RpbWUKCmBgYHtyfQojIEV4Y2x1ZGUgY2VsbCBjeWNsZSBhc3NvY2lhdGVkIGdlbmVzCkNDZ2VuZXMgPC0gYXMuY2hhcmFjdGVyKHJlYWQudGFibGUoIi4vUHJvZ2VuaXRvcnMvQ2VsbEN5Y2xlR2VuZXMuY3N2Iiwgc2VwID0gIlx0IiwgaGVhZGVyID0gRilbLDFdKQpJbnB1dC5nZW5lcyA8LSBBbGxjZWxscy5kYXRhQHZhci5nZW5lc1shQWxsY2VsbHMuZGF0YUB2YXIuZ2VuZXMgJWluJSBDQ2dlbmVzXQpgYGAKCmBgYHtyfQojIFNwbGl0IHBhbGxpYWwgYW5kIHN1YnBhbGxpYWwgY2VsbHMgZm9yIGdlbmUgZXhwcmVzc2lvbiBmaXR0aW5nCiNQYWxsaWFsIGNlbGxzClBhbGxpYWxjZWxscyA8LSBBbGxjZWxscy5kYXRhQG1ldGEuZGF0YSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKExpbmVhZ2UgPT0gIlBhbGxpYWwiKSAlPiUKICAgICAgICAgICAgICAgICAgcHVsbChCYXJjb2RlcykKCiMgU3ViLXBhbGxpYWwgY2VsbHMKU3ViUGFsbGlhbGNlbGxzIDwtIEFsbGNlbGxzLmRhdGFAbWV0YS5kYXRhICU+JQogICAgICAgICAgICAgICAgICBmaWx0ZXIoTGluZWFnZSA9PSAiU3ViUGFsbGlhbCIpICU+JQogICAgICAgICAgICAgICAgICBwdWxsKEJhcmNvZGVzKQoKYGBgCgojIyMgUGFsbGlhbCBjZWxscwoKYGBge3IgY2FjaGU9IFRSVUV9ClBzZXVkb3RpbWUuZGlmZi5QYWxsIDwtIGRpZmZlcmVudGlhbEdlbmVUZXN0KGdibV9jZHNbSW5wdXQuZ2VuZXMsIFBhbGxpYWxjZWxsc10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsTW9kZWxGb3JtdWxhU3RyID0gIn5zbS5ucyhQc2V1ZG90aW1lLlNjb3JlLCBkZiA9IDMpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjZWRNb2RlbEZvcm11bGFTdHIgPSAifjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBkZXRlY3RDb3JlcygpIC0gMikKCiNGaWx0ZXIgYmFzZWQgb24gRkRSClBzZXVkb3RpbWUuZGlmZi5QYWxsLmZpbHRlcmVkIDwtIFBzZXVkb3RpbWUuZGlmZi5QYWxsICU+JSBmaWx0ZXIocXZhbCA8IDFlLTMpCmBgYAoKIyMjIFN1YnBhbGxpYWwgY2VsbHMKCmBgYHtyIGNhY2hlPSBUUlVFfQpQc2V1ZG90aW1lLmRpZmYuU3ViUGFsbGlhbCA8LSBkaWZmZXJlbnRpYWxHZW5lVGVzdChnYm1fY2RzW0lucHV0LmdlbmVzLCBTdWJQYWxsaWFsY2VsbHNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbE1vZGVsRm9ybXVsYVN0ciA9ICJ+c20ubnMoUHNldWRvdGltZS5TY29yZSwgZGYgPSAzKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y2VkTW9kZWxGb3JtdWxhU3RyID0gIn4xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gZGV0ZWN0Q29yZXMoKSAtIDIpCgojRmlsdGVyIGJhc2VkIG9uIEZEUgpQc2V1ZG90aW1lLmRpZmYuU3ViUGFsbGlhbC5maWx0ZXJlZCA8LSBQc2V1ZG90aW1lLmRpZmYuU3ViUGFsbGlhbCAgJT4lIGZpbHRlcihxdmFsIDwgMWUtMykKYGBgCgojIyBJbnRlcnNlY3QgdGhlIHR3byBnZW5lIGxpc3RzCgpgYGB7cn0KY29tbW9uR2VuZXMgPC0gaW50ZXJzZWN0KFBzZXVkb3RpbWUuZGlmZi5QYWxsLmZpbHRlcmVkJGdlbmVfc2hvcnRfbmFtZSwgUHNldWRvdGltZS5kaWZmLlN1YlBhbGxpYWwuZmlsdGVyZWQkZ2VuZV9zaG9ydF9uYW1lKQpgYGAKCiMjIFNtb290aCBjb21tb24gZ2VuZXMgZXhwcmVzc2lvbiBhbG9uZyB0aGUgdHdvIHRyYWplY3RvcmllcwoKYGBge3IgY2FjaGU9IFRSVUV9CiMgQ3JlYXRlIGEgbmV3IHBzZXVkby1EViB2ZWN0b3Igb2YgMjAwIHBvaW50cwpuUG9pbnRzIDwtIDIwMAoKbmV3X2RhdGEgPSBsaXN0KCkKZm9yIChMaW5lYWdlIGluIHVuaXF1ZShwRGF0YShnYm1fY2RzKSRMaW5lYWdlKSl7CiAgbmV3X2RhdGFbW2xlbmd0aChuZXdfZGF0YSkgKyAxXV0gPSBkYXRhLmZyYW1lKFBzZXVkb3RpbWUuU2NvcmUgPSBzZXEobWluKHBEYXRhKGdibV9jZHMpJFBzZXVkb3RpbWUuU2NvcmUpLCBtYXgocERhdGEoZ2JtX2NkcykkUHNldWRvdGltZS5TY29yZSksIGxlbmd0aC5vdXQgPSBuUG9pbnRzKSwgTGluZWFnZT1MaW5lYWdlKQp9CgpuZXdfZGF0YSA9IGRvLmNhbGwocmJpbmQsIG5ld19kYXRhKQoKIyBTbW9vdGggZ2VuZSBleHByZXNzaW9uCmN1cnZlX21hdHJpeCA8LSBnZW5TbW9vdGhDdXJ2ZXMoZ2JtX2Nkc1thcy5jaGFyYWN0ZXIoY29tbW9uR2VuZXMpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlbmRfZm9ybXVsYSA9ICJ+c20ubnMoUHNldWRvdGltZS5TY29yZSwgZGYgPSAzKSpMaW5lYWdlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxhdGl2ZV9leHByID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfZGF0YSA9IG5ld19kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzPSBkZXRlY3RDb3JlcygpIC0gMikKYGBgCgojIyMgUGxvdCBzbW9vdGhlZCBnZW5lIHRyZW5kcyBhbG9uZyBwc2V1ZG90aW1lcwoKYGBge3IgZmlnLmRpbT1jKDUuMywgNCl9CiMgRXh0cmFjdCBnZW5lcyB3aXRoIHBlcnNvbidzIGNvciA+IDAuNiBiZXR3ZWVuIHRoZSAyIHRyYWplY3RvcmllcwoKUGFsbGlhbC5zbW9vdGhlZCA8LSBzY2FsZSh0KGN1cnZlX21hdHJpeFssYygyMDE6NDAwKV0pKSAjUGFsbGlhbCBwb2ludHMKU3ViUGFsbGlhbC5zbW9vdGhlZCA8LSBzY2FsZSh0KGN1cnZlX21hdHJpeFssYygxOjIwMCldKSkgI1N1YlBhbGxpYWwgcG9pbnRzCgptYXQgPC0gY29yKFBhbGxpYWwuc21vb3RoZWQsIFN1YlBhbGxpYWwuc21vb3RoZWQsIG1ldGhvZCA9ICJwZWFyc29uIikKCkdlbmUuQ29yIDwtIGRpYWcobWF0KQpoaXN0KEdlbmUuQ29yLGJyZWFrcyA9IDEwMCkKYWJsaW5lKHY9MC42LGNvbD1jKCJibHVlIikpCgpQYW5OZXVyby5nZW5lcyA8LSBuYW1lcyhHZW5lLkNvcltHZW5lLkNvciA+IDAuNl0pCmBgYAoKYGBge3J9CiMgV2UgZnVydGhlciBmaWx0ZXIgZ2VuZXMgZGV0ZWN0ZWQgaW4gbGVzcyB0aGFuIDMwMCBvciAxMDAgY2VsbHMgYWxvbmcgUGFsbGlhbCBvciBTdWJwYWxsaWFsIGxpbmVhZ2VzLCByZXNwZWN0aXZlbHkKbnVtLmNlbGxzIDwtIE1hdHJpeDo6cm93U3VtcyhBbGxjZWxscy5kYXRhQHJhdy5kYXRhWyxQYWxsaWFsY2VsbHNdID4gMCkKUGFsbEdlbmVzIDwtIG5hbWVzKHggPSBudW0uY2VsbHNbd2hpY2goeCA9IG51bS5jZWxscyA+PSAzMDApXSkKCm51bS5jZWxscyA8LSBNYXRyaXg6OnJvd1N1bXMoQWxsY2VsbHMuZGF0YUByYXcuZGF0YVssU3ViUGFsbGlhbGNlbGxzXSA+IDApClN1YlBhbGxHZW5lcyA8LSBuYW1lcyh4ID0gbnVtLmNlbGxzW3doaWNoKHggPSBudW0uY2VsbHMgPj0gMTAwKV0pCgpQYW5OZXVyby5nZW5lcyA8LSBQYW5OZXVyby5nZW5lc1tQYW5OZXVyby5nZW5lcyAlaW4lIGludGVyc2VjdChQYWxsR2VuZXMsIFN1YlBhbGxHZW5lcyldCmBgYAoKYGBge3J9CiMgT3JkZXIgcm93cyB1c2luZyBzZXJpYXRpb24KZHN0IDwtIGFzLmRpc3QoKDEtY29yKHNjYWxlKHQoY3VydmVfbWF0cml4W1Bhbk5ldXJvLmdlbmVzLGMoMToyMDApXSkpLCBtZXRob2QgPSAicGVhcnNvbiIpKSkKcm93LnNlciA8LSBzZXJpYXRlKGRzdCwgbWV0aG9kID0iT0xPX2NvbXBsZXRlIikKZ2VuZS5vcmRlciA8LSBQYW5OZXVyby5nZW5lc1tnZXRfb3JkZXIocm93LnNlcildCgphbm5vLmNvbG9ycyA8LSBsaXN0KGxpbmVhZ2UgPSBjKFBhbGxpYWw9IiMwMjZjOWEiLFN1YlBhbGxpYWw9IiNjYzM5MWIiKSkKCgpwaGVhdG1hcDo6cGhlYXRtYXAoY3VydmVfbWF0cml4W3JldihnZW5lLm9yZGVyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDQwMDoyMDEsICNQYWxsaWFsIHBvaW50cwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMToyMDApXSwgI1N1YlBhbGxpYWwgcG9pbnRzCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEYsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGRhdGEuZnJhbWUobGluZWFnZSA9IHJlcChjKCJTdWJQYWxsaWFsIiwiUGFsbGlhbCIpLCBlYWNoPTIwMCkpLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vLmNvbG9ycywKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcyA9IFQsCiAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSAyLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAgdmlyaWRpczo6dmlyaWRpcyg5KSwKICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMi41LDIuNSwgbGVuZ3RoLm91dCA9IDkpLAogICAgICAgICAgICAgICAgICAgbWFpbiA9ICIiKQpgYGAKYGBge3J9CndyaXRlLnRhYmxlKHJldihnZW5lLm9yZGVyKSwgIi4vVHJhamVjdG9yaWVzL1Bhbk5ldXJvR2VuZXMuY3N2Iiwgc2VwID0gIjsiLCBxdW90ZSA9IEYpCmBgYAoKIyMgUGxvdCByZWxldmFudCBnZW5lIHRyZW5kcwoKYGBge3J9CnNvdXJjZSgiLi9mdW5jdGlvbnMvVHJhamVjdG9yaWVzUGxvdEZ1bmN0aW9ucy5SIikKYGBgCgpgYGB7ciBmaWcuZGltPWMoOSw4KSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KUGxvdC5HZW5lcy50cmVuZChBbGxjZWxscy5kYXRhLAogICAgICAgICAgICAgICAgIGdlbmVzID0gYygiU294MiIsICJIbWdhMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZXM2IiwiTWZuZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdDE4IiwgIk15dDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiTmV1cm9nMiIsIlNsYzE3YTYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiRGx4MSIsICJHYWQyIiksCiAgICAgICAgICAgICAgICAgY29sb3IuYnkgPSAibGluZWFnZSIsCiAgICAgICAgICAgICAgICAgVXNlLnNjYWxlLmRhdGEgPSBGKQpgYGAKCmBgYHtyIGZpZy5zaG93PSdoaWRlJ30KcGxvdCA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSBBbGxjZWxscy5kYXRhLAogICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzLnBsb3QgPSAgYygiU294MiIsICJIbWdhMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZXM2IiwgIk1mbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3QxOCIsIk15dDEiKSwKICAgICAgICAgICAgICAgICAgICBjb2xzLnVzZSA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpLAogICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbi51c2UgPSAic3ByaW5nIiwKICAgICAgICAgICAgICAgICAgICBuby5sZWdlbmQgPSBULAogICAgICAgICAgICAgICAgICAgIHB0LnNpemUgPSAxLAogICAgICAgICAgICAgICAgICAgIG92ZXJsYXkgPSBGLAogICAgICAgICAgICAgICAgICAgIGRhcmsudGhlbWUgPSBGLAogICAgICAgICAgICAgICAgICAgIGRvLnJldHVybiA9VCwKICAgICAgICAgICAgICAgICAgICBuby5heGVzID0gVCkKCgpmb3IgKGkgaW4gMTpsZW5ndGgocGxvdCkpewogIHBsb3RbW2ldXSRkYXRhIDwtIHBsb3RbW2ldXSRkYXRhW29yZGVyKHBsb3RbW2ldXSRkYXRhJGdlbmUpLF0KfQpgYGAKCmBgYHtyIGZpZy5kaW09Yyg2LCA5KX0KY293cGxvdDo6cGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxvdFsxOjZdLCBuY29sID0yKQpgYGAKCiMgRmluZCBERUcgYWxvbmcgdGhlIHBhbkdsdXRhbWF0ZXJnaWMgYW5kIHBhbkdBQkFlcmdpYyB0cmFqZWN0b3JpZXMKCmBgYHtyIGNhY2hlPSBUUlVFfQpQc2V1ZG90aW1lLmxpbmVhZ2VzLmRpZmYgPC0gZGlmZmVyZW50aWFsR2VuZVRlc3QoZ2JtX2Nkc1tJbnB1dC5nZW5lcyxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGxNb2RlbEZvcm11bGFTdHIgPSAifnNtLm5zKFBzZXVkb3RpbWUuU2NvcmUsIGRmID0gMykqTGluZWFnZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWNlZE1vZGVsRm9ybXVsYVN0ciA9ICJ+c20ubnMoUHNldWRvdGltZS5TY29yZSwgZGYgPSAzKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBkZXRlY3RDb3JlcygpIC0gMikKCiMgRmlsdGVyIGdlbmVzIGJhc2VkIG9uIEZEUgpQc2V1ZG90aW1lLmxpbmVhZ2VzLmRpZmYuZmlsdGVyZWQgPC0gUHNldWRvdGltZS5saW5lYWdlcy5kaWZmICU+JSBmaWx0ZXIocXZhbCA8IDFlLTMpCmBgYAoKIyMgRGlyZWN0aW9uIG9mIHRoZSBERUcgYnkgY2FsY3VsYXRpbmcgdGhlIGFyZWEgYmV0d2VlbiBjdXJ2ZXMgKEFCQykKCiMjIyBTbW9vdGggY29tbW9uIGdlbmVzIGFsb25nIHRoZSB0d28gdHJhamVjdG9yaWVzCgpgYGB7ciBjYWNoZT0gVFJVRX0KIyBDcmVhdGUgYSBuZXcgcHNldWRvLURWIHZlY3RvciBvZiAyMDAgcG9pbnRzCm5Qb2ludHMgPC0gMjAwCgpuZXdfZGF0YSA9IGxpc3QoKQpmb3IgKExpbmVhZ2UgaW4gdW5pcXVlKHBEYXRhKGdibV9jZHMpJExpbmVhZ2UpKXsKICBuZXdfZGF0YVtbbGVuZ3RoKG5ld19kYXRhKSArIDFdXSA9IGRhdGEuZnJhbWUoUHNldWRvdGltZS5TY29yZSA9IHNlcShtaW4ocERhdGEoZ2JtX2NkcykkUHNldWRvdGltZS5TY29yZSksIG1heChwRGF0YShnYm1fY2RzKSRQc2V1ZG90aW1lLlNjb3JlKSwgbGVuZ3RoLm91dCA9IG5Qb2ludHMpLCBMaW5lYWdlPUxpbmVhZ2UpCn0KCm5ld19kYXRhID0gZG8uY2FsbChyYmluZCwgbmV3X2RhdGEpCgojIFNtb290aCBnZW5lIGV4cHJlc3Npb24KRGlmZi5jdXJ2ZV9tYXRyaXggPC0gZ2VuU21vb3RoQ3VydmVzKGdibV9jZHNbYXMuY2hhcmFjdGVyKFBzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZCRnZW5lX3Nob3J0X25hbWUpLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlbmRfZm9ybXVsYSA9ICJ+c20ubnMoUHNldWRvdGltZS5TY29yZSwgZGYgPSAzKSpMaW5lYWdlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxhdGl2ZV9leHByID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfZGF0YSA9IG5ld19kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzPSBkZXRlY3RDb3JlcygpIC0gMikKYGBgCgojIyMgQ29tcHV0ZSB0aGUgQUJDIGZvciBlYWNoIGdlbmUKCmBgYHtyfQpTdWJQYWxsaWFsX2N1cnZlX21hdHJpeCA8LSBEaWZmLmN1cnZlX21hdHJpeFssIDE6blBvaW50c10gI1N1YlBhbGxpYWwgcG9pbnRzClBhbGxpYWxfY3VydmVfbWF0cml4IDwtIERpZmYuY3VydmVfbWF0cml4WywgKG5Qb2ludHMgKyAxKTooMiAqIG5Qb2ludHMpXSAjUGFsbGlhbCBwb2ludHMKICAKQUJDc19yZXMgPC0gU3ViUGFsbGlhbF9jdXJ2ZV9tYXRyaXggLSBQYWxsaWFsX2N1cnZlX21hdHJpeCAjIERpcmVjdGlvbiBvZiB0aGUgY29tcGFyaXNvbiA6IHBvc3RpdmUgQUJDcyA8PT4gVXByZWd1bGF0ZWQgaW4gU3ViUGFsbGlhbCBsaW5lYWdlCklMUl9yZXMgPC0gbG9nMihTdWJQYWxsaWFsX2N1cnZlX21hdHJpeC8gKFBhbGxpYWxfY3VydmVfbWF0cml4ICsgMC4xKSkgIyBBdmVyYWdlIGxvZ0ZDIGJldHdlZW4gdGhlIDIgY3VydmVzCiAgCkFCQ3NfcmVzIDwtIGFwcGx5KEFCQ3NfcmVzLCAxLCBmdW5jdGlvbih4LCBuUG9pbnRzKSB7CiAgICAgICAgICAgICAgICAgIGF2Z19kZWx0YV94IDwtICh4WzE6KG5Qb2ludHMgLSAxKV0gKyB4WzI6KG5Qb2ludHMpXSkvMgogICAgICAgICAgICAgICAgICBzdGVwIDwtICgxMDAvKG5Qb2ludHMgLSAxKSkKICAgICAgICAgICAgICAgICAgcmVzIDwtIHJvdW5kKHN1bShhdmdfZGVsdGFfeCAqIHN0ZXApLCAzKQogICAgICAgICAgICAgICAgICByZXR1cm4ocmVzKX0sCiAgICAgICAgICAgICAgICAgIG5Qb2ludHMgPSBuUG9pbnRzKSAjIENvbXB1dGUgdGhlIGFyZWEgYmVsb3cgdGhlIGN1cnZlCiAgCkFCQ3NfcmVzIDwtIGNiaW5kKEFCQ3NfcmVzLCBJTFJfcmVzWyxuY29sKElMUl9yZXMpXSkKY29sbmFtZXMoQUJDc19yZXMpPC0gYygiQUJDcyIsICJFbmRwb2ludF9JTFIiKQoKIyBJbXBvcnQgQUJDIHZhbHVlcyBpbnRvIHRoZSBERSB0ZXN0IHJlc3VsdHMgdGFibGUKUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkIDwtIGNiaW5kKFBzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZFssMTo0XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFCQ3NfcmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkWyw1OjZdKQpgYGAKCiMjIFBsb3QgcGFsbGlhbCBzcGVjaWZpYyB0cmFqZWN0b3J5CgpgYGB7cn0KIyBFeHRyYWN0IFBhbGxpYWwgbmV1cm9ucyB0cmFqZWN0b3J5IGdlbmVzClBhbGxpYWwucmVzIDwtIGFzLmRhdGEuZnJhbWUoUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkW1BzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZCRBQkNzIDwgMCxdKQpQYWxsaWFsLmdlbmVzIDwtIHJvdy5uYW1lcyhQYWxsaWFsLnJlcykKCiMgV2UgZnVydGhlciBmaWx0ZXIgZ2VuZXMgZGV0ZWN0ZWQgaW4gbGVzcyB0aGFuIDMwMCBhbmQgbW9yZSB0aGFuIDI1MCBjZWxscyBhbW9uZyBQYWxsaWFsIGFuZCBTdWJwYWxsaWFsIGxpbmVhZ2VzLCByZXNwZWN0aXZlbHkKbnVtLmNlbGxzIDwtIE1hdHJpeDo6cm93U3VtcyhBbGxjZWxscy5kYXRhQHJhdy5kYXRhW1BhbGxpYWwuZ2VuZXMsIFBhbGxpYWxjZWxsc10gPiAwKQpQYWxsaWFsLmdlbmVzIDwtIG5hbWVzKHggPSBudW0uY2VsbHNbd2hpY2goeCA9IG51bS5jZWxscyA+PSAzMDApXSkKCm51bS5jZWxscyA8LSBNYXRyaXg6OnJvd1N1bXMoQWxsY2VsbHMuZGF0YUByYXcuZGF0YVtQYWxsaWFsLmdlbmVzLCBTdWJQYWxsaWFsY2VsbHNdID4gMCkKZmlsdGVyZWQgPC0gbmFtZXMoeCA9IG51bS5jZWxsc1t3aGljaCh4ID0gbnVtLmNlbGxzID49IDI1MCldKQoKUGFsbGlhbC5nZW5lcyA8LSBQYWxsaWFsLmdlbmVzWyFQYWxsaWFsLmdlbmVzICVpbiUgZmlsdGVyZWRdCgpQYWxsaWFsX2N1cnZlX21hdHJpeCA8LSBQYWxsaWFsX2N1cnZlX21hdHJpeFtQYWxsaWFsLmdlbmVzLCBdCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgT3JkZXIgcm93cyB1c2luZyBzZXJpYXRpb24KZHN0IDwtIGFzLmRpc3QoKDEtY29yKHNjYWxlKHQoUGFsbGlhbF9jdXJ2ZV9tYXRyaXgpKSwgbWV0aG9kID0gInBlYXJzb24iKSkpCnJvdy5zZXIgPC0gc2VyaWF0ZShkc3QsIG1ldGhvZCA9IkdXIikKZ2VuZS5vcmRlciA8LSByb3duYW1lcyhQYWxsaWFsX2N1cnZlX21hdHJpeFtnZXRfb3JkZXIocm93LnNlciksXSkKCmFubm8uY29sb3JzIDwtIGxpc3QobGluZWFnZSA9IGMoUGFsbGlhbD0iIzAyNmM5YSIsU3ViUGFsbGlhbD0iI2NjMzkxYiIpKQoKCnBoZWF0bWFwOjpwaGVhdG1hcChEaWZmLmN1cnZlX21hdHJpeFtnZW5lLm9yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoNDAwOjIwMSwgI1BhbGxpYWwgcG9pbnRzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxOjIwMCldLCAjU3ViUGFsbGlhbCBwb2ludHMKICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRiwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gZGF0YS5mcmFtZShsaW5lYWdlID0gcmVwKGMoIlN1YlBhbGxpYWwiLCJQYWxsaWFsIiksIGVhY2g9MjAwKSksCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm8uY29sb3JzLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gVCwKICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICB2aXJpZGlzOjp2aXJpZGlzKDkpLAogICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0yLjUsMi41LCBsZW5ndGgub3V0ID0gOSksCiAgICAgICAgICAgICAgICAgICBtYWluID0gIiIpCmBgYAoKCmBgYHtyfQpQYWxsaWFsLkNvbW1vbiA8LSBQc2V1ZG90aW1lLmxpbmVhZ2VzLmRpZmYuZmlsdGVyZWRbUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkJGdlbmVfc2hvcnRfbmFtZSAlaW4lIFBhbGxpYWwuZ2VuZXMsIF0KCndyaXRlLnRhYmxlKFBhbGxpYWwuQ29tbW9uW2dlbmUub3JkZXIsXSwgIi4vVHJhamVjdG9yaWVzL1BhbGxpYWxfQ29tbW9uX0dlbmVzLmNzdiIsIHNlcCA9ICI7IiwgcXVvdGUgPSBGKQpgYGAKCgojIyBQbG90IFN1YlBhbGxpYWwgc3BlY2lmaWMgdHJhamVjdG9yeQoKYGBge3J9CiMgRXh0cmFjdCBzdWJQYWxsaWFsIG5ldXJvbnMgdHJhamVjdG9yeSBnZW5lcwpTdWJQYWxsaWFsLnJlcyA8LSBhcy5kYXRhLmZyYW1lKFBzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZFtQc2V1ZG90aW1lLmxpbmVhZ2VzLmRpZmYuZmlsdGVyZWQkQUJDcyA+IDAsXSkKU3ViUGFsbGlhbC5nZW5lcyA8LSByb3cubmFtZXMoU3ViUGFsbGlhbC5yZXMpClN1YlBhbGxpYWxfY3VydmVfbWF0cml4IDwtIFN1YlBhbGxpYWxfY3VydmVfbWF0cml4W1N1YlBhbGxpYWwuZ2VuZXMsIF0KYGBgCgpgYGB7cn0KIyBFeHRyYWN0IHN1YlBhbGxpYWwgbmV1cm9ucyB0cmFqZWN0b3J5IGdlbmVzClN1YlBhbGxpYWwucmVzIDwtIGFzLmRhdGEuZnJhbWUoUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkW1BzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZCRBQkNzID4gMCxdKQpTdWJQYWxsaWFsLmdlbmVzIDwtIHJvdy5uYW1lcyhTdWJQYWxsaWFsLnJlcykKCiMgV2UgZnVydGhlciBmaWx0ZXIgZ2VuZXMgZGV0ZWN0ZWQgaW4gbGVzcyB0aGFuIDEwMCBhbmQgbW9yZSB0aGFuIDMwMCBjZWxscyBhbW9uZyBTdWJwYWxsaWFsIGFuZCBQYWxsaWFsIGxpbmVhZ2VzLCByZXNwZWN0aXZlbHkKbnVtLmNlbGxzIDwtIE1hdHJpeDo6cm93U3VtcyhBbGxjZWxscy5kYXRhQHJhdy5kYXRhW1N1YlBhbGxpYWwuZ2VuZXMsIFN1YlBhbGxpYWxjZWxsc10gPiAwKQpTdWJQYWxsaWFsLmdlbmVzIDwtIG5hbWVzKHggPSBudW0uY2VsbHNbd2hpY2goeCA9IG51bS5jZWxscyA+PSAxMDApXSkKCm51bS5jZWxscyA8LSBNYXRyaXg6OnJvd1N1bXMoQWxsY2VsbHMuZGF0YUByYXcuZGF0YVtTdWJQYWxsaWFsLmdlbmVzLCBQYWxsaWFsY2VsbHNdID4gMCkKZmlsdGVyZWQgPC0gbmFtZXMoeCA9IG51bS5jZWxsc1t3aGljaCh4ID0gbnVtLmNlbGxzID49IDMwMCldKQoKU3ViUGFsbGlhbC5nZW5lcyA8LSBTdWJQYWxsaWFsLmdlbmVzWyFTdWJQYWxsaWFsLmdlbmVzJWluJSBmaWx0ZXJlZF0KClN1YlBhbGxpYWxfY3VydmVfbWF0cml4IDwtIFN1YlBhbGxpYWxfY3VydmVfbWF0cml4W1N1YlBhbGxpYWwuZ2VuZXMsIF0KYGBgCgoKYGBge3J9CiMgT3JkZXIgcm93cyB1c2luZyBzZXJpYXRpb24KZHN0IDwtIGFzLmRpc3QoKDEtY29yKHNjYWxlKHQoU3ViUGFsbGlhbF9jdXJ2ZV9tYXRyaXgpKSwgbWV0aG9kID0gInBlYXJzb24iKSkpCnJvdy5zZXIgPC0gc2VyaWF0ZShkc3QsIG1ldGhvZCA9IkdXIikKZ2VuZS5vcmRlciA8LSByb3duYW1lcyhTdWJQYWxsaWFsX2N1cnZlX21hdHJpeFtnZXRfb3JkZXIocm93LnNlciksXSkKCmFubm8uY29sb3JzIDwtIGxpc3QobGluZWFnZSA9IGMoUGFsbGlhbD0iIzAyNmM5YSIsU3ViUGFsbGlhbD0iI2NjMzkxYiIpKQoKCnBoZWF0bWFwOjpwaGVhdG1hcChEaWZmLmN1cnZlX21hdHJpeFtnZW5lLm9yZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoNDAwOjIwMSwgI1BhbGxpYWwgcG9pbnRzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxOjIwMCldLCAjU3ViUGFsbGlhbCBwb2ludHMKICAgICAgICAgICAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRiwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gZGF0YS5mcmFtZShsaW5lYWdlID0gcmVwKGMoIlN1YlBhbGxpYWwiLCJQYWxsaWFsIiksIGVhY2g9MjAwKSksCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm8uY29sb3JzLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICBzaG93X3Jvd25hbWVzID0gVCwKICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDgsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICB2aXJpZGlzOjp2aXJpZGlzKDkpLAogICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0yLjUsMi41LCBsZW5ndGgub3V0ID0gOSksCiAgICAgICAgICAgICAgICAgICBtYWluID0gIiIpCmBgYApgYGB7cn0KU3ViUGFsbGlhbC5Db21tb24gPC0gUHNldWRvdGltZS5saW5lYWdlcy5kaWZmLmZpbHRlcmVkW1BzZXVkb3RpbWUubGluZWFnZXMuZGlmZi5maWx0ZXJlZCRnZW5lX3Nob3J0X25hbWUgJWluJSBTdWJQYWxsaWFsLmdlbmVzLCBdCgp3cml0ZS50YWJsZShTdWJQYWxsaWFsLkNvbW1vbltnZW5lLm9yZGVyLF0sICIuL1RyYWplY3Rvcmllcy9TdWJQYWxsaWFsX0NvbW1vbl9HZW5lcy5jc3YiLCBzZXAgPSAiOyIsIHF1b3RlID0gRikKYGBgCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CiNkYXRlCmZvcm1hdChTeXMudGltZSgpLCAiJWQgJUIsICVZLCAlSCwlTSIpCgojUGFja2FnZXMgdXNlZApzZXNzaW9uSW5mbygpCmBgYAo=