Load libraries

library(Seurat)
library(scrattch.hicat)
library(FateID)
library(Matrix)
library(dplyr)
library(RColorBrewer)
library(ggplot2)
library(ggExtra)
library(cowplot)
library(reticulate)
library(wesanderson)
library(princurve)
use_python("/usr/bin/python3")

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

Load the raw counts matrix

Countdata <- Read10X("../../RawData/Gmnc_KO/outs/filtered_feature_bc_matrix/")

Raw.data <- CreateSeuratObject(counts = Countdata,
                              project = "Gmnc_KO",
                              min.cells = 3,
                              min.features = 800)

Raw.data$Barcodes <- rownames(Raw.data@meta.data)

rm(Countdata)

dim(Raw.data)
## [1] 21077 16272
Raw.data$percent.mito <- PercentageFeatureSet(Raw.data, pattern = "^mt-")
Raw.data$percent.ribo <- PercentageFeatureSet(Raw.data, pattern = "(^Rpl|^Rps|^Mrp)")
VlnPlot(object = Raw.data, features = c("nFeature_RNA","nCount_RNA", "percent.mito", "percent.ribo"), ncol= 2) & NoAxes()

# Inspect cell based on relation between nUMI and nGene detected

# Relation between nUMI and nGene detected
Cell.QC.Stat <- Raw.data@meta.data

p1 <- ggplot(Cell.QC.Stat, aes(x=nCount_RNA, y=nFeature_RNA)) + geom_point() + geom_smooth(method="lm")
p1 <- ggMarginal(p1, type = "histogram", fill="lightgrey")

p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point() + geom_smooth(method="lm")
p2 <- ggMarginal(p2, type = "histogram", fill="lightgrey")

plot_grid(plotlist = list(p1,p2), ncol=2, align='h', rel_widths = c(1, 1)) ; rm(p1,p2)

Cells with deviating nGene/nUMI ratio display an Erythrocyte signature

Raw.data <- AddModuleScore(Raw.data,
                           features = list(c("Hbb-bt", "Hbq1a", "Isg20", "Fech", "Snca", "Rec114")),
                           ctrl = 10,
                           name = "Erythrocyte.signature")

Cell.QC.Stat$Erythrocyte.signature <- Raw.data$Erythrocyte.signature1
gradient <- colorRampPalette(brewer.pal(n =11, name = "Spectral"))(100)

p1 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= Erythrocyte.signature))  + 
      scale_color_gradientn(colours=rev(gradient), name='Erythrocyte score') + theme(legend.position="none")

p2 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= percent.mito))  + 
      scale_color_gradientn(colours=rev(gradient), name='Percent mito') + theme(legend.position="none")

p3 <- ggplot(Cell.QC.Stat, aes(log10(nCount_RNA), y=log10(nFeature_RNA))) +
      geom_point(aes(color= percent.ribo))  + 
      scale_color_gradientn(colours=rev(gradient), name='Percent ribo') + theme(legend.position="none")

p1 + p2 + p3

## Exclude Erythrocytes

Cell.QC.Stat$Erythrocyte <- ifelse(Cell.QC.Stat$Erythrocyte.signature > 0.1, "Erythrocyte", "Not_Erythrocyte")
p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point(aes(colour = Erythrocyte)) +
  theme(legend.position="none")

ggMarginal(p2, type = "histogram", fill="lightgrey")

# Filter cells based on these thresholds
Cell.QC.Stat <- Cell.QC.Stat %>% filter(Cell.QC.Stat$Erythrocyte.signature < 0.1)

Low quality cell filtering

Filtering cells based on percentage of mitochondrial transcripts

We applied a high and low median absolute deviation (mad) thresholds to exclude outlier cells

max.mito.thr <- median(Cell.QC.Stat$percent.mito) + 3*mad(Cell.QC.Stat$percent.mito)
min.mito.thr <- median(Cell.QC.Stat$percent.mito) - 3*mad(Cell.QC.Stat$percent.mito)
p1 <- ggplot(Cell.QC.Stat, aes(x=nFeature_RNA, y=percent.mito)) +
  geom_point() +
  geom_hline(aes(yintercept = max.mito.thr), colour = "red", linetype = 2) +
  geom_hline(aes(yintercept = min.mito.thr), colour = "red", linetype = 2) +
  annotate(geom = "text", label = paste0(as.numeric(table(Cell.QC.Stat$percent.mito > max.mito.thr | Cell.QC.Stat$percent.mito < min.mito.thr)[2])," cells removed\n",
                                         as.numeric(table(Cell.QC.Stat$percent.mito > max.mito.thr | Cell.QC.Stat$percent.mito < min.mito.thr)[1])," cells remain"),
           x = 6000, y = 20)

ggMarginal(p1, type = "histogram", fill="lightgrey", bins=100) 

# Filter cells based on these thresholds
Cell.QC.Stat <- Cell.QC.Stat %>% filter(percent.mito < max.mito.thr) %>% filter(percent.mito > min.mito.thr)

Filtering cells based on number of genes and transcripts detected

Remove cells with to few gene detected or with to many UMI counts

We filter cells which are likely to be doublet based on their higher content of transcript detected as well as cell with to few genes/UMI sequenced

# Set low and hight thresholds on the number of detected genes based on the one obtain with the WT dataset
min.Genes.thr <- log10(1635)
max.Genes.thr <- log10(8069)

# Set hight threshold on the number of transcripts
max.nUMI.thr <- log10(58958)
# Gene/UMI scatter plot before filtering
p1 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point() +
  geom_smooth(method="lm") +
  geom_hline(aes(yintercept = min.Genes.thr), colour = "green", linetype = 2) +
  geom_hline(aes(yintercept = max.Genes.thr), colour = "green", linetype = 2) +
  geom_vline(aes(xintercept = max.nUMI.thr), colour = "red", linetype = 2)

ggMarginal(p1, type = "histogram", fill="lightgrey")

# Filter cells base on both metrics
Cell.QC.Stat <- Cell.QC.Stat %>% filter(log10(nFeature_RNA) > min.Genes.thr) %>% filter(log10(nCount_RNA) < max.nUMI.thr)

Filter cells below the main population nUMI/nGene relationship

lm.model <- lm(data = Cell.QC.Stat, formula = log10(nFeature_RNA) ~ log10(nCount_RNA))

p2 <- ggplot(Cell.QC.Stat, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) +
  geom_point() +
  geom_smooth(method="lm") +
  geom_hline(aes(yintercept = min.Genes.thr), colour = "green", linetype = 2) +
  geom_hline(aes(yintercept = max.Genes.thr), colour = "green", linetype = 2) +
  geom_vline(aes(xintercept = max.nUMI.thr), colour = "red", linetype = 2) +
  annotate(geom = "text", label = paste0(dim(Cell.QC.Stat)[1], " QC passed cells"), x = 4, y = 3.8)

ggMarginal(p2, type = "histogram", fill="lightgrey")

Filter the Seurat object

Raw.data <- subset(x = Raw.data, subset = Barcodes %in%  Cell.QC.Stat$Barcodes)
# Plot final QC metrics
VlnPlot(object = Raw.data, features = c("nFeature_RNA","nCount_RNA", "percent.mito", "percent.ribo"), ncol= 2) & NoAxes()

p1 <- ggplot(Raw.data@meta.data, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point() + geom_smooth(method="lm")
ggMarginal(p1, type = "histogram", fill="lightgrey")

rm(list = ls()[!ls() %in% "Raw.data"])

Use Scrublet to detect obvious doublets

Run Scrublet with default parameter

Export raw count matrix as input to Scrublet

#Export filtered matrix
dir.create("../../RawData/Gmnc_KO/Scrublet_inputs")

exprData <- Matrix(as.matrix(Raw.data@assays[["RNA"]]@counts), sparse = TRUE)
writeMM(exprData, "../../RawData/Gmnc_KO/Scrublet_inputs/matrix1.mtx")
## NULL
import scrublet as scr
import scipy.io
import numpy as np
import os

#Load raw counts matrix and gene list
input_dir = '../../RawData/Gmnc_KO/Scrublet_inputs'
counts_matrix = scipy.io.mmread(input_dir + '/matrix1.mtx').T.tocsc()

#Initialize Scrublet
scrub = scr.Scrublet(counts_matrix,
                     expected_doublet_rate=0.1,
                     sim_doublet_ratio=2,
                     n_neighbors = 8)

#Run the default pipeline
doublet_scores, predicted_doublets = scrub.scrub_doublets(min_counts=1, 
                                                          min_cells=3, 
                                                          min_gene_variability_pctl=85, 
                                                          n_prin_comps=25)
## Preprocessing...
## Simulating doublets...
## Embedding transcriptomes using PCA...
## Calculating doublet scores...
## Automatically set threshold at doublet score = 0.35
## Detected doublet rate = 3.7%
## Estimated detectable doublet fraction = 26.0%
## Overall doublet rate:
##  Expected   = 10.0%
##  Estimated  = 14.2%
## Elapsed time: 19.9 seconds
# Import scrublet's doublet score
Raw.data$Doubletscore <- py$doublet_scores

# Plot doublet score
ggplot(Raw.data@meta.data, aes(x = Doubletscore, stat(ndensity))) +
  geom_histogram(bins = 200, colour ="lightgrey")+
  geom_vline(xintercept = 0.15, colour = "red", linetype = 2)

# Manually set threshold at doublet score to 0.2
Raw.data$Predicted_doublets <- ifelse(py$doublet_scores > 0.15, "Doublet","Singlet")
table(Raw.data$Predicted_doublets)
## 
## Doublet Singlet 
##    2273   10215
Raw.data <- subset(x = Raw.data, subset = Predicted_doublets == "Singlet")

Generate SRING dimentionality reduction

Export counts matrix

dir.create("./SpringCoordinates")
# Export raw expression matrix and gene list to regenerate a spring plot
exprData <- Matrix(as.matrix(Raw.data@assays[["RNA"]]@counts), sparse = TRUE)
writeMM(exprData, "./SpringCoordinates/ExprData.mtx")
## NULL
Genelist <- row.names(Raw.data@assays[["RNA"]]@counts)
write.table(Genelist, "./SpringCoordinates/Genelist.csv", sep="\t", col.names = F, row.names = F, quote = F)
#Export metadata
Scrublet <- c("Scrublet", Raw.data$Predicted_doublets)
Scrublet <- paste(Scrublet, sep=",", collapse=",")

Cellgrouping <- Scrublet
write.table(Cellgrouping, "./SpringCoordinates/Cellgrouping.csv", quote =F, row.names = F, col.names = F)

Import coordinates

spring.coor <- read.table("SpringCoordinates/coordinates.txt", sep = ",", header = F, row.names = 1)
colnames(spring.coor) <- c("Spring_1", "Spring_2")
Spring.Sym <- function(x){
  x = abs(max(spring.coor$Spring_2)-x)
 }

spring.coor$Spring_2 <- sapply(spring.coor$Spring_2, function(x) Spring.Sym(x))
Raw.data$Spring_1 <- spring.coor$Spring_1
Raw.data$Spring_2 <- spring.coor$Spring_2
spring <- as.matrix(Raw.data@meta.data %>% select("Spring_1", "Spring_2"))
  
Raw.data[["spring"]] <- CreateDimReducObject(embeddings = spring, key = "Spring_", assay = DefaultAssay(Raw.data))
DimPlot(Raw.data, 
        reduction = "spring",
        pt.size = 0.5) & NoAxes()

# Broad clustering

Sctransform normalization

Raw.data <- SCTransform(Raw.data,
                        method = "glmGamPoi",
                        vars.to.regress = c("percent.mito"),
                        verbose = T)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   5%
  |                                                                            
  |=====                                                                 |   8%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |===========                                                           |  15%
  |                                                                            
  |=============                                                         |  18%
  |                                                                            
  |==============                                                        |  21%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  38%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |===========================================                           |  62%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  79%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |===========================================================           |  85%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  92%
  |                                                                            
  |==================================================================    |  95%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   5%
  |                                                                            
  |=====                                                                 |   8%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |===========                                                           |  15%
  |                                                                            
  |=============                                                         |  18%
  |                                                                            
  |==============                                                        |  21%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  38%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |===========================================                           |  62%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  79%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |===========================================================           |  85%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  92%
  |                                                                            
  |==================================================================    |  95%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%

Run PCA and broad clustering

Raw.data <- RunPCA(Raw.data, verbose = FALSE)

Raw.data <- FindNeighbors(Raw.data,
                          dims = 1:20,
                          k.param = 8)

Raw.data <- FindClusters(Raw.data, resolution = 0.2)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 10215
## Number of edges: 218490
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.9335
## Number of communities: 9
## Elapsed time: 1 seconds
DimPlot(Raw.data,
        reduction = "spring",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b", "#d14c8d", "#4cabdc", "#5ab793", "#e7823a", "#046c9a", "#4990c9"),
        pt.size = 0.5) & NoAxes()

Raw.data$Broadclust.ident <- Raw.data$seurat_clusters

Differentiating neurons sub-clustering

Extract differentiating neurons

Neurons.data <-  subset(Raw.data, idents = 3)

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

## Fit pseudotime

fit <- principal_curve(as.matrix(Neurons.data@meta.data[,c("Spring_1", "Spring_2")]),
                       smoother='lowess',
                       trace=TRUE,
                       f = 1,
                       stretch=0)
## Starting curve---distance^2: 84204082853
## Iteration 1---distance^2: 46039577
## Iteration 2---distance^2: 42955956
## Iteration 3---distance^2: 41286356
## Iteration 4---distance^2: 40749859
## Iteration 5---distance^2: 40679459
## Iteration 6---distance^2: 40714117
#Pseudotime score
PseudotimeScore <- fit$lambda/max(fit$lambda)

if (cor(PseudotimeScore, Neurons.data@assays$SCT@data['Hmga2', ]) > 0) {
  Neurons.data$PseudotimeScore <- -(PseudotimeScore - max(PseudotimeScore))
}

cols <- brewer.pal(n =11, name = "Spectral")

ggplot(Neurons.data@meta.data, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=PseudotimeScore), size=2, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='Pseudotime score')

