1. load libraries
2. Load Seurat Object
load("../5-SS_ScRNA_Data_Analysis/4-ScSS_MyAnalysis_on_SS/0-Important_R_OBJ/All_Normal-PBMC_Abnormal-cellLines_T_cells_Merged_Annotated_UMAP_on_Clusters_to_USE.Robj")
All_samples_Merged
An object of class Seurat
62625 features across 46976 samples within 6 assays
Active assay: SCT (25901 features, 3000 variable features)
3 layers present: counts, data, scale.data
5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
4 dimensional reductions calculated: pca, umap, integrated_dr, ref.umap
DimPlot(All_samples_Merged,group.by = "cell_line",
reduction = "umap",
label.size = 3,
repel = T,
label = T)

DimPlot(All_samples_Merged,
group.by = "SCT_snn_res.0.9",
reduction = "umap",
label.size = 3,
repel = T,
label = T)

cluster_table <- table(Idents(All_samples_Merged))
DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2",
reduction = "umap",
label.size = 3,
repel = T,
label = T)

library(clustree)
Le chargement a nécessité le package : ggraph
Attachement du package : 'ggraph'
L'objet suivant est masqué depuis 'package:sp':
geometry
clustree(All_samples_Merged, prefix = "SCT_snn_res.")

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l1",
reduction = "umap",
label.size = 3,
repel = T,
label = T, label.box = T)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l1",
reduction = "umap",
label.size = 3,
repel = T,
label = F)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2",
reduction = "umap",
label.size = 3,
repel = T,
label = T, label.box = T)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2",
reduction = "umap",
label.size = 3,
repel = T,
label = F)

DimPlot(All_samples_Merged, group.by = "predicted.celltype.l2",
reduction = "umap",
label.size = 3,
repel = T,
label = T, label.box = T)

table(All_samples_Merged$predicted.celltype.l2, All_samples_Merged$SCT_snn_res.0.9)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
CD4 CTL 0 0 0 0 0 0 2 0 4 0 0 0 0 0 0 0 0 0 0
CD4 Naive 0 0 0 0 0 0 595 0 100 0 0 1 0 0 0 0 6 0 4
CD4 Proliferating 5124 5231 3823 2401 1748 2535 0 2547 0 1263 1329 20 1327 598 41 237 0 154 1
CD4 TCM 978 158 501 1366 21 24 2170 22 1892 266 585 1859 41 111 406 57 235 35 61
CD4 TEM 0 0 0 8 0 0 19 0 27 0 0 15 0 0 0 0 0 0 0
CD8 Naive 6 0 2 0 0 0 304 0 61 0 19 0 1 3 2 0 12 0 3
CD8 TCM 0 0 0 76 0 0 115 0 137 10 0 72 0 0 0 0 2 0 1
CD8 TEM 0 0 0 0 0 0 27 0 182 8 0 0 0 0 0 0 0 0 0
cDC2 9 0 155 0 0 23 0 5 1 0 67 0 9 43 0 22 0 2 0
dnT 1 0 0 2 2 0 4 0 33 0 0 0 0 0 0 7 11 0 1
gdT 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 0 0
HSPC 167 8 285 1 0 744 1 652 1 1 12 8 401 43 1 26 0 6 0
ILC 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
MAIT 0 0 0 0 0 0 4 0 50 0 0 0 0 0 0 0 2 0 0
NK 0 0 0 0 0 0 0 0 91 0 0 0 0 0 0 0 0 0 1
NK Proliferating 7 11 162 20 1971 4 0 4 0 644 10 0 0 0 0 31 0 0 0
Treg 11 0 2 1 0 0 50 0 103 0 0 0 0 1 0 20 12 0 5
3. Data PREPERATION
#Extract the mean protein expression for each cell line:
# Assuming 'cell_line' is a metadata column in your Seurat object
cell_lines <- unique(All_samples_Merged$cell_line)
# Calculate mean expression for each protein in each cell line
mean_expression <- sapply(cell_lines, function(cl) {
cells <- WhichCells(All_samples_Merged, expression = cell_line == cl)
rowMeans(LayerData(All_samples_Merged, assay = "ADT", layer = "data")[, cells])
})
#Calculate distances between cell lines based on protein expression:
# Calculate Euclidean distances
dist_matrix <- dist(t(mean_expression))
Plus d’une classe "dist" est trouvée en cache : Utilisation de la première, depuis l’espace de noms 'spam'
Aussi défini par 'BiocGenerics'
# Convert distance matrix to a phylogenetic tree
tree <- nj(dist_matrix)
#Visualize the tree:
# Plot the tree
plot(tree, main = "Cell Line Similarity Tree Based on Protein Expression")

#Optionally, you can create a heatmap of protein expression:
# Create a heatmap
pheatmap(mean_expression,
main = "Protein Expression Heatmap",
scale = "row",
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE)

NA
NA
NA
NA
NA
DefaultAssay(All_samples_Merged) <- 'ADT'
# ====================================
# Phylogenetic Tree Construction and Visualization
# ====================================
# Load necessary libraries
library(ape)
library(phangorn)
library(plotly)
library(phytools)
# ====================================
# Step 1: Prepare Mean Expression Data
# ====================================
# Assuming 'mean_expression' is a matrix with proteins as rows and cell lines as columns
# Transpose mean_expression to ensure rows are cell lines and columns are proteins
mean_expression_cell_lines <- t(mean_expression)
# Step 2: Compute the Distance Matrix
# ====================================
# Calculate the Euclidean distance matrix between the cell lines
dist_matrix <- dist(mean_expression_cell_lines, method = "euclidean")
Plus d’une classe "dist" est trouvée en cache : Utilisation de la première, depuis l’espace de noms 'spam'
Aussi défini par 'BiocGenerics'
# ====================================
# Step 3: Construct the Phylogenetic Tree
# ====================================
# Create a hierarchical clustering object using UPGMA method
hc <- hclust(dist_matrix, method = "average")
# Convert the hierarchical clustering object into a phylogenetic tree
phylo_tree <- as.phylo(hc)
# ====================================
# Step 4: Visualize the Phylogenetic Tree Using Different Methods
# ====================================
# Method 1: Basic Tree Plot Using `ape`
plot(phylo_tree, main = "Phylogenetic Tree of Sézary Syndrome Cell Lines (ape)",
type = "phylo", no.margin = TRUE)
tiplabels(cex = 0.7, adj = 0.5) # Adjust tip label size and position

