Introduction

This R Markdown script provides the complete, executable code and interpretation guidance to perform the single-cell RNA sequencing (scRNA-seq) analysis on All_samples_Merged Seurat object. The goal is to achieve a robust T cell annotation and answer specific questions regarding Sezary cell phenotype, cell line heterogeneity, and the drivers of expression clustering.

Prerequisite: Ensure the All_samples_Merged Seurat object is loaded into your R environment before running the chunks below.

Setup and Data Loading

We will use the Seurat package for core scRNA-seq analysis, dplyr for data manipulation, and ggplot2 for visualization.

# Load necessary libraries
library(Seurat)
library(dplyr)
library(ggplot2)
library(patchwork)
library(Matrix)

# IMPORTANT: Replace this with the actual path and command to load your object
All_samples_Merged <- readRDS("../../../PHD_3rd_YEAR_Analysis/0-Seurat_RDS_OBJECT_FINAL/All_samples_Merged_with_Renamed_Clusters_final-26-10-2025.rds")
# Placeholder:
if (!exists("All_samples_Merged")) {
  stop("The 'All_samples_Merged' Seurat object is not loaded. Please load your data.")
}

# Check the object structure
print(All_samples_Merged)
An object of class Seurat 
62900 features across 49305 samples within 6 assays 
Active assay: RNA (36601 features, 0 variable features)
 2 layers present: data, counts
 5 other assays present: ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony

Phase 1: Robust T Cell Annotation and Subsetting

The first critical step is to isolate the T cell population and re-run the clustering workflow to maximize resolution within this specific lineage.

1 T Cell Subsetting

We subset based on the expression of pan-T cell markers (CD3D, CD3E, CD3G).

# Identify cells expressing at least one of the pan-T cell markers
T_cells <- subset(All_samples_Merged, subset = CD3D > 0 | CD3E > 0 | CD3G > 0)

# Check the number of T cells retained
cat("Number of T cells retained:", ncol(T_cells), "\n")
Number of T cells retained: 48386 
# Visualize the new T cell clusters
DimPlot(T_cells, reduction = "umap", label = F) 

# Visualize the new T cell clusters

FeaturePlot(T_cells, features = c("CD4", "CD8A", "FOXP3", "KIR3DL2"), reduction = "umap")

Interpretation Guidance (Phase 1): * UMAP: Visually inspect the clusters. Are they well-separated? * Feature Plots: Use known markers (e.g., CD4, CD8A, FOXP3, CCR7, GZMB) to assign initial identities (CD4+, CD8+, Treg, Naive, Effector). * Marker Identification: Use FindAllMarkers(T_cells, only.pos = TRUE) to get a list of genes for each cluster and finalize the annotation. You must add a new column to the metadata, e.g., T_cells$cell_subtype, with the final, robust annotations (e.g., “CD4_Naive”, “CD8_Exhausted”, “Treg”, “Sezary_Malignant”).

Phase 2: Sezary Cell and Treg-like Phenotype Check

We will check if the identified Sezary cell cluster(s) (likely CD4+ and expressing markers like KIR3DL2 or having a unique malignant signature) exhibit a T regulatory cell (Treg) phenotype.

2.1 Calculate Treg Module Score

A module score is a robust way to quantify the expression of a gene set.

# Define the core Treg gene signature
Treg_genes <- c("FOXP3", "IL2RA", "CTLA4", "TIGIT")

# Calculate the module score
T_cells <- AddModuleScore(
  object = T_cells,
  features = list(Treg_genes),
  name = "Treg_Score"
)

# Rename the score column for simplicity
T_cells$Treg_Score <- T_cells$Treg_Score1

2.2 Compare Treg Score Distribution

We compare the Treg score across all clusters, paying close attention to the Sezary cluster(s) and the bona fide Treg cluster(s).

# Visualize the distribution of the Treg score per cluster
VlnPlot(T_cells, features = "Treg_Score", group.by = "seurat_clusters", pt.size = 0) +
  geom_boxplot(width = 0.1, outlier.shape = NA) +
  labs(title = "Treg Signature Score Distribution by Cluster")


# Statistical comparison (e.g., comparing Sezary cluster to canonical Treg cluster)
# *NOTE: Replace "Sezary Cluster ID" and "Treg Cluster ID" with your actual cluster numbers/names*
wilcox.test(T_cells$Treg_Score[T_cells$seurat_clusters == "2"],
             T_cells$Treg_Score[T_cells$seurat_clusters == "6"])

    Wilcoxon rank sum test with continuity correction

data:  T_cells$Treg_Score[T_cells$seurat_clusters == "2"] and T_cells$Treg_Score[T_cells$seurat_clusters == "6"]
W = 9672619, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

# Statistical comparison (e.g., comparing Sezary cluster to canonical Treg cluster)
# *NOTE: Replace "Sezary Cluster ID" and "Treg Cluster ID" with your actual cluster numbers/names*
wilcox.test(T_cells$Treg_Score[T_cells$seurat_clusters == "2"],
             T_cells$Treg_Score[T_cells$seurat_clusters == "8"])

    Wilcoxon rank sum test with continuity correction

data:  T_cells$Treg_Score[T_cells$seurat_clusters == "2"] and T_cells$Treg_Score[T_cells$seurat_clusters == "8"]
W = 4951569, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
# Statistical comparison (e.g., comparing Sezary cluster to canonical Treg cluster)
# *NOTE: Replace "Sezary Cluster ID" and "Treg Cluster ID" with your actual cluster numbers/names*
wilcox.test(T_cells$Treg_Score[T_cells$seurat_clusters == "6"],
             T_cells$Treg_Score[T_cells$seurat_clusters == "8"])

    Wilcoxon rank sum test with continuity correction

data:  T_cells$Treg_Score[T_cells$seurat_clusters == "6"] and T_cells$Treg_Score[T_cells$seurat_clusters == "8"]
W = 2515212, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
# Statistical comparison (e.g., comparing Sezary cluster to canonical Treg cluster)
# *NOTE: Replace "Sezary Cluster ID" and "Treg Cluster ID" with your actual cluster numbers/names*
wilcox.test(T_cells$Treg_Score[T_cells$seurat_clusters == "5"],
             T_cells$Treg_Score[T_cells$seurat_clusters == "1"])

    Wilcoxon rank sum test with continuity correction

data:  T_cells$Treg_Score[T_cells$seurat_clusters == "5"] and T_cells$Treg_Score[T_cells$seurat_clusters == "1"]
W = 14625089, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

Interpretation Guidance (Phase 2): * VlnPlot: If the Sezary cluster shows a high median Treg score, comparable to or higher than the canonical Treg cluster, it suggests a Treg-like immunosuppressive phenotype. * Statistical Test: A significant p-value (e.g., p < 0.05) from the Wilcoxon test confirms a statistically different (or similar, depending on the means) expression of the Treg signature between the two populations.

Phase 3: Distribution of Cell Lines in T Cell States

This answers the question: “Could you show the distribution for each cell lines in T cell state?”

3.1 Calculate Proportions

We calculate the proportion of each T cell cluster within each cell line (patient origin). Ensure your cell line/patient origin information is in a metadata column named cell_line.

# Calculate the raw counts of cells per cluster per cell line
count_table <- table(T_cells$seurat_clusters, T_cells$cell_line)

# Calculate the proportion (margin = 2 means proportions within each column, i.e., within each cell line)
prop_table <- prop.table(count_table, margin = 2)

# Convert to data frame for plotting
prop_df <- as.data.frame(prop_table) %>%
  rename(Cluster = Var1, CellLine = Var2, Proportion = Freq)

# Display the first few rows of the proportion table
head(prop_df)

3.2 Visualize Distribution