# Late Neurons diversity

Extract late neurons

Neurons.data$Cell.state <- cut(Neurons.data$PseudotimeScore,
                              c(0,0.4,0.8,1),
                              include.lowest = T,
                              labels=c("BP","EN","LN"))
DimPlot(Neurons.data,
        group.by = "Cell.state",
        reduction = "spring",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b"),
        pt.size = 1.5) & NoAxes()

LN.data <- subset(Neurons.data, subset = Cell.state == "LN")
DimPlot(LN.data,
        reduction = "spring",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b"),
        pt.size = 1.5) & NoAxes()

## Prepare the dataset for clustering with scrattch.hicat

Gene filtering

# Exclude genes detected in less than 3 cells
num.cells <- Matrix::rowSums(LN.data@assays[["RNA"]]@counts > 0)
genes.use <- names(x = num.cells[which(x = num.cells >= 3)])

GenesToRemove <- c(grep(pattern = "(^Rpl|^Rps|^Mrp)", x = genes.use, value = TRUE),
                   grep(pattern = "^mt-", x = genes.use, value = TRUE),
                   "Xist")

genes.use <- genes.use[!genes.use %in% GenesToRemove]

Normalization

dgeMatrix_count <- as.matrix(LN.data@assays[["RNA"]]@counts)[rownames(LN.data@assays[["RNA"]]@counts) %in% genes.use,]
dgeMatrix_cpm <- cpm(dgeMatrix_count)
norm.dat <- log2(dgeMatrix_cpm + 1)

norm.dat <- Matrix(norm.dat, sparse = TRUE)
Data.matrix <- list(raw.dat=dgeMatrix_count, norm.dat=norm.dat)
attach(Data.matrix)

Exclude unwanted sources of variation

gene.counts <- log2(colSums(as.matrix(Data.matrix$norm.dat) > 0))
nUMI <- log2(colSums(Data.matrix$raw.dat))
perctMito <- LN.data$percent.mito
perctRibo <- LN.data$percent.ribo
Pseudotime <- LN.data$PseudotimeScore

rm.eigen <- as.matrix(cbind(gene.counts,
                            nUMI,
                            perctMito,
                            perctRibo,
                            Pseudotime))

row.names(rm.eigen) <- names(gene.counts)

colnames(rm.eigen) <- c("log2nGenes",
                        "log2nUMI",
                        "perctMito",
                        "perctRibo",
                        "Pseudotime ")

rm(gene.counts, nUMI, perctMito, perctRibo, Pseudotime)

Iterative clustering

# Parameters for iterative clustering
de.param <- de_param(padj.th     = 0.01, 
                     lfc.th      = 0.9,
                     low.th      = 1, 
                     q1.th       = 0.25, 
                     q2.th       = NULL,
                     q.diff.th   = 0.7,
                     de.score.th = 80,
                     min.cells   = 10)
iter.result <- iter_clust(norm.dat, 
                          counts = raw.dat,
                          dim.method = "pca",
                          max.dim = 15,
                          k.nn = 8,
                          de.param = de.param,
                          rm.eigen = rm.eigen,
                          rm.th = 0.7,
                          vg.padj.th = 0.5,
                          method = "louvain",
                          prefix = "test-iter_clust",
                          verbose = F)
## [1] "test-iter_clust"
##   Finding nearest neighbors...DONE ~ 0.01 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.016 s
##   Build undirected graph from the weighted links...DONE ~ 0.03 s
##   Run louvain clustering on the graph ...DONE ~ 0.015 s
##   Return a community class
##   -Modularity value: 0.8158831 
##   -Number of clusters: 19[1] "test-iter_clust.1"
## [1] "test-iter_clust.2"
##   Finding nearest neighbors...DONE ~ 0.002 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.008 s
##   Build undirected graph from the weighted links...DONE ~ 0.013 s
##   Run louvain clustering on the graph ...DONE ~ 0.006 s
##   Return a community class
##   -Modularity value: 0.8361195 
##   -Number of clusters: 16[1] "test-iter_clust.3"
##   Finding nearest neighbors...DONE ~ 0.001 s
##   Compute jaccard coefficient between nearest-neighbor sets...DONE ~ 0.008 s
##   Build undirected graph from the weighted links...DONE ~ 0.012 s
##   Run louvain clustering on the graph ...DONE ~ 0.005 s
##   Return a community class
##   -Modularity value: 0.8542279 
##   -Number of clusters: 15
# Merge clusters which are not seperable by DEGs
rd.dat <- t(norm.dat[iter.result$markers,])
merge.result <- merge_cl(norm.dat, 
                         cl = iter.result$cl, 
                         rd.dat = rd.dat,
                         de.param = de.param)

cat(length(unique(merge.result$cl))," Clusters")
## 3  Clusters
LN.data$iter.clust <- merge.result$cl

Idents(LN.data) <- "iter.clust"

colors <-  c("#ebcb2e", "#9ec22f", "#cc3a1b")

DimPlot(LN.data,
        reduction = "spring",
        #cols = colors,
        pt.size = 1.5) & NoAxes()

Neurons.markers <- FindAllMarkers(LN.data,
                                  test.use = "roc",
                                  only.pos = TRUE,
                                  min.pct = 0.25,
                                  logfc.threshold = 0.25)
top10 <- Neurons.markers %>%
          group_by(cluster) %>%
          filter(power > 0.45)

DoHeatmap(LN.data,
          group.colors = c("#ebcb2e", "#9ec22f", "#cc3a1b"),
          features = top10$gene) + NoLegend()

FeaturePlot(object = LN.data,
            features = c("Foxg1", "Zfpm2",
                         "Lhx1", "Zic5", "Zfp503"),
            pt.size = 1,
            cols = c("grey90", brewer.pal(9,"YlGnBu")),
            reduction = "spring",
            order = T) & NoAxes() & NoLegend()

## Use fate ID to infer lineages along differentiating cells

Neurons.data$Broadclust.ident <- sapply(Neurons.data$Barcodes,
                              FUN = function(x) {
                                if (x %in% LN.data$Barcodes) {
                                  x = paste0("Neuron_", LN.data@meta.data[x, "iter.clust"])
                                } else {
                                  x = Neurons.data@meta.data[x, "Broadclust.ident"]
                                  }
                              })

Idents(Neurons.data) <- "Broadclust.ident"
DimPlot(Neurons.data,
        reduction = "spring",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b", "#d14c8d", "#4cabdc", "#5ab793", "grey90", "#e7823a", "#046c9a", "#4990c9", "grey60"),
        pt.size = 0.5) & NoAxes()

Run FateID

FateID

Neurons.data <- SCTransform(Neurons.data,
                            method = "glmGamPoi",
                            vars.to.regress = c("percent.mito", "percent.ribo"),
                            verbose = T)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |=====                                                                 |   7%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |===================                                                   |  27%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |==========================                                            |  37%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |==============================                                        |  43%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |========================================                              |  57%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |============================================                          |  63%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |===================================================                   |  73%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  93%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |=====                                                                 |   7%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |===================                                                   |  27%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |==========================                                            |  37%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |==============================                                        |  43%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |========================================                              |  57%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |============================================                          |  63%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |===================================================                   |  73%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |=================================================================     |  93%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%
Neurons.data <- FindVariableFeatures(Neurons.data, selection.method = "vst", nfeatures = 1500)
Norm.Mat <- as.data.frame(as.matrix(Neurons.data@assays$SCT@data[Neurons.data@assays$SCT@var.features,]))

#Rename idents
id <- 4:1
names(id) <- levels(Neurons.data)
Neurons.data <- RenameIdents(Neurons.data, id)

# Set a cluster assignment factor for each cells
ClusterIdent <- Idents(Neurons.data)
names(ClusterIdent) <- names(Idents(Neurons.data))

Attractors <- 1:3

# Distance in spring space
z <- as.matrix(dist(cbind(Neurons.data$Spring_1, Neurons.data$Spring_2)))
Infered.Fate.bias  <- fateBias(Norm.Mat, ClusterIdent, Attractors,
                               z = z,
                               minnr=20,
                               minnrh=30,
                               adapt=TRUE,
                               confidence=0.75,
                               nbfactor=5,
                               use.dist=FALSE,
                               seed=1234,
                               nbtree=NULL)

Inspect test set used iteratively

Neurons.data$FateID.iteration <- "Attractors"
Idents(Neurons.data) <- "FateID.iteration"

for (i in seq(0, length(Infered.Fate.bias$rfl), by = 5)[-1]) {
  iter <- seq(i-4,i)
  Barcodes <- c()
  for (j in iter) {
    Barcodes <- c(Barcodes, names(Infered.Fate.bias$rfl[[j]]$test$predicted))
  }
  Neurons.data <- SetIdent(Neurons.data, cells = Barcodes, value = paste0("iter ",iter[1]," to ", iter[4]))
}

DimPlot(Neurons.data,
        reduction = "spring",
        pt.size = 1) & NoAxes()

Import lineage bias into Seurat meta.data

probs <- Infered.Fate.bias$probs[,seq(length(Attractors))]

Neurons.data$prob.1 <- probs$t1
Neurons.data$prob.2 <- probs$t2
Neurons.data$prob.3 <- probs$t3

FeaturePlot(object = Neurons.data,
            features = c("prob.1", "prob.2", "prob.3"),
            pt.size = 0.5,
            cols = rev(RColorBrewer::brewer.pal(n = 11, name = "Spectral")),
            reduction = "spring",
            order = T) & NoAxes() & NoLegend()

New.data <- data.frame(barcode=Neurons.data$Barcodes,
                       cluster= Neurons.data$Broadclust.ident,
                       spring1= Neurons.data$Spring_1,
                       spring2= Neurons.data$Spring_2,
                       prob.1= Neurons.data$prob.1,
                       prob.2= Neurons.data$prob.2,
                       prob.3 = Neurons.data$prob.3)

New.data$lineage.bias <- colnames(New.data[,5:7])[apply(New.data[,5:7],1,which.max)]

ggplot(New.data, aes(spring1, spring2, colour = lineage.bias)) +
  scale_color_manual(values=c("#e7823a","#cc391b","#026c9a","#d14c8d")) +
  geom_point() 

Transfert ident to the full dataset

Neurons.data$Lineage.bias <- New.data$lineage.bias

Raw.data$Broadclust.ident <- sapply(Raw.data$Barcodes,
                              FUN = function(x) {
                                if (x %in% Neurons.data$Barcodes) {
                                  x = paste0("Neuron_",Neurons.data@meta.data[x, "Lineage.bias"])
                                } else {
                                  x = Raw.data@meta.data[x, "Broadclust.ident"]
                                  }
                              })