library(plotly)
library(phytools)
# Generate the phylogenetic tree (this should be done beforehand)
# phylo_tree <- ... # your phylogenetic tree construction code here
# Prepare data for plotting
edge_data <- as.data.frame(phylo_tree$edge)
edge_data$length <- phylo_tree$edge.length
# Create a scatter plot for the phylogenetic tree
plot_ly(data = edge_data,
x = ~length,
y = ~V1, # Accessing the first column of the edge_data
type = 'scatter', mode = 'lines+text',
text = c(phylo_tree$tip.label, rep("", nrow(edge_data) - length(phylo_tree$tip.label))),
textposition = 'top') %>%
layout(title = "Phylogenetic Tree of Sézary Syndrome Cell Lines (plotly)",
xaxis = list(title = "Branch Length"),
yaxis = list(title = "Nodes"))
# Method 4: Using `phytools`
if (requireNamespace("phytools", quietly = TRUE)) {
library(phytools)
plot(phylo_tree, main = "Phylogenetic Tree of Sézary Syndrome Cell Lines (phytools)",
edge.width = 2, show.tip.label = TRUE, type = "unrooted")
} else {
message("phytools package is not installed. Please install it for this visualization.")
}

# ====================================
# Step 5: Save the Tree in Newick Format (Optional)
# ====================================
# Save the tree as a Newick file for further analysis or visualization
write.tree(phylo_tree, file = "phylogenetic_tree_cell_lines.newick")
# ====================================
# End of Script
# ====================================
DefaultAssay(All_samples_Merged) <- 'ADT'
# Get cluster information
cluster_info <- All_samples_Merged$SCT_snn_res.0.9
print(table(cluster_info)) # This will show the distribution of cells across clusters
cluster_info
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
6303 5408 4930 3875 3742 3330 3291 3230 2696 2192 2022 1975 1779 799 450 400 280 197 77
# Get unique cluster IDs
clusters <- sort(unique(cluster_info))
print(clusters) # This will show you what cluster IDs are actually present
[1] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Levels: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# Calculate mean expression for each protein in each cluster
mean_expression_clusters <- sapply(clusters, function(cl) {
cells <- names(cluster_info)[cluster_info == cl]
rowMeans(LayerData(All_samples_Merged, assay = "ADT", layer = "data")[, cells, drop = FALSE])
})
# Check the dimensions of the resulting matrix
print(dim(mean_expression_clusters))
[1] 28 19
# Create cluster labels starting from 0
cluster_labels <- paste0("Cluster ", seq(0, length(clusters) - 1))
# Set column names
colnames(mean_expression_clusters) <- cluster_labels
# Create the heatmap
pheatmap(mean_expression_clusters,
main = "Protein Expression Heatmap by Cluster",
scale = "row",
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
fontsize_col = 8,
angle_col = 45)

# For the tree visualization
dist_matrix_clusters <- dist(t(mean_expression_clusters))
Plus d’une classe "dist" est trouvée en cache : Utilisation de la première, depuis l’espace de noms 'spam'
Aussi défini par 'BiocGenerics'
tree_clusters <- nj(dist_matrix_clusters)
plot(tree_clusters, main = "Cluster Similarity Tree Based on Protein Expression")

NA
NA
NA
4. Data PREPERATION
DefaultAssay(All_samples_Merged) <- 'ADT'
# Identify multimodal neighbors. These will be stored in the neighbors slot,
# and can be accessed using bm[['weighted.nn']]
# The WNN graph can be accessed at bm[["wknn"]],
# and the SNN graph used for clustering at bm[["wsnn"]]
# Cell-specific modality weights can be accessed at bm$RNA.weight
All_samples_Merged <- FindMultiModalNeighbors(
All_samples_Merged, reduction.list = list("pca", "apca"),
dims.list = list(1:20, 1:18), modality.weight.name = "RNA.weight"
)
Calculating cell-specific modality weights
Finding 20 nearest neighbors for each modality.
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~15s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=29s
Calculating kernel bandwidths
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~01s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=02s
Avis : The number of provided modality.weight.name is not equal to the number of modalities. SCT.weight ADT.weight are used to store the modality weightsFinding multimodal neighbors
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~51s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01m 47s
| | 0 % ~calculating
|+++++++++++++++++++++++++ | 50% ~02s
|++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=04s
Constructing multimodal KNN graph
Constructing multimodal SNN graph
5. Visualization RNA+ADT


p1 <- DimPlot(All_samples_Merged, reduction = 'wnn.umap', label = TRUE, repel = TRUE, label.size = 2.5) + NoLegend()
p2 <- DimPlot(All_samples_Merged, reduction = 'wnn.umap', group.by = 'predicted.celltype.l2', label = TRUE, repel = TRUE, label.size = 2.5) + NoLegend()
p1 + p2
DimPlot(All_samples_Merged, reduction = 'wnn.umap', group.by = "cell_line",label = TRUE, repel = TRUE, label.size = 2.5)
DimPlot(All_samples_Merged, reduction = 'wnn.umap', group.by = "wsnn_res.0.5",label = TRUE, repel = TRUE, label.size = 2.5)

DimPlot(All_samples_Merged, reduction = 'wnn.umap', group.by = 'predicted.celltype.l2', label = TRUE, repel = TRUE, label.size = 2.5)



