1. load libraries
2. Load Seurat Object
# load("/home/bioinfo/Cluster_to_Computer_Transfer_files_folder/All_Normal-PBMC_Abnormal-cellLines_T_cells_Merged_Annotated_UMAP_on_Clusters_to_USE.Robj")
library(ape)
library(dendextend)
library(ggplot2)
library(dplyr)
# Read the observation groupings
groupings <- read.table("L1_L2_P1_inferCNV/infercnv.observation_groupings.txt", header=TRUE, stringsAsFactors=FALSE, row.names=1)
# Convert Dendrogram.Group to a factor, then to numeric
groupings$Dendrogram.Group_Numeric <- as.numeric(factor(groupings$Dendrogram.Group))
# Create a distance matrix based on the numeric dendrogram groups
dist_matrix <- dist(groupings$Dendrogram.Group_Numeric)
# Create a dendrogram
dend <- as.dendrogram(hclust(dist_matrix))
# Color the dendrogram branches
unique_colors <- unique(groupings$Dendrogram.Color)
dend <- color_branches(dend, k=length(unique(groupings$Dendrogram.Group)),
col=unique_colors)
# Convert to Newick format and write to file
newick <- write.tree(as.phylo(dend))
write(newick, file="infercnv.observations_dendrogram.txt")
# Plot the dendrogram
plot(dend, main="Dendrogram of Cells")

# Create a data frame for cell line information
cell_data <- data.frame(
cell = rownames(groupings),
cell_line = ifelse(grepl("^L1_", rownames(groupings)), "L1",
ifelse(grepl("^L2_", rownames(groupings)), "L2", "Other"))
)
# Create a heatmap-like visualization
p <- ggplot(cell_data, aes(x=1, y=cell, fill=cell_line)) +
geom_tile() +
scale_fill_manual(values=c("L1"="darkgreen", "L2"="purple", "Other"="gray")) +
theme_minimal() +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
legend.position="bottom") +
labs(x=NULL, y=NULL, fill="Cell Line", title="Cell Line Distribution")
# Display the plot
print(p)

# Print summary
cat("Number of cells in L1:", sum(cell_data$cell_line == "L1"), "\n")
Number of cells in L1: 5825
cat("Number of cells in L2:", sum(cell_data$cell_line == "L2"), "\n")
Number of cells in L2: 5935
cat("Number of other cells:", sum(cell_data$cell_line == "Other"), "\n")
Number of other cells: 0
# Print the number of unique groups
cat("Number of unique Dendrogram Groups:", length(unique(groupings$Dendrogram.Group)), "\n")
Number of unique Dendrogram Groups: 119
3. Phylogeney of inferCNV
library(ggplot2)
library(dplyr)
library(tidyr)
library(ggdendro)
library(dendextend)
library(patchwork)
library(tibble)
# Read the heatmap thresholds
thresholds <- read.table("L1_L2_P1_inferCNV/infercnv.heatmap_thresholds.txt", header=FALSE)$V1
# Read the observation groupings
groupings <- read.table("L1_L2_P1_inferCNV/infercnv.observation_groupings.txt", header=TRUE, stringsAsFactors=FALSE, row.names=1)
# Process the groupings data
metadata <- groupings %>%
rownames_to_column("sample") %>%
rename(
dendrogram_group = Dendrogram.Group,
dendrogram_color = Dendrogram.Color,
annotation_group = Annotation.Group,
annotation_color = Annotation.Color
) %>%
mutate(
patient = case_when(
grepl("^L1_|^L2_", sample) ~ "P1",
grepl("^L3_|^L4_", sample) ~ "P2",
grepl("^L5_|^L6_|^L7_", sample) ~ "P3",
TRUE ~ NA_character_
),
annotation_group = as.factor(annotation_group) # Convert to factor
)
# Convert dendrogram_group to numeric if it's not already
metadata$dendrogram_group <- as.numeric(as.factor(metadata$dendrogram_group))
# Remove rows with NA in dendrogram_group
metadata <- metadata %>% filter(!is.na(dendrogram_group))
# Create a distance matrix based on the dendrogram groups
dist_matrix <- dist(metadata$dendrogram_group)
# Create a dendrogram
dend <- as.dendrogram(hclust(dist_matrix))
# Color the dendrogram branches
dend <- color_branches(dend, k=length(unique(metadata$dendrogram_group)),
col=unique(metadata$dendrogram_color))
# Plot the dendrogram
p1 <- ggdendrogram(dend, rotate=TRUE, size=2) +
labs(title="Dendrogram of Sézary Cell Lines (L1 and L2)") +
theme(plot.title = element_text(hjust = 0.5))
# Create a heatmap-like plot of the groupings
p2 <- ggplot(metadata, aes(x=1, y=sample, fill=annotation_group)) +
geom_tile() +
scale_fill_manual(values=setNames(metadata$annotation_color, metadata$annotation_group)) +
theme_minimal() +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
legend.position="bottom") +
labs(x=NULL, y=NULL, fill="Annotation Group")
# Combine the plots
combined_plot <- p1 + p2 + plot_layout(widths=c(3, 1))
# Display the plot in the notebook
combined_plot