Idents(Raw.data) <- "Broadclust.ident"
DimPlot(Raw.data,
        reduction = "spring",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b", "#d14c8d", "#4cabdc", "#5ab793", "#e7823a", "#046c9a", "grey90", "#4990c9"),
        pt.size = 0.5) & NoAxes()

rm(list = ls()[!ls() %in% "Raw.data"])
gc()
##             used   (Mb) gc trigger   (Mb)  max used   (Mb)
## Ncells   3051089  163.0    5399218  288.4   5399218  288.4
## Vcells 252292949 1924.9  712258272 5434.1 699288732 5335.2

Project progenitors domain ident from WT

WT.KO <- list(WT = readRDS("../QC.filtered.clustered.cells.RDS") %>%
                subset(subset = orig.ident == "Hem1" & Cell_ident %in% c("ChP_progenitors", "ChP",
                                                                         "Dorso-Medial_pallium", "Medial_pallium",
                                                                         "Hem", "Thalamic_eminence") ),
              KO = Raw.data %>% subset(idents = c(1,2,3,5)))
p1 <- DimPlot(object = WT.KO[["WT"]],
        group.by = "Cell.state",
        reduction = "spring",
        cols = c("#31b6bd", "#ebcb2e", "#9ec22f", "#cc3a1b", "#d14c8d", "#4cabdc", "#5ab793", "#e7823a", "#046c9a", "#4990c9"),
        pt.size = 1.5
        )  & NoAxes()

p2 <- DimPlot(WT.KO[["KO"]],
        reduction = "spring",
        group.by = "Broadclust.ident",
        cols = c("#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b"),
        pt.size = 1.5) & NoAxes()

p1 + p2

