This R Markdown document outlines a complete, step-by-step pipeline for generating all essential and advanced single-cell RNA-seq visualizations required for a high-impact publication in cancer genomics. The methodologies are rigorously derived from the latest literature (e.g., Herrera et al., Xue et al., Borcherding et al.).

CRITICAL NOTE FOR EXECUTION: This script is designed to operate on your Harmony-integrated Seurat object, which is assumed to be named All_samples_Merged. The R code below uses a placeholder PBMC dataset to ensure the script is fully executable and demonstrates the expected output. To run this pipeline on your data, you MUST replace the placeholder data loading and processing steps in the data_prep chunk with the command to load your object: ss.integrated <- readRDS("path/to/your/All_samples_Merged.rds")object is assumed to have a dimensionality reduction named harmony and a metadata column for cell type annotation named cell_type.

Setup and Data Preparation

The following chunk loads all necessary libraries, defines publication-quality parameters, and sets up the output directory.

# Load Libraries (Ensure these are installed in your R environment)
library(Seurat)
library(ggplot2)
library(patchwork)
library(dplyr)
library(schex) # For Hexbin Plots
# library(monocle3) # For Trajectory Analysis
# library(CellChat) # For Cell-Cell Communication
# library(scRepertoire) # For TCR Clonality

# --- Define Publication Parameters ---
OUTPUT_DIR <- "./publication_figures/"
PUB_WIDTH <- 10
PUB_HEIGHT <- 8
PUB_RES <- 300 # DPI (Dots Per Inch)

if (!dir.exists(OUTPUT_DIR)) {
  dir.create(OUTPUT_DIR)
}

message(paste("Output directory created at:", OUTPUT_DIR))

Data Object Initialization and Validation

This section simulates your pre-processed, Harmony-integrated Seurat object. We load a standard dataset and process it up to the clustering and UMAP stage.

# Load the PBMC 3k dataset (Placeholder for your Harmony-integrated object)
 ss.integrated <- readRDS("/home/nabbasi/cluster_home/PHD_3rd_YEAR_Analysis/0-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_final-26-10-2025.rds") # <-- REPLACE THIS LINE

I. Foundational Visualizations: Establishing Cellular Identity and Heterogeneity

These plots are essential for establishing the cellular landscape and validating cell type annotation.

1. Dimensionality Reduction Visualization (UMAP)

Purpose: Global visualization of cellular heterogeneity.

umap_cluster_plot <- DimPlot(ss.integrated, reduction = "umap", group.by = "seurat_clusters",label = TRUE, pt.size = 0.5) 

# Display plot in Rmd
print(umap_cluster_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "UMAP_Cluster.png"), plot = umap_cluster_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)
umap_cellline_plot <- DimPlot(ss.integrated, reduction = "umap", group.by = "orig.ident",label = TRUE, pt.size = 0.5) 

# Display plot in Rmd
print(umap_cellline_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "umap_cellline_plot.png"), plot = umap_cellline_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)
umap_cluster_A_plot <- DimPlot(ss.integrated, reduction = "umap", group.by = "renamed_clusters",label = F, pt.size = 0.5) 

# Display plot in Rmd
print(umap_cluster_A_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "umap_cluster_A_plot.png"), plot = umap_cluster_A_plot, width = 12, height = 6, dpi = PUB_RES)
library(SCpubr)
umap_cluster_plot <- SCpubr::do_DimPlot(ss.integrated, reduction = "umap", group.by = "seurat_clusters",label = TRUE, pt.size = 0.5, legend.position = "right") 

# Display plot in Rmd
print(umap_cluster_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "UMAP_Cluster-scpubr.png"), plot = umap_cluster_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)
library(SCpubr)
umap_cellline_plot <- SCpubr::do_DimPlot(ss.integrated, reduction = "umap", group.by = "orig.ident",label = TRUE, pt.size = 0.5, legend.position = "right") 

# Display plot in Rmd
print(umap_cellline_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "UMAP_cellline-scpubr.png"), plot = umap_cellline_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)
library(SCpubr)
umap_cluster_A_plot <- do_DimPlot(ss.integrated, reduction = "umap", group.by = "renamed_clusters",label = F, pt.size = 0.5, legend.position = "right") 

# Display plot in Rmd
print(umap_cluster_A_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "umap_cluster_A_plot-scpubr.png"), plot = umap_cluster_A_plot, width = 12, height = 6, dpi = PUB_RES)

2. Feature Plot: Gene Expression Mapping for Cell Type Confirmation

Purpose: Visualizes the expression level of a key gene across the UMAP space.

3. Marker Gene Expression: Dot Plot and Heatmap for Cluster Annotation

Purpose: Systematically compares the expression of top differentially expressed genes (DEGs) across all cell types for annotation confirmation.

library(dplyr)

# Precise blacklist for uninformative genes
blacklist_patterns <- c(
  "^TRAV", "^TRBV", "^TRGV", "^TRDV", "^TRBC", "^TRAC", "^TRDC", "^TRGC", # TCR
  "^IGH", "^IGK", "^IGL", "^IGJ",                                         # Ig genes
  "^RPL", "^RPS",                                                         # ribosomal
  "^MT-",                                                                 # mitochondria
  "^HBA", "^HBB", "^HB[ABZ]",                                             # hemoglobins
  "^NEAT1$", "^MALAT1$",                                                  # optional lncRNAs
  "^XIST$"                              )

blacklist_regex <- paste(blacklist_patterns, collapse = "|")

# Preview which markers will be removed
to_remove <- ss.integrated.markers %>%
  filter(grepl(blacklist_regex, gene, ignore.case = TRUE))
message("Rows to remove: ", nrow(to_remove))
head(to_remove$gene)
[1] "TRAV17"      "TRAV9-2"     "RPL22L1"     "NEAT1"       "TRAV38-2DV8" "TRGV2"      
# Filter markers (keep important metabolic/proliferation genes)
SS_markers_filtered <- ss.integrated.markers %>%
  filter(!grepl(blacklist_regex, gene, ignore.case = TRUE))

top5 <- SS_markers_filtered %>%
  filter(p_val_adj < 0.05) %>%  
  group_by(cluster) %>%
  slice_max(n = 5, order_by = avg_log2FC, with_ties = FALSE)

# Dot Plot
dot_plot_markers <- DotPlot(ss.integrated, features = unique(top5$gene)) +
  RotatedAxis() +
  ggtitle("Top Marker Gene Expression Across Cell Types")

# Display plot in Rmd
print(dot_plot_markers)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "DotPlot_Markers.png"), plot = dot_plot_markers, width = 26, height = 6, dpi = PUB_RES)

II. Quantitative and Comparative Visualizations

These plots are used to quantify differences between groups or visualize specific gene signatures.

4. Quantitative Analysis: Cell Type Composition Across Conditions

Purpose: Visualizes the change in the proportion of cell types across different conditions or samples (simulated here by ‘orig.ident’).

