1 Overview

This notebook combines LIANA results from all 7 SƩzary syndrome cell lines (L1-L7) to identify:

  1. Conserved signaling modules (present across multiple cell lines)
  2. Cell line-specific communication programs (unique to individual lines)
  3. Publication-quality visualizations for manuscript and thesis

2 load libraries

3 Load All LIANA Results

# Helper function to load and label each cell line
read_liana <- function(path, name) {
  df <- read.csv(path)
  df$CellLine <- name
  return(df)
}

# Load all 7 cell lines
L1 <- read_liana("liana_L1_aggregate_results.csv", "L1")
L2 <- read_liana("liana_L2_aggregate_results.csv", "L2")
L3 <- read_liana("liana_L3_aggregate_results.csv", "L3")
L4 <- read_liana("liana_L4_aggregate_results.csv", "L4")
L5 <- read_liana("liana_L5_aggregate_results.csv", "L5")
L6 <- read_liana("liana_L6_aggregate_results.csv", "L6")
L7 <- read_liana("liana_L7_aggregate_results.csv", "L7")


cat("āœ“ Loaded interactions from all 7 cell lines.\n")
āœ“ Loaded interactions from all 7 cell lines.

4 Combine and Process Data

# Combine all data
all_data <- bind_rows(L1, L2, L3, L4, L5, L6, L7)

# Create Interaction Name (Ligand -> Receptor)
all_data$Interaction <- paste(all_data$ligand.complex, "->", all_data$receptor.complex)

cat("\nāœ“ Combined", nrow(all_data), "total interaction records\n")

āœ“ Combined 48958 total interaction records
cat("āœ“ Unique interactions:", length(unique(all_data$Interaction)), "\n")
āœ“ Unique interactions: 605 

4.1 Filter Significant Interactions

# Filter for significant interactions (aggregate_rank <= 0.05 in at least ONE cell line)
top_interactions <- all_data %>%
  filter(aggregate_rank <= 0.05) %>%
  pull(Interaction) %>%
  unique()

cat("\nāœ“ Found", length(top_interactions), "significant interactions (rank ≤ 0.05)\n")

āœ“ Found 544 significant interactions (rank ≤ 0.05)
# Filter the main dataset to keep only these relevant interactions
plot_data <- all_data %>%
  filter(Interaction %in% top_interactions) %>%
  select(Interaction, CellLine, aggregate_rank)

# Show breakdown by cell line
plot_data %>%
  group_by(CellLine) %>%
  summarise(SignificantInteractions = n()) %>%
  print()
# A tibble: 7 Ɨ 2
  CellLine SignificantInteractions
  <chr>                      <int>
1 L1                          6289
2 L2                          1585
3 L3                          4653
4 L4                         12024
5 L5                         10016
6 L6                          3196
7 L7                         10216

4.2 Create Heatmap Matrix

# Transform for Heatmap (Interactions as Rows, Cell Lines as Cols)
# Fix: Summarize duplicates by taking the BEST score (max) for each cell line/interaction
heatmap_matrix <- plot_data %>%
  mutate(Score = -log10(aggregate_rank)) %>%
  group_by(Interaction, CellLine) %>%           # Group by unique ID
  summarise(Score = max(Score), .groups = "drop") %>% # Keep only the BEST score
  pivot_wider(names_from = CellLine, values_from = Score, values_fill = 0) %>%
  as.data.frame()

# Set row names
rownames(heatmap_matrix) <- heatmap_matrix$Interaction
heatmap_matrix$Interaction <- NULL

cat("\nāœ“ Created matrix with", nrow(heatmap_matrix), "interactions Ɨ", ncol(heatmap_matrix), "cell lines\n")

āœ“ Created matrix with 544 interactions Ɨ 7 cell lines

5 Filter for ā€œCore Signaling Backboneā€ (Present in ≄5 cell lines)

# Count how many cell lines each interaction appears in (with significant signal)
interaction_counts <- rowSums(heatmap_matrix > 1.3)  # 1.3 = -log10(0.05)

# Keep only interactions present in at least 5 of 7 cell lines
keep_rows <- interaction_counts >= 5

final_matrix <- heatmap_matrix[keep_rows, ]

# Sort by conservation (most conserved at top)
final_matrix <- final_matrix[order(rowSums(final_matrix > 1.3), decreasing = TRUE), ]

cat("\nāœ“ Identified", nrow(final_matrix), "conserved interactions (present in ≄5 cell lines)\n")

āœ“ Identified 130 conserved interactions (present in ≄5 cell lines)

5.1 Generate Main Figure: Conserved Heatmap

library(ComplexHeatmap)
library(circlize)

# Convert to matrix
final_matrix <- as.matrix(final_matrix)

# Define color function (0 to 5 scale)
col_fun = colorRamp2(c(0, 5), c("white", "firebrick"))

# Create the Heatmap Object
ht = Heatmap(final_matrix,
             name = "-log10(Rank)", # Correct Legend Title!
             col = col_fun,
             cluster_columns = FALSE, # Keep L1-L7 order
             cluster_rows = TRUE,     # Cluster interactions
             show_row_dend = TRUE,
             show_column_dend = FALSE,
             row_names_gp = gpar(fontsize = 7),
             column_names_gp = gpar(fontsize = 10, fontface = "bold"),
             column_title = "Conserved & Cell Line-Specific Signaling",
             border = TRUE)

# Draw it in the notebook
draw(ht)

# Save as PDF (Vector graphic)
pdf("Figure_3_15_Conserved_Heatmap.pdf", width = 8, height = 12)
draw(ht)
dev.off()
png 
  2 
# Save as PNG (Raster image)
png("Figure_3_15_Conserved_Heatmap.png", width = 2400, height = 3600, res = 300)
draw(ht)
dev.off()
png 
  2 

cat("\nāœ“ Heatmap saved with correct legend labels\n")

āœ“ Heatmap saved with correct legend labels

6 Filter for ā€œConserved & Strongā€ Interactions

# 1. Conservation: Must be in >= 5 cell lines
is_conserved <- rowSums(heatmap_matrix > 1.3) >= 5

# 2. Strength: Must have a high max score (e.g., Rank <= 0.001 / Score > 3)
is_strong <- apply(heatmap_matrix, 1, max) > 3

# Combine: Conserved AND Strong
keep_rows <- is_conserved & is_strong

final_matrix <- heatmap_matrix[keep_rows, ]

# Sort by conservation
final_matrix <- final_matrix[order(rowSums(final_matrix > 1.3), decreasing = TRUE), ]

cat("\nāœ“ Filtered from 130 to", nrow(final_matrix), "Conserved & Strong interactions\n")

āœ“ Filtered from 130 to 79 Conserved & Strong interactions

6.1 Generate Main Figure: Conserved Heatmap

library(ComplexHeatmap)
library(circlize)

# Convert to matrix
final_matrix <- as.matrix(final_matrix)

# Define color function (0 to 5 scale)
col_fun = colorRamp2(c(0, 5), c("white", "firebrick"))

# Create the Heatmap Object
ht = Heatmap(final_matrix,
             name = "-log10(Rank)", # Correct Legend Title!
             col = col_fun,
             cluster_columns = FALSE, # Keep L1-L7 order
             cluster_rows = TRUE,     # Cluster interactions
             show_row_dend = TRUE,
             show_column_dend = FALSE,
             row_names_gp = gpar(fontsize = 7),
             column_names_gp = gpar(fontsize = 10, fontface = "bold"),
             column_title = "Conserved & Cell Line-Specific Signaling",
             border = TRUE)

# Draw it in the notebook
draw(ht)

# Save as PDF (Vector graphic)
pdf("Figure_3_15_Conserved_Heatmap.pdf", width = 8, height = 12)
draw(ht)
dev.off()
png 
  2 
# Save as PNG (Raster image)
png("Figure_3_15_Conserved_Heatmap.png", width = 2400, height = 3600, res = 300)
draw(ht)
dev.off()
png 
  2 