WT.KO[["WT"]] <- NormalizeData(WT.KO[["WT"]], normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
WT.KO[["KO"]] <- NormalizeData(WT.KO[["KO"]], normalization.method = "LogNormalize", scale.factor = 10000, assay = "RNA")
WT.KO[["WT"]] <- FindVariableFeatures(WT.KO[["WT"]], selection.method = "vst", nfeatures = 2000)
WT.KO[["KO"]] <- FindVariableFeatures(WT.KO[["KO"]], selection.method = "vst", nfeatures = 2000)
features <- SelectIntegrationFeatures(object.list = WT.KO, nfeatures = 1500)

TFs <- read.table("TF.csv", sep = ";")[,1]
TFs <- features[features %in% TFs]

transfert identity labels WT to KO

KO.anchors <- FindTransferAnchors(reference = WT.KO[["WT"]],
                                  query = WT.KO[["KO"]],
                                  features = TFs,
                                  reduction = "rpca",
                                  k.anchor = 5,
                                  k.filter = 100,
                                  k.score = 30,
                                  npcs = 25,
                                  dims = 1:25,
                                  max.features = 200)

predictions <- TransferData(anchorset = KO.anchors,
                            refdata = WT.KO[["WT"]]$Cell.state,
                            dims = 1:25)

WT.KO[["KO"]] <- AddMetaData(WT.KO[["KO"]], metadata = predictions)
cols <- brewer.pal(n =11, name = "Spectral")

ggplot(WT.KO[["KO"]]@meta.data, aes(Spring_1, Spring_2)) +
  geom_point(aes(color=prediction.score.max), size=1, shape=16) + 
  scale_color_gradientn(colours=rev(cols), name='prediction.score.max')

p1 <- DimPlot(object = WT.KO[["WT"]],
        group.by = "Cell.state",
        reduction = "spring",
        cols = c("#7293c8", "#b79f0b", "#3ca73f","#31b6bd",
                 "#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b",
                 "#d14c8d", "#4cabdc", "#5ab793", "#e7823a",
                 "#046c9a", "#4990c9"),
        pt.size = 1)  & NoAxes()

p2 <- DimPlot(WT.KO[["KO"]],
              group.by = "predicted.id",
              reduction = "spring",
              cols = c("#31b6bd", "#ebcb2e", "#9ec22f", "#a9961b", "#cc3a1b"),
              pt.size = 1) & NoAxes()

p1 + p2

Transfert to the full dataset

Raw.data$Cell.ident <- sapply(Raw.data$Barcodes,
                              FUN = function(x) {
                                if (x %in% WT.KO[["KO"]]$Barcodes) {
                                  x = WT.KO[["KO"]]@meta.data[x, "predicted.id"]
                                } else {
                                  x = Raw.data@meta.data[x, "Broadclust.ident"]
                                  }
                              })
DimPlot(object = Raw.data,
        group.by = "Cell.ident",
        reduction = "spring",
        cols = c( "#4cabdc", "#7293c8", "grey40" ,"#3ca73f","grey80",
                  "#31b6bd", "#ebcb2e", "#9ec22f", "#a9961b",
                 "#046c9a", "#cc3a1b","#4990c9","#e7823a"),
        pt.size = 0.5)  & NoAxes()

Change gene name annotation

Reads were realigned using the same transcriptome annotation as the WT E11.5-E12.5 dataset. We re import the count matrix from the realignment.

rm(list = ls()[!ls() %in% "Raw.data"])
gc()
##             used   (Mb) gc trigger   (Mb)   max used   (Mb)
## Ncells   3059672  163.5    5399218  288.4    5399218  288.4
## Vcells 252333733 1925.2 1033469064 7884.8 1105207168 8432.1
Raw.data@assays[["RNA"]]@counts <- Read10X("../../RawData/Gmnc_KO/mm10_ref/outs/filtered_feature_bc_matrix/")[,Raw.data$Barcodes]
Raw.data@assays[["RNA"]]@data <- Raw.data@assays[["RNA"]]@counts

Raw.data <- SCTransform(Raw.data,
                        method = "glmGamPoi",
                        vars.to.regress = c("percent.mito"),
                        verbose = T)
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   6%
  |                                                                            
  |======                                                                |   8%
  |                                                                            
  |========                                                              |  11%
  |                                                                            
  |==========                                                            |  14%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |==============                                                        |  19%
  |                                                                            
  |================                                                      |  22%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================                                                   |  28%
  |                                                                            
  |=====================                                                 |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  39%
  |                                                                            
  |=============================                                         |  42%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  58%
  |                                                                            
  |===========================================                           |  61%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |=================================================                     |  69%
  |                                                                            
  |===================================================                   |  72%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================                |  78%
  |                                                                            
  |========================================================              |  81%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |============================================================          |  86%
  |                                                                            
  |==============================================================        |  89%
  |                                                                            
  |================================================================      |  92%
  |                                                                            
  |==================================================================    |  94%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%
## 
  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |====                                                                  |   6%
  |                                                                            
  |======                                                                |   8%
  |                                                                            
  |========                                                              |  11%
  |                                                                            
  |==========                                                            |  14%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |==============                                                        |  19%
  |                                                                            
  |================                                                      |  22%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |===================                                                   |  28%
  |                                                                            
  |=====================                                                 |  31%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |===========================                                           |  39%
  |                                                                            
  |=============================                                         |  42%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |=========================================                             |  58%
  |                                                                            
  |===========================================                           |  61%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |=================================================                     |  69%
  |                                                                            
  |===================================================                   |  72%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |======================================================                |  78%
  |                                                                            
  |========================================================              |  81%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |============================================================          |  86%
  |                                                                            
  |==============================================================        |  89%
  |                                                                            
  |================================================================      |  92%
  |                                                                            
  |==================================================================    |  94%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |======================================================================| 100%

Save the object

saveRDS(Raw.data, "./GmncKO.cells.RDS")

Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "02 juin, 2022, 10,21"
#Packages used
sessionInfo()
## R version 4.2.0 (2022-04-22)
## 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: /home/matthieu/anaconda3/lib/libmkl_rt.so.1
## 
## 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] Rphenograph_0.99.1   igraph_1.2.11        matrixStats_0.61.0  
##  [4] princurve_2.1.6      wesanderson_0.3.6    reticulate_1.22     
##  [7] cowplot_1.1.1        ggExtra_0.9          ggplot2_3.3.5       
## [10] RColorBrewer_1.1-2   dplyr_1.0.7          Matrix_1.4-1        
## [13] FateID_0.2.1         scrattch.hicat_1.0.0 SeuratObject_4.0.4  
## [16] Seurat_4.0.5        
## 
## loaded via a namespace (and not attached):
##   [1] plyr_1.8.6                  lazyeval_0.2.2             
##   [3] splines_4.2.0               listenv_0.8.0              
##   [5] scattermore_0.7             lle_1.1                    
##   [7] GenomeInfoDb_1.30.0         digest_0.6.29              
##   [9] htmltools_0.5.2             fansi_0.5.0                
##  [11] magrittr_2.0.2              tensor_1.5                 
##  [13] cluster_2.1.3               ROCR_1.0-11                
##  [15] limma_3.50.0                globals_0.14.0             
##  [17] askpass_1.1                 spatstat.sparse_2.0-0      
##  [19] colorspace_2.0-2            ggrepel_0.9.1              
##  [21] xfun_0.28                   RCurl_1.98-1.5             
##  [23] crayon_1.4.2                jsonlite_1.7.2             
##  [25] spatstat.data_2.1-0         survival_3.2-13            
##  [27] zoo_1.8-9                   glue_1.5.1                 
##  [29] polyclip_1.10-0             gtable_0.3.0               
##  [31] zlibbioc_1.40.0             XVector_0.34.0             
##  [33] leiden_0.3.9                DelayedArray_0.20.0        
##  [35] future.apply_1.8.1          BiocGenerics_0.40.0        
##  [37] abind_1.4-5                 scales_1.1.1               
##  [39] pheatmap_1.0.12             DBI_1.1.1                  
##  [41] som_0.3-5.1                 miniUI_0.1.1.1             
##  [43] Rcpp_1.0.8                  viridisLite_0.4.0          
##  [45] xtable_1.8-4                spatstat.core_2.3-1        
##  [47] stats4_4.2.0                umap_0.2.8.0               
##  [49] htmlwidgets_1.5.4           httr_1.4.2                 
##  [51] ellipsis_0.3.2              ica_1.0-2                  
##  [53] pkgconfig_2.0.3             farver_2.1.0               
##  [55] sass_0.4.0                  uwot_0.1.10                
##  [57] deldir_1.0-6                locfit_1.5-9.4             
##  [59] utf8_1.2.2                  tidyselect_1.1.1           
##  [61] labeling_0.4.2              rlang_0.4.12               
##  [63] reshape2_1.4.4              later_1.3.0                
##  [65] munsell_0.5.0               tools_4.2.0                
##  [67] generics_0.1.1              ggridges_0.5.3             
##  [69] evaluate_0.14               stringr_1.4.0              
##  [71] fastmap_1.1.0               yaml_2.2.1                 
##  [73] goftest_1.2-3               knitr_1.36                 
##  [75] fitdistrplus_1.1-6          purrr_0.3.4                
##  [77] randomForest_4.7-1          RANN_2.6.1                 
##  [79] sparseMatrixStats_1.6.0     pbapply_1.5-0              
##  [81] future_1.23.0               nlme_3.1-153               
##  [83] mime_0.12                   compiler_4.2.0             
##  [85] plotly_4.10.0               png_0.1-7                  
##  [87] spatstat.utils_2.2-0        tibble_3.1.6               
##  [89] bslib_0.3.1                 glmGamPoi_1.6.0            
##  [91] stringi_1.7.6               highr_0.9                  
##  [93] RSpectra_0.16-0             lattice_0.20-45            
##  [95] vctrs_0.3.8                 pillar_1.6.4               
##  [97] lifecycle_1.0.1             spatstat.geom_2.3-0        
##  [99] lmtest_0.9-39               jquerylib_0.1.4            
## [101] RcppAnnoy_0.0.19            bitops_1.0-7               
## [103] data.table_1.14.2           irlba_2.3.3                
## [105] GenomicRanges_1.46.1        httpuv_1.6.3               
## [107] patchwork_1.1.1             R6_2.5.1                   
## [109] promises_1.2.0.1            KernSmooth_2.23-20         
## [111] gridExtra_2.3               IRanges_2.28.0             
## [113] parallelly_1.29.0           codetools_0.2-18           
## [115] MASS_7.3-57                 assertthat_0.2.1           
## [117] SummarizedExperiment_1.24.0 openssl_1.4.5              
## [119] withr_2.4.3                 sctransform_0.3.2          
## [121] GenomeInfoDbData_1.2.7      S4Vectors_0.32.3           
## [123] mgcv_1.8-40                 parallel_4.2.0             
## [125] grid_4.2.0                  rpart_4.1.16               
## [127] tidyr_1.1.4                 DelayedMatrixStats_1.16.0  
## [129] rmarkdown_2.11              MatrixGenerics_1.6.0       
## [131] Rtsne_0.15                  Biobase_2.54.0             
## [133] scatterplot3d_0.3-41        shiny_1.7.1                
## [135] snowfall_1.84-6.1

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

LS0tCnRpdGxlOiAiR21uYyBLTyBxdWFsaXR5IGNvbnRyb2wiCmF1dGhvcjoKICAgLSBNYXR0aGlldSBNb3JlYXVeW0luc3RpdHV0ZSBvZiBQc3ljaGlhdHJ5IGFuZCBOZXVyb3NjaWVuY2Ugb2YgUGFyaXMsIElOU0VSTSBVMTI2NiwgNzUwMTQsIFBhcmlzLCBGcmFuY2UsIG1hdHRoaWV1Lm1vcmVhdUBpbnNlcm0uZnJdIFshW10oaHR0cHM6Ly9vcmNpZC5vcmcvc2l0ZXMvZGVmYXVsdC9maWxlcy9pbWFnZXMvb3JjaWRfMTZ4MTYucG5nKV0oaHR0cHM6Ly9vcmNpZC5vcmcvMDAwMC0wMDAyLTI1OTItMjM3MykKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBkZl9wcmludDogdGliYmxlCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRoZW1lOiBjb3NtbwogICAgY3NzOiAiLi4vc3R5bGUuY3NzIgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGZpZy5hbGlnbiA9ICdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZS5sYXp5ID0gRkFMU0UpCmBgYAoKIyBMb2FkIGxpYnJhcmllcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoc2NyYXR0Y2guaGljYXQpCmxpYnJhcnkoRmF0ZUlEKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ0V4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocmV0aWN1bGF0ZSkKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShwcmluY3VydmUpCnVzZV9weXRob24oIi91c3IvYmluL3B5dGhvbjMiKQoKI1NldCBnZ3Bsb3QgdGhlbWUgYXMgY2xhc3NpYwp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpKQpgYGAKCiMgTG9hZCB0aGUgcmF3IGNvdW50cyBtYXRyaXgKCmBgYHtyfQpDb3VudGRhdGEgPC0gUmVhZDEwWCgiLi4vLi4vUmF3RGF0YS9HbW5jX0tPL291dHMvZmlsdGVyZWRfZmVhdHVyZV9iY19tYXRyaXgvIikKClJhdy5kYXRhIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBDb3VudGRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiR21uY19LTyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5mZWF0dXJlcyA9IDgwMCkKClJhdy5kYXRhJEJhcmNvZGVzIDwtIHJvd25hbWVzKFJhdy5kYXRhQG1ldGEuZGF0YSkKCnJtKENvdW50ZGF0YSkKCmRpbShSYXcuZGF0YSkKYGBgCmBgYHtyfQpSYXcuZGF0YSRwZXJjZW50Lm1pdG8gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoUmF3LmRhdGEsIHBhdHRlcm4gPSAiXm10LSIpClJhdy5kYXRhJHBlcmNlbnQucmlibyA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChSYXcuZGF0YSwgcGF0dGVybiA9ICIoXlJwbHxeUnBzfF5NcnApIikKYGBgCgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBSYXcuZGF0YSwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCJuQ291bnRfUk5BIiwgInBlcmNlbnQubWl0byIsICJwZXJjZW50LnJpYm8iKSwgbmNvbD0gMikgJiBOb0F4ZXMoKQpgYGAKIyBJbnNwZWN0IGNlbGwgYmFzZWQgb24gcmVsYXRpb24gYmV0d2VlbiBuVU1JIGFuZCBuR2VuZSBkZXRlY3RlZAoKYGBge3J9CiMgUmVsYXRpb24gYmV0d2VlbiBuVU1JIGFuZCBuR2VuZSBkZXRlY3RlZApDZWxsLlFDLlN0YXQgPC0gUmF3LmRhdGFAbWV0YS5kYXRhCgpwMSA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMoeD1uQ291bnRfUk5BLCB5PW5GZWF0dXJlX1JOQSkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCnAxIDwtIGdnTWFyZ2luYWwocDEsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikKCnAyIDwtIGdncGxvdChDZWxsLlFDLlN0YXQsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpwMiA8LSBnZ01hcmdpbmFsKHAyLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCgpwbG90X2dyaWQocGxvdGxpc3QgPSBsaXN0KHAxLHAyKSwgbmNvbD0yLCBhbGlnbj0naCcsIHJlbF93aWR0aHMgPSBjKDEsIDEpKSA7IHJtKHAxLHAyKQpgYGAKCkNlbGxzIHdpdGggZGV2aWF0aW5nIG5HZW5lL25VTUkgcmF0aW8gZGlzcGxheSBhbiBFcnl0aHJvY3l0ZSBzaWduYXR1cmUgCgoKYGBge3J9ClJhdy5kYXRhIDwtIEFkZE1vZHVsZVNjb3JlKFJhdy5kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGxpc3QoYygiSGJiLWJ0IiwgIkhicTFhIiwgIklzZzIwIiwgIkZlY2giLCAiU25jYSIsICJSZWMxMTQiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGN0cmwgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJFcnl0aHJvY3l0ZS5zaWduYXR1cmUiKQoKQ2VsbC5RQy5TdGF0JEVyeXRocm9jeXRlLnNpZ25hdHVyZSA8LSBSYXcuZGF0YSRFcnl0aHJvY3l0ZS5zaWduYXR1cmUxCmBgYAoKYGBge3J9CmdyYWRpZW50IDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0xMSwgbmFtZSA9ICJTcGVjdHJhbCIpKSgxMDApCgpwMSA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMobG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3I9IEVyeXRocm9jeXRlLnNpZ25hdHVyZSkpICArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoZ3JhZGllbnQpLCBuYW1lPSdFcnl0aHJvY3l0ZSBzY29yZScpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKCnAyIDwtIGdncGxvdChDZWxsLlFDLlN0YXQsIGFlcyhsb2cxMChuQ291bnRfUk5BKSwgeT1sb2cxMChuRmVhdHVyZV9STkEpKSkgKwogICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gcGVyY2VudC5taXRvKSkgICsgCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzPXJldihncmFkaWVudCksIG5hbWU9J1BlcmNlbnQgbWl0bycpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKCnAzIDwtIGdncGxvdChDZWxsLlFDLlN0YXQsIGFlcyhsb2cxMChuQ291bnRfUk5BKSwgeT1sb2cxMChuRmVhdHVyZV9STkEpKSkgKwogICAgICBnZW9tX3BvaW50KGFlcyhjb2xvcj0gcGVyY2VudC5yaWJvKSkgICsgCiAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzPXJldihncmFkaWVudCksIG5hbWU9J1BlcmNlbnQgcmlibycpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKCnAxICsgcDIgKyBwMwpgYGAKIyMgRXhjbHVkZSBFcnl0aHJvY3l0ZXMKCmBgYHtyfQpDZWxsLlFDLlN0YXQkRXJ5dGhyb2N5dGUgPC0gaWZlbHNlKENlbGwuUUMuU3RhdCRFcnl0aHJvY3l0ZS5zaWduYXR1cmUgPiAwLjEsICJFcnl0aHJvY3l0ZSIsICJOb3RfRXJ5dGhyb2N5dGUiKQpgYGAKCmBgYHtyfQpwMiA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMoeD1sb2cxMChuQ291bnRfUk5BKSwgeT1sb2cxMChuRmVhdHVyZV9STkEpKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IEVyeXRocm9jeXRlKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCgpnZ01hcmdpbmFsKHAyLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCmBgYAoKYGBge3J9CiMgRmlsdGVyIGNlbGxzIGJhc2VkIG9uIHRoZXNlIHRocmVzaG9sZHMKQ2VsbC5RQy5TdGF0IDwtIENlbGwuUUMuU3RhdCAlPiUgZmlsdGVyKENlbGwuUUMuU3RhdCRFcnl0aHJvY3l0ZS5zaWduYXR1cmUgPCAwLjEpCmBgYAoKIyBMb3cgcXVhbGl0eSBjZWxsIGZpbHRlcmluZwoKIyMgRmlsdGVyaW5nIGNlbGxzIGJhc2VkIG9uIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCB0cmFuc2NyaXB0cwoKV2UgYXBwbGllZCBhIGhpZ2ggYW5kIGxvdyBtZWRpYW4gYWJzb2x1dGUgZGV2aWF0aW9uIChtYWQpIHRocmVzaG9sZHMgdG8gZXhjbHVkZSBvdXRsaWVyIGNlbGxzCgpgYGB7cn0KbWF4Lm1pdG8udGhyIDwtIG1lZGlhbihDZWxsLlFDLlN0YXQkcGVyY2VudC5taXRvKSArIDMqbWFkKENlbGwuUUMuU3RhdCRwZXJjZW50Lm1pdG8pCm1pbi5taXRvLnRociA8LSBtZWRpYW4oQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0bykgLSAzKm1hZChDZWxsLlFDLlN0YXQkcGVyY2VudC5taXRvKQpgYGAKCmBgYHtyfQpwMSA8LSBnZ3Bsb3QoQ2VsbC5RQy5TdGF0LCBhZXMoeD1uRmVhdHVyZV9STkEsIHk9cGVyY2VudC5taXRvKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1heC5taXRvLnRociksIGNvbG91ciA9ICJyZWQiLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gbWluLm1pdG8udGhyKSwgY29sb3VyID0gInJlZCIsIGxpbmV0eXBlID0gMikgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIGxhYmVsID0gcGFzdGUwKGFzLm51bWVyaWModGFibGUoQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0byA+IG1heC5taXRvLnRociB8IENlbGwuUUMuU3RhdCRwZXJjZW50Lm1pdG8gPCBtaW4ubWl0by50aHIpWzJdKSwiIGNlbGxzIHJlbW92ZWRcbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyh0YWJsZShDZWxsLlFDLlN0YXQkcGVyY2VudC5taXRvID4gbWF4Lm1pdG8udGhyIHwgQ2VsbC5RQy5TdGF0JHBlcmNlbnQubWl0byA8IG1pbi5taXRvLnRocilbMV0pLCIgY2VsbHMgcmVtYWluIiksCiAgICAgICAgICAgeCA9IDYwMDAsIHkgPSAyMCkKCmdnTWFyZ2luYWwocDEsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IiwgYmlucz0xMDApIApgYGAKYGBge3J9CiMgRmlsdGVyIGNlbGxzIGJhc2VkIG9uIHRoZXNlIHRocmVzaG9sZHMKQ2VsbC5RQy5TdGF0IDwtIENlbGwuUUMuU3RhdCAlPiUgZmlsdGVyKHBlcmNlbnQubWl0byA8IG1heC5taXRvLnRocikgJT4lIGZpbHRlcihwZXJjZW50Lm1pdG8gPiBtaW4ubWl0by50aHIpCmBgYAoKIyMgRmlsdGVyaW5nIGNlbGxzIGJhc2VkIG9uIG51bWJlciBvZiBnZW5lcyBhbmQgdHJhbnNjcmlwdHMgZGV0ZWN0ZWQKCiMjIyBSZW1vdmUgY2VsbHMgd2l0aCB0byBmZXcgZ2VuZSBkZXRlY3RlZCBvciB3aXRoIHRvIG1hbnkgVU1JIGNvdW50cwoKV2UgZmlsdGVyIGNlbGxzIHdoaWNoIGFyZSBsaWtlbHkgdG8gYmUgZG91YmxldCBiYXNlZCBvbiB0aGVpciBoaWdoZXIgY29udGVudCBvZiB0cmFuc2NyaXB0IGRldGVjdGVkIGFzIHdlbGwgYXMgY2VsbCB3aXRoIHRvIGZldyBnZW5lcy9VTUkgc2VxdWVuY2VkCgpgYGB7cn0KIyBTZXQgbG93IGFuZCBoaWdodCB0aHJlc2hvbGRzIG9uIHRoZSBudW1iZXIgb2YgZGV0ZWN0ZWQgZ2VuZXMgYmFzZWQgb24gdGhlIG9uZSBvYnRhaW4gd2l0aCB0aGUgV1QgZGF0YXNldAptaW4uR2VuZXMudGhyIDwtIGxvZzEwKDE2MzUpCm1heC5HZW5lcy50aHIgPC0gbG9nMTAoODA2OSkKCiMgU2V0IGhpZ2h0IHRocmVzaG9sZCBvbiB0aGUgbnVtYmVyIG9mIHRyYW5zY3JpcHRzCm1heC5uVU1JLnRociA8LSBsb2cxMCg1ODk1OCkKYGBgCgoKYGBge3J9CiMgR2VuZS9VTUkgc2NhdHRlciBwbG90IGJlZm9yZSBmaWx0ZXJpbmcKcDEgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKHg9bG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1pbi5HZW5lcy50aHIpLCBjb2xvdXIgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gbWF4LkdlbmVzLnRociksIGNvbG91ciA9ICJncmVlbiIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtYXgublVNSS50aHIpLCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAyKQoKZ2dNYXJnaW5hbChwMSwgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJsaWdodGdyZXkiKQpgYGAKYGBge3J9CiMgRmlsdGVyIGNlbGxzIGJhc2Ugb24gYm90aCBtZXRyaWNzCkNlbGwuUUMuU3RhdCA8LSBDZWxsLlFDLlN0YXQgJT4lIGZpbHRlcihsb2cxMChuRmVhdHVyZV9STkEpID4gbWluLkdlbmVzLnRocikgJT4lIGZpbHRlcihsb2cxMChuQ291bnRfUk5BKSA8IG1heC5uVU1JLnRocikKYGBgCgojIyMgRmlsdGVyIGNlbGxzIGJlbG93IHRoZSBtYWluIHBvcHVsYXRpb24gblVNSS9uR2VuZSByZWxhdGlvbnNoaXAKCmBgYHtyfQpsbS5tb2RlbCA8LSBsbShkYXRhID0gQ2VsbC5RQy5TdGF0LCBmb3JtdWxhID0gbG9nMTAobkZlYXR1cmVfUk5BKSB+IGxvZzEwKG5Db3VudF9STkEpKQoKcDIgPC0gZ2dwbG90KENlbGwuUUMuU3RhdCwgYWVzKHg9bG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IG1pbi5HZW5lcy50aHIpLCBjb2xvdXIgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gbWF4LkdlbmVzLnRociksIGNvbG91ciA9ICJncmVlbiIsIGxpbmV0eXBlID0gMikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtYXgublVNSS50aHIpLCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAyKSArCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgbGFiZWwgPSBwYXN0ZTAoZGltKENlbGwuUUMuU3RhdClbMV0sICIgUUMgcGFzc2VkIGNlbGxzIiksIHggPSA0LCB5ID0gMy44KQoKZ2dNYXJnaW5hbChwMiwgdHlwZSA9ICJoaXN0b2dyYW0iLCBmaWxsPSJsaWdodGdyZXkiKQpgYGAKCiMjIEZpbHRlciB0aGUgU2V1cmF0IG9iamVjdAoKYGBge3J9ClJhdy5kYXRhIDwtIHN1YnNldCh4ID0gUmF3LmRhdGEsIHN1YnNldCA9IEJhcmNvZGVzICVpbiUgIENlbGwuUUMuU3RhdCRCYXJjb2RlcykKYGBgCgpgYGB7cn0KIyBQbG90IGZpbmFsIFFDIG1ldHJpY3MKVmxuUGxvdChvYmplY3QgPSBSYXcuZGF0YSwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCJuQ291bnRfUk5BIiwgInBlcmNlbnQubWl0byIsICJwZXJjZW50LnJpYm8iKSwgbmNvbD0gMikgJiBOb0F4ZXMoKQpgYGAKYGBge3J9CnAxIDwtIGdncGxvdChSYXcuZGF0YUBtZXRhLmRhdGEsIGFlcyh4PWxvZzEwKG5Db3VudF9STkEpLCB5PWxvZzEwKG5GZWF0dXJlX1JOQSkpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpnZ01hcmdpbmFsKHAxLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCmBgYApgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSAiUmF3LmRhdGEiXSkKYGBgCgoKIyBVc2UgU2NydWJsZXQgdG8gZGV0ZWN0IG9idmlvdXMgZG91YmxldHMKCiMjIFJ1biBTY3J1YmxldCB3aXRoIGRlZmF1bHQgcGFyYW1ldGVyCgpFeHBvcnQgcmF3IGNvdW50IG1hdHJpeCBhcyBpbnB1dCB0byBTY3J1YmxldAoKYGBge3J9CiNFeHBvcnQgZmlsdGVyZWQgbWF0cml4CmRpci5jcmVhdGUoIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9TY3J1YmxldF9pbnB1dHMiKQoKZXhwckRhdGEgPC0gTWF0cml4KGFzLm1hdHJpeChSYXcuZGF0YUBhc3NheXNbWyJSTkEiXV1AY291bnRzKSwgc3BhcnNlID0gVFJVRSkKd3JpdGVNTShleHByRGF0YSwgIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9TY3J1YmxldF9pbnB1dHMvbWF0cml4MS5tdHgiKQpgYGAKYGBge3B5dGhvbn0KaW1wb3J0IHNjcnVibGV0IGFzIHNjcgppbXBvcnQgc2NpcHkuaW8KaW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBvcwoKI0xvYWQgcmF3IGNvdW50cyBtYXRyaXggYW5kIGdlbmUgbGlzdAppbnB1dF9kaXIgPSAnLi4vLi4vUmF3RGF0YS9HbW5jX0tPL1NjcnVibGV0X2lucHV0cycKY291bnRzX21hdHJpeCA9IHNjaXB5LmlvLm1tcmVhZChpbnB1dF9kaXIgKyAnL21hdHJpeDEubXR4JykuVC50b2NzYygpCgojSW5pdGlhbGl6ZSBTY3J1YmxldApzY3J1YiA9IHNjci5TY3J1YmxldChjb3VudHNfbWF0cml4LAogICAgICAgICAgICAgICAgICAgICBleHBlY3RlZF9kb3VibGV0X3JhdGU9MC4xLAogICAgICAgICAgICAgICAgICAgICBzaW1fZG91YmxldF9yYXRpbz0yLAogICAgICAgICAgICAgICAgICAgICBuX25laWdoYm9ycyA9IDgpCgojUnVuIHRoZSBkZWZhdWx0IHBpcGVsaW5lCmRvdWJsZXRfc2NvcmVzLCBwcmVkaWN0ZWRfZG91YmxldHMgPSBzY3J1Yi5zY3J1Yl9kb3VibGV0cyhtaW5fY291bnRzPTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX2NlbGxzPTMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX2dlbmVfdmFyaWFiaWxpdHlfcGN0bD04NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3ByaW5fY29tcHM9MjUpCmBgYAoKYGBge3J9CiMgSW1wb3J0IHNjcnVibGV0J3MgZG91YmxldCBzY29yZQpSYXcuZGF0YSREb3VibGV0c2NvcmUgPC0gcHkkZG91YmxldF9zY29yZXMKCiMgUGxvdCBkb3VibGV0IHNjb3JlCmdncGxvdChSYXcuZGF0YUBtZXRhLmRhdGEsIGFlcyh4ID0gRG91YmxldHNjb3JlLCBzdGF0KG5kZW5zaXR5KSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjAwLCBjb2xvdXIgPSJsaWdodGdyZXkiKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjE1LCBjb2xvdXIgPSAicmVkIiwgbGluZXR5cGUgPSAyKQpgYGAKYGBge3J9CiMgTWFudWFsbHkgc2V0IHRocmVzaG9sZCBhdCBkb3VibGV0IHNjb3JlIHRvIDAuMgpSYXcuZGF0YSRQcmVkaWN0ZWRfZG91YmxldHMgPC0gaWZlbHNlKHB5JGRvdWJsZXRfc2NvcmVzID4gMC4xNSwgIkRvdWJsZXQiLCJTaW5nbGV0IikKdGFibGUoUmF3LmRhdGEkUHJlZGljdGVkX2RvdWJsZXRzKQpgYGAKYGBge3J9ClJhdy5kYXRhIDwtIHN1YnNldCh4ID0gUmF3LmRhdGEsIHN1YnNldCA9IFByZWRpY3RlZF9kb3VibGV0cyA9PSAiU2luZ2xldCIpCmBgYAoKIyBHZW5lcmF0ZSBTUklORyBkaW1lbnRpb25hbGl0eSByZWR1Y3Rpb24KCiMjIEV4cG9ydCBjb3VudHMgbWF0cml4CgpgYGB7cn0KZGlyLmNyZWF0ZSgiLi9TcHJpbmdDb29yZGluYXRlcyIpCmBgYAoKYGBge3J9CiMgRXhwb3J0IHJhdyBleHByZXNzaW9uIG1hdHJpeCBhbmQgZ2VuZSBsaXN0IHRvIHJlZ2VuZXJhdGUgYSBzcHJpbmcgcGxvdApleHByRGF0YSA8LSBNYXRyaXgoYXMubWF0cml4KFJhdy5kYXRhQGFzc2F5c1tbIlJOQSJdXUBjb3VudHMpLCBzcGFyc2UgPSBUUlVFKQp3cml0ZU1NKGV4cHJEYXRhLCAiLi9TcHJpbmdDb29yZGluYXRlcy9FeHByRGF0YS5tdHgiKQpgYGAKCmBgYHtyfQpHZW5lbGlzdCA8LSByb3cubmFtZXMoUmF3LmRhdGFAYXNzYXlzW1siUk5BIl1dQGNvdW50cykKd3JpdGUudGFibGUoR2VuZWxpc3QsICIuL1NwcmluZ0Nvb3JkaW5hdGVzL0dlbmVsaXN0LmNzdiIsIHNlcD0iXHQiLCBjb2wubmFtZXMgPSBGLCByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCmBgYAoKYGBge3J9CiNFeHBvcnQgbWV0YWRhdGEKU2NydWJsZXQgPC0gYygiU2NydWJsZXQiLCBSYXcuZGF0YSRQcmVkaWN0ZWRfZG91YmxldHMpClNjcnVibGV0IDwtIHBhc3RlKFNjcnVibGV0LCBzZXA9IiwiLCBjb2xsYXBzZT0iLCIpCgpDZWxsZ3JvdXBpbmcgPC0gU2NydWJsZXQKd3JpdGUudGFibGUoQ2VsbGdyb3VwaW5nLCAiLi9TcHJpbmdDb29yZGluYXRlcy9DZWxsZ3JvdXBpbmcuY3N2IiwgcXVvdGUgPUYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCmBgYAoKIyMgSW1wb3J0IGNvb3JkaW5hdGVzCgpgYGB7cn0Kc3ByaW5nLmNvb3IgPC0gcmVhZC50YWJsZSgiU3ByaW5nQ29vcmRpbmF0ZXMvY29vcmRpbmF0ZXMudHh0Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBGLCByb3cubmFtZXMgPSAxKQpjb2xuYW1lcyhzcHJpbmcuY29vcikgPC0gYygiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKQpgYGAKCmBgYHtyfQpTcHJpbmcuU3ltIDwtIGZ1bmN0aW9uKHgpewogIHggPSBhYnMobWF4KHNwcmluZy5jb29yJFNwcmluZ18yKS14KQogfQoKc3ByaW5nLmNvb3IkU3ByaW5nXzIgPC0gc2FwcGx5KHNwcmluZy5jb29yJFNwcmluZ18yLCBmdW5jdGlvbih4KSBTcHJpbmcuU3ltKHgpKQpgYGAKCmBgYHtyfQpSYXcuZGF0YSRTcHJpbmdfMSA8LSBzcHJpbmcuY29vciRTcHJpbmdfMQpSYXcuZGF0YSRTcHJpbmdfMiA8LSBzcHJpbmcuY29vciRTcHJpbmdfMgpgYGAKCgpgYGB7cn0Kc3ByaW5nIDwtIGFzLm1hdHJpeChSYXcuZGF0YUBtZXRhLmRhdGEgJT4lIHNlbGVjdCgiU3ByaW5nXzEiLCAiU3ByaW5nXzIiKSkKICAKUmF3LmRhdGFbWyJzcHJpbmciXV0gPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoZW1iZWRkaW5ncyA9IHNwcmluZywga2V5ID0gIlNwcmluZ18iLCBhc3NheSA9IERlZmF1bHRBc3NheShSYXcuZGF0YSkpCmBgYAoKYGBge3J9CkRpbVBsb3QoUmF3LmRhdGEsIAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIHB0LnNpemUgPSAwLjUpICYgTm9BeGVzKCkKYGBgCiMgQnJvYWQgY2x1c3RlcmluZwoKIyMgU2N0cmFuc2Zvcm0gbm9ybWFsaXphdGlvbgoKYGBge3IgY2xhc3Mub3V0cHV0PSJzY3JvbGwtMTAwIiwgY2FjaGU9VFJVRX0KUmF3LmRhdGEgPC0gU0NUcmFuc2Zvcm0oUmF3LmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1HYW1Qb2kiLAogICAgICAgICAgICAgICAgICAgICAgICB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJwZXJjZW50Lm1pdG8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFQpCmBgYAojIyBSdW4gUENBIGFuZCBicm9hZCBjbHVzdGVyaW5nCgpgYGB7ciBjbGFzcy5vdXRwdXQ9InNjcm9sbC0xMDAiLCBjYWNoZT1UUlVFfQpSYXcuZGF0YSA8LSBSdW5QQ0EoUmF3LmRhdGEsIHZlcmJvc2UgPSBGQUxTRSkKClJhdy5kYXRhIDwtIEZpbmROZWlnaGJvcnMoUmF3LmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6MjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgay5wYXJhbSA9IDgpCgpSYXcuZGF0YSA8LSBGaW5kQ2x1c3RlcnMoUmF3LmRhdGEsIHJlc29sdXRpb24gPSAwLjIpCmBgYAoKYGBge3J9CkRpbVBsb3QoUmF3LmRhdGEsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgY29scyA9IGMoIiNlYmNiMmUiLCAiIzllYzIyZiIsICIjYTk5NjFiIiwgIiNjYzNhMWIiLCAiI2QxNGM4ZCIsICIjNGNhYmRjIiwgIiM1YWI3OTMiLCAiI2U3ODIzYSIsICIjMDQ2YzlhIiwgIiM0OTkwYzkiKSwKICAgICAgICBwdC5zaXplID0gMC41KSAmIE5vQXhlcygpCmBgYApgYGB7cn0KUmF3LmRhdGEkQnJvYWRjbHVzdC5pZGVudCA8LSBSYXcuZGF0YSRzZXVyYXRfY2x1c3RlcnMKYGBgCgojIERpZmZlcmVudGlhdGluZyBuZXVyb25zIHN1Yi1jbHVzdGVyaW5nCgojIyBFeHRyYWN0IGRpZmZlcmVudGlhdGluZyBuZXVyb25zCgpgYGB7cn0KTmV1cm9ucy5kYXRhIDwtICBzdWJzZXQoUmF3LmRhdGEsIGlkZW50cyA9IDMpCgpEaW1QbG90KE5ldXJvbnMuZGF0YSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBwdC5zaXplID0gMSwKICAgICAgICBjb2xzID0gIGMoIiNjYzNhMWIiKSkgKyBOb0F4ZXMoKQpgYGAKIyMgRml0IHBzZXVkb3RpbWUKCmBgYHtyfQpmaXQgPC0gcHJpbmNpcGFsX2N1cnZlKGFzLm1hdHJpeChOZXVyb25zLmRhdGFAbWV0YS5kYXRhWyxjKCJTcHJpbmdfMSIsICJTcHJpbmdfMiIpXSksCiAgICAgICAgICAgICAgICAgICAgICAgc21vb3RoZXI9J2xvd2VzcycsCiAgICAgICAgICAgICAgICAgICAgICAgdHJhY2U9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBmID0gMSwKICAgICAgICAgICAgICAgICAgICAgICBzdHJldGNoPTApCmBgYAoKYGBge3J9CiNQc2V1ZG90aW1lIHNjb3JlClBzZXVkb3RpbWVTY29yZSA8LSBmaXQkbGFtYmRhL21heChmaXQkbGFtYmRhKQoKaWYgKGNvcihQc2V1ZG90aW1lU2NvcmUsIE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbJ0htZ2EyJywgXSkgPiAwKSB7CiAgTmV1cm9ucy5kYXRhJFBzZXVkb3RpbWVTY29yZSA8LSAtKFBzZXVkb3RpbWVTY29yZSAtIG1heChQc2V1ZG90aW1lU2NvcmUpKQp9Cgpjb2xzIDwtIGJyZXdlci5wYWwobiA9MTEsIG5hbWUgPSAiU3BlY3RyYWwiKQoKZ2dwbG90KE5ldXJvbnMuZGF0YUBtZXRhLmRhdGEsIGFlcyhTcHJpbmdfMSwgU3ByaW5nXzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UHNldWRvdGltZVNjb3JlKSwgc2l6ZT0yLCBzaGFwZT0xNikgKyAKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3Vycz1yZXYoY29scyksIG5hbWU9J1BzZXVkb3RpbWUgc2NvcmUnKQpgYGAKIyBMYXRlIE5ldXJvbnMgZGl2ZXJzaXR5CgojIyBFeHRyYWN0IGxhdGUgbmV1cm9ucwoKYGBge3J9Ck5ldXJvbnMuZGF0YSRDZWxsLnN0YXRlIDwtIGN1dChOZXVyb25zLmRhdGEkUHNldWRvdGltZVNjb3JlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDAsMC40LDAuOCwxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiQlAiLCJFTiIsIkxOIikpCmBgYAoKYGBge3J9CkRpbVBsb3QoTmV1cm9ucy5kYXRhLAogICAgICAgIGdyb3VwLmJ5ID0gIkNlbGwuc3RhdGUiLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCIjZWJjYjJlIiwgIiM5ZWMyMmYiLCAiI2E5OTYxYiIpLAogICAgICAgIHB0LnNpemUgPSAxLjUpICYgTm9BeGVzKCkKYGBgCmBgYHtyfQpMTi5kYXRhIDwtIHN1YnNldChOZXVyb25zLmRhdGEsIHN1YnNldCA9IENlbGwuc3RhdGUgPT0gIkxOIikKYGBgCgpgYGB7cn0KRGltUGxvdChMTi5kYXRhLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCIjZWJjYjJlIiwgIiM5ZWMyMmYiLCAiI2E5OTYxYiIpLAogICAgICAgIHB0LnNpemUgPSAxLjUpICYgTm9BeGVzKCkKYGBgCiMjIFByZXBhcmUgdGhlIGRhdGFzZXQgZm9yIGNsdXN0ZXJpbmcgd2l0aCBzY3JhdHRjaC5oaWNhdAoKIyMjIEdlbmUgZmlsdGVyaW5nCgpgYGB7cn0KIyBFeGNsdWRlIGdlbmVzIGRldGVjdGVkIGluIGxlc3MgdGhhbiAzIGNlbGxzCm51bS5jZWxscyA8LSBNYXRyaXg6OnJvd1N1bXMoTE4uZGF0YUBhc3NheXNbWyJSTkEiXV1AY291bnRzID4gMCkKZ2VuZXMudXNlIDwtIG5hbWVzKHggPSBudW0uY2VsbHNbd2hpY2goeCA9IG51bS5jZWxscyA+PSAzKV0pCgpHZW5lc1RvUmVtb3ZlIDwtIGMoZ3JlcChwYXR0ZXJuID0gIiheUnBsfF5ScHN8Xk1ycCkiLCB4ID0gZ2VuZXMudXNlLCB2YWx1ZSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgZ3JlcChwYXR0ZXJuID0gIl5tdC0iLCB4ID0gZ2VuZXMudXNlLCB2YWx1ZSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgIlhpc3QiKQoKZ2VuZXMudXNlIDwtIGdlbmVzLnVzZVshZ2VuZXMudXNlICVpbiUgR2VuZXNUb1JlbW92ZV0KYGBgCgojIyMgTm9ybWFsaXphdGlvbgoKYGBge3J9CmRnZU1hdHJpeF9jb3VudCA8LSBhcy5tYXRyaXgoTE4uZGF0YUBhc3NheXNbWyJSTkEiXV1AY291bnRzKVtyb3duYW1lcyhMTi5kYXRhQGFzc2F5c1tbIlJOQSJdXUBjb3VudHMpICVpbiUgZ2VuZXMudXNlLF0KZGdlTWF0cml4X2NwbSA8LSBjcG0oZGdlTWF0cml4X2NvdW50KQpub3JtLmRhdCA8LSBsb2cyKGRnZU1hdHJpeF9jcG0gKyAxKQoKbm9ybS5kYXQgPC0gTWF0cml4KG5vcm0uZGF0LCBzcGFyc2UgPSBUUlVFKQpEYXRhLm1hdHJpeCA8LSBsaXN0KHJhdy5kYXQ9ZGdlTWF0cml4X2NvdW50LCBub3JtLmRhdD1ub3JtLmRhdCkKYXR0YWNoKERhdGEubWF0cml4KQpgYGAKCiMjIyBFeGNsdWRlIHVud2FudGVkIHNvdXJjZXMgb2YgdmFyaWF0aW9uCgpgYGB7cn0KZ2VuZS5jb3VudHMgPC0gbG9nMihjb2xTdW1zKGFzLm1hdHJpeChEYXRhLm1hdHJpeCRub3JtLmRhdCkgPiAwKSkKblVNSSA8LSBsb2cyKGNvbFN1bXMoRGF0YS5tYXRyaXgkcmF3LmRhdCkpCnBlcmN0TWl0byA8LSBMTi5kYXRhJHBlcmNlbnQubWl0bwpwZXJjdFJpYm8gPC0gTE4uZGF0YSRwZXJjZW50LnJpYm8KUHNldWRvdGltZSA8LSBMTi5kYXRhJFBzZXVkb3RpbWVTY29yZQoKcm0uZWlnZW4gPC0gYXMubWF0cml4KGNiaW5kKGdlbmUuY291bnRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgblVNSSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmN0TWl0bywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmN0UmlibywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUpKQoKcm93Lm5hbWVzKHJtLmVpZ2VuKSA8LSBuYW1lcyhnZW5lLmNvdW50cykKCmNvbG5hbWVzKHJtLmVpZ2VuKSA8LSBjKCJsb2cybkdlbmVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgImxvZzJuVU1JIiwKICAgICAgICAgICAgICAgICAgICAgICAgInBlcmN0TWl0byIsCiAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjdFJpYm8iLAogICAgICAgICAgICAgICAgICAgICAgICAiUHNldWRvdGltZSAiKQoKcm0oZ2VuZS5jb3VudHMsIG5VTUksIHBlcmN0TWl0bywgcGVyY3RSaWJvLCBQc2V1ZG90aW1lKQpgYGAKCiMjIEl0ZXJhdGl2ZSBjbHVzdGVyaW5nCgpgYGB7cn0KIyBQYXJhbWV0ZXJzIGZvciBpdGVyYXRpdmUgY2x1c3RlcmluZwpkZS5wYXJhbSA8LSBkZV9wYXJhbShwYWRqLnRoICAgICA9IDAuMDEsIAogICAgICAgICAgICAgICAgICAgICBsZmMudGggICAgICA9IDAuOSwKICAgICAgICAgICAgICAgICAgICAgbG93LnRoICAgICAgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgcTEudGggICAgICAgPSAwLjI1LCAKICAgICAgICAgICAgICAgICAgICAgcTIudGggICAgICAgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICBxLmRpZmYudGggICA9IDAuNywKICAgICAgICAgICAgICAgICAgICAgZGUuc2NvcmUudGggPSA4MCwKICAgICAgICAgICAgICAgICAgICAgbWluLmNlbGxzICAgPSAxMCkKYGBgCgoKYGBge3IgY2xhc3Mub3V0cHV0PSJzY3JvbGwtMTAwIiwgY2FjaGU9VFJVRX0KaXRlci5yZXN1bHQgPC0gaXRlcl9jbHVzdChub3JtLmRhdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRzID0gcmF3LmRhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ubWV0aG9kID0gInBjYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmRpbSA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgIGsubm4gPSA4LAogICAgICAgICAgICAgICAgICAgICAgICAgIGRlLnBhcmFtID0gZGUucGFyYW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgcm0uZWlnZW4gPSBybS5laWdlbiwKICAgICAgICAgICAgICAgICAgICAgICAgICBybS50aCA9IDAuNywKICAgICAgICAgICAgICAgICAgICAgICAgICB2Zy5wYWRqLnRoID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJsb3V2YWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVmaXggPSAidGVzdC1pdGVyX2NsdXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRikKYGBgCgpgYGB7cn0KIyBNZXJnZSBjbHVzdGVycyB3aGljaCBhcmUgbm90IHNlcGVyYWJsZSBieSBERUdzCnJkLmRhdCA8LSB0KG5vcm0uZGF0W2l0ZXIucmVzdWx0JG1hcmtlcnMsXSkKbWVyZ2UucmVzdWx0IDwtIG1lcmdlX2NsKG5vcm0uZGF0LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNsID0gaXRlci5yZXN1bHQkY2wsIAogICAgICAgICAgICAgICAgICAgICAgICAgcmQuZGF0ID0gcmQuZGF0LAogICAgICAgICAgICAgICAgICAgICAgICAgZGUucGFyYW0gPSBkZS5wYXJhbSkKCmNhdChsZW5ndGgodW5pcXVlKG1lcmdlLnJlc3VsdCRjbCkpLCIgQ2x1c3RlcnMiKQpgYGAKYGBge3J9CkxOLmRhdGEkaXRlci5jbHVzdCA8LSBtZXJnZS5yZXN1bHQkY2wKCklkZW50cyhMTi5kYXRhKSA8LSAiaXRlci5jbHVzdCIKCmNvbG9ycyA8LSAgYygiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNjYzNhMWIiKQoKRGltUGxvdChMTi5kYXRhLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICNjb2xzID0gY29sb3JzLAogICAgICAgIHB0LnNpemUgPSAxLjUpICYgTm9BeGVzKCkKYGBgCgpgYGB7ciBjbGFzcy5vdXRwdXQ9InNjcm9sbC0xMDAifQpOZXVyb25zLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoTE4uZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gInJvYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCmBgYApgYGB7cn0KdG9wMTAgPC0gTmV1cm9ucy5tYXJrZXJzICU+JQogICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICAgICAgICBmaWx0ZXIocG93ZXIgPiAwLjQ1KQoKRG9IZWF0bWFwKExOLmRhdGEsCiAgICAgICAgICBncm91cC5jb2xvcnMgPSBjKCIjZWJjYjJlIiwgIiM5ZWMyMmYiLCAiI2NjM2ExYiIpLAogICAgICAgICAgZmVhdHVyZXMgPSB0b3AxMCRnZW5lKSArIE5vTGVnZW5kKCkKYGBgCmBgYHtyfQpGZWF0dXJlUGxvdChvYmplY3QgPSBMTi5kYXRhLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoIkZveGcxIiwgIlpmcG0yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJMaHgxIiwgIlppYzUiLCAiWmZwNTAzIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAxLAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbEduQnUiKSksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICBvcmRlciA9IFQpICYgTm9BeGVzKCkgJiBOb0xlZ2VuZCgpCmBgYAojIyBVc2UgZmF0ZSBJRCB0byBpbmZlciBsaW5lYWdlcyBhbG9uZyBkaWZmZXJlbnRpYXRpbmcgY2VsbHMKCmBgYHtyfQpOZXVyb25zLmRhdGEkQnJvYWRjbHVzdC5pZGVudCA8LSBzYXBwbHkoTmV1cm9ucy5kYXRhJEJhcmNvZGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHggJWluJSBMTi5kYXRhJEJhcmNvZGVzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gcGFzdGUwKCJOZXVyb25fIiwgTE4uZGF0YUBtZXRhLmRhdGFbeCwgIml0ZXIuY2x1c3QiXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IE5ldXJvbnMuZGF0YUBtZXRhLmRhdGFbeCwgIkJyb2FkY2x1c3QuaWRlbnQiXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KQoKSWRlbnRzKE5ldXJvbnMuZGF0YSkgPC0gIkJyb2FkY2x1c3QuaWRlbnQiCmBgYAoKYGBge3J9CkRpbVBsb3QoTmV1cm9ucy5kYXRhLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCIjZWJjYjJlIiwgIiM5ZWMyMmYiLCAiI2E5OTYxYiIsICIjY2MzYTFiIiwgIiNkMTRjOGQiLCAiIzRjYWJkYyIsICIjNWFiNzkzIiwgImdyZXk5MCIsICIjZTc4MjNhIiwgIiMwNDZjOWEiLCAiIzQ5OTBjOSIsICJncmV5NjAiKSwKICAgICAgICBwdC5zaXplID0gMC41KSAmIE5vQXhlcygpCmBgYAoKIyMgUnVuIEZhdGVJRAoKIyMjIEZhdGVJRAoKYGBge3IgY2xhc3Mub3V0cHV0PSJzY3JvbGwtMTAwIiwgY2FjaGU9VFJVRX0KTmV1cm9ucy5kYXRhIDwtIFNDVHJhbnNmb3JtKE5ldXJvbnMuZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1HYW1Qb2kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFycy50by5yZWdyZXNzID0gYygicGVyY2VudC5taXRvIiwgInBlcmNlbnQucmlibyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFQpCgpOZXVyb25zLmRhdGEgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoTmV1cm9ucy5kYXRhLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDE1MDApCmBgYAoKYGBge3J9Ck5vcm0uTWF0IDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KE5ldXJvbnMuZGF0YUBhc3NheXMkU0NUQGRhdGFbTmV1cm9ucy5kYXRhQGFzc2F5cyRTQ1RAdmFyLmZlYXR1cmVzLF0pKQoKI1JlbmFtZSBpZGVudHMKaWQgPC0gNDoxCm5hbWVzKGlkKSA8LSBsZXZlbHMoTmV1cm9ucy5kYXRhKQpOZXVyb25zLmRhdGEgPC0gUmVuYW1lSWRlbnRzKE5ldXJvbnMuZGF0YSwgaWQpCgojIFNldCBhIGNsdXN0ZXIgYXNzaWdubWVudCBmYWN0b3IgZm9yIGVhY2ggY2VsbHMKQ2x1c3RlcklkZW50IDwtIElkZW50cyhOZXVyb25zLmRhdGEpCm5hbWVzKENsdXN0ZXJJZGVudCkgPC0gbmFtZXMoSWRlbnRzKE5ldXJvbnMuZGF0YSkpCgpBdHRyYWN0b3JzIDwtIDE6MwoKIyBEaXN0YW5jZSBpbiBzcHJpbmcgc3BhY2UKeiA8LSBhcy5tYXRyaXgoZGlzdChjYmluZChOZXVyb25zLmRhdGEkU3ByaW5nXzEsIE5ldXJvbnMuZGF0YSRTcHJpbmdfMikpKQpgYGAKCmBgYHtyIGNsYXNzLm91dHB1dD0ic2Nyb2xsLTEwMCIsIGNhY2hlPVRSVUV9CkluZmVyZWQuRmF0ZS5iaWFzICA8LSBmYXRlQmlhcyhOb3JtLk1hdCwgQ2x1c3RlcklkZW50LCBBdHRyYWN0b3JzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeiA9IHosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5ucj0yMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbm5yaD0zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkYXB0PVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maWRlbmNlPTAuNzUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYmZhY3Rvcj01LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlLmRpc3Q9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkPTEyMzQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYnRyZWU9TlVMTCkKYGBgCgojIyMgSW5zcGVjdCB0ZXN0IHNldCB1c2VkIGl0ZXJhdGl2ZWx5CgpgYGB7cn0KTmV1cm9ucy5kYXRhJEZhdGVJRC5pdGVyYXRpb24gPC0gIkF0dHJhY3RvcnMiCklkZW50cyhOZXVyb25zLmRhdGEpIDwtICJGYXRlSUQuaXRlcmF0aW9uIgoKZm9yIChpIGluIHNlcSgwLCBsZW5ndGgoSW5mZXJlZC5GYXRlLmJpYXMkcmZsKSwgYnkgPSA1KVstMV0pIHsKICBpdGVyIDwtIHNlcShpLTQsaSkKICBCYXJjb2RlcyA8LSBjKCkKICBmb3IgKGogaW4gaXRlcikgewogICAgQmFyY29kZXMgPC0gYyhCYXJjb2RlcywgbmFtZXMoSW5mZXJlZC5GYXRlLmJpYXMkcmZsW1tqXV0kdGVzdCRwcmVkaWN0ZWQpKQogIH0KICBOZXVyb25zLmRhdGEgPC0gU2V0SWRlbnQoTmV1cm9ucy5kYXRhLCBjZWxscyA9IEJhcmNvZGVzLCB2YWx1ZSA9IHBhc3RlMCgiaXRlciAiLGl0ZXJbMV0sIiB0byAiLCBpdGVyWzRdKSkKfQoKRGltUGxvdChOZXVyb25zLmRhdGEsCiAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgcHQuc2l6ZSA9IDEpICYgTm9BeGVzKCkKYGBgCgojIyMgSW1wb3J0IGxpbmVhZ2UgYmlhcyBpbnRvIFNldXJhdCBtZXRhLmRhdGEKCmBgYHtyfQpwcm9icyA8LSBJbmZlcmVkLkZhdGUuYmlhcyRwcm9ic1ssc2VxKGxlbmd0aChBdHRyYWN0b3JzKSldCgpOZXVyb25zLmRhdGEkcHJvYi4xIDwtIHByb2JzJHQxCk5ldXJvbnMuZGF0YSRwcm9iLjIgPC0gcHJvYnMkdDIKTmV1cm9ucy5kYXRhJHByb2IuMyA8LSBwcm9icyR0MwoKRmVhdHVyZVBsb3Qob2JqZWN0ID0gTmV1cm9ucy5kYXRhLAogICAgICAgICAgICBmZWF0dXJlcyA9IGMoInByb2IuMSIsICJwcm9iLjIiLCAicHJvYi4zIiksCiAgICAgICAgICAgIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgIGNvbHMgPSByZXYoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG4gPSAxMSwgbmFtZSA9ICJTcGVjdHJhbCIpKSwKICAgICAgICAgICAgcmVkdWN0aW9uID0gInNwcmluZyIsCiAgICAgICAgICAgIG9yZGVyID0gVCkgJiBOb0F4ZXMoKSAmIE5vTGVnZW5kKCkKYGBgCmBgYHtyfQpOZXcuZGF0YSA8LSBkYXRhLmZyYW1lKGJhcmNvZGU9TmV1cm9ucy5kYXRhJEJhcmNvZGVzLAogICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXI9IE5ldXJvbnMuZGF0YSRCcm9hZGNsdXN0LmlkZW50LAogICAgICAgICAgICAgICAgICAgICAgIHNwcmluZzE9IE5ldXJvbnMuZGF0YSRTcHJpbmdfMSwKICAgICAgICAgICAgICAgICAgICAgICBzcHJpbmcyPSBOZXVyb25zLmRhdGEkU3ByaW5nXzIsCiAgICAgICAgICAgICAgICAgICAgICAgcHJvYi4xPSBOZXVyb25zLmRhdGEkcHJvYi4xLAogICAgICAgICAgICAgICAgICAgICAgIHByb2IuMj0gTmV1cm9ucy5kYXRhJHByb2IuMiwKICAgICAgICAgICAgICAgICAgICAgICBwcm9iLjMgPSBOZXVyb25zLmRhdGEkcHJvYi4zKQoKTmV3LmRhdGEkbGluZWFnZS5iaWFzIDwtIGNvbG5hbWVzKE5ldy5kYXRhWyw1OjddKVthcHBseShOZXcuZGF0YVssNTo3XSwxLHdoaWNoLm1heCldCgpnZ3Bsb3QoTmV3LmRhdGEsIGFlcyhzcHJpbmcxLCBzcHJpbmcyLCBjb2xvdXIgPSBsaW5lYWdlLmJpYXMpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjZTc4MjNhIiwiI2NjMzkxYiIsIiMwMjZjOWEiLCIjZDE0YzhkIikpICsKICBnZW9tX3BvaW50KCkgCmBgYAoKIyBUcmFuc2ZlcnQgaWRlbnQgdG8gdGhlIGZ1bGwgZGF0YXNldAoKYGBge3J9Ck5ldXJvbnMuZGF0YSRMaW5lYWdlLmJpYXMgPC0gTmV3LmRhdGEkbGluZWFnZS5iaWFzCgpSYXcuZGF0YSRCcm9hZGNsdXN0LmlkZW50IDwtIHNhcHBseShSYXcuZGF0YSRCYXJjb2RlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh4ICVpbiUgTmV1cm9ucy5kYXRhJEJhcmNvZGVzKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gcGFzdGUwKCJOZXVyb25fIixOZXVyb25zLmRhdGFAbWV0YS5kYXRhW3gsICJMaW5lYWdlLmJpYXMiXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IFJhdy5kYXRhQG1ldGEuZGF0YVt4LCAiQnJvYWRjbHVzdC5pZGVudCJdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pCgpJZGVudHMoUmF3LmRhdGEpIDwtICJCcm9hZGNsdXN0LmlkZW50IgpgYGAKCgpgYGB7cn0KRGltUGxvdChSYXcuZGF0YSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYygiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNhOTk2MWIiLCAiI2NjM2ExYiIsICIjZDE0YzhkIiwgIiM0Y2FiZGMiLCAiIzVhYjc5MyIsICIjZTc4MjNhIiwgIiMwNDZjOWEiLCAiZ3JleTkwIiwgIiM0OTkwYzkiKSwKICAgICAgICBwdC5zaXplID0gMC41KSAmIE5vQXhlcygpCmBgYApgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSAiUmF3LmRhdGEiXSkKZ2MoKQpgYGAKIyBQcm9qZWN0IHByb2dlbml0b3JzIGRvbWFpbiBpZGVudCBmcm9tIFdUCgpgYGB7cn0KV1QuS08gPC0gbGlzdChXVCA9IHJlYWRSRFMoIi4uL1FDLmZpbHRlcmVkLmNsdXN0ZXJlZC5jZWxscy5SRFMiKSAlPiUKICAgICAgICAgICAgICAgIHN1YnNldChzdWJzZXQgPSBvcmlnLmlkZW50ID09ICJIZW0xIiAmIENlbGxfaWRlbnQgJWluJSBjKCJDaFBfcHJvZ2VuaXRvcnMiLCAiQ2hQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEb3Jzby1NZWRpYWxfcGFsbGl1bSIsICJNZWRpYWxfcGFsbGl1bSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVtIiwgIlRoYWxhbWljX2VtaW5lbmNlIikgKSwKICAgICAgICAgICAgICBLTyA9IFJhdy5kYXRhICU+JSBzdWJzZXQoaWRlbnRzID0gYygxLDIsMyw1KSkpCgpgYGAKCgpgYGB7cn0KcDEgPC0gRGltUGxvdChvYmplY3QgPSBXVC5LT1tbIldUIl1dLAogICAgICAgIGdyb3VwLmJ5ID0gIkNlbGwuc3RhdGUiLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCIjMzFiNmJkIiwgIiNlYmNiMmUiLCAiIzllYzIyZiIsICIjY2MzYTFiIiwgIiNkMTRjOGQiLCAiIzRjYWJkYyIsICIjNWFiNzkzIiwgIiNlNzgyM2EiLCAiIzA0NmM5YSIsICIjNDk5MGM5IiksCiAgICAgICAgcHQuc2l6ZSA9IDEuNQogICAgICAgICkgICYgTm9BeGVzKCkKCnAyIDwtIERpbVBsb3QoV1QuS09bWyJLTyJdXSwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBncm91cC5ieSA9ICJCcm9hZGNsdXN0LmlkZW50IiwKICAgICAgICBjb2xzID0gYygiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNhOTk2MWIiLCAiI2NjM2ExYiIpLAogICAgICAgIHB0LnNpemUgPSAxLjUpICYgTm9BeGVzKCkKCnAxICsgcDIKYGBgCmBgYHtyfQpXVC5LT1tbIldUIl1dIDwtIE5vcm1hbGl6ZURhdGEoV1QuS09bWyJXVCJdXSwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDAsIGFzc2F5ID0gIlJOQSIpCldULktPW1siS08iXV0gPC0gTm9ybWFsaXplRGF0YShXVC5LT1tbIktPIl1dLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCwgYXNzYXkgPSAiUk5BIikKYGBgCgpgYGB7cn0KV1QuS09bWyJXVCJdXSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhXVC5LT1tbIldUIl1dLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCldULktPW1siS08iXV0gPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoV1QuS09bWyJLTyJdXSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQpgYGAKCmBgYHtyfQpmZWF0dXJlcyA8LSBTZWxlY3RJbnRlZ3JhdGlvbkZlYXR1cmVzKG9iamVjdC5saXN0ID0gV1QuS08sIG5mZWF0dXJlcyA9IDE1MDApCgpURnMgPC0gcmVhZC50YWJsZSgiVEYuY3N2Iiwgc2VwID0gIjsiKVssMV0KVEZzIDwtIGZlYXR1cmVzW2ZlYXR1cmVzICVpbiUgVEZzXQpgYGAKCiMjIHRyYW5zZmVydCBpZGVudGl0eSBsYWJlbHMgV1QgdG8gS08KCmBgYHtyIGNsYXNzLm91dHB1dD0ic2Nyb2xsLTEwMCIsIGNhY2hlPVRSVUV9CktPLmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBXVC5LT1tbIldUIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVlcnkgPSBXVC5LT1tbIktPIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBURnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAicnBjYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLmFuY2hvciA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLmZpbHRlciA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsuc2NvcmUgPSAzMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5wY3MgPSAyNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4LmZlYXR1cmVzID0gMjAwKQoKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IEtPLmFuY2hvcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWZkYXRhID0gV1QuS09bWyJXVCJdXSRDZWxsLnN0YXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6MjUpCgpXVC5LT1tbIktPIl1dIDwtIEFkZE1ldGFEYXRhKFdULktPW1siS08iXV0sIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCmBgYApgYGB7cn0KY29scyA8LSBicmV3ZXIucGFsKG4gPTExLCBuYW1lID0gIlNwZWN0cmFsIikKCmdncGxvdChXVC5LT1tbIktPIl1dQG1ldGEuZGF0YSwgYWVzKFNwcmluZ18xLCBTcHJpbmdfMikpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1wcmVkaWN0aW9uLnNjb3JlLm1heCksIHNpemU9MSwgc2hhcGU9MTYpICsgCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnM9cmV2KGNvbHMpLCBuYW1lPSdwcmVkaWN0aW9uLnNjb3JlLm1heCcpCmBgYAoKYGBge3J9CnAxIDwtIERpbVBsb3Qob2JqZWN0ID0gV1QuS09bWyJXVCJdXSwKICAgICAgICBncm91cC5ieSA9ICJDZWxsLnN0YXRlIiwKICAgICAgICByZWR1Y3Rpb24gPSAic3ByaW5nIiwKICAgICAgICBjb2xzID0gYygiIzcyOTNjOCIsICIjYjc5ZjBiIiwgIiMzY2E3M2YiLCIjMzFiNmJkIiwKICAgICAgICAgICAgICAgICAiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNhOTk2MWIiLCAiI2NjM2ExYiIsCiAgICAgICAgICAgICAgICAgIiNkMTRjOGQiLCAiIzRjYWJkYyIsICIjNWFiNzkzIiwgIiNlNzgyM2EiLAogICAgICAgICAgICAgICAgICIjMDQ2YzlhIiwgIiM0OTkwYzkiKSwKICAgICAgICBwdC5zaXplID0gMSkgICYgTm9BeGVzKCkKCnAyIDwtIERpbVBsb3QoV1QuS09bWyJLTyJdXSwKICAgICAgICAgICAgICBncm91cC5ieSA9ICJwcmVkaWN0ZWQuaWQiLAogICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgICAgICAgIGNvbHMgPSBjKCIjMzFiNmJkIiwgIiNlYmNiMmUiLCAiIzllYzIyZiIsICIjYTk5NjFiIiwgIiNjYzNhMWIiKSwKICAgICAgICAgICAgICBwdC5zaXplID0gMSkgJiBOb0F4ZXMoKQoKcDEgKyBwMgpgYGAKCiMjIFRyYW5zZmVydCB0byB0aGUgZnVsbCBkYXRhc2V0CgpgYGB7cn0KUmF3LmRhdGEkQ2VsbC5pZGVudCA8LSBzYXBwbHkoUmF3LmRhdGEkQmFyY29kZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoeCAlaW4lIFdULktPW1siS08iXV0kQmFyY29kZXMpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBXVC5LT1tbIktPIl1dQG1ldGEuZGF0YVt4LCAicHJlZGljdGVkLmlkIl0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IFJhdy5kYXRhQG1ldGEuZGF0YVt4LCAiQnJvYWRjbHVzdC5pZGVudCJdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pCmBgYAoKCmBgYHtyfQpEaW1QbG90KG9iamVjdCA9IFJhdy5kYXRhLAogICAgICAgIGdyb3VwLmJ5ID0gIkNlbGwuaWRlbnQiLAogICAgICAgIHJlZHVjdGlvbiA9ICJzcHJpbmciLAogICAgICAgIGNvbHMgPSBjKCAiIzRjYWJkYyIsICIjNzI5M2M4IiwgImdyZXk0MCIgLCIjM2NhNzNmIiwiZ3JleTgwIiwKICAgICAgICAgICAgICAgICAgIiMzMWI2YmQiLCAiI2ViY2IyZSIsICIjOWVjMjJmIiwgIiNhOTk2MWIiLAogICAgICAgICAgICAgICAgICIjMDQ2YzlhIiwgIiNjYzNhMWIiLCIjNDk5MGM5IiwiI2U3ODIzYSIpLAogICAgICAgIHB0LnNpemUgPSAwLjUpICAmIE5vQXhlcygpCmBgYAoKIyBDaGFuZ2UgZ2VuZSBuYW1lIGFubm90YXRpb24KClJlYWRzIHdlcmUgcmVhbGlnbmVkIHVzaW5nIHRoZSBzYW1lIHRyYW5zY3JpcHRvbWUgYW5ub3RhdGlvbiBhcyB0aGUgV1QgRTExLjUtRTEyLjUgZGF0YXNldC4gV2UgcmUgaW1wb3J0IHRoZSBjb3VudCBtYXRyaXggZnJvbSB0aGUgcmVhbGlnbm1lbnQuCgpgYGB7cn0Kcm0obGlzdCA9IGxzKClbIWxzKCkgJWluJSAiUmF3LmRhdGEiXSkKZ2MoKQpgYGAKCgpgYGB7ciBjbGFzcy5vdXRwdXQ9InNjcm9sbC0xMDAiLCBjYWNoZT1UUlVFfQpSYXcuZGF0YUBhc3NheXNbWyJSTkEiXV1AY291bnRzIDwtIFJlYWQxMFgoIi4uLy4uL1Jhd0RhdGEvR21uY19LTy9tbTEwX3JlZi9vdXRzL2ZpbHRlcmVkX2ZlYXR1cmVfYmNfbWF0cml4LyIpWyxSYXcuZGF0YSRCYXJjb2Rlc10KUmF3LmRhdGFAYXNzYXlzW1siUk5BIl1dQGRhdGEgPC0gUmF3LmRhdGFAYXNzYXlzW1siUk5BIl1dQGNvdW50cwoKUmF3LmRhdGEgPC0gU0NUcmFuc2Zvcm0oUmF3LmRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG1HYW1Qb2kiLAogICAgICAgICAgICAgICAgICAgICAgICB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJwZXJjZW50Lm1pdG8iKSwKICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFQpCmBgYAoKIyBTYXZlIHRoZSBvYmplY3QKCmBgYHtyIFNhdmUgUkRTfQpzYXZlUkRTKFJhdy5kYXRhLCAiLi9HbW5jS08uY2VsbHMuUkRTIikKYGBgCgoKIyBTZXNzaW9uIEluZm8KCmBgYHtyfQojZGF0ZQpmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICVCLCAlWSwgJUgsJU0iKQoKI1BhY2thZ2VzIHVzZWQKc2Vzc2lvbkluZm8oKQpgYGA=