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=