#Workspace setup

#Import data ##Load filtered objects

U1 <- Read10X_h5("Filtered h5 objects/UTI-1_filtered_feature_bc_matrix.h5")
U2 <- Read10X_h5("Filtered h5 objects/UTI-2_filtered_feature_bc_matrix.h5")
U3 <- Read10X_h5("Filtered h5 objects/UTI-3_filtered_feature_bc_matrix.h5")
C1 <- Read10X_h5("Filtered h5 objects/Control-1_filtered_feature_bc_matrix.h5")
C2 <- Read10X_h5("Filtered h5 objects/Control-2_filtered_feature_bc_matrix.h5")
C3 <- Read10X_h5("Filtered h5 objects/Control-3_filtered_feature_bc_matrix.h5")

##Create seurat objects

#Turn into seurat objects
U1 <- CreateSeuratObject(counts = U1)
U2 <- CreateSeuratObject(counts = U2)
U3 <- CreateSeuratObject(counts = U3)
C1 <- CreateSeuratObject(counts = C1)
C2 <- CreateSeuratObject(counts = C2)
C3 <- CreateSeuratObject(counts = C3)

##Merge, labeling cell.id in metadata

#merge into single seurat object, layers still separated
merged_all <- merge(U1, y = c(U2, U3, C1, C2, C3),
                add.cell.ids = c("U1_UTI", "U2_UTI", "U3_UTI", "C1_Control", "C2_Control", "C3_Control"),
                project = "RecUTI")
#Adjust metadata
merged_all$sample <- rownames(merged_all@meta.data)
merged_all@meta.data <- separate(merged_all@meta.data, col = 'sample', into = c('sample', 'condition', 'barcode'),
                             sep = '_')

#label percent mitochondrial DNA
merged_all$percent.mt <- PercentageFeatureSet(merged_all, pattern = "^mt-")

#add number of genes per UMI for each cell to metadata
#log10genesPerUMI expected is ~0.8-0.9 for scRNA data, >1.0 is suspected doublet
merged_all$log10GenesPerUMI <- log10(merged_all$nFeature_RNA) / log10(merged_all$nCount_RNA)
merged_all$GenesPerUMI <- (merged_all$nFeature_RNA / merged_all$nCount_RNA)

#QC ##log10genesperUMI

#Visualize log10genesPerUMI PRIOR to subsetting
VlnPlot(merged_all, features = "log10GenesPerUMI") +
  geom_hline(yintercept = 0.95, linetype = "dashed", color = "red") + 
  geom_hline(yintercept = 0.8, linetype = "dashed", color = "red")

#plot log10UMI vs nCount_RNA
merged_all@meta.data %>% 
    ggplot(aes(color=condition, x=nCount_RNA, fill= sample)) + 
    geom_density(alpha = 0.2) + 
    scale_x_log10() + 
    theme_classic() +
    ylab("log10 cell density") +
    geom_vline(xintercept = 500)

##qc feature plots (before subsetting)

#plot nCount vs nFeature
qcfeat1 <- FeatureScatter(merged_all, feature1 = 'nCount_RNA', feature2 = 'nFeature_RNA', group.by = 'sample', pt.size = 0.05) 
qcfeat2 <- FeatureScatter(merged_all, feature1 = "nCount_RNA", feature2 = "percent.mt", group.by = 'sample', pt.size = 0.05)
qcfeat3 <- FeatureScatter(merged_all, feature1 = "nFeature_RNA", feature2 = "percent.mt", group.by = 'sample', pt.size = 0.05)

qcfeat1 + qcfeat2 + qcfeat3

##qc vln plots (pre-subsetting)

qc_vln <- VlnPlot(merged_all, features = c('nCount_RNA', 'nFeature_RNA', 'percent.mt'), alpha = 0.1, group.by = 'sample')
qc_vln[[2]] <- qc_vln[[2]] + geom_hline(yintercept = 500) + geom_hline(yintercept = 5000)
qc_vln[[3]] <- qc_vln[[3]] + geom_hline(yintercept = 10) 
qc_vln

##Subset data - percent.mt<10, nFeatures 500-5000, log10genesperUMI>0.8

merged_all <- subset(merged_all, subset = percent.mt<10 &
                                nFeature_RNA>500 &
                                nFeature_RNA<5000 &
                                log10GenesPerUMI >=0.8)

##repeat QC vln plots

qc_vln <- VlnPlot(merged_all, features = c('nCount_RNA', 'nFeature_RNA', 'percent.mt'), alpha = 0.1, group.by = 'sample')
qc_vln[[2]] <- qc_vln[[2]] + geom_hline(yintercept = 500) + geom_hline(yintercept = 5000)
qc_vln[[3]] <- qc_vln[[3]] + geom_hline(yintercept = 10) 
qc_vln

##cell density by nFeature_RNA (post-subsetting)

#plot log10UMI vs nFeature_RNA
merged_all@meta.data %>% 
    ggplot(aes(color=condition, x=nFeature_RNA, fill= sample)) + 
    geom_density(alpha = 0.2) + 
    scale_x_log10() + 
    theme_classic() +
    ylab("log10 cell density") +
    geom_vline(xintercept = 500)

##cell density by percent.mt

#plot log10UMI vs percent.mt
merged_all@meta.data %>% 
    ggplot(aes(color=condition, x=percent.mt, fill= sample)) + 
    geom_density(alpha = 0.2) + 
    theme_classic() +
    ylab("log10 cell density") 

##Filter out low quality cells (features expressed in <10 cells)

#subset out features expressed in <10 cells (Suzstak used 10)
counts <- LayerData(merged_all, assay = "RNA", layer = "counts")
keep_genes <- rowSums(counts>0) >=10
merged_all <- subset(merged_all, features = names(keep_genes[keep_genes]))

merged_all #features 33696 -> 17500 genes with sufficient expression data
An object of class Seurat 
17535 features across 27248 samples within 1 assay 
Active assay: RNA (17535 features, 0 variable features)
 6 layers present: counts.1, counts.2, counts.3, counts.4, counts.5, counts.6

#Processing ##Join layers and preprocessing workflow

#Join layers
#Perform standard PREprocessing workflow steps to figure out if we have significant batch effects