cat("\nāœ“ Heatmap saved with correct legend labels\n")

āœ“ Heatmap saved with correct legend labels

6.2 Generate ā€œTop 50 Strongest Interactionsā€ Heatmap

library(ComplexHeatmap)
library(circlize)

# Calculate the "Max Score" for each interaction (best rank across any cell line)
max_scores <- apply(heatmap_matrix, 1, max)

# Select the Top 50 interactions with the highest scores
top_50_names <- names(sort(max_scores, decreasing = TRUE))[1:50]

top50_matrix <- as.matrix(heatmap_matrix[top_50_names, ])

# Sort by conservation within the Top 50
interaction_counts <- rowSums(top50_matrix > 1.3)
top50_matrix <- top50_matrix[order(interaction_counts, decreasing = TRUE), ]

cat("\nāœ“ Created Top 50 matrix with", nrow(top50_matrix), "interactions\n")

āœ“ Created Top 50 matrix with 50 interactions
# Define color function
col_fun = colorRamp2(c(0, 5), c("white", "firebrick"))

# Create the Heatmap
ht_top50 = Heatmap(top50_matrix,
                   name = "-log10(Rank)",
                   col = col_fun,
                   cluster_columns = FALSE,
                   cluster_rows = TRUE,
                   show_row_dend = TRUE,
                   show_column_dend = FALSE,
                   row_names_gp = gpar(fontsize = 8),
                   column_names_gp = gpar(fontsize = 10, fontface = "bold"),
                   column_title = "Top 50 Strongest Interactions",
                   border = TRUE)

# Display
draw(ht_top50)

# Save as PDF
pdf("Figure_Top50_Strongest_Interactions.pdf", width = 8, height = 10)
draw(ht_top50)
dev.off()
png 
  2 
# Save as PNG
png("Figure_Top50_Strongest_Interactions.png", width = 2400, height = 3000, res = 300)
draw(ht_top50)
dev.off()
png 
  2 

cat("\nāœ“ Top 50 heatmap saved\n")

āœ“ Top 50 heatmap saved

7 Identify Conserved Interactions (For Table/Manuscript)


# Find interactions present in 4+ cell lines
conserved_threshold <- 4

conserved_interactions <- final_matrix %>%
  as.data.frame() %>%
  mutate(Interaction = rownames(.)) %>%
  mutate(NumCellLines = rowSums(. > 1.3)) %>%
  filter(NumCellLines >= conserved_threshold) %>%
  arrange(desc(NumCellLines)) %>%
  select(Interaction, NumCellLines, everything())

cat("\n=== CONSERVED INTERACTIONS (present in ≄", conserved_threshold, "cell lines) ===\n")

=== CONSERVED INTERACTIONS (present in ≄ 4 cell lines) ===
# FIX: Use head() instead of print(n=20)
print(head(conserved_interactions, 20))
                  Interaction NumCellLines       L1       L2       L3       L4       L5       L6       L7
APP -> CD74       APP -> CD74            8 2.427044 2.097410 2.540423 3.035142 2.233287 3.433230 3.276978
APP -> RPSA       APP -> RPSA            8 2.859844 1.784693 2.585750 2.082001 1.675984 3.433230 3.276978
B2M -> CD3D       B2M -> CD3D            8 2.409527 2.076219 3.838593 6.619306 4.290847 1.962993 4.055871
B2M -> CD3G       B2M -> CD3G            8 1.711780 1.664896 2.334387 3.061881 2.790122 2.221280 2.963125
B2M -> TFRC       B2M -> TFRC            8 3.107166 2.624036 3.808239 2.829140 2.949735 2.572508 3.001382
BSG -> SLC16A1 BSG -> SLC16A1            8 3.107166 1.873258 2.604569 3.458272 2.437962 1.562134 2.826260
BSG -> SLC16A7 BSG -> SLC16A7            8 3.107166 1.610084 2.728660 2.212417 2.092365 1.962993 2.027920
CALM1 -> HMMR   CALM1 -> HMMR            8 3.049360 1.873258 2.225881 2.518224 2.695310 1.739326 2.462684
CALM1 -> KCNQ5 CALM1 -> KCNQ5            8 3.107166 2.699362 3.808239 2.240883 2.764712 1.770722 3.001051
CALM1 -> PTPRA CALM1 -> PTPRA            8 2.636722 2.464799 3.089644 2.827368 2.308769 2.213511 2.457262
CALM3 -> KCNQ5 CALM3 -> KCNQ5            8 2.520392 1.772887 3.808239 2.244944 2.194104 1.619079 2.397619
CD48 -> CD2       CD48 -> CD2            8 3.210106 2.987327 3.319307 2.934511 2.949735 3.375082 3.276978
CD58 -> CD2       CD58 -> CD2            8 1.711780 2.773591 3.808239 2.623709 2.949735 3.242399 3.233319
COPA -> CD74     COPA -> CD74            8 3.107166 2.987327 1.595022 2.082001 1.758501 1.770722 2.394987
HLA-A -> APLP2 HLA-A -> APLP2            8 1.729698 2.006730 2.434962 2.987269 2.172361 2.575560 3.276978
HLA-A -> CD3D   HLA-A -> CD3D            8 1.745095 1.820641 2.257867 4.643092 3.394427 1.962993 3.480976
HLA-A -> CD3G   HLA-A -> CD3G            8 1.711780 1.490774 2.253768 3.013373 2.733362 2.287128 3.276978
HLA-B -> CANX   HLA-B -> CANX            8 1.775745 1.449518 3.171821 3.446182 3.114564 1.962993 2.150742
HLA-B -> CD3D   HLA-B -> CD3D            8 2.339695 1.659410 2.253768 5.149534 3.407009 1.753069 3.500984
HLA-C -> CD3D   HLA-C -> CD3D            8 2.504882 2.048066 2.253768 4.478311 3.171069 1.562134 3.276978
# Save to CSV
write.csv(conserved_interactions, 
          "Conserved_Interactions.csv", 
          row.names = FALSE)

8 Identify Specific Interactions (For Discussion)


# Find interactions present in 4+ cell lines
conserved_threshold <- 4

conserved_interactions <- final_matrix %>%
  as.data.frame() %>%
  mutate(Interaction = rownames(.)) %>%
  mutate(NumCellLines = rowSums(. > 1.3)) %>%
  filter(NumCellLines >= conserved_threshold) %>%
  arrange(desc(NumCellLines)) %>%
  select(Interaction, NumCellLines, everything())

cat("\n=== CONSERVED INTERACTIONS (present in ≄", conserved_threshold, "cell lines) ===\n")

=== CONSERVED INTERACTIONS (present in ≄ 4 cell lines) ===
# FIX: Use head() instead of print(n=20)
print(head(conserved_interactions, 20))
                  Interaction NumCellLines       L1       L2       L3       L4       L5       L6       L7