p3 <- DimPlot(All_samples_Merged, reduction = 'rna.umap', group.by = 'predicted.celltype.l2', label = TRUE,
repel = TRUE, label.size = 2.5) + NoLegend()
p4 <- DimPlot(All_samples_Merged, reduction = 'adt.umap', group.by = 'predicted.celltype.l2', label = TRUE,
repel = TRUE, label.size = 2.5) + NoLegend()
p3 + p4
DimPlot(All_samples_Merged, reduction = 'rna.umap', group.by = "cell_line",label = TRUE, repel = TRUE, label.size = 2.5)
DimPlot(All_samples_Merged, reduction = 'rna.umap', group.by = "seurat_clusters",label = TRUE, repel = TRUE, label.size = 2.5)

DimPlot(All_samples_Merged, reduction = 'rna.umap', group.by = 'predicted.celltype.l2', label = TRUE,
repel = TRUE, label.size = 2.5)

DimPlot(All_samples_Merged, reduction = 'adt.umap', group.by = "cell_line",label = TRUE, repel = TRUE, label.size = 2.5)

DimPlot(All_samples_Merged, reduction = 'adt.umap', group.by = "seurat_clusters",label = TRUE, repel = TRUE, label.size = 2.5)

DimPlot(All_samples_Merged, reduction = 'adt.umap', group.by = 'predicted.celltype.l2', label = TRUE,
repel = TRUE, label.size = 2.5) + NoLegend()