# Create a dummy 'orig.ident' column to simulate different samples/conditions
ss.integrated$orig.ident <- sample(c("L1", "L2", "L3", "L4", "L5", "L6", "L7"), size = ncol(ss.integrated), replace = TRUE)

cell_counts <- as.data.frame(table(ss.integrated$Prediction, ss.integrated$orig.ident))
names(cell_counts) <- c("Prediction", "orig.ident", "Count")

composition_plot <- ggplot(cell_counts, aes(x = orig.ident, y = Count, fill = Prediction)) +
  geom_bar(stat = "identity", position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(y = "Proportion of Cells", x = "Sample/Condition", fill = "Prediction") +
  ggtitle("Cell Type Composition Across Simulated Samples") +
  theme_classic() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

# Display plot in Rmd
print(composition_plot)

# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "CellComposition_BarPlot.png"), plot = composition_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

5. High-Resolution Density Visualization (Hexbin Plot)

Purpose: High-resolution density visualization for large datasets, overcoming point overlap (Borcherding et al. methodology).

library(schex)
# Requires the schex package
ss.integrated.hex <- make_hexbin(ss.integrated, nbins = 80, dimension_reduction = "UMAP")

# Plot density of a key marker (e.g., CD14 for Monocytes)
hexbin_plot_CD74 <- hexbin_plot(ss.integrated.hex, col = "CD74") +
  ggtitle("Hexbin Plot of CD14 Expression Density") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

# Display plot in Rmd
print(hexbin_plot_CD74)

# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "HexbinPlot_CD74_Density.png"), plot = hexbin_plot_CD74, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

III. Mechanistic and Trajectory Visualizations (Advanced Templates)

These advanced analyses require specialized packages and often additional data (TCR, CNV). The code below provides the structure and key functions.

6. Functional State Mapping: Pathway Activity Score (Module Score)

Purpose: Maps the functional state (e.g., proliferation, exhaustion) of cells onto the UMAP space.

# NOTE: This is a template using Seurat's AddModuleScore (similar to UCell/AUCell)
# We will use a dummy gene set for "T Cell Exhaustion" for demonstration purposes.
exhaustion_genes <- list(c("PDCD1", "CTLA4", "LAG3", "TIGIT", "HAVCR2"))

ss.integrated <- AddModuleScore(ss.integrated, features = exhaustion_genes, name = "Exhaustion_Score")

pathway_plot <- FeaturePlot(ss.integrated, features = "Exhaustion_Score1", pt.size = 0.5, reduction = "umap") +
  ggtitle("T Cell Exhaustion Pathway Activity Score") +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

# Display plot in Rmd
print(pathway_plot)


# Save high-resolution version
ggsave(paste0(OUTPUT_DIR, "PathwayActivity_Exhaustion.png"), plot = pathway_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

7. Pseudotime Trajectory Analysis (Monocle3 Template)

Purpose: Orders cells along a developmental or disease progression path (e.g., malignant T-cell evolution).

# NOTE: Requires monocle3 installation and the object to be converted.

# 1. Convert Seurat object to Monocle3 CellDataSet
# cds <- as.cell_data_set(ss.integrated)

# 2. Learn the graph structure
# cds <- learn_graph(cds, use_partition = TRUE)

# 3. Order cells by pseudotime (requires defining a root node)
# cds <- order_cells(cds, root_cells = colnames(ss.integrated)[ss.integrated$cell_type == "CD4 T cells"][1])

# 4. Plot the pseudotime trajectory
# trajectory_plot <- plot_cells(cds, color_cells_by = "pseudotime", label_groups_by_cluster = FALSE, cell_size = 0.5) +
#   ggtitle("Pseudotime Trajectory of T-cell Differentiation")

# ggsave(paste0(OUTPUT_DIR, "Monocle3_Pseudotime_Plot.png"), plot = trajectory_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

8. Intercellular Communication Network (CellChat Template)

Purpose: Summarizes the overall and specific ligand-receptor interactions between cell types in the TME.

# NOTE: Requires CellChat installation and a fully annotated object.

# 1. Prepare CellChat object
# cellchat <- createCellChat(object = ss.integrated, group.by = "cell_type", assay = "RNA")
# CellChatDB <- CellChatDB.human
# cellchat@DB <- CellChatDB

# 2. Compute and aggregate the network
# cellchat <- subsetData(cellchat)
# cellchat <- computeCommunProb(cellchat)
# cellchat <- aggregateNet(cellchat)

# 3. Visualize the overall network (Circle Plot)
# net_circle_plot <- netVisual_circle(cellchat@net$count,
#                                     vertex.weight = rowSums(cellchat@net$count),
#                                     weight.scale = TRUE,
#                                     label.edge = FALSE,
#                                     title.name = "Number of Interactions")

# ggsave(paste0(OUTPUT_DIR, "CellChat_Overall_Interactions.png"), plot = net_circle_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

# 4. Targeted Bubble Plot (e.g., for a key Sézary axis like CCL5-ACKR1)
# target_axis_plot <- netVisual_bubble(cellchat,
#                                      sources.use = c("CD4 T cells"),
#                                      targets.use = c("CD14 Monocytes"),
#                                      pairLR.use = data.frame(ligand = "CCL5", receptor = "ACKR1"))
# ggsave(paste0(OUTPUT_DIR, "CellChat_Targeted_Axis.png"), plot = target_axis_plot, width = PUB_WIDTH, height = PUB_HEIGHT, dpi = PUB_RES)

9. Clonal and Genetic Heterogeneity Visualizations (CNV/TCR Templates)

These are crucial for cancer-specific analysis (Herrera et al. and Su et al. methodologies).

# NOTE: These require specialized packages (copykat/InferCNV, scRepertoire)
# and often raw count data or external TCR data files.

# CNV Heatmap (for Malignant Cell Identification)
# CNV_heatmap_plot <- plot(copykat.obj$cnv.scores)
# ggsave(paste0(OUTPUT_DIR, "CNV_Inference_Heatmap.png"), plot = CNV_heatmap_plot, width = 12, height = 18, dpi = PUB_RES)

# TCR Clonal Heatmap (for Tracking Clonal Expansion)
# clonal_heatmap_plot <- clonal_heatmap(combined_tcr, cloneCall = "CTstrict", group.by = "cell_type")
# ggsave(paste0(OUTPUT_DIR, "TCR_Clonal_Heatmap.png"), plot = clonal_heatmap_plot, width = 10, height = 8, dpi = PUB_RES)

Conclusion and Next Steps

This R Markdown report demonstrates the core visualization pipeline for single-cell RNA-seq data in cancer genomics. By replacing the placeholder data loading with your Harmony-integrated object and installing the necessary advanced packages, you will be able to reproduce these publication-quality figures for your Sézary syndrome study. ```

LS0tCnRpdGxlOiAiUHVibGljYXRpb24tUmVhZHkgU2luZ2xlLUNlbGwgUk5BLXNlcSBWaXN1YWxpemF0aW9uIFBpcGVsaW5lOiBBbmFseXNpcyBvZiBIYXJtb255LUludGVncmF0ZWQgU2V1cmF0IE9iamVjdCIKYXV0aG9yOiAiTmFzaXIiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpcClRoaXMgUiBNYXJrZG93biBkb2N1bWVudCBvdXRsaW5lcyBhIGNvbXBsZXRlLCBzdGVwLWJ5LXN0ZXAgcGlwZWxpbmUgZm9yIGdlbmVyYXRpbmcgYWxsIGVzc2VudGlhbCBhbmQgYWR2YW5jZWQgc2luZ2xlLWNlbGwgUk5BLXNlcSB2aXN1YWxpemF0aW9ucyByZXF1aXJlZCBmb3IgYSBoaWdoLWltcGFjdCBwdWJsaWNhdGlvbiBpbiBjYW5jZXIgZ2Vub21pY3MuIFRoZSBtZXRob2RvbG9naWVzIGFyZSByaWdvcm91c2x5IGRlcml2ZWQgZnJvbSB0aGUgbGF0ZXN0IGxpdGVyYXR1cmUgKGUuZy4sIEhlcnJlcmEgZXQgYWwuLCBYdWUgZXQgYWwuLCBCb3JjaGVyZGluZyBldCBhbC4pLgoKKipDUklUSUNBTCBOT1RFIEZPUiBFWEVDVVRJT046KiogVGhpcyBzY3JpcHQgaXMgZGVzaWduZWQgdG8gb3BlcmF0ZSBvbiB5b3VyICoqSGFybW9ueS1pbnRlZ3JhdGVkIFNldXJhdCBvYmplY3QqKiwgd2hpY2ggaXMgYXNzdW1lZCB0byBiZSBuYW1lZCBgQWxsX3NhbXBsZXNfTWVyZ2VkYC4gVGhlIFIgY29kZSBiZWxvdyB1c2VzIGEgcGxhY2Vob2xkZXIgUEJNQyBkYXRhc2V0IHRvIGVuc3VyZSB0aGUgc2NyaXB0IGlzIGZ1bGx5IGV4ZWN1dGFibGUgYW5kIGRlbW9uc3RyYXRlcyB0aGUgZXhwZWN0ZWQgb3V0cHV0LiAqKlRvIHJ1biB0aGlzIHBpcGVsaW5lIG9uIHlvdXIgZGF0YSwgeW91IE1VU1QgcmVwbGFjZSB0aGUgcGxhY2Vob2xkZXIgZGF0YSBsb2FkaW5nIGFuZCBwcm9jZXNzaW5nIHN0ZXBzIGluIHRoZSBgZGF0YV9wcmVwYCBjaHVuayB3aXRoIHRoZSBjb21tYW5kIHRvIGxvYWQgeW91ciBvYmplY3Q6KiogXG5cbmBzcy5pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoInBhdGgvdG8veW91ci9BbGxfc2FtcGxlc19NZXJnZWQucmRzIilgXG5cbllvdXIgb2JqZWN0IGlzIGFzc3VtZWQgdG8gaGF2ZSBhIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBuYW1lZCBgaGFybW9ueWAgYW5kIGEgbWV0YWRhdGEgY29sdW1uIGZvciBjZWxsIHR5cGUgYW5ub3RhdGlvbiBuYW1lZCBgY2VsbF90eXBlYC4KCiMgU2V0dXAgYW5kIERhdGEgUHJlcGFyYXRpb24KClRoZSBmb2xsb3dpbmcgY2h1bmsgbG9hZHMgYWxsIG5lY2Vzc2FyeSBsaWJyYXJpZXMsIGRlZmluZXMgcHVibGljYXRpb24tcXVhbGl0eSBwYXJhbWV0ZXJzLCBhbmQgc2V0cyB1cCB0aGUgb3V0cHV0IGRpcmVjdG9yeS4KCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIExvYWQgTGlicmFyaWVzIChFbnN1cmUgdGhlc2UgYXJlIGluc3RhbGxlZCBpbiB5b3VyIFIgZW52aXJvbm1lbnQpCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNjaGV4KSAjIEZvciBIZXhiaW4gUGxvdHMKIyBsaWJyYXJ5KG1vbm9jbGUzKSAjIEZvciBUcmFqZWN0b3J5IEFuYWx5c2lzCiMgbGlicmFyeShDZWxsQ2hhdCkgIyBGb3IgQ2VsbC1DZWxsIENvbW11bmljYXRpb24KIyBsaWJyYXJ5KHNjUmVwZXJ0b2lyZSkgIyBGb3IgVENSIENsb25hbGl0eQoKIyAtLS0gRGVmaW5lIFB1YmxpY2F0aW9uIFBhcmFtZXRlcnMgLS0tCk9VVFBVVF9ESVIgPC0gIi4vcHVibGljYXRpb25fZmlndXJlcy8iClBVQl9XSURUSCA8LSAxMApQVUJfSEVJR0hUIDwtIDgKUFVCX1JFUyA8LSAzMDAgIyBEUEkgKERvdHMgUGVyIEluY2gpCgppZiAoIWRpci5leGlzdHMoT1VUUFVUX0RJUikpIHsKICBkaXIuY3JlYXRlKE9VVFBVVF9ESVIpCn0KCm1lc3NhZ2UocGFzdGUoIk91dHB1dCBkaXJlY3RvcnkgY3JlYXRlZCBhdDoiLCBPVVRQVVRfRElSKSkKYGBgCgojIyBEYXRhIE9iamVjdCBJbml0aWFsaXphdGlvbiBhbmQgVmFsaWRhdGlvbiAKClRoaXMgc2VjdGlvbiBzaW11bGF0ZXMgeW91ciBwcmUtcHJvY2Vzc2VkLCBIYXJtb255LWludGVncmF0ZWQgU2V1cmF0IG9iamVjdC4gV2UgbG9hZCBhIHN0YW5kYXJkIGRhdGFzZXQgYW5kIHByb2Nlc3MgaXQgdXAgdG8gdGhlIGNsdXN0ZXJpbmcgYW5kIFVNQVAgc3RhZ2UuCgpgYGB7ciBkYXRhX3ByZXAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgTG9hZCB0aGUgUEJNQyAzayBkYXRhc2V0IChQbGFjZWhvbGRlciBmb3IgeW91ciBIYXJtb255LWludGVncmF0ZWQgb2JqZWN0KQogc3MuaW50ZWdyYXRlZCA8LSByZWFkUkRTKCIvaG9tZS9uYWJiYXNpL2NsdXN0ZXJfaG9tZS9QSERfM3JkX1lFQVJfQW5hbHlzaXMvMC1TZXVyYXRfUkRTX09CSkVDVF9GSU5BTC9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9SZW5hbWVkX0NsdXN0ZXJzX2ZpbmFsLTI2LTEwLTIwMjUucmRzIikgIyA8LS0gUkVQTEFDRSBUSElTIExJTkUKCgptZXNzYWdlKCJQbGFjZWhvbGRlciBvYmplY3QgcmVhZHkgZm9yIHZpc3VhbGl6YXRpb24uIikKYGBgCgojIEkuIEZvdW5kYXRpb25hbCBWaXN1YWxpemF0aW9uczogRXN0YWJsaXNoaW5nIENlbGx1bGFyIElkZW50aXR5IGFuZCBIZXRlcm9nZW5laXR5CgpUaGVzZSBwbG90cyBhcmUgZXNzZW50aWFsIGZvciBlc3RhYmxpc2hpbmcgdGhlIGNlbGx1bGFyIGxhbmRzY2FwZSBhbmQgdmFsaWRhdGluZyBjZWxsIHR5cGUgYW5ub3RhdGlvbi4KCiMjIDEuIERpbWVuc2lvbmFsaXR5IFJlZHVjdGlvbiBWaXN1YWxpemF0aW9uIChVTUFQKQoKKipQdXJwb3NlOioqIEdsb2JhbCB2aXN1YWxpemF0aW9uIG9mIGNlbGx1bGFyIGhldGVyb2dlbmVpdHkuCgpgYGB7ciB1bWFwMSwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9Nn0KdW1hcF9jbHVzdGVyX3Bsb3QgPC0gRGltUGxvdChzcy5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsbGFiZWwgPSBUUlVFLCBwdC5zaXplID0gMC41KSAKCiMgRGlzcGxheSBwbG90IGluIFJtZApwcmludCh1bWFwX2NsdXN0ZXJfcGxvdCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJVTUFQX0NsdXN0ZXIucG5nIiksIHBsb3QgPSB1bWFwX2NsdXN0ZXJfcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCmBgYAoKYGBge3IgdW1hcDIsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9CnVtYXBfY2VsbGxpbmVfcGxvdCA8LSBEaW1QbG90KHNzLmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIsbGFiZWwgPSBUUlVFLCBwdC5zaXplID0gMC41KSAKCiMgRGlzcGxheSBwbG90IGluIFJtZApwcmludCh1bWFwX2NlbGxsaW5lX3Bsb3QpCgojIFNhdmUgaGlnaC1yZXNvbHV0aW9uIHZlcnNpb24KZ2dzYXZlKHBhc3RlMChPVVRQVVRfRElSLCAidW1hcF9jZWxsbGluZV9wbG90LnBuZyIpLCBwbG90ID0gdW1hcF9jZWxsbGluZV9wbG90LCB3aWR0aCA9IFBVQl9XSURUSCwgaGVpZ2h0ID0gUFVCX0hFSUdIVCwgZHBpID0gUFVCX1JFUykKYGBgCgpgYGB7ciB1bWFwMywgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CnVtYXBfY2x1c3Rlcl9BX3Bsb3QgPC0gRGltUGxvdChzcy5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInJlbmFtZWRfY2x1c3RlcnMiLGxhYmVsID0gRiwgcHQuc2l6ZSA9IDAuNSkgCgojIERpc3BsYXkgcGxvdCBpbiBSbWQKcHJpbnQodW1hcF9jbHVzdGVyX0FfcGxvdCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJ1bWFwX2NsdXN0ZXJfQV9wbG90LnBuZyIpLCBwbG90ID0gdW1hcF9jbHVzdGVyX0FfcGxvdCwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNiwgZHBpID0gUFVCX1JFUykKYGBgCgpgYGB7ciB1bWFwNCwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KbGlicmFyeShTQ3B1YnIpCnVtYXBfY2x1c3Rlcl9wbG90IDwtIFNDcHVicjo6ZG9fRGltUGxvdChzcy5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsbGFiZWwgPSBUUlVFLCBwdC5zaXplID0gMC41LCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAKCiMgRGlzcGxheSBwbG90IGluIFJtZApwcmludCh1bWFwX2NsdXN0ZXJfcGxvdCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJVTUFQX0NsdXN0ZXItc2NwdWJyLnBuZyIpLCBwbG90ID0gdW1hcF9jbHVzdGVyX3Bsb3QsIHdpZHRoID0gUFVCX1dJRFRILCBoZWlnaHQgPSBQVUJfSEVJR0hULCBkcGkgPSBQVUJfUkVTKQpgYGAKCgpgYGB7ciB1bWFwNSwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KbGlicmFyeShTQ3B1YnIpCnVtYXBfY2VsbGxpbmVfcGxvdCA8LSBTQ3B1YnI6OmRvX0RpbVBsb3Qoc3MuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IixsYWJlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUsIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpIAoKIyBEaXNwbGF5IHBsb3QgaW4gUm1kCnByaW50KHVtYXBfY2VsbGxpbmVfcGxvdCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJVTUFQX2NlbGxsaW5lLXNjcHVici5wbmciKSwgcGxvdCA9IHVtYXBfY2VsbGxpbmVfcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCmBgYApgYGB7ciB1bWFwNiwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTZ9CmxpYnJhcnkoU0NwdWJyKQp1bWFwX2NsdXN0ZXJfQV9wbG90IDwtIGRvX0RpbVBsb3Qoc3MuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJyZW5hbWVkX2NsdXN0ZXJzIixsYWJlbCA9IEYsIHB0LnNpemUgPSAwLjUsIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpIAoKIyBEaXNwbGF5IHBsb3QgaW4gUm1kCnByaW50KHVtYXBfY2x1c3Rlcl9BX3Bsb3QpCgojIFNhdmUgaGlnaC1yZXNvbHV0aW9uIHZlcnNpb24KZ2dzYXZlKHBhc3RlMChPVVRQVVRfRElSLCAidW1hcF9jbHVzdGVyX0FfcGxvdC1zY3B1YnIucG5nIiksIHBsb3QgPSB1bWFwX2NsdXN0ZXJfQV9wbG90LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2LCBkcGkgPSBQVUJfUkVTKQpgYGAKCiMjIDIuIEZlYXR1cmUgUGxvdDogR2VuZSBFeHByZXNzaW9uIE1hcHBpbmcgZm9yIENlbGwgVHlwZSBDb25maXJtYXRpb24KCioqUHVycG9zZToqKiBWaXN1YWxpemVzIHRoZSBleHByZXNzaW9uIGxldmVsIG9mIGEga2V5IGdlbmUgYWNyb3NzIHRoZSBVTUFQIHNwYWNlLgoKYGBge3IgZmVhdHVyZV9wbG90LCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MzZ9CiMgVXNpbmcgY2Fub25pY2FsIFBCTUMgbWFya2VycyBhcyBhIHN0YW5kLWluIGZvciB5b3VyIFNTLXNwZWNpZmljIG1hcmtlcnMKa2V5X21hcmtlcnMgPC0gYygiQ0QzRCIsICJDRDQiLCAiQ0Q4QSIsICJDRDciLCAiQ0Q0MCIsICJDRDQ0IiwiQ0Q3MCIsICJDRDc0IiAsICJDRDQ1UkEiLCAiQ0Q0NVJPIiwgICJEUFA0IiwgIktJUjNETDIiLCAiSUwyUkEiLCAiQ0QyNSIsICJUSUdJVCIsICJQRDEiLCJDRDI3NCIsICJDVExBNCIsICJIQVZDUjIiLCJFTlRQRDEiLCAiQ0NMMTciLCAiQ0NMNSIsICJJTDQiLCAiSUwxMyIsICAiSVJGNCIsICJJUkY3IiwgIkZPWFAzIiwgIkNMSUMxIiwgIllXSEFIIiwgIkNPWDVBIiwiR1RTRjEiLCAiU0xDMjVBNSIsIlBJSzNJUDEiLCAiUklQT1IyIiwgIlJBU0EzIiwgIkRHS0EiLCAiVFhOSVAiLCAiQ0RLTjFBIiwgIklUSyIsICJDRDY5IiwgIlNUQVQxIiwgIlRCWDIxIiwgIkdBVEEzIiwgIkdOTFkiLCAgIkNEMTQiLCAiQ0QxNiIsICJQTFMzIiwgIkNDUjQiLCAiQ0NSNyIsICJUT1giLCAiVFdJU1QxIiwgIlBSRjEiLCAiR1pNQSIsICJHWk1CIiwgIk1JRiIsICJITEEtRFJBIiwgIkhMQS1EUkIxIiwgIkNEODAiLCAiQ0Q4NiIsICJDSUlUQSIsICJUUDUzIiwgIlA1MyIsICJJTDdSIiwgIlNFTEwiLCAiTEVGMSIsICJUQ0Y3IiwgIkNES04yQSIsICJLTEYyIiwgIkNEMjciLCAiQ0QyOCIsICJMQ0siLCJaQVA3MCIsICIiKQoKZmVhdHVyZV9wbG90X21hcmtlciA8LSBGZWF0dXJlUGxvdChzcy5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGtleV9tYXJrZXJzLCBuY29sID0gNCwgcmVkdWN0aW9uID0gInVtYXAiKSAmCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQuaXRhbGljIikpCgojIERpc3BsYXkgcGxvdCBpbiBSbWQKcHJpbnQoZmVhdHVyZV9wbG90X21hcmtlcikKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJGZWF0dXJlUGxvdF9LZXlNYXJrZXJzLnBuZyIpLCBwbG90ID0gZmVhdHVyZV9wbG90X21hcmtlciwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMzYsIGRwaSA9IFBVQl9SRVMpCmBgYAoKIyMgMy4gTWFya2VyIEdlbmUgRXhwcmVzc2lvbjogRG90IFBsb3QgYW5kIEhlYXRtYXAgZm9yIENsdXN0ZXIgQW5ub3RhdGlvbgoKKipQdXJwb3NlOioqIFN5c3RlbWF0aWNhbGx5IGNvbXBhcmVzIHRoZSBleHByZXNzaW9uIG9mIHRvcCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgKERFR3MpIGFjcm9zcyBhbGwgY2VsbCB0eXBlcyBmb3IgYW5ub3RhdGlvbiBjb25maXJtYXRpb24uCgpgYGB7ciBtYXJrZXJfcGxvdHMsIGZpZy53aWR0aD0yNiwgZmlnLmhlaWdodD02fQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkocHJlc3RvKQojIEZpbmQgdG9wIDUgbWFya2VycyBwZXIgY2x1c3RlciAoZm9yIGRlbW9uc3RyYXRpb24pCnNzLmludGVncmF0ZWQubWFya2VycyA8LSBGaW5kQWxsTWFya2Vycyhzcy5pbnRlZ3JhdGVkLCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LG1pbi5kaWZmLnBjdCA9IDAuMiwgdmVyYm9zZSA9IEZBTFNFKQoKbGlicmFyeShkcGx5cikKCiMgUHJlY2lzZSBibGFja2xpc3QgZm9yIHVuaW5mb3JtYXRpdmUgZ2VuZXMKYmxhY2tsaXN0X3BhdHRlcm5zIDwtIGMoCiAgIl5UUkFWIiwgIl5UUkJWIiwgIl5UUkdWIiwgIl5UUkRWIiwgIl5UUkJDIiwgIl5UUkFDIiwgIl5UUkRDIiwgIl5UUkdDIiwgIyBUQ1IKICAiXklHSCIsICJeSUdLIiwgIl5JR0wiLCAiXklHSiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIElnIGdlbmVzCiAgIl5SUEwiLCAiXlJQUyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByaWJvc29tYWwKICAiXk1ULSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1pdG9jaG9uZHJpYQogICJeSEJBIiwgIl5IQkIiLCAiXkhCW0FCWl0iLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaGVtb2dsb2JpbnMKICAiXk5FQVQxJCIsICJeTUFMQVQxJCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9wdGlvbmFsIGxuY1JOQXMKICAiXlhJU1QkIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCmJsYWNrbGlzdF9yZWdleCA8LSBwYXN0ZShibGFja2xpc3RfcGF0dGVybnMsIGNvbGxhcHNlID0gInwiKQoKIyBQcmV2aWV3IHdoaWNoIG1hcmtlcnMgd2lsbCBiZSByZW1vdmVkCnRvX3JlbW92ZSA8LSBzcy5pbnRlZ3JhdGVkLm1hcmtlcnMgJT4lCiAgZmlsdGVyKGdyZXBsKGJsYWNrbGlzdF9yZWdleCwgZ2VuZSwgaWdub3JlLmNhc2UgPSBUUlVFKSkKbWVzc2FnZSgiUm93cyB0byByZW1vdmU6ICIsIG5yb3codG9fcmVtb3ZlKSkKaGVhZCh0b19yZW1vdmUkZ2VuZSkKCiMgRmlsdGVyIG1hcmtlcnMgKGtlZXAgaW1wb3J0YW50IG1ldGFib2xpYy9wcm9saWZlcmF0aW9uIGdlbmVzKQpTU19tYXJrZXJzX2ZpbHRlcmVkIDwtIHNzLmludGVncmF0ZWQubWFya2VycyAlPiUKICBmaWx0ZXIoIWdyZXBsKGJsYWNrbGlzdF9yZWdleCwgZ2VuZSwgaWdub3JlLmNhc2UgPSBUUlVFKSkKCnRvcDUgPC0gU1NfbWFya2Vyc19maWx0ZXJlZCAlPiUKICBmaWx0ZXIocF92YWxfYWRqIDwgMC4wNSkgJT4lICAKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICBzbGljZV9tYXgobiA9IDUsIG9yZGVyX2J5ID0gYXZnX2xvZzJGQywgd2l0aF90aWVzID0gRkFMU0UpCgojIERvdCBQbG90CmRvdF9wbG90X21hcmtlcnMgPC0gRG90UGxvdChzcy5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IHVuaXF1ZSh0b3A1JGdlbmUpKSArCiAgUm90YXRlZEF4aXMoKSArCiAgZ2d0aXRsZSgiVG9wIE1hcmtlciBHZW5lIEV4cHJlc3Npb24gQWNyb3NzIENlbGwgVHlwZXMiKQoKIyBEaXNwbGF5IHBsb3QgaW4gUm1kCnByaW50KGRvdF9wbG90X21hcmtlcnMpCgojIFNhdmUgaGlnaC1yZXNvbHV0aW9uIHZlcnNpb24KZ2dzYXZlKHBhc3RlMChPVVRQVVRfRElSLCAiRG90UGxvdF9NYXJrZXJzLnBuZyIpLCBwbG90ID0gZG90X3Bsb3RfbWFya2Vycywgd2lkdGggPSAyNiwgaGVpZ2h0ID0gNiwgZHBpID0gUFVCX1JFUykKCgoKYGBgCgojIElJLiBRdWFudGl0YXRpdmUgYW5kIENvbXBhcmF0aXZlIFZpc3VhbGl6YXRpb25zCgpUaGVzZSBwbG90cyBhcmUgdXNlZCB0byBxdWFudGlmeSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGdyb3VwcyBvciB2aXN1YWxpemUgc3BlY2lmaWMgZ2VuZSBzaWduYXR1cmVzLgoKIyMgNC4gUXVhbnRpdGF0aXZlIEFuYWx5c2lzOiBDZWxsIFR5cGUgQ29tcG9zaXRpb24gQWNyb3NzIENvbmRpdGlvbnMKCioqUHVycG9zZToqKiBWaXN1YWxpemVzIHRoZSBjaGFuZ2UgaW4gdGhlIHByb3BvcnRpb24gb2YgY2VsbCB0eXBlcyBhY3Jvc3MgZGlmZmVyZW50IGNvbmRpdGlvbnMgb3Igc2FtcGxlcyAoc2ltdWxhdGVkIGhlcmUgYnkgJ29yaWcuaWRlbnQnKS4KCmBgYHtyIGNvbXBvc2l0aW9uX3Bsb3QsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQojIENyZWF0ZSBhIGR1bW15ICdvcmlnLmlkZW50JyBjb2x1bW4gdG8gc2ltdWxhdGUgZGlmZmVyZW50IHNhbXBsZXMvY29uZGl0aW9ucwpzcy5pbnRlZ3JhdGVkJG9yaWcuaWRlbnQgPC0gc2FtcGxlKGMoIkwxIiwgIkwyIiwgIkwzIiwgIkw0IiwgIkw1IiwgIkw2IiwgIkw3IiksIHNpemUgPSBuY29sKHNzLmludGVncmF0ZWQpLCByZXBsYWNlID0gVFJVRSkKCmNlbGxfY291bnRzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc3MuaW50ZWdyYXRlZCRQcmVkaWN0aW9uLCBzcy5pbnRlZ3JhdGVkJG9yaWcuaWRlbnQpKQpuYW1lcyhjZWxsX2NvdW50cykgPC0gYygiUHJlZGljdGlvbiIsICJvcmlnLmlkZW50IiwgIkNvdW50IikKCmNvbXBvc2l0aW9uX3Bsb3QgPC0gZ2dwbG90KGNlbGxfY291bnRzLCBhZXMoeCA9IG9yaWcuaWRlbnQsIHkgPSBDb3VudCwgZmlsbCA9IFByZWRpY3Rpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogIGxhYnMoeSA9ICJQcm9wb3J0aW9uIG9mIENlbGxzIiwgeCA9ICJTYW1wbGUvQ29uZGl0aW9uIiwgZmlsbCA9ICJQcmVkaWN0aW9uIikgKwogIGdndGl0bGUoIkNlbGwgVHlwZSBDb21wb3NpdGlvbiBBY3Jvc3MgU2ltdWxhdGVkIFNhbXBsZXMiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkKCiMgRGlzcGxheSBwbG90IGluIFJtZApwcmludChjb21wb3NpdGlvbl9wbG90KQoKIyBTYXZlIGhpZ2gtcmVzb2x1dGlvbiB2ZXJzaW9uCmdnc2F2ZShwYXN0ZTAoT1VUUFVUX0RJUiwgIkNlbGxDb21wb3NpdGlvbl9CYXJQbG90LnBuZyIpLCBwbG90ID0gY29tcG9zaXRpb25fcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCmBgYAoKIyMgNS4gSGlnaC1SZXNvbHV0aW9uIERlbnNpdHkgVmlzdWFsaXphdGlvbiAoSGV4YmluIFBsb3QpCgoqKlB1cnBvc2U6KiogSGlnaC1yZXNvbHV0aW9uIGRlbnNpdHkgdmlzdWFsaXphdGlvbiBmb3IgbGFyZ2UgZGF0YXNldHMsIG92ZXJjb21pbmcgcG9pbnQgb3ZlcmxhcCAoQm9yY2hlcmRpbmcgZXQgYWwuIG1ldGhvZG9sb2d5KS4KCmBgYHtyIGhleGJpbl9wbG90LCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD03fQpsaWJyYXJ5KHNjaGV4KQojIFJlcXVpcmVzIHRoZSBzY2hleCBwYWNrYWdlCnNzLmludGVncmF0ZWQuaGV4IDwtIG1ha2VfaGV4YmluKHNzLmludGVncmF0ZWQsIG5iaW5zID0gODAsIGRpbWVuc2lvbl9yZWR1Y3Rpb24gPSAiVU1BUCIpCgojIFBsb3QgZGVuc2l0eSBvZiBhIGtleSBtYXJrZXIgKGUuZy4sIENEMTQgZm9yIE1vbm9jeXRlcykKaGV4YmluX3Bsb3RfQ0Q3NCA8LSBoZXhiaW5fcGxvdChzcy5pbnRlZ3JhdGVkLmhleCwgY29sID0gIkNENzQiKSArCiAgZ2d0aXRsZSgiSGV4YmluIFBsb3Qgb2YgQ0QxNCBFeHByZXNzaW9uIERlbnNpdHkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpCgojIERpc3BsYXkgcGxvdCBpbiBSbWQKcHJpbnQoaGV4YmluX3Bsb3RfQ0Q3NCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJIZXhiaW5QbG90X0NENzRfRGVuc2l0eS5wbmciKSwgcGxvdCA9IGhleGJpbl9wbG90X0NENzQsIHdpZHRoID0gUFVCX1dJRFRILCBoZWlnaHQgPSBQVUJfSEVJR0hULCBkcGkgPSBQVUJfUkVTKQpgYGAKCiMgSUlJLiBNZWNoYW5pc3RpYyBhbmQgVHJhamVjdG9yeSBWaXN1YWxpemF0aW9ucyAoQWR2YW5jZWQgVGVtcGxhdGVzKQoKVGhlc2UgYWR2YW5jZWQgYW5hbHlzZXMgcmVxdWlyZSBzcGVjaWFsaXplZCBwYWNrYWdlcyBhbmQgb2Z0ZW4gYWRkaXRpb25hbCBkYXRhIChUQ1IsIENOVikuIFRoZSBjb2RlIGJlbG93IHByb3ZpZGVzIHRoZSBzdHJ1Y3R1cmUgYW5kIGtleSBmdW5jdGlvbnMuCgojIyA2LiBGdW5jdGlvbmFsIFN0YXRlIE1hcHBpbmc6IFBhdGh3YXkgQWN0aXZpdHkgU2NvcmUgKE1vZHVsZSBTY29yZSkKCioqUHVycG9zZToqKiBNYXBzIHRoZSBmdW5jdGlvbmFsIHN0YXRlIChlLmcuLCBwcm9saWZlcmF0aW9uLCBleGhhdXN0aW9uKSBvZiBjZWxscyBvbnRvIHRoZSBVTUFQIHNwYWNlLgoKYGBge3IgcGF0aHdheV9hY3Rpdml0eSwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9N30KIyBOT1RFOiBUaGlzIGlzIGEgdGVtcGxhdGUgdXNpbmcgU2V1cmF0J3MgQWRkTW9kdWxlU2NvcmUgKHNpbWlsYXIgdG8gVUNlbGwvQVVDZWxsKQojIFdlIHdpbGwgdXNlIGEgZHVtbXkgZ2VuZSBzZXQgZm9yICJUIENlbGwgRXhoYXVzdGlvbiIgZm9yIGRlbW9uc3RyYXRpb24gcHVycG9zZXMuCmV4aGF1c3Rpb25fZ2VuZXMgPC0gbGlzdChjKCJQRENEMSIsICJDVExBNCIsICJMQUczIiwgIlRJR0lUIiwgIkhBVkNSMiIpKQoKc3MuaW50ZWdyYXRlZCA8LSBBZGRNb2R1bGVTY29yZShzcy5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGV4aGF1c3Rpb25fZ2VuZXMsIG5hbWUgPSAiRXhoYXVzdGlvbl9TY29yZSIpCgpwYXRod2F5X3Bsb3QgPC0gRmVhdHVyZVBsb3Qoc3MuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiRXhoYXVzdGlvbl9TY29yZTEiLCBwdC5zaXplID0gMC41LCByZWR1Y3Rpb24gPSAidW1hcCIpICsKICBnZ3RpdGxlKCJUIENlbGwgRXhoYXVzdGlvbiBQYXRod2F5IEFjdGl2aXR5IFNjb3JlIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQoKIyBEaXNwbGF5IHBsb3QgaW4gUm1kCnByaW50KHBhdGh3YXlfcGxvdCkKCiMgU2F2ZSBoaWdoLXJlc29sdXRpb24gdmVyc2lvbgpnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJQYXRod2F5QWN0aXZpdHlfRXhoYXVzdGlvbi5wbmciKSwgcGxvdCA9IHBhdGh3YXlfcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCmBgYAoKIyMgNy4gUHNldWRvdGltZSBUcmFqZWN0b3J5IEFuYWx5c2lzIChNb25vY2xlMyBUZW1wbGF0ZSkKCioqUHVycG9zZToqKiBPcmRlcnMgY2VsbHMgYWxvbmcgYSBkZXZlbG9wbWVudGFsIG9yIGRpc2Vhc2UgcHJvZ3Jlc3Npb24gcGF0aCAoZS5nLiwgbWFsaWduYW50IFQtY2VsbCBldm9sdXRpb24pLgoKYGBge3IgdHJhamVjdG9yeV90ZW1wbGF0ZSwgZXZhbD1GQUxTRX0KIyBOT1RFOiBSZXF1aXJlcyBtb25vY2xlMyBpbnN0YWxsYXRpb24gYW5kIHRoZSBvYmplY3QgdG8gYmUgY29udmVydGVkLgoKIyAxLiBDb252ZXJ0IFNldXJhdCBvYmplY3QgdG8gTW9ub2NsZTMgQ2VsbERhdGFTZXQKIyBjZHMgPC0gYXMuY2VsbF9kYXRhX3NldChzcy5pbnRlZ3JhdGVkKQoKIyAyLiBMZWFybiB0aGUgZ3JhcGggc3RydWN0dXJlCiMgY2RzIDwtIGxlYXJuX2dyYXBoKGNkcywgdXNlX3BhcnRpdGlvbiA9IFRSVUUpCgojIDMuIE9yZGVyIGNlbGxzIGJ5IHBzZXVkb3RpbWUgKHJlcXVpcmVzIGRlZmluaW5nIGEgcm9vdCBub2RlKQojIGNkcyA8LSBvcmRlcl9jZWxscyhjZHMsIHJvb3RfY2VsbHMgPSBjb2xuYW1lcyhzcy5pbnRlZ3JhdGVkKVtzcy5pbnRlZ3JhdGVkJGNlbGxfdHlwZSA9PSAiQ0Q0IFQgY2VsbHMiXVsxXSkKCiMgNC4gUGxvdCB0aGUgcHNldWRvdGltZSB0cmFqZWN0b3J5CiMgdHJhamVjdG9yeV9wbG90IDwtIHBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIiwgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSwgY2VsbF9zaXplID0gMC41KSArCiMgICBnZ3RpdGxlKCJQc2V1ZG90aW1lIFRyYWplY3Rvcnkgb2YgVC1jZWxsIERpZmZlcmVudGlhdGlvbiIpCgojIGdnc2F2ZShwYXN0ZTAoT1VUUFVUX0RJUiwgIk1vbm9jbGUzX1BzZXVkb3RpbWVfUGxvdC5wbmciKSwgcGxvdCA9IHRyYWplY3RvcnlfcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCmBgYAoKIyMgOC4gSW50ZXJjZWxsdWxhciBDb21tdW5pY2F0aW9uIE5ldHdvcmsgKENlbGxDaGF0IFRlbXBsYXRlKQoKKipQdXJwb3NlOioqIFN1bW1hcml6ZXMgdGhlIG92ZXJhbGwgYW5kIHNwZWNpZmljIGxpZ2FuZC1yZWNlcHRvciBpbnRlcmFjdGlvbnMgYmV0d2VlbiBjZWxsIHR5cGVzIGluIHRoZSBUTUUuCgpgYGB7ciBjZWxsY2hhdF90ZW1wbGF0ZSwgZXZhbD1GQUxTRX0KIyBOT1RFOiBSZXF1aXJlcyBDZWxsQ2hhdCBpbnN0YWxsYXRpb24gYW5kIGEgZnVsbHkgYW5ub3RhdGVkIG9iamVjdC4KCiMgMS4gUHJlcGFyZSBDZWxsQ2hhdCBvYmplY3QKIyBjZWxsY2hhdCA8LSBjcmVhdGVDZWxsQ2hhdChvYmplY3QgPSBzcy5pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJjZWxsX3R5cGUiLCBhc3NheSA9ICJSTkEiKQojIENlbGxDaGF0REIgPC0gQ2VsbENoYXREQi5odW1hbgojIGNlbGxjaGF0QERCIDwtIENlbGxDaGF0REIKCiMgMi4gQ29tcHV0ZSBhbmQgYWdncmVnYXRlIHRoZSBuZXR3b3JrCiMgY2VsbGNoYXQgPC0gc3Vic2V0RGF0YShjZWxsY2hhdCkKIyBjZWxsY2hhdCA8LSBjb21wdXRlQ29tbXVuUHJvYihjZWxsY2hhdCkKIyBjZWxsY2hhdCA8LSBhZ2dyZWdhdGVOZXQoY2VsbGNoYXQpCgojIDMuIFZpc3VhbGl6ZSB0aGUgb3ZlcmFsbCBuZXR3b3JrIChDaXJjbGUgUGxvdCkKIyBuZXRfY2lyY2xlX3Bsb3QgPC0gbmV0VmlzdWFsX2NpcmNsZShjZWxsY2hhdEBuZXQkY291bnQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVydGV4LndlaWdodCA9IHJvd1N1bXMoY2VsbGNoYXRAbmV0JGNvdW50KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQuc2NhbGUgPSBUUlVFLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLmVkZ2UgPSBGQUxTRSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5uYW1lID0gIk51bWJlciBvZiBJbnRlcmFjdGlvbnMiKQoKIyBnZ3NhdmUocGFzdGUwKE9VVFBVVF9ESVIsICJDZWxsQ2hhdF9PdmVyYWxsX0ludGVyYWN0aW9ucy5wbmciKSwgcGxvdCA9IG5ldF9jaXJjbGVfcGxvdCwgd2lkdGggPSBQVUJfV0lEVEgsIGhlaWdodCA9IFBVQl9IRUlHSFQsIGRwaSA9IFBVQl9SRVMpCgojIDQuIFRhcmdldGVkIEJ1YmJsZSBQbG90IChlLmcuLCBmb3IgYSBrZXkgU8OpemFyeSBheGlzIGxpa2UgQ0NMNS1BQ0tSMSkKIyB0YXJnZXRfYXhpc19wbG90IDwtIG5ldFZpc3VhbF9idWJibGUoY2VsbGNoYXQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMudXNlID0gYygiQ0Q0IFQgY2VsbHMiKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0cy51c2UgPSBjKCJDRDE0IE1vbm9jeXRlcyIpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWlyTFIudXNlID0gZGF0YS5mcmFtZShsaWdhbmQgPSAiQ0NMNSIsIHJlY2VwdG9yID0gIkFDS1IxIikpCiMgZ2dzYXZlKHBhc3RlMChPVVRQVVRfRElSLCAiQ2VsbENoYXRfVGFyZ2V0ZWRfQXhpcy5wbmciKSwgcGxvdCA9IHRhcmdldF9heGlzX3Bsb3QsIHdpZHRoID0gUFVCX1dJRFRILCBoZWlnaHQgPSBQVUJfSEVJR0hULCBkcGkgPSBQVUJfUkVTKQpgYGAKCiMjIDkuIENsb25hbCBhbmQgR2VuZXRpYyBIZXRlcm9nZW5laXR5IFZpc3VhbGl6YXRpb25zIChDTlYvVENSIFRlbXBsYXRlcykKClRoZXNlIGFyZSBjcnVjaWFsIGZvciBjYW5jZXItc3BlY2lmaWMgYW5hbHlzaXMgKEhlcnJlcmEgZXQgYWwuIGFuZCBTdSBldCBhbC4gbWV0aG9kb2xvZ2llcykuCgpgYGB7ciBjbnZfdGNyX3RlbXBsYXRlcywgZXZhbD1GQUxTRX0KIyBOT1RFOiBUaGVzZSByZXF1aXJlIHNwZWNpYWxpemVkIHBhY2thZ2VzIChjb3B5a2F0L0luZmVyQ05WLCBzY1JlcGVydG9pcmUpCiMgYW5kIG9mdGVuIHJhdyBjb3VudCBkYXRhIG9yIGV4dGVybmFsIFRDUiBkYXRhIGZpbGVzLgoKIyBDTlYgSGVhdG1hcCAoZm9yIE1hbGlnbmFudCBDZWxsIElkZW50aWZpY2F0aW9uKQojIENOVl9oZWF0bWFwX3Bsb3QgPC0gcGxvdChjb3B5a2F0Lm9iaiRjbnYuc2NvcmVzKQojIGdnc2F2ZShwYXN0ZTAoT1VUUFVUX0RJUiwgIkNOVl9JbmZlcmVuY2VfSGVhdG1hcC5wbmciKSwgcGxvdCA9IENOVl9oZWF0bWFwX3Bsb3QsIHdpZHRoID0gMTIsIGhlaWdodCA9IDE4LCBkcGkgPSBQVUJfUkVTKQoKIyBUQ1IgQ2xvbmFsIEhlYXRtYXAgKGZvciBUcmFja2luZyBDbG9uYWwgRXhwYW5zaW9uKQojIGNsb25hbF9oZWF0bWFwX3Bsb3QgPC0gY2xvbmFsX2hlYXRtYXAoY29tYmluZWRfdGNyLCBjbG9uZUNhbGwgPSAiQ1RzdHJpY3QiLCBncm91cC5ieSA9ICJjZWxsX3R5cGUiKQojIGdnc2F2ZShwYXN0ZTAoT1VUUFVUX0RJUiwgIlRDUl9DbG9uYWxfSGVhdG1hcC5wbmciKSwgcGxvdCA9IGNsb25hbF9oZWF0bWFwX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaSA9IFBVQl9SRVMpCmBgYAoKIyBDb25jbHVzaW9uIGFuZCBOZXh0IFN0ZXBzCgpUaGlzIFIgTWFya2Rvd24gcmVwb3J0IGRlbW9uc3RyYXRlcyB0aGUgY29yZSB2aXN1YWxpemF0aW9uIHBpcGVsaW5lIGZvciBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGEgaW4gY2FuY2VyIGdlbm9taWNzLiBCeSByZXBsYWNpbmcgdGhlIHBsYWNlaG9sZGVyIGRhdGEgbG9hZGluZyB3aXRoIHlvdXIgSGFybW9ueS1pbnRlZ3JhdGVkIG9iamVjdCBhbmQgaW5zdGFsbGluZyB0aGUgbmVjZXNzYXJ5IGFkdmFuY2VkIHBhY2thZ2VzLCB5b3Ugd2lsbCBiZSBhYmxlIHRvIHJlcHJvZHVjZSB0aGVzZSBwdWJsaWNhdGlvbi1xdWFsaXR5IGZpZ3VyZXMgZm9yIHlvdXIgU8OpemFyeSBzeW5kcm9tZSBzdHVkeS4KXGBcYFxgCg==