library(ggplot2)
library(dplyr)
library(tidyr)
library(pheatmap)
library(RColorBrewer)
# Read the observation groupings
groupings <- read.table("L1_L2_P1_inferCNV/infercnv.observation_groupings.txt", header=TRUE, stringsAsFactors=FALSE, row.names=1)
# Filter for L1 and L2 cells and create a data frame
l1_l2_data <- groupings %>%
filter(grepl("^L1_|^L2_", rownames(.))) %>%
mutate(
Cell_Line = ifelse(grepl("^L1_", rownames(.)), "L1", "L2"),
Dendrogram_Group = as.numeric(factor(Dendrogram.Group)),
Annotation_Group = as.numeric(factor(Annotation.Group))
) %>%
select(Cell_Line, Dendrogram_Group, Annotation_Group)
# Create a matrix for the heatmap
heatmap_matrix <- l1_l2_data %>%
select(Dendrogram_Group, Annotation_Group) %>%
as.matrix()
rownames(heatmap_matrix) <- rownames(l1_l2_data)
# Create annotation for cell lines
cell_line_anno <- data.frame(
Cell_Line = l1_l2_data$Cell_Line
)
rownames(cell_line_anno) <- rownames(l1_l2_data)
# Create color palettes
group_colors <- colorRampPalette(brewer.pal(8, "Set3"))(length(unique(c(heatmap_matrix))))
# Create the heatmap
pheatmap(
heatmap_matrix,
color = group_colors,
cluster_rows = TRUE,
cluster_cols = FALSE,
show_rownames = FALSE,
annotation_row = cell_line_anno,
annotation_colors = list(Cell_Line = c(L1 = "darkgreen", L2 = "purple")),
main = "Groupings of L1 and L2 Sézary Cell Lines",
labels_col = c("Dendrogram Group", "Annotation Group")
)