FeaturePlot(All_samples_Merged, features = c("adt_CD45RA","adt_CD45RO","adt_CD5","adt_CD274", "adt_CD95"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_TCRab", "adt_CD7", "adt_CD3", "adt_CD28"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_CD26", "adt_CD44", "adt_CD62L","adt_CXCR3", "adt_CD127", "adt_CD45"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_CCR6","adt_CCR7","adt_CCR8","adt_CCR10"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_CD30","adt_CD40","adt_CCR4","adt_CD4" ,"adt_CD25"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_PD1","adt_CD62L","adt_CD95","adt_TCRab", "adt_CXCR4"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("adt_CD2","adt_CD28","adt_CD127","adt_CD19"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("rna_TP53","rna_CARD11","rna_ARID1A","rna_FAS","rna_CCR4"),
reduction = 'wnn.umap', max.cutoff = 3, ncol = 3)

FeaturePlot(All_samples_Merged, features = c("rna_PLS3","rna_STAT4","rna_GATA3","rna_TRAIL","rna_CD1D","rna_RHOA","rna_TNFRSF1B"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)
Avis : The following features could not be found rna_TRAILAvis : The following requested variables were not found: rna_TRAIL

FeaturePlot(All_samples_Merged, features = c("rna_KIR3DL2","rna_NKp46","rna_IL2RA","rna_TOX","rna_STAT5A"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)
Avis : The following features could not be found rna_NKp46Avis : The following requested variables were not found: rna_NKp46

FeaturePlot(All_samples_Merged, features = c("rna_MYC","rna_MNT","rna_EPHA4","rna_DNM3","rna_TWIST1"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)

FeaturePlot(All_samples_Merged, features = c("rna_TRAF2","rna_SELL","rna_miR21","rna_FCL3","rna_PDCD1","rna_CXCL13"),
reduction = 'wnn.umap', max.cutoff = 2,
cols = c("lightgrey","darkgreen"), ncol = 3)
Avis : The following features could not be found rna_miR21, rna_FCL3Avis : The following requested variables were not found: rna_miR21, rna_FCL3

NA
NA
NA
NA
NA
VlnPlot(All_samples_Merged, features = "SCT.weight", group.by = 'predicted.celltype.l2', sort = TRUE, pt.size = 0.1) +
NoLegend()

VlnPlot(All_samples_Merged, features = "ADT.weight", group.by = 'predicted.celltype.l2', sort = TRUE, pt.size = 0.1) +
NoLegend()

table(All_samples_Merged$predicted.celltype.l2, All_samples_Merged$wsnn_res.0.5)
0 1 10 11 12 13 14 15 16 17 18 19 2 3 4 5 6 7 8 9
CD4 CTL 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 5 0 0 0
CD4 Naive 0 0 0 0 0 0 21 0 0 0 0 4 0 0 0 0 1 679 1 0
CD4 Proliferating 5025 3002 922 1302 1420 581 0 283 31 144 88 0 5242 3797 2573 2600 0 0 69 1300
CD4 TCM 959 286 1021 46 179 114 550 84 428 40 17 61 132 477 27 25 2144 1605 1991 602
CD4 TEM 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 45 0 22 0
CD8 Naive 6 0 0 1 0 3 41 0 2 0 0 3 0 2 0 0 20 316 0 19
CD8 TCM 0 10 53 0 2 0 9 1 0 0 0 1 0 0 0 0 232 13 92 0
CD8 TEM 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 209 0 0 0
cDC2 9 0 0 9 0 43 0 25 0 2 0 0 0 147 27 5 0 0 0 69
dnT 0 0 0 0 3 0 33 7 0 0 0 1 0 1 0 0 14 2 0 0
gdT 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0
HSPC 158 1 0 399 0 36 2 37 3 5 3 0 9 285 755 653 0 1 0 10
ILC 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
MAIT 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 54 0 0 0
NK 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 91 0 0 0
NK Proliferating 7 2611 8 0 11 0 0 33 0 0 0 0 11 166 4 5 0 0 0 8
Treg 3 0 0 0 1 1 29 30 0 0 0 4 0 1 0 0 102 34 0 0
# library(clustree)
# clustree(All_samples_Merged, prefix = "wsnn_res.")
6. Save the Seurat object as an Robj file
save(All_samples_Merged, file = "../5-SS_ScRNA_Data_Analysis/4-ScSS_MyAnalysis_on_SS/0-Important_R_OBJ/All_samples_Merged_WNN_correct_on_HPC.Robj")
LS0tCnRpdGxlOiAiV05OIGFuYWx5c2lzIG9mIENJVEUtc2VxLCBSTkEgKyBBRFQtUGFydDIiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU2V1cmF0T2JqZWN0KQpsaWJyYXJ5KFNldXJhdERhdGEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHJldGljdWxhdGUpCmxpYnJhcnkoQXppbXV0aCkKbGlicmFyeShkcGx5cikKbGlicmFyeShSdHNuZSkKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShhcGUpCmxpYnJhcnkocGhlYXRtYXApCgpgYGAKCiMgMi4gTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7ciBsb2FkX3NldXJhdCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9CgogbG9hZCgiLi4vNS1TU19TY1JOQV9EYXRhX0FuYWx5c2lzLzQtU2NTU19NeUFuYWx5c2lzX29uX1NTLzAtSW1wb3J0YW50X1JfT0JKL0FsbF9Ob3JtYWwtUEJNQ19BYm5vcm1hbC1jZWxsTGluZXNfVF9jZWxsc19NZXJnZWRfQW5ub3RhdGVkX1VNQVBfb25fQ2x1c3RlcnNfdG9fVVNFLlJvYmoiKQogCiAgQWxsX3NhbXBsZXNfTWVyZ2VkCgogIAogIERpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLGdyb3VwLmJ5ID0gImNlbGxfbGluZSIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBUKQoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsCiAgICAgICAgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMC45IiwgCiAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLAogICAgICAgIGxhYmVsLnNpemUgPSAzLAogICAgICAgIHJlcGVsID0gVCwKICAgICAgICBsYWJlbCA9IFQpCgpjbHVzdGVyX3RhYmxlIDwtIHRhYmxlKElkZW50cyhBbGxfc2FtcGxlc19NZXJnZWQpKQoKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCkKCmxpYnJhcnkoY2x1c3RyZWUpCmNsdXN0cmVlKEFsbF9zYW1wbGVzX01lcmdlZCwgcHJlZml4ID0gIlNDVF9zbm5fcmVzLiIpCgoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMSIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMSIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBGKQoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBUKQoKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIAogICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwKICAgICAgICBsYWJlbC5zaXplID0gMywKICAgICAgICByZXBlbCA9IFQsCiAgICAgICAgbGFiZWwgPSBGKQoKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCAKICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsCiAgICAgICAgbGFiZWwuc2l6ZSA9IDMsCiAgICAgICAgcmVwZWwgPSBULAogICAgICAgIGxhYmVsID0gVCwgbGFiZWwuYm94ID0gVCkKCgoKdGFibGUoQWxsX3NhbXBsZXNfTWVyZ2VkJHByZWRpY3RlZC5jZWxsdHlwZS5sMiwgQWxsX3NhbXBsZXNfTWVyZ2VkJFNDVF9zbm5fcmVzLjAuOSkKCgpgYGAKCgojIDMuIERhdGEgUFJFUEVSQVRJT04KYGBge3IgZGF0YSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICdBRFQnCgpWYXJpYWJsZUZlYXR1cmVzKEFsbF9zYW1wbGVzX01lcmdlZCkgPC0gcm93bmFtZXMoQWxsX3NhbXBsZXNfTWVyZ2VkW1siQURUIl1dKQoKIyB3ZSB3aWxsIHVzZSBhbGwgQURUIGZlYXR1cmVzIGZvciBkaW1lbnNpb25hbCByZWR1Y3Rpb24KIyB3ZSBzZXQgYSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gbmFtZSB0byBhdm9pZCBvdmVyd3JpdGluZyB0aGUgCkFsbF9zYW1wbGVzX01lcmdlZCA8LSBOb3JtYWxpemVEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAnQ0xSJywgbWFyZ2luID0gMikgJT4lIAogIFNjYWxlRGF0YSgpICU+JSBSdW5QQ0EocmVkdWN0aW9uLm5hbWUgPSAnYXBjYScsIG5wY3MgPTI4LCBtYXhpdCA9IDUwMDApCgoKCgojRXh0cmFjdCB0aGUgbWVhbiBwcm90ZWluIGV4cHJlc3Npb24gZm9yIGVhY2ggY2VsbCBsaW5lOgoKIyBBc3N1bWluZyAnY2VsbF9saW5lJyBpcyBhIG1ldGFkYXRhIGNvbHVtbiBpbiB5b3VyIFNldXJhdCBvYmplY3QKY2VsbF9saW5lcyA8LSB1bmlxdWUoQWxsX3NhbXBsZXNfTWVyZ2VkJGNlbGxfbGluZSkKCgoKIyBDYWxjdWxhdGUgbWVhbiBleHByZXNzaW9uIGZvciBlYWNoIHByb3RlaW4gaW4gZWFjaCBjZWxsIGxpbmUKbWVhbl9leHByZXNzaW9uIDwtIHNhcHBseShjZWxsX2xpbmVzLCBmdW5jdGlvbihjbCkgewogIGNlbGxzIDwtIFdoaWNoQ2VsbHMoQWxsX3NhbXBsZXNfTWVyZ2VkLCBleHByZXNzaW9uID0gY2VsbF9saW5lID09IGNsKQogIHJvd01lYW5zKExheWVyRGF0YShBbGxfc2FtcGxlc19NZXJnZWQsIGFzc2F5ID0gIkFEVCIsIGxheWVyID0gImRhdGEiKVssIGNlbGxzXSkKfSkKCgojQ2FsY3VsYXRlIGRpc3RhbmNlcyBiZXR3ZWVuIGNlbGwgbGluZXMgYmFzZWQgb24gcHJvdGVpbiBleHByZXNzaW9uOgoKIyBDYWxjdWxhdGUgRXVjbGlkZWFuIGRpc3RhbmNlcwpkaXN0X21hdHJpeCA8LSBkaXN0KHQobWVhbl9leHByZXNzaW9uKSkKCiMgQ29udmVydCBkaXN0YW5jZSBtYXRyaXggdG8gYSBwaHlsb2dlbmV0aWMgdHJlZQp0cmVlIDwtIG5qKGRpc3RfbWF0cml4KQoKI1Zpc3VhbGl6ZSB0aGUgdHJlZToKCiMgUGxvdCB0aGUgdHJlZQpwbG90KHRyZWUsIG1haW4gPSAiQ2VsbCBMaW5lIFNpbWlsYXJpdHkgVHJlZSBCYXNlZCBvbiBQcm90ZWluIEV4cHJlc3Npb24iKQoKI09wdGlvbmFsbHksIHlvdSBjYW4gY3JlYXRlIGEgaGVhdG1hcCBvZiBwcm90ZWluIGV4cHJlc3Npb246CgojIENyZWF0ZSBhIGhlYXRtYXAKcGhlYXRtYXAobWVhbl9leHByZXNzaW9uLCAKICAgICAgICAgbWFpbiA9ICJQcm90ZWluIEV4cHJlc3Npb24gSGVhdG1hcCIsCiAgICAgICAgIHNjYWxlID0gInJvdyIsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsIAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFRSVUUpCgoKCgoKCgpgYGAKYGBge3IgZGF0YTIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQpEZWZhdWx0QXNzYXkoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAnQURUJwoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBQaHlsb2dlbmV0aWMgVHJlZSBDb25zdHJ1Y3Rpb24gYW5kIFZpc3VhbGl6YXRpb24KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHBoYW5nb3JuKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwaHl0b29scykKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgU3RlcCAxOiBQcmVwYXJlIE1lYW4gRXhwcmVzc2lvbiBEYXRhCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIEFzc3VtaW5nICdtZWFuX2V4cHJlc3Npb24nIGlzIGEgbWF0cml4IHdpdGggcHJvdGVpbnMgYXMgcm93cyBhbmQgY2VsbCBsaW5lcyBhcyBjb2x1bW5zCiMgVHJhbnNwb3NlIG1lYW5fZXhwcmVzc2lvbiB0byBlbnN1cmUgcm93cyBhcmUgY2VsbCBsaW5lcyBhbmQgY29sdW1ucyBhcmUgcHJvdGVpbnMKbWVhbl9leHByZXNzaW9uX2NlbGxfbGluZXMgPC0gdChtZWFuX2V4cHJlc3Npb24pCgojIFN0ZXAgMjogQ29tcHV0ZSB0aGUgRGlzdGFuY2UgTWF0cml4CiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIENhbGN1bGF0ZSB0aGUgRXVjbGlkZWFuIGRpc3RhbmNlIG1hdHJpeCBiZXR3ZWVuIHRoZSBjZWxsIGxpbmVzCmRpc3RfbWF0cml4IDwtIGRpc3QobWVhbl9leHByZXNzaW9uX2NlbGxfbGluZXMsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTdGVwIDM6IENvbnN0cnVjdCB0aGUgUGh5bG9nZW5ldGljIFRyZWUKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgQ3JlYXRlIGEgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb2JqZWN0IHVzaW5nIFVQR01BIG1ldGhvZApoYyA8LSBoY2x1c3QoZGlzdF9tYXRyaXgsIG1ldGhvZCA9ICJhdmVyYWdlIikKCiMgQ29udmVydCB0aGUgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgb2JqZWN0IGludG8gYSBwaHlsb2dlbmV0aWMgdHJlZQpwaHlsb190cmVlIDwtIGFzLnBoeWxvKGhjKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBTdGVwIDQ6IFZpc3VhbGl6ZSB0aGUgUGh5bG9nZW5ldGljIFRyZWUgVXNpbmcgRGlmZmVyZW50IE1ldGhvZHMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgTWV0aG9kIDE6IEJhc2ljIFRyZWUgUGxvdCBVc2luZyBgYXBlYApwbG90KHBoeWxvX3RyZWUsIG1haW4gPSAiUGh5bG9nZW5ldGljIFRyZWUgb2YgU8OpemFyeSBTeW5kcm9tZSBDZWxsIExpbmVzIChhcGUpIiwgCiAgICAgdHlwZSA9ICJwaHlsbyIsIG5vLm1hcmdpbiA9IFRSVUUpCnRpcGxhYmVscyhjZXggPSAwLjcsIGFkaiA9IDAuNSkgICMgQWRqdXN0IHRpcCBsYWJlbCBzaXplIGFuZCBwb3NpdGlvbgpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwaHl0b29scykKCiMgR2VuZXJhdGUgdGhlIHBoeWxvZ2VuZXRpYyB0cmVlICh0aGlzIHNob3VsZCBiZSBkb25lIGJlZm9yZWhhbmQpCiMgcGh5bG9fdHJlZSA8LSAuLi4gICMgeW91ciBwaHlsb2dlbmV0aWMgdHJlZSBjb25zdHJ1Y3Rpb24gY29kZSBoZXJlCgojIFByZXBhcmUgZGF0YSBmb3IgcGxvdHRpbmcKZWRnZV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUocGh5bG9fdHJlZSRlZGdlKQplZGdlX2RhdGEkbGVuZ3RoIDwtIHBoeWxvX3RyZWUkZWRnZS5sZW5ndGgKCiMgQ3JlYXRlIGEgc2NhdHRlciBwbG90IGZvciB0aGUgcGh5bG9nZW5ldGljIHRyZWUKcGxvdF9seShkYXRhID0gZWRnZV9kYXRhLCAKICAgICAgICB4ID0gfmxlbmd0aCwgCiAgICAgICAgeSA9IH5WMSwgICMgQWNjZXNzaW5nIHRoZSBmaXJzdCBjb2x1bW4gb2YgdGhlIGVkZ2VfZGF0YQogICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbGluZXMrdGV4dCcsIAogICAgICAgIHRleHQgPSBjKHBoeWxvX3RyZWUkdGlwLmxhYmVsLCByZXAoIiIsIG5yb3coZWRnZV9kYXRhKSAtIGxlbmd0aChwaHlsb190cmVlJHRpcC5sYWJlbCkpKSwgCiAgICAgICAgdGV4dHBvc2l0aW9uID0gJ3RvcCcpICU+JQogIGxheW91dCh0aXRsZSA9ICJQaHlsb2dlbmV0aWMgVHJlZSBvZiBTw6l6YXJ5IFN5bmRyb21lIENlbGwgTGluZXMgKHBsb3RseSkiLAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQnJhbmNoIExlbmd0aCIpLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTm9kZXMiKSkKCiMgTWV0aG9kIDQ6IFVzaW5nIGBwaHl0b29sc2AKaWYgKHJlcXVpcmVOYW1lc3BhY2UoInBoeXRvb2xzIiwgcXVpZXRseSA9IFRSVUUpKSB7CiAgbGlicmFyeShwaHl0b29scykKICBwbG90KHBoeWxvX3RyZWUsIG1haW4gPSAiUGh5bG9nZW5ldGljIFRyZWUgb2YgU8OpemFyeSBTeW5kcm9tZSBDZWxsIExpbmVzIChwaHl0b29scykiLCAKICAgICAgIGVkZ2Uud2lkdGggPSAyLCBzaG93LnRpcC5sYWJlbCA9IFRSVUUsIHR5cGUgPSAidW5yb290ZWQiKQp9IGVsc2UgewogIG1lc3NhZ2UoInBoeXRvb2xzIHBhY2thZ2UgaXMgbm90IGluc3RhbGxlZC4gUGxlYXNlIGluc3RhbGwgaXQgZm9yIHRoaXMgdmlzdWFsaXphdGlvbi4iKQp9CgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFN0ZXAgNTogU2F2ZSB0aGUgVHJlZSBpbiBOZXdpY2sgRm9ybWF0IChPcHRpb25hbCkKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgU2F2ZSB0aGUgdHJlZSBhcyBhIE5ld2ljayBmaWxlIGZvciBmdXJ0aGVyIGFuYWx5c2lzIG9yIHZpc3VhbGl6YXRpb24Kd3JpdGUudHJlZShwaHlsb190cmVlLCBmaWxlID0gInBoeWxvZ2VuZXRpY190cmVlX2NlbGxfbGluZXMubmV3aWNrIikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgRW5kIG9mIFNjcmlwdAojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKCgpgYGAKCmBgYHtyIGRhdGEzLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICdBRFQnCgojIEdldCBjbHVzdGVyIGluZm9ybWF0aW9uCmNsdXN0ZXJfaW5mbyA8LSBBbGxfc2FtcGxlc19NZXJnZWQkU0NUX3Nubl9yZXMuMC45CnByaW50KHRhYmxlKGNsdXN0ZXJfaW5mbykpICAjIFRoaXMgd2lsbCBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgY2VsbHMgYWNyb3NzIGNsdXN0ZXJzCgojIEdldCB1bmlxdWUgY2x1c3RlciBJRHMKY2x1c3RlcnMgPC0gc29ydCh1bmlxdWUoY2x1c3Rlcl9pbmZvKSkKcHJpbnQoY2x1c3RlcnMpICAjIFRoaXMgd2lsbCBzaG93IHlvdSB3aGF0IGNsdXN0ZXIgSURzIGFyZSBhY3R1YWxseSBwcmVzZW50CgojIENhbGN1bGF0ZSBtZWFuIGV4cHJlc3Npb24gZm9yIGVhY2ggcHJvdGVpbiBpbiBlYWNoIGNsdXN0ZXIKbWVhbl9leHByZXNzaW9uX2NsdXN0ZXJzIDwtIHNhcHBseShjbHVzdGVycywgZnVuY3Rpb24oY2wpIHsKICBjZWxscyA8LSBuYW1lcyhjbHVzdGVyX2luZm8pW2NsdXN0ZXJfaW5mbyA9PSBjbF0KICByb3dNZWFucyhMYXllckRhdGEoQWxsX3NhbXBsZXNfTWVyZ2VkLCBhc3NheSA9ICJBRFQiLCBsYXllciA9ICJkYXRhIilbLCBjZWxscywgZHJvcCA9IEZBTFNFXSkKfSkKCiMgQ2hlY2sgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHJlc3VsdGluZyBtYXRyaXgKcHJpbnQoZGltKG1lYW5fZXhwcmVzc2lvbl9jbHVzdGVycykpCgojIENyZWF0ZSBjbHVzdGVyIGxhYmVscyBzdGFydGluZyBmcm9tIDAKY2x1c3Rlcl9sYWJlbHMgPC0gcGFzdGUwKCJDbHVzdGVyICIsIHNlcSgwLCBsZW5ndGgoY2x1c3RlcnMpIC0gMSkpCgojIFNldCBjb2x1bW4gbmFtZXMKY29sbmFtZXMobWVhbl9leHByZXNzaW9uX2NsdXN0ZXJzKSA8LSBjbHVzdGVyX2xhYmVscwoKIyBDcmVhdGUgdGhlIGhlYXRtYXAKcGhlYXRtYXAobWVhbl9leHByZXNzaW9uX2NsdXN0ZXJzLCAKICAgICAgICAgbWFpbiA9ICJQcm90ZWluIEV4cHJlc3Npb24gSGVhdG1hcCBieSBDbHVzdGVyIiwKICAgICAgICAgc2NhbGUgPSAicm93IiwKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICBzaG93X2NvbG5hbWVzID0gVFJVRSwKICAgICAgICAgZm9udHNpemVfY29sID0gOCwKICAgICAgICAgYW5nbGVfY29sID0gNDUpCgojIEZvciB0aGUgdHJlZSB2aXN1YWxpemF0aW9uCmRpc3RfbWF0cml4X2NsdXN0ZXJzIDwtIGRpc3QodChtZWFuX2V4cHJlc3Npb25fY2x1c3RlcnMpKQp0cmVlX2NsdXN0ZXJzIDwtIG5qKGRpc3RfbWF0cml4X2NsdXN0ZXJzKQoKcGxvdCh0cmVlX2NsdXN0ZXJzLCBtYWluID0gIkNsdXN0ZXIgU2ltaWxhcml0eSBUcmVlIEJhc2VkIG9uIFByb3RlaW4gRXhwcmVzc2lvbiIpCgoKCmBgYAoKIyA0LiBEYXRhIFBSRVBFUkFUSU9OCmBgYHtyIFdOTiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICdBRFQnCgoKIyBJZGVudGlmeSBtdWx0aW1vZGFsIG5laWdoYm9ycy4gVGhlc2Ugd2lsbCBiZSBzdG9yZWQgaW4gdGhlIG5laWdoYm9ycyBzbG90LCAKIyBhbmQgY2FuIGJlIGFjY2Vzc2VkIHVzaW5nIGJtW1snd2VpZ2h0ZWQubm4nXV0KIyBUaGUgV05OIGdyYXBoIGNhbiBiZSBhY2Nlc3NlZCBhdCBibVtbIndrbm4iXV0sIAojIGFuZCB0aGUgU05OIGdyYXBoIHVzZWQgZm9yIGNsdXN0ZXJpbmcgYXQgYm1bWyJ3c25uIl1dCiMgQ2VsbC1zcGVjaWZpYyBtb2RhbGl0eSB3ZWlnaHRzIGNhbiBiZSBhY2Nlc3NlZCBhdCBibSRSTkEud2VpZ2h0CgpBbGxfc2FtcGxlc19NZXJnZWQgPC0gRmluZE11bHRpTW9kYWxOZWlnaGJvcnMoCiAgQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24ubGlzdCA9IGxpc3QoInBjYSIsICJhcGNhIiksIAogIGRpbXMubGlzdCA9IGxpc3QoMToyMCwgMToxOCksIG1vZGFsaXR5LndlaWdodC5uYW1lID0gIlJOQS53ZWlnaHQiCikKCgoKCmBgYAojIDUuIFZpc3VhbGl6YXRpb24gUk5BK0FEVApgYGB7ciBWaXN1YWxpemUsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIFJ1blVNQVAoQWxsX3NhbXBsZXNfTWVyZ2VkLCBubi5uYW1lID0gIndlaWdodGVkLm5uIiwgcmVkdWN0aW9uLm5hbWUgPSAid25uLnVtYXAiLCByZWR1Y3Rpb24ua2V5ID0gIndublVNQVBfIikKQWxsX3NhbXBsZXNfTWVyZ2VkIDwtIEZpbmRDbHVzdGVycyhBbGxfc2FtcGxlc19NZXJnZWQsIGdyYXBoLm5hbWUgPSAid3NubiIsIGFsZ29yaXRobSA9IDMsIHJlc29sdXRpb24gPSAwLjUsIHZlcmJvc2UgPSBGQUxTRSkKCnAxIDwtIERpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDIuNSkgKyBOb0xlZ2VuZCgpCnAyIDwtIERpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBncm91cC5ieSA9ICdwcmVkaWN0ZWQuY2VsbHR5cGUubDInLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDIuNSkgKyBOb0xlZ2VuZCgpCnAxICsgcDIKCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBncm91cC5ieSA9ICJjZWxsX2xpbmUiLGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMi41KQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ3dubi51bWFwJywgZ3JvdXAuYnkgPSAid3Nubl9yZXMuMC41IixsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDIuNSkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICd3bm4udW1hcCcsIGdyb3VwLmJ5ID0gJ3ByZWRpY3RlZC5jZWxsdHlwZS5sMicsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMi41KQoKYGBgCgpgYGB7ciBWaXN1YWxpemUyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkFsbF9zYW1wbGVzX01lcmdlZCA8LSBSdW5VTUFQKEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ3BjYScsIGRpbXMgPSAxOjIwLCBhc3NheSA9ICdSTkEnLCAKICAgICAgICAgICAgICByZWR1Y3Rpb24ubmFtZSA9ICdybmEudW1hcCcsIHJlZHVjdGlvbi5rZXkgPSAncm5hVU1BUF8nKQpBbGxfc2FtcGxlc19NZXJnZWQgPC0gUnVuVU1BUChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICdhcGNhJywgZGltcyA9IDE6MTgsIGFzc2F5ID0gJ0FEVCcsIAogICAgICAgICAgICAgIHJlZHVjdGlvbi5uYW1lID0gJ2FkdC51bWFwJywgcmVkdWN0aW9uLmtleSA9ICdhZHRVTUFQXycpCgpwMyA8LSBEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ3JuYS51bWFwJywgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmNlbGx0eXBlLmwyJywgbGFiZWwgPSBUUlVFLCAKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAyLjUpICsgTm9MZWdlbmQoKQpwNCA8LSBEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ2FkdC51bWFwJywgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmNlbGx0eXBlLmwyJywgbGFiZWwgPSBUUlVFLCAKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAyLjUpICsgTm9MZWdlbmQoKQpwMyArIHA0CgpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ3JuYS51bWFwJywgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIixsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDIuNSkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICdybmEudW1hcCcsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAyLjUpCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAncm5hLnVtYXAnLCBncm91cC5ieSA9ICdwcmVkaWN0ZWQuY2VsbHR5cGUubDInLCBsYWJlbCA9IFRSVUUsIAogICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDIuNSkKRGltUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIHJlZHVjdGlvbiA9ICdhZHQudW1hcCcsIGdyb3VwLmJ5ID0gImNlbGxfbGluZSIsbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAyLjUpCkRpbVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCByZWR1Y3Rpb24gPSAnYWR0LnVtYXAnLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMi41KQpEaW1QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgcmVkdWN0aW9uID0gJ2FkdC51bWFwJywgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmNlbGx0eXBlLmwyJywgbGFiZWwgPSBUUlVFLCAKICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAyLjUpICsgTm9MZWdlbmQoKQoKYGBgCgoKYGBge3IgVmlzdWFsaXplMywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpGZWF0dXJlUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygiYWR0X0NENDVSQSIsImFkdF9DRDQ1Uk8iLCJhZHRfQ0Q1IiwiYWR0X0NEMjc0IiwgImFkdF9DRDk1IiksCiAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICd3bm4udW1hcCcsIG1heC5jdXRvZmYgPSAyLCAKICAgICAgICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Z3JleSIsImRhcmtncmVlbiIpLCBuY29sID0gMykKCkZlYXR1cmVQbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSBjKCJhZHRfVENSYWIiLCAiYWR0X0NENyIsICJhZHRfQ0QzIiwgImFkdF9DRDI4IiksCiAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICd3bm4udW1hcCcsIG1heC5jdXRvZmYgPSAyLCAKICAgICAgICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Z3JleSIsImRhcmtncmVlbiIpLCBuY29sID0gMykKICAgICAgICAgICAgCiBGZWF0dXJlUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygiYWR0X0NEMjYiLCAiYWR0X0NENDQiLCAiYWR0X0NENjJMIiwiYWR0X0NYQ1IzIiwgImFkdF9DRDEyNyIsICJhZHRfQ0Q0NSIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpICAgICAKIAogRmVhdHVyZVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoImFkdF9DQ1I2IiwiYWR0X0NDUjciLCJhZHRfQ0NSOCIsImFkdF9DQ1IxMCIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpIAogCiBGZWF0dXJlUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygiYWR0X0NEMzAiLCJhZHRfQ0Q0MCIsImFkdF9DQ1I0IiwiYWR0X0NENCIgLCJhZHRfQ0QyNSIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpIAogCiBGZWF0dXJlUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygiYWR0X1BEMSIsImFkdF9DRDYyTCIsImFkdF9DRDk1IiwiYWR0X1RDUmFiIiwgImFkdF9DWENSNCIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpICAKIEZlYXR1cmVQbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSBjKCJhZHRfQ0QyIiwiYWR0X0NEMjgiLCJhZHRfQ0QxMjciLCJhZHRfQ0QxOSIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpICAKIAogCiBGZWF0dXJlUGxvdChBbGxfc2FtcGxlc19NZXJnZWQsIGZlYXR1cmVzID0gYygicm5hX1RQNTMiLCJybmFfQ0FSRDExIiwicm5hX0FSSUQxQSIsInJuYV9GQVMiLCJybmFfQ0NSNCIpLCAKICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gJ3dubi51bWFwJywgbWF4LmN1dG9mZiA9IDMsIG5jb2wgPSAzKQoKIAogRmVhdHVyZVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoInJuYV9QTFMzIiwicm5hX1NUQVQ0Iiwicm5hX0dBVEEzIiwicm5hX1RSQUlMIiwicm5hX0NEMUQiLCJybmFfUkhPQSIsInJuYV9UTkZSU0YxQiIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpICAKIAogRmVhdHVyZVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoInJuYV9LSVIzREwyIiwicm5hX05LcDQ2Iiwicm5hX0lMMlJBIiwicm5hX1RPWCIsInJuYV9TVEFUNUEiKSwKICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gJ3dubi51bWFwJywgbWF4LmN1dG9mZiA9IDIsIAogICAgICAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRncmV5IiwiZGFya2dyZWVuIiksIG5jb2wgPSAzKSAgCiAKIEZlYXR1cmVQbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSBjKCJybmFfTVlDIiwicm5hX01OVCIsInJuYV9FUEhBNCIsInJuYV9ETk0zIiwicm5hX1RXSVNUMSIpLAogICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAnd25uLnVtYXAnLCBtYXguY3V0b2ZmID0gMiwgCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGdyZXkiLCJkYXJrZ3JlZW4iKSwgbmNvbCA9IDMpICAKIAogRmVhdHVyZVBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9IGMoInJuYV9UUkFGMiIsInJuYV9TRUxMIiwicm5hX21pUjIxIiwicm5hX0ZDTDMiLCJybmFfUERDRDEiLCJybmFfQ1hDTDEzIiksCiAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICd3bm4udW1hcCcsIG1heC5jdXRvZmYgPSAyLCAKICAgICAgICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Z3JleSIsImRhcmtncmVlbiIpLCBuY29sID0gMykgIAogCgogCiAKCmBgYAoKCmBgYHtyIFZpc3VhbGl6ZTQsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIFZsblBsb3QoQWxsX3NhbXBsZXNfTWVyZ2VkLCBmZWF0dXJlcyA9ICJTQ1Qud2VpZ2h0IiwgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmNlbGx0eXBlLmwyJywgc29ydCA9IFRSVUUsIHB0LnNpemUgPSAwLjEpICsKICBOb0xlZ2VuZCgpCiBWbG5QbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSAiQURULndlaWdodCIsIGdyb3VwLmJ5ID0gJ3ByZWRpY3RlZC5jZWxsdHlwZS5sMicsIHNvcnQgPSBUUlVFLCBwdC5zaXplID0gMC4xKSArCiAgTm9MZWdlbmQoKQogCiB0YWJsZShBbGxfc2FtcGxlc19NZXJnZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyLCBBbGxfc2FtcGxlc19NZXJnZWQkd3Nubl9yZXMuMC41KQogIyBsaWJyYXJ5KGNsdXN0cmVlKQogIyBjbHVzdHJlZShBbGxfc2FtcGxlc19NZXJnZWQsIHByZWZpeCA9ICJ3c25uX3Jlcy4iKQoKYGBgCgojIDYuIFNhdmUgdGhlIFNldXJhdCBvYmplY3QgYXMgYW4gUm9iaiBmaWxlCmBgYHtyIHNhdmVST0JKfQoKc2F2ZShBbGxfc2FtcGxlc19NZXJnZWQsIGZpbGUgPSAiLi4vNS1TU19TY1JOQV9EYXRhX0FuYWx5c2lzLzQtU2NTU19NeUFuYWx5c2lzX29uX1NTLzAtSW1wb3J0YW50X1JfT0JKL0FsbF9zYW1wbGVzX01lcmdlZF9XTk5fY29ycmVjdF9vbl9IUEMuUm9iaiIpCgoKYGBgCgoKCgo=