merged_all <- JoinLayers(merged_all)
merged_all <- NormalizeData(merged_all)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
merged_all <- FindVariableFeatures(merged_all, nfeatures = 3000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
merged_all <- ScaleData(merged_all)

  |                                                                                                                           
  |                                                                                                                     |   0%
  |                                                                                                                           
  |=======================================                                                                              |  33%
  |                                                                                                                           
  |==============================================================================                                       |  67%
  |                                                                                                                           
  |=====================================================================================================================| 100%
top_var_genes_3000 <- head(VariableFeatures(merged_all), 20)
print(top_var_genes_3000)
 [1] "Jchain"   "Igkc"     "Igha"     "Hba-a1"   "Hbb-bs"   "Slc12a3"  "Slc26a4"  "Abca13"   "Atp6v1g3" "Calb1"    "Ngp"     
[12] "Mzb1"     "Lcn2"     "Ccl4"     "Robo2"    "Camp"     "Nrxn3"    "Retnlg"   "S100g"    "Cxcl10"  

##Visualize most variable features

#Visualize most variable features
VariableFeaturePlot(merged_all)

LabelPoints(points = top_var_genes_3000, plot = last_plot(), repel = TRUE)

##decide number of PCAs to use for analysis: npcs=20

#decide number of PCAs to use for analysis
merged_all <- RunPCA(merged_all, npcs = 50)
ElbowPlot_50PCAs <- ElbowPlot(merged_all, ndims = 50) + 
  scale_y_continuous(n.breaks = 20) + 
  geom_hline(yintercept = 2) +
  geom_vline(xintercept = 20)
ElbowPlot_50PCAs 

##Standard processing and clustering, 0.6 resolution

#Standard processing and clustering
merged_all <- FindNeighbors(merged_all, dims = 1:20, verbose = F)
merged_all <- FindClusters(merged_all, resolution = 0.6)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 27248
Number of edges: 954660

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9489
Number of communities: 27
Elapsed time: 3 seconds
merged_all <- RunUMAP(merged_all, dims = 1:20)
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

##Calculate number of cells in each cluster

print(cells_per_cluster)

print(cells_per_cluster_cond)

#UMAP visualization pre-doublet removal

Idents(merged_all) <- "seurat_clusters"
DimPlot(merged_all, reduction = "umap", label = T, repel = T) + ggtitle("Seurat Clusters")

#Remove doublets

##Remove doublets
#install and load scDblFinder package

#BiocManager::install("scDblFinder")
library(scDblFinder)
library(SingleCellExperiment)

##convert to single cell experiment and run scDblFinder

#convert to single cell experiment and run scDblFinder
sce <- as.SingleCellExperiment(merged_all)
sce <- scDblFinder::scDblFinder(sce, samples = 'sample')

  |                                                                                                                           
  |                                                                                                                     |   0%
  |                                                                                                                           
  |====================                                                                                                 |  17%
  |                                                                                                                           
  |=======================================                                                                              |  33%
  |                                                                                                                           
  |==========================================================                                                           |  50%
  |                                                                                                                           
  |==============================================================================                                       |  67%
  |                                                                                                                           
  |==================================================================================================                   |  83%
  |                                                                                                                           
  |=====================================================================================================================| 100%

##add doublet results back into metadata and visualize on UMAP

#add results back into seurat metadata
merged_all$scDblFinder.class <- colData(sce)$scDblFinder.class

#visualize
sing_vs_doub_before_subset <- DimPlot(merged_all,split.by = 'condition', reduction = "umap", group.by = "scDblFinder.class", pt.size = 0.5) + ggtitle("scDblFinder: Singlets vs Doublets")
sing_vs_doub_before_subset

##subset to only singlets

##rename merged_all2 and findneighbors and clusters again?

merged_all2 <- merged_all

merged_all2 <- FindNeighbors(merged_all2, dims = 1:20, verbose = F)
merged_all2 <- FindClusters(merged_all2, resolution = 0.6)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9492
Number of communities: 25
Elapsed time: 2 seconds
merged_all2 <- RunUMAP(merged_all2, dims = 1:20)
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
A <- DimPlot(merged_all, label = T, repel = T) + NoLegend() + ggtitle("Old Clusters After \nDoublet Removal")
B <- DimPlot(merged_all2, label = T, repel = T) + NoLegend() + ggtitle("Reclustering After \nDoublet Removal")
A+B

##calculate cells in each cluster after doublet removal and reclustering


cells_per_cluster2 <- merged_all2@meta.data %>%
  group_by(seurat_clusters) %>%
  summarise(cell_count = n()) %>%
  arrange(seurat_clusters)

cells_per_cluster_cond2 <- merged_all2@meta.data %>%
  group_by(seurat_clusters, condition) %>%
  summarise(cell_count = n()) %>%
  arrange(seurat_clusters, condition)

View(cells_per_cluster2)
View(cells_per_cluster_cond2)

print(cells_per_cluster2)
print(cells_per_cluster_cond2)

#Visualization ##By condition

#Group by condition
DimPlot(merged_all2, reduction = "umap", group.by = "condition", pt.size = 0.1, alpha = 0.3) 

##by sample, split by condition

##grouped by cluster, split by condition

##Bar graph number of cells per cluster from each individual sample

#visualize percent of each cluster from individual samples
meta_data <- merged_all2@meta.data

# Count cells per cluster per sample
cluster_counts <- meta_data %>%
  group_by(seurat_clusters, sample) %>%
  summarise(count = n(), .groups = 'drop')

# Calculate total cells per sample
total_per_cluster <- cluster_counts %>%
  group_by(seurat_clusters) %>%
  summarise(total = sum(count), .groups = 'drop')

# Merge and calculate percentage
cluster_percentages <- cluster_counts %>%
  left_join(total_per_cluster, by = "seurat_clusters") %>%
  mutate(percentage = (count / total) * 100)


# Plot
ggplot(cluster_percentages, aes(x = seurat_clusters, y = percentage, fill = sample)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(title = "Cluster Composition By Sample",
       x = "Cluster",
       y = "Percentage of Cluster",
       fill = "Sample") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

NA
NA

##percent of each cluster from each condition

#visualize percent of each cluster from each condition

# Count cells per cluster per condition
cluster_counts_cond <- meta_data %>%
  group_by(seurat_clusters, condition) %>%
  summarise(count = n(), .groups = 'drop')

# Calculate total cells per sample
total_cond_per_cluster <- cluster_counts_cond %>%
  group_by(seurat_clusters) %>%
  summarise(total = sum(count), .groups = 'drop')

# Merge and calculate percentage
cluster_cond_percentages <- cluster_counts_cond %>%
  left_join(total_cond_per_cluster, by = "seurat_clusters") %>%
  mutate(percentage = (count / total) * 100)


# Plot
ggplot(cluster_cond_percentages, aes(x = seurat_clusters, y = percentage, fill = condition)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(title = "Cluster Composition by Condition",
       x = "Cluster",
       y = "Percentage of Cluster",
       fill = "Sample") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

##visualize percent.mt per cluster

#add metadata column for cluster_condition
merged_all2$cluster_condition <- paste0(merged_all2$seurat_clusters,"_",merged_all2$condition)
Idents(merged_all2) <- merged_all2$cluster_condition

#check that metadata column is added
colnames(merged_all2@meta.data)
 [1] "orig.ident"        "nCount_RNA"        "nFeature_RNA"      "sample"            "condition"         "barcode"          
 [7] "percent.mt"        "log10GenesPerUMI"  "GenesPerUMI"       "RNA_snn_res.0.6"   "seurat_clusters"   "scDblFinder.class"
[13] "cluster_condition"
# Create summary data frame
percent_mt_summary <- merged_all2@meta.data %>%
  group_by(seurat_clusters) %>%
    summarise(
    mean_percent_mt = mean(percent.mt, na.rm = TRUE),
    median_percent_mt = median(percent.mt, na.rm = TRUE),
        n_cells = n()
  )

print(percent_mt_summary)

ggplot(percent_mt_summary, aes(x = factor(seurat_clusters), y = mean_percent_mt)) +
  geom_bar(stat = "identity", fill = "#2c7fb8") +
  labs(
    title = "Mean Mitochondrial Percentage by Cluster",
    x = "Cluster",
    y = "Mean % Mitochondrial Genes"
  ) +
  theme_minimal()

clusters_table <- table(merged_all2$seurat_clusters, merged_all2$sample)
clusters_table_cond <- table(merged_all2$seurat_clusters, merged_all2$condition)
clusters_table
    
      C1  C2  C3  U1  U2  U3
  0  209 414 535 325 612 820
  1  124 379 872 234 585 670
  2  139 332 596 231 775 780
  3  168 283 371 656 304 405
  4  123 174 507 516 256 454
  5  111 339 448 126 433 543
  6   67 232 335 148 332 385
  7   50 103 441 135 285 266
  8  134 127 123 640  50 144
  9   51  82  68 855  65  91
  10  99 280 141 106 194 194
  11  20  39  46 414  33 100
  12   4   4  30  65 197 335
  13  15  41 190  12 113 143
  14  29  88  83  48 133 114
  15  40  36 113  58  88 140
  16  11  40 102  51 121 116
  17   4   8  74  17  98 178
  18  20  31  51  43  77  90
  19  43  23  60  54  40  89
  20   5  45  59  23  66  56
  21   3  34  46  12  46  85
  22  28   8  64  60  52  12
  23   1   9  13   4  51  47
  24   7   7  36  18  28  20
clusters_table_cond
    
     Control  UTI
  0     1158 1757
  1     1375 1489
  2     1067 1786
  3      822 1365
  4      804 1226
  5      898 1102
  6      634  865
  7      594  686
  8      384  834
  9      201 1011
  10     520  494
  11     105  547
  12      38  597
  13     246  268
  14     200  295
  15     189  286
  16     153  288
  17      86  293
  18     102  210
  19     126  183
  20     109  145
  21      83  143
  22     100  124
  23      23  102
  24      50   66

#Create cluster tree

# Clustree visualization
install.packages("clustree")
Error in install.packages : Updating loaded packages
library(clustree)

merged_tree <- merged_all2

#Add multiple resolutions
merged_tree <- FindClusters(merged_tree, resolution = c(0.1, 0.2, 0.4, 0.6, 0.8))
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9871
Number of communities: 14
Elapsed time: 3 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9777
Number of communities: 17
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9621
Number of communities: 24
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9492
Number of communities: 25
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 26229
Number of edges: 923064

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9369
Number of communities: 28
Elapsed time: 3 seconds
install.packages("clustree")
Warning in install.packages :
  package ‘clustree’ is in use and will not be installed
cluster.tree <- clustree(
  merged_tree, "RNA_snn_res.") + ggtitle("Cluster tree")

ggsave("resolution cluster tree.svg", plot = cluster.tree, width = 12)

cluster.tree 

##silhouette plot

#Evaluate conserved marker genes, use to consolidate smaller clusters into larger ones

Idents(merged_all2) <- 'seurat_clusters'
merged_all2$consolidated_clusters <- merged_all2$seurat_clusters

library(presto)
library(SeuratWrappers)

# Initialize the list
conserved_markers <- list()

# Loop through the clusters in the specified order
for (i in 0:24) {
  aux <- SeuratWrappers::RunPresto(
    merged_all2,
    ident.1 = i,
    only.pos = TRUE,
    logfc.threshold = 0.5,
    min.pct = 0.4
  )
  
  if (!is.null(aux) && nrow(aux) > 0) {
    aux$gene <- rownames(aux)
    aux$cluster <- i
    conserved_markers[[paste0("cluster_", i)]] <- aux
  }
}

#filter
for(i in names(conserved_markers)){
  aux <- conserved_markers[[i]]
  aux$cluster <- i
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  conserved_markers[[i]] <- aux
}

##export conserved markers as excel file

#Consolidate clusters


#copy seurat_clusters to new metadate column
merged_all2$consolidated_clusters <- merged_all2$seurat_clusters

#set identity as new column, 'consolidated_clusters'
Idents(merged_all2) <- 'consolidated_clusters'

# Make new column a character vector instead of factor
merged_all2@meta.data$consolidated_clusters <- 
  as.character(merged_all2@meta.data$consolidated_clusters)

#define 'current clusters' for mapping later
current_clusters <- as.character(merged_all2$seurat_clusters)


#Consolidations (unnamed clusters go unchanged)
new_cluster_map <- c(
  "24"  = "12",
  "23"  = "1",
  "21" = "14"
)

##5,10,14,18,21 are all myeloid (CD68+)
   #14/21 = DC
##from cluster tree: 5 and 10 combine, 14, 18, and 21 combine
#24 -> 12 (gamma delta T?) -> 7 (also expressing Trgv in top genes)

#Apply mapping back to metadata
merged_all2$consolidated_clusters <- ifelse(
  current_clusters %in% names(new_cluster_map),
  new_cluster_map[current_clusters],
  current_clusters
)

# Convert back to factor (optional, but usually cleaner for Idents)
merged_all2@meta.data$consolidated_clusters <- 
  factor(merged_all2@meta.data$consolidated_clusters, levels = c(0:20,22))

# Set active identities correctly
Idents(merged_all2) <- 'consolidated_clusters'

#Naming clusters (preliminary, manual). In new object ‘merged_annot’

merged_annot <- merged_all2
merged_annot$annot <- merged_annot$consolidated_clusters


#set identity as new column, 'consolidated_clusters'
Idents(merged_annot) <- 'annot'

# Make new column a character vector instead of factor
merged_annot@meta.data$annot <- 
  as.character(merged_annot@meta.data$annot)

#define 'current clusters' for mapping later
current_clusters_annot <- as.character(merged_annot$annot)


#Consolidations (unnamed clusters go unchanged)
new_cluster_map_annot <- c(
  "0" = "Cytotoxic NK-T",
  "1" = "B cell",
  "2" = "Naive T_TCM",
  "3" = "Neutrophil", 
  "4" = "PT group 1",
  "5" = "Activated macrophage",
  "6" = "Immature T_group 2",
  "7" = "Th1",
  "8" = "PT group 2",
  "9" = "PT group 3",
  "10" = "Myeloid",
  "11" = "PT group 4",
  "12" = "T cell_gamma_delta",
  "13" = "TAL_DCT",
  "14" = "DC",
  "15" = "DCT_CNT",
  "16" = "TAL_DCT",
  "17" = "TAL",
  "18" = "Mono_macrophage",
  "19" = "Tissue-resident NK-T",
  "20" = "Endothelial",
  "22" = "Intercalated cell")



#Apply mapping back to metadata
merged_annot$annot <- ifelse(
  current_clusters_annot %in% names(new_cluster_map_annot),
  new_cluster_map_annot[current_clusters_annot],
  current_clusters_annot
)

# Convert back to factor (optional, but usually cleaner for Idents)
merged_annot@meta.data$annot <- 
  factor(merged_annot@meta.data$annot)

# Set active identities correctly
Idents(merged_annot) <- 'annot'

#Visualize umap with annotations

##split by condition

Idents(merged_annot) <- 'annot'

annotations <- list()
annotations <- unique(Idents(merged_annot))

# Initialize the list
conserved_markers_annot <- list()

# Loop through the clusters in the specified order
for (i in unique(annotations)) {
  aux <- SeuratWrappers::RunPresto(
    merged_annot,
    ident.1 = i,
    only.pos = TRUE,
    logfc.threshold = 0.5,
    min.pct = 0.4
  )
  
  if (!is.null(aux) && nrow(aux) > 0) {
    aux$gene <- rownames(aux)
    aux$cluster <- i
    conserved_markers_annot[[i]] <- aux
  }
}

#filter
for(i in names(conserved_markers_annot)){
  aux <- conserved_markers_annot[[i]]
  aux$cluster <- i
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  conserved_markers_annot[[i]] <- aux
}
merged_all2$consolidated_clusters <- merged_all2$seurat_clusters
Idents(merged_all2) <- 'consolidated_clusters'

##24 into 12, T cell population with Trg 
merged_all2@meta.data$consolidated_clusters <- 
  ifelse(
    merged_all2@meta.data$consolidated_clusters == "24",
    12,
    merged_all2@meta.data$consolidated_clusters
  )

#23 into 1, B cells - lots of immunoglobulins in 23 and jchain, 1 is cd19-high b cell group
merged_all2@meta.data$consolidated_clusters <- 
  ifelse(
    merged_all2@meta.data$consolidated_clusters == "23",
    1,
    merged_all2@meta.data$consolidated_clusters
  )

unique(merged_all2$consolidated_clusters)

++++ #Evaluate conserved and differentially expressed genes

Idents(merged_all2) <- 'seurat_clusters'

# Define the custom order
cluster_order_0.1 <- c(0, 1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9)

# Initialize the list
conserved_markers_res0.1 <- list()

# Loop through the clusters in the specified order
for (i in cluster_order_0.1) {
  aux <- SeuratWrappers::RunPresto(
    merged_all_cons,
    ident.1 = i,
    only.pos = TRUE,
    logfc.threshold = 0.5,
    min.pct = 0.4
  )
  
  if (!is.null(aux) && nrow(aux) > 0) {
    aux$gene <- rownames(aux)
    aux$cluster <- i
    conserved_markers_res0.1[[paste0("cluster_", i)]] <- aux
  }
}
#filter
for(i in names(conserved_markers_res0.1)){
  aux <- conserved_markers_res0.1[[i]]
  aux$cluster <- i
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  conserved_markers_res0.1[[i]] <- aux
}
# take top 15 genes from each cluster to do annotations
cluster_annot_df_0.1 <- conserved_markers_res0.1 %>%
  map(~ head(.x, 10)) %>%  # Take first 10 rows of each data frame
  bind_rows()              # Combine into one data frame
rio::export(conserved_markers_res0.1, "all pos conserved genes per cluster.xlsx")
rio::export(cluster_annot_df_0.1, "top 15 conserved genes per cluster.xlsx")

#Put in cluster annotations

l1_annotations_res0.1 <- c(
  "PT",           # cluster 0
  "T cell",                    # cluster 1
  "Myeloid",        # cluster 2
  "B Cell",                         # cluster 3
  "NK-T",      # cluster 4
  "T cell", # cluster 5
  "PMN",                    # cluster 6
  "Fibro_Stromal",     # cluster 7
  "Podocyte",                      # cluster 8
  "Macrophage",              # cluster 9
  "T cell",          # cluster 10
  "TAL",           # cluster 11
  "pDC",           # cluster 12
  "DCT",       # cluster 13
  "IC-B",      # cluster 14
  "ILC2/Myeloid"    # cluster 15
)

Idents(merged_all_cons) <- 'RNA_snn_res.0.1'

unique(Idents(merged_all_cons))
cluster.tree
Idents(merged_all_cons) <- 'seurat_clusters'
DefaultAssay(merged_all_cons)

merged_0.05 <- FindClusters(merged_0.05, resolution = 0.01)
  
cluster.tree.8dim <- clustree(merged_0.05, prefix = "RNA_snn_res.")
cluster.tree.8dim
# Make sure cluster IDs are numeric and 0-based
clusters <- as.numeric(as.character(merged_all_cons$RNA_snn_res.0.1))

# Map cluster IDs to manual annotations
# Create a named vector for easy lookup
names(l1_annotations_res0.1) <- as.character(0:15)

# Add annotation metadata by matching cluster IDs
merged_all_cons@meta.data$l1_annotations_res0.1 <- l1_annotations_res0.1[as.character(clusters)]
merged_all_cons@meta.data
Idents(merged_all_cons) <- 'annotation'
DimPlot(merged_all_cons, label = T, repel = T)
Idents(merged_all_cons) <- 'RNA_snn_res.0.1'
DimPlot(merged_all_cons, reduction = "tsne")+ ggtitle("unbiased clustering")
Idents(obj_annot) <- 'grouping'
DimPlot(obj_annot, reduction = "tsne", split.by = 'condition')
DimPlot(merged_all_cons, label = T, repel = T, split.by = 'condition') + NoLegend()
clusters_0.1_table <- table(merged_all_cons$RNA_snn_res.0.1, merged_all_cons$sample)
clusters_0.1_table_cond <- table(merged_all_cons$RNA_snn_res.0.1, merged_all_cons$condition)
clusters_0.1_table
clusters_0.1_table_cond
clusters_0.01_table <- table(merged_0.05$RNA_snn_res.0.01, merged_0.05$sample)
clusters_0.01_table_cond <- table(merged_0.05$RNA_snn_res.0.01, merged_0.05$condition)
clusters_0.01_table
clusters_0.01_table_cond

clusters_0.01_df <- as.data.frame(clusters_0.01_table)
clusters_0.01_df

clusters_0.01_df$annot <- c("lymphocyte", "myeloid", "PT", "B cell", "NK", "PMN", "TAL_Distal tubule", "PT_EMT_Fibro", "DCT")
merged_all_cons@meta.data$l1_annotations_res0.1 <- 
  ifelse(
    merged_all_cons@meta.data$l1_annotations_res0.1 == "Fibroblast/Stroma",
    "Fibro_Stromal",
    merged_all_cons@meta.data$l1_annotations_res0.1
  )
Idents(merged_all_cons) <- 'RNA_snn_res.0.8'

DE_0.8_10v19 <- SeuratWrappers::RunPresto(merged_all_cons, ident.1 = 10, ident.2 = 19)
gene <- rownames(DE_0.8_10v19)
DE_0.8_10v19$gene <- gene

DE_0.8_10v19 <- DE_0.8_10v19[DE_0.8_10v19$p_val_adj < 0.05,]
DE_0.8_10v19 <- order(DE_0.8_10v19$avg_log2FC, decreasing = T)  
#compare DE gene expression between UTI/controls in each cluster
#defined as deg_cons (list)
colnames(merged_all_cons@meta.data)

merged_all_cons@meta.data$l1_condition <- paste0(merged_all_cons@meta.data$l1_annotations_res0.1,"_",merged_all_cons$condition)

Idents(merged_all_cons) <- 'l1_condition'
unique(Idents(merged_all_cons))

DEg_res_0.1_UTI <-  list()

for(i in unique(merged_all_cons$l1_annotations_res0.1)){
  aux <- SeuratWrappers::RunPresto(merged_all_cons,ident.1 = paste0(i,"_UTI"), ident.2 = paste0(i,"_Control"))  
  aux$gene <- rownames(aux)
  DEg_res_0.1_UTI[[paste0(i,"_UTI")]] <- aux
}

#Filter for easier analysis
for(i in names(DEg_res_0.1_UTI)){
  aux <- DEg_res_0.1_UTI[[i]]
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  DEg_res_0.1_UTI[[i]] <- aux
}

names(DEg_res_0.1_UTI)[names(DEg_res_0.1_UTI) %in% "ILC2/Myeloid_UTI"] <- "ILC2_UTI"

#export as excel file
rio::export(DEg_res_0.1_UTI, "res 0.1_DE genes.xlsx")

#save RDS and create loupe


saveRDS(merged_all_cons, "merged_obj.RDS")
save.image("res 0.5_PCA 25_percentmt10.RData")
setwd("C:/Users/evrajadh/OneDrive - Indiana University/Research/Recurrent UTI GFR/ScRNA/Rec_UTI")
create_loupe_from_seurat(merged_all_cons, output_dir = "cloupes/", output_name = "manual annot_res_0.5")
#Split object by condition and analyze conditions separately
merged_split <- SplitObject(merged_all_cons, split.by = "condition")

#eval conserved markers by condition

merged_split$UTI

merged_UTI <- merged_split$UTI

#Add multiple resolutions
merged_UTI <- RunPCA(merged_UTI, npcs=30)
merged_UTI <- FindNeighbors(merged_UTI, dims = 1:20, verbose = F)
merged_UTI <- FindClusters(merged_UTI, resolution = c(0.1, 0.2, 0.4, 0.6, 0.8))

merged_UTI <- RunUMAP(merged_UTI, dims = 1:20)

DimPlot(merged_UTI)

cluster.tree_UTI <- clustree(
  merged_UTI, "RNA_snn_res.") + ggtitle("Cluster tree")

cluster.tree_UTI
#haven't removed doublets, only preliminary
Idents
Idents(merged_UTI) <- 'l1_annotations_res0.1'

DEg_UTI_LOW_res <- list()
for(i in unique(merged_0.05$RNA_snn_res.0.01)){
  aux <- SeuratWrappers::RunPresto(merged_0.05,ident.1 = paste0(i,"_UTI"), ident.2 = paste0(i,"_Control"))  
  aux$gene <- rownames(aux)
  DEg_UTI_LOW_res[[paste0(i,"_UTI")]] <- aux
}

#Filter for easier analysis
for(i in names(DEg_UTI_LOW_res)){
  aux <- DEg_UTI_LOW_res[[i]]
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  DEg_UTI_LOW_res[[i]] <- aux
}

rio::export(DEg_UTI_LOW_res, "LOW resolution DEgenes_UTI.xlsx")
Idents(merged_0.05) <- 'RNA_snn_res.0.01'
DimPlot(merged_0.05, reduction = "tsne")
DimPlot(merged_0.05, reduction = "pca", label = T, repel = T)
Idents(merged_0.05) <- 'l1_annotations_res0.1'
DimPlot(merged_0.05, reduction = "tsne", label = T)
DimPlot(merged_0.05, reduction = "pca", label = T) + NoLegend()
obj_annot <- merged_all_cons
obj_annot$grouping <- NA

obj_annot$grouping[obj_annot$RNA_snn_res.0.1 %in% c(1,5,10,15,4,3)] <- "Lymphocyte"
obj_annot$grouping[obj_annot$RNA_snn_res.0.1 %in% c(2,12,9,6)] <- "Myeloid"
obj_annot$grouping[obj_annot$RNA_snn_res.0.1 %in% c(0)] <- "PT"
obj_annot$grouping[obj_annot$RNA_snn_res.0.1 %in% c(7)] <- "PT_EMT"
obj_annot$grouping[obj_annot$RNA_snn_res.0.1 %in% c(14,11,8,13)] <- "TAL_distal tubule"
Idents(obj_annot) <- 'grouping'
unique(Idents(obj_annot))
conserved_genes_lowres_grouping <- list()
Idents(obj_annot) <- 'grouping'

# Loop through the clusters in the specified order
conserved_genes_lowres_grouping <- SeuratWrappers::RunPrestoAll(obj_annot,
    only.pos = TRUE,
    logfc.threshold = 0.5,
    min.pct = 0.4)
conserved_genes_lowres_grouping$gene <- rownames(conserved_genes_lowres_grouping)

rio::export(conserved_genes_lowres_grouping, "Cluster_GROUPING_conserved genes.xlsx")
    
obj_annot$group_cond <- paste0(obj_annot$grouping,'_',obj_annot$condition)
Idents(obj_annot) <- 'group_cond'

DEg_UTI_LOW_res_annot <- list()
for(i in unique(obj_annot$grouping)){
  aux <- SeuratWrappers::RunPresto(obj_annot,ident.1 = paste0(i,"_UTI"), ident.2 = paste0(i,"_Control"))  
  aux$gene <- rownames(aux)
  DEg_UTI_LOW_res_annot[[paste0(i,"_UTI")]] <- aux
}

#Filter for easier analysis
for(i in names(DEg_UTI_LOW_res_annot)){
  aux <- DEg_UTI_LOW_res_annot[[i]]
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  DEg_UTI_LOW_res_annot[[i]] <- aux
}

rio::export(DEg_UTI_LOW_res_annot, "DEgenes cluster_GROUPING_UTIvControl.xlsx")
rio::export(DEg_UTI_LOW_res, "LOW resolution DEgenes_UTI.xlsx")

Monocling

Idents(merged_all_cons) <- 'RNA_snn_res.0.1'
pt_cells <- subset(merged_all_cons, idents = c('0', '7'))
library(monocle3)

cds <- SeuratWrappers::as.cell_data_set(pt_cells)
cds <- cluster_cells(cds)
cds <- learn_graph(cds)
plot_cells(cds, color_cells_by = "cluster", label_cell_groups = T)
Idents(obj_annot) <- 'l1_annotations_res0.1'
unique(Idents(obj_annot))

obj_annot$l1_annotations_res0.1[obj_annot$l1_annotations_res0.1 %in% "Fibro_Stromal"] <- "PT_EMT"
obj_annot$l1_annotations_res0.1[obj_annot$l1_annotations_res0.1 %in% "ILC2"] <- "ILC"
obj_annot$l1_annotations_res0.1[obj_annot$l1_annotations_res0.1 %in% "Podocyte"] <- "TAL_DCT"
obj_annot$l1_annotations_res0.1[obj_annot$l1_annotations_res0.1 %in% "pDC"] <- "DC"
cds <- SeuratWrappers::as.cell_data_set(obj_annot)
cds <- cluster_cells(cds)
cds <- learn_graph(cds)
# Plot to choose root node visually
plot_cells(cds, color_cells_by = "cluster", label_cell_groups = T, label_roots = T) 

get_earliest_principal_node <- function(cds) {
  pr_graph_test <- principal_graph(cds)[[1]]
  names(which.min(igraph::degree(pr_graph_test)))
}

# Once you identify the root cell/cluster:
cds <- order_cells(cds, root_pr_nodes = get_earliest_principal_node(cds))
plot_cells(cds, color_cells_by = "pseudotime", label_groups_by_cluster = FALSE)
DimPlot(obj_annot)
BiocManager::install("slingshot")
library(slingshot)

Idents(obj_annot) <- 'l1_annotations_res0.1'
DimPlot(obj_annot, reduction = 'tsne') + DimPlot(obj_annot, reduction = 'pca')

sce <- as.SingleCellExperiment(obj_annot)
sce <- slingshot(sce, clusterLabels = obj_annot$l1_annotations_res0.1, reducedDim = 'UMAP')

#Pseudotime analysis with slingshot

sce <- as.SingleCellExperiment(obj_annot)
sce <- slingshot::slingshot(sce, clusterLabels = sce$l1_annotations_res0.1, reducedDim = 'UMAP')
#plot pseudotime
library(scater)

plot(reducedDim(sce, "UMAP"), col = sce$slingPseudotime_1 , pch = 16)
plot(reducedDim(sce, "TSNE"), col = sce$slingPseudotime_1 , pch = 16)

plot(reducedDim(sce, "UMAP"), col = sce$slingPseudotime_1 , pch = 16)

clusters <- sce$l1_annotations_res0.1
centers <- t(sapply(unique(clusters),function(cl){
  colMeans(reducedDim(sce, "UMAP")[clusters == cl,])
}))
text(centers, labels = unique(clusters),col = "black", cex = 0.8)
sce <- as.SingleCellExperiment(pt_cells)
sce <- slingshot::slingshot(sce, clusterLabels = sce$l1_annotations_res0.1, reducedDim = 'UMAP')
plot(reducedDim(sce, "UMAP"), col = sce$slingPseudotime_1 , pch = 10)

clusters <- sce$l1_annotations_res0.1
centers <- t(sapply(unique(clusters),function(cl){
  colMeans(reducedDim(sce, "UMAP")[clusters == cl,])
}))
text(centers, labels = unique(clusters),col = "black", cex = 0.8)
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
umap_df <- as.data.frame(reducedDim(sce, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")  # Rename to readable names
umap_df$cluster <- sce$l1_annotations_res0.1
umap_df$pseudotime <- sce$slingPseudotime_1


# Calculate cluster centroids for labeling
label_df <- umap_df %>%
  group_by(cluster) %>%
  summarize(UMAP_1 = mean(UMAP_1), UMAP_2 = mean(UMAP_2))


# Plot with ggplot2
ggplot(umap_df, aes(x = UMAP_1, y = UMAP_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_df, aes(x = UMAP_1, y = UMAP_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "UMAP 1", y = "UMAP 2", title = "Slingshot Pseudotime [PT Cells] with Cluster Labels")
sce <- as.SingleCellExperiment(obj_annot)
sce <- slingshot::slingshot(sce, clusterLabels = sce$RNA_snn_res.0.4, reducedDim = 'UMAP')
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
umap_df <- as.data.frame(reducedDim(sce, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")  # Rename to readable names
umap_df$cluster <- sce$l1_annotations_res0.1
umap_df$pseudotime <- sce$slingPseudotime_1


# Calculate cluster centroids for labeling
label_df <- umap_df %>%
  group_by(cluster) %>%
  summarize(UMAP_1 = mean(UMAP_1), UMAP_2 = mean(UMAP_2))


# Plot with ggplot2
ggplot(umap_df, aes(x = UMAP_1, y = UMAP_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_df, aes(x = UMAP_1, y = UMAP_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "UMAP 1", y = "UMAP 2", title = "Slingshot Pseudotime [PT Cells] with Cluster Labels")
Idents(obj_annot) <- 'grouping'
unique(Idents(obj_annot))

#already subsetted PT and PT_EMT to pt_cells
myeloid_cells <- subset(obj_annot, idents = "Myeloid")
lympho_cells <- subset(obj_annot, idents = "Lymphocyte")
TAL_DCT_cells <- subset(obj_annot, idents = "TAL_distal tubule")

#myeloid slingshot TSNE

sce_myeloid <- as.SingleCellExperiment(myeloid_cells)
sce_myeloid <- slingshot::slingshot(sce_myeloid, clusterLabels = sce_myeloid$RNA_snn_res.0.4, reducedDim = 'TSNE')
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
umap_myeloid_df <- as.data.frame(reducedDim(sce_myeloid, "TSNE"))
colnames(umap_myeloid_df) <- c("TSNE_1", "TSNE_2")  # Rename to readable names
umap_myeloid_df$cluster <- sce_myeloid$l1_annotations_res0.1
umap_myeloid_df$pseudotime <- sce_myeloid$slingPseudotime_1


# Calculate cluster centroids for labeling
label_myeloid_df <- umap_myeloid_df %>%
  group_by(cluster) %>%
  summarize(TSNE_1 = mean(TSNE_1), TSNE_2 = mean(TSNE_2))


# Plot with ggplot2
ggplot(umap_myeloid_df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_myeloid_df, aes(x = TSNE_1, y = TSNE_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "TSNE1", y = "TSNE 2", title = "Slingshot Pseudotime [Myeloid Cells] with Cluster Labels")

#myeloid slingshot UMAP

sce_myeloid <- as.SingleCellExperiment(myeloid_cells)
sce_myeloid <- slingshot::slingshot(sce_myeloid, clusterLabels = sce_myeloid$RNA_snn_res.0.4, reducedDim = 'UMAP')
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
umap_myeloid_df <- as.data.frame(reducedDim(sce_myeloid, "UMAP"))
colnames(umap_myeloid_df) <- c("UMAP_1", "UMAP_2")  # Rename to readable names
umap_myeloid_df$cluster <- sce_myeloid$l1_annotations_res0.1
umap_myeloid_df$pseudotime <- sce_myeloid$slingPseudotime_1


# Calculate cluster centroids for labeling
label_myeloid_df <- umap_myeloid_df %>%
  group_by(cluster) %>%
  summarize(UMAP_1 = mean(UMAP_1), UMAP_2 = mean(UMAP_2))


# Plot with ggplot2
ggplot(umap_myeloid_df, aes(x = UMAP_1, y = UMAP_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_myeloid_df, aes(x = UMAP_1, y = UMAP_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "UMAP 1", y = "UMAP 2", title = "Slingshot Pseudotime [PT Cells] with Cluster Labels")

#lympho slingshot

sce_lymph <- as.SingleCellExperiment(lympho_cells)
sce_lymph <- slingshot::slingshot(sce_lymph, clusterLabels = sce_lymph$RNA_snn_res.0.4, reducedDim = 'TSNE')
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
umap_lymph_df <- as.data.frame(reducedDim(sce_lymph, "TSNE"))
colnames(umap_lymph_df) <- c("TSNE_1", "TSNE_2")  # Rename to readable names
umap_lymph_df$cluster <- sce_lymph$l1_annotations_res0.1
umap_lymph_df$pseudotime <- sce_lymph$slingPseudotime_1


# Calculate cluster centroids for labeling
label_lymph_df <- umap_lymph_df %>%
  group_by(cluster) %>%
  summarize(TSNE_1 = mean(TSNE_1), TSNE_2 = mean(TSNE_2))


# Plot with ggplot2
ggplot(umap_lymph_df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_lymph_df, aes(x = TSNE_1, y = TSNE_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "TSNE1", y = "TSNE 2", title = "Slingshot Pseudotime [PT Cells] with Cluster Labels")

#TAL_DCT cell slingshot

sce_tub <- as.SingleCellExperiment(TAL_DCT_cells)
sce_tub <- slingshot::slingshot(sce_tub, clusterLabels = sce_tub$RNA_snn_res.0.4, reducedDim = 'TSNE')

# Extract data from SingleCellExperiment
tub_df <- as.data.frame(reducedDim(sce_tub, "TSNE"))
colnames(tub_df) <- c("TSNE_1", "TSNE_2")  # Rename to readable names
tub_df$cluster <- sce_tub$l1_annotations_res0.1
tub_df$pseudotime <- sce_tub$slingPseudotime_1


# Calculate cluster centroids for labeling
label_tub_df <- tub_df %>%
  group_by(cluster) %>%
  summarize(TSNE_1 = mean(TSNE_1), TSNE_2 = mean(TSNE_2))


# Plot with ggplot2
ggplot(tub_df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_tub_df, aes(x = TSNE_1, y = TSNE_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "TSNE1", y = "TSNE 2", title = "Slingshot Pseudotime [PT Cells] with Cluster Labels")
Idents(obj_annot) <- 'RNA_snn_res.0.1'
DimPlot(obj_annot, reduction = "tsne", label = T,repel=T,  label.size = 5) + ggtitle("0.1 resolution clustering")
obj_annot <- readRDS("C:/Users/evrajadh/OneDrive - Indiana University/Research/Recurrent UTI GFR/ScRNA/Rec_UTI/res 0.5_PCA 25_7-29/annotation object.RDS")

Idents(obj_annot) <- 'l1_annotations_res0.1'
DimPlot(obj_annot, reduction = "tsne", label = T,repel=T,  label.size = 5)
Idents(obj_annot) <- 'grouping'
DimPlot(obj_annot, reduction = "tsne", label = T, label.size = 4, pt.size = 0.1) + NoLegend() + ggtitle('Clusters')
Idents(obj_annot) <- 'grouping'
DoHeatmap(obj_annot, features = c("Nrep", "Map3k7cl", "Angptl7", "Hdc", "Slc6a18", "Tmigd1", "Slc22a12", "Slc22a6"), cells = "PT")
VlnPlot(obj_annot, features = c("Nrep", "Map3k7cl", "Angptl7", "Hdc", "Slc6a18", "Tmigd1", "Slc22a12", "Slc22a6"), raster = F, split.by = 'condition')
FeaturePlot(obj_annot, features = "Nrep", reduction = "tsne", split.by = 'condition', pt.size = 0.8)
FeaturePlot(obj_annot, features = "Map3k7cl", reduction = "tsne", split.by = 'condition', pt.size = 0.8)
VlnPlot(obj_annot, features = "Nrep", raster = F, split.by = 'condition')
VlnPlot(obj_annot, features = "Map3k7cl", raster = F, split.by = 'condition')
VlnPlot(obj_annot, features = "B2m", raster = F, split.by = 'condition')
feat_scCKDatlas <- c("Cd79a", "Cd3d", "Prf1", "Cpa3", "Folr2", "Sema3g", "Sost", "Prox1", "Vcam1", "Plvap", "Rergl", "Cox4l2", "Dcn", "Postn", "Slc22a6", "Prune2", "Nos1", "Umod", "Calb1", "Slc4a1", "Upk3b", "Wt1", "Gfr3a")

DoHeatmap(obj_annot, features = c("Cryab", "Sema5a", "Pdgfrb", "Dcdc2a", "Cp", "Nkg7", "Xcr1", "S100a9", "Lrp2", "Slc12a1", "Slc12a3"))
FeaturePlot(obj_annot, features = c("Cryab", "Sema5a", "Pdgfrb", "Dcdc2a", "Cp", "Nkg7", "Xcr1", "S100a9", "Lrp2", "Slc12a1", "Slc12a3"), reduction = "tsne", split.by = 'condition', pt.size = 0.8)
VlnPlot(obj_annot, features = c("Cryab", "Sema5a", "Pdgfrb", "Dcdc2a", "Cp", "Nkg7", "Xcr1", "S100a9", "Lrp2", "Slc12a1", "Slc12a3"), raster = F, split.by = 'condition')

feat_PTinjury <- c("Slc5a12", "Slc34a1", "Slc22a30", "Col27a1", "Plin2", "Ypel2", "Bcat1", "Slc7a12", "Hsp90aa1", "Top2a", "Kcnip4", "Vcam1", "Havcr1")
#Healthy: Slc5a12, 45a1, 22a30, 7a13
#type 1 injured S1/2: Col27a1, Plin2
#Type 1 injured S3: Plin2, Havcr1
#type2 injured S1/2: Ypel2
#Type2 injured S3: ypel2, Bcat1, Slc7a12
#acute injury: Hsp90aa1
#Repairing: Top2a
#Failed repair: Ypel2, Kcnip4,Vcam1, Havcr1

FeaturePlot(obj_annot, features = feat_PTinjury, reduction = "tsne", split.by = 'condition', pt.size = 0.8)
VlnPlot(obj_annot, features = feat_PTinjury, raster = F, split.by = 'condition')
#see which PT clusters are where on tsne (clusters 5,9, and 11 on res0.5)
Idents(obj_annot) <- 'RNA_snn_res.0.5'
DimPlot(obj_annot, reduction = "tsne", label = T)
sce <- as.SingleCellExperiment(pt_cells)
sce <- slingshot(sce, clusterLabels = sce$l1_con, reducedDim = "TSNE")
curves <- slingCurves(sce)

  
  df <- as.data.frame(reducedDim(sce, "TSNE"))
colnames(df) <- c("TSNE_1", "TSNE_2")
df$pseudotime <- sce$slingPseudotime_1
df$cluster <- sce$l1_annotations_res0.1 

  p <- ggplot(df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  theme_minimal()
  
  for (i in seq_along(curves)) {
  curve_df <- as.data.frame(curves[[i]]$s)
  colnames(curve_df) <- c("TSNE_1", "TSNE_2")
  
  # Add arrows along the curve
  p <- p + geom_path(data = curve_df, aes(x = TSNE_1, y = TSNE_2),
                     arrow = arrow(type = "open", length = unit(0.15, "inches")),
                     color = "black", size = 0.8)
  }
  
  p

#PT cells also with condition separation

sce <- as.SingleCellExperiment(pt_cells)
sce <- slingshot(sce, clusterLabels = sce$l1_condition, reducedDim = "TSNE")
curves <- slingCurves(sce)

  
  df <- as.data.frame(reducedDim(sce, "TSNE"))
colnames(df) <- c("TSNE_1", "TSNE_2")
df$pseudotime <- sce$slingPseudotime_1
df$cluster <- sce$l1_condition

  p <- ggplot(df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  theme_minimal()
  
  for (i in seq_along(curves)) {
  curve_df <- as.data.frame(curves[[i]]$s)
  colnames(curve_df) <- c("TSNE_1", "TSNE_2")
  
  # Add arrows along the curve
  p <- p + geom_path(data = curve_df, aes(x = TSNE_1, y = TSNE_2),
                     arrow = arrow(type = "open", length = unit(0.15, "inches")),
                     color = "black", size = 0.8)
  }
  
  p
saveRDS(obj_annot, "annotation object.RDS")
unique(merged_all_cons@meta.data$l1_annotations_res0.1)
Idents(merged_all_cons) <- 'l1_annotations_res0.1'
DimPlot(merged_all_cons, reduction = "umap")
markers_test <- FindMarkers(merged_all_cons, grouping.var = "l1_annotations_res0.1", ident.1 = "Podocyte")
markers_test
DimPlot(merged_all_cons, label = T, repel = T)

+++++++++++

myeloid_df <- as.data.frame(reducedDim(sce_myeloid, "TSNE"))
colnames(myeloid_df) <- c("TSNE_1", "TSNE_2")

myeloid_df$lineage <- is.na(sce_myeloid$slingPseudotime_1)
ggplot(myeloid_df, aes(x = TSNE_1, y = TSNE_2, color = lineage)) +
  geom_point(size = 0.5) +
  scale_color_manual(values = c("FALSE" = "blue", "TRUE" = "gray")) +
  theme_minimal() +
  labs(title = "Cells Assigned to Slingshot Lineage 1",
       color = "Assigned?")
sce_all <- as.SingleCellExperiment(obj_annot)
sce_all <- slingshot::slingshot(sce_all, clusterLabels = sce_all$RNA_snn_res.0.4, reducedDim = 'TSNE')
#For just PT cells and PT_EMT

# Extract data from SingleCellExperiment
tsne_all_df <- as.data.frame(reducedDim(sce_all, "TSNE"))
colnames(tsne_all_df) <- c("TSNE_1", "TSNE_2")  # Rename to readable names
tsne_all_df$cluster <- sce_all$l1_annotations_res0.1
tsne_all_df$pseudotime <- sce_all$slingPseudotime_1


# Calculate cluster centroids for labeling
label_all_tsne_df <- tsne_all_df %>%
  group_by(cluster) %>%
  summarize(TSNE_1 = mean(TSNE_1), TSNE_2 = mean(TSNE_2))


# Plot with ggplot2
ggplot(tsne_all_df, aes(x = TSNE_1, y = TSNE_2, color = pseudotime)) +
  geom_point(size = 0.5) +
  scale_color_viridis_c() +
  geom_text(data = label_all_tsne_df, aes(x = TSNE_1, y = TSNE_2, label = cluster), 
            color = "black", size = 4) +
  theme_minimal() +
  labs(x = "TSNE1", y = "TSNE 2", title = "Slingshot Pseudotime [All Cells] with Cluster Labels")
tsne_all_df <- as.data.frame(reducedDim(sce_all, "TSNE"))
colnames(tsne_all_df) <- c("TSNE_1", "TSNE_2")

tsne_all_df$lineage <- is.na(sce_all$slingPseudotime_1)
ggplot(tsne_all_df, aes(x = TSNE_1, y = TSNE_2, color = lineage)) +
  geom_point(size = 0.5) +
  scale_color_manual(values = c("FALSE" = "blue", "TRUE" = "gray")) +
  theme_minimal() +
  labs(title = "Cells Assigned to Slingshot Lineage 1",
       color = "Assigned?")
sce_myeloid$lineage <- is.na(sce_myeloid$slingPseudotime_1)
ggplot(..., color = lineage)  # TRUE = unassigned = gray

df <- as.data.frame(reducedDim(sce_myeloid, "TSNE"))
colnames(df) <- c("TSNE_1", "TSNE_2")

df$lineage <- is.na(sce_myeloid$slingPseudotime_1)
plot(reducedDim(sce), col = sce$cluster, type = 'lineages')

sce$li
plot_cells(cds, color_cells_by = "cluster")
plot_cells(cds, genes = c("Cdh2"), show_trajectory_graph = TRUE)
+++++++++++

ggsave("resolution cluster tree.svg", plot = cluster.tree, width = 12)

cluster.tree 


UTI_0.5_markers_clust_annot <- SeuratWrappers::RunPrestoAll(merged_0.5_splitlist$UTI)

UTI_0.5_markers_list <- split(UTI_0.5_markers_clust_annot, UTI_0.5_markers_clust_annot[['cluster']])

for(i in names(UTI_0.5_markers_list)){
  aux <- UTI_0.5_markers_list[[i]]
  aux <- aux[aux$p_val_adj < 0.05,]
  aux <- aux[order(aux$avg_log2FC, decreasing=T),]
  UTI_all_markers_list[[i]] <- aux
}

#DE genes by condition at res 0.01

merged_0.05$l0_condition <- paste0(merged_0.05$RNA_snn_res.0.01, '_', merged_0.05$condition)
Idents(merged_0.05) <- 'l0_condition'

DE_0.05_resol_condition <- SeuratWrappers::RunPresto(merged_0.05)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tDQp0aXRsZTogIkF1Z3VzdCAyMDI1IGFuYWx5c2lzIGZvciBUYWthc2hpIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQojV29ya3NwYWNlIHNldHVwDQpgYGB7cn0NCiNsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcw0KbGlicmFyeShjZWxscmFuZ2VyKQ0KbGlicmFyeShoZGY1cikNCmxpYnJhcnkoU2V1cmF0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShnbG1HYW1Qb2kpDQpsaWJyYXJ5KHNjdHJhbnNmb3JtKQ0KbGlicmFyeShsb3VwZVIpDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojdXBkYXRlLnBhY2thZ2VzKGxpc3QgPSBjKGNlbGxyYW5nZXIsIGhkZjVyLCBTZXVyYXQsIGRwbHlyLCBwYXRjaHdvcmssIGdsbUdhbVBvaSwgc2N0cmFuc2Zvcm0sIGxvdXBlUiwgdGlkeXZlcnNlKSkNCg0Kc2V0d2QoIkM6L1VzZXJzL2V2cmFqYWRoL09uZURyaXZlIC0gSW5kaWFuYSBVbml2ZXJzaXR5L1Jlc2VhcmNoL1JlY3VycmVudCBVVEkgR0ZSL1NjUk5BL1JlY19VVEkiKQ0Kcm0obGlzdCA9IGxzKCkpDQpgYGANCg0KI0ltcG9ydCBkYXRhDQojI0xvYWQgZmlsdGVyZWQgb2JqZWN0cw0KYGBge3J9DQpVMSA8LSBSZWFkMTBYX2g1KCJGaWx0ZXJlZCBoNSBvYmplY3RzL1VUSS0xX2ZpbHRlcmVkX2ZlYXR1cmVfYmNfbWF0cml4Lmg1IikNClUyIDwtIFJlYWQxMFhfaDUoIkZpbHRlcmVkIGg1IG9iamVjdHMvVVRJLTJfZmlsdGVyZWRfZmVhdHVyZV9iY19tYXRyaXguaDUiKQ0KVTMgPC0gUmVhZDEwWF9oNSgiRmlsdGVyZWQgaDUgb2JqZWN0cy9VVEktM19maWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeC5oNSIpDQpDMSA8LSBSZWFkMTBYX2g1KCJGaWx0ZXJlZCBoNSBvYmplY3RzL0NvbnRyb2wtMV9maWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeC5oNSIpDQpDMiA8LSBSZWFkMTBYX2g1KCJGaWx0ZXJlZCBoNSBvYmplY3RzL0NvbnRyb2wtMl9maWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeC5oNSIpDQpDMyA8LSBSZWFkMTBYX2g1KCJGaWx0ZXJlZCBoNSBvYmplY3RzL0NvbnRyb2wtM19maWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeC5oNSIpDQpgYGANCg0KIyNDcmVhdGUgc2V1cmF0IG9iamVjdHMgDQpgYGB7cn0NCiNUdXJuIGludG8gc2V1cmF0IG9iamVjdHMNClUxIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBVMSkNClUyIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBVMikNClUzIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBVMykNCkMxIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBDMSkNCkMyIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBDMikNCkMzIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBDMykNCmBgYA0KDQojI01lcmdlLCBsYWJlbGluZyBjZWxsLmlkIGluIG1ldGFkYXRhDQpgYGB7cn0NCiNtZXJnZSBpbnRvIHNpbmdsZSBzZXVyYXQgb2JqZWN0LCBsYXllcnMgc3RpbGwgc2VwYXJhdGVkDQptZXJnZWRfYWxsIDwtIG1lcmdlKFUxLCB5ID0gYyhVMiwgVTMsIEMxLCBDMiwgQzMpLA0KICAgICAgICAgICAgICAgIGFkZC5jZWxsLmlkcyA9IGMoIlUxX1VUSSIsICJVMl9VVEkiLCAiVTNfVVRJIiwgIkMxX0NvbnRyb2wiLCAiQzJfQ29udHJvbCIsICJDM19Db250cm9sIiksDQogICAgICAgICAgICAgICAgcHJvamVjdCA9ICJSZWNVVEkiKQ0KYGBgDQoNCmBgYHtyfQ0KI0FkanVzdCBtZXRhZGF0YQ0KbWVyZ2VkX2FsbCRzYW1wbGUgPC0gcm93bmFtZXMobWVyZ2VkX2FsbEBtZXRhLmRhdGEpDQptZXJnZWRfYWxsQG1ldGEuZGF0YSA8LSBzZXBhcmF0ZShtZXJnZWRfYWxsQG1ldGEuZGF0YSwgY29sID0gJ3NhbXBsZScsIGludG8gPSBjKCdzYW1wbGUnLCAnY29uZGl0aW9uJywgJ2JhcmNvZGUnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gJ18nKQ0KDQojbGFiZWwgcGVyY2VudCBtaXRvY2hvbmRyaWFsIEROQQ0KbWVyZ2VkX2FsbCRwZXJjZW50Lm10IDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KG1lcmdlZF9hbGwsIHBhdHRlcm4gPSAiXm10LSIpDQoNCiNhZGQgbnVtYmVyIG9mIGdlbmVzIHBlciBVTUkgZm9yIGVhY2ggY2VsbCB0byBtZXRhZGF0YQ0KI2xvZzEwZ2VuZXNQZXJVTUkgZXhwZWN0ZWQgaXMgfjAuOC0wLjkgZm9yIHNjUk5BIGRhdGEsID4xLjAgaXMgc3VzcGVjdGVkIGRvdWJsZXQNCm1lcmdlZF9hbGwkbG9nMTBHZW5lc1BlclVNSSA8LSBsb2cxMChtZXJnZWRfYWxsJG5GZWF0dXJlX1JOQSkgLyBsb2cxMChtZXJnZWRfYWxsJG5Db3VudF9STkEpDQptZXJnZWRfYWxsJEdlbmVzUGVyVU1JIDwtIChtZXJnZWRfYWxsJG5GZWF0dXJlX1JOQSAvIG1lcmdlZF9hbGwkbkNvdW50X1JOQSkNCmBgYA0KDQojUUMNCiMjbG9nMTBnZW5lc3BlclVNSQ0KYGBge3J9DQojVmlzdWFsaXplIGxvZzEwZ2VuZXNQZXJVTUkgUFJJT1IgdG8gc3Vic2V0dGluZw0KVmxuUGxvdChtZXJnZWRfYWxsLCBmZWF0dXJlcyA9ICJsb2cxMEdlbmVzUGVyVU1JIikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjk1LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjgsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpDQpgYGANCg0KYGBge3J9DQojcGxvdCBsb2cxMFVNSSB2cyBuQ291bnRfUk5BDQptZXJnZWRfYWxsQG1ldGEuZGF0YSAlPiUgDQogIAlnZ3Bsb3QoYWVzKGNvbG9yPWNvbmRpdGlvbiwgeD1uQ291bnRfUk5BLCBmaWxsPSBzYW1wbGUpKSArIA0KICAJZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKSArIA0KICAJc2NhbGVfeF9sb2cxMCgpICsgDQogIAl0aGVtZV9jbGFzc2ljKCkgKw0KICAJeWxhYigibG9nMTAgY2VsbCBkZW5zaXR5IikgKw0KICAJZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNTAwKQ0KYGBgDQojI3FjIGZlYXR1cmUgcGxvdHMgKGJlZm9yZSBzdWJzZXR0aW5nKQ0KYGBge3IsIGZpZy53aWR0aD0xMH0NCiNwbG90IG5Db3VudCB2cyBuRmVhdHVyZQ0KcWNmZWF0MSA8LSBGZWF0dXJlU2NhdHRlcihtZXJnZWRfYWxsLCBmZWF0dXJlMSA9ICduQ291bnRfUk5BJywgZmVhdHVyZTIgPSAnbkZlYXR1cmVfUk5BJywgZ3JvdXAuYnkgPSAnc2FtcGxlJywgcHQuc2l6ZSA9IDAuMDUpIA0KcWNmZWF0MiA8LSBGZWF0dXJlU2NhdHRlcihtZXJnZWRfYWxsLCBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgZmVhdHVyZTIgPSAicGVyY2VudC5tdCIsIGdyb3VwLmJ5ID0gJ3NhbXBsZScsIHB0LnNpemUgPSAwLjA1KQ0KcWNmZWF0MyA8LSBGZWF0dXJlU2NhdHRlcihtZXJnZWRfYWxsLCBmZWF0dXJlMSA9ICJuRmVhdHVyZV9STkEiLCBmZWF0dXJlMiA9ICJwZXJjZW50Lm10IiwgZ3JvdXAuYnkgPSAnc2FtcGxlJywgcHQuc2l6ZSA9IDAuMDUpDQoNCnFjZmVhdDEgKyBxY2ZlYXQyICsgcWNmZWF0Mw0KYGBgDQojI3FjIHZsbiBwbG90cyAocHJlLXN1YnNldHRpbmcpDQpgYGB7ciwgZmlnLndpZHRoPTEyfQ0KcWNfdmxuIDwtIFZsblBsb3QobWVyZ2VkX2FsbCwgZmVhdHVyZXMgPSBjKCduQ291bnRfUk5BJywgJ25GZWF0dXJlX1JOQScsICdwZXJjZW50Lm10JyksIGFscGhhID0gMC4xLCBncm91cC5ieSA9ICdzYW1wbGUnKQ0KcWNfdmxuW1syXV0gPC0gcWNfdmxuW1syXV0gKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MDApICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTAwMCkNCnFjX3ZsbltbM11dIDwtIHFjX3ZsbltbM11dICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTApIA0KcWNfdmxuDQpgYGANCiMjU3Vic2V0IGRhdGEgLSBwZXJjZW50Lm10PDEwLCBuRmVhdHVyZXMgNTAwLTUwMDAsIGxvZzEwZ2VuZXNwZXJVTUk+MC44DQpgYGB7cn0NCm1lcmdlZF9hbGwgPC0gc3Vic2V0KG1lcmdlZF9hbGwsIHN1YnNldCA9IHBlcmNlbnQubXQ8MTAgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuRmVhdHVyZV9STkE+NTAwICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbkZlYXR1cmVfUk5BPDUwMDAgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cxMEdlbmVzUGVyVU1JID49MC44KQ0KDQpgYGANCg0KIyNyZXBlYXQgUUMgdmxuIHBsb3RzDQpgYGB7cn0NCnFjX3ZsbiA8LSBWbG5QbG90KG1lcmdlZF9hbGwsIGZlYXR1cmVzID0gYygnbkNvdW50X1JOQScsICduRmVhdHVyZV9STkEnLCAncGVyY2VudC5tdCcpLCBhbHBoYSA9IDAuMSwgZ3JvdXAuYnkgPSAnc2FtcGxlJykNCnFjX3ZsbltbMl1dIDwtIHFjX3ZsbltbMl1dICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTAwKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwMDApDQpxY192bG5bWzNdXSA8LSBxY192bG5bWzNdXSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwKSANCnFjX3Zsbg0KYGBgDQpgYGB7cn0NClZsblBsb3QobWVyZ2VkX2FsbCwgZmVhdHVyZXMgPSAibG9nMTBHZW5lc1BlclVNSSIpIA0KYGBgDQojI2NlbGwgZGVuc2l0eSBieSBuRmVhdHVyZV9STkEgKHBvc3Qtc3Vic2V0dGluZykNCmBgYHtyfQ0KI3Bsb3QgbG9nMTBVTUkgdnMgbkZlYXR1cmVfUk5BDQptZXJnZWRfYWxsQG1ldGEuZGF0YSAlPiUgDQogIAlnZ3Bsb3QoYWVzKGNvbG9yPWNvbmRpdGlvbiwgeD1uRmVhdHVyZV9STkEsIGZpbGw9IHNhbXBsZSkpICsgDQogIAlnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsgDQogIAlzY2FsZV94X2xvZzEwKCkgKyANCiAgCXRoZW1lX2NsYXNzaWMoKSArDQogIAl5bGFiKCJsb2cxMCBjZWxsIGRlbnNpdHkiKSArDQogIAlnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA1MDApDQpgYGANCiMjY2VsbCBkZW5zaXR5IGJ5IHBlcmNlbnQubXQNCmBgYHtyfQ0KI3Bsb3QgbG9nMTBVTUkgdnMgcGVyY2VudC5tdA0KbWVyZ2VkX2FsbEBtZXRhLmRhdGEgJT4lIA0KICAJZ2dwbG90KGFlcyhjb2xvcj1jb25kaXRpb24sIHg9cGVyY2VudC5tdCwgZmlsbD0gc2FtcGxlKSkgKyANCiAgCWdlb21fZGVuc2l0eShhbHBoYSA9IDAuMikgKyANCiAgCXRoZW1lX2NsYXNzaWMoKSArDQogIAl5bGFiKCJsb2cxMCBjZWxsIGRlbnNpdHkiKSANCmBgYA0KIyNGaWx0ZXIgb3V0IGxvdyBxdWFsaXR5IGNlbGxzIChmZWF0dXJlcyBleHByZXNzZWQgaW4gPDEwIGNlbGxzKQ0KYGBge3J9DQojc3Vic2V0IG91dCBmZWF0dXJlcyBleHByZXNzZWQgaW4gPDEwIGNlbGxzIChTdXpzdGFrIHVzZWQgMTApDQpjb3VudHMgPC0gTGF5ZXJEYXRhKG1lcmdlZF9hbGwsIGFzc2F5ID0gIlJOQSIsIGxheWVyID0gImNvdW50cyIpDQprZWVwX2dlbmVzIDwtIHJvd1N1bXMoY291bnRzPjApID49MTANCm1lcmdlZF9hbGwgPC0gc3Vic2V0KG1lcmdlZF9hbGwsIGZlYXR1cmVzID0gbmFtZXMoa2VlcF9nZW5lc1trZWVwX2dlbmVzXSkpDQoNCm1lcmdlZF9hbGwgI2ZlYXR1cmVzIDMzNjk2IC0+IDE3NTM1IGdlbmVzIHdpdGggc3VmZmljaWVudCBleHByZXNzaW9uIGRhdGENCmBgYA0KDQojUHJvY2Vzc2luZw0KIyNKb2luIGxheWVycyBhbmQgcHJlcHJvY2Vzc2luZyB3b3JrZmxvdw0KYGBge3J9DQojSm9pbiBsYXllcnMNCiNQZXJmb3JtIHN0YW5kYXJkIFBSRXByb2Nlc3Npbmcgd29ya2Zsb3cgc3RlcHMgdG8gZmlndXJlIG91dCBpZiB3ZSBoYXZlIHNpZ25pZmljYW50IGJhdGNoIGVmZmVjdHMNCg0KbWVyZ2VkX2FsbCA8LSBKb2luTGF5ZXJzKG1lcmdlZF9hbGwpDQptZXJnZWRfYWxsIDwtIE5vcm1hbGl6ZURhdGEobWVyZ2VkX2FsbCkNCg0KbWVyZ2VkX2FsbCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhtZXJnZWRfYWxsLCBuZmVhdHVyZXMgPSAzMDAwKQ0KbWVyZ2VkX2FsbCA8LSBTY2FsZURhdGEobWVyZ2VkX2FsbCkNCg0KdG9wX3Zhcl9nZW5lc18zMDAwIDwtIGhlYWQoVmFyaWFibGVGZWF0dXJlcyhtZXJnZWRfYWxsKSwgMjApDQpwcmludCh0b3BfdmFyX2dlbmVzXzMwMDApDQpgYGANCg0KIyNWaXN1YWxpemUgbW9zdCB2YXJpYWJsZSBmZWF0dXJlcw0KYGBge3J9DQpWYXJpYWJsZUZlYXR1cmVQbG90KG1lcmdlZF9hbGwpDQpMYWJlbFBvaW50cyhwb2ludHMgPSB0b3BfdmFyX2dlbmVzXzMwMDAsIHBsb3QgPSBsYXN0X3Bsb3QoKSwgcmVwZWwgPSBUUlVFKQ0KDQpgYGANCg0KIyNkZWNpZGUgbnVtYmVyIG9mIFBDQXMgdG8gdXNlIGZvciBhbmFseXNpczogbnBjcz0yMA0KYGBge3J9DQptZXJnZWRfYWxsIDwtIFJ1blBDQShtZXJnZWRfYWxsLCBucGNzID0gNTApDQpFbGJvd1Bsb3RfNTBQQ0FzIDwtIEVsYm93UGxvdChtZXJnZWRfYWxsLCBuZGltcyA9IDUwKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobi5icmVha3MgPSAyMCkgKyANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMCkNCkVsYm93UGxvdF81MFBDQXMgDQpgYGANCg0KIyNTdGFuZGFyZCBwcm9jZXNzaW5nIGFuZCBjbHVzdGVyaW5nLCAwLjYgcmVzb2x1dGlvbg0KYGBge3J9DQojU3RhbmRhcmQgcHJvY2Vzc2luZyBhbmQgY2x1c3RlcmluZw0KbWVyZ2VkX2FsbCA8LSBGaW5kTmVpZ2hib3JzKG1lcmdlZF9hbGwsIGRpbXMgPSAxOjIwLCB2ZXJib3NlID0gRikNCm1lcmdlZF9hbGwgPC0gRmluZENsdXN0ZXJzKG1lcmdlZF9hbGwsIHJlc29sdXRpb24gPSAwLjYpDQptZXJnZWRfYWxsIDwtIFJ1blVNQVAobWVyZ2VkX2FsbCwgZGltcyA9IDE6MjApDQpgYGANCg0KIyNDYWxjdWxhdGUgbnVtYmVyIG9mIGNlbGxzIGluIGVhY2ggY2x1c3Rlcg0KYGBge3J9DQoNCiBjZWxsc19wZXJfY2x1c3RlciA8LSBtZXJnZWRfYWxsQG1ldGEuZGF0YSAlPiUNCiAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUNCiAgc3VtbWFyaXNlKGNlbGxfY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKHNldXJhdF9jbHVzdGVycykNCg0KIGNlbGxzX3Blcl9jbHVzdGVyX2NvbmQgPC0gbWVyZ2VkX2FsbEBtZXRhLmRhdGEgJT4lDQogIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycywgY29uZGl0aW9uKSAlPiUNCiAgc3VtbWFyaXNlKGNlbGxfY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKHNldXJhdF9jbHVzdGVycywgY29uZGl0aW9uKQ0KDQpWaWV3KGNlbGxzX3Blcl9jbHVzdGVyKQ0KVmlldyhjZWxsc19wZXJfY2x1c3Rlcl9jb25kKQ0KDQpwcmludChjZWxsc19wZXJfY2x1c3RlcikNCnByaW50KGNlbGxzX3Blcl9jbHVzdGVyX2NvbmQpDQpgYGANCg0KI1VNQVAgdmlzdWFsaXphdGlvbiBwcmUtZG91YmxldCByZW1vdmFsDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYWxsKSA8LSAic2V1cmF0X2NsdXN0ZXJzIg0KRGltUGxvdChtZXJnZWRfYWxsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVCwgcmVwZWwgPSBUKSArIGdndGl0bGUoIlNldXJhdCBDbHVzdGVycyIpDQpgYGANCg0KI1JlbW92ZSBkb3VibGV0cw0KYGBge3J9DQojaW5zdGFsbCBhbmQgbG9hZCBzY0RibEZpbmRlciBwYWNrYWdlDQoNCiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgic2NEYmxGaW5kZXIiKQ0KbGlicmFyeShzY0RibEZpbmRlcikNCmxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpDQpgYGANCiMjY29udmVydCB0byBzaW5nbGUgY2VsbCBleHBlcmltZW50IGFuZCBydW4gc2NEYmxGaW5kZXINCmBgYHtyfQ0KI2NvbnZlcnQgdG8gc2luZ2xlIGNlbGwgZXhwZXJpbWVudCBhbmQgcnVuIHNjRGJsRmluZGVyDQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQobWVyZ2VkX2FsbCkNCnNjZSA8LSBzY0RibEZpbmRlcjo6c2NEYmxGaW5kZXIoc2NlLCBzYW1wbGVzID0gJ3NhbXBsZScpDQoNCmBgYA0KIyNhZGQgZG91YmxldCByZXN1bHRzIGJhY2sgaW50byBtZXRhZGF0YSBhbmQgdmlzdWFsaXplIG9uIFVNQVANCmBgYHtyfQ0KI2FkZCByZXN1bHRzIGJhY2sgaW50byBzZXVyYXQgbWV0YWRhdGENCm1lcmdlZF9hbGwkc2NEYmxGaW5kZXIuY2xhc3MgPC0gY29sRGF0YShzY2UpJHNjRGJsRmluZGVyLmNsYXNzDQoNCiN2aXN1YWxpemUNCnNpbmdfdnNfZG91Yl9iZWZvcmVfc3Vic2V0IDwtIERpbVBsb3QobWVyZ2VkX2FsbCxzcGxpdC5ieSA9ICdjb25kaXRpb24nLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInNjRGJsRmluZGVyLmNsYXNzIiwgcHQuc2l6ZSA9IDAuNSkgKyBnZ3RpdGxlKCJzY0RibEZpbmRlcjogU2luZ2xldHMgdnMgRG91YmxldHMiKQ0Kc2luZ192c19kb3ViX2JlZm9yZV9zdWJzZXQNCmBgYA0KDQojI3N1YnNldCB0byBvbmx5IHNpbmdsZXRzDQpgYGB7cn0NCm1lcmdlZF9hbGwgPC0gc3Vic2V0KG1lcmdlZF9hbGwsIHN1YnNldCA9IHNjRGJsRmluZGVyLmNsYXNzID09ICJzaW5nbGV0IikNCmBgYA0KDQojI3JlbmFtZSBtZXJnZWRfYWxsMiBhbmQgZmluZG5laWdoYm9ycyBhbmQgY2x1c3RlcnMgYWdhaW4/DQpgYGB7cn0NCm1lcmdlZF9hbGwyIDwtIG1lcmdlZF9hbGwNCg0KbWVyZ2VkX2FsbDIgPC0gRmluZE5laWdoYm9ycyhtZXJnZWRfYWxsMiwgZGltcyA9IDE6MjAsIHZlcmJvc2UgPSBGKQ0KbWVyZ2VkX2FsbDIgPC0gRmluZENsdXN0ZXJzKG1lcmdlZF9hbGwyLCByZXNvbHV0aW9uID0gMC42KQ0KDQptZXJnZWRfYWxsMiA8LSBSdW5VTUFQKG1lcmdlZF9hbGwyLCBkaW1zID0gMToyMCkNCmBgYA0KYGBge3J9DQpBIDwtIERpbVBsb3QobWVyZ2VkX2FsbCwgbGFiZWwgPSBULCByZXBlbCA9IFQpICsgTm9MZWdlbmQoKSArIGdndGl0bGUoIk9sZCBDbHVzdGVycyBBZnRlciBcbkRvdWJsZXQgUmVtb3ZhbCIpDQpCIDwtIERpbVBsb3QobWVyZ2VkX2FsbDIsIGxhYmVsID0gVCwgcmVwZWwgPSBUKSArIE5vTGVnZW5kKCkgKyBnZ3RpdGxlKCJSZWNsdXN0ZXJpbmcgQWZ0ZXIgXG5Eb3VibGV0IFJlbW92YWwiKQ0KQStCDQpgYGANCiMjY2FsY3VsYXRlIGNlbGxzIGluIGVhY2ggY2x1c3RlciBhZnRlciBkb3VibGV0IHJlbW92YWwgYW5kIHJlY2x1c3RlcmluZw0KYGBge3J9DQoNCmNlbGxzX3Blcl9jbHVzdGVyMiA8LSBtZXJnZWRfYWxsMkBtZXRhLmRhdGEgJT4lDQogIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lDQogIHN1bW1hcmlzZShjZWxsX2NvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShzZXVyYXRfY2x1c3RlcnMpDQoNCmNlbGxzX3Blcl9jbHVzdGVyX2NvbmQyIDwtIG1lcmdlZF9hbGwyQG1ldGEuZGF0YSAlPiUNCiAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzLCBjb25kaXRpb24pICU+JQ0KICBzdW1tYXJpc2UoY2VsbF9jb3VudCA9IG4oKSkgJT4lDQogIGFycmFuZ2Uoc2V1cmF0X2NsdXN0ZXJzLCBjb25kaXRpb24pDQoNClZpZXcoY2VsbHNfcGVyX2NsdXN0ZXIyKQ0KVmlldyhjZWxsc19wZXJfY2x1c3Rlcl9jb25kMikNCg0KcHJpbnQoY2VsbHNfcGVyX2NsdXN0ZXIyKQ0KcHJpbnQoY2VsbHNfcGVyX2NsdXN0ZXJfY29uZDIpDQpgYGANCg0KI1Zpc3VhbGl6YXRpb24NCiMjQnkgY29uZGl0aW9uDQpgYGB7cn0NCiNHcm91cCBieSBjb25kaXRpb24NCkRpbVBsb3QobWVyZ2VkX2FsbDIsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIiwgcHQuc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjMpIA0KYGBgDQojI2J5IHNhbXBsZSwgc3BsaXQgYnkgY29uZGl0aW9uDQpgYGB7ciwgZmlnLndpZHRoPTl9DQpEaW1QbG90KG1lcmdlZF9hbGwyLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ3NhbXBsZScsIHNwbGl0LmJ5ID0gImNvbmRpdGlvbiIsIGFscGhhID0gMC4zKQ0KYGBgDQojI2dyb3VwZWQgYnkgY2x1c3Rlciwgc3BsaXQgYnkgY29uZGl0aW9uDQpgYGB7ciwgZmlnLndpZHRoPTEwfQ0KRGltUGxvdChtZXJnZWRfYWxsMiwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJjb25kaXRpb24iLCBsYWJlbCA9IFQsIHJlcGVsID0gRiwgbGFiZWwuc2l6ZSA9IDUpICsgTm9MZWdlbmQoKQ0KDQpgYGANCiMjQmFyIGdyYXBoIG51bWJlciBvZiBjZWxscyBwZXIgY2x1c3RlciBmcm9tIGVhY2ggaW5kaXZpZHVhbCBzYW1wbGUNCmBgYHtyfQ0KI3Zpc3VhbGl6ZSBwZXJjZW50IG9mIGVhY2ggY2x1c3RlciBmcm9tIGluZGl2aWR1YWwgc2FtcGxlcw0KbWV0YV9kYXRhIDwtIG1lcmdlZF9hbGwyQG1ldGEuZGF0YQ0KDQojIENvdW50IGNlbGxzIHBlciBjbHVzdGVyIHBlciBzYW1wbGUNCmNsdXN0ZXJfY291bnRzIDwtIG1ldGFfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzLCBzYW1wbGUpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpDQoNCiMgQ2FsY3VsYXRlIHRvdGFsIGNlbGxzIHBlciBzYW1wbGUNCnRvdGFsX3Blcl9jbHVzdGVyIDwtIGNsdXN0ZXJfY291bnRzICU+JQ0KICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JQ0KICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIE1lcmdlIGFuZCBjYWxjdWxhdGUgcGVyY2VudGFnZQ0KY2x1c3Rlcl9wZXJjZW50YWdlcyA8LSBjbHVzdGVyX2NvdW50cyAlPiUNCiAgbGVmdF9qb2luKHRvdGFsX3Blcl9jbHVzdGVyLCBieSA9ICJzZXVyYXRfY2x1c3RlcnMiKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSAoY291bnQgLyB0b3RhbCkgKiAxMDApDQoNCg0KIyBQbG90DQpnZ3Bsb3QoY2x1c3Rlcl9wZXJjZW50YWdlcywgYWVzKHggPSBzZXVyYXRfY2x1c3RlcnMsIHkgPSBwZXJjZW50YWdlLCBmaWxsID0gc2FtcGxlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArDQogIGxhYnModGl0bGUgPSAiQ2x1c3RlciBDb21wb3NpdGlvbiBCeSBTYW1wbGUiLA0KICAgICAgIHggPSAiQ2x1c3RlciIsDQogICAgICAgeSA9ICJQZXJjZW50YWdlIG9mIENsdXN0ZXIiLA0KICAgICAgIGZpbGwgPSAiU2FtcGxlIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQoNCmBgYA0KIyNwZXJjZW50IG9mIGVhY2ggY2x1c3RlciBmcm9tIGVhY2ggY29uZGl0aW9uDQpgYGB7cn0NCiN2aXN1YWxpemUgcGVyY2VudCBvZiBlYWNoIGNsdXN0ZXIgZnJvbSBlYWNoIGNvbmRpdGlvbg0KDQojIENvdW50IGNlbGxzIHBlciBjbHVzdGVyIHBlciBjb25kaXRpb24NCmNsdXN0ZXJfY291bnRzX2NvbmQgPC0gbWV0YV9kYXRhICU+JQ0KICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMsIGNvbmRpdGlvbikgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KIyBDYWxjdWxhdGUgdG90YWwgY2VsbHMgcGVyIHNhbXBsZQ0KdG90YWxfY29uZF9wZXJfY2x1c3RlciA8LSBjbHVzdGVyX2NvdW50c19jb25kICU+JQ0KICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JQ0KICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIE1lcmdlIGFuZCBjYWxjdWxhdGUgcGVyY2VudGFnZQ0KY2x1c3Rlcl9jb25kX3BlcmNlbnRhZ2VzIDwtIGNsdXN0ZXJfY291bnRzX2NvbmQgJT4lDQogIGxlZnRfam9pbih0b3RhbF9jb25kX3Blcl9jbHVzdGVyLCBieSA9ICJzZXVyYXRfY2x1c3RlcnMiKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSAoY291bnQgLyB0b3RhbCkgKiAxMDApDQoNCg0KIyBQbG90DQpnZ3Bsb3QoY2x1c3Rlcl9jb25kX3BlcmNlbnRhZ2VzLCBhZXMoeCA9IHNldXJhdF9jbHVzdGVycywgeSA9IHBlcmNlbnRhZ2UsIGZpbGwgPSBjb25kaXRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJDbHVzdGVyIENvbXBvc2l0aW9uIGJ5IENvbmRpdGlvbiIsDQogICAgICAgeCA9ICJDbHVzdGVyIiwNCiAgICAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgQ2x1c3RlciIsDQogICAgICAgZmlsbCA9ICJTYW1wbGUiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCiMjdmlzdWFsaXplIHBlcmNlbnQubXQgcGVyIGNsdXN0ZXINCmBgYHtyfQ0KI2FkZCBtZXRhZGF0YSBjb2x1bW4gZm9yIGNsdXN0ZXJfY29uZGl0aW9uDQptZXJnZWRfYWxsMiRjbHVzdGVyX2NvbmRpdGlvbiA8LSBwYXN0ZTAobWVyZ2VkX2FsbDIkc2V1cmF0X2NsdXN0ZXJzLCJfIixtZXJnZWRfYWxsMiRjb25kaXRpb24pDQpJZGVudHMobWVyZ2VkX2FsbDIpIDwtIG1lcmdlZF9hbGwyJGNsdXN0ZXJfY29uZGl0aW9uDQoNCiNjaGVjayB0aGF0IG1ldGFkYXRhIGNvbHVtbiBpcyBhZGRlZA0KY29sbmFtZXMobWVyZ2VkX2FsbDJAbWV0YS5kYXRhKQ0KDQojIENyZWF0ZSBzdW1tYXJ5IGRhdGEgZnJhbWUNCnBlcmNlbnRfbXRfc3VtbWFyeSA8LSBtZXJnZWRfYWxsMkBtZXRhLmRhdGEgJT4lDQogIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgIG1lYW5fcGVyY2VudF9tdCA9IG1lYW4ocGVyY2VudC5tdCwgbmEucm0gPSBUUlVFKSwNCiAgICBtZWRpYW5fcGVyY2VudF9tdCA9IG1lZGlhbihwZXJjZW50Lm10LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICBuX2NlbGxzID0gbigpDQogICkNCg0KcHJpbnQocGVyY2VudF9tdF9zdW1tYXJ5KQ0KDQpnZ3Bsb3QocGVyY2VudF9tdF9zdW1tYXJ5LCBhZXMoeCA9IGZhY3RvcihzZXVyYXRfY2x1c3RlcnMpLCB5ID0gbWVhbl9wZXJjZW50X210KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjMmM3ZmI4IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk1lYW4gTWl0b2Nob25kcmlhbCBQZXJjZW50YWdlIGJ5IENsdXN0ZXIiLA0KICAgIHggPSAiQ2x1c3RlciIsDQogICAgeSA9ICJNZWFuICUgTWl0b2Nob25kcmlhbCBHZW5lcyINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcnNfdGFibGUgPC0gdGFibGUobWVyZ2VkX2FsbDIkc2V1cmF0X2NsdXN0ZXJzLCBtZXJnZWRfYWxsMiRzYW1wbGUpDQpjbHVzdGVyc190YWJsZV9jb25kIDwtIHRhYmxlKG1lcmdlZF9hbGwyJHNldXJhdF9jbHVzdGVycywgbWVyZ2VkX2FsbDIkY29uZGl0aW9uKQ0KY2x1c3RlcnNfdGFibGUNCmNsdXN0ZXJzX3RhYmxlX2NvbmQNCg0KYGBgDQojQ3JlYXRlIGNsdXN0ZXIgdHJlZSANCmBgYHtyfQ0KIyBDbHVzdHJlZSB2aXN1YWxpemF0aW9uDQppbnN0YWxsLnBhY2thZ2VzKCJjbHVzdHJlZSIpDQpsaWJyYXJ5KGNsdXN0cmVlKQ0KDQptZXJnZWRfdHJlZSA8LSBtZXJnZWRfYWxsMg0KDQojQWRkIG11bHRpcGxlIHJlc29sdXRpb25zDQptZXJnZWRfdHJlZSA8LSBGaW5kQ2x1c3RlcnMobWVyZ2VkX3RyZWUsIHJlc29sdXRpb24gPSBjKDAuMSwgMC4yLCAwLjQsIDAuNiwgMC44KSkNCg0KDQpjbHVzdGVyLnRyZWUgPC0gY2x1c3RyZWUoDQogIG1lcmdlZF90cmVlLCAiUk5BX3Nubl9yZXMuIikgKyBnZ3RpdGxlKCJDbHVzdGVyIHRyZWUiKQ0KDQpnZ3NhdmUoInJlc29sdXRpb24gY2x1c3RlciB0cmVlLnN2ZyIsIHBsb3QgPSBjbHVzdGVyLnRyZWUsIHdpZHRoID0gMTIpDQoNCmNsdXN0ZXIudHJlZSANCmBgYA0KIyNzaWxob3VldHRlIHBsb3QNCmBgYHtyLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0PTEyfQ0KbGlicmFyeShjbHVzdGVyKQ0KbGlicmFyeShwdXJycikNCg0KIyBDb252ZXJ0IGNsdXN0ZXJzIHRvIG51bWVyaWMNCmNsdXN0ZXJzIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKG1lcmdlZF9hbGwyJHNldXJhdF9jbHVzdGVycykpDQoNCiMgQ29tcHV0ZSBkaXN0YW5jZSBvbiBQQ0EgZW1iZWRkaW5ncw0KZCA8LSBkaXN0KG1lcmdlZF9hbGwyQHJlZHVjdGlvbnMkcGNhQGNlbGwuZW1iZWRkaW5ncykNCg0KIyBSdW4gc2lsaG91ZXR0ZQ0Kc2lsIDwtIGNsdXN0ZXI6OnNpbGhvdWV0dGUoY2x1c3RlcnMsIGQpDQoNCiMgNC4gQ29udmVydCB0byBkYXRhIGZyYW1lDQpzaWxfZGYgPC0gYXMuZGF0YS5mcmFtZShzaWwpDQpzaWxfZGYkY2VsbCA8LSByb3duYW1lcyhzaWxfZGYpIA0KY29sbmFtZXMoc2lsX2RmKSA8LSBjKCJjbHVzdGVyIiwgIm5laWdoYm9yIiwgInNpbF93aWR0aCIsICJjZWxsIikNCnNpbF9kZg0KDQojIE1ha2UgY2x1c3RlciBhIGZhY3RvciBmb3IgcGxvdHRpbmcNCnNpbF9kZiRjbHVzdGVyIDwtIGFzLmZhY3RvcihzaWxfZGYkY2x1c3RlcikNCg0KIyA1LiBnZ3Bsb3Qgc2lsaG91ZXR0ZSBwbG90DQpnZ3Bsb3Qoc2lsX2RmLCBhZXMoeCA9IHJlb3JkZXIoY2VsbCwgc2lsX3dpZHRoKSwgeSA9IHNpbF93aWR0aCwgZmlsbCA9IGNsdXN0ZXIpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEsIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZmFjZXRfd3JhcCh+IGNsdXN0ZXIsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMSkgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiQ2VsbHMgKG9yZGVyZWQgYnkgc2lsaG91ZXR0ZSB3aWR0aCkiLA0KICAgICAgIHkgPSAiU2lsaG91ZXR0ZSB3aWR0aCIsDQogICAgICAgdGl0bGUgPSAiU2lsaG91ZXR0ZSBwbG90IG9mIFNldXJhdCBjbHVzdGVycyIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQoNCiNFdmFsdWF0ZSBjb25zZXJ2ZWQgbWFya2VyIGdlbmVzLCB1c2UgdG8gY29uc29saWRhdGUgc21hbGxlciBjbHVzdGVycyBpbnRvIGxhcmdlciBvbmVzDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYWxsMikgPC0gJ3NldXJhdF9jbHVzdGVycycNCm1lcmdlZF9hbGwyJGNvbnNvbGlkYXRlZF9jbHVzdGVycyA8LSBtZXJnZWRfYWxsMiRzZXVyYXRfY2x1c3RlcnMNCg0KbGlicmFyeShwcmVzdG8pDQpsaWJyYXJ5KFNldXJhdFdyYXBwZXJzKQ0KDQojIEluaXRpYWxpemUgdGhlIGxpc3QNCmNvbnNlcnZlZF9tYXJrZXJzIDwtIGxpc3QoKQ0KDQojIExvb3AgdGhyb3VnaCB0aGUgY2x1c3RlcnMgaW4gdGhlIHNwZWNpZmllZCBvcmRlcg0KZm9yIChpIGluIDA6MjQpIHsNCiAgYXV4IDwtIFNldXJhdFdyYXBwZXJzOjpSdW5QcmVzdG8oDQogICAgbWVyZ2VkX2FsbDIsDQogICAgaWRlbnQuMSA9IGksDQogICAgb25seS5wb3MgPSBUUlVFLA0KICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuNSwNCiAgICBtaW4ucGN0ID0gMC40DQogICkNCiAgDQogIGlmICghaXMubnVsbChhdXgpICYmIG5yb3coYXV4KSA+IDApIHsNCiAgICBhdXgkZ2VuZSA8LSByb3duYW1lcyhhdXgpDQogICAgYXV4JGNsdXN0ZXIgPC0gaQ0KICAgIGNvbnNlcnZlZF9tYXJrZXJzW1twYXN0ZTAoImNsdXN0ZXJfIiwgaSldXSA8LSBhdXgNCiAgfQ0KfQ0KDQojZmlsdGVyDQpmb3IoaSBpbiBuYW1lcyhjb25zZXJ2ZWRfbWFya2Vycykpew0KICBhdXggPC0gY29uc2VydmVkX21hcmtlcnNbW2ldXQ0KICBhdXgkY2x1c3RlciA8LSBpDQogIGF1eCA8LSBhdXhbYXV4JHBfdmFsX2FkaiA8IDAuMDUsXQ0KICBhdXggPC0gYXV4W29yZGVyKGF1eCRhdmdfbG9nMkZDLCBkZWNyZWFzaW5nPVQpLF0NCiAgY29uc2VydmVkX21hcmtlcnNbW2ldXSA8LSBhdXgNCn0NCg0KYGBgDQojI2V4cG9ydCBjb25zZXJ2ZWQgbWFya2VycyBhcyBleGNlbCBmaWxlDQpgYGB7cn0NCmxpYnJhcnkocmlvKQ0KcmlvOjpleHBvcnQoY29uc2VydmVkX21hcmtlcnMsICJjb25zZXJ2ZWQgbWFya2VycyBhbGwgY2x1c3RlcnMueGxzeCIpDQpgYGANCg0KI0NvbnNvbGlkYXRlIGNsdXN0ZXJzDQpgYGB7cn0NCg0KI2NvcHkgc2V1cmF0X2NsdXN0ZXJzIHRvIG5ldyBtZXRhZGF0ZSBjb2x1bW4NCm1lcmdlZF9hbGwyJGNvbnNvbGlkYXRlZF9jbHVzdGVycyA8LSBtZXJnZWRfYWxsMiRzZXVyYXRfY2x1c3RlcnMNCg0KI3NldCBpZGVudGl0eSBhcyBuZXcgY29sdW1uLCAnY29uc29saWRhdGVkX2NsdXN0ZXJzJw0KSWRlbnRzKG1lcmdlZF9hbGwyKSA8LSAnY29uc29saWRhdGVkX2NsdXN0ZXJzJw0KDQojIE1ha2UgbmV3IGNvbHVtbiBhIGNoYXJhY3RlciB2ZWN0b3IgaW5zdGVhZCBvZiBmYWN0b3INCm1lcmdlZF9hbGwyQG1ldGEuZGF0YSRjb25zb2xpZGF0ZWRfY2x1c3RlcnMgPC0gDQogIGFzLmNoYXJhY3RlcihtZXJnZWRfYWxsMkBtZXRhLmRhdGEkY29uc29saWRhdGVkX2NsdXN0ZXJzKQ0KDQojZGVmaW5lICdjdXJyZW50IGNsdXN0ZXJzJyBmb3IgbWFwcGluZyBsYXRlcg0KY3VycmVudF9jbHVzdGVycyA8LSBhcy5jaGFyYWN0ZXIobWVyZ2VkX2FsbDIkc2V1cmF0X2NsdXN0ZXJzKQ0KDQoNCiNDb25zb2xpZGF0aW9ucyAodW5uYW1lZCBjbHVzdGVycyBnbyB1bmNoYW5nZWQpDQpuZXdfY2x1c3Rlcl9tYXAgPC0gYygNCiAgIjI0IiAgPSAiMTIiLA0KICAiMjMiICA9ICIxIiwNCiAgIjIxIiA9ICIxNCINCikNCg0KIyM1LDEwLDE0LDE4LDIxIGFyZSBhbGwgbXllbG9pZCAoQ0Q2OCspDQogICAjMTQvMjEgPSBEQw0KIyNmcm9tIGNsdXN0ZXIgdHJlZTogNSBhbmQgMTAgY29tYmluZSwgMTQsIDE4LCBhbmQgMjEgY29tYmluZQ0KIzI0IC0+IDEyIChnYW1tYSBkZWx0YSBUPykgLT4gNyAoYWxzbyBleHByZXNzaW5nIFRyZ3YgaW4gdG9wIGdlbmVzKQ0KDQojQXBwbHkgbWFwcGluZyBiYWNrIHRvIG1ldGFkYXRhDQptZXJnZWRfYWxsMiRjb25zb2xpZGF0ZWRfY2x1c3RlcnMgPC0gaWZlbHNlKA0KICBjdXJyZW50X2NsdXN0ZXJzICVpbiUgbmFtZXMobmV3X2NsdXN0ZXJfbWFwKSwNCiAgbmV3X2NsdXN0ZXJfbWFwW2N1cnJlbnRfY2x1c3RlcnNdLA0KICBjdXJyZW50X2NsdXN0ZXJzDQopDQoNCiMgQ29udmVydCBiYWNrIHRvIGZhY3RvciAob3B0aW9uYWwsIGJ1dCB1c3VhbGx5IGNsZWFuZXIgZm9yIElkZW50cykNCm1lcmdlZF9hbGwyQG1ldGEuZGF0YSRjb25zb2xpZGF0ZWRfY2x1c3RlcnMgPC0gDQogIGZhY3RvcihtZXJnZWRfYWxsMkBtZXRhLmRhdGEkY29uc29saWRhdGVkX2NsdXN0ZXJzLCBsZXZlbHMgPSBjKDA6MjAsMjIpKQ0KDQojIFNldCBhY3RpdmUgaWRlbnRpdGllcyBjb3JyZWN0bHkNCklkZW50cyhtZXJnZWRfYWxsMikgPC0gJ2NvbnNvbGlkYXRlZF9jbHVzdGVycycNCmBgYA0KDQojTmFtaW5nIGNsdXN0ZXJzIChwcmVsaW1pbmFyeSwgbWFudWFsKS4gSW4gbmV3IG9iamVjdCAnbWVyZ2VkX2Fubm90Jw0KYGBge3J9DQptZXJnZWRfYW5ub3QgPC0gbWVyZ2VkX2FsbDINCm1lcmdlZF9hbm5vdCRhbm5vdCA8LSBtZXJnZWRfYW5ub3QkY29uc29saWRhdGVkX2NsdXN0ZXJzDQoNCg0KI3NldCBpZGVudGl0eSBhcyBuZXcgY29sdW1uLCAnY29uc29saWRhdGVkX2NsdXN0ZXJzJw0KSWRlbnRzKG1lcmdlZF9hbm5vdCkgPC0gJ2Fubm90Jw0KDQojIE1ha2UgbmV3IGNvbHVtbiBhIGNoYXJhY3RlciB2ZWN0b3IgaW5zdGVhZCBvZiBmYWN0b3INCm1lcmdlZF9hbm5vdEBtZXRhLmRhdGEkYW5ub3QgPC0gDQogIGFzLmNoYXJhY3RlcihtZXJnZWRfYW5ub3RAbWV0YS5kYXRhJGFubm90KQ0KDQojZGVmaW5lICdjdXJyZW50IGNsdXN0ZXJzJyBmb3IgbWFwcGluZyBsYXRlcg0KY3VycmVudF9jbHVzdGVyc19hbm5vdCA8LSBhcy5jaGFyYWN0ZXIobWVyZ2VkX2Fubm90JGFubm90KQ0KDQoNCiNDb25zb2xpZGF0aW9ucyAodW5uYW1lZCBjbHVzdGVycyBnbyB1bmNoYW5nZWQpDQpuZXdfY2x1c3Rlcl9tYXBfYW5ub3QgPC0gYygNCiAgIjAiID0gIkN5dG90b3hpYyBOSy1UIiwNCiAgIjEiID0gIkIgY2VsbCIsDQogICIyIiA9ICJOYWl2ZSBUX1RDTSIsDQogICIzIiA9ICJOZXV0cm9waGlsIiwgDQogICI0IiA9ICJQVCBncm91cCAxIiwNCiAgIjUiID0gIkFjdGl2YXRlZCBtYWNyb3BoYWdlIiwNCiAgIjYiID0gIkltbWF0dXJlIFRfZ3JvdXAgMiIsDQogICI3IiA9ICJUaDEiLA0KICAiOCIgPSAiUFQgZ3JvdXAgMiIsDQogICI5IiA9ICJQVCBncm91cCAzIiwNCiAgIjEwIiA9ICJNeWVsb2lkIiwNCiAgIjExIiA9ICJQVCBncm91cCA0IiwNCiAgIjEyIiA9ICJUIGNlbGxfZ2FtbWFfZGVsdGEiLA0KICAiMTMiID0gIlRBTF9EQ1QiLA0KICAiMTQiID0gIkRDIiwNCiAgIjE1IiA9ICJEQ1RfQ05UIiwNCiAgIjE2IiA9ICJUQUxfRENUIiwNCiAgIjE3IiA9ICJUQUwiLA0KICAiMTgiID0gIk1vbm9fbWFjcm9waGFnZSIsDQogICIxOSIgPSAiVGlzc3VlLXJlc2lkZW50IE5LLVQiLA0KICAiMjAiID0gIkVuZG90aGVsaWFsIiwNCiAgIjIyIiA9ICJJbnRlcmNhbGF0ZWQgY2VsbCIpDQoNCg0KDQojQXBwbHkgbWFwcGluZyBiYWNrIHRvIG1ldGFkYXRhDQptZXJnZWRfYW5ub3QkYW5ub3QgPC0gaWZlbHNlKA0KICBjdXJyZW50X2NsdXN0ZXJzX2Fubm90ICVpbiUgbmFtZXMobmV3X2NsdXN0ZXJfbWFwX2Fubm90KSwNCiAgbmV3X2NsdXN0ZXJfbWFwX2Fubm90W2N1cnJlbnRfY2x1c3RlcnNfYW5ub3RdLA0KICBjdXJyZW50X2NsdXN0ZXJzX2Fubm90DQopDQoNCiMgQ29udmVydCBiYWNrIHRvIGZhY3RvciAob3B0aW9uYWwsIGJ1dCB1c3VhbGx5IGNsZWFuZXIgZm9yIElkZW50cykNCm1lcmdlZF9hbm5vdEBtZXRhLmRhdGEkYW5ub3QgPC0gDQogIGZhY3RvcihtZXJnZWRfYW5ub3RAbWV0YS5kYXRhJGFubm90KQ0KDQojIFNldCBhY3RpdmUgaWRlbnRpdGllcyBjb3JyZWN0bHkNCklkZW50cyhtZXJnZWRfYW5ub3QpIDwtICdhbm5vdCcNCg0KDQpgYGANCg0KI1Zpc3VhbGl6ZSB1bWFwIHdpdGggYW5ub3RhdGlvbnMNCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03fQ0KRGltUGxvdChtZXJnZWRfYW5ub3QsIGxhYmVsPVQpICsgTm9MZWdlbmQoKQ0KYGBgDQojI3NwbGl0IGJ5IGNvbmRpdGlvbg0KYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEzfQ0KRGltUGxvdChtZXJnZWRfYW5ub3QsIGxhYmVsPVQsIHNwbGl0LmJ5ID0gJ2NvbmRpdGlvbicpICsgTm9MZWdlbmQoKQ0KYGBgDQoNCmBgYHtyfQ0Kc2F2ZVJEUyhtZXJnZWRfYW5ub3QsICJFdmFuX3NldXJhdF9vYmouUkRTIikNCmBgYA0KDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYW5ub3QpIDwtICdhbm5vdCcNCg0KYW5ub3RhdGlvbnMgPC0gbGlzdCgpDQphbm5vdGF0aW9ucyA8LSB1bmlxdWUoSWRlbnRzKG1lcmdlZF9hbm5vdCkpDQoNCiMgSW5pdGlhbGl6ZSB0aGUgbGlzdA0KY29uc2VydmVkX21hcmtlcnNfYW5ub3QgPC0gbGlzdCgpDQoNCiMgTG9vcCB0aHJvdWdoIHRoZSBjbHVzdGVycyBpbiB0aGUgc3BlY2lmaWVkIG9yZGVyDQpmb3IgKGkgaW4gdW5pcXVlKGFubm90YXRpb25zKSkgew0KICBhdXggPC0gU2V1cmF0V3JhcHBlcnM6OlJ1blByZXN0bygNCiAgICBtZXJnZWRfYW5ub3QsDQogICAgaWRlbnQuMSA9IGksDQogICAgb25seS5wb3MgPSBUUlVFLA0KICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuNSwNCiAgICBtaW4ucGN0ID0gMC40DQogICkNCiAgDQogIGlmICghaXMubnVsbChhdXgpICYmIG5yb3coYXV4KSA+IDApIHsNCiAgICBhdXgkZ2VuZSA8LSByb3duYW1lcyhhdXgpDQogICAgYXV4JGNsdXN0ZXIgPC0gaQ0KICAgIGNvbnNlcnZlZF9tYXJrZXJzX2Fubm90W1tpXV0gPC0gYXV4DQogIH0NCn0NCg0KI2ZpbHRlcg0KZm9yKGkgaW4gbmFtZXMoY29uc2VydmVkX21hcmtlcnNfYW5ub3QpKXsNCiAgYXV4IDwtIGNvbnNlcnZlZF9tYXJrZXJzX2Fubm90W1tpXV0NCiAgYXV4JGNsdXN0ZXIgPC0gaQ0KICBhdXggPC0gYXV4W2F1eCRwX3ZhbF9hZGogPCAwLjA1LF0NCiAgYXV4IDwtIGF1eFtvcmRlcihhdXgkYXZnX2xvZzJGQywgZGVjcmVhc2luZz1UKSxdDQogIGNvbnNlcnZlZF9tYXJrZXJzX2Fubm90W1tpXV0gPC0gYXV4DQp9DQoNCmBgYA0KDQoNCmBgYHtyfQ0KbWVyZ2VkX2FsbDIkY29uc29saWRhdGVkX2NsdXN0ZXJzIDwtIG1lcmdlZF9hbGwyJHNldXJhdF9jbHVzdGVycw0KSWRlbnRzKG1lcmdlZF9hbGwyKSA8LSAnY29uc29saWRhdGVkX2NsdXN0ZXJzJw0KDQojIzI0IGludG8gMTIsIFQgY2VsbCBwb3B1bGF0aW9uIHdpdGggVHJnIA0KbWVyZ2VkX2FsbDJAbWV0YS5kYXRhJGNvbnNvbGlkYXRlZF9jbHVzdGVycyA8LSANCiAgaWZlbHNlKA0KICAgIG1lcmdlZF9hbGwyQG1ldGEuZGF0YSRjb25zb2xpZGF0ZWRfY2x1c3RlcnMgPT0gIjI0IiwNCiAgICAxMiwNCiAgICBtZXJnZWRfYWxsMkBtZXRhLmRhdGEkY29uc29saWRhdGVkX2NsdXN0ZXJzDQogICkNCg0KIzIzIGludG8gMSwgQiBjZWxscyAtIGxvdHMgb2YgaW1tdW5vZ2xvYnVsaW5zIGluIDIzIGFuZCBqY2hhaW4sIDEgaXMgY2QxOS1oaWdoIGIgY2VsbCBncm91cA0KbWVyZ2VkX2FsbDJAbWV0YS5kYXRhJGNvbnNvbGlkYXRlZF9jbHVzdGVycyA8LSANCiAgaWZlbHNlKA0KICAgIG1lcmdlZF9hbGwyQG1ldGEuZGF0YSRjb25zb2xpZGF0ZWRfY2x1c3RlcnMgPT0gIjIzIiwNCiAgICAxLA0KICAgIG1lcmdlZF9hbGwyQG1ldGEuZGF0YSRjb25zb2xpZGF0ZWRfY2x1c3RlcnMNCiAgKQ0KDQp1bmlxdWUobWVyZ2VkX2FsbDIkY29uc29saWRhdGVkX2NsdXN0ZXJzKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCisrKysNCiNFdmFsdWF0ZSBjb25zZXJ2ZWQgYW5kIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcw0KYGBge3J9DQpJZGVudHMobWVyZ2VkX2FsbDIpIDwtICdzZXVyYXRfY2x1c3RlcnMnDQoNCiMgRGVmaW5lIHRoZSBjdXN0b20gb3JkZXINCmNsdXN0ZXJfb3JkZXJfMC4xIDwtIGMoMCwgMSwgMTAsIDExLCAxMiwgMTMsIDE0LCAxNSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSkNCg0KIyBJbml0aWFsaXplIHRoZSBsaXN0DQpjb25zZXJ2ZWRfbWFya2Vyc19yZXMwLjEgPC0gbGlzdCgpDQoNCiMgTG9vcCB0aHJvdWdoIHRoZSBjbHVzdGVycyBpbiB0aGUgc3BlY2lmaWVkIG9yZGVyDQpmb3IgKGkgaW4gY2x1c3Rlcl9vcmRlcl8wLjEpIHsNCiAgYXV4IDwtIFNldXJhdFdyYXBwZXJzOjpSdW5QcmVzdG8oDQogICAgbWVyZ2VkX2FsbF9jb25zLA0KICAgIGlkZW50LjEgPSBpLA0KICAgIG9ubHkucG9zID0gVFJVRSwNCiAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjUsDQogICAgbWluLnBjdCA9IDAuNA0KICApDQogIA0KICBpZiAoIWlzLm51bGwoYXV4KSAmJiBucm93KGF1eCkgPiAwKSB7DQogICAgYXV4JGdlbmUgPC0gcm93bmFtZXMoYXV4KQ0KICAgIGF1eCRjbHVzdGVyIDwtIGkNCiAgICBjb25zZXJ2ZWRfbWFya2Vyc19yZXMwLjFbW3Bhc3RlMCgiY2x1c3Rlcl8iLCBpKV1dIDwtIGF1eA0KICB9DQp9DQpgYGANCg0KDQpgYGB7cn0NCiNmaWx0ZXINCmZvcihpIGluIG5hbWVzKGNvbnNlcnZlZF9tYXJrZXJzX3JlczAuMSkpew0KICBhdXggPC0gY29uc2VydmVkX21hcmtlcnNfcmVzMC4xW1tpXV0NCiAgYXV4JGNsdXN0ZXIgPC0gaQ0KICBhdXggPC0gYXV4W2F1eCRwX3ZhbF9hZGogPCAwLjA1LF0NCiAgYXV4IDwtIGF1eFtvcmRlcihhdXgkYXZnX2xvZzJGQywgZGVjcmVhc2luZz1UKSxdDQogIGNvbnNlcnZlZF9tYXJrZXJzX3JlczAuMVtbaV1dIDwtIGF1eA0KfQ0KYGBgDQoNCmBgYHtyfQ0KIyB0YWtlIHRvcCAxNSBnZW5lcyBmcm9tIGVhY2ggY2x1c3RlciB0byBkbyBhbm5vdGF0aW9ucw0KY2x1c3Rlcl9hbm5vdF9kZl8wLjEgPC0gY29uc2VydmVkX21hcmtlcnNfcmVzMC4xICU+JQ0KICBtYXAofiBoZWFkKC54LCAxMCkpICU+JSAgIyBUYWtlIGZpcnN0IDEwIHJvd3Mgb2YgZWFjaCBkYXRhIGZyYW1lDQogIGJpbmRfcm93cygpICAgICAgICAgICAgICAjIENvbWJpbmUgaW50byBvbmUgZGF0YSBmcmFtZQ0KYGBgDQoNCg0KYGBge3J9DQpyaW86OmV4cG9ydChjb25zZXJ2ZWRfbWFya2Vyc19yZXMwLjEsICJhbGwgcG9zIGNvbnNlcnZlZCBnZW5lcyBwZXIgY2x1c3Rlci54bHN4IikNCnJpbzo6ZXhwb3J0KGNsdXN0ZXJfYW5ub3RfZGZfMC4xLCAidG9wIDE1IGNvbnNlcnZlZCBnZW5lcyBwZXIgY2x1c3Rlci54bHN4IikNCmBgYA0KDQojUHV0IGluIGNsdXN0ZXIgYW5ub3RhdGlvbnMNCmBgYHtyfQ0KbDFfYW5ub3RhdGlvbnNfcmVzMC4xIDwtIGMoDQogICJQVCIsICAgICAgICAgICAjIGNsdXN0ZXIgMA0KICAiVCBjZWxsIiwgICAgICAgICAgICAgICAgICAgICMgY2x1c3RlciAxDQogICJNeWVsb2lkIiwgICAgICAgICMgY2x1c3RlciAyDQogICJCIENlbGwiLCAgICAgICAgICAgICAgICAgICAgICAgICAjIGNsdXN0ZXIgMw0KICAiTkstVCIsICAgICAgIyBjbHVzdGVyIDQNCiAgIlQgY2VsbCIsICMgY2x1c3RlciA1DQogICJQTU4iLCAgICAgICAgICAgICAgICAgICAgIyBjbHVzdGVyIDYNCiAgIkZpYnJvX1N0cm9tYWwiLCAgICAgIyBjbHVzdGVyIDcNCiAgIlBvZG9jeXRlIiwgICAgICAgICAgICAgICAgICAgICAgIyBjbHVzdGVyIDgNCiAgIk1hY3JvcGhhZ2UiLCAgICAgICAgICAgICAgIyBjbHVzdGVyIDkNCiAgIlQgY2VsbCIsICAgICAgICAgICMgY2x1c3RlciAxMA0KICAiVEFMIiwgICAgICAgICAgICMgY2x1c3RlciAxMQ0KICAicERDIiwgICAgICAgICAgICMgY2x1c3RlciAxMg0KICAiRENUIiwgICAgICAgIyBjbHVzdGVyIDEzDQogICJJQy1CIiwgICAgICAjIGNsdXN0ZXIgMTQNCiAgIklMQzIvTXllbG9pZCIgICAgIyBjbHVzdGVyIDE1DQopDQoNCklkZW50cyhtZXJnZWRfYWxsX2NvbnMpIDwtICdSTkFfc25uX3Jlcy4wLjEnDQoNCnVuaXF1ZShJZGVudHMobWVyZ2VkX2FsbF9jb25zKSkNCmBgYA0KYGBge3IsIGZpZy53aWR0aD0xMH0NCmNsdXN0ZXIudHJlZQ0KYGBgDQpgYGB7ciwgZmlnLmhlaWdodD04fQ0KSWRlbnRzKG1lcmdlZF9hbGxfY29ucykgPC0gJ3NldXJhdF9jbHVzdGVycycNCkRlZmF1bHRBc3NheShtZXJnZWRfYWxsX2NvbnMpDQoNCm1lcmdlZF8wLjA1IDwtIEZpbmRDbHVzdGVycyhtZXJnZWRfMC4wNSwgcmVzb2x1dGlvbiA9IDAuMDEpDQogIA0KY2x1c3Rlci50cmVlLjhkaW0gPC0gY2x1c3RyZWUobWVyZ2VkXzAuMDUsIHByZWZpeCA9ICJSTkFfc25uX3Jlcy4iKQ0KY2x1c3Rlci50cmVlLjhkaW0NCmBgYA0KDQoNCmBgYHtyfQ0KIyBNYWtlIHN1cmUgY2x1c3RlciBJRHMgYXJlIG51bWVyaWMgYW5kIDAtYmFzZWQNCmNsdXN0ZXJzIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKG1lcmdlZF9hbGxfY29ucyRSTkFfc25uX3Jlcy4wLjEpKQ0KDQojIE1hcCBjbHVzdGVyIElEcyB0byBtYW51YWwgYW5ub3RhdGlvbnMNCiMgQ3JlYXRlIGEgbmFtZWQgdmVjdG9yIGZvciBlYXN5IGxvb2t1cA0KbmFtZXMobDFfYW5ub3RhdGlvbnNfcmVzMC4xKSA8LSBhcy5jaGFyYWN0ZXIoMDoxNSkNCg0KIyBBZGQgYW5ub3RhdGlvbiBtZXRhZGF0YSBieSBtYXRjaGluZyBjbHVzdGVyIElEcw0KbWVyZ2VkX2FsbF9jb25zQG1ldGEuZGF0YSRsMV9hbm5vdGF0aW9uc19yZXMwLjEgPC0gbDFfYW5ub3RhdGlvbnNfcmVzMC4xW2FzLmNoYXJhY3RlcihjbHVzdGVycyldDQoNCmBgYA0KDQpgYGB7cn0NCm1lcmdlZF9hbGxfY29uc0BtZXRhLmRhdGENCmBgYA0KDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYWxsX2NvbnMpIDwtICdhbm5vdGF0aW9uJw0KRGltUGxvdChtZXJnZWRfYWxsX2NvbnMsIGxhYmVsID0gVCwgcmVwZWwgPSBUKQ0KYGBgDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYWxsX2NvbnMpIDwtICdSTkFfc25uX3Jlcy4wLjEnDQpEaW1QbG90KG1lcmdlZF9hbGxfY29ucywgcmVkdWN0aW9uID0gInRzbmUiKSsgZ2d0aXRsZSgidW5iaWFzZWQgY2x1c3RlcmluZyIpDQpgYGANCmBgYHtyfQ0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2dyb3VwaW5nJw0KRGltUGxvdChvYmpfYW5ub3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgc3BsaXQuYnkgPSAnY29uZGl0aW9uJykNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTl9DQpEaW1QbG90KG1lcmdlZF9hbGxfY29ucywgbGFiZWwgPSBULCByZXBlbCA9IFQsIHNwbGl0LmJ5ID0gJ2NvbmRpdGlvbicpICsgTm9MZWdlbmQoKQ0KYGBgDQoNCmBgYHtyfQ0KY2x1c3RlcnNfMC4xX3RhYmxlIDwtIHRhYmxlKG1lcmdlZF9hbGxfY29ucyRSTkFfc25uX3Jlcy4wLjEsIG1lcmdlZF9hbGxfY29ucyRzYW1wbGUpDQpjbHVzdGVyc18wLjFfdGFibGVfY29uZCA8LSB0YWJsZShtZXJnZWRfYWxsX2NvbnMkUk5BX3Nubl9yZXMuMC4xLCBtZXJnZWRfYWxsX2NvbnMkY29uZGl0aW9uKQ0KY2x1c3RlcnNfMC4xX3RhYmxlDQpjbHVzdGVyc18wLjFfdGFibGVfY29uZA0KYGBgDQpgYGB7cn0NCmNsdXN0ZXJzXzAuMDFfdGFibGUgPC0gdGFibGUobWVyZ2VkXzAuMDUkUk5BX3Nubl9yZXMuMC4wMSwgbWVyZ2VkXzAuMDUkc2FtcGxlKQ0KY2x1c3RlcnNfMC4wMV90YWJsZV9jb25kIDwtIHRhYmxlKG1lcmdlZF8wLjA1JFJOQV9zbm5fcmVzLjAuMDEsIG1lcmdlZF8wLjA1JGNvbmRpdGlvbikNCmNsdXN0ZXJzXzAuMDFfdGFibGUNCmNsdXN0ZXJzXzAuMDFfdGFibGVfY29uZA0KDQpjbHVzdGVyc18wLjAxX2RmIDwtIGFzLmRhdGEuZnJhbWUoY2x1c3RlcnNfMC4wMV90YWJsZSkNCmNsdXN0ZXJzXzAuMDFfZGYNCg0KY2x1c3RlcnNfMC4wMV9kZiRhbm5vdCA8LSBjKCJseW1waG9jeXRlIiwgIm15ZWxvaWQiLCAiUFQiLCAiQiBjZWxsIiwgIk5LIiwgIlBNTiIsICJUQUxfRGlzdGFsIHR1YnVsZSIsICJQVF9FTVRfRmlicm8iLCAiRENUIikNCg0KYGBgDQoNCg0KYGBge3J9DQptZXJnZWRfYWxsX2NvbnNAbWV0YS5kYXRhJGwxX2Fubm90YXRpb25zX3JlczAuMSA8LSANCiAgaWZlbHNlKA0KICAgIG1lcmdlZF9hbGxfY29uc0BtZXRhLmRhdGEkbDFfYW5ub3RhdGlvbnNfcmVzMC4xID09ICJGaWJyb2JsYXN0L1N0cm9tYSIsDQogICAgIkZpYnJvX1N0cm9tYWwiLA0KICAgIG1lcmdlZF9hbGxfY29uc0BtZXRhLmRhdGEkbDFfYW5ub3RhdGlvbnNfcmVzMC4xDQogICkNCmBgYA0KDQpgYGB7cn0NCklkZW50cyhtZXJnZWRfYWxsX2NvbnMpIDwtICdSTkFfc25uX3Jlcy4wLjgnDQoNCkRFXzAuOF8xMHYxOSA8LSBTZXVyYXRXcmFwcGVyczo6UnVuUHJlc3RvKG1lcmdlZF9hbGxfY29ucywgaWRlbnQuMSA9IDEwLCBpZGVudC4yID0gMTkpDQpnZW5lIDwtIHJvd25hbWVzKERFXzAuOF8xMHYxOSkNCkRFXzAuOF8xMHYxOSRnZW5lIDwtIGdlbmUNCg0KREVfMC44XzEwdjE5IDwtIERFXzAuOF8xMHYxOVtERV8wLjhfMTB2MTkkcF92YWxfYWRqIDwgMC4wNSxdDQpERV8wLjhfMTB2MTkgPC0gb3JkZXIoREVfMC44XzEwdjE5JGF2Z19sb2cyRkMsIGRlY3JlYXNpbmcgPSBUKSAgDQoNCg0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI2NvbXBhcmUgREUgZ2VuZSBleHByZXNzaW9uIGJldHdlZW4gVVRJL2NvbnRyb2xzIGluIGVhY2ggY2x1c3Rlcg0KI2RlZmluZWQgYXMgZGVnX2NvbnMgKGxpc3QpDQpjb2xuYW1lcyhtZXJnZWRfYWxsX2NvbnNAbWV0YS5kYXRhKQ0KDQptZXJnZWRfYWxsX2NvbnNAbWV0YS5kYXRhJGwxX2NvbmRpdGlvbiA8LSBwYXN0ZTAobWVyZ2VkX2FsbF9jb25zQG1ldGEuZGF0YSRsMV9hbm5vdGF0aW9uc19yZXMwLjEsIl8iLG1lcmdlZF9hbGxfY29ucyRjb25kaXRpb24pDQoNCklkZW50cyhtZXJnZWRfYWxsX2NvbnMpIDwtICdsMV9jb25kaXRpb24nDQp1bmlxdWUoSWRlbnRzKG1lcmdlZF9hbGxfY29ucykpDQoNCkRFZ19yZXNfMC4xX1VUSSA8LSAgbGlzdCgpDQoNCmZvcihpIGluIHVuaXF1ZShtZXJnZWRfYWxsX2NvbnMkbDFfYW5ub3RhdGlvbnNfcmVzMC4xKSl7DQogIGF1eCA8LSBTZXVyYXRXcmFwcGVyczo6UnVuUHJlc3RvKG1lcmdlZF9hbGxfY29ucyxpZGVudC4xID0gcGFzdGUwKGksIl9VVEkiKSwgaWRlbnQuMiA9IHBhc3RlMChpLCJfQ29udHJvbCIpKSAgDQogIGF1eCRnZW5lIDwtIHJvd25hbWVzKGF1eCkNCiAgREVnX3Jlc18wLjFfVVRJW1twYXN0ZTAoaSwiX1VUSSIpXV0gPC0gYXV4DQp9DQoNCiNGaWx0ZXIgZm9yIGVhc2llciBhbmFseXNpcw0KZm9yKGkgaW4gbmFtZXMoREVnX3Jlc18wLjFfVVRJKSl7DQogIGF1eCA8LSBERWdfcmVzXzAuMV9VVElbW2ldXQ0KICBhdXggPC0gYXV4W2F1eCRwX3ZhbF9hZGogPCAwLjA1LF0NCiAgYXV4IDwtIGF1eFtvcmRlcihhdXgkYXZnX2xvZzJGQywgZGVjcmVhc2luZz1UKSxdDQogIERFZ19yZXNfMC4xX1VUSVtbaV1dIDwtIGF1eA0KfQ0KYGBgDQoNCmBgYHtyfQ0KDQpuYW1lcyhERWdfcmVzXzAuMV9VVEkpW25hbWVzKERFZ19yZXNfMC4xX1VUSSkgJWluJSAiSUxDMi9NeWVsb2lkX1VUSSJdIDwtICJJTEMyX1VUSSINCg0KI2V4cG9ydCBhcyBleGNlbCBmaWxlDQpyaW86OmV4cG9ydChERWdfcmVzXzAuMV9VVEksICJyZXMgMC4xX0RFIGdlbmVzLnhsc3giKQ0KDQpgYGANCg0KI3NhdmUgUkRTIGFuZCBjcmVhdGUgbG91cGUNCmBgYHtyfQ0KDQpzYXZlUkRTKG1lcmdlZF9hbGxfY29ucywgIm1lcmdlZF9vYmouUkRTIikNCg0KYGBgDQoNCmBgYHtyfQ0Kc2F2ZS5pbWFnZSgicmVzIDAuNV9QQ0EgMjVfcGVyY2VudG10MTAuUkRhdGEiKQ0KDQpgYGANCg0KDQpgYGB7cn0NCnNldHdkKCJDOi9Vc2Vycy9ldnJhamFkaC9PbmVEcml2ZSAtIEluZGlhbmEgVW5pdmVyc2l0eS9SZXNlYXJjaC9SZWN1cnJlbnQgVVRJIEdGUi9TY1JOQS9SZWNfVVRJIikNCmNyZWF0ZV9sb3VwZV9mcm9tX3NldXJhdChtZXJnZWRfYWxsX2NvbnMsIG91dHB1dF9kaXIgPSAiY2xvdXBlcy8iLCBvdXRwdXRfbmFtZSA9ICJtYW51YWwgYW5ub3RfcmVzXzAuNSIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KI1NwbGl0IG9iamVjdCBieSBjb25kaXRpb24gYW5kIGFuYWx5emUgY29uZGl0aW9ucyBzZXBhcmF0ZWx5DQptZXJnZWRfc3BsaXQgPC0gU3BsaXRPYmplY3QobWVyZ2VkX2FsbF9jb25zLCBzcGxpdC5ieSA9ICJjb25kaXRpb24iKQ0KDQojZXZhbCBjb25zZXJ2ZWQgbWFya2VycyBieSBjb25kaXRpb24NCg0KbWVyZ2VkX3NwbGl0JFVUSQ0KDQptZXJnZWRfVVRJIDwtIG1lcmdlZF9zcGxpdCRVVEkNCg0KI0FkZCBtdWx0aXBsZSByZXNvbHV0aW9ucw0KbWVyZ2VkX1VUSSA8LSBSdW5QQ0EobWVyZ2VkX1VUSSwgbnBjcz0zMCkNCm1lcmdlZF9VVEkgPC0gRmluZE5laWdoYm9ycyhtZXJnZWRfVVRJLCBkaW1zID0gMToyMCwgdmVyYm9zZSA9IEYpDQptZXJnZWRfVVRJIDwtIEZpbmRDbHVzdGVycyhtZXJnZWRfVVRJLCByZXNvbHV0aW9uID0gYygwLjEsIDAuMiwgMC40LCAwLjYsIDAuOCkpDQoNCm1lcmdlZF9VVEkgPC0gUnVuVU1BUChtZXJnZWRfVVRJLCBkaW1zID0gMToyMCkNCg0KRGltUGxvdChtZXJnZWRfVVRJKQ0KDQpjbHVzdGVyLnRyZWVfVVRJIDwtIGNsdXN0cmVlKA0KICBtZXJnZWRfVVRJLCAiUk5BX3Nubl9yZXMuIikgKyBnZ3RpdGxlKCJDbHVzdGVyIHRyZWUiKQ0KDQpjbHVzdGVyLnRyZWVfVVRJDQojaGF2ZW4ndCByZW1vdmVkIGRvdWJsZXRzLCBvbmx5IHByZWxpbWluYXJ5DQoNCg0KDQpgYGANCmBgYHtyfQ0KSWRlbnRzDQpgYGANCg0KYGBge3J9DQpJZGVudHMobWVyZ2VkX1VUSSkgPC0gJ2wxX2Fubm90YXRpb25zX3JlczAuMScNCg0KREVnX1VUSV9MT1dfcmVzIDwtIGxpc3QoKQ0KZm9yKGkgaW4gdW5pcXVlKG1lcmdlZF8wLjA1JFJOQV9zbm5fcmVzLjAuMDEpKXsNCiAgYXV4IDwtIFNldXJhdFdyYXBwZXJzOjpSdW5QcmVzdG8obWVyZ2VkXzAuMDUsaWRlbnQuMSA9IHBhc3RlMChpLCJfVVRJIiksIGlkZW50LjIgPSBwYXN0ZTAoaSwiX0NvbnRyb2wiKSkgIA0KICBhdXgkZ2VuZSA8LSByb3duYW1lcyhhdXgpDQogIERFZ19VVElfTE9XX3Jlc1tbcGFzdGUwKGksIl9VVEkiKV1dIDwtIGF1eA0KfQ0KDQojRmlsdGVyIGZvciBlYXNpZXIgYW5hbHlzaXMNCmZvcihpIGluIG5hbWVzKERFZ19VVElfTE9XX3Jlcykpew0KICBhdXggPC0gREVnX1VUSV9MT1dfcmVzW1tpXV0NCiAgYXV4IDwtIGF1eFthdXgkcF92YWxfYWRqIDwgMC4wNSxdDQogIGF1eCA8LSBhdXhbb3JkZXIoYXV4JGF2Z19sb2cyRkMsIGRlY3JlYXNpbmc9VCksXQ0KICBERWdfVVRJX0xPV19yZXNbW2ldXSA8LSBhdXgNCn0NCg0KcmlvOjpleHBvcnQoREVnX1VUSV9MT1dfcmVzLCAiTE9XIHJlc29sdXRpb24gREVnZW5lc19VVEkueGxzeCIpDQoNCg0KYGBgDQoNCmBgYHtyfQ0KSWRlbnRzKG1lcmdlZF8wLjA1KSA8LSAnUk5BX3Nubl9yZXMuMC4wMScNCkRpbVBsb3QobWVyZ2VkXzAuMDUsIHJlZHVjdGlvbiA9ICJ0c25lIikNCmBgYA0KYGBge3J9DQpEaW1QbG90KG1lcmdlZF8wLjA1LCByZWR1Y3Rpb24gPSAicGNhIiwgbGFiZWwgPSBULCByZXBlbCA9IFQpDQpgYGANCmBgYHtyfQ0KSWRlbnRzKG1lcmdlZF8wLjA1KSA8LSAnbDFfYW5ub3RhdGlvbnNfcmVzMC4xJw0KRGltUGxvdChtZXJnZWRfMC4wNSwgcmVkdWN0aW9uID0gInRzbmUiLCBsYWJlbCA9IFQpDQpgYGANCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQ0KRGltUGxvdChtZXJnZWRfMC4wNSwgcmVkdWN0aW9uID0gInBjYSIsIGxhYmVsID0gVCkgKyBOb0xlZ2VuZCgpDQpgYGANCg0KYGBge3J9DQpvYmpfYW5ub3QgPC0gbWVyZ2VkX2FsbF9jb25zDQpgYGANCg0KDQpgYGB7cn0NCm9ial9hbm5vdCRncm91cGluZyA8LSBOQQ0KDQpvYmpfYW5ub3QkZ3JvdXBpbmdbb2JqX2Fubm90JFJOQV9zbm5fcmVzLjAuMSAlaW4lIGMoMSw1LDEwLDE1LDQsMyldIDwtICJMeW1waG9jeXRlIg0Kb2JqX2Fubm90JGdyb3VwaW5nW29ial9hbm5vdCRSTkFfc25uX3Jlcy4wLjEgJWluJSBjKDIsMTIsOSw2KV0gPC0gIk15ZWxvaWQiDQpvYmpfYW5ub3QkZ3JvdXBpbmdbb2JqX2Fubm90JFJOQV9zbm5fcmVzLjAuMSAlaW4lIGMoMCldIDwtICJQVCINCm9ial9hbm5vdCRncm91cGluZ1tvYmpfYW5ub3QkUk5BX3Nubl9yZXMuMC4xICVpbiUgYyg3KV0gPC0gIlBUX0VNVCINCm9ial9hbm5vdCRncm91cGluZ1tvYmpfYW5ub3QkUk5BX3Nubl9yZXMuMC4xICVpbiUgYygxNCwxMSw4LDEzKV0gPC0gIlRBTF9kaXN0YWwgdHVidWxlIg0KYGBgDQoNCmBgYHtyfQ0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2dyb3VwaW5nJw0KdW5pcXVlKElkZW50cyhvYmpfYW5ub3QpKQ0KYGBgDQoNCmBgYHtyfQ0KY29uc2VydmVkX2dlbmVzX2xvd3Jlc19ncm91cGluZyA8LSBsaXN0KCkNCklkZW50cyhvYmpfYW5ub3QpIDwtICdncm91cGluZycNCg0KIyBMb29wIHRocm91Z2ggdGhlIGNsdXN0ZXJzIGluIHRoZSBzcGVjaWZpZWQgb3JkZXINCmNvbnNlcnZlZF9nZW5lc19sb3dyZXNfZ3JvdXBpbmcgPC0gU2V1cmF0V3JhcHBlcnM6OlJ1blByZXN0b0FsbChvYmpfYW5ub3QsDQogICAgb25seS5wb3MgPSBUUlVFLA0KICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuNSwNCiAgICBtaW4ucGN0ID0gMC40KQ0KY29uc2VydmVkX2dlbmVzX2xvd3Jlc19ncm91cGluZyRnZW5lIDwtIHJvd25hbWVzKGNvbnNlcnZlZF9nZW5lc19sb3dyZXNfZ3JvdXBpbmcpDQoNCnJpbzo6ZXhwb3J0KGNvbnNlcnZlZF9nZW5lc19sb3dyZXNfZ3JvdXBpbmcsICJDbHVzdGVyX0dST1VQSU5HX2NvbnNlcnZlZCBnZW5lcy54bHN4IikNCiAgICANCmBgYA0KYGBge3J9DQpvYmpfYW5ub3QkZ3JvdXBfY29uZCA8LSBwYXN0ZTAob2JqX2Fubm90JGdyb3VwaW5nLCdfJyxvYmpfYW5ub3QkY29uZGl0aW9uKQ0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2dyb3VwX2NvbmQnDQoNCkRFZ19VVElfTE9XX3Jlc19hbm5vdCA8LSBsaXN0KCkNCmZvcihpIGluIHVuaXF1ZShvYmpfYW5ub3QkZ3JvdXBpbmcpKXsNCiAgYXV4IDwtIFNldXJhdFdyYXBwZXJzOjpSdW5QcmVzdG8ob2JqX2Fubm90LGlkZW50LjEgPSBwYXN0ZTAoaSwiX1VUSSIpLCBpZGVudC4yID0gcGFzdGUwKGksIl9Db250cm9sIikpICANCiAgYXV4JGdlbmUgPC0gcm93bmFtZXMoYXV4KQ0KICBERWdfVVRJX0xPV19yZXNfYW5ub3RbW3Bhc3RlMChpLCJfVVRJIildXSA8LSBhdXgNCn0NCg0KI0ZpbHRlciBmb3IgZWFzaWVyIGFuYWx5c2lzDQpmb3IoaSBpbiBuYW1lcyhERWdfVVRJX0xPV19yZXNfYW5ub3QpKXsNCiAgYXV4IDwtIERFZ19VVElfTE9XX3Jlc19hbm5vdFtbaV1dDQogIGF1eCA8LSBhdXhbYXV4JHBfdmFsX2FkaiA8IDAuMDUsXQ0KICBhdXggPC0gYXV4W29yZGVyKGF1eCRhdmdfbG9nMkZDLCBkZWNyZWFzaW5nPVQpLF0NCiAgREVnX1VUSV9MT1dfcmVzX2Fubm90W1tpXV0gPC0gYXV4DQp9DQoNCnJpbzo6ZXhwb3J0KERFZ19VVElfTE9XX3Jlc19hbm5vdCwgIkRFZ2VuZXMgY2x1c3Rlcl9HUk9VUElOR19VVEl2Q29udHJvbC54bHN4IikNCmBgYA0KDQoNCmBgYHtyfQ0KcmlvOjpleHBvcnQoREVnX1VUSV9MT1dfcmVzLCAiTE9XIHJlc29sdXRpb24gREVnZW5lc19VVEkueGxzeCIpDQoNCg0KYGBgDQoNCg0KDQoNCg0KTW9ub2NsaW5nDQoNCmBgYHtyfQ0KSWRlbnRzKG1lcmdlZF9hbGxfY29ucykgPC0gJ1JOQV9zbm5fcmVzLjAuMScNCnB0X2NlbGxzIDwtIHN1YnNldChtZXJnZWRfYWxsX2NvbnMsIGlkZW50cyA9IGMoJzAnLCAnNycpKQ0KbGlicmFyeShtb25vY2xlMykNCmBgYA0KYGBge3J9DQoNCmNkcyA8LSBTZXVyYXRXcmFwcGVyczo6YXMuY2VsbF9kYXRhX3NldChwdF9jZWxscykNCmNkcyA8LSBjbHVzdGVyX2NlbGxzKGNkcykNCmNkcyA8LSBsZWFybl9ncmFwaChjZHMpDQpgYGANCmBgYHtyfQ0KcGxvdF9jZWxscyhjZHMsIGNvbG9yX2NlbGxzX2J5ID0gImNsdXN0ZXIiLCBsYWJlbF9jZWxsX2dyb3VwcyA9IFQpDQpgYGANCg0KYGBge3J9DQpJZGVudHMob2JqX2Fubm90KSA8LSAnbDFfYW5ub3RhdGlvbnNfcmVzMC4xJw0KdW5pcXVlKElkZW50cyhvYmpfYW5ub3QpKQ0KDQpvYmpfYW5ub3QkbDFfYW5ub3RhdGlvbnNfcmVzMC4xW29ial9hbm5vdCRsMV9hbm5vdGF0aW9uc19yZXMwLjEgJWluJSAiRmlicm9fU3Ryb21hbCJdIDwtICJQVF9FTVQiDQpvYmpfYW5ub3QkbDFfYW5ub3RhdGlvbnNfcmVzMC4xW29ial9hbm5vdCRsMV9hbm5vdGF0aW9uc19yZXMwLjEgJWluJSAiSUxDMiJdIDwtICJJTEMiDQpvYmpfYW5ub3QkbDFfYW5ub3RhdGlvbnNfcmVzMC4xW29ial9hbm5vdCRsMV9hbm5vdGF0aW9uc19yZXMwLjEgJWluJSAiUG9kb2N5dGUiXSA8LSAiVEFMX0RDVCINCm9ial9hbm5vdCRsMV9hbm5vdGF0aW9uc19yZXMwLjFbb2JqX2Fubm90JGwxX2Fubm90YXRpb25zX3JlczAuMSAlaW4lICJwREMiXSA8LSAiREMiDQoNCmBgYA0KYGBge3J9DQpjZHMgPC0gU2V1cmF0V3JhcHBlcnM6OmFzLmNlbGxfZGF0YV9zZXQob2JqX2Fubm90KQ0KY2RzIDwtIGNsdXN0ZXJfY2VsbHMoY2RzKQ0KY2RzIDwtIGxlYXJuX2dyYXBoKGNkcykNCmBgYA0KDQoNCmBgYHtyfQ0KIyBQbG90IHRvIGNob29zZSByb290IG5vZGUgdmlzdWFsbHkNCnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVyIiwgbGFiZWxfY2VsbF9ncm91cHMgPSBULCBsYWJlbF9yb290cyA9IFQpIA0KDQpgYGANCmBgYHtyfQ0KDQpnZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUgPC0gZnVuY3Rpb24oY2RzKSB7DQogIHByX2dyYXBoX3Rlc3QgPC0gcHJpbmNpcGFsX2dyYXBoKGNkcylbWzFdXQ0KICBuYW1lcyh3aGljaC5taW4oaWdyYXBoOjpkZWdyZWUocHJfZ3JhcGhfdGVzdCkpKQ0KfQ0KDQojIE9uY2UgeW91IGlkZW50aWZ5IHRoZSByb290IGNlbGwvY2x1c3RlcjoNCmNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfcHJfbm9kZXMgPSBnZXRfZWFybGllc3RfcHJpbmNpcGFsX25vZGUoY2RzKSkNCmBgYA0KDQpgYGB7cn0NCnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIiwgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSkNCg0KYGBgDQpgYGB7cn0NCkRpbVBsb3Qob2JqX2Fubm90KQ0KYGBgDQoNCmBgYHtyfQ0KQmlvY01hbmFnZXI6Omluc3RhbGwoInNsaW5nc2hvdCIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNsaW5nc2hvdCkNCg0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2wxX2Fubm90YXRpb25zX3JlczAuMScNCkRpbVBsb3Qob2JqX2Fubm90LCByZWR1Y3Rpb24gPSAndHNuZScpICsgRGltUGxvdChvYmpfYW5ub3QsIHJlZHVjdGlvbiA9ICdwY2EnKQ0KDQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQob2JqX2Fubm90KQ0Kc2NlIDwtIHNsaW5nc2hvdChzY2UsIGNsdXN0ZXJMYWJlbHMgPSBvYmpfYW5ub3QkbDFfYW5ub3RhdGlvbnNfcmVzMC4xLCByZWR1Y2VkRGltID0gJ1VNQVAnKQ0KYGBgDQojUHNldWRvdGltZSBhbmFseXNpcyB3aXRoIHNsaW5nc2hvdA0KYGBge3J9DQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQob2JqX2Fubm90KQ0Kc2NlIDwtIHNsaW5nc2hvdDo6c2xpbmdzaG90KHNjZSwgY2x1c3RlckxhYmVscyA9IHNjZSRsMV9hbm5vdGF0aW9uc19yZXMwLjEsIHJlZHVjZWREaW0gPSAnVU1BUCcpDQoNCmBgYA0KDQpgYGB7cn0NCiNwbG90IHBzZXVkb3RpbWUNCmxpYnJhcnkoc2NhdGVyKQ0KDQpwbG90KHJlZHVjZWREaW0oc2NlLCAiVU1BUCIpLCBjb2wgPSBzY2Ukc2xpbmdQc2V1ZG90aW1lXzEgLCBwY2ggPSAxNikNCmBgYA0KDQpgYGB7cn0NCnBsb3QocmVkdWNlZERpbShzY2UsICJUU05FIiksIGNvbCA9IHNjZSRzbGluZ1BzZXVkb3RpbWVfMSAsIHBjaCA9IDE2KQ0KYGBgDQoNCmBgYHtyfQ0KDQpwbG90KHJlZHVjZWREaW0oc2NlLCAiVU1BUCIpLCBjb2wgPSBzY2Ukc2xpbmdQc2V1ZG90aW1lXzEgLCBwY2ggPSAxNikNCg0KY2x1c3RlcnMgPC0gc2NlJGwxX2Fubm90YXRpb25zX3JlczAuMQ0KY2VudGVycyA8LSB0KHNhcHBseSh1bmlxdWUoY2x1c3RlcnMpLGZ1bmN0aW9uKGNsKXsNCiAgY29sTWVhbnMocmVkdWNlZERpbShzY2UsICJVTUFQIilbY2x1c3RlcnMgPT0gY2wsXSkNCn0pKQ0KdGV4dChjZW50ZXJzLCBsYWJlbHMgPSB1bmlxdWUoY2x1c3RlcnMpLGNvbCA9ICJibGFjayIsIGNleCA9IDAuOCkNCmBgYA0KDQpgYGB7cn0NCnNjZSA8LSBhcy5TaW5nbGVDZWxsRXhwZXJpbWVudChwdF9jZWxscykNCnNjZSA8LSBzbGluZ3Nob3Q6OnNsaW5nc2hvdChzY2UsIGNsdXN0ZXJMYWJlbHMgPSBzY2UkbDFfYW5ub3RhdGlvbnNfcmVzMC4xLCByZWR1Y2VkRGltID0gJ1VNQVAnKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChyZWR1Y2VkRGltKHNjZSwgIlVNQVAiKSwgY29sID0gc2NlJHNsaW5nUHNldWRvdGltZV8xICwgcGNoID0gMTApDQoNCmNsdXN0ZXJzIDwtIHNjZSRsMV9hbm5vdGF0aW9uc19yZXMwLjENCmNlbnRlcnMgPC0gdChzYXBwbHkodW5pcXVlKGNsdXN0ZXJzKSxmdW5jdGlvbihjbCl7DQogIGNvbE1lYW5zKHJlZHVjZWREaW0oc2NlLCAiVU1BUCIpW2NsdXN0ZXJzID09IGNsLF0pDQp9KSkNCnRleHQoY2VudGVycywgbGFiZWxzID0gdW5pcXVlKGNsdXN0ZXJzKSxjb2wgPSAiYmxhY2siLCBjZXggPSAwLjgpDQpgYGANCg0KYGBge3J9DQojRm9yIGp1c3QgUFQgY2VsbHMgYW5kIFBUX0VNVA0KDQojIEV4dHJhY3QgZGF0YSBmcm9tIFNpbmdsZUNlbGxFeHBlcmltZW50DQp1bWFwX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVkdWNlZERpbShzY2UsICJVTUFQIikpDQpjb2xuYW1lcyh1bWFwX2RmKSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikgICMgUmVuYW1lIHRvIHJlYWRhYmxlIG5hbWVzDQp1bWFwX2RmJGNsdXN0ZXIgPC0gc2NlJGwxX2Fubm90YXRpb25zX3JlczAuMQ0KdW1hcF9kZiRwc2V1ZG90aW1lIDwtIHNjZSRzbGluZ1BzZXVkb3RpbWVfMQ0KDQoNCiMgQ2FsY3VsYXRlIGNsdXN0ZXIgY2VudHJvaWRzIGZvciBsYWJlbGluZw0KbGFiZWxfZGYgPC0gdW1hcF9kZiAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcml6ZShVTUFQXzEgPSBtZWFuKFVNQVBfMSksIFVNQVBfMiA9IG1lYW4oVU1BUF8yKSkNCg0KDQojIFBsb3Qgd2l0aCBnZ3Bsb3QyDQpnZ3Bsb3QodW1hcF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gcHNldWRvdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYWJlbF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGxhYmVsID0gY2x1c3RlciksIA0KICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiLCB0aXRsZSA9ICJTbGluZ3Nob3QgUHNldWRvdGltZSBbUFQgQ2VsbHNdIHdpdGggQ2x1c3RlciBMYWJlbHMiKQ0KDQoNCmBgYA0KYGBge3J9DQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQob2JqX2Fubm90KQ0Kc2NlIDwtIHNsaW5nc2hvdDo6c2xpbmdzaG90KHNjZSwgY2x1c3RlckxhYmVscyA9IHNjZSRSTkFfc25uX3Jlcy4wLjQsIHJlZHVjZWREaW0gPSAnVU1BUCcpDQpgYGANCg0KYGBge3J9DQojRm9yIGp1c3QgUFQgY2VsbHMgYW5kIFBUX0VNVA0KDQojIEV4dHJhY3QgZGF0YSBmcm9tIFNpbmdsZUNlbGxFeHBlcmltZW50DQp1bWFwX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVkdWNlZERpbShzY2UsICJVTUFQIikpDQpjb2xuYW1lcyh1bWFwX2RmKSA8LSBjKCJVTUFQXzEiLCAiVU1BUF8yIikgICMgUmVuYW1lIHRvIHJlYWRhYmxlIG5hbWVzDQp1bWFwX2RmJGNsdXN0ZXIgPC0gc2NlJGwxX2Fubm90YXRpb25zX3JlczAuMQ0KdW1hcF9kZiRwc2V1ZG90aW1lIDwtIHNjZSRzbGluZ1BzZXVkb3RpbWVfMQ0KDQoNCiMgQ2FsY3VsYXRlIGNsdXN0ZXIgY2VudHJvaWRzIGZvciBsYWJlbGluZw0KbGFiZWxfZGYgPC0gdW1hcF9kZiAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcml6ZShVTUFQXzEgPSBtZWFuKFVNQVBfMSksIFVNQVBfMiA9IG1lYW4oVU1BUF8yKSkNCg0KDQojIFBsb3Qgd2l0aCBnZ3Bsb3QyDQpnZ3Bsb3QodW1hcF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG9yID0gcHNldWRvdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYWJlbF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGxhYmVsID0gY2x1c3RlciksIA0KICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiLCB0aXRsZSA9ICJTbGluZ3Nob3QgUHNldWRvdGltZSBbUFQgQ2VsbHNdIHdpdGggQ2x1c3RlciBMYWJlbHMiKQ0KDQpgYGANCg0KYGBge3J9DQpJZGVudHMob2JqX2Fubm90KSA8LSAnZ3JvdXBpbmcnDQp1bmlxdWUoSWRlbnRzKG9ial9hbm5vdCkpDQoNCiNhbHJlYWR5IHN1YnNldHRlZCBQVCBhbmQgUFRfRU1UIHRvIHB0X2NlbGxzDQpteWVsb2lkX2NlbGxzIDwtIHN1YnNldChvYmpfYW5ub3QsIGlkZW50cyA9ICJNeWVsb2lkIikNCmx5bXBob19jZWxscyA8LSBzdWJzZXQob2JqX2Fubm90LCBpZGVudHMgPSAiTHltcGhvY3l0ZSIpDQpUQUxfRENUX2NlbGxzIDwtIHN1YnNldChvYmpfYW5ub3QsIGlkZW50cyA9ICJUQUxfZGlzdGFsIHR1YnVsZSIpDQoNCmBgYA0KDQojbXllbG9pZCBzbGluZ3Nob3QgVFNORQ0KDQpgYGB7cn0NCnNjZV9teWVsb2lkIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KG15ZWxvaWRfY2VsbHMpDQpzY2VfbXllbG9pZCA8LSBzbGluZ3Nob3Q6OnNsaW5nc2hvdChzY2VfbXllbG9pZCwgY2x1c3RlckxhYmVscyA9IHNjZV9teWVsb2lkJFJOQV9zbm5fcmVzLjAuNCwgcmVkdWNlZERpbSA9ICdUU05FJykNCmBgYA0KDQpgYGB7cn0NCiNGb3IganVzdCBQVCBjZWxscyBhbmQgUFRfRU1UDQoNCiMgRXh0cmFjdCBkYXRhIGZyb20gU2luZ2xlQ2VsbEV4cGVyaW1lbnQNCnVtYXBfbXllbG9pZF9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlX215ZWxvaWQsICJUU05FIikpDQpjb2xuYW1lcyh1bWFwX215ZWxvaWRfZGYpIDwtIGMoIlRTTkVfMSIsICJUU05FXzIiKSAgIyBSZW5hbWUgdG8gcmVhZGFibGUgbmFtZXMNCnVtYXBfbXllbG9pZF9kZiRjbHVzdGVyIDwtIHNjZV9teWVsb2lkJGwxX2Fubm90YXRpb25zX3JlczAuMQ0KdW1hcF9teWVsb2lkX2RmJHBzZXVkb3RpbWUgPC0gc2NlX215ZWxvaWQkc2xpbmdQc2V1ZG90aW1lXzENCg0KDQojIENhbGN1bGF0ZSBjbHVzdGVyIGNlbnRyb2lkcyBmb3IgbGFiZWxpbmcNCmxhYmVsX215ZWxvaWRfZGYgPC0gdW1hcF9teWVsb2lkX2RmICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXplKFRTTkVfMSA9IG1lYW4oVFNORV8xKSwgVFNORV8yID0gbWVhbihUU05FXzIpKQ0KDQoNCiMgUGxvdCB3aXRoIGdncGxvdDINCmdncGxvdCh1bWFwX215ZWxvaWRfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yLCBjb2xvciA9IHBzZXVkb3RpbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArDQogIGdlb21fdGV4dChkYXRhID0gbGFiZWxfbXllbG9pZF9kZiwgYWVzKHggPSBUU05FXzEsIHkgPSBUU05FXzIsIGxhYmVsID0gY2x1c3RlciksIA0KICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiVFNORTEiLCB5ID0gIlRTTkUgMiIsIHRpdGxlID0gIlNsaW5nc2hvdCBQc2V1ZG90aW1lIFtNeWVsb2lkIENlbGxzXSB3aXRoIENsdXN0ZXIgTGFiZWxzIikNCg0KYGBgDQoNCiNteWVsb2lkIHNsaW5nc2hvdCBVTUFQDQpgYGB7cn0NCnNjZV9teWVsb2lkIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KG15ZWxvaWRfY2VsbHMpDQpzY2VfbXllbG9pZCA8LSBzbGluZ3Nob3Q6OnNsaW5nc2hvdChzY2VfbXllbG9pZCwgY2x1c3RlckxhYmVscyA9IHNjZV9teWVsb2lkJFJOQV9zbm5fcmVzLjAuNCwgcmVkdWNlZERpbSA9ICdVTUFQJykNCmBgYA0KDQpgYGB7cn0NCiNGb3IganVzdCBQVCBjZWxscyBhbmQgUFRfRU1UDQoNCiMgRXh0cmFjdCBkYXRhIGZyb20gU2luZ2xlQ2VsbEV4cGVyaW1lbnQNCnVtYXBfbXllbG9pZF9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlX215ZWxvaWQsICJVTUFQIikpDQpjb2xuYW1lcyh1bWFwX215ZWxvaWRfZGYpIDwtIGMoIlVNQVBfMSIsICJVTUFQXzIiKSAgIyBSZW5hbWUgdG8gcmVhZGFibGUgbmFtZXMNCnVtYXBfbXllbG9pZF9kZiRjbHVzdGVyIDwtIHNjZV9teWVsb2lkJGwxX2Fubm90YXRpb25zX3JlczAuMQ0KdW1hcF9teWVsb2lkX2RmJHBzZXVkb3RpbWUgPC0gc2NlX215ZWxvaWQkc2xpbmdQc2V1ZG90aW1lXzENCg0KDQojIENhbGN1bGF0ZSBjbHVzdGVyIGNlbnRyb2lkcyBmb3IgbGFiZWxpbmcNCmxhYmVsX215ZWxvaWRfZGYgPC0gdW1hcF9teWVsb2lkX2RmICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXplKFVNQVBfMSA9IG1lYW4oVU1BUF8xKSwgVU1BUF8yID0gbWVhbihVTUFQXzIpKQ0KDQoNCiMgUGxvdCB3aXRoIGdncGxvdDINCmdncGxvdCh1bWFwX215ZWxvaWRfZGYsIGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvciA9IHBzZXVkb3RpbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArDQogIGdlb21fdGV4dChkYXRhID0gbGFiZWxfbXllbG9pZF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGxhYmVsID0gY2x1c3RlciksIA0KICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiLCB0aXRsZSA9ICJTbGluZ3Nob3QgUHNldWRvdGltZSBbUFQgQ2VsbHNdIHdpdGggQ2x1c3RlciBMYWJlbHMiKQ0KDQpgYGANCg0KI2x5bXBobyBzbGluZ3Nob3QNCmBgYHtyfQ0Kc2NlX2x5bXBoIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KGx5bXBob19jZWxscykNCnNjZV9seW1waCA8LSBzbGluZ3Nob3Q6OnNsaW5nc2hvdChzY2VfbHltcGgsIGNsdXN0ZXJMYWJlbHMgPSBzY2VfbHltcGgkUk5BX3Nubl9yZXMuMC40LCByZWR1Y2VkRGltID0gJ1RTTkUnKQ0KYGBgDQoNCmBgYHtyfQ0KI0ZvciBqdXN0IFBUIGNlbGxzIGFuZCBQVF9FTVQNCg0KIyBFeHRyYWN0IGRhdGEgZnJvbSBTaW5nbGVDZWxsRXhwZXJpbWVudA0KdW1hcF9seW1waF9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlX2x5bXBoLCAiVFNORSIpKQ0KY29sbmFtZXModW1hcF9seW1waF9kZikgPC0gYygiVFNORV8xIiwgIlRTTkVfMiIpICAjIFJlbmFtZSB0byByZWFkYWJsZSBuYW1lcw0KdW1hcF9seW1waF9kZiRjbHVzdGVyIDwtIHNjZV9seW1waCRsMV9hbm5vdGF0aW9uc19yZXMwLjENCnVtYXBfbHltcGhfZGYkcHNldWRvdGltZSA8LSBzY2VfbHltcGgkc2xpbmdQc2V1ZG90aW1lXzENCg0KDQojIENhbGN1bGF0ZSBjbHVzdGVyIGNlbnRyb2lkcyBmb3IgbGFiZWxpbmcNCmxhYmVsX2x5bXBoX2RmIDwtIHVtYXBfbHltcGhfZGYgJT4lDQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICBzdW1tYXJpemUoVFNORV8xID0gbWVhbihUU05FXzEpLCBUU05FXzIgPSBtZWFuKFRTTkVfMikpDQoNCg0KIyBQbG90IHdpdGggZ2dwbG90Mg0KZ2dwbG90KHVtYXBfbHltcGhfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yLCBjb2xvciA9IHBzZXVkb3RpbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArDQogIGdlb21fdGV4dChkYXRhID0gbGFiZWxfbHltcGhfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yLCBsYWJlbCA9IGNsdXN0ZXIpLCANCiAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDQpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh4ID0gIlRTTkUxIiwgeSA9ICJUU05FIDIiLCB0aXRsZSA9ICJTbGluZ3Nob3QgUHNldWRvdGltZSBbUFQgQ2VsbHNdIHdpdGggQ2x1c3RlciBMYWJlbHMiKQ0KDQpgYGANCiNUQUxfRENUIGNlbGwgc2xpbmdzaG90DQpgYGB7cn0NCnNjZV90dWIgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQoVEFMX0RDVF9jZWxscykNCnNjZV90dWIgPC0gc2xpbmdzaG90OjpzbGluZ3Nob3Qoc2NlX3R1YiwgY2x1c3RlckxhYmVscyA9IHNjZV90dWIkUk5BX3Nubl9yZXMuMC40LCByZWR1Y2VkRGltID0gJ1RTTkUnKQ0KYGBgDQoNCmBgYHtyfQ0KDQojIEV4dHJhY3QgZGF0YSBmcm9tIFNpbmdsZUNlbGxFeHBlcmltZW50DQp0dWJfZGYgPC0gYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNjZV90dWIsICJUU05FIikpDQpjb2xuYW1lcyh0dWJfZGYpIDwtIGMoIlRTTkVfMSIsICJUU05FXzIiKSAgIyBSZW5hbWUgdG8gcmVhZGFibGUgbmFtZXMNCnR1Yl9kZiRjbHVzdGVyIDwtIHNjZV90dWIkbDFfYW5ub3RhdGlvbnNfcmVzMC4xDQp0dWJfZGYkcHNldWRvdGltZSA8LSBzY2VfdHViJHNsaW5nUHNldWRvdGltZV8xDQoNCg0KIyBDYWxjdWxhdGUgY2x1c3RlciBjZW50cm9pZHMgZm9yIGxhYmVsaW5nDQpsYWJlbF90dWJfZGYgPC0gdHViX2RmICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXplKFRTTkVfMSA9IG1lYW4oVFNORV8xKSwgVFNORV8yID0gbWVhbihUU05FXzIpKQ0KDQoNCiMgUGxvdCB3aXRoIGdncGxvdDINCmdncGxvdCh0dWJfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yLCBjb2xvciA9IHBzZXVkb3RpbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDAuNSkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArDQogIGdlb21fdGV4dChkYXRhID0gbGFiZWxfdHViX2RmLCBhZXMoeCA9IFRTTkVfMSwgeSA9IFRTTkVfMiwgbGFiZWwgPSBjbHVzdGVyKSwgDQogICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoeCA9ICJUU05FMSIsIHkgPSAiVFNORSAyIiwgdGl0bGUgPSAiU2xpbmdzaG90IFBzZXVkb3RpbWUgW1BUIENlbGxzXSB3aXRoIENsdXN0ZXIgTGFiZWxzIikNCg0KYGBgDQoNCmBgYHtyfQ0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ1JOQV9zbm5fcmVzLjAuMScNCkRpbVBsb3Qob2JqX2Fubm90LCByZWR1Y3Rpb24gPSAidHNuZSIsIGxhYmVsID0gVCxyZXBlbD1ULCAgbGFiZWwuc2l6ZSA9IDUpICsgZ2d0aXRsZSgiMC4xIHJlc29sdXRpb24gY2x1c3RlcmluZyIpDQpgYGANCg0KDQpgYGB7cn0NCm9ial9hbm5vdCA8LSByZWFkUkRTKCJDOi9Vc2Vycy9ldnJhamFkaC9PbmVEcml2ZSAtIEluZGlhbmEgVW5pdmVyc2l0eS9SZXNlYXJjaC9SZWN1cnJlbnQgVVRJIEdGUi9TY1JOQS9SZWNfVVRJL3JlcyAwLjVfUENBIDI1XzctMjkvYW5ub3RhdGlvbiBvYmplY3QuUkRTIikNCg0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2wxX2Fubm90YXRpb25zX3JlczAuMScNCkRpbVBsb3Qob2JqX2Fubm90LCByZWR1Y3Rpb24gPSAidHNuZSIsIGxhYmVsID0gVCxyZXBlbD1ULCAgbGFiZWwuc2l6ZSA9IDUpDQpgYGANCmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQ0KSWRlbnRzKG9ial9hbm5vdCkgPC0gJ2dyb3VwaW5nJw0KRGltUGxvdChvYmpfYW5ub3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgbGFiZWwgPSBULCBsYWJlbC5zaXplID0gNCwgcHQuc2l6ZSA9IDAuMSkgKyBOb0xlZ2VuZCgpICsgZ2d0aXRsZSgnQ2x1c3RlcnMnKQ0KYGBgDQpgYGB7cn0NCklkZW50cyhvYmpfYW5ub3QpIDwtICdncm91cGluZycNCkRvSGVhdG1hcChvYmpfYW5ub3QsIGZlYXR1cmVzID0gYygiTnJlcCIsICJNYXAzazdjbCIsICJBbmdwdGw3IiwgIkhkYyIsICJTbGM2YTE4IiwgIlRtaWdkMSIsICJTbGMyMmExMiIsICJTbGMyMmE2IiksIGNlbGxzID0gIlBUIikNCmBgYA0KYGBge3IsIGZpZy5oZWlnaHQ9MTJ9DQpWbG5QbG90KG9ial9hbm5vdCwgZmVhdHVyZXMgPSBjKCJOcmVwIiwgIk1hcDNrN2NsIiwgIkFuZ3B0bDciLCAiSGRjIiwgIlNsYzZhMTgiLCAiVG1pZ2QxIiwgIlNsYzIyYTEyIiwgIlNsYzIyYTYiKSwgcmFzdGVyID0gRiwgc3BsaXQuYnkgPSAnY29uZGl0aW9uJykNCmBgYA0KYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTN9DQpGZWF0dXJlUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gIk5yZXAiLCByZWR1Y3Rpb24gPSAidHNuZSIsIHNwbGl0LmJ5ID0gJ2NvbmRpdGlvbicsIHB0LnNpemUgPSAwLjgpDQpGZWF0dXJlUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gIk1hcDNrN2NsIiwgcmVkdWN0aW9uID0gInRzbmUiLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nLCBwdC5zaXplID0gMC44KQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD00fQ0KVmxuUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gIk5yZXAiLCByYXN0ZXIgPSBGLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nKQ0KVmxuUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gIk1hcDNrN2NsIiwgcmFzdGVyID0gRiwgc3BsaXQuYnkgPSAnY29uZGl0aW9uJykNClZsblBsb3Qob2JqX2Fubm90LCBmZWF0dXJlcyA9ICJCMm0iLCByYXN0ZXIgPSBGLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nKQ0KYGBgDQpgYGB7cn0NCmZlYXRfc2NDS0RhdGxhcyA8LSBjKCJDZDc5YSIsICJDZDNkIiwgIlByZjEiLCAiQ3BhMyIsICJGb2xyMiIsICJTZW1hM2ciLCAiU29zdCIsICJQcm94MSIsICJWY2FtMSIsICJQbHZhcCIsICJSZXJnbCIsICJDb3g0bDIiLCAiRGNuIiwgIlBvc3RuIiwgIlNsYzIyYTYiLCAiUHJ1bmUyIiwgIk5vczEiLCAiVW1vZCIsICJDYWxiMSIsICJTbGM0YTEiLCAiVXBrM2IiLCAiV3QxIiwgIkdmcjNhIikNCg0KRG9IZWF0bWFwKG9ial9hbm5vdCwgZmVhdHVyZXMgPSBjKCJDcnlhYiIsICJTZW1hNWEiLCAiUGRnZnJiIiwgIkRjZGMyYSIsICJDcCIsICJOa2c3IiwgIlhjcjEiLCAiUzEwMGE5IiwgIkxycDIiLCAiU2xjMTJhMSIsICJTbGMxMmEzIikpDQpgYGANCmBgYHtyLCBmaWcuaGVpZ2h0PTIyfQ0KRmVhdHVyZVBsb3Qob2JqX2Fubm90LCBmZWF0dXJlcyA9IGMoIkNyeWFiIiwgIlNlbWE1YSIsICJQZGdmcmIiLCAiRGNkYzJhIiwgIkNwIiwgIk5rZzciLCAiWGNyMSIsICJTMTAwYTkiLCAiTHJwMiIsICJTbGMxMmExIiwgIlNsYzEyYTMiKSwgcmVkdWN0aW9uID0gInRzbmUiLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nLCBwdC5zaXplID0gMC44KQ0KVmxuUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gYygiQ3J5YWIiLCAiU2VtYTVhIiwgIlBkZ2ZyYiIsICJEY2RjMmEiLCAiQ3AiLCAiTmtnNyIsICJYY3IxIiwgIlMxMDBhOSIsICJMcnAyIiwgIlNsYzEyYTEiLCAiU2xjMTJhMyIpLCByYXN0ZXIgPSBGLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nKQ0KYGBgDQpgYGB7ciwgZmlnLmhlaWdodD0yNX0NCg0KZmVhdF9QVGluanVyeSA8LSBjKCJTbGM1YTEyIiwgIlNsYzM0YTEiLCAiU2xjMjJhMzAiLCAiQ29sMjdhMSIsICJQbGluMiIsICJZcGVsMiIsICJCY2F0MSIsICJTbGM3YTEyIiwgIkhzcDkwYWExIiwgIlRvcDJhIiwgIktjbmlwNCIsICJWY2FtMSIsICJIYXZjcjEiKQ0KI0hlYWx0aHk6IFNsYzVhMTIsIDQ1YTEsIDIyYTMwLCA3YTEzDQojdHlwZSAxIGluanVyZWQgUzEvMjogQ29sMjdhMSwgUGxpbjINCiNUeXBlIDEgaW5qdXJlZCBTMzogUGxpbjIsIEhhdmNyMQ0KI3R5cGUyIGluanVyZWQgUzEvMjogWXBlbDINCiNUeXBlMiBpbmp1cmVkIFMzOiB5cGVsMiwgQmNhdDEsIFNsYzdhMTINCiNhY3V0ZSBpbmp1cnk6IEhzcDkwYWExDQojUmVwYWlyaW5nOiBUb3AyYQ0KI0ZhaWxlZCByZXBhaXI6IFlwZWwyLCBLY25pcDQsVmNhbTEsIEhhdmNyMQ0KDQpGZWF0dXJlUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gZmVhdF9QVGluanVyeSwgcmVkdWN0aW9uID0gInRzbmUiLCBzcGxpdC5ieSA9ICdjb25kaXRpb24nLCBwdC5zaXplID0gMC44KQ0KVmxuUGxvdChvYmpfYW5ub3QsIGZlYXR1cmVzID0gZmVhdF9QVGluanVyeSwgcmFzdGVyID0gRiwgc3BsaXQuYnkgPSAnY29uZGl0aW9uJykNCg0KYGBgDQoNCg0KYGBge3J9DQojc2VlIHdoaWNoIFBUIGNsdXN0ZXJzIGFyZSB3aGVyZSBvbiB0c25lIChjbHVzdGVycyA1LDksIGFuZCAxMSBvbiByZXMwLjUpDQpJZGVudHMob2JqX2Fubm90KSA8LSAnUk5BX3Nubl9yZXMuMC41Jw0KRGltUGxvdChvYmpfYW5ub3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgbGFiZWwgPSBUKQ0KYGBgDQoNCg0KYGBge3J9DQpzY2UgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQocHRfY2VsbHMpDQpzY2UgPC0gc2xpbmdzaG90KHNjZSwgY2x1c3RlckxhYmVscyA9IHNjZSRsMV9jb24sIHJlZHVjZWREaW0gPSAiVFNORSIpDQpjdXJ2ZXMgPC0gc2xpbmdDdXJ2ZXMoc2NlKQ0KYGBgDQoNCmBgYHtyfQ0KDQogIA0KICBkZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlLCAiVFNORSIpKQ0KY29sbmFtZXMoZGYpIDwtIGMoIlRTTkVfMSIsICJUU05FXzIiKQ0KZGYkcHNldWRvdGltZSA8LSBzY2Ukc2xpbmdQc2V1ZG90aW1lXzENCmRmJGNsdXN0ZXIgPC0gc2NlJGwxX2Fubm90YXRpb25zX3JlczAuMSANCg0KICBwIDwtIGdncGxvdChkZiwgYWVzKHggPSBUU05FXzEsIHkgPSBUU05FXzIsIGNvbG9yID0gcHNldWRvdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsNCiAgdGhlbWVfbWluaW1hbCgpDQogIA0KICBmb3IgKGkgaW4gc2VxX2Fsb25nKGN1cnZlcykpIHsNCiAgY3VydmVfZGYgPC0gYXMuZGF0YS5mcmFtZShjdXJ2ZXNbW2ldXSRzKQ0KICBjb2xuYW1lcyhjdXJ2ZV9kZikgPC0gYygiVFNORV8xIiwgIlRTTkVfMiIpDQogIA0KICAjIEFkZCBhcnJvd3MgYWxvbmcgdGhlIGN1cnZlDQogIHAgPC0gcCArIGdlb21fcGF0aChkYXRhID0gY3VydmVfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yKSwNCiAgICAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3codHlwZSA9ICJvcGVuIiwgbGVuZ3RoID0gdW5pdCgwLjE1LCAiaW5jaGVzIikpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC44KQ0KICB9DQogIA0KICBwDQpgYGANCiNQVCBjZWxscyBhbHNvIHdpdGggY29uZGl0aW9uIHNlcGFyYXRpb24NCmBgYHtyfQ0Kc2NlIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KHB0X2NlbGxzKQ0Kc2NlIDwtIHNsaW5nc2hvdChzY2UsIGNsdXN0ZXJMYWJlbHMgPSBzY2UkbDFfY29uZGl0aW9uLCByZWR1Y2VkRGltID0gIlRTTkUiKQ0KY3VydmVzIDwtIHNsaW5nQ3VydmVzKHNjZSkNCmBgYA0KDQpgYGB7cn0NCg0KICANCiAgZGYgPC0gYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNjZSwgIlRTTkUiKSkNCmNvbG5hbWVzKGRmKSA8LSBjKCJUU05FXzEiLCAiVFNORV8yIikNCmRmJHBzZXVkb3RpbWUgPC0gc2NlJHNsaW5nUHNldWRvdGltZV8xDQpkZiRjbHVzdGVyIDwtIHNjZSRsMV9jb25kaXRpb24NCg0KICBwIDwtIGdncGxvdChkZiwgYWVzKHggPSBUU05FXzEsIHkgPSBUU05FXzIsIGNvbG9yID0gcHNldWRvdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsNCiAgdGhlbWVfbWluaW1hbCgpDQogIA0KICBmb3IgKGkgaW4gc2VxX2Fsb25nKGN1cnZlcykpIHsNCiAgY3VydmVfZGYgPC0gYXMuZGF0YS5mcmFtZShjdXJ2ZXNbW2ldXSRzKQ0KICBjb2xuYW1lcyhjdXJ2ZV9kZikgPC0gYygiVFNORV8xIiwgIlRTTkVfMiIpDQogIA0KICAjIEFkZCBhcnJvd3MgYWxvbmcgdGhlIGN1cnZlDQogIHAgPC0gcCArIGdlb21fcGF0aChkYXRhID0gY3VydmVfZGYsIGFlcyh4ID0gVFNORV8xLCB5ID0gVFNORV8yKSwNCiAgICAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3codHlwZSA9ICJvcGVuIiwgbGVuZ3RoID0gdW5pdCgwLjE1LCAiaW5jaGVzIikpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC44KQ0KICB9DQogIA0KICBwDQpgYGANCg0KDQoNCmBgYHtyfQ0Kc2F2ZVJEUyhvYmpfYW5ub3QsICJhbm5vdGF0aW9uIG9iamVjdC5SRFMiKQ0KYGBgDQoNCg0KYGBge3J9DQp1bmlxdWUobWVyZ2VkX2FsbF9jb25zQG1ldGEuZGF0YSRsMV9hbm5vdGF0aW9uc19yZXMwLjEpDQpgYGANCg0KYGBge3J9DQpJZGVudHMobWVyZ2VkX2FsbF9jb25zKSA8LSAnbDFfYW5ub3RhdGlvbnNfcmVzMC4xJw0KYGBgDQoNCmBgYHtyfQ0KRGltUGxvdChtZXJnZWRfYWxsX2NvbnMsIHJlZHVjdGlvbiA9ICJ1bWFwIikNCmBgYA0KYGBge3J9DQptYXJrZXJzX3Rlc3QgPC0gRmluZE1hcmtlcnMobWVyZ2VkX2FsbF9jb25zLCBncm91cGluZy52YXIgPSAibDFfYW5ub3RhdGlvbnNfcmVzMC4xIiwgaWRlbnQuMSA9ICJQb2RvY3l0ZSIpDQpgYGANCg0KYGBge3J9DQptYXJrZXJzX3Rlc3QNCmBgYA0KDQpgYGB7cn0NCkRpbVBsb3QobWVyZ2VkX2FsbF9jb25zLCBsYWJlbCA9IFQsIHJlcGVsID0gVCkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQorKysrKysrKysrKw0KYGBge3J9DQpteWVsb2lkX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVkdWNlZERpbShzY2VfbXllbG9pZCwgIlRTTkUiKSkNCmNvbG5hbWVzKG15ZWxvaWRfZGYpIDwtIGMoIlRTTkVfMSIsICJUU05FXzIiKQ0KDQpteWVsb2lkX2RmJGxpbmVhZ2UgPC0gaXMubmEoc2NlX215ZWxvaWQkc2xpbmdQc2V1ZG90aW1lXzEpDQoNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChteWVsb2lkX2RmLCBhZXMoeCA9IFRTTkVfMSwgeSA9IFRTTkVfMiwgY29sb3IgPSBsaW5lYWdlKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJibHVlIiwgIlRSVUUiID0gImdyYXkiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIkNlbGxzIEFzc2lnbmVkIHRvIFNsaW5nc2hvdCBMaW5lYWdlIDEiLA0KICAgICAgIGNvbG9yID0gIkFzc2lnbmVkPyIpDQoNCmBgYA0KDQpgYGB7cn0NCnNjZV9hbGwgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQob2JqX2Fubm90KQ0Kc2NlX2FsbCA8LSBzbGluZ3Nob3Q6OnNsaW5nc2hvdChzY2VfYWxsLCBjbHVzdGVyTGFiZWxzID0gc2NlX2FsbCRSTkFfc25uX3Jlcy4wLjQsIHJlZHVjZWREaW0gPSAnVFNORScpDQpgYGANCg0KYGBge3J9DQojRm9yIGp1c3QgUFQgY2VsbHMgYW5kIFBUX0VNVA0KDQojIEV4dHJhY3QgZGF0YSBmcm9tIFNpbmdsZUNlbGxFeHBlcmltZW50DQp0c25lX2FsbF9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlX2FsbCwgIlRTTkUiKSkNCmNvbG5hbWVzKHRzbmVfYWxsX2RmKSA8LSBjKCJUU05FXzEiLCAiVFNORV8yIikgICMgUmVuYW1lIHRvIHJlYWRhYmxlIG5hbWVzDQp0c25lX2FsbF9kZiRjbHVzdGVyIDwtIHNjZV9hbGwkbDFfYW5ub3RhdGlvbnNfcmVzMC4xDQp0c25lX2FsbF9kZiRwc2V1ZG90aW1lIDwtIHNjZV9hbGwkc2xpbmdQc2V1ZG90aW1lXzENCg0KDQojIENhbGN1bGF0ZSBjbHVzdGVyIGNlbnRyb2lkcyBmb3IgbGFiZWxpbmcNCmxhYmVsX2FsbF90c25lX2RmIDwtIHRzbmVfYWxsX2RmICU+JQ0KICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXplKFRTTkVfMSA9IG1lYW4oVFNORV8xKSwgVFNORV8yID0gbWVhbihUU05FXzIpKQ0KDQoNCiMgUGxvdCB3aXRoIGdncGxvdDINCmdncGxvdCh0c25lX2FsbF9kZiwgYWVzKHggPSBUU05FXzEsIHkgPSBUU05FXzIsIGNvbG9yID0gcHNldWRvdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBsYWJlbF9hbGxfdHNuZV9kZiwgYWVzKHggPSBUU05FXzEsIHkgPSBUU05FXzIsIGxhYmVsID0gY2x1c3RlciksIA0KICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHggPSAiVFNORTEiLCB5ID0gIlRTTkUgMiIsIHRpdGxlID0gIlNsaW5nc2hvdCBQc2V1ZG90aW1lIFtBbGwgQ2VsbHNdIHdpdGggQ2x1c3RlciBMYWJlbHMiKQ0KDQpgYGANCmBgYHtyfQ0KdHNuZV9hbGxfZGYgPC0gYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNjZV9hbGwsICJUU05FIikpDQpjb2xuYW1lcyh0c25lX2FsbF9kZikgPC0gYygiVFNORV8xIiwgIlRTTkVfMiIpDQoNCnRzbmVfYWxsX2RmJGxpbmVhZ2UgPC0gaXMubmEoc2NlX2FsbCRzbGluZ1BzZXVkb3RpbWVfMSkNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHRzbmVfYWxsX2RmLCBhZXMoeCA9IFRTTkVfMSwgeSA9IFRTTkVfMiwgY29sb3IgPSBsaW5lYWdlKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJibHVlIiwgIlRSVUUiID0gImdyYXkiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIkNlbGxzIEFzc2lnbmVkIHRvIFNsaW5nc2hvdCBMaW5lYWdlIDEiLA0KICAgICAgIGNvbG9yID0gIkFzc2lnbmVkPyIpDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCnNjZV9teWVsb2lkJGxpbmVhZ2UgPC0gaXMubmEoc2NlX215ZWxvaWQkc2xpbmdQc2V1ZG90aW1lXzEpDQpnZ3Bsb3QoLi4uLCBjb2xvciA9IGxpbmVhZ2UpICAjIFRSVUUgPSB1bmFzc2lnbmVkID0gZ3JheQ0KDQpkZiA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2NlX215ZWxvaWQsICJUU05FIikpDQpjb2xuYW1lcyhkZikgPC0gYygiVFNORV8xIiwgIlRTTkVfMiIpDQoNCmRmJGxpbmVhZ2UgPC0gaXMubmEoc2NlX215ZWxvaWQkc2xpbmdQc2V1ZG90aW1lXzEpDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCmBgYHtyfQ0KcGxvdChyZWR1Y2VkRGltKHNjZSksIGNvbCA9IHNjZSRjbHVzdGVyLCB0eXBlID0gJ2xpbmVhZ2VzJykNCg0Kc2NlJGxpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVyIikNCnBsb3RfY2VsbHMoY2RzLCBnZW5lcyA9IGMoIkNkaDIiKSwgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRSkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCisrKysrKysrKysrDQoNCmdnc2F2ZSgicmVzb2x1dGlvbiBjbHVzdGVyIHRyZWUuc3ZnIiwgcGxvdCA9IGNsdXN0ZXIudHJlZSwgd2lkdGggPSAxMikNCg0KY2x1c3Rlci50cmVlIA0KDQoNClVUSV8wLjVfbWFya2Vyc19jbHVzdF9hbm5vdCA8LSBTZXVyYXRXcmFwcGVyczo6UnVuUHJlc3RvQWxsKG1lcmdlZF8wLjVfc3BsaXRsaXN0JFVUSSkNCg0KVVRJXzAuNV9tYXJrZXJzX2xpc3QgPC0gc3BsaXQoVVRJXzAuNV9tYXJrZXJzX2NsdXN0X2Fubm90LCBVVElfMC41X21hcmtlcnNfY2x1c3RfYW5ub3RbWydjbHVzdGVyJ11dKQ0KDQpmb3IoaSBpbiBuYW1lcyhVVElfMC41X21hcmtlcnNfbGlzdCkpew0KICBhdXggPC0gVVRJXzAuNV9tYXJrZXJzX2xpc3RbW2ldXQ0KICBhdXggPC0gYXV4W2F1eCRwX3ZhbF9hZGogPCAwLjA1LF0NCiAgYXV4IDwtIGF1eFtvcmRlcihhdXgkYXZnX2xvZzJGQywgZGVjcmVhc2luZz1UKSxdDQogIFVUSV9hbGxfbWFya2Vyc19saXN0W1tpXV0gPC0gYXV4DQp9DQpgYGANCg0KI0RFIGdlbmVzIGJ5IGNvbmRpdGlvbiBhdCByZXMgMC4wMQ0KYGBge3J9DQptZXJnZWRfMC4wNSRsMF9jb25kaXRpb24gPC0gcGFzdGUwKG1lcmdlZF8wLjA1JFJOQV9zbm5fcmVzLjAuMDEsICdfJywgbWVyZ2VkXzAuMDUkY29uZGl0aW9uKQ0KSWRlbnRzKG1lcmdlZF8wLjA1KSA8LSAnbDBfY29uZGl0aW9uJw0KDQpERV8wLjA1X3Jlc29sX2NvbmRpdGlvbiA8LSBTZXVyYXRXcmFwcGVyczo6UnVuUHJlc3RvKG1lcmdlZF8wLjA1KQ0KYGBgDQoNCg0KDQoNCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDdHJsK0FsdCtJKi4NCg0KV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuDQoNClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4NCg==