1. load libraries

2. Load Data into Seurat

table(merged_seurat$sample_id)

Healthy_Blood  Healthy_Skin     MF1_Blood      MF1_Skin     SS1_Blood      SS1_Skin     SS2_Blood 
         4503            50          5027           698          4042          1644          6814 
     SS2_Skin     SS3_Blood      SS3_Skin     SS4_Blood      SS4_Skin     SS5_Blood     SS6_Blood 
          834          2424          1072          2326          1556          3590          3239 
table(merged_seurat$condition)

Healthy      MF      SS 
   4553    5725   27541 
table(merged_seurat$tissue)

Blood  Skin 
31965  5854 

3. QC & Filtering


# Mitochondrial content
merged_seurat[["percent.mt"]] <- PercentageFeatureSet(merged_seurat, pattern = "^MT-")

# Basic filtering
merged_seurat <- subset(merged_seurat, subset = nFeature_RNA > 200 & nFeature_RNA < 8000 & percent.mt < 10)

# QC plots
VlnPlot(merged_seurat, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3, pt.size = 0.1)
Warning: Default search for "data" layer in "RNA" assay yielded no results; utilizing "counts" layer instead.Warning: The `slot` argument of `FetchData()` is deprecated as of SeuratObject 5.0.0.
Please use the `layer` argument instead.Warning: `PackageCheck()` was deprecated in SeuratObject 5.0.0.
Please use `rlang::check_installed()` instead.

FeatureScatter(merged_seurat, feature1 = "nCount_RNA", feature2 = "nFeature_RNA") + geom_smooth(method = 'lm')

NA
NA

4. Normalization & PCA

5. PC Selection (Automated)




pct <- merged_seurat[["pca"]]@stdev / sum(merged_seurat[["pca"]]@stdev) * 100
cumu <- cumsum(pct)
co1 <- which(cumu > 90 & pct < 5)[1]
co2 <- sort(which((pct[-length(pct)] - pct[-1]) > 0.1), decreasing = TRUE)[1] + 1
min_pc <- min(co1, co2)

plot_df <- data.frame(pct = pct, cumu = cumu, rank = 1:length(pct))

ggplot(plot_df, aes(x = rank, y = pct)) +
  geom_col() +
  geom_point(aes(y = cumu), color = "red") +
  geom_vline(xintercept = min_pc, linetype = "dashed", color = "blue") +
  labs(title = "PCA Explained Variance", x = "PC", y = "% Variance")



min_pc
[1] 16

6. Dimensionality Reduction & Clustering


# Run Harmony integration if needed (optional)
# merged_seurat <- RunHarmony(merged_seurat, group.by.vars = "sample_id")

merged_seurat <- RunUMAP(merged_seurat, dims = 1:min_pc)
17:10:08 UMAP embedding parameters a = 0.9922 b = 1.112
17:10:08 Read 30345 rows and found 16 numeric columns
17:10:08 Using Annoy for neighbor search, n_neighbors = 30
17:10:08 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
17:10:10 Writing NN index file to temp file /tmp/RtmpwTyIcm/file6d1a2200108e6
17:10:10 Searching Annoy index using 1 thread, search_k = 3000
17:10:17 Annoy recall = 100%
17:10:17 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
17:10:19 Initializing from normalized Laplacian + noise (using RSpectra)
17:10:20 Commencing optimization for 200 epochs, with 1298492 positive edges
17:10:20 Using rng type: pcg
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
17:10:30 Optimization finished
merged_seurat <- FindNeighbors(merged_seurat, dims = 1:min_pc)
Computing nearest neighbor graph
Computing SNN
merged_seurat <- FindClusters(merged_seurat, resolution = 0.2)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 30345
Number of edges: 1096561

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9693
Number of communities: 20
Elapsed time: 4 seconds
# UMAP
DimPlot(merged_seurat, group.by = "condition", label = TRUE, repel = TRUE)

DimPlot(merged_seurat, group.by = "tissue", label = TRUE, repel = TRUE)

DimPlot(merged_seurat, label = TRUE)

7. Marker Discovery (Optional)

DoHeatmap(merged_seurat, features = top10$gene) + NoLegend()
Warning: The following features were omitted as they were not found in the scale.data slot for the RNA assay: CA1, AHSP, SLC4A1, ALAS2, AC114752.3, RP11-501J20.5, ITGB3, IGHGP, CLEC2A, KLK8, GRHL3, CPXM2, SV2A, CTD-2006K23.1, MME, WDR86, CD177, NCAM1, SFTPC, HLX, NRG1, OXNAD1

8. FeaturePlots for Top50 UP

top_50_up <- read.csv("../Gaydosik_Paper_Data_3_SS_Patients/top_50_upregulated.csv")        # or read.delim("top_50_up.tsv")
top_50_down <- read.csv("../Gaydosik_Paper_Data_3_SS_Patients/top_50_downregulated.csv")



FeaturePlot(merged_seurat, 
             features = top_50_up$gene[1:10], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)
Warning: The following requested variables were not found: PCLAF

FeaturePlot(merged_seurat, 
             features = top_50_up$gene[11:20], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)