# Stacked bar plot visualization
ggplot(prop_df, aes(x = CellLine, y = Proportion, fill = Cluster)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(title = "T Cell Cluster Composition by Cell Line (Patient Origin)",
       y = "Proportion of Total T Cells per Line") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Interpretation Guidance (Phase 3): * Stacked Bar Plot: Look for dominant clusters in specific cell lines. For example, if Cell Line A is 80% “Sezary_Malignant” but Cell Line B is only 20%, it indicates a significant difference in the purity or in vitro differentiation state of the cell lines. This heterogeneity will be the basis for the next clustering step.

Phase 4: Unsupervised Clustering of Cell Lines (Pseudobulk)

This addresses: “Could you make an unsupervised clustering of our cell lines based upon expression?” We treat each cell line as a single sample and cluster them based on their overall gene expression profile.

4.1 Aggregate Expression (Pseudobulk)

# Calculate the average expression for all genes across all T cells, grouped by 'cell_line'
# We use the 'data' slot (normalized expression)
pseudobulk <- AverageExpression(T_cells,
                                group.by = "cell_line",
                                assays = "RNA",
                                slot = "data")

# Extract the expression matrix and transpose it (Cell Lines as rows, Genes as columns)
pb_matrix <- as.matrix(pseudobulk$RNA)
pb_matrix_t <- t(pb_matrix)

4.2 Dimensionality Reduction and Hierarchical Clustering

# Perform PCA on the pseudobulk matrix
# scale. = TRUE standardizes the gene expression across cell lines
pb_pca <- prcomp(pb_matrix_t, scale. = TRUE)
Error in prcomp.default(pb_matrix_t, scale. = TRUE) : 
  cannot rescale a constant/zero column to unit variance

Interpretation Guidance (Phase 4): * PCA Plot: Cell lines that group closely together share similar overall gene expression profiles. * Dendrogram: The branches show the similarity. Cell lines joining early are highly similar. Cutting the tree (e.g., k=3) defines the Cell Line Clusters (e.g., “Cluster A”, “Cluster B”, “Cluster C”).

Phase 5: Defining Cluster-Specific Genes and Shared Clusters

This addresses: “define clusters that we observe, a list of genes that we have in each clusters? Maybe we have clusters that are shared with cell lines derived from other patients?”

5.1 Marker Genes for T Cell Subtypes (Review)

You should have already done this in Phase 1, but here is the code to re-run and extract the top markers for the single-cell clusters.

# Find markers for all single-cell clusters
T_cells.markers <- FindAllMarkers(T_cells,
                                  only.pos = TRUE,
                                  min.pct = 0.25,
                                  logfc.threshold = 0.25)

# Get the top 10 markers per cluster
top10 <- T_cells.markers %>%
  group_by(cluster) %>%
  top_n(n = 10, wt = avg_log2FC)

# Print the top markers for review
print(top10)
# Find markers for all single-cell clusters
T_cells.markers <- FindAllMarkers(T_cells,
                                  group.by = "cell_line",
                                  only.pos = TRUE,
                                  min.pct = 0.25,
                                  logfc.threshold = 0.25)

# Get the top 10 markers per cluster
top10_cl <- T_cells.markers %>%
  group_by(cluster) %>%
  top_n(n = 10, wt = avg_log2FC)

# Print the top markers for review
print(top10_cl)

5.2 Marker Genes for Cell Line Clusters (The New Insight)

We now want to find the genes that define the Cell Line Clusters identified in Phase 4.

# Now, find markers between the Cell Line Clusters
line_cluster_markers <- FindAllMarkers(T_cells,
                                       group.by = "line_cluster",
                                       only.pos = TRUE,
                                       min.pct = 0.25,
                                       logfc.threshold = 0.25)
Error in FindAllMarkers(T_cells, group.by = "line_cluster", only.pos = TRUE,  : 
  'line_cluster' not found in object metadata

Interpretation Guidance (Phase 5): * Gene List: The top10_line_markers list is the answer to the “list of genes that we have in each clusters” question, but for the cell line clusters. These genes represent the core biological differences between the groups of cell lines. * Shared Clusters: To check if these clusters are “shared with cell lines derived from other patients,” you need to manually search the top marker genes (e.g., S100A4, GZMB, FOXP3) in public databases (e.g., GEO, literature) for known T cell states or malignant signatures. If the marker list for “Line Cluster A” matches a known signature (e.g., “Interferon Response Signature”), then the cluster is not unique to your patient cohort.

Phase 6: Testing Metadata as Explanatory Variables for Clustering

This addresses: “Could you test metadata that could explain the clustering, instead of only patient origin? Like all the parameters that you have in metadata and also composition in T cell immunophenotype…”

6.1 Prepare Metadata for Modeling

We need a table where each row is a cell line, and columns contain: 1. The PC scores (quantitative representation of the clustering from Phase 4). 2. The proportion of each T cell subtype (immunophenotype composition from Phase 3). 3. Any other relevant metadata (e.g., age, sex, treatment status, batch).

# 1. Get PC scores (quantitative clustering)
cell_line_pcs <- data.frame(pb_pca$x) %>%
  rownames_to_column("cell_line") %>%
  select(cell_line, PC1, PC2, PC3) # Use the top PCs that explain most variance

# 2. Get T cell immunophenotype composition (proportions from Phase 3)
# *NOTE: This assumes you have finalized the 'cell_subtype' column in Phase 1*
cell_subtype_counts <- T_cells@meta.data %>%
  group_by(cell_line, cell_subtype) %>%
  summarise(Count = n(), .groups = 'drop')

cell_subtype_proportions <- cell_subtype_counts %>%
  group_by(cell_line) %>%
  mutate(Total = sum(Count),
         Proportion = Count / Total) %>%
  select(cell_line, cell_subtype, Proportion) %>%
  # Widen the table so each cell subtype proportion is a column
  tidyr::pivot_wider(names_from = cell_subtype, values_from = Proportion, values_fill = 0) %>%
  rename_with(~paste0("Prop_", .), -cell_line) # Prefix column names

# 3. Get other metadata (e.g., Age, Sex)
# *NOTE: Replace "Age" and "Sex" with actual column names from your All_samples_Merged metadata*
other_metadata <- T_cells@meta.data %>%
  select(cell_line, Age, Sex, Batch) %>%
  distinct() # Ensure only one row per cell line

# 4. Merge all data into the final model table
model_data <- cell_line_pcs %>%
  left_join(cell_subtype_proportions, by = "cell_line") %>%
  left_join(other_metadata, by = "cell_line")

print(head(model_data))

6.2 Statistical Modeling

We use a linear model to test if the metadata variables (e.g., Prop_Treg, Age) significantly predict the cell line’s expression profile, represented by its PC scores.

# Test PC1 (the primary driver of the cell line clustering) against all predictors
# We test the T cell composition (e.g., Prop_Treg) and other metadata (e.g., Age)
# *NOTE: Adjust the formula to include all relevant metadata columns*
lm_model_pc1 <- lm(PC1 ~ Prop_Treg + Prop_Sezary_Malignant + Age + Sex + Batch, data = model_data)

# View the results
summary(lm_model_pc1)

# You can repeat this for PC2, PC3, etc.
# lm_model_pc2 <- lm(PC2 ~ Prop_Treg + Prop_Sezary_Malignant + Age + Sex + Batch, data = model_data)
# summary(lm_model_pc2)

Interpretation Guidance (Phase 6): * summary(lm_model_pc1): Focus on the p-value (Pr(>|t|)) for each predictor variable (e.g., Prop_Treg). * Significant Predictor (p < 0.05): If a variable like Prop_Treg has a low p-value, it means the proportion of Tregs in a cell line is a significant predictor of where that cell line falls in the expression clustering space (PC1). This suggests that the biological difference captured by PC1 (the clustering) is explained by the underlying T cell immunophenotype composition, independent of the simple “patient origin” label. * Coefficient (Estimate): The sign of the coefficient indicates the direction. A positive coefficient for Prop_Treg means cell lines with a higher proportion of Tregs tend to have a higher PC1 score.

Conclusion

This script provides a comprehensive framework to move from robust annotation to deep biological interpretation. By following these steps, you will be able to not only describe the heterogeneity of your cell lines but also identify the underlying cellular and clinical factors that drive their global expression differences. ```

LS0tCnRpdGxlOiAiU2luZ2xlLUNlbGwgUk5BLXNlcSBBbmFseXNpcyBvZiBUIENlbGwgUG9wdWxhdGlvbnMgaW4gU2V6YXJ5IFN5bmRyb21lIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgojIEludHJvZHVjdGlvbgoKVGhpcyBSIE1hcmtkb3duIHNjcmlwdCBwcm92aWRlcyB0aGUgY29tcGxldGUsIGV4ZWN1dGFibGUgY29kZSBhbmQgaW50ZXJwcmV0YXRpb24gZ3VpZGFuY2UgdG8gcGVyZm9ybSB0aGUgc2luZ2xlLWNlbGwgUk5BIHNlcXVlbmNpbmcgKHNjUk5BLXNlcSkgYW5hbHlzaXMgb24gYEFsbF9zYW1wbGVzX01lcmdlZGAgU2V1cmF0IG9iamVjdC4gVGhlIGdvYWwgaXMgdG8gYWNoaWV2ZSBhIHJvYnVzdCBUIGNlbGwgYW5ub3RhdGlvbiBhbmQgYW5zd2VyIHNwZWNpZmljIHF1ZXN0aW9ucyByZWdhcmRpbmcgU2V6YXJ5IGNlbGwgcGhlbm90eXBlLCBjZWxsIGxpbmUgaGV0ZXJvZ2VuZWl0eSwgYW5kIHRoZSBkcml2ZXJzIG9mIGV4cHJlc3Npb24gY2x1c3RlcmluZy4KCioqUHJlcmVxdWlzaXRlOioqIEVuc3VyZSB0aGUgYEFsbF9zYW1wbGVzX01lcmdlZGAgU2V1cmF0IG9iamVjdCBpcyBsb2FkZWQgaW50byB5b3VyIFIgZW52aXJvbm1lbnQgYmVmb3JlIHJ1bm5pbmcgdGhlIGNodW5rcyBiZWxvdy4KCiMjIFNldHVwIGFuZCBEYXRhIExvYWRpbmcKCldlIHdpbGwgdXNlIHRoZSBgU2V1cmF0YCBwYWNrYWdlIGZvciBjb3JlIHNjUk5BLXNlcSBhbmFseXNpcywgYGRwbHlyYCBmb3IgZGF0YSBtYW5pcHVsYXRpb24sIGFuZCBgZ2dwbG90MmAgZm9yIHZpc3VhbGl6YXRpb24uCgpgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoTWF0cml4KQoKIyBJTVBPUlRBTlQ6IFJlcGxhY2UgdGhpcyB3aXRoIHRoZSBhY3R1YWwgcGF0aCBhbmQgY29tbWFuZCB0byBsb2FkIHlvdXIgb2JqZWN0CkFsbF9zYW1wbGVzX01lcmdlZCA8LSByZWFkUkRTKCIuLi8uLi8uLi9QSERfM3JkX1lFQVJfQW5hbHlzaXMvMC1TZXVyYXRfUkRTX09CSkVDVF9GSU5BTC9BbGxfc2FtcGxlc19NZXJnZWRfd2l0aF9SZW5hbWVkX0NsdXN0ZXJzX2ZpbmFsLTI2LTEwLTIwMjUucmRzIikKIyBQbGFjZWhvbGRlcjoKaWYgKCFleGlzdHMoIkFsbF9zYW1wbGVzX01lcmdlZCIpKSB7CiAgc3RvcCgiVGhlICdBbGxfc2FtcGxlc19NZXJnZWQnIFNldXJhdCBvYmplY3QgaXMgbm90IGxvYWRlZC4gUGxlYXNlIGxvYWQgeW91ciBkYXRhLiIpCn0KCiMgQ2hlY2sgdGhlIG9iamVjdCBzdHJ1Y3R1cmUKcHJpbnQoQWxsX3NhbXBsZXNfTWVyZ2VkKQpgYGAKCiMgUGhhc2UgMTogUm9idXN0IFQgQ2VsbCBBbm5vdGF0aW9uIGFuZCBTdWJzZXR0aW5nCgpUaGUgZmlyc3QgY3JpdGljYWwgc3RlcCBpcyB0byBpc29sYXRlIHRoZSBUIGNlbGwgcG9wdWxhdGlvbiBhbmQgcmUtcnVuIHRoZSBjbHVzdGVyaW5nIHdvcmtmbG93IHRvIG1heGltaXplIHJlc29sdXRpb24gd2l0aGluIHRoaXMgc3BlY2lmaWMgbGluZWFnZS4KCiMjIDEgVCBDZWxsIFN1YnNldHRpbmcKCldlIHN1YnNldCBiYXNlZCBvbiB0aGUgZXhwcmVzc2lvbiBvZiBwYW4tVCBjZWxsIG1hcmtlcnMgKCpDRDNEKiwgKkNEM0UqLCAqQ0QzRyopLgoKYGBge3J9CiMgSWRlbnRpZnkgY2VsbHMgZXhwcmVzc2luZyBhdCBsZWFzdCBvbmUgb2YgdGhlIHBhbi1UIGNlbGwgbWFya2VycwpUX2NlbGxzIDwtIHN1YnNldChBbGxfc2FtcGxlc19NZXJnZWQsIHN1YnNldCA9IENEM0QgPiAwIHwgQ0QzRSA+IDAgfCBDRDNHID4gMCkKCiMgQ2hlY2sgdGhlIG51bWJlciBvZiBUIGNlbGxzIHJldGFpbmVkCmNhdCgiTnVtYmVyIG9mIFQgY2VsbHMgcmV0YWluZWQ6IiwgbmNvbChUX2NlbGxzKSwgIlxuIikKYGBgCgoKYGBge3IgLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0KIyBWaXN1YWxpemUgdGhlIG5ldyBUIGNlbGwgY2x1c3RlcnMKRGltUGxvdChUX2NlbGxzLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gRikgCmBgYAoKCgpgYGB7ciAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiMgVmlzdWFsaXplIHRoZSBuZXcgVCBjZWxsIGNsdXN0ZXJzCgpGZWF0dXJlUGxvdChUX2NlbGxzLCBmZWF0dXJlcyA9IGMoIkNENCIsICJDRDhBIiwgIkZPWFAzIiwgIktJUjNETDIiKSwgcmVkdWN0aW9uID0gInVtYXAiKQpgYGAKCgoKKipJbnRlcnByZXRhdGlvbiBHdWlkYW5jZSAoUGhhc2UgMSk6KioKKiAgICoqVU1BUDoqKiBWaXN1YWxseSBpbnNwZWN0IHRoZSBjbHVzdGVycy4gQXJlIHRoZXkgd2VsbC1zZXBhcmF0ZWQ/CiogICAqKkZlYXR1cmUgUGxvdHM6KiogVXNlIGtub3duIG1hcmtlcnMgKGUuZy4sICpDRDQqLCAqQ0Q4QSosICpGT1hQMyosICpDQ1I3KiwgKkdaTUIqKSB0byBhc3NpZ24gaW5pdGlhbCBpZGVudGl0aWVzIChDRDQrLCBDRDgrLCBUcmVnLCBOYWl2ZSwgRWZmZWN0b3IpLgoqICAgKipNYXJrZXIgSWRlbnRpZmljYXRpb246KiogVXNlIGBGaW5kQWxsTWFya2VycyhUX2NlbGxzLCBvbmx5LnBvcyA9IFRSVUUpYCB0byBnZXQgYSBsaXN0IG9mIGdlbmVzIGZvciBlYWNoIGNsdXN0ZXIgYW5kIGZpbmFsaXplIHRoZSBhbm5vdGF0aW9uLiAqKllvdSBtdXN0IGFkZCBhIG5ldyBjb2x1bW4gdG8gdGhlIG1ldGFkYXRhLCBlLmcuLCBgVF9jZWxscyRjZWxsX3N1YnR5cGVgLCB3aXRoIHRoZSBmaW5hbCwgcm9idXN0IGFubm90YXRpb25zIChlLmcuLCAiQ0Q0X05haXZlIiwgIkNEOF9FeGhhdXN0ZWQiLCAiVHJlZyIsICJTZXphcnlfTWFsaWduYW50IikuKioKCiMgUGhhc2UgMjogU2V6YXJ5IENlbGwgYW5kIFRyZWctbGlrZSBQaGVub3R5cGUgQ2hlY2sKCldlIHdpbGwgY2hlY2sgaWYgdGhlIGlkZW50aWZpZWQgU2V6YXJ5IGNlbGwgY2x1c3RlcihzKSAobGlrZWx5ICpDRDQrKiBhbmQgZXhwcmVzc2luZyBtYXJrZXJzIGxpa2UgKktJUjNETDIqIG9yIGhhdmluZyBhIHVuaXF1ZSBtYWxpZ25hbnQgc2lnbmF0dXJlKSBleGhpYml0IGEgVCByZWd1bGF0b3J5IGNlbGwgKFRyZWcpIHBoZW5vdHlwZS4KCiMjIDIuMSBDYWxjdWxhdGUgVHJlZyBNb2R1bGUgU2NvcmUKCkEgbW9kdWxlIHNjb3JlIGlzIGEgcm9idXN0IHdheSB0byBxdWFudGlmeSB0aGUgZXhwcmVzc2lvbiBvZiBhIGdlbmUgc2V0LgoKYGBge3J9CiMgRGVmaW5lIHRoZSBjb3JlIFRyZWcgZ2VuZSBzaWduYXR1cmUKVHJlZ19nZW5lcyA8LSBjKCJGT1hQMyIsICJJTDJSQSIsICJDVExBNCIsICJUSUdJVCIpCgojIENhbGN1bGF0ZSB0aGUgbW9kdWxlIHNjb3JlClRfY2VsbHMgPC0gQWRkTW9kdWxlU2NvcmUoCiAgb2JqZWN0ID0gVF9jZWxscywKICBmZWF0dXJlcyA9IGxpc3QoVHJlZ19nZW5lcyksCiAgbmFtZSA9ICJUcmVnX1Njb3JlIgopCgojIFJlbmFtZSB0aGUgc2NvcmUgY29sdW1uIGZvciBzaW1wbGljaXR5ClRfY2VsbHMkVHJlZ19TY29yZSA8LSBUX2NlbGxzJFRyZWdfU2NvcmUxCmBgYAoKIyMgMi4yIENvbXBhcmUgVHJlZyBTY29yZSBEaXN0cmlidXRpb24KCldlIGNvbXBhcmUgdGhlIFRyZWcgc2NvcmUgYWNyb3NzIGFsbCBjbHVzdGVycywgcGF5aW5nIGNsb3NlIGF0dGVudGlvbiB0byB0aGUgU2V6YXJ5IGNsdXN0ZXIocykgYW5kIHRoZSBib25hIGZpZGUgVHJlZyBjbHVzdGVyKHMpLgoKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KIyBWaXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgVHJlZyBzY29yZSBwZXIgY2x1c3RlcgpWbG5QbG90KFRfY2VsbHMsIGZlYXR1cmVzID0gIlRyZWdfU2NvcmUiLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBwdC5zaXplID0gMCkgKwogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BKSArCiAgbGFicyh0aXRsZSA9ICJUcmVnIFNpZ25hdHVyZSBTY29yZSBEaXN0cmlidXRpb24gYnkgQ2x1c3RlciIpCgpgYGAKCgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBTdGF0aXN0aWNhbCBjb21wYXJpc29uIChlLmcuLCBjb21wYXJpbmcgU2V6YXJ5IGNsdXN0ZXIgdG8gY2Fub25pY2FsIFRyZWcgY2x1c3RlcikKIyAqTk9URTogUmVwbGFjZSAiU2V6YXJ5IENsdXN0ZXIgSUQiIGFuZCAiVHJlZyBDbHVzdGVyIElEIiB3aXRoIHlvdXIgYWN0dWFsIGNsdXN0ZXIgbnVtYmVycy9uYW1lcyoKd2lsY294LnRlc3QoVF9jZWxscyRUcmVnX1Njb3JlW1RfY2VsbHMkc2V1cmF0X2NsdXN0ZXJzID09ICIyIl0sCiAgICAgICAgICAgICBUX2NlbGxzJFRyZWdfU2NvcmVbVF9jZWxscyRzZXVyYXRfY2x1c3RlcnMgPT0gIjYiXSkKYGBgCgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBTdGF0aXN0aWNhbCBjb21wYXJpc29uIChlLmcuLCBjb21wYXJpbmcgU2V6YXJ5IGNsdXN0ZXIgdG8gY2Fub25pY2FsIFRyZWcgY2x1c3RlcikKIyAqTk9URTogUmVwbGFjZSAiU2V6YXJ5IENsdXN0ZXIgSUQiIGFuZCAiVHJlZyBDbHVzdGVyIElEIiB3aXRoIHlvdXIgYWN0dWFsIGNsdXN0ZXIgbnVtYmVycy9uYW1lcyoKd2lsY294LnRlc3QoVF9jZWxscyRUcmVnX1Njb3JlW1RfY2VsbHMkc2V1cmF0X2NsdXN0ZXJzID09ICIyIl0sCiAgICAgICAgICAgICBUX2NlbGxzJFRyZWdfU2NvcmVbVF9jZWxscyRzZXVyYXRfY2x1c3RlcnMgPT0gIjgiXSkKYGBgCgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIFN0YXRpc3RpY2FsIGNvbXBhcmlzb24gKGUuZy4sIGNvbXBhcmluZyBTZXphcnkgY2x1c3RlciB0byBjYW5vbmljYWwgVHJlZyBjbHVzdGVyKQojICpOT1RFOiBSZXBsYWNlICJTZXphcnkgQ2x1c3RlciBJRCIgYW5kICJUcmVnIENsdXN0ZXIgSUQiIHdpdGggeW91ciBhY3R1YWwgY2x1c3RlciBudW1iZXJzL25hbWVzKgp3aWxjb3gudGVzdChUX2NlbGxzJFRyZWdfU2NvcmVbVF9jZWxscyRzZXVyYXRfY2x1c3RlcnMgPT0gIjYiXSwKICAgICAgICAgICAgIFRfY2VsbHMkVHJlZ19TY29yZVtUX2NlbGxzJHNldXJhdF9jbHVzdGVycyA9PSAiOCJdKQpgYGAKYGBge3IgLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KIyBTdGF0aXN0aWNhbCBjb21wYXJpc29uIChlLmcuLCBjb21wYXJpbmcgU2V6YXJ5IGNsdXN0ZXIgdG8gY2Fub25pY2FsIFRyZWcgY2x1c3RlcikKIyAqTk9URTogUmVwbGFjZSAiU2V6YXJ5IENsdXN0ZXIgSUQiIGFuZCAiVHJlZyBDbHVzdGVyIElEIiB3aXRoIHlvdXIgYWN0dWFsIGNsdXN0ZXIgbnVtYmVycy9uYW1lcyoKd2lsY294LnRlc3QoVF9jZWxscyRUcmVnX1Njb3JlW1RfY2VsbHMkc2V1cmF0X2NsdXN0ZXJzID09ICI1Il0sCiAgICAgICAgICAgICBUX2NlbGxzJFRyZWdfU2NvcmVbVF9jZWxscyRzZXVyYXRfY2x1c3RlcnMgPT0gIjEiXSkKYGBgCgoKKipJbnRlcnByZXRhdGlvbiBHdWlkYW5jZSAoUGhhc2UgMik6KioKKiAgICoqVmxuUGxvdDoqKiBJZiB0aGUgU2V6YXJ5IGNsdXN0ZXIgc2hvd3MgYSBoaWdoIG1lZGlhbiBUcmVnIHNjb3JlLCBjb21wYXJhYmxlIHRvIG9yIGhpZ2hlciB0aGFuIHRoZSBjYW5vbmljYWwgVHJlZyBjbHVzdGVyLCBpdCBzdWdnZXN0cyBhICoqVHJlZy1saWtlIGltbXVub3N1cHByZXNzaXZlIHBoZW5vdHlwZSoqLgoqICAgKipTdGF0aXN0aWNhbCBUZXN0OioqIEEgc2lnbmlmaWNhbnQgcC12YWx1ZSAoZS5nLiwgcCA8IDAuMDUpIGZyb20gdGhlIFdpbGNveG9uIHRlc3QgY29uZmlybXMgYSBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCAob3Igc2ltaWxhciwgZGVwZW5kaW5nIG9uIHRoZSBtZWFucykgZXhwcmVzc2lvbiBvZiB0aGUgVHJlZyBzaWduYXR1cmUgYmV0d2VlbiB0aGUgdHdvIHBvcHVsYXRpb25zLgoKIyBQaGFzZSAzOiBEaXN0cmlidXRpb24gb2YgQ2VsbCBMaW5lcyBpbiBUIENlbGwgU3RhdGVzCgpUaGlzIGFuc3dlcnMgdGhlIHF1ZXN0aW9uOiAiQ291bGQgeW91IHNob3cgdGhlIGRpc3RyaWJ1dGlvbiBmb3IgZWFjaCBjZWxsIGxpbmVzIGluIFQgY2VsbCBzdGF0ZT8iCgojIyAzLjEgQ2FsY3VsYXRlIFByb3BvcnRpb25zCgpXZSBjYWxjdWxhdGUgdGhlIHByb3BvcnRpb24gb2YgZWFjaCBUIGNlbGwgY2x1c3RlciB3aXRoaW4gZWFjaCBjZWxsIGxpbmUgKHBhdGllbnQgb3JpZ2luKS4gKipFbnN1cmUgeW91ciBjZWxsIGxpbmUvcGF0aWVudCBvcmlnaW4gaW5mb3JtYXRpb24gaXMgaW4gYSBtZXRhZGF0YSBjb2x1bW4gbmFtZWQgYGNlbGxfbGluZWAuKioKCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgQ2FsY3VsYXRlIHRoZSByYXcgY291bnRzIG9mIGNlbGxzIHBlciBjbHVzdGVyIHBlciBjZWxsIGxpbmUKY291bnRfdGFibGUgPC0gdGFibGUoVF9jZWxscyRzZXVyYXRfY2x1c3RlcnMsIFRfY2VsbHMkY2VsbF9saW5lKQoKIyBDYWxjdWxhdGUgdGhlIHByb3BvcnRpb24gKG1hcmdpbiA9IDIgbWVhbnMgcHJvcG9ydGlvbnMgd2l0aGluIGVhY2ggY29sdW1uLCBpLmUuLCB3aXRoaW4gZWFjaCBjZWxsIGxpbmUpCnByb3BfdGFibGUgPC0gcHJvcC50YWJsZShjb3VudF90YWJsZSwgbWFyZ2luID0gMikKCiMgQ29udmVydCB0byBkYXRhIGZyYW1lIGZvciBwbG90dGluZwpwcm9wX2RmIDwtIGFzLmRhdGEuZnJhbWUocHJvcF90YWJsZSkgJT4lCiAgcmVuYW1lKENsdXN0ZXIgPSBWYXIxLCBDZWxsTGluZSA9IFZhcjIsIFByb3BvcnRpb24gPSBGcmVxKQoKIyBEaXNwbGF5IHRoZSBmaXJzdCBmZXcgcm93cyBvZiB0aGUgcHJvcG9ydGlvbiB0YWJsZQpoZWFkKHByb3BfZGYpCmBgYAoKIyMgMy4yIFZpc3VhbGl6ZSBEaXN0cmlidXRpb24KCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgU3RhY2tlZCBiYXIgcGxvdCB2aXN1YWxpemF0aW9uCmdncGxvdChwcm9wX2RmLCBhZXMoeCA9IENlbGxMaW5lLCB5ID0gUHJvcG9ydGlvbiwgZmlsbCA9IENsdXN0ZXIpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKwogIGxhYnModGl0bGUgPSAiVCBDZWxsIENsdXN0ZXIgQ29tcG9zaXRpb24gYnkgQ2VsbCBMaW5lIChQYXRpZW50IE9yaWdpbikiLAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIFQgQ2VsbHMgcGVyIExpbmUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCioqSW50ZXJwcmV0YXRpb24gR3VpZGFuY2UgKFBoYXNlIDMpOioqCiogICAqKlN0YWNrZWQgQmFyIFBsb3Q6KiogTG9vayBmb3IgKipkb21pbmFudCBjbHVzdGVycyoqIGluIHNwZWNpZmljIGNlbGwgbGluZXMuIEZvciBleGFtcGxlLCBpZiBDZWxsIExpbmUgQSBpcyA4MCUgIlNlemFyeV9NYWxpZ25hbnQiIGJ1dCBDZWxsIExpbmUgQiBpcyBvbmx5IDIwJSwgaXQgaW5kaWNhdGVzIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgcHVyaXR5IG9yICppbiB2aXRybyogZGlmZmVyZW50aWF0aW9uIHN0YXRlIG9mIHRoZSBjZWxsIGxpbmVzLiBUaGlzIGhldGVyb2dlbmVpdHkgd2lsbCBiZSB0aGUgYmFzaXMgZm9yIHRoZSBuZXh0IGNsdXN0ZXJpbmcgc3RlcC4KCiMgUGhhc2UgNDogVW5zdXBlcnZpc2VkIENsdXN0ZXJpbmcgb2YgQ2VsbCBMaW5lcyAoUHNldWRvYnVsaykKClRoaXMgYWRkcmVzc2VzOiAiQ291bGQgeW91IG1ha2UgYW4gdW5zdXBlcnZpc2VkIGNsdXN0ZXJpbmcgb2Ygb3VyIGNlbGwgbGluZXMgYmFzZWQgdXBvbiBleHByZXNzaW9uPyIgV2UgdHJlYXQgZWFjaCBjZWxsIGxpbmUgYXMgYSBzaW5nbGUgc2FtcGxlIGFuZCBjbHVzdGVyIHRoZW0gYmFzZWQgb24gdGhlaXIgb3ZlcmFsbCBnZW5lIGV4cHJlc3Npb24gcHJvZmlsZS4KCiMjIDQuMSBBZ2dyZWdhdGUgRXhwcmVzc2lvbiAoUHNldWRvYnVsaykKCmBgYHtyfQojIENhbGN1bGF0ZSB0aGUgYXZlcmFnZSBleHByZXNzaW9uIGZvciBhbGwgZ2VuZXMgYWNyb3NzIGFsbCBUIGNlbGxzLCBncm91cGVkIGJ5ICdjZWxsX2xpbmUnCiMgV2UgdXNlIHRoZSAnZGF0YScgc2xvdCAobm9ybWFsaXplZCBleHByZXNzaW9uKQpwc2V1ZG9idWxrIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKFRfY2VsbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2VsbF9saW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheXMgPSAiUk5BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gImRhdGEiKQoKIyBFeHRyYWN0IHRoZSBleHByZXNzaW9uIG1hdHJpeCBhbmQgdHJhbnNwb3NlIGl0IChDZWxsIExpbmVzIGFzIHJvd3MsIEdlbmVzIGFzIGNvbHVtbnMpCnBiX21hdHJpeCA8LSBhcy5tYXRyaXgocHNldWRvYnVsayRSTkEpCnBiX21hdHJpeF90IDwtIHQocGJfbWF0cml4KQpgYGAKCiMjIDQuMiBEaW1lbnNpb25hbGl0eSBSZWR1Y3Rpb24gYW5kIEhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nCgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIFBlcmZvcm0gUENBIG9uIHRoZSBwc2V1ZG9idWxrIG1hdHJpeAojIHNjYWxlLiA9IFRSVUUgc3RhbmRhcmRpemVzIHRoZSBnZW5lIGV4cHJlc3Npb24gYWNyb3NzIGNlbGwgbGluZXMKcGJfcGNhIDwtIHByY29tcChwYl9tYXRyaXhfdCwgc2NhbGUuID0gVFJVRSkKCiMgVmlzdWFsaXplIHRoZSBjZWxsIGxpbmVzIGluIHRoZSBQQ0Egc3BhY2UKcGxvdChwYl9wY2EkeFssIDFdLCBwYl9wY2EkeFssIDJdLAogICAgIG1haW4gPSAiUENBIG9mIENlbGwgTGluZXMgKFBDMSB2cyBQQzIpIiwKICAgICB4bGFiID0gcGFzdGUwKCJQQzEgKCIsIHJvdW5kKHN1bW1hcnkocGJfcGNhKSRpbXBvcnRhbmNlWzIsIDFdICogMTAwLCAyKSwgIiUpIiksCiAgICAgeWxhYiA9IHBhc3RlMCgiUEMyICgiLCByb3VuZChzdW1tYXJ5KHBiX3BjYSkkaW1wb3J0YW5jZVsyLCAyXSAqIDEwMCwgMiksICIlKSIpLAogICAgIHBjaCA9IDE5LAogICAgIGNvbCA9IGZhY3Rvcihyb3duYW1lcyhwYl9wY2EkeCkpKQp0ZXh0KHBiX3BjYSR4WywgMV0sIHBiX3BjYSR4WywgMl0sIGxhYmVscyA9IHJvd25hbWVzKHBiX3BjYSR4KSwgcG9zID0gMykKCiMgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgYmFzZWQgb24gdGhlIGZpcnN0IDEwIFBDcwpoY2x1c3RfcmVzIDwtIGhjbHVzdChkaXN0KHBiX3BjYSR4WywgMToxMF0pLCBtZXRob2QgPSAid2FyZC5EMiIpCgojIFZpc3VhbGl6ZSB0aGUgZGVuZHJvZ3JhbQpwbG90KGhjbHVzdF9yZXMsIG1haW4gPSAiSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgb2YgQ2VsbCBMaW5lcyIsIHhsYWIgPSAiQ2VsbCBMaW5lIikKCiMgQ3V0IHRoZSB0cmVlIHRvIGRlZmluZSAnQ2VsbCBMaW5lIENsdXN0ZXJzJyAoZS5nLiwgMyBjbHVzdGVycykKY2VsbF9saW5lX2NsdXN0ZXJzIDwtIGN1dHJlZShoY2x1c3RfcmVzLCBrID0gMykKY2VsbF9saW5lX2NsdXN0ZXJzX2RmIDwtIGRhdGEuZnJhbWUoY2VsbF9saW5lID0gbmFtZXMoY2VsbF9saW5lX2NsdXN0ZXJzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZV9jbHVzdGVyID0gZmFjdG9yKGNlbGxfbGluZV9jbHVzdGVycykpCmBgYAoKKipJbnRlcnByZXRhdGlvbiBHdWlkYW5jZSAoUGhhc2UgNCk6KioKKiAgICoqUENBIFBsb3Q6KiogQ2VsbCBsaW5lcyB0aGF0IGdyb3VwIGNsb3NlbHkgdG9nZXRoZXIgc2hhcmUgc2ltaWxhciBvdmVyYWxsIGdlbmUgZXhwcmVzc2lvbiBwcm9maWxlcy4KKiAgICoqRGVuZHJvZ3JhbToqKiBUaGUgYnJhbmNoZXMgc2hvdyB0aGUgc2ltaWxhcml0eS4gQ2VsbCBsaW5lcyBqb2luaW5nIGVhcmx5IGFyZSBoaWdobHkgc2ltaWxhci4gQ3V0dGluZyB0aGUgdHJlZSAoZS5nLiwgYGs9M2ApIGRlZmluZXMgdGhlICoqQ2VsbCBMaW5lIENsdXN0ZXJzKiogKGUuZy4sICJDbHVzdGVyIEEiLCAiQ2x1c3RlciBCIiwgIkNsdXN0ZXIgQyIpLgoKIyBQaGFzZSA1OiBEZWZpbmluZyBDbHVzdGVyLVNwZWNpZmljIEdlbmVzIGFuZCBTaGFyZWQgQ2x1c3RlcnMKClRoaXMgYWRkcmVzc2VzOiAiZGVmaW5lIGNsdXN0ZXJzIHRoYXQgd2Ugb2JzZXJ2ZSwgYSBsaXN0IG9mIGdlbmVzIHRoYXQgd2UgaGF2ZSBpbiBlYWNoIGNsdXN0ZXJzPyBNYXliZSB3ZSBoYXZlIGNsdXN0ZXJzIHRoYXQgYXJlIHNoYXJlZCB3aXRoIGNlbGwgbGluZXMgZGVyaXZlZCBmcm9tIG90aGVyIHBhdGllbnRzPyIKCiMjIDUuMSBNYXJrZXIgR2VuZXMgZm9yIFQgQ2VsbCBTdWJ0eXBlcyAoUmV2aWV3KQoKWW91IHNob3VsZCBoYXZlIGFscmVhZHkgZG9uZSB0aGlzIGluIFBoYXNlIDEsIGJ1dCBoZXJlIGlzIHRoZSBjb2RlIHRvIHJlLXJ1biBhbmQgZXh0cmFjdCB0aGUgdG9wIG1hcmtlcnMgZm9yIHRoZSBzaW5nbGUtY2VsbCBjbHVzdGVycy4KCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgRmluZCBtYXJrZXJzIGZvciBhbGwgc2luZ2xlLWNlbGwgY2x1c3RlcnMKVF9jZWxscy5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKFRfY2VsbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMC4yNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCgojIEdldCB0aGUgdG9wIDEwIG1hcmtlcnMgcGVyIGNsdXN0ZXIKdG9wMTAgPC0gVF9jZWxscy5tYXJrZXJzICU+JQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQogIHRvcF9uKG4gPSAxMCwgd3QgPSBhdmdfbG9nMkZDKQoKIyBQcmludCB0aGUgdG9wIG1hcmtlcnMgZm9yIHJldmlldwpwcmludCh0b3AxMCkKYGBgCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgRmluZCBtYXJrZXJzIGZvciBhbGwgc2luZ2xlLWNlbGwgY2x1c3RlcnMKVF9jZWxscy5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKFRfY2VsbHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJjZWxsX2xpbmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLnBjdCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQoKIyBHZXQgdGhlIHRvcCAxMCBtYXJrZXJzIHBlciBjbHVzdGVyCnRvcDEwX2NsIDwtIFRfY2VsbHMubWFya2VycyAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKCiMgUHJpbnQgdGhlIHRvcCBtYXJrZXJzIGZvciByZXZpZXcKcHJpbnQodG9wMTBfY2wpCmBgYAojIyA1LjIgTWFya2VyIEdlbmVzIGZvciBDZWxsIExpbmUgQ2x1c3RlcnMgKFRoZSBOZXcgSW5zaWdodCkKCldlIG5vdyB3YW50IHRvIGZpbmQgdGhlIGdlbmVzIHRoYXQgZGVmaW5lIHRoZSAqKkNlbGwgTGluZSBDbHVzdGVycyoqIGlkZW50aWZpZWQgaW4gUGhhc2UgNC4KCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgMS4gTWVyZ2UgdGhlIG5ldyAnbGluZV9jbHVzdGVyJyBpbmZvcm1hdGlvbiBpbnRvIHRoZSBwc2V1ZG9idWxrIFBDQSByZXN1bHRzCnBiX3BjYV9kZiA8LSBkYXRhLmZyYW1lKHBiX3BjYSR4WywgMToxMF0pICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiY2VsbF9saW5lIikgJT4lCiAgbGVmdF9qb2luKGNlbGxfbGluZV9jbHVzdGVyc19kZiwgYnkgPSAiY2VsbF9saW5lIikKCiMgMi4gRmluZCB0aGUgbWFya2VyIGdlbmVzIHRoYXQgZGlmZmVyZW50aWF0ZSB0aGUgQ2VsbCBMaW5lIENsdXN0ZXJzCiMgVGhpcyByZXF1aXJlcyBhIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIHRlc3Qgb24gdGhlIHBzZXVkb2J1bGsgZGF0YQojIEZvciBzaW1wbGljaXR5LCB3ZSB3aWxsIHVzZSB0aGUgJ2xpbmVfY2x1c3RlcicgYXMgYSBncm91cGluZyB2YXJpYWJsZSBvbiB0aGUgb3JpZ2luYWwgVF9jZWxscyBvYmplY3QKIyB0byBmaW5kIGdlbmVzIGhpZ2hseSBleHByZXNzZWQgaW4gY2VsbHMgYmVsb25naW5nIHRvIGxpbmVzIGluIGEgc3BlY2lmaWMgJ2xpbmVfY2x1c3RlcicuCgojIEZpcnN0LCBhZGQgdGhlIGNlbGwgbGluZSBjbHVzdGVyIGluZm9ybWF0aW9uIHRvIHRoZSBzaW5nbGUtY2VsbCBvYmplY3QgbWV0YWRhdGEKVF9jZWxsc0BtZXRhLmRhdGEgPC0gVF9jZWxsc0BtZXRhLmRhdGEgJT4lCiAgbGVmdF9qb2luKGNlbGxfbGluZV9jbHVzdGVyc19kZiwgYnkgPSAiY2VsbF9saW5lIikgJT4lCiAgIyBIYW5kbGUgcG90ZW50aWFsIE5BIHZhbHVlcyBpZiAnY2VsbF9saW5lJyBjb2x1bW4gd2FzIG1pc3NpbmcKICBtdXRhdGUobGluZV9jbHVzdGVyID0gYXMuZmFjdG9yKGlmZWxzZShpcy5uYShsaW5lX2NsdXN0ZXIpLCAiVW5rbm93biIsIGFzLmNoYXJhY3RlcihsaW5lX2NsdXN0ZXIpKSkpCgojIE5vdywgZmluZCBtYXJrZXJzIGJldHdlZW4gdGhlIENlbGwgTGluZSBDbHVzdGVycwpsaW5lX2NsdXN0ZXJfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhUX2NlbGxzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJsaW5lX2NsdXN0ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQoKIyBHZXQgdGhlIHRvcCAxMCBtYXJrZXJzIGZvciBlYWNoIENlbGwgTGluZSBDbHVzdGVyCnRvcDEwX2xpbmVfbWFya2VycyA8LSBsaW5lX2NsdXN0ZXJfbWFya2VycyAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKCnByaW50KHRvcDEwX2xpbmVfbWFya2VycykKYGBgCgoqKkludGVycHJldGF0aW9uIEd1aWRhbmNlIChQaGFzZSA1KToqKgoqICAgKipHZW5lIExpc3Q6KiogVGhlIGB0b3AxMF9saW5lX21hcmtlcnNgIGxpc3QgaXMgdGhlIGFuc3dlciB0byB0aGUgImxpc3Qgb2YgZ2VuZXMgdGhhdCB3ZSBoYXZlIGluIGVhY2ggY2x1c3RlcnMiIHF1ZXN0aW9uLCBidXQgZm9yIHRoZSAqY2VsbCBsaW5lKiBjbHVzdGVycy4gVGhlc2UgZ2VuZXMgcmVwcmVzZW50IHRoZSBjb3JlIGJpb2xvZ2ljYWwgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgZ3JvdXBzIG9mIGNlbGwgbGluZXMuCiogICAqKlNoYXJlZCBDbHVzdGVyczoqKiBUbyBjaGVjayBpZiB0aGVzZSBjbHVzdGVycyBhcmUgInNoYXJlZCB3aXRoIGNlbGwgbGluZXMgZGVyaXZlZCBmcm9tIG90aGVyIHBhdGllbnRzLCIgeW91IG5lZWQgdG8gKiptYW51YWxseSBzZWFyY2gqKiB0aGUgdG9wIG1hcmtlciBnZW5lcyAoZS5nLiwgKlMxMDBBNCosICpHWk1CKiwgKkZPWFAzKikgaW4gcHVibGljIGRhdGFiYXNlcyAoZS5nLiwgR0VPLCBsaXRlcmF0dXJlKSBmb3Iga25vd24gVCBjZWxsIHN0YXRlcyBvciBtYWxpZ25hbnQgc2lnbmF0dXJlcy4gSWYgdGhlIG1hcmtlciBsaXN0IGZvciAiTGluZSBDbHVzdGVyIEEiIG1hdGNoZXMgYSBrbm93biBzaWduYXR1cmUgKGUuZy4sICJJbnRlcmZlcm9uIFJlc3BvbnNlIFNpZ25hdHVyZSIpLCB0aGVuIHRoZSBjbHVzdGVyIGlzIG5vdCB1bmlxdWUgdG8geW91ciBwYXRpZW50IGNvaG9ydC4KCiMgUGhhc2UgNjogVGVzdGluZyBNZXRhZGF0YSBhcyBFeHBsYW5hdG9yeSBWYXJpYWJsZXMgZm9yIENsdXN0ZXJpbmcKClRoaXMgYWRkcmVzc2VzOiAiQ291bGQgeW91IHRlc3QgbWV0YWRhdGEgdGhhdCBjb3VsZCBleHBsYWluIHRoZSBjbHVzdGVyaW5nLCBpbnN0ZWFkIG9mIG9ubHkgcGF0aWVudCBvcmlnaW4/IExpa2UgYWxsIHRoZSBwYXJhbWV0ZXJzIHRoYXQgeW91IGhhdmUgaW4gbWV0YWRhdGEgYW5kIGFsc28gY29tcG9zaXRpb24gaW4gVCBjZWxsIGltbXVub3BoZW5vdHlwZS4uLiIKCiMjIDYuMSBQcmVwYXJlIE1ldGFkYXRhIGZvciBNb2RlbGluZwoKV2UgbmVlZCBhIHRhYmxlIHdoZXJlIGVhY2ggcm93IGlzIGEgY2VsbCBsaW5lLCBhbmQgY29sdW1ucyBjb250YWluOgoxLiAgVGhlIFBDIHNjb3JlcyAocXVhbnRpdGF0aXZlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjbHVzdGVyaW5nIGZyb20gUGhhc2UgNCkuCjIuICBUaGUgcHJvcG9ydGlvbiBvZiBlYWNoIFQgY2VsbCBzdWJ0eXBlIChpbW11bm9waGVub3R5cGUgY29tcG9zaXRpb24gZnJvbSBQaGFzZSAzKS4KMy4gIEFueSBvdGhlciByZWxldmFudCBtZXRhZGF0YSAoZS5nLiwgYWdlLCBzZXgsIHRyZWF0bWVudCBzdGF0dXMsIGJhdGNoKS4KCmBgYHtyICwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgMS4gR2V0IFBDIHNjb3JlcyAocXVhbnRpdGF0aXZlIGNsdXN0ZXJpbmcpCmNlbGxfbGluZV9wY3MgPC0gZGF0YS5mcmFtZShwYl9wY2EkeCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJjZWxsX2xpbmUiKSAlPiUKICBzZWxlY3QoY2VsbF9saW5lLCBQQzEsIFBDMiwgUEMzKSAjIFVzZSB0aGUgdG9wIFBDcyB0aGF0IGV4cGxhaW4gbW9zdCB2YXJpYW5jZQoKIyAyLiBHZXQgVCBjZWxsIGltbXVub3BoZW5vdHlwZSBjb21wb3NpdGlvbiAocHJvcG9ydGlvbnMgZnJvbSBQaGFzZSAzKQojICpOT1RFOiBUaGlzIGFzc3VtZXMgeW91IGhhdmUgZmluYWxpemVkIHRoZSAnY2VsbF9zdWJ0eXBlJyBjb2x1bW4gaW4gUGhhc2UgMSoKY2VsbF9zdWJ0eXBlX2NvdW50cyA8LSBUX2NlbGxzQG1ldGEuZGF0YSAlPiUKICBncm91cF9ieShjZWxsX2xpbmUsIGNlbGxfc3VidHlwZSkgJT4lCiAgc3VtbWFyaXNlKENvdW50ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKY2VsbF9zdWJ0eXBlX3Byb3BvcnRpb25zIDwtIGNlbGxfc3VidHlwZV9jb3VudHMgJT4lCiAgZ3JvdXBfYnkoY2VsbF9saW5lKSAlPiUKICBtdXRhdGUoVG90YWwgPSBzdW0oQ291bnQpLAogICAgICAgICBQcm9wb3J0aW9uID0gQ291bnQgLyBUb3RhbCkgJT4lCiAgc2VsZWN0KGNlbGxfbGluZSwgY2VsbF9zdWJ0eXBlLCBQcm9wb3J0aW9uKSAlPiUKICAjIFdpZGVuIHRoZSB0YWJsZSBzbyBlYWNoIGNlbGwgc3VidHlwZSBwcm9wb3J0aW9uIGlzIGEgY29sdW1uCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjZWxsX3N1YnR5cGUsIHZhbHVlc19mcm9tID0gUHJvcG9ydGlvbiwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICByZW5hbWVfd2l0aCh+cGFzdGUwKCJQcm9wXyIsIC4pLCAtY2VsbF9saW5lKSAjIFByZWZpeCBjb2x1bW4gbmFtZXMKCiMgMy4gR2V0IG90aGVyIG1ldGFkYXRhIChlLmcuLCBBZ2UsIFNleCkKIyAqTk9URTogUmVwbGFjZSAiQWdlIiBhbmQgIlNleCIgd2l0aCBhY3R1YWwgY29sdW1uIG5hbWVzIGZyb20geW91ciBBbGxfc2FtcGxlc19NZXJnZWQgbWV0YWRhdGEqCm90aGVyX21ldGFkYXRhIDwtIFRfY2VsbHNAbWV0YS5kYXRhICU+JQogIHNlbGVjdChjZWxsX2xpbmUsIEFnZSwgU2V4LCBCYXRjaCkgJT4lCiAgZGlzdGluY3QoKSAjIEVuc3VyZSBvbmx5IG9uZSByb3cgcGVyIGNlbGwgbGluZQoKIyA0LiBNZXJnZSBhbGwgZGF0YSBpbnRvIHRoZSBmaW5hbCBtb2RlbCB0YWJsZQptb2RlbF9kYXRhIDwtIGNlbGxfbGluZV9wY3MgJT4lCiAgbGVmdF9qb2luKGNlbGxfc3VidHlwZV9wcm9wb3J0aW9ucywgYnkgPSAiY2VsbF9saW5lIikgJT4lCiAgbGVmdF9qb2luKG90aGVyX21ldGFkYXRhLCBieSA9ICJjZWxsX2xpbmUiKQoKcHJpbnQoaGVhZChtb2RlbF9kYXRhKSkKYGBgCgojIyA2LjIgU3RhdGlzdGljYWwgTW9kZWxpbmcKCldlIHVzZSBhIGxpbmVhciBtb2RlbCB0byB0ZXN0IGlmIHRoZSBtZXRhZGF0YSB2YXJpYWJsZXMgKGUuZy4sIGBQcm9wX1RyZWdgLCBgQWdlYCkgc2lnbmlmaWNhbnRseSBwcmVkaWN0IHRoZSBjZWxsIGxpbmUncyBleHByZXNzaW9uIHByb2ZpbGUsIHJlcHJlc2VudGVkIGJ5IGl0cyBQQyBzY29yZXMuCgpgYGB7ciAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIFRlc3QgUEMxICh0aGUgcHJpbWFyeSBkcml2ZXIgb2YgdGhlIGNlbGwgbGluZSBjbHVzdGVyaW5nKSBhZ2FpbnN0IGFsbCBwcmVkaWN0b3JzCiMgV2UgdGVzdCB0aGUgVCBjZWxsIGNvbXBvc2l0aW9uIChlLmcuLCBQcm9wX1RyZWcpIGFuZCBvdGhlciBtZXRhZGF0YSAoZS5nLiwgQWdlKQojICpOT1RFOiBBZGp1c3QgdGhlIGZvcm11bGEgdG8gaW5jbHVkZSBhbGwgcmVsZXZhbnQgbWV0YWRhdGEgY29sdW1ucyoKbG1fbW9kZWxfcGMxIDwtIGxtKFBDMSB+IFByb3BfVHJlZyArIFByb3BfU2V6YXJ5X01hbGlnbmFudCArIEFnZSArIFNleCArIEJhdGNoLCBkYXRhID0gbW9kZWxfZGF0YSkKCiMgVmlldyB0aGUgcmVzdWx0cwpzdW1tYXJ5KGxtX21vZGVsX3BjMSkKCiMgWW91IGNhbiByZXBlYXQgdGhpcyBmb3IgUEMyLCBQQzMsIGV0Yy4KIyBsbV9tb2RlbF9wYzIgPC0gbG0oUEMyIH4gUHJvcF9UcmVnICsgUHJvcF9TZXphcnlfTWFsaWduYW50ICsgQWdlICsgU2V4ICsgQmF0Y2gsIGRhdGEgPSBtb2RlbF9kYXRhKQojIHN1bW1hcnkobG1fbW9kZWxfcGMyKQpgYGAKCioqSW50ZXJwcmV0YXRpb24gR3VpZGFuY2UgKFBoYXNlIDYpOioqCiogICAqKmBzdW1tYXJ5KGxtX21vZGVsX3BjMSlgOioqIEZvY3VzIG9uIHRoZSAqKnAtdmFsdWUqKiAoUHIoPnx0fCkpIGZvciBlYWNoIHByZWRpY3RvciB2YXJpYWJsZSAoZS5nLiwgYFByb3BfVHJlZ2ApLgoqICAgKipTaWduaWZpY2FudCBQcmVkaWN0b3IgKHAgPCAwLjA1KToqKiBJZiBhIHZhcmlhYmxlIGxpa2UgYFByb3BfVHJlZ2AgaGFzIGEgbG93IHAtdmFsdWUsIGl0IG1lYW5zIHRoZSBwcm9wb3J0aW9uIG9mIFRyZWdzIGluIGEgY2VsbCBsaW5lIGlzIGEgKipzaWduaWZpY2FudCBwcmVkaWN0b3IqKiBvZiB3aGVyZSB0aGF0IGNlbGwgbGluZSBmYWxscyBpbiB0aGUgZXhwcmVzc2lvbiBjbHVzdGVyaW5nIHNwYWNlIChQQzEpLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGJpb2xvZ2ljYWwgZGlmZmVyZW5jZSBjYXB0dXJlZCBieSBQQzEgKHRoZSBjbHVzdGVyaW5nKSBpcyAqKmV4cGxhaW5lZCBieSoqIHRoZSB1bmRlcmx5aW5nIFQgY2VsbCBpbW11bm9waGVub3R5cGUgY29tcG9zaXRpb24sIGluZGVwZW5kZW50IG9mIHRoZSBzaW1wbGUgInBhdGllbnQgb3JpZ2luIiBsYWJlbC4KKiAgICoqQ29lZmZpY2llbnQgKEVzdGltYXRlKToqKiBUaGUgc2lnbiBvZiB0aGUgY29lZmZpY2llbnQgaW5kaWNhdGVzIHRoZSBkaXJlY3Rpb24uIEEgcG9zaXRpdmUgY29lZmZpY2llbnQgZm9yIGBQcm9wX1RyZWdgIG1lYW5zIGNlbGwgbGluZXMgd2l0aCBhIGhpZ2hlciBwcm9wb3J0aW9uIG9mIFRyZWdzIHRlbmQgdG8gaGF2ZSBhIGhpZ2hlciBQQzEgc2NvcmUuCgojIENvbmNsdXNpb24KClRoaXMgc2NyaXB0IHByb3ZpZGVzIGEgY29tcHJlaGVuc2l2ZSBmcmFtZXdvcmsgdG8gbW92ZSBmcm9tIHJvYnVzdCBhbm5vdGF0aW9uIHRvIGRlZXAgYmlvbG9naWNhbCBpbnRlcnByZXRhdGlvbi4gQnkgZm9sbG93aW5nIHRoZXNlIHN0ZXBzLCB5b3Ugd2lsbCBiZSBhYmxlIHRvIG5vdCBvbmx5IGRlc2NyaWJlIHRoZSBoZXRlcm9nZW5laXR5IG9mIHlvdXIgY2VsbCBsaW5lcyBidXQgYWxzbyBpZGVudGlmeSB0aGUgdW5kZXJseWluZyBjZWxsdWxhciBhbmQgY2xpbmljYWwgZmFjdG9ycyB0aGF0IGRyaXZlIHRoZWlyIGdsb2JhbCBleHByZXNzaW9uIGRpZmZlcmVuY2VzLgpgYGAK