APP -> CD74       APP -> CD74            8 2.427044 2.097410 2.540423 3.035142 2.233287 3.433230 3.276978
APP -> RPSA       APP -> RPSA            8 2.859844 1.784693 2.585750 2.082001 1.675984 3.433230 3.276978
B2M -> CD3D       B2M -> CD3D            8 2.409527 2.076219 3.838593 6.619306 4.290847 1.962993 4.055871
B2M -> CD3G       B2M -> CD3G            8 1.711780 1.664896 2.334387 3.061881 2.790122 2.221280 2.963125
B2M -> TFRC       B2M -> TFRC            8 3.107166 2.624036 3.808239 2.829140 2.949735 2.572508 3.001382
BSG -> SLC16A1 BSG -> SLC16A1            8 3.107166 1.873258 2.604569 3.458272 2.437962 1.562134 2.826260
BSG -> SLC16A7 BSG -> SLC16A7            8 3.107166 1.610084 2.728660 2.212417 2.092365 1.962993 2.027920
CALM1 -> HMMR   CALM1 -> HMMR            8 3.049360 1.873258 2.225881 2.518224 2.695310 1.739326 2.462684
CALM1 -> KCNQ5 CALM1 -> KCNQ5            8 3.107166 2.699362 3.808239 2.240883 2.764712 1.770722 3.001051
CALM1 -> PTPRA CALM1 -> PTPRA            8 2.636722 2.464799 3.089644 2.827368 2.308769 2.213511 2.457262
CALM3 -> KCNQ5 CALM3 -> KCNQ5            8 2.520392 1.772887 3.808239 2.244944 2.194104 1.619079 2.397619
CD48 -> CD2       CD48 -> CD2            8 3.210106 2.987327 3.319307 2.934511 2.949735 3.375082 3.276978
CD58 -> CD2       CD58 -> CD2            8 1.711780 2.773591 3.808239 2.623709 2.949735 3.242399 3.233319
COPA -> CD74     COPA -> CD74            8 3.107166 2.987327 1.595022 2.082001 1.758501 1.770722 2.394987
HLA-A -> APLP2 HLA-A -> APLP2            8 1.729698 2.006730 2.434962 2.987269 2.172361 2.575560 3.276978
HLA-A -> CD3D   HLA-A -> CD3D            8 1.745095 1.820641 2.257867 4.643092 3.394427 1.962993 3.480976
HLA-A -> CD3G   HLA-A -> CD3G            8 1.711780 1.490774 2.253768 3.013373 2.733362 2.287128 3.276978
HLA-B -> CANX   HLA-B -> CANX            8 1.775745 1.449518 3.171821 3.446182 3.114564 1.962993 2.150742
HLA-B -> CD3D   HLA-B -> CD3D            8 2.339695 1.659410 2.253768 5.149534 3.407009 1.753069 3.500984
HLA-C -> CD3D   HLA-C -> CD3D            8 2.504882 2.048066 2.253768 4.478311 3.171069 1.562134 3.276978
# Save to CSV
write.csv(conserved_interactions, 
          "Conserved_Interactions.csv", 
          row.names = FALSE)