9. Save the Seurat object as an Robj file
#save(All_samples_Merged, file = "../5-SS_ScRNA_Data_Analysis/4-ScSS_MyAnalysis_on_SS/0-Important_R_OBJ/All_samples_Merged_WNN_correct_on_HPC.Robj")
LS0tCnRpdGxlOiAiUGh5bG9nZW55X2Jhc2VkIG9uIGluZmVyQ05WIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMgMS4gbG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KFNldXJhdE9iamVjdCkKbGlicmFyeShTZXVyYXREYXRhKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShoYXJtb255KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShyZXRpY3VsYXRlKQpsaWJyYXJ5KEF6aW11dGgpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoUnRzbmUpCmxpYnJhcnkoaGFybW9ueSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHBoZWF0bWFwKQoKbGlicmFyeShnZ3RyZWUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZ2dkZW5kcm8pCmxpYnJhcnkoZGVuZGV4dGVuZCkKCgoKYGBgCiMgMi4gTG9hZCBTZXVyYXQgT2JqZWN0IApgYGB7ciBsb2FkX3NldXJhdH0KIyBsb2FkKCIvaG9tZS9iaW9pbmZvL0NsdXN0ZXJfdG9fQ29tcHV0ZXJfVHJhbnNmZXJfZmlsZXNfZm9sZGVyL0FsbF9Ob3JtYWwtUEJNQ19BYm5vcm1hbC1jZWxsTGluZXNfVF9jZWxsc19NZXJnZWRfQW5ub3RhdGVkX1VNQVBfb25fQ2x1c3RlcnNfdG9fVVNFLlJvYmoiKQoKbGlicmFyeShhcGUpCmxpYnJhcnkoZGVuZGV4dGVuZCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQoKIyBSZWFkIHRoZSBvYnNlcnZhdGlvbiBncm91cGluZ3MKZ3JvdXBpbmdzIDwtIHJlYWQudGFibGUoIkwxX0wyX1AxX2luZmVyQ05WL2luZmVyY252Lm9ic2VydmF0aW9uX2dyb3VwaW5ncy50eHQiLCBoZWFkZXI9VFJVRSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcm93Lm5hbWVzPTEpCgojIENvbnZlcnQgRGVuZHJvZ3JhbS5Hcm91cCB0byBhIGZhY3RvciwgdGhlbiB0byBudW1lcmljCmdyb3VwaW5ncyREZW5kcm9ncmFtLkdyb3VwX051bWVyaWMgPC0gYXMubnVtZXJpYyhmYWN0b3IoZ3JvdXBpbmdzJERlbmRyb2dyYW0uR3JvdXApKQoKIyBDcmVhdGUgYSBkaXN0YW5jZSBtYXRyaXggYmFzZWQgb24gdGhlIG51bWVyaWMgZGVuZHJvZ3JhbSBncm91cHMKZGlzdF9tYXRyaXggPC0gZGlzdChncm91cGluZ3MkRGVuZHJvZ3JhbS5Hcm91cF9OdW1lcmljKQoKIyBDcmVhdGUgYSBkZW5kcm9ncmFtCmRlbmQgPC0gYXMuZGVuZHJvZ3JhbShoY2x1c3QoZGlzdF9tYXRyaXgpKQoKIyBDb2xvciB0aGUgZGVuZHJvZ3JhbSBicmFuY2hlcwp1bmlxdWVfY29sb3JzIDwtIHVuaXF1ZShncm91cGluZ3MkRGVuZHJvZ3JhbS5Db2xvcikKZGVuZCA8LSBjb2xvcl9icmFuY2hlcyhkZW5kLCBrPWxlbmd0aCh1bmlxdWUoZ3JvdXBpbmdzJERlbmRyb2dyYW0uR3JvdXApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sPXVuaXF1ZV9jb2xvcnMpCgojIENvbnZlcnQgdG8gTmV3aWNrIGZvcm1hdCBhbmQgd3JpdGUgdG8gZmlsZQpuZXdpY2sgPC0gd3JpdGUudHJlZShhcy5waHlsbyhkZW5kKSkKd3JpdGUobmV3aWNrLCBmaWxlPSJpbmZlcmNudi5vYnNlcnZhdGlvbnNfZGVuZHJvZ3JhbS50eHQiKQoKIyBQbG90IHRoZSBkZW5kcm9ncmFtCnBsb3QoZGVuZCwgbWFpbj0iRGVuZHJvZ3JhbSBvZiBDZWxscyIpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIGNlbGwgbGluZSBpbmZvcm1hdGlvbgpjZWxsX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBjZWxsID0gcm93bmFtZXMoZ3JvdXBpbmdzKSwKICBjZWxsX2xpbmUgPSBpZmVsc2UoZ3JlcGwoIl5MMV8iLCByb3duYW1lcyhncm91cGluZ3MpKSwgIkwxIiwgCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiXkwyXyIsIHJvd25hbWVzKGdyb3VwaW5ncykpLCAiTDIiLCAiT3RoZXIiKSkKKQoKIyBDcmVhdGUgYSBoZWF0bWFwLWxpa2UgdmlzdWFsaXphdGlvbgpwIDwtIGdncGxvdChjZWxsX2RhdGEsIGFlcyh4PTEsIHk9Y2VsbCwgZmlsbD1jZWxsX2xpbmUpKSArCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJMMSI9ImRhcmtncmVlbiIsICJMMiI9InB1cnBsZSIsICJPdGhlciI9ImdyYXkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGxhYnMoeD1OVUxMLCB5PU5VTEwsIGZpbGw9IkNlbGwgTGluZSIsIHRpdGxlPSJDZWxsIExpbmUgRGlzdHJpYnV0aW9uIikKCiMgRGlzcGxheSB0aGUgcGxvdApwcmludChwKQoKIyBQcmludCBzdW1tYXJ5CmNhdCgiTnVtYmVyIG9mIGNlbGxzIGluIEwxOiIsIHN1bShjZWxsX2RhdGEkY2VsbF9saW5lID09ICJMMSIpLCAiXG4iKQpjYXQoIk51bWJlciBvZiBjZWxscyBpbiBMMjoiLCBzdW0oY2VsbF9kYXRhJGNlbGxfbGluZSA9PSAiTDIiKSwgIlxuIikKY2F0KCJOdW1iZXIgb2Ygb3RoZXIgY2VsbHM6Iiwgc3VtKGNlbGxfZGF0YSRjZWxsX2xpbmUgPT0gIk90aGVyIiksICJcbiIpCgojIFByaW50IHRoZSBudW1iZXIgb2YgdW5pcXVlIGdyb3VwcwpjYXQoIk51bWJlciBvZiB1bmlxdWUgRGVuZHJvZ3JhbSBHcm91cHM6IiwgbGVuZ3RoKHVuaXF1ZShncm91cGluZ3MkRGVuZHJvZ3JhbS5Hcm91cCkpLCAiXG4iKQoKYGBgCgoKIyAzLiBQaHlsb2dlbmV5IG9mIGluZmVyQ05WCmBgYHtyIHBoeWxvZ2VueV9pbmZlckNOVl9MMUwyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ2RlbmRybykKbGlicmFyeShkZW5kZXh0ZW5kKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeSh0aWJibGUpCgojIFJlYWQgdGhlIGhlYXRtYXAgdGhyZXNob2xkcwp0aHJlc2hvbGRzIDwtIHJlYWQudGFibGUoIkwxX0wyX1AxX2luZmVyQ05WL2luZmVyY252LmhlYXRtYXBfdGhyZXNob2xkcy50eHQiLCBoZWFkZXI9RkFMU0UpJFYxCgojIFJlYWQgdGhlIG9ic2VydmF0aW9uIGdyb3VwaW5ncwpncm91cGluZ3MgPC0gcmVhZC50YWJsZSgiTDFfTDJfUDFfaW5mZXJDTlYvaW5mZXJjbnYub2JzZXJ2YXRpb25fZ3JvdXBpbmdzLnR4dCIsIGhlYWRlcj1UUlVFLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFLCByb3cubmFtZXM9MSkKCiMgUHJvY2VzcyB0aGUgZ3JvdXBpbmdzIGRhdGEKbWV0YWRhdGEgPC0gZ3JvdXBpbmdzICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigic2FtcGxlIikgJT4lCiAgcmVuYW1lKAogICAgZGVuZHJvZ3JhbV9ncm91cCA9IERlbmRyb2dyYW0uR3JvdXAsCiAgICBkZW5kcm9ncmFtX2NvbG9yID0gRGVuZHJvZ3JhbS5Db2xvciwKICAgIGFubm90YXRpb25fZ3JvdXAgPSBBbm5vdGF0aW9uLkdyb3VwLAogICAgYW5ub3RhdGlvbl9jb2xvciA9IEFubm90YXRpb24uQ29sb3IKICApICU+JQogIG11dGF0ZSgKICAgIHBhdGllbnQgPSBjYXNlX3doZW4oCiAgICAgIGdyZXBsKCJeTDFffF5MMl8iLCBzYW1wbGUpIH4gIlAxIiwKICAgICAgZ3JlcGwoIl5MM198Xkw0XyIsIHNhbXBsZSkgfiAiUDIiLAogICAgICBncmVwbCgiXkw1X3xeTDZffF5MN18iLCBzYW1wbGUpIH4gIlAzIiwKICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICAgICksCiAgICBhbm5vdGF0aW9uX2dyb3VwID0gYXMuZmFjdG9yKGFubm90YXRpb25fZ3JvdXApICAjIENvbnZlcnQgdG8gZmFjdG9yCiAgKQoKIyBDb252ZXJ0IGRlbmRyb2dyYW1fZ3JvdXAgdG8gbnVtZXJpYyBpZiBpdCdzIG5vdCBhbHJlYWR5Cm1ldGFkYXRhJGRlbmRyb2dyYW1fZ3JvdXAgPC0gYXMubnVtZXJpYyhhcy5mYWN0b3IobWV0YWRhdGEkZGVuZHJvZ3JhbV9ncm91cCkpCgojIFJlbW92ZSByb3dzIHdpdGggTkEgaW4gZGVuZHJvZ3JhbV9ncm91cAptZXRhZGF0YSA8LSBtZXRhZGF0YSAlPiUgZmlsdGVyKCFpcy5uYShkZW5kcm9ncmFtX2dyb3VwKSkKCiMgQ3JlYXRlIGEgZGlzdGFuY2UgbWF0cml4IGJhc2VkIG9uIHRoZSBkZW5kcm9ncmFtIGdyb3VwcwpkaXN0X21hdHJpeCA8LSBkaXN0KG1ldGFkYXRhJGRlbmRyb2dyYW1fZ3JvdXApCgojIENyZWF0ZSBhIGRlbmRyb2dyYW0KZGVuZCA8LSBhcy5kZW5kcm9ncmFtKGhjbHVzdChkaXN0X21hdHJpeCkpCgojIENvbG9yIHRoZSBkZW5kcm9ncmFtIGJyYW5jaGVzCmRlbmQgPC0gY29sb3JfYnJhbmNoZXMoZGVuZCwgaz1sZW5ndGgodW5pcXVlKG1ldGFkYXRhJGRlbmRyb2dyYW1fZ3JvdXApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgY29sPXVuaXF1ZShtZXRhZGF0YSRkZW5kcm9ncmFtX2NvbG9yKSkKCiMgUGxvdCB0aGUgZGVuZHJvZ3JhbQpwMSA8LSBnZ2RlbmRyb2dyYW0oZGVuZCwgcm90YXRlPVRSVUUsIHNpemU9MikgKwogIGxhYnModGl0bGU9IkRlbmRyb2dyYW0gb2YgU8OpemFyeSBDZWxsIExpbmVzIChMMSBhbmQgTDIpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKIyBDcmVhdGUgYSBoZWF0bWFwLWxpa2UgcGxvdCBvZiB0aGUgZ3JvdXBpbmdzCnAyIDwtIGdncGxvdChtZXRhZGF0YSwgYWVzKHg9MSwgeT1zYW1wbGUsIGZpbGw9YW5ub3RhdGlvbl9ncm91cCkpICsKICBnZW9tX3RpbGUoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXNldE5hbWVzKG1ldGFkYXRhJGFubm90YXRpb25fY29sb3IsIG1ldGFkYXRhJGFubm90YXRpb25fZ3JvdXApKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgbGFicyh4PU5VTEwsIHk9TlVMTCwgZmlsbD0iQW5ub3RhdGlvbiBHcm91cCIpCgojIENvbWJpbmUgdGhlIHBsb3RzCmNvbWJpbmVkX3Bsb3QgPC0gcDEgKyBwMiArIHBsb3RfbGF5b3V0KHdpZHRocz1jKDMsIDEpKQoKIyBEaXNwbGF5IHRoZSBwbG90IGluIHRoZSBub3RlYm9vawpjb21iaW5lZF9wbG90CmBgYAoKCgpgYGB7ciBwaHlsb2dlbnlfU2V1cmF0MiwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKIyBSZWFkIHRoZSBvYnNlcnZhdGlvbiBncm91cGluZ3MKZ3JvdXBpbmdzIDwtIHJlYWQudGFibGUoIkwxX0wyX1AxX2luZmVyQ05WL2luZmVyY252Lm9ic2VydmF0aW9uX2dyb3VwaW5ncy50eHQiLCBoZWFkZXI9VFJVRSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwgcm93Lm5hbWVzPTEpCgojIEZpbHRlciBmb3IgTDEgYW5kIEwyIGNlbGxzIGFuZCBjcmVhdGUgYSBkYXRhIGZyYW1lCmwxX2wyX2RhdGEgPC0gZ3JvdXBpbmdzICU+JQogIGZpbHRlcihncmVwbCgiXkwxX3xeTDJfIiwgcm93bmFtZXMoLikpKSAlPiUKICBtdXRhdGUoCiAgICBDZWxsX0xpbmUgPSBpZmVsc2UoZ3JlcGwoIl5MMV8iLCByb3duYW1lcyguKSksICJMMSIsICJMMiIpLAogICAgRGVuZHJvZ3JhbV9Hcm91cCA9IGFzLm51bWVyaWMoZmFjdG9yKERlbmRyb2dyYW0uR3JvdXApKSwKICAgIEFubm90YXRpb25fR3JvdXAgPSBhcy5udW1lcmljKGZhY3RvcihBbm5vdGF0aW9uLkdyb3VwKSkKICApICU+JQogIHNlbGVjdChDZWxsX0xpbmUsIERlbmRyb2dyYW1fR3JvdXAsIEFubm90YXRpb25fR3JvdXApCgojIENyZWF0ZSBhIG1hdHJpeCBmb3IgdGhlIGhlYXRtYXAKaGVhdG1hcF9tYXRyaXggPC0gbDFfbDJfZGF0YSAlPiUKICBzZWxlY3QoRGVuZHJvZ3JhbV9Hcm91cCwgQW5ub3RhdGlvbl9Hcm91cCkgJT4lCiAgYXMubWF0cml4KCkKCnJvd25hbWVzKGhlYXRtYXBfbWF0cml4KSA8LSByb3duYW1lcyhsMV9sMl9kYXRhKQoKIyBDcmVhdGUgYW5ub3RhdGlvbiBmb3IgY2VsbCBsaW5lcwpjZWxsX2xpbmVfYW5ubyA8LSBkYXRhLmZyYW1lKAogIENlbGxfTGluZSA9IGwxX2wyX2RhdGEkQ2VsbF9MaW5lCikKcm93bmFtZXMoY2VsbF9saW5lX2Fubm8pIDwtIHJvd25hbWVzKGwxX2wyX2RhdGEpCgojIENyZWF0ZSBjb2xvciBwYWxldHRlcwpncm91cF9jb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJTZXQzIikpKGxlbmd0aCh1bmlxdWUoYyhoZWF0bWFwX21hdHJpeCkpKSkKCiMgQ3JlYXRlIHRoZSBoZWF0bWFwCnBoZWF0bWFwKAogIGhlYXRtYXBfbWF0cml4LAogIGNvbG9yID0gZ3JvdXBfY29sb3JzLAogIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgc2hvd19yb3duYW1lcyA9IEZBTFNFLAogIGFubm90YXRpb25fcm93ID0gY2VsbF9saW5lX2Fubm8sCiAgYW5ub3RhdGlvbl9jb2xvcnMgPSBsaXN0KENlbGxfTGluZSA9IGMoTDEgPSAiZGFya2dyZWVuIiwgTDIgPSAicHVycGxlIikpLAogIG1haW4gPSAiR3JvdXBpbmdzIG9mIEwxIGFuZCBMMiBTw6l6YXJ5IENlbGwgTGluZXMiLAogIGxhYmVsc19jb2wgPSBjKCJEZW5kcm9ncmFtIEdyb3VwIiwgIkFubm90YXRpb24gR3JvdXAiKQopCmBgYAoKIyA5LiBTYXZlIHRoZSBTZXVyYXQgb2JqZWN0IGFzIGFuIFJvYmogZmlsZQpgYGB7ciBzYXZlUk9CSn0KCiNzYXZlKEFsbF9zYW1wbGVzX01lcmdlZCwgZmlsZSA9ICIuLi81LVNTX1NjUk5BX0RhdGFfQW5hbHlzaXMvNC1TY1NTX015QW5hbHlzaXNfb25fU1MvMC1JbXBvcnRhbnRfUl9PQkovQWxsX3NhbXBsZXNfTWVyZ2VkX1dOTl9jb3JyZWN0X29uX0hQQy5Sb2JqIikKCgpgYGAKCgoKCg==