FeaturePlot(merged_seurat, 
             features = top_50_up$gene[21:30], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

FeaturePlot(merged_seurat, 
             features = top_50_up$gene[31:40], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

FeaturePlot(merged_seurat, 
             features = top_50_up$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

9. FeaturePlots for Top50 DOWN


FeaturePlot(merged_seurat, 
             features = top_50_down$gene[1:10], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)
Warning: The following requested variables were not found: PCED1B-AS1, SNHG5

FeaturePlot(merged_seurat, 
             features = top_50_down$gene[11:20], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)
Warning: The following requested variables were not found: RIPOR2

FeaturePlot(merged_seurat, 
             features = top_50_down$gene[21:30], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)

FeaturePlot(merged_seurat, 
             features = top_50_down$gene[31:40], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)
Warning: The following requested variables were not found: LINC01578

FeaturePlot(merged_seurat, 
             features = top_50_down$gene[41:50], 
             reduction = "umap", 
             cols = c("lightblue", "red"),  # Custom color gradient from light blue to red
             label = TRUE)
Warning: The following requested variables were not found: AL138963.4

Visualization



DimPlot(merged_seurat, group.by = "seurat_clusters", label = T, label.box = T, repel = T, reduction = "umap")

NA
NA

Visualization of Potential biomarkers-Upregulated



# Vector of genes to plot
up_genes <- c("CLIC1", "COX5A","GTSF1", "MAD2L1","MYBL2","MYL6B","NME1","PLK1", "PYCR1", "SLC25A5", "SRI", "TUBA1C", "UBE2T", "YWHAH")

# DotPlot with custom firebrick-red gradient
DotPlot(merged_seurat, features = up_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with custom firebrick-red gradient
DotPlot(merged_seurat, features = up_genes, group.by = "sample_id") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with custom firebrick-red gradient
DotPlot(merged_seurat, features = up_genes, group.by = "tissue") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: Scaling data with a low number of groups may produce misleading resultsScale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with custom firebrick-red gradient
DotPlot(merged_seurat, features = up_genes, group.by = "condition") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Upregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: Scaling data with a low number of groups may produce misleading resultsScale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

Visualization of Potential biomarkers-Downregulated



# Downregulated genes
down_genes <- c("TXNIP", "RASA3", "RIPOR2", 
                "ZFP36", "ZFP36L1", "ZFP36L2",
                "PRMT2", "MAX", "PIK3IP1", 
                "BTG1", "CDKN1B")

# DotPlot with firebrick color for high expression
DotPlot(merged_seurat, features = down_genes) +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: The following requested variables were not found: RIPOR2Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with firebrick color for high expression
DotPlot(merged_seurat, features = down_genes, group.by = "sample_id") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: The following requested variables were not found: RIPOR2Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with firebrick color for high expression
DotPlot(merged_seurat, features = down_genes, group.by = "tissue") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: The following requested variables were not found: RIPOR2Warning: Scaling data with a low number of groups may produce misleading resultsScale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

# DotPlot with firebrick color for high expression
DotPlot(merged_seurat, features = down_genes, group.by = "condition") +
  RotatedAxis() +
  scale_color_gradient2(low = "lightblue", mid = "red", high = "firebrick", midpoint = 1) +
  ggtitle("Expression of Downregulated Genes in Sézary Syndrome") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
    axis.text.y = element_text(size = 12),
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
  )
Warning: The following requested variables were not found: RIPOR2Warning: Scaling data with a low number of groups may produce misleading resultsScale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

10. Compare disease status using RNA assay

library(Seurat)
library(dplyr)
library(tibble)

# Set Idents to sample_id for DE grouping
Idents(merged_seurat) <- "sample_id"

# Define healthy reference groups
healthy_blood <- "Healthy_Blood"
healthy_skin <- "Healthy_Skin"

# Get all sample_ids
all_samples <- unique(merged_seurat$sample_id)

# Extract SS blood and skin samples by pattern
ss_blood_samples <- grep("^SS[0-9]+_Blood$", all_samples, value = TRUE)
ss_skin_samples <- grep("^SS[0-9]+_Skin$", all_samples, value = TRUE)

# Function to run DE and save results
run_DE_and_save <- function(case_sample, control_sample, assay_name = "RNA") {
  message("Running DE: ", case_sample, " vs ", control_sample)
  
  # Run DE using Wilcox test (can change to MAST if needed)
  markers <- FindMarkers(
    object = merged_seurat,
    ident.1 = case_sample,
    ident.2 = control_sample,
    assay = assay_name,
    logfc.threshold = 0,
    min.pct = 0,
    test.use = "wilcox"
  )
  
  # Expression matrix for mean expression calculations
  expr_data <- GetAssayData(merged_seurat, assay = assay_name, slot = "data")
  
  # Cells in each group
  case_cells <- WhichCells(merged_seurat, idents = case_sample)
  control_cells <- WhichCells(merged_seurat, idents = control_sample)
  
  # Add mean expression and manual log2FC
  markers <- markers %>%
    rownames_to_column("gene") %>%
    mutate(
      mean_expr_case = rowMeans(expr_data[, case_cells, drop = FALSE], na.rm = TRUE)[gene],
      mean_expr_control = rowMeans(expr_data[, control_cells, drop = FALSE], na.rm = TRUE)[gene],
      log2FC_manual = log2(mean_expr_case + 1) - log2(mean_expr_control + 1)
    )
  
  # Write CSV output
  filename <- paste0("DE_", case_sample, "_vs_", control_sample, ".csv")
  write.csv(markers, filename, row.names = FALSE)
  message("Saved DE to ", filename)
  
  return(markers)
}

# Run DE for all SS Blood samples vs Healthy_Blood
for (ss_blood in ss_blood_samples) {
  run_DE_and_save(ss_blood, healthy_blood)
}
Running DE: SS1_Blood vs Healthy_Blood
Saved DE to DE_SS1_Blood_vs_Healthy_Blood.csv
Running DE: SS2_Blood vs Healthy_Blood
Saved DE to DE_SS2_Blood_vs_Healthy_Blood.csv
Running DE: SS3_Blood vs Healthy_Blood
Saved DE to DE_SS3_Blood_vs_Healthy_Blood.csv
Running DE: SS4_Blood vs Healthy_Blood
Saved DE to DE_SS4_Blood_vs_Healthy_Blood.csv
Running DE: SS5_Blood vs Healthy_Blood
Saved DE to DE_SS5_Blood_vs_Healthy_Blood.csv
Running DE: SS6_Blood vs Healthy_Blood
Saved DE to DE_SS6_Blood_vs_Healthy_Blood.csv
# Run DE for all SS Skin samples vs Healthy_Skin
for (ss_skin in ss_skin_samples) {
  run_DE_and_save(ss_skin, healthy_skin)
}
Running DE: SS1_Skin vs Healthy_Skin
Saved DE to DE_SS1_Skin_vs_Healthy_Skin.csv
Running DE: SS2_Skin vs Healthy_Skin
Saved DE to DE_SS2_Skin_vs_Healthy_Skin.csv
Running DE: SS3_Skin vs Healthy_Skin
Saved DE to DE_SS3_Skin_vs_Healthy_Skin.csv
Running DE: SS4_Skin vs Healthy_Skin
Saved DE to DE_SS4_Skin_vs_Healthy_Skin.csv

11. Compare disease status using RNA assay

# Create a new group column to classify each cell
merged_seurat$DE_group <- case_when(
  grepl("^SS[0-9]+_Blood$", merged_seurat$sample_id) ~ "SS_Blood",
  merged_seurat$sample_id == "Healthy_Blood" ~ "Healthy_Blood",
  grepl("^SS[0-9]+_Skin$", merged_seurat$sample_id) ~ "SS_Skin",
  merged_seurat$sample_id == "Healthy_Skin" ~ "Healthy_Skin",
  TRUE ~ NA_character_
)

# Check counts to ensure assignment worked
table(merged_seurat$DE_group)

Healthy_Blood  Healthy_Skin      SS_Blood       SS_Skin 
         4386            33         19543          1210 
Idents(merged_seurat) <- "DE_group"


# Function to perform grouped DE and save
run_grouped_DE <- function(group1, group2, assay_name = "RNA") {
  message("Running DE: ", group1, " vs ", group2)
  
  markers <- FindMarkers(
    object = merged_seurat,
    ident.1 = group1,
    ident.2 = group2,
    assay = assay_name,
    logfc.threshold = 0,
    min.pct = 0,
    test.use = "wilcox"
  )
  
  expr_data <- GetAssayData(merged_seurat, assay = assay_name, slot = "data")
  
  # Get cell names in each group
  group1_cells <- WhichCells(merged_seurat, idents = group1)
  group2_cells <- WhichCells(merged_seurat, idents = group2)
  
  # Add expression summaries
  markers <- markers %>%
    rownames_to_column("gene") %>%
    mutate(
      mean_expr_group1 = rowMeans(expr_data[, group1_cells, drop = FALSE], na.rm = TRUE)[gene],
      mean_expr_group2 = rowMeans(expr_data[, group2_cells, drop = FALSE], na.rm = TRUE)[gene],
      log2FC_manual = log2(mean_expr_group1 + 1) - log2(mean_expr_group2 + 1)
    )
  
  # Write to CSV
  filename <- paste0("Grouped_DE_", group1, "_vs_", group2, ".csv")
  write.csv(markers, filename, row.names = FALSE)
  message("Saved DE to ", filename)
  
  return(markers)
}

# Run DE for SS_Blood vs Healthy_Blood
de_blood <- run_grouped_DE("SS_Blood", "Healthy_Blood")
Running DE: SS_Blood vs Healthy_Blood
Saved DE to Grouped_DE_SS_Blood_vs_Healthy_Blood.csv
# Run DE for SS_Skin vs Healthy_Skin
de_skin <- run_grouped_DE("SS_Skin", "Healthy_Skin")
Running DE: SS_Skin vs Healthy_Skin
Saved DE to Grouped_DE_SS_Skin_vs_Healthy_Skin.csv

Save the Seurat object as an RDS



saveRDS(merged_seurat, file = "Herrara_All_samples.rds")
LS0tCnRpdGxlOiAiUG90ZW50aWFsIGJpb21hcmtlcnMgVmFsaWRhdGlvbl9IZXJyYXJhIGRhdGEiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciAsIGluY2x1ZGU9RkFMU0V9CgojIEF0IHRoZSB0b3Agb2YgeW91ciBzY3JpcHQsIGNvbWJpbmUgcGFja2FnZXMgbGlrZSB0aGlzOgpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICAjIGluY2x1ZGVzIGRwbHlyLCBnZ3Bsb3QyLCB0aWJibGUsIHJlYWRyLCBldGMuCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGhhcm1vbnkpCmxpYnJhcnkoZGl0dG9TZXEpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KFNldXJhdERpc2spCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeSh0aW55dGV4KQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkoU1RBQ0FTKQpsaWJyYXJ5KFByb2plY1RJTHMpCmxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCgpgYGAKCgojIDIuIExvYWQgRGF0YSBpbnRvIFNldXJhdApgYGB7ciB9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KE1hdHJpeCkKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBTdGVwIDE6IERlZmluZSBzYW1wbGUgbWV0YWRhdGEKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzYW1wbGVfaW5mbyA8LSBkYXRhLmZyYW1lKAogIGZpbGUgPSBjKAogICAgIkJsb29kL1NTMS9HU001MjM0NTc4X1NTMV9CbG9vZF9HRVgudHN2Lmd6IiwgCiAgICAiQmxvb2QvU1MyL0dTTTUyMzQ1ODBfU1MyX0Jsb29kX0dFWC50c3YuZ3oiLCAKICAgICJCbG9vZC9TUzMvR1NNNTIzNDU4Ml9TUzNfQmxvb2RfR0VYLnRzdi5neiIsCiAgICAiQmxvb2QvU1M0L0dTTTUyMzQ1ODRfU1M0X0Jsb29kX0dFWC50c3YuZ3oiLAogICAgIkJsb29kL1NTNS9HU001MjM0NTg4X1NTNV9CbG9vZF9HRVgudHN2Lmd6IiwgCiAgICAiQmxvb2QvU1M2L0dTTTUyMzQ1ODlfU1M2X0Jsb29kX0dFWC50c3YuZ3oiLAogICAgIkJsb29kL01GMS9HU001MjM0NTg2X01GSVYxX0Jsb29kX0dFWC50c3YuZ3oiLCAKICAgICJTa2luL1NTMS1Ta2luL0dTTTUyMzQ1NzlfU1MxX1NraW5fR0VYLnRzdi5neiIsIAogICAgIlNraW4vU1MyLVNraW4vR1NNNTIzNDU4MV9TUzJfU2tpbl9HRVgudHN2Lmd6IiwKICAgICJTa2luL1NTMy1Ta2luL0dTTTUyMzQ1ODNfU1MzX1NraW5fR0VYLnRzdi5neiIsIAogICAgIlNraW4vU1M0LVNraW4vR1NNNTIzNDU4NV9TUzRfU2tpbl9HRVgudHN2Lmd6IiwKICAgICJTa2luL01GMS1Ta2luL0dTTTUyMzQ1ODdfTUZJVjFfU2tpbl9HRVgudHN2Lmd6IiwgCiAgICAiSGVhbHRoeV9Ta2luL0dTTTUyMzQ1NzdfSEMxX1NraW5fR0VYLnRzdi5neiIsIAogICAgIkhlYWx0aHlfYmxvb2QvR1NNNTIzNDU3Nl9IQzFfQmxvb2RfR0VYLnRzdi5neiIKICApLAogIHNhbXBsZV9pZCA9IGMoCiAgICAiU1MxX0Jsb29kIiwgIlNTMl9CbG9vZCIsICJTUzNfQmxvb2QiLCAiU1M0X0Jsb29kIiwgIlNTNV9CbG9vZCIsICJTUzZfQmxvb2QiLAogICAgIk1GMV9CbG9vZCIsICJTUzFfU2tpbiIsICJTUzJfU2tpbiIsICJTUzNfU2tpbiIsICJTUzRfU2tpbiIsCiAgICAiTUYxX1NraW4iLCAiSGVhbHRoeV9Ta2luIiwgIkhlYWx0aHlfQmxvb2QiCiAgKSwKICBjb25kaXRpb24gPSBjKAogICAgcmVwKCJTUyIsIDYpLAogICAgIk1GIiwKICAgIHJlcCgiU1MiLCA0KSwKICAgICJNRiIsCiAgICAiSGVhbHRoeSIsCiAgICAiSGVhbHRoeSIKICApLAogIHRpc3N1ZSA9IGMoCiAgICByZXAoIkJsb29kIiwgNyksCiAgICByZXAoIlNraW4iLCA1KSwKICAgICJTa2luIiwKICAgICJCbG9vZCIKICApLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgU3RlcCAyOiBEZWZpbmUgYSBmdW5jdGlvbiB0byByZWFkIGFuZCBjcmVhdGUgU2V1cmF0CiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KY3JlYXRlX3NldXJhdF9vYmplY3QgPC0gZnVuY3Rpb24oZmlsZSwgc2FtcGxlX2lkLCBjb25kaXRpb24sIHRpc3N1ZSkgewogIG1lc3NhZ2UoIkxvYWRpbmc6ICIsIHNhbXBsZV9pZCkKICAKICAjIFJlYWQgZXhwcmVzc2lvbiBtYXRyaXgKICBleHByX21hdHJpeCA8LSBkYXRhLnRhYmxlOjpmcmVhZChmaWxlLCBkYXRhLnRhYmxlID0gRkFMU0UpCiAgcm93bmFtZXMoZXhwcl9tYXRyaXgpIDwtIGV4cHJfbWF0cml4WywgMV0KICBleHByX21hdHJpeCA8LSBhcy5tYXRyaXgoZXhwcl9tYXRyaXhbLCAtMV0pCiAgCiAgIyBFbnN1cmUgdW5pcXVlIGdlbmUgbmFtZXMgKGlmIGR1cGxpY2F0ZWQpCiAgcm93bmFtZXMoZXhwcl9tYXRyaXgpIDwtIG1ha2UudW5pcXVlKHJvd25hbWVzKGV4cHJfbWF0cml4KSkKICAKICAjIENyZWF0ZSBTZXVyYXQgb2JqZWN0CiAgc2V1IDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBleHByX21hdHJpeCwgcHJvamVjdCA9IHNhbXBsZV9pZCkKICAKICAjIEFkZCBtZXRhZGF0YQogIHNldSRzYW1wbGVfaWQgPC0gc2FtcGxlX2lkCiAgc2V1JGNvbmRpdGlvbiA8LSBjb25kaXRpb24KICBzZXUkdGlzc3VlIDwtIHRpc3N1ZQogIAogIHJldHVybihzZXUpCn0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBTdGVwIDM6IExvYWQgYWxsIHNhbXBsZXMgaW50byBhIGxpc3Qgd2l0aCBlcnJvciBoYW5kbGluZwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnNldXJhdF9saXN0IDwtIGxhcHBseShzZXFfbGVuKG5yb3coc2FtcGxlX2luZm8pKSwgZnVuY3Rpb24oaSkgewogIHRyeUNhdGNoKHsKICAgIGNyZWF0ZV9zZXVyYXRfb2JqZWN0KAogICAgICBmaWxlID0gc2FtcGxlX2luZm8kZmlsZVtpXSwKICAgICAgc2FtcGxlX2lkID0gc2FtcGxlX2luZm8kc2FtcGxlX2lkW2ldLAogICAgICBjb25kaXRpb24gPSBzYW1wbGVfaW5mbyRjb25kaXRpb25baV0sCiAgICAgIHRpc3N1ZSA9IHNhbXBsZV9pbmZvJHRpc3N1ZVtpXQogICAgKQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgbWVzc2FnZSgi4pqg77iPIEVycm9yIGxvYWRpbmcgIiwgc2FtcGxlX2luZm8kc2FtcGxlX2lkW2ldLCAiOiAiLCBlJG1lc3NhZ2UpCiAgICByZXR1cm4oTlVMTCkKICB9KQp9KQoKIyBSZW1vdmUgZmFpbGVkIGVudHJpZXMKc2V1cmF0X2xpc3QgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgc2V1cmF0X2xpc3QpCgojIE9wdGlvbmFsOiBjaGVjayBsb2FkZWQgc2FtcGxlcwptZXNzYWdlKCJMb2FkZWQgc2FtcGxlczogIiwgcGFzdGUoc2FwcGx5KHNldXJhdF9saXN0LCBmdW5jdGlvbih4KSB1bmlxdWUoeCRzYW1wbGVfaWQpKSwgY29sbGFwc2UgPSAiLCAiKSkKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBTdGVwIDQ6IE1lcmdlIGFsbCBTZXVyYXQgb2JqZWN0cyBpbnRvIG9uZQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1lcmdlZF9zZXVyYXQgPC0gbWVyZ2UoCiAgeCA9IHNldXJhdF9saXN0W1sxXV0sCiAgeSA9IHNldXJhdF9saXN0Wy0xXSwKICBhZGQuY2VsbC5pZHMgPSBzYXBwbHkoc2V1cmF0X2xpc3QsIGZ1bmN0aW9uKHgpIHVuaXF1ZSh4JHNhbXBsZV9pZCkpCikKCnRhYmxlKG1lcmdlZF9zZXVyYXQkc2FtcGxlX2lkKQp0YWJsZShtZXJnZWRfc2V1cmF0JGNvbmRpdGlvbikKdGFibGUobWVyZ2VkX3NldXJhdCR0aXNzdWUpCgoKYGBgCgojIDMuIFFDICYgRmlsdGVyaW5nCmBgYHtyICwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgojIE1pdG9jaG9uZHJpYWwgY29udGVudAptZXJnZWRfc2V1cmF0W1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChtZXJnZWRfc2V1cmF0LCBwYXR0ZXJuID0gIl5NVC0iKQoKIyBCYXNpYyBmaWx0ZXJpbmcKbWVyZ2VkX3NldXJhdCA8LSBzdWJzZXQobWVyZ2VkX3NldXJhdCwgc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gMjAwICYgbkZlYXR1cmVfUk5BIDwgODAwMCAmIHBlcmNlbnQubXQgPCAxMCkKCiMgUUMgcGxvdHMKVmxuUGxvdChtZXJnZWRfc2V1cmF0LCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsICJuQ291bnRfUk5BIiwgInBlcmNlbnQubXQiKSwgbmNvbCA9IDMsIHB0LnNpemUgPSAwLjEpCgpGZWF0dXJlU2NhdHRlcihtZXJnZWRfc2V1cmF0LCBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgZmVhdHVyZTIgPSAibkZlYXR1cmVfUk5BIikgKyBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKQoKCmBgYAoKIyA0LiBOb3JtYWxpemF0aW9uICYgUENBCmBgYHtyIH0KCiMgTm9ybWFsaXplLCBmaW5kIHZhcmlhYmxlIGZlYXR1cmVzLCBzY2FsZSwgUENBCm1lcmdlZF9zZXVyYXQgPC0gTm9ybWFsaXplRGF0YShtZXJnZWRfc2V1cmF0LCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKbWVyZ2VkX3NldXJhdCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhtZXJnZWRfc2V1cmF0LCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCm1lcmdlZF9zZXVyYXQgPC0gU2NhbGVEYXRhKG1lcmdlZF9zZXVyYXQpCm1lcmdlZF9zZXVyYXQgPC0gUnVuUENBKG1lcmdlZF9zZXVyYXQpCgoKCiMgRWxib3cgUGxvdCB0byBkZWNpZGUgbnVtYmVyIG9mIFBDcwpFbGJvd1Bsb3QobWVyZ2VkX3NldXJhdCkKCmBgYAoKCiMgNS4gUEMgU2VsZWN0aW9uIChBdXRvbWF0ZWQpCmBgYHtyICwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKCnBjdCA8LSBtZXJnZWRfc2V1cmF0W1sicGNhIl1dQHN0ZGV2IC8gc3VtKG1lcmdlZF9zZXVyYXRbWyJwY2EiXV1Ac3RkZXYpICogMTAwCmN1bXUgPC0gY3Vtc3VtKHBjdCkKY28xIDwtIHdoaWNoKGN1bXUgPiA5MCAmIHBjdCA8IDUpWzFdCmNvMiA8LSBzb3J0KHdoaWNoKChwY3RbLWxlbmd0aChwY3QpXSAtIHBjdFstMV0pID4gMC4xKSwgZGVjcmVhc2luZyA9IFRSVUUpWzFdICsgMQptaW5fcGMgPC0gbWluKGNvMSwgY28yKQoKcGxvdF9kZiA8LSBkYXRhLmZyYW1lKHBjdCA9IHBjdCwgY3VtdSA9IGN1bXUsIHJhbmsgPSAxOmxlbmd0aChwY3QpKQoKZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gcmFuaywgeSA9IHBjdCkpICsKICBnZW9tX2NvbCgpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gY3VtdSksIGNvbG9yID0gInJlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtaW5fcGMsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJQQ0EgRXhwbGFpbmVkIFZhcmlhbmNlIiwgeCA9ICJQQyIsIHkgPSAiJSBWYXJpYW5jZSIpCgoKbWluX3BjCgpgYGAKCiMgNi4gRGltZW5zaW9uYWxpdHkgUmVkdWN0aW9uICYgQ2x1c3RlcmluZwpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBSdW4gSGFybW9ueSBpbnRlZ3JhdGlvbiBpZiBuZWVkZWQgKG9wdGlvbmFsKQojIG1lcmdlZF9zZXVyYXQgPC0gUnVuSGFybW9ueShtZXJnZWRfc2V1cmF0LCBncm91cC5ieS52YXJzID0gInNhbXBsZV9pZCIpCgptZXJnZWRfc2V1cmF0IDwtIFJ1blVNQVAobWVyZ2VkX3NldXJhdCwgZGltcyA9IDE6bWluX3BjKQptZXJnZWRfc2V1cmF0IDwtIEZpbmROZWlnaGJvcnMobWVyZ2VkX3NldXJhdCwgZGltcyA9IDE6bWluX3BjKQptZXJnZWRfc2V1cmF0IDwtIEZpbmRDbHVzdGVycyhtZXJnZWRfc2V1cmF0LCByZXNvbHV0aW9uID0gMC4yKQoKIyBVTUFQCkRpbVBsb3QobWVyZ2VkX3NldXJhdCwgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUpCkRpbVBsb3QobWVyZ2VkX3NldXJhdCwgZ3JvdXAuYnkgPSAidGlzc3VlIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUpCkRpbVBsb3QobWVyZ2VkX3NldXJhdCwgbGFiZWwgPSBUUlVFKQoKYGBgCgojIDcuIE1hcmtlciBEaXNjb3ZlcnkgKE9wdGlvbmFsKQpgYGB7ciAsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xNH0KCiMgSm9pbiB0aGUgbGF5ZXJzIG9mIHRoZSBSTkEgYXNzYXkKbWVyZ2VkX3NldXJhdCA8LSBKb2luTGF5ZXJzKG1lcmdlZF9zZXVyYXQsIGFzc2F5ID0gIlJOQSIpCgojIENsdXN0ZXIgbWFya2VycyAoYWxsIGNsdXN0ZXJzIHZzIGFsbCBvdGhlcnMpCmFsbF9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKG1lcmdlZF9zZXVyYXQsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCmhlYWQoYWxsX21hcmtlcnMpCgojIFRvcCBtYXJrZXJzIHBlciBjbHVzdGVyCnRvcDUgPC0gYWxsX21hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3Bfbig1LCBhdmdfbG9nMkZDKQoKRG9IZWF0bWFwKG1lcmdlZF9zZXVyYXQsIGZlYXR1cmVzID0gdG9wMTAkZ2VuZSkgKyBOb0xlZ2VuZCgpCgoKYGBgCgojIDguICBGZWF0dXJlUGxvdHMgZm9yIFRvcDUwIFVQCmBgYHtyICwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTIwfQp0b3BfNTBfdXAgPC0gcmVhZC5jc3YoIi4uL0dheWRvc2lrX1BhcGVyX0RhdGFfM19TU19QYXRpZW50cy90b3BfNTBfdXByZWd1bGF0ZWQuY3N2IikgICAgICAgICMgb3IgcmVhZC5kZWxpbSgidG9wXzUwX3VwLnRzdiIpCnRvcF81MF9kb3duIDwtIHJlYWQuY3N2KCIuLi9HYXlkb3Npa19QYXBlcl9EYXRhXzNfU1NfUGF0aWVudHMvdG9wXzUwX2Rvd25yZWd1bGF0ZWQuY3N2IikKCgoKRmVhdHVyZVBsb3QobWVyZ2VkX3NldXJhdCwgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF91cCRnZW5lWzE6MTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKCkZlYXR1cmVQbG90KG1lcmdlZF9zZXVyYXQsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfdXAkZ2VuZVsxMToyMF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCgpGZWF0dXJlUGxvdChtZXJnZWRfc2V1cmF0LCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMjE6MzBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQpGZWF0dXJlUGxvdChtZXJnZWRfc2V1cmF0LCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbMzE6NDBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQpGZWF0dXJlUGxvdChtZXJnZWRfc2V1cmF0LCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX3VwJGdlbmVbNDE6NTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKYGBgCgoKCiMgOS4gIEZlYXR1cmVQbG90cyBmb3IgVG9wNTAgRE9XTgpgYGB7ciAsIGZpZy5oZWlnaHQ9MTYsIGZpZy53aWR0aD0yMH0KCkZlYXR1cmVQbG90KG1lcmdlZF9zZXVyYXQsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzE6MTBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQoKCkZlYXR1cmVQbG90KG1lcmdlZF9zZXVyYXQsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzExOjIwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKCkZlYXR1cmVQbG90KG1lcmdlZF9zZXVyYXQsIAogICAgICAgICAgICAgZmVhdHVyZXMgPSB0b3BfNTBfZG93biRnZW5lWzIxOjMwXSwgCiAgICAgICAgICAgICByZWR1Y3Rpb24gPSAidW1hcCIsIAogICAgICAgICAgICAgY29scyA9IGMoImxpZ2h0Ymx1ZSIsICJyZWQiKSwgICMgQ3VzdG9tIGNvbG9yIGdyYWRpZW50IGZyb20gbGlnaHQgYmx1ZSB0byByZWQKICAgICAgICAgICAgIGxhYmVsID0gVFJVRSkKRmVhdHVyZVBsb3QobWVyZ2VkX3NldXJhdCwgCiAgICAgICAgICAgICBmZWF0dXJlcyA9IHRvcF81MF9kb3duJGdlbmVbMzE6NDBdLCAKICAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgCiAgICAgICAgICAgICBjb2xzID0gYygibGlnaHRibHVlIiwgInJlZCIpLCAgIyBDdXN0b20gY29sb3IgZ3JhZGllbnQgZnJvbSBsaWdodCBibHVlIHRvIHJlZAogICAgICAgICAgICAgbGFiZWwgPSBUUlVFKQpGZWF0dXJlUGxvdChtZXJnZWRfc2V1cmF0LCAKICAgICAgICAgICAgIGZlYXR1cmVzID0gdG9wXzUwX2Rvd24kZ2VuZVs0MTo1MF0sIAogICAgICAgICAgICAgcmVkdWN0aW9uID0gInVtYXAiLCAKICAgICAgICAgICAgIGNvbHMgPSBjKCJsaWdodGJsdWUiLCAicmVkIiksICAjIEN1c3RvbSBjb2xvciBncmFkaWVudCBmcm9tIGxpZ2h0IGJsdWUgdG8gcmVkCiAgICAgICAgICAgICBsYWJlbCA9IFRSVUUpCmBgYAoKIyMgVmlzdWFsaXphdGlvbgpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKCkRpbVBsb3QobWVyZ2VkX3NldXJhdCwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgbGFiZWwgPSBULCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQsIHJlZHVjdGlvbiA9ICJ1bWFwIikKCgpgYGAKCiMjIFZpc3VhbGl6YXRpb24gb2YgUG90ZW50aWFsIGJpb21hcmtlcnMtVXByZWd1bGF0ZWQKYGBge3IgLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgojIFZlY3RvciBvZiBnZW5lcyB0byBwbG90CnVwX2dlbmVzIDwtIGMoIkNMSUMxIiwgIkNPWDVBIiwiR1RTRjEiLCAiTUFEMkwxIiwiTVlCTDIiLCJNWUw2QiIsIk5NRTEiLCJQTEsxIiwgIlBZQ1IxIiwgIlNMQzI1QTUiLCAiU1JJIiwgIlRVQkExQyIsICJVQkUyVCIsICJZV0hBSCIpCgojIERvdFBsb3Qgd2l0aCBjdXN0b20gZmlyZWJyaWNrLXJlZCBncmFkaWVudApEb3RQbG90KG1lcmdlZF9zZXVyYXQsIGZlYXR1cmVzID0gdXBfZ2VuZXMpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKIyBEb3RQbG90IHdpdGggY3VzdG9tIGZpcmVicmljay1yZWQgZ3JhZGllbnQKRG90UGxvdChtZXJnZWRfc2V1cmF0LCBmZWF0dXJlcyA9IHVwX2dlbmVzLCBncm91cC5ieSA9ICJzYW1wbGVfaWQiKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIFVwcmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGN1c3RvbSBmaXJlYnJpY2stcmVkIGdyYWRpZW50CkRvdFBsb3QobWVyZ2VkX3NldXJhdCwgZmVhdHVyZXMgPSB1cF9nZW5lcywgZ3JvdXAuYnkgPSAidGlzc3VlIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBVcHJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCgojIERvdFBsb3Qgd2l0aCBjdXN0b20gZmlyZWJyaWNrLXJlZCBncmFkaWVudApEb3RQbG90KG1lcmdlZF9zZXVyYXQsIGZlYXR1cmVzID0gdXBfZ2VuZXMsIGdyb3VwLmJ5ID0gImNvbmRpdGlvbiIpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgVXByZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQpgYGAKCgoKIyMgVmlzdWFsaXphdGlvbiBvZiBQb3RlbnRpYWwgYmlvbWFya2Vycy1Eb3ducmVndWxhdGVkCmBgYHtyIEMyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCgojIERvd25yZWd1bGF0ZWQgZ2VuZXMKZG93bl9nZW5lcyA8LSBjKCJUWE5JUCIsICJSQVNBMyIsICJSSVBPUjIiLCAKICAgICAgICAgICAgICAgICJaRlAzNiIsICJaRlAzNkwxIiwgIlpGUDM2TDIiLAogICAgICAgICAgICAgICAgIlBSTVQyIiwgIk1BWCIsICJQSUszSVAxIiwgCiAgICAgICAgICAgICAgICAiQlRHMSIsICJDREtOMUIiKQoKIyBEb3RQbG90IHdpdGggZmlyZWJyaWNrIGNvbG9yIGZvciBoaWdoIGV4cHJlc3Npb24KRG90UGxvdChtZXJnZWRfc2V1cmF0LCBmZWF0dXJlcyA9IGRvd25fZ2VuZXMpICsKICBSb3RhdGVkQXhpcygpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gImxpZ2h0Ymx1ZSIsIG1pZCA9ICJyZWQiLCBoaWdoID0gImZpcmVicmljayIsIG1pZHBvaW50ID0gMSkgKwogIGdndGl0bGUoIkV4cHJlc3Npb24gb2YgRG93bnJlZ3VsYXRlZCBHZW5lcyBpbiBTw6l6YXJ5IFN5bmRyb21lIikgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCkKICApCgojIERvdFBsb3Qgd2l0aCBmaXJlYnJpY2sgY29sb3IgZm9yIGhpZ2ggZXhwcmVzc2lvbgpEb3RQbG90KG1lcmdlZF9zZXVyYXQsIGZlYXR1cmVzID0gZG93bl9nZW5lcywgZ3JvdXAuYnkgPSAic2FtcGxlX2lkIikgKwogIFJvdGF0ZWRBeGlzKCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAibGlnaHRibHVlIiwgbWlkID0gInJlZCIsIGhpZ2ggPSAiZmlyZWJyaWNrIiwgbWlkcG9pbnQgPSAxKSArCiAgZ2d0aXRsZSgiRXhwcmVzc2lvbiBvZiBEb3ducmVndWxhdGVkIEdlbmVzIGluIFPDqXphcnkgU3luZHJvbWUiKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KQogICkKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3QobWVyZ2VkX3NldXJhdCwgZmVhdHVyZXMgPSBkb3duX2dlbmVzLCBncm91cC5ieSA9ICJ0aXNzdWUiKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQoKCiMgRG90UGxvdCB3aXRoIGZpcmVicmljayBjb2xvciBmb3IgaGlnaCBleHByZXNzaW9uCkRvdFBsb3QobWVyZ2VkX3NldXJhdCwgZmVhdHVyZXMgPSBkb3duX2dlbmVzLCBncm91cC5ieSA9ICJjb25kaXRpb24iKSArCiAgUm90YXRlZEF4aXMoKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJsaWdodGJsdWUiLCBtaWQgPSAicmVkIiwgaGlnaCA9ICJmaXJlYnJpY2siLCBtaWRwb2ludCA9IDEpICsKICBnZ3RpdGxlKCJFeHByZXNzaW9uIG9mIERvd25yZWd1bGF0ZWQgR2VuZXMgaW4gU8OpemFyeSBTeW5kcm9tZSIpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTQpCiAgKQpgYGAKCiMgMTAuIENvbXBhcmUgZGlzZWFzZSBzdGF0dXMgdXNpbmcgUk5BIGFzc2F5CmBgYHtyICwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGliYmxlKQoKIyBTZXQgSWRlbnRzIHRvIHNhbXBsZV9pZCBmb3IgREUgZ3JvdXBpbmcKSWRlbnRzKG1lcmdlZF9zZXVyYXQpIDwtICJzYW1wbGVfaWQiCgojIERlZmluZSBoZWFsdGh5IHJlZmVyZW5jZSBncm91cHMKaGVhbHRoeV9ibG9vZCA8LSAiSGVhbHRoeV9CbG9vZCIKaGVhbHRoeV9za2luIDwtICJIZWFsdGh5X1NraW4iCgojIEdldCBhbGwgc2FtcGxlX2lkcwphbGxfc2FtcGxlcyA8LSB1bmlxdWUobWVyZ2VkX3NldXJhdCRzYW1wbGVfaWQpCgojIEV4dHJhY3QgU1MgYmxvb2QgYW5kIHNraW4gc2FtcGxlcyBieSBwYXR0ZXJuCnNzX2Jsb29kX3NhbXBsZXMgPC0gZ3JlcCgiXlNTWzAtOV0rX0Jsb29kJCIsIGFsbF9zYW1wbGVzLCB2YWx1ZSA9IFRSVUUpCnNzX3NraW5fc2FtcGxlcyA8LSBncmVwKCJeU1NbMC05XStfU2tpbiQiLCBhbGxfc2FtcGxlcywgdmFsdWUgPSBUUlVFKQoKIyBGdW5jdGlvbiB0byBydW4gREUgYW5kIHNhdmUgcmVzdWx0cwpydW5fREVfYW5kX3NhdmUgPC0gZnVuY3Rpb24oY2FzZV9zYW1wbGUsIGNvbnRyb2xfc2FtcGxlLCBhc3NheV9uYW1lID0gIlJOQSIpIHsKICBtZXNzYWdlKCJSdW5uaW5nIERFOiAiLCBjYXNlX3NhbXBsZSwgIiB2cyAiLCBjb250cm9sX3NhbXBsZSkKICAKICAjIFJ1biBERSB1c2luZyBXaWxjb3ggdGVzdCAoY2FuIGNoYW5nZSB0byBNQVNUIGlmIG5lZWRlZCkKICBtYXJrZXJzIDwtIEZpbmRNYXJrZXJzKAogICAgb2JqZWN0ID0gbWVyZ2VkX3NldXJhdCwKICAgIGlkZW50LjEgPSBjYXNlX3NhbXBsZSwKICAgIGlkZW50LjIgPSBjb250cm9sX3NhbXBsZSwKICAgIGFzc2F5ID0gYXNzYXlfbmFtZSwKICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgICBtaW4ucGN0ID0gMCwKICAgIHRlc3QudXNlID0gIndpbGNveCIKICApCiAgCiAgIyBFeHByZXNzaW9uIG1hdHJpeCBmb3IgbWVhbiBleHByZXNzaW9uIGNhbGN1bGF0aW9ucwogIGV4cHJfZGF0YSA8LSBHZXRBc3NheURhdGEobWVyZ2VkX3NldXJhdCwgYXNzYXkgPSBhc3NheV9uYW1lLCBzbG90ID0gImRhdGEiKQogIAogICMgQ2VsbHMgaW4gZWFjaCBncm91cAogIGNhc2VfY2VsbHMgPC0gV2hpY2hDZWxscyhtZXJnZWRfc2V1cmF0LCBpZGVudHMgPSBjYXNlX3NhbXBsZSkKICBjb250cm9sX2NlbGxzIDwtIFdoaWNoQ2VsbHMobWVyZ2VkX3NldXJhdCwgaWRlbnRzID0gY29udHJvbF9zYW1wbGUpCiAgCiAgIyBBZGQgbWVhbiBleHByZXNzaW9uIGFuZCBtYW51YWwgbG9nMkZDCiAgbWFya2VycyA8LSBtYXJrZXJzICU+JQogICAgcm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgJT4lCiAgICBtdXRhdGUoCiAgICAgIG1lYW5fZXhwcl9jYXNlID0gcm93TWVhbnMoZXhwcl9kYXRhWywgY2FzZV9jZWxscywgZHJvcCA9IEZBTFNFXSwgbmEucm0gPSBUUlVFKVtnZW5lXSwKICAgICAgbWVhbl9leHByX2NvbnRyb2wgPSByb3dNZWFucyhleHByX2RhdGFbLCBjb250cm9sX2NlbGxzLCBkcm9wID0gRkFMU0VdLCBuYS5ybSA9IFRSVUUpW2dlbmVdLAogICAgICBsb2cyRkNfbWFudWFsID0gbG9nMihtZWFuX2V4cHJfY2FzZSArIDEpIC0gbG9nMihtZWFuX2V4cHJfY29udHJvbCArIDEpCiAgICApCiAgCiAgIyBXcml0ZSBDU1Ygb3V0cHV0CiAgZmlsZW5hbWUgPC0gcGFzdGUwKCJERV8iLCBjYXNlX3NhbXBsZSwgIl92c18iLCBjb250cm9sX3NhbXBsZSwgIi5jc3YiKQogIHdyaXRlLmNzdihtYXJrZXJzLCBmaWxlbmFtZSwgcm93Lm5hbWVzID0gRkFMU0UpCiAgbWVzc2FnZSgiU2F2ZWQgREUgdG8gIiwgZmlsZW5hbWUpCiAgCiAgcmV0dXJuKG1hcmtlcnMpCn0KCiMgUnVuIERFIGZvciBhbGwgU1MgQmxvb2Qgc2FtcGxlcyB2cyBIZWFsdGh5X0Jsb29kCmZvciAoc3NfYmxvb2QgaW4gc3NfYmxvb2Rfc2FtcGxlcykgewogIHJ1bl9ERV9hbmRfc2F2ZShzc19ibG9vZCwgaGVhbHRoeV9ibG9vZCkKfQoKIyBSdW4gREUgZm9yIGFsbCBTUyBTa2luIHNhbXBsZXMgdnMgSGVhbHRoeV9Ta2luCmZvciAoc3Nfc2tpbiBpbiBzc19za2luX3NhbXBsZXMpIHsKICBydW5fREVfYW5kX3NhdmUoc3Nfc2tpbiwgaGVhbHRoeV9za2luKQp9CgpgYGAKIyAxMS4gQ29tcGFyZSBkaXNlYXNlIHN0YXR1cyB1c2luZyBSTkEgYXNzYXkKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD02fQojIENyZWF0ZSBhIG5ldyBncm91cCBjb2x1bW4gdG8gY2xhc3NpZnkgZWFjaCBjZWxsCm1lcmdlZF9zZXVyYXQkREVfZ3JvdXAgPC0gY2FzZV93aGVuKAogIGdyZXBsKCJeU1NbMC05XStfQmxvb2QkIiwgbWVyZ2VkX3NldXJhdCRzYW1wbGVfaWQpIH4gIlNTX0Jsb29kIiwKICBtZXJnZWRfc2V1cmF0JHNhbXBsZV9pZCA9PSAiSGVhbHRoeV9CbG9vZCIgfiAiSGVhbHRoeV9CbG9vZCIsCiAgZ3JlcGwoIl5TU1swLTldK19Ta2luJCIsIG1lcmdlZF9zZXVyYXQkc2FtcGxlX2lkKSB+ICJTU19Ta2luIiwKICBtZXJnZWRfc2V1cmF0JHNhbXBsZV9pZCA9PSAiSGVhbHRoeV9Ta2luIiB+ICJIZWFsdGh5X1NraW4iLAogIFRSVUUgfiBOQV9jaGFyYWN0ZXJfCikKCiMgQ2hlY2sgY291bnRzIHRvIGVuc3VyZSBhc3NpZ25tZW50IHdvcmtlZAp0YWJsZShtZXJnZWRfc2V1cmF0JERFX2dyb3VwKQoKCklkZW50cyhtZXJnZWRfc2V1cmF0KSA8LSAiREVfZ3JvdXAiCgoKIyBGdW5jdGlvbiB0byBwZXJmb3JtIGdyb3VwZWQgREUgYW5kIHNhdmUKcnVuX2dyb3VwZWRfREUgPC0gZnVuY3Rpb24oZ3JvdXAxLCBncm91cDIsIGFzc2F5X25hbWUgPSAiUk5BIikgewogIG1lc3NhZ2UoIlJ1bm5pbmcgREU6ICIsIGdyb3VwMSwgIiB2cyAiLCBncm91cDIpCiAgCiAgbWFya2VycyA8LSBGaW5kTWFya2VycygKICAgIG9iamVjdCA9IG1lcmdlZF9zZXVyYXQsCiAgICBpZGVudC4xID0gZ3JvdXAxLAogICAgaWRlbnQuMiA9IGdyb3VwMiwKICAgIGFzc2F5ID0gYXNzYXlfbmFtZSwKICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAsCiAgICBtaW4ucGN0ID0gMCwKICAgIHRlc3QudXNlID0gIndpbGNveCIKICApCiAgCiAgZXhwcl9kYXRhIDwtIEdldEFzc2F5RGF0YShtZXJnZWRfc2V1cmF0LCBhc3NheSA9IGFzc2F5X25hbWUsIHNsb3QgPSAiZGF0YSIpCiAgCiAgIyBHZXQgY2VsbCBuYW1lcyBpbiBlYWNoIGdyb3VwCiAgZ3JvdXAxX2NlbGxzIDwtIFdoaWNoQ2VsbHMobWVyZ2VkX3NldXJhdCwgaWRlbnRzID0gZ3JvdXAxKQogIGdyb3VwMl9jZWxscyA8LSBXaGljaENlbGxzKG1lcmdlZF9zZXVyYXQsIGlkZW50cyA9IGdyb3VwMikKICAKICAjIEFkZCBleHByZXNzaW9uIHN1bW1hcmllcwogIG1hcmtlcnMgPC0gbWFya2VycyAlPiUKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiZ2VuZSIpICU+JQogICAgbXV0YXRlKAogICAgICBtZWFuX2V4cHJfZ3JvdXAxID0gcm93TWVhbnMoZXhwcl9kYXRhWywgZ3JvdXAxX2NlbGxzLCBkcm9wID0gRkFMU0VdLCBuYS5ybSA9IFRSVUUpW2dlbmVdLAogICAgICBtZWFuX2V4cHJfZ3JvdXAyID0gcm93TWVhbnMoZXhwcl9kYXRhWywgZ3JvdXAyX2NlbGxzLCBkcm9wID0gRkFMU0VdLCBuYS5ybSA9IFRSVUUpW2dlbmVdLAogICAgICBsb2cyRkNfbWFudWFsID0gbG9nMihtZWFuX2V4cHJfZ3JvdXAxICsgMSkgLSBsb2cyKG1lYW5fZXhwcl9ncm91cDIgKyAxKQogICAgKQogIAogICMgV3JpdGUgdG8gQ1NWCiAgZmlsZW5hbWUgPC0gcGFzdGUwKCJHcm91cGVkX0RFXyIsIGdyb3VwMSwgIl92c18iLCBncm91cDIsICIuY3N2IikKICB3cml0ZS5jc3YobWFya2VycywgZmlsZW5hbWUsIHJvdy5uYW1lcyA9IEZBTFNFKQogIG1lc3NhZ2UoIlNhdmVkIERFIHRvICIsIGZpbGVuYW1lKQogIAogIHJldHVybihtYXJrZXJzKQp9CgojIFJ1biBERSBmb3IgU1NfQmxvb2QgdnMgSGVhbHRoeV9CbG9vZApkZV9ibG9vZCA8LSBydW5fZ3JvdXBlZF9ERSgiU1NfQmxvb2QiLCAiSGVhbHRoeV9CbG9vZCIpCgojIFJ1biBERSBmb3IgU1NfU2tpbiB2cyBIZWFsdGh5X1NraW4KZGVfc2tpbiA8LSBydW5fZ3JvdXBlZF9ERSgiU1NfU2tpbiIsICJIZWFsdGh5X1NraW4iKQoKCmBgYAoKIyBTYXZlIHRoZSBTZXVyYXQgb2JqZWN0IGFzIGFuIFJEUwpgYGB7ciBzYXZlUkRTfQoKCnNhdmVSRFMobWVyZ2VkX3NldXJhdCwgZmlsZSA9ICJIZXJyYXJhX0FsbF9zYW1wbGVzLnJkcyIpCgoKYGBgCgoKCg==