# Identify Specific Interactions (For Discussion)
```{r, fig.height=8, fig.width=13}
Error: attempt to use zero-length variable name

9 Summary


cat("\n=== SUMMARY STATISTICS ===\n")

=== SUMMARY STATISTICS ===
cat("Total significant interactions analyzed:", nrow(final_matrix), "\n")
Total significant interactions analyzed: 79 
cat("Conserved interactions (≄4 lines):", nrow(conserved_interactions), "\n")
Conserved interactions (≄4 lines): 79 
cat("Cell line-specific interactions (≤2 lines):", nrow(specific_interactions), "\n")
Cell line-specific interactions (≤2 lines): 0 
cat("\nTop 5 most conserved interactions:\n")

Top 5 most conserved interactions:
print(head(conserved_interactions %>% select(Interaction, NumCellLines), 100))
                              Interaction NumCellLines
APP -> CD74                   APP -> CD74            8
APP -> RPSA                   APP -> RPSA            8
B2M -> CD3D                   B2M -> CD3D            8
B2M -> CD3G                   B2M -> CD3G            8
B2M -> TFRC                   B2M -> TFRC            8
BSG -> SLC16A1             BSG -> SLC16A1            8
BSG -> SLC16A7             BSG -> SLC16A7            8
CALM1 -> HMMR               CALM1 -> HMMR            8
CALM1 -> KCNQ5             CALM1 -> KCNQ5            8
CALM1 -> PTPRA             CALM1 -> PTPRA            8
CALM3 -> KCNQ5             CALM3 -> KCNQ5            8
CD48 -> CD2                   CD48 -> CD2            8
CD58 -> CD2                   CD58 -> CD2            8
COPA -> CD74                 COPA -> CD74            8
HLA-A -> APLP2             HLA-A -> APLP2            8
HLA-A -> CD3D               HLA-A -> CD3D            8
HLA-A -> CD3G               HLA-A -> CD3G            8
HLA-B -> CANX               HLA-B -> CANX            8
HLA-B -> CD3D               HLA-B -> CD3D            8
HLA-C -> CD3D               HLA-C -> CD3D            8
HMGB1 -> CXCR4             HMGB1 -> CXCR4            8
HSPA8 -> LDLR               HSPA8 -> LDLR            8
MIF -> CD44_CD74         MIF -> CD44_CD74            8
PKM -> CD44                   PKM -> CD44            8
ADAM10 -> CD44             ADAM10 -> CD44            7
AGTRAP -> RACK1           AGTRAP -> RACK1            7
APP -> LRP10                 APP -> LRP10            7
B2M -> CD247                 B2M -> CD247            7
CALM1 -> KCNN4             CALM1 -> KCNN4            7
CALM2 -> KCNQ5             CALM2 -> KCNQ5            7
CCL5 -> CCR4                 CCL5 -> CCR4            7
CCL5 -> DPP4                 CCL5 -> DPP4            7
CKLF -> CCR4                 CKLF -> CCR4            7
FABP5 -> RXRA               FABP5 -> RXRA            7
GNAI2 -> S1PR1             GNAI2 -> S1PR1            7
GNAI2 -> S1PR4             GNAI2 -> S1PR4            7
GPI -> AMFR                   GPI -> AMFR            7
ICAM1 -> IL2RG             ICAM1 -> IL2RG            7
ICAM3 -> ITGAL             ICAM3 -> ITGAL            7
LGALS1 -> CD69             LGALS1 -> CD69            7
LGALS1 -> ITGB1           LGALS1 -> ITGB1            7
LGALS1 -> PTPRC           LGALS1 -> PTPRC            7
LTA -> RIPK1                 LTA -> RIPK1            7
LTA -> TNFRSF1B           LTA -> TNFRSF1B            7
MIF -> CD74_CXCR4       MIF -> CD74_CXCR4            7
SELPLG -> ITGB2           SELPLG -> ITGB2            7
TGFB1 -> CXCR4             TGFB1 -> CXCR4            7
TGFB1 -> ITGB1             TGFB1 -> ITGB1            7
TGFB1 -> LPP                 TGFB1 -> LPP            7
TIMP1 -> CD63               TIMP1 -> CD63            7
TNF -> TNFRSF1A           TNF -> TNFRSF1A            7
TNF -> TNFRSF1B           TNF -> TNFRSF1B            7
TNF -> TRADD                 TNF -> TRADD            7
TNF -> TRAF2                 TNF -> TRAF2            7
TNFSF10 -> RIPK1         TNFSF10 -> RIPK1            7
TNFSF9 -> TRAF2           TNFSF9 -> TRAF2            7
VIM -> CD44                   VIM -> CD44            7
ADAM10 -> CADM1           ADAM10 -> CADM1            6
ADAM10 -> TSPAN5         ADAM10 -> TSPAN5            6
CCL5 -> SDC4                 CCL5 -> SDC4            6
CD99 -> CD81                 CD99 -> CD81            6
CXCL10 -> SDC4             CXCL10 -> SDC4            6
FN1 -> CD44                   FN1 -> CD44            6
FN1 -> ITGA4_ITGB1     FN1 -> ITGA4_ITGB1            6
FN1 -> ITGA4_ITGB7     FN1 -> ITGA4_ITGB7            6
FN1 -> ITGAV_ITGB1     FN1 -> ITGAV_ITGB1            6
GNAI2 -> ADCY7             GNAI2 -> ADCY7            6
GNAI2 -> F2R                 GNAI2 -> F2R            6
GNAS -> ADCY7               GNAS -> ADCY7            6
HLA-A -> KIR3DL2         HLA-A -> KIR3DL2            6
HLA-B -> KIR3DL2         HLA-B -> KIR3DL2            6
HLA-DRA -> CD4             HLA-DRA -> CD4            6
LTA -> TNFRSF14           LTA -> TNFRSF14            6
LTB -> TNFRSF1A           LTB -> TNFRSF1A            6
NUCB2 -> ERAP1             NUCB2 -> ERAP1            6
PCSK1N -> GPR171         PCSK1N -> GPR171            6
TNF -> ICOS                   TNF -> ICOS            6
TNFSF10 -> TNFRSF10B TNFSF10 -> TNFRSF10B            6
TNFSF9 -> HLA-DPA1     TNFSF9 -> HLA-DPA1            6

10 Session Info


library(UpSetR)

# 1. Prepare Data: Convert heatmap scores to binary (1 = significant, 0 = not)
# Threshold 1.3 corresponds to aggregate_rank <= 0.05 (-log10(0.05) ā‰ˆ 1.3)
upset_df <- as.data.frame(heatmap_matrix > 1.3)
upset_df <- upset_df * 1  # Convert logical TRUE/FALSE to integer 1/0

# 2. Create the UpSet Plot
# This will show:
# - Intersection Size (Bar chart): How many interactions are in each set
# - Set Size (Horizontal bars): Total interactions per cell line
upset(upset_df, 
      sets = c("L7", "L6", "L5", "L4", "L3", "L2", "L1"), # Order of cell lines
      order.by = "freq",         # Order intersections by size (largest overlap first)
      keep.order = TRUE,         # Keep set order fixed
      sets.bar.color = "firebrick", # Match your heatmap color
      main.bar.color = "black",
      matrix.color = "black",
      mainbar.y.label = "Number of Shared Interactions",
      sets.x.label = "Total Significant Interactions",
      text.scale = c(1.5, 1.2, 1.2, 1.2, 1.5, 1.2), # Make fonts readable for paper
      mb.ratio = c(0.6, 0.4))    # Adjust ratio of top bar chart vs matrix


# 3. Save as PDF (Vector)
pdf("Figure_3_15B_UpSetR.pdf", width = 10, height = 7, onefile=FALSE)
upset(upset_df, 
      sets = c("L7", "L6", "L5", "L4", "L3", "L2", "L1"),
      order.by = "freq",
      keep.order = TRUE,
      sets.bar.color = "firebrick",
      mainbar.y.label = "Number of Shared Interactions",
      sets.x.label = "Total Significant Interactions",
      text.scale = c(1.5, 1.2, 1.2, 1.2, 1.5, 1.2))
dev.off()
png 
  2 
# 4. Save as PNG
png("Figure_3_15B_UpSetR.png", width = 3000, height = 2100, res = 300)
upset(upset_df, 
      sets = c("L7", "L6", "L5", "L4", "L3", "L2", "L1"),
      order.by = "freq",
      keep.order = TRUE,
      sets.bar.color = "firebrick",
      mainbar.y.label = "Number of Shared Interactions",
      sets.x.label = "Total Significant Interactions",
      text.scale = c(1.5, 1.2, 1.2, 1.2, 1.5, 1.2))
dev.off()
png 
  2 

cat("\nāœ“ UpSetR plot saved successfully\n")

āœ“ UpSetR plot saved successfully

10.1 Session Info


sessionInfo()
R version 4.5.2 (2025-10-31)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.12.0 
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0  LAPACK version 3.12.0

locale:
 [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C               LC_TIME=fr_FR.UTF-8        LC_COLLATE=en_GB.UTF-8    
 [5] LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=en_GB.UTF-8    LC_PAPER=fr_FR.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Paris
tzcode source: system (glibc)

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] circlize_0.4.17       UpSetR_1.4.0          viridis_0.6.5         viridisLite_0.4.3     ComplexHeatmap_2.26.1
[6] pheatmap_1.0.13       tidyr_1.3.2           ggplot2_4.0.2         dplyr_1.2.0          

loaded via a namespace (and not attached):
 [1] utf8_1.2.6          sass_0.4.10         generics_0.1.4      shape_1.4.6.1       digest_0.6.39       magrittr_2.0.4     
 [7] evaluate_1.0.5      RColorBrewer_1.1-3  iterators_1.0.14    fastmap_1.2.0       plyr_1.8.9          foreach_1.5.2      
[13] doParallel_1.0.17   jsonlite_2.0.0      GlobalOptions_0.1.3 gridExtra_2.3       purrr_1.2.1         scales_1.4.0       
[19] codetools_0.2-20    jquerylib_0.1.4     cli_3.6.5           rlang_1.1.7         crayon_1.5.3        withr_3.0.2        
[25] cachem_1.1.0        yaml_2.3.12         otel_0.2.0          tools_4.5.2         parallel_4.5.2      colorspace_2.1-2   
[31] BiocGenerics_0.56.0 GetoptLong_1.1.0    vctrs_0.7.1         R6_2.6.1            png_0.1-8           magick_2.9.0       
[37] stats4_4.5.2        matrixStats_1.5.0   lifecycle_1.0.5     S4Vectors_0.48.0    IRanges_2.44.0      clue_0.3-66        
[43] cluster_2.1.8.1     pkgconfig_2.0.3     pillar_1.11.1       bslib_0.10.0        gtable_0.3.6        Rcpp_1.1.1         
[49] rsconnect_1.7.0     glue_1.8.0          xfun_0.56           tibble_3.3.1        tidyselect_1.2.1    rstudioapi_0.18.0  
[55] knitr_1.51          dichromat_2.0-0.1   farver_2.1.2        rjson_0.2.23        htmltools_0.5.9     rmarkdown_2.30     
[61] Cairo_1.7-0         compiler_4.5.2      S7_0.2.1           
LS0tCnRpdGxlOiAiQ29tYmluZWQgTElBTkEgQW5hbHlzaXM6IENvbnNlcnZlZCAmIFNwZWNpZmljIFNpZ25hbGluZyIKYXV0aG9yOiAiTmFzaXIgTWFobW9vZCBBYmJhc2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIHRoZW1lOiBqb3VybmFsCi0tLQoKIyBPdmVydmlldwoKVGhpcyBub3RlYm9vayBjb21iaW5lcyBMSUFOQSByZXN1bHRzIGZyb20gYWxsIDcgU8OpemFyeSBzeW5kcm9tZSBjZWxsIGxpbmVzIChMMS1MNykgdG8gaWRlbnRpZnk6CgoxLiAqKkNvbnNlcnZlZCBzaWduYWxpbmcgbW9kdWxlcyoqIChwcmVzZW50IGFjcm9zcyBtdWx0aXBsZSBjZWxsIGxpbmVzKQoyLiAqKkNlbGwgbGluZS1zcGVjaWZpYyBjb21tdW5pY2F0aW9uIHByb2dyYW1zKiogKHVuaXF1ZSB0byBpbmRpdmlkdWFsIGxpbmVzKQozLiAqKlB1YmxpY2F0aW9uLXF1YWxpdHkgdmlzdWFsaXphdGlvbnMqKiBmb3IgbWFudXNjcmlwdCBhbmQgdGhlc2lzCgojIGxvYWQgbGlicmFyaWVzCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQoKCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgICBsaWJyYXJ5KGRwbHlyKSAgICAgICAjIERhdGEgbWFuaXB1bGF0aW9uCiAgICBsaWJyYXJ5KGdncGxvdDIpICAgICAjIFBsb3R0aW5nCiAgICBsaWJyYXJ5KHRpZHlyKSAgICAgICAjIERhdGEgcmVzaGFwaW5nCiAgICBsaWJyYXJ5KHBoZWF0bWFwKSAgICAjIEhlYXRtYXBzCiAgICBsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKSAjIEFkdmFuY2VkIGhlYXRtYXBzCiAgICBsaWJyYXJ5KHZpcmlkaXMpICAgICAjIENvbG9yIHBhbGV0dGVzCiAgICBsaWJyYXJ5KFVwU2V0UikgICAgICAjIFVwU2V0IHBsb3RzCn0pCgpgYGAKCgojIExvYWQgQWxsIExJQU5BIFJlc3VsdHMKYGBge3IgfQojIEhlbHBlciBmdW5jdGlvbiB0byBsb2FkIGFuZCBsYWJlbCBlYWNoIGNlbGwgbGluZQpyZWFkX2xpYW5hIDwtIGZ1bmN0aW9uKHBhdGgsIG5hbWUpIHsKICBkZiA8LSByZWFkLmNzdihwYXRoKQogIGRmJENlbGxMaW5lIDwtIG5hbWUKICByZXR1cm4oZGYpCn0KCiMgTG9hZCBhbGwgNyBjZWxsIGxpbmVzCkwxIDwtIHJlYWRfbGlhbmEoImxpYW5hX0wxX2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMMSIpCkwyIDwtIHJlYWRfbGlhbmEoImxpYW5hX0wyX2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMMiIpCkwzIDwtIHJlYWRfbGlhbmEoImxpYW5hX0wzX2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMMyIpCkw0IDwtIHJlYWRfbGlhbmEoImxpYW5hX0w0X2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMNCIpCkw1IDwtIHJlYWRfbGlhbmEoImxpYW5hX0w1X2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMNSIpCkw2IDwtIHJlYWRfbGlhbmEoImxpYW5hX0w2X2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMNiIpCkw3IDwtIHJlYWRfbGlhbmEoImxpYW5hX0w3X2FnZ3JlZ2F0ZV9yZXN1bHRzLmNzdiIsICJMNyIpCgoKY2F0KCLinJMgTG9hZGVkIGludGVyYWN0aW9ucyBmcm9tIGFsbCA3IGNlbGwgbGluZXMuXG4iKQoKYGBgCgoKIyBDb21iaW5lIGFuZCBQcm9jZXNzIERhdGEKYGBge3IgfQojIENvbWJpbmUgYWxsIGRhdGEKYWxsX2RhdGEgPC0gYmluZF9yb3dzKEwxLCBMMiwgTDMsIEw0LCBMNSwgTDYsIEw3KQoKIyBDcmVhdGUgSW50ZXJhY3Rpb24gTmFtZSAoTGlnYW5kIC0+IFJlY2VwdG9yKQphbGxfZGF0YSRJbnRlcmFjdGlvbiA8LSBwYXN0ZShhbGxfZGF0YSRsaWdhbmQuY29tcGxleCwgIi0+IiwgYWxsX2RhdGEkcmVjZXB0b3IuY29tcGxleCkKCmNhdCgiXG7inJMgQ29tYmluZWQiLCBucm93KGFsbF9kYXRhKSwgInRvdGFsIGludGVyYWN0aW9uIHJlY29yZHNcbiIpCmNhdCgi4pyTIFVuaXF1ZSBpbnRlcmFjdGlvbnM6IiwgbGVuZ3RoKHVuaXF1ZShhbGxfZGF0YSRJbnRlcmFjdGlvbikpLCAiXG4iKQoKYGBgCgojIyAgRmlsdGVyIFNpZ25pZmljYW50IEludGVyYWN0aW9ucwpgYGB7ciB9CiMgRmlsdGVyIGZvciBzaWduaWZpY2FudCBpbnRlcmFjdGlvbnMgKGFnZ3JlZ2F0ZV9yYW5rIDw9IDAuMDUgaW4gYXQgbGVhc3QgT05FIGNlbGwgbGluZSkKdG9wX2ludGVyYWN0aW9ucyA8LSBhbGxfZGF0YSAlPiUKICBmaWx0ZXIoYWdncmVnYXRlX3JhbmsgPD0gMC4wNSkgJT4lCiAgcHVsbChJbnRlcmFjdGlvbikgJT4lCiAgdW5pcXVlKCkKCmNhdCgiXG7inJMgRm91bmQiLCBsZW5ndGgodG9wX2ludGVyYWN0aW9ucyksICJzaWduaWZpY2FudCBpbnRlcmFjdGlvbnMgKHJhbmsg4omkIDAuMDUpXG4iKQoKIyBGaWx0ZXIgdGhlIG1haW4gZGF0YXNldCB0byBrZWVwIG9ubHkgdGhlc2UgcmVsZXZhbnQgaW50ZXJhY3Rpb25zCnBsb3RfZGF0YSA8LSBhbGxfZGF0YSAlPiUKICBmaWx0ZXIoSW50ZXJhY3Rpb24gJWluJSB0b3BfaW50ZXJhY3Rpb25zKSAlPiUKICBzZWxlY3QoSW50ZXJhY3Rpb24sIENlbGxMaW5lLCBhZ2dyZWdhdGVfcmFuaykKCiMgU2hvdyBicmVha2Rvd24gYnkgY2VsbCBsaW5lCnBsb3RfZGF0YSAlPiUKICBncm91cF9ieShDZWxsTGluZSkgJT4lCiAgc3VtbWFyaXNlKFNpZ25pZmljYW50SW50ZXJhY3Rpb25zID0gbigpKSAlPiUKICBwcmludCgpCgpgYGAKCiMjIENyZWF0ZSBIZWF0bWFwIE1hdHJpeApgYGB7ciB9CiMgVHJhbnNmb3JtIGZvciBIZWF0bWFwIChJbnRlcmFjdGlvbnMgYXMgUm93cywgQ2VsbCBMaW5lcyBhcyBDb2xzKQojIEZpeDogU3VtbWFyaXplIGR1cGxpY2F0ZXMgYnkgdGFraW5nIHRoZSBCRVNUIHNjb3JlIChtYXgpIGZvciBlYWNoIGNlbGwgbGluZS9pbnRlcmFjdGlvbgpoZWF0bWFwX21hdHJpeCA8LSBwbG90X2RhdGEgJT4lCiAgbXV0YXRlKFNjb3JlID0gLWxvZzEwKGFnZ3JlZ2F0ZV9yYW5rKSkgJT4lCiAgZ3JvdXBfYnkoSW50ZXJhY3Rpb24sIENlbGxMaW5lKSAlPiUgICAgICAgICAgICMgR3JvdXAgYnkgdW5pcXVlIElECiAgc3VtbWFyaXNlKFNjb3JlID0gbWF4KFNjb3JlKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lICMgS2VlcCBvbmx5IHRoZSBCRVNUIHNjb3JlCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENlbGxMaW5lLCB2YWx1ZXNfZnJvbSA9IFNjb3JlLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKIyBTZXQgcm93IG5hbWVzCnJvd25hbWVzKGhlYXRtYXBfbWF0cml4KSA8LSBoZWF0bWFwX21hdHJpeCRJbnRlcmFjdGlvbgpoZWF0bWFwX21hdHJpeCRJbnRlcmFjdGlvbiA8LSBOVUxMCgpjYXQoIlxu4pyTIENyZWF0ZWQgbWF0cml4IHdpdGgiLCBucm93KGhlYXRtYXBfbWF0cml4KSwgImludGVyYWN0aW9ucyDDlyIsIG5jb2woaGVhdG1hcF9tYXRyaXgpLCAiY2VsbCBsaW5lc1xuIikKCmBgYAoKIyBGaWx0ZXIgZm9yICJDb3JlIFNpZ25hbGluZyBCYWNrYm9uZSIgKFByZXNlbnQgaW4g4omlNSBjZWxsIGxpbmVzKQpgYGB7ciB9CiMgQ291bnQgaG93IG1hbnkgY2VsbCBsaW5lcyBlYWNoIGludGVyYWN0aW9uIGFwcGVhcnMgaW4gKHdpdGggc2lnbmlmaWNhbnQgc2lnbmFsKQppbnRlcmFjdGlvbl9jb3VudHMgPC0gcm93U3VtcyhoZWF0bWFwX21hdHJpeCA+IDEuMykgICMgMS4zID0gLWxvZzEwKDAuMDUpCgojIEtlZXAgb25seSBpbnRlcmFjdGlvbnMgcHJlc2VudCBpbiBhdCBsZWFzdCA1IG9mIDcgY2VsbCBsaW5lcwprZWVwX3Jvd3MgPC0gaW50ZXJhY3Rpb25fY291bnRzID49IDUKCmZpbmFsX21hdHJpeCA8LSBoZWF0bWFwX21hdHJpeFtrZWVwX3Jvd3MsIF0KCiMgU29ydCBieSBjb25zZXJ2YXRpb24gKG1vc3QgY29uc2VydmVkIGF0IHRvcCkKZmluYWxfbWF0cml4IDwtIGZpbmFsX21hdHJpeFtvcmRlcihyb3dTdW1zKGZpbmFsX21hdHJpeCA+IDEuMyksIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQoKY2F0KCJcbuKckyBJZGVudGlmaWVkIiwgbnJvdyhmaW5hbF9tYXRyaXgpLCAiY29uc2VydmVkIGludGVyYWN0aW9ucyAocHJlc2VudCBpbiDiiaU1IGNlbGwgbGluZXMpXG4iKQpgYGAKCgojIyBHZW5lcmF0ZSBNYWluIEZpZ3VyZTogQ29uc2VydmVkIEhlYXRtYXAKYGBge3IsIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD02fQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGNpcmNsaXplKQoKIyBDb252ZXJ0IHRvIG1hdHJpeApmaW5hbF9tYXRyaXggPC0gYXMubWF0cml4KGZpbmFsX21hdHJpeCkKCiMgRGVmaW5lIGNvbG9yIGZ1bmN0aW9uICgwIHRvIDUgc2NhbGUpCmNvbF9mdW4gPSBjb2xvclJhbXAyKGMoMCwgNSksIGMoIndoaXRlIiwgImZpcmVicmljayIpKQoKIyBDcmVhdGUgdGhlIEhlYXRtYXAgT2JqZWN0Cmh0ID0gSGVhdG1hcChmaW5hbF9tYXRyaXgsCiAgICAgICAgICAgICBuYW1lID0gIi1sb2cxMChSYW5rKSIsICMgQ29ycmVjdCBMZWdlbmQgVGl0bGUhCiAgICAgICAgICAgICBjb2wgPSBjb2xfZnVuLAogICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsICMgS2VlcCBMMS1MNyBvcmRlcgogICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwgICAgICMgQ2x1c3RlciBpbnRlcmFjdGlvbnMKICAgICAgICAgICAgIHNob3dfcm93X2RlbmQgPSBUUlVFLAogICAgICAgICAgICAgc2hvd19jb2x1bW5fZGVuZCA9IEZBTFNFLAogICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDcpLAogICAgICAgICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDEwLCBmb250ZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICBjb2x1bW5fdGl0bGUgPSAiQ29uc2VydmVkICYgQ2VsbCBMaW5lLVNwZWNpZmljIFNpZ25hbGluZyIsCiAgICAgICAgICAgICBib3JkZXIgPSBUUlVFKQoKIyBEcmF3IGl0IGluIHRoZSBub3RlYm9vawpkcmF3KGh0KQoKIyBTYXZlIGFzIFBERiAoVmVjdG9yIGdyYXBoaWMpCnBkZigiRmlndXJlXzNfMTVfQ29uc2VydmVkX0hlYXRtYXAucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSAxMikKZHJhdyhodCkKZGV2Lm9mZigpCgojIFNhdmUgYXMgUE5HIChSYXN0ZXIgaW1hZ2UpCnBuZygiRmlndXJlXzNfMTVfQ29uc2VydmVkX0hlYXRtYXAucG5nIiwgd2lkdGggPSAyNDAwLCBoZWlnaHQgPSAzNjAwLCByZXMgPSAzMDApCmRyYXcoaHQpCmRldi5vZmYoKQoKY2F0KCJcbuKckyBIZWF0bWFwIHNhdmVkIHdpdGggY29ycmVjdCBsZWdlbmQgbGFiZWxzXG4iKQpgYGAKCiMgRmlsdGVyIGZvciAiQ29uc2VydmVkICYgU3Ryb25nIiBJbnRlcmFjdGlvbnMKYGBge3IgfQojIDEuIENvbnNlcnZhdGlvbjogTXVzdCBiZSBpbiA+PSA1IGNlbGwgbGluZXMKaXNfY29uc2VydmVkIDwtIHJvd1N1bXMoaGVhdG1hcF9tYXRyaXggPiAxLjMpID49IDUKCiMgMi4gU3RyZW5ndGg6IE11c3QgaGF2ZSBhIGhpZ2ggbWF4IHNjb3JlIChlLmcuLCBSYW5rIDw9IDAuMDAxIC8gU2NvcmUgPiAzKQppc19zdHJvbmcgPC0gYXBwbHkoaGVhdG1hcF9tYXRyaXgsIDEsIG1heCkgPiAzCgojIENvbWJpbmU6IENvbnNlcnZlZCBBTkQgU3Ryb25nCmtlZXBfcm93cyA8LSBpc19jb25zZXJ2ZWQgJiBpc19zdHJvbmcKCmZpbmFsX21hdHJpeCA8LSBoZWF0bWFwX21hdHJpeFtrZWVwX3Jvd3MsIF0KCiMgU29ydCBieSBjb25zZXJ2YXRpb24KZmluYWxfbWF0cml4IDwtIGZpbmFsX21hdHJpeFtvcmRlcihyb3dTdW1zKGZpbmFsX21hdHJpeCA+IDEuMyksIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQoKY2F0KCJcbuKckyBGaWx0ZXJlZCBmcm9tIDEzMCB0byIsIG5yb3coZmluYWxfbWF0cml4KSwgIkNvbnNlcnZlZCAmIFN0cm9uZyBpbnRlcmFjdGlvbnNcbiIpCmBgYAoKCiMjIEdlbmVyYXRlIE1haW4gRmlndXJlOiBDb25zZXJ2ZWQgSGVhdG1hcApgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTZ9CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCgojIENvbnZlcnQgdG8gbWF0cml4CmZpbmFsX21hdHJpeCA8LSBhcy5tYXRyaXgoZmluYWxfbWF0cml4KQoKIyBEZWZpbmUgY29sb3IgZnVuY3Rpb24gKDAgdG8gNSBzY2FsZSkKY29sX2Z1biA9IGNvbG9yUmFtcDIoYygwLCA1KSwgYygid2hpdGUiLCAiZmlyZWJyaWNrIikpCgojIENyZWF0ZSB0aGUgSGVhdG1hcCBPYmplY3QKaHQgPSBIZWF0bWFwKGZpbmFsX21hdHJpeCwKICAgICAgICAgICAgIG5hbWUgPSAiLWxvZzEwKFJhbmspIiwgIyBDb3JyZWN0IExlZ2VuZCBUaXRsZSEKICAgICAgICAgICAgIGNvbCA9IGNvbF9mdW4sCiAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwgIyBLZWVwIEwxLUw3IG9yZGVyCiAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLCAgICAgIyBDbHVzdGVyIGludGVyYWN0aW9ucwogICAgICAgICAgICAgc2hvd19yb3dfZGVuZCA9IFRSVUUsCiAgICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gNyksCiAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gMTAsIGZvbnRmYWNlID0gImJvbGQiKSwKICAgICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICJDb25zZXJ2ZWQgJiBDZWxsIExpbmUtU3BlY2lmaWMgU2lnbmFsaW5nIiwKICAgICAgICAgICAgIGJvcmRlciA9IFRSVUUpCgojIERyYXcgaXQgaW4gdGhlIG5vdGVib29rCmRyYXcoaHQpCgojIFNhdmUgYXMgUERGIChWZWN0b3IgZ3JhcGhpYykKcGRmKCJGaWd1cmVfM18xNV9Db25zZXJ2ZWRfSGVhdG1hcC5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDEyKQpkcmF3KGh0KQpkZXYub2ZmKCkKCiMgU2F2ZSBhcyBQTkcgKFJhc3RlciBpbWFnZSkKcG5nKCJGaWd1cmVfM18xNV9Db25zZXJ2ZWRfSGVhdG1hcC5wbmciLCB3aWR0aCA9IDI0MDAsIGhlaWdodCA9IDM2MDAsIHJlcyA9IDMwMCkKZHJhdyhodCkKZGV2Lm9mZigpCgpjYXQoIlxu4pyTIEhlYXRtYXAgc2F2ZWQgd2l0aCBjb3JyZWN0IGxlZ2VuZCBsYWJlbHNcbiIpCgpgYGAKCgoKCiMjIEdlbmVyYXRlICJUb3AgNTAgU3Ryb25nZXN0IEludGVyYWN0aW9ucyIgSGVhdG1hcApgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTZ9CmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmxpYnJhcnkoY2lyY2xpemUpCgojIENhbGN1bGF0ZSB0aGUgIk1heCBTY29yZSIgZm9yIGVhY2ggaW50ZXJhY3Rpb24gKGJlc3QgcmFuayBhY3Jvc3MgYW55IGNlbGwgbGluZSkKbWF4X3Njb3JlcyA8LSBhcHBseShoZWF0bWFwX21hdHJpeCwgMSwgbWF4KQoKIyBTZWxlY3QgdGhlIFRvcCA1MCBpbnRlcmFjdGlvbnMgd2l0aCB0aGUgaGlnaGVzdCBzY29yZXMKdG9wXzUwX25hbWVzIDwtIG5hbWVzKHNvcnQobWF4X3Njb3JlcywgZGVjcmVhc2luZyA9IFRSVUUpKVsxOjUwXQoKdG9wNTBfbWF0cml4IDwtIGFzLm1hdHJpeChoZWF0bWFwX21hdHJpeFt0b3BfNTBfbmFtZXMsIF0pCgojIFNvcnQgYnkgY29uc2VydmF0aW9uIHdpdGhpbiB0aGUgVG9wIDUwCmludGVyYWN0aW9uX2NvdW50cyA8LSByb3dTdW1zKHRvcDUwX21hdHJpeCA+IDEuMykKdG9wNTBfbWF0cml4IDwtIHRvcDUwX21hdHJpeFtvcmRlcihpbnRlcmFjdGlvbl9jb3VudHMsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQoKY2F0KCJcbuKckyBDcmVhdGVkIFRvcCA1MCBtYXRyaXggd2l0aCIsIG5yb3codG9wNTBfbWF0cml4KSwgImludGVyYWN0aW9uc1xuIikKCiMgRGVmaW5lIGNvbG9yIGZ1bmN0aW9uCmNvbF9mdW4gPSBjb2xvclJhbXAyKGMoMCwgNSksIGMoIndoaXRlIiwgImZpcmVicmljayIpKQoKIyBDcmVhdGUgdGhlIEhlYXRtYXAKaHRfdG9wNTAgPSBIZWF0bWFwKHRvcDUwX21hdHJpeCwKICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiLWxvZzEwKFJhbmspIiwKICAgICAgICAgICAgICAgICAgIGNvbCA9IGNvbF9mdW4sCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBzaG93X3Jvd19kZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA4KSwKICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSAxMCwgZm9udGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgICAgICAgICAgY29sdW1uX3RpdGxlID0gIlRvcCA1MCBTdHJvbmdlc3QgSW50ZXJhY3Rpb25zIiwKICAgICAgICAgICAgICAgICAgIGJvcmRlciA9IFRSVUUpCgojIERpc3BsYXkKZHJhdyhodF90b3A1MCkKCiMgU2F2ZSBhcyBQREYKcGRmKCJGaWd1cmVfVG9wNTBfU3Ryb25nZXN0X0ludGVyYWN0aW9ucy5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDEwKQpkcmF3KGh0X3RvcDUwKQpkZXYub2ZmKCkKCiMgU2F2ZSBhcyBQTkcKcG5nKCJGaWd1cmVfVG9wNTBfU3Ryb25nZXN0X0ludGVyYWN0aW9ucy5wbmciLCB3aWR0aCA9IDI0MDAsIGhlaWdodCA9IDMwMDAsIHJlcyA9IDMwMCkKZHJhdyhodF90b3A1MCkKZGV2Lm9mZigpCgpjYXQoIlxu4pyTIFRvcCA1MCBoZWF0bWFwIHNhdmVkXG4iKQoKYGBgCgojIElkZW50aWZ5IENvbnNlcnZlZCBJbnRlcmFjdGlvbnMgKEZvciBUYWJsZS9NYW51c2NyaXB0KQpgYGB7cn0KCiMgRmluZCBpbnRlcmFjdGlvbnMgcHJlc2VudCBpbiA0KyBjZWxsIGxpbmVzCmNvbnNlcnZlZF90aHJlc2hvbGQgPC0gNAoKY29uc2VydmVkX2ludGVyYWN0aW9ucyA8LSBmaW5hbF9tYXRyaXggJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShJbnRlcmFjdGlvbiA9IHJvd25hbWVzKC4pKSAlPiUKICBtdXRhdGUoTnVtQ2VsbExpbmVzID0gcm93U3VtcyguID4gMS4zKSkgJT4lCiAgZmlsdGVyKE51bUNlbGxMaW5lcyA+PSBjb25zZXJ2ZWRfdGhyZXNob2xkKSAlPiUKICBhcnJhbmdlKGRlc2MoTnVtQ2VsbExpbmVzKSkgJT4lCiAgc2VsZWN0KEludGVyYWN0aW9uLCBOdW1DZWxsTGluZXMsIGV2ZXJ5dGhpbmcoKSkKCmNhdCgiXG49PT0gQ09OU0VSVkVEIElOVEVSQUNUSU9OUyAocHJlc2VudCBpbiDiiaUiLCBjb25zZXJ2ZWRfdGhyZXNob2xkLCAiY2VsbCBsaW5lcykgPT09XG4iKQoKIyBGSVg6IFVzZSBoZWFkKCkgaW5zdGVhZCBvZiBwcmludChuPTIwKQpwcmludChoZWFkKGNvbnNlcnZlZF9pbnRlcmFjdGlvbnMsIDIwKSkKCiMgU2F2ZSB0byBDU1YKd3JpdGUuY3N2KGNvbnNlcnZlZF9pbnRlcmFjdGlvbnMsIAogICAgICAgICAgIkNvbnNlcnZlZF9JbnRlcmFjdGlvbnMuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKIyBJZGVudGlmeSBTcGVjaWZpYyBJbnRlcmFjdGlvbnMgKEZvciBEaXNjdXNzaW9uKQpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTN9CiMgRmluZCBpbnRlcmFjdGlvbnMgdW5pcXVlIHRvIDEtMiBjZWxsIGxpbmVzCnNwZWNpZmljX2ludGVyYWN0aW9ucyA8LSBmaW5hbF9tYXRyaXggJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShJbnRlcmFjdGlvbiA9IHJvd25hbWVzKC4pKSAlPiUKICBtdXRhdGUoTnVtQ2VsbExpbmVzID0gcm93U3VtcyguID4gMS4zKSkgJT4lCiAgZmlsdGVyKE51bUNlbGxMaW5lcyA8PSAyKSAlPiUKICBhcnJhbmdlKE51bUNlbGxMaW5lcykgJT4lCiAgc2VsZWN0KEludGVyYWN0aW9uLCBOdW1DZWxsTGluZXMsIGV2ZXJ5dGhpbmcoKSkKCmNhdCgiXG49PT0gQ0VMTCBMSU5FLVNQRUNJRklDIElOVEVSQUNUSU9OUyAocHJlc2VudCBpbiDiiaQgMiBjZWxsIGxpbmVzKSA9PT1cbiIpCnByaW50KHNwZWNpZmljX2ludGVyYWN0aW9ucywgbiA9IDIwKQoKIyBTYXZlIHNwZWNpZmljIGludGVyYWN0aW9ucyB0byBDU1YKd3JpdGUuY3N2KHNwZWNpZmljX2ludGVyYWN0aW9ucywgCiAgICAgICAgICAiQ2VsbExpbmVTcGVjaWZpY19JbnRlcmFjdGlvbnMuY3N2IiwgCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKCmBgYAoKIyBTdW1tYXJ5CmBgYHtyLCBmaWcuaGVpZ2h0PTExLCBmaWcud2lkdGg9MTJ9CgpjYXQoIlxuPT09IFNVTU1BUlkgU1RBVElTVElDUyA9PT1cbiIpCmNhdCgiVG90YWwgc2lnbmlmaWNhbnQgaW50ZXJhY3Rpb25zIGFuYWx5emVkOiIsIG5yb3coZmluYWxfbWF0cml4KSwgIlxuIikKY2F0KCJDb25zZXJ2ZWQgaW50ZXJhY3Rpb25zICjiiaU0IGxpbmVzKToiLCBucm93KGNvbnNlcnZlZF9pbnRlcmFjdGlvbnMpLCAiXG4iKQpjYXQoIkNlbGwgbGluZS1zcGVjaWZpYyBpbnRlcmFjdGlvbnMgKOKJpDIgbGluZXMpOiIsIG5yb3coc3BlY2lmaWNfaW50ZXJhY3Rpb25zKSwgIlxuIikKY2F0KCJcblRvcCA1IG1vc3QgY29uc2VydmVkIGludGVyYWN0aW9uczpcbiIpCnByaW50KGhlYWQoY29uc2VydmVkX2ludGVyYWN0aW9ucyAlPiUgc2VsZWN0KEludGVyYWN0aW9uLCBOdW1DZWxsTGluZXMpLCAxMDApKQoKCmBgYAojIFNlc3Npb24gSW5mbwpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CgpsaWJyYXJ5KFVwU2V0UikKCiMgMS4gUHJlcGFyZSBEYXRhOiBDb252ZXJ0IGhlYXRtYXAgc2NvcmVzIHRvIGJpbmFyeSAoMSA9IHNpZ25pZmljYW50LCAwID0gbm90KQojIFRocmVzaG9sZCAxLjMgY29ycmVzcG9uZHMgdG8gYWdncmVnYXRlX3JhbmsgPD0gMC4wNSAoLWxvZzEwKDAuMDUpIOKJiCAxLjMpCnVwc2V0X2RmIDwtIGFzLmRhdGEuZnJhbWUoaGVhdG1hcF9tYXRyaXggPiAxLjMpCnVwc2V0X2RmIDwtIHVwc2V0X2RmICogMSAgIyBDb252ZXJ0IGxvZ2ljYWwgVFJVRS9GQUxTRSB0byBpbnRlZ2VyIDEvMAoKIyAyLiBDcmVhdGUgdGhlIFVwU2V0IFBsb3QKIyBUaGlzIHdpbGwgc2hvdzoKIyAtIEludGVyc2VjdGlvbiBTaXplIChCYXIgY2hhcnQpOiBIb3cgbWFueSBpbnRlcmFjdGlvbnMgYXJlIGluIGVhY2ggc2V0CiMgLSBTZXQgU2l6ZSAoSG9yaXpvbnRhbCBiYXJzKTogVG90YWwgaW50ZXJhY3Rpb25zIHBlciBjZWxsIGxpbmUKdXBzZXQodXBzZXRfZGYsIAogICAgICBzZXRzID0gYygiTDciLCAiTDYiLCAiTDUiLCAiTDQiLCAiTDMiLCAiTDIiLCAiTDEiKSwgIyBPcmRlciBvZiBjZWxsIGxpbmVzCiAgICAgIG9yZGVyLmJ5ID0gImZyZXEiLCAgICAgICAgICMgT3JkZXIgaW50ZXJzZWN0aW9ucyBieSBzaXplIChsYXJnZXN0IG92ZXJsYXAgZmlyc3QpCiAgICAgIGtlZXAub3JkZXIgPSBUUlVFLCAgICAgICAgICMgS2VlcCBzZXQgb3JkZXIgZml4ZWQKICAgICAgc2V0cy5iYXIuY29sb3IgPSAiZmlyZWJyaWNrIiwgIyBNYXRjaCB5b3VyIGhlYXRtYXAgY29sb3IKICAgICAgbWFpbi5iYXIuY29sb3IgPSAiYmxhY2siLAogICAgICBtYXRyaXguY29sb3IgPSAiYmxhY2siLAogICAgICBtYWluYmFyLnkubGFiZWwgPSAiTnVtYmVyIG9mIFNoYXJlZCBJbnRlcmFjdGlvbnMiLAogICAgICBzZXRzLngubGFiZWwgPSAiVG90YWwgU2lnbmlmaWNhbnQgSW50ZXJhY3Rpb25zIiwKICAgICAgdGV4dC5zY2FsZSA9IGMoMS41LCAxLjIsIDEuMiwgMS4yLCAxLjUsIDEuMiksICMgTWFrZSBmb250cyByZWFkYWJsZSBmb3IgcGFwZXIKICAgICAgbWIucmF0aW8gPSBjKDAuNiwgMC40KSkgICAgIyBBZGp1c3QgcmF0aW8gb2YgdG9wIGJhciBjaGFydCB2cyBtYXRyaXgKCiMgMy4gU2F2ZSBhcyBQREYgKFZlY3RvcikKcGRmKCJGaWd1cmVfM18xNUJfVXBTZXRSLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDcsIG9uZWZpbGU9RkFMU0UpCnVwc2V0KHVwc2V0X2RmLCAKICAgICAgc2V0cyA9IGMoIkw3IiwgIkw2IiwgIkw1IiwgIkw0IiwgIkwzIiwgIkwyIiwgIkwxIiksCiAgICAgIG9yZGVyLmJ5ID0gImZyZXEiLAogICAgICBrZWVwLm9yZGVyID0gVFJVRSwKICAgICAgc2V0cy5iYXIuY29sb3IgPSAiZmlyZWJyaWNrIiwKICAgICAgbWFpbmJhci55LmxhYmVsID0gIk51bWJlciBvZiBTaGFyZWQgSW50ZXJhY3Rpb25zIiwKICAgICAgc2V0cy54LmxhYmVsID0gIlRvdGFsIFNpZ25pZmljYW50IEludGVyYWN0aW9ucyIsCiAgICAgIHRleHQuc2NhbGUgPSBjKDEuNSwgMS4yLCAxLjIsIDEuMiwgMS41LCAxLjIpKQpkZXYub2ZmKCkKCiMgNC4gU2F2ZSBhcyBQTkcKcG5nKCJGaWd1cmVfM18xNUJfVXBTZXRSLnBuZyIsIHdpZHRoID0gMzAwMCwgaGVpZ2h0ID0gMjEwMCwgcmVzID0gMzAwKQp1cHNldCh1cHNldF9kZiwgCiAgICAgIHNldHMgPSBjKCJMNyIsICJMNiIsICJMNSIsICJMNCIsICJMMyIsICJMMiIsICJMMSIpLAogICAgICBvcmRlci5ieSA9ICJmcmVxIiwKICAgICAga2VlcC5vcmRlciA9IFRSVUUsCiAgICAgIHNldHMuYmFyLmNvbG9yID0gImZpcmVicmljayIsCiAgICAgIG1haW5iYXIueS5sYWJlbCA9ICJOdW1iZXIgb2YgU2hhcmVkIEludGVyYWN0aW9ucyIsCiAgICAgIHNldHMueC5sYWJlbCA9ICJUb3RhbCBTaWduaWZpY2FudCBJbnRlcmFjdGlvbnMiLAogICAgICB0ZXh0LnNjYWxlID0gYygxLjUsIDEuMiwgMS4yLCAxLjIsIDEuNSwgMS4yKSkKZGV2Lm9mZigpCgpjYXQoIlxu4pyTIFVwU2V0UiBwbG90IHNhdmVkIHN1Y2Nlc3NmdWxseVxuIikKCmBgYAoKIyMgU2Vzc2lvbiBJbmZvCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KCnNlc3Npb25JbmZvKCkKCmBgYAoKCgo=