1. load libraries

2. perform infercnv operations to reveal cnv signal


##this is to match the chr-regions to the chr-arms
hg38 = read.delim("../cytoBand_hg38.txt", header = F)
cnv = read.table("../L1/HMM_CNV_predictions.HMMi6.rand_trees.hmm_mode-subclusters.Pnorm_0.5.pred_cnv_regions.dat",header = T) ##from inferCNV resulting files

cytoband = hg38
cytoband <- data.frame(V1=gsub("chr", "", cytoband[,1]), V2=cytoband[,2], V3=cytoband[,3], V4=substring(cytoband$V4, 1, 1), stringsAsFactors=F)
start <- do.call(rbind, lapply(split(cytoband$V2, paste0(cytoband$V1, cytoband$V4)), min))
end <- do.call(rbind, lapply(split(cytoband$V3, paste0(cytoband$V1, cytoband$V4)), max))
cytoband <- data.frame(V1=gsub("p", "", gsub("q", "", rownames(start))), V2=start, V3=end, V4=rownames(start), stringsAsFactors=F)
cytoband <- cytoband [as.vector(unlist(sapply(c(1:22, "X"), function(x) which(cytoband$V1 %in% x)))), ]
cytoband$V4[grep("q", cytoband$V4)] <- "q"
cytoband$V4[grep("p", cytoband$V4)] <- "p"
rownames(cytoband) <- NULL
names(cytoband) = c("chr", "start", "end", "arm")
cytoband$chr_arm = paste0(cytoband$chr, cytoband$arm)
cytoband$chromosome = paste0("chr", cytoband$chr)
cytoband$chr = cytoband$chromosome
cytoband = cytoband[,1:5]


library(dplyr)
cnv$chr = as.character(cnv$chr)
cytoband$chr = as.character(cytoband$chr)
cnv$mid = (as.numeric(cnv$start) + as.numeric(cnv$end))/2
    new = inner_join(cnv,cytoband, by=c("chr"))%>%
          mutate(arm = ifelse(mid >= as.numeric(start.y) & mid <= as.numeric(end.y), chr_arm, NA))%>%
          group_by(chr)%>%
          filter(!is.na(arm)|n()==1)
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
          final_cnv = new[,c(1:6, 10)]

names(final_cnv) = c("cell_group_name", "cnv_name", "state", "chr", "start", "end", "arm")

final_cnv$event = ifelse(final_cnv$state >=4, "gain", "loss")

final_cnv$large_event = paste(final_cnv$arm, final_cnv$event, sep = " ")

final_cnv = final_cnv[!duplicated(final_cnv[,c('cell_group_name', 'large_event')]),]

large_events = unique(final_cnv$large_event)

final_cnv$group = gsub("sample.", "", final_cnv$cell_group_name)

##change the data frame to wide to summarize the event
library(reshape2)
wide = reshape2::dcast(final_cnv, large_event ~ group, value.var = "event", fun.aggregate = length)
##change the table to 0/1
rownames(wide) = wide$large_event
wide = wide[,-1]
wide = as.matrix(ifelse(wide >= 1, 1, 0))
wide = as.data.frame(cbind(wide, total = rowSums(wide)))
new = wide[order(-wide$total),]
new$"1.1.1" = ifelse((new$`1.1.1.1` + new$`1.1.1.2`) >=2, 1, 0)
Error in `$<-.data.frame`(`*tmp*`, "1.1.1", value = logical(0)) : 
  replacement has 0 rows, data has 64

3. perform infercnv operations to reveal cnv signal


library(dplyr)
library(reshape2)

# Read input files
hg38 = read.delim("../cytoBand_hg38.txt", header = F)
cnv = read.table("../L1/HMM_CNV_predictions.HMMi6.rand_trees.hmm_mode-subclusters.Pnorm_0.5.pred_cnv_regions.dat", header = T)

# Process cytoband data
cytoband = hg38
cytoband <- data.frame(V1=gsub("chr", "", cytoband[,1]), V2=cytoband[,2], V3=cytoband[,3], V4=substring(cytoband$V4, 1, 1), stringsAsFactors=F)
start <- do.call(rbind, lapply(split(cytoband$V2, paste0(cytoband$V1, cytoband$V4)), min))
end <- do.call(rbind, lapply(split(cytoband$V3, paste0(cytoband$V1, cytoband$V4)), max))
cytoband <- data.frame(V1=gsub("p", "", gsub("q", "", rownames(start))), V2=start, V3=end, V4=rownames(start), stringsAsFactors=F)
cytoband <- cytoband[as.vector(unlist(sapply(c(1:22, "X"), function(x) which(cytoband$V1 %in% x)))), ]
cytoband$V4[grep("q", cytoband$V4)] <- "q"
cytoband$V4[grep("p", cytoband$V4)] <- "p"
rownames(cytoband) <- NULL
names(cytoband) = c("chr", "start", "end", "arm")
cytoband$chr_arm = paste0(cytoband$chr, cytoband$arm)
cytoband$chromosome = paste0("chr", cytoband$chr)
cytoband$chr = cytoband$chromosome
cytoband = cytoband[,1:5]

# Process CNV data
cnv$chr = as.character(cnv$chr)
cytoband$chr = as.character(cytoband$chr)
cnv$mid = (as.numeric(cnv$start) + as.numeric(cnv$end))/2

# Join CNV and cytoband data
new = inner_join(cnv, cytoband, by=c("chr")) %>%
      mutate(arm = ifelse(mid >= as.numeric(start.y) & mid <= as.numeric(end.y), chr_arm, NA)) %>%
      group_by(chr) %>%
      filter(!is.na(arm) | n()==1)
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
final_cnv = new[,c(1:6, 10)]

names(final_cnv) = c("cell_group_name", "cnv_name", "state", "chr", "start", "end", "arm")

final_cnv$event = ifelse(final_cnv$state >= 4, "gain", "loss")
final_cnv$large_event = paste(final_cnv$arm, final_cnv$event, sep = " ")
final_cnv = final_cnv[!duplicated(final_cnv[,c('cell_group_name', 'large_event')]),]
final_cnv$group = gsub("sample.", "", final_cnv$cell_group_name)

# Create wide format data
wide = dcast(final_cnv, large_event ~ group, value.var = "event", fun.aggregate = length)
rownames(wide) = wide$large_event
wide = wide[,-1]
wide = as.matrix(ifelse(wide >= 1, 1, 0))
wide = as.data.frame(cbind(wide, total = rowSums(wide)))
new = wide[order(-wide$total),]

# Create new columns based on existing ones
new$"L1.L1.1.1" = ifelse((new$L1.L1.1.1.1.1 + new$L1.L1.1.1.1.2) >= 2, 1, 0)
new$"L1.L1.1.2" = ifelse((new$L1.L1.1.2.1.1 + new$L1.L1.1.2.1.2) >= 2, 1, 0)
new$"L1.L1.1" = ifelse((new$L1.L1.1.1 + new$L1.L1.1.2) >= 2, 1, 0)
new$"L1.L1.2.1" = ifelse((new$L1.L1.1.2.2.1 + new$L1.L1.1.2.2.2) >= 2, 1, 0)
new$"L1.L1.2" = new$L1.L1.2.1
new$"L1.L1" = ifelse((new$L1.L1.1 + new$L1.L1.2) >= 2, 1, 0)

# Reorder columns
new_order = c("L1.L1", "L1.L1.1", "L1.L1.1.1", "L1.L1.1.1.1.1", "L1.L1.1.1.1.2", 
              "L1.L1.1.2", "L1.L1.1.2.1.1", "L1.L1.1.2.1.2", 
              "L1.L1.2", "L1.L1.2.1", "L1.L1.1.2.2.1", "L1.L1.1.2.2.2", "total")
new = new[, c(new_order, setdiff(names(new), new_order))]

write.csv(new, "../L1/events.csv", row.names = TRUE)

# Calculate percentage of each CNV event
tryCatch({
  # Read the file as a single column
  cell_group = read.csv("../../uphyloplot2-2.3/Inputs/L1.cell_groupings", 
                        header = FALSE, stringsAsFactors = FALSE)
  
  # Split the column into two based on the tab character
  cell_group = data.frame(do.call('rbind', strsplit(as.character(cell_group$V1), '\t', fixed=TRUE)))
  colnames(cell_group) = c("cell_group_name", "cell")
  
  # Remove the header row
  cell_group = cell_group[-1,]
  
  print("Structure of cell_group:")
  print(str(cell_group))
  
  # Create group dataframe
  group = as.data.frame(table(cell_group$cell_group_name))
  colnames(group) = c("cell_group_name", "count")
  rownames(group) = group$cell_group_name
  
  print("Structure of group:")
  print(str(group))
  
  # Assuming 'new' is your dataframe with CNV events
  per = new[, setdiff(names(new), "total")]
  
  print("Columns of per:")
  print(colnames(per))
  
  print("Rows of group:")
  print(rownames(group))
  
  matching_rows = intersect(rownames(group), colnames(per))
  if(length(matching_rows) == 0) {
    stop("No matching row names between group and columns of per.")
  }
  
  # Calculate percentages
  percentage = per[, matching_rows] * group[matching_rows, "count"]
  
  # Calculate total cells for each CNV event
  total_cells = rowSums(percentage)
  
  # Convert counts to percentages
  percentage = sweep(percentage, 1, total_cells, "/") * 100
  
  # Add total percentage column
  percentage$sample = rowSums(percentage)
  
  write.csv(percentage, "../L1/sample_events_percentage.csv", row.names = TRUE)
  
  print("Percentage calculation completed successfully.")
}, error = function(e) {
  print(paste("An error occurred:", e$message))
})
[1] "Structure of cell_group:"
'data.frame':   5825 obs. of  2 variables:
 $ cell_group_name: chr  "L1.L1.1.1.1.1" "L1.L1.1.1.1.1" "L1.L1.1.1.1.1" "L1.L1.1.1.1.1" ...
 $ cell           : chr  "L1_AAACCTGAGGGCTTCC-1" "L1_AAACCTGGTGCAGGTA-1" "L1_AAACCTGTCCCTGACT-1" "L1_AAACCTGTCCTTCAAT-1" ...
NULL
[1] "Structure of group:"
'data.frame':   8 obs. of  2 variables:
 $ cell_group_name: Factor w/ 8 levels "L1.L1.1.1.1.1",..: 1 2 3 4 5 6 7 8
 $ count          : int  1462 14 211 151 2564 1025 325 73
NULL
[1] "Columns of per:"
 [1] "L1.L1"             "L1.L1.1"           "L1.L1.1.1"         "L1.L1.1.1.1.1"     "L1.L1.1.1.1.2"     "L1.L1.1.2"         "L1.L1.1.2.1.1"     "L1.L1.1.2.1.2"    
 [9] "L1.L1.2"           "L1.L1.2.1"         "L1.L1.1.2.2.1"     "L1.L1.1.2.2.2"     "L1.L1.1.1.2.1"     "L1.L1.1.1.2.2"     "PBMC.PBMC.1.1.1.2" "PBMC.PBMC.1.2.1.1"
[17] "PBMC.PBMC.1.2.1.2" "PBMC.PBMC.1.2.2"  
[1] "Rows of group:"
[1] "L1.L1.1.1.1.1" "L1.L1.1.1.1.2" "L1.L1.1.1.2.1" "L1.L1.1.1.2.2" "L1.L1.1.2.1.1" "L1.L1.1.2.1.2" "L1.L1.1.2.2.1" "L1.L1.1.2.2.2"
[1] "Percentage calculation completed successfully."

2. perform infercnv operations to reveal cnv signal



library(dplyr)
library(readr)

# Read the .cell_groupings file, skipping the first row which is an extra header
cell_groupings_file <- "../L7/L7.cell_groupings"
cell_mapping <- read_tsv(cell_groupings_file, col_names = c("cell_group_name", "cell_id"))
Rows: 5332 Columns: 2── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (2): cell_group_name, cell_id
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Filter for only L1 cells
cell_mapping <- cell_mapping %>%
  filter(grepl("^L7_", cell_id))

# Write the mapping to a CSV file
write_csv(cell_mapping, "../L7/cell_to_group_mapping.csv")

# Print the first few rows to verify
print(head(cell_mapping))

# Print the number of rows to verify it's not empty
print(paste("Number of rows in cell_mapping:", nrow(cell_mapping)))
[1] "Number of rows in cell_mapping: 5331"
library(dplyr)
library(tidyr)

# Read the CNV data
cnv_data <- read.csv("../L7/L7_infercnv_with_chr_bands.csv", stringsAsFactors = FALSE)

# Read the cell to cell group mapping file
# This file should have columns: cell_id, cell_group_name
cell_mapping <- read.csv("../L7/cell_to_group_mapping.csv", stringsAsFactors = FALSE)

# Join the CNV data with the cell mapping
expanded_cnv_data <- cnv_data %>%
  left_join(cell_mapping, by = "cell_group_name") %>%
  select(-cell_group_name) %>%  # Remove the cell group column
  rename(cell_id = cell_id)  # Rename for clarity

# Count total number of cells
total_cells <- nrow(cell_mapping)

# Process the expanded data
cnv_summary <- expanded_cnv_data %>%
  # Group by chromosome band and CNV state
  group_by(chr_band, state) %>%
  # Count cells for each CNV event
  summarize(
    cell_count = n(),
    .groups = 'drop'
  ) %>%
  # Calculate percentage
  mutate(
    percentage = (cell_count / total_cells) * 100,
    cnv_type = case_when(
      state == 1 ~ "Complete Loss (0x)",
      state == 2 ~ "Loss of One Copy (0.5x)",
      state == 3 ~ "Neutral (1x)",
      state == 4 ~ "Addition of One Copy (1.5x)",
      state == 5 ~ "Addition of Two Copies (2x)",
      state == 6 ~ "Placeholder for >2x Copies (3x)"
    )
  ) %>%
  # Select relevant columns and sort
  select(chr_band, cnv_type, cell_count, percentage) %>%
  arrange(desc(percentage))

# Display the results
print(cnv_summary)

# Optionally, write to a CSV file
write.csv(cnv_summary, "../L7/cnv_event_percentages_by_cell.csv", row.names = FALSE)

Visualization_L1


# Load necessary libraries
library(dplyr)
library(readr)
library(ggplot2)
library(gtable)

# Step 1: Read the CNV data file
significant_cnv_data <- read_csv("../L1/cnv_event_percentages_by_cell.csv")
Rows: 1598 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): chr_band, cnv_type
dbl (2): cell_count, percentage
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Verify that the data was read correctly
print(head(significant_cnv_data))

# Step 2: Filter data to only include rows with a percentage > 5%
filtered_cnv_data <- significant_cnv_data %>%
  filter(percentage > 10)  # Change 5 to 90 if you want to filter for >90%

# Step 3: Create the bar plot using the filtered data
ggplot(filtered_cnv_data, aes(x = percentage, y = reorder(chr_band, percentage), fill = cnv_type)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +  # Adjusted bar width
  scale_fill_manual(values = c("Complete Loss (0x)" = "#fdae61",  # Orange for complete loss
                               "Loss of One Copy (0.5x)" = "#313695",  # Blue for partial loss
                               "Addition of One Copy (1.5x)" = "red",  # Red for gain
                               "Addition of Two Copies (2x)" = "darkgreen")) +  # Green for higher gain
  labs(
    title = "Significant CNVs Affecting >10% of Cells",  # Update title accordingly
    subtitle = "Chromosomal Bands with CNVs in >10% of Cells",  # Update subtitle accordingly
    x = "Percentage of Cells (%)",
    y = "Chromosomal Band",
    fill = "CNV Type"
  ) +
  theme_minimal(base_size = 14) +  # Adjust text size for readability
  theme(
    axis.title.x = element_text(size = 14, face = "bold"),
    axis.title.y = element_text(size = 14, face = "bold"),
    axis.text.y = element_text(size = 12),
    axis.text.x = element_text(size = 12),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10)
  )

NA
NA
NA
NA

Visualization_L2


# Load necessary libraries
library(dplyr)
library(readr)
library(ggplot2)
library(gtable)

# Step 1: Read the CNV data file
significant_cnv_data <- read_csv("../L2/cnv_event_percentages_by_cell.csv")
Rows: 1631 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): chr_band, cnv_type
dbl (2): cell_count, percentage
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Verify that the data was read correctly
print(head(significant_cnv_data))

# Step 2: Filter data to only include rows with a percentage > 5%
filtered_cnv_data <- significant_cnv_data %>%
  filter(percentage > 15)  # Change 5 to 90 if you want to filter for >90%

# Step 3: Create the bar plot using the filtered data
ggplot(filtered_cnv_data, aes(x = percentage, y = reorder(chr_band, percentage), fill = cnv_type)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +  # Adjusted bar width
  scale_fill_manual(values = c("Complete Loss (0x)" = "#fdae61",  # Orange for complete loss
                               "Loss of One Copy (0.5x)" = "#313695",  # Blue for partial loss
                               "Addition of One Copy (1.5x)" = "red",  # Red for gain
                               "Addition of Two Copies (2x)" = "darkgreen")) +  # Green for higher gain
  labs(
    title = "Significant CNVs Affecting >15% of Cells",  # Update title accordingly
    subtitle = "Chromosomal Bands with CNVs in >15% of Cells",  # Update subtitle accordingly
    x = "Percentage of Cells (%)",
    y = "Chromosomal Band",
    fill = "CNV Type"
  ) +
  theme_minimal(base_size = 14) +  # Adjust text size for readability
  theme(
    axis.title.x = element_text(size = 14, face = "bold"),
    axis.title.y = element_text(size = 14, face = "bold"),
    axis.text.y = element_text(size = 12),
    axis.text.x = element_text(size = 12),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10)
  )

NA
NA
NA
NA

Visualization_L3


# Load necessary libraries
library(dplyr)
library(readr)
library(ggplot2)
library(gtable)

# Step 1: Read the CNV data file
significant_cnv_data <- read_csv("../L3/cnv_event_percentages_by_cell.csv")
Rows: 1569 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): chr_band, cnv_type
dbl (2): cell_count, percentage
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Verify that the data was read correctly
print(head(significant_cnv_data))

# Step 2: Filter data to only include rows with a percentage > 5%
filtered_cnv_data <- significant_cnv_data %>%
  filter(percentage > 15)  # Change 5 to 90 if you want to filter for >90%

# Step 3: Create the bar plot using the filtered data
ggplot(filtered_cnv_data, aes(x = percentage, y = reorder(chr_band, percentage), fill = cnv_type)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +  # Adjusted bar width
  scale_fill_manual(values = c("Complete Loss (0x)" = "#fdae61",  # Orange for complete loss
                               "Loss of One Copy (0.5x)" = "#313695",  # Blue for partial loss
                               "Addition of One Copy (1.5x)" = "red",  # Red for gain
                               "Addition of Two Copies (2x)" = "darkgreen")) +  # Green for higher gain
  labs(
    title = "Significant CNVs Affecting >15% of Cells",  # Update title accordingly
    subtitle = "Chromosomal Bands with CNVs in >15% of Cells",  # Update subtitle accordingly
    x = "Percentage of Cells (%)",
    y = "Chromosomal Band",
    fill = "CNV Type"
  ) +
  theme_minimal(base_size = 14) +  # Adjust text size for readability
  theme(
    axis.title.x = element_text(size = 14, face = "bold"),
    axis.title.y = element_text(size = 14, face = "bold"),
    axis.text.y = element_text(size = 12),
    axis.text.x = element_text(size = 12),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10)
  )

NA
NA
NA
NA

Visualization_L4


# Load necessary libraries
library(dplyr)
library(readr)
library(ggplot2)
library(gtable)

# Step 1: Read the CNV data file
significant_cnv_data <- read_csv("../L4/cnv_event_percentages_by_cell.csv")
Rows: 2090 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): chr_band, cnv_type
dbl (2): cell_count, percentage
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Verify that the data was read correctly
print(head(significant_cnv_data))

# Step 2: Filter data to only include rows with a percentage > 5%
filtered_cnv_data <- significant_cnv_data %>%
  filter(percentage > 15)  # Change 5 to 90 if you want to filter for >90%

# Step 3: Create the bar plot using the filtered data
ggplot(filtered_cnv_data, aes(x = percentage, y = reorder(chr_band, percentage), fill = cnv_type)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +  # Adjusted bar width
  scale_fill_manual(values = c("Complete Loss (0x)" = "#fdae61",  # Orange for complete loss
                               "Loss of One Copy (0.5x)" = "#313695",  # Blue for partial loss
                               "Addition of One Copy (1.5x)" = "red",  # Red for gain
                               "Addition of Two Copies (2x)" = "darkgreen")) +  # Green for higher gain
  labs(
    title = "Significant CNVs Affecting >15% of Cells",  # Update title accordingly
    subtitle = "Chromosomal Bands with CNVs in >15% of Cells",  # Update subtitle accordingly
    x = "Percentage of Cells (%)",
    y = "Chromosomal Band",
    fill = "CNV Type"
  ) +
  theme_minimal(base_size = 14) +  # Adjust text size for readability
  theme(
    axis.title.x = element_text(size = 14, face = "bold"),
    axis.title.y = element_text(size = 14, face = "bold"),
    axis.text.y = element_text(size = 12),
    axis.text.x = element_text(size = 12),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10)
  )

NA
NA
NA
NA

Visualization_L7


# Load necessary libraries
library(dplyr)
library(readr)
library(ggplot2)
library(gtable)

# Step 1: Read the CNV data file
significant_cnv_data <- read_csv("../L7/cnv_event_percentages_by_cell.csv")
Rows: 2085 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): chr_band, cnv_type
dbl (2): cell_count, percentage
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Verify that the data was read correctly
print(head(significant_cnv_data))

# Step 2: Filter data to only include rows with a percentage > 5%
filtered_cnv_data <- significant_cnv_data %>%
  filter(percentage > 15)  # Change 5 to 90 if you want to filter for >90%

# Step 3: Create the bar plot using the filtered data
ggplot(filtered_cnv_data, aes(x = percentage, y = reorder(chr_band, percentage), fill = cnv_type)) +
  geom_bar(stat = "identity", position = "dodge", width = 0.8) +  # Adjusted bar width
  scale_fill_manual(values = c("Complete Loss (0x)" = "#fdae61",  # Orange for complete loss
                               "Loss of One Copy (0.5x)" = "#313695",  # Blue for partial loss
                               "Addition of One Copy (1.5x)" = "red",  # Red for gain
                               "Addition of Two Copies (2x)" = "darkgreen")) +  # Green for higher gain
  labs(
    title = "Significant CNVs Affecting >15% of Cells",  # Update title accordingly
    subtitle = "Chromosomal Bands with CNVs in >15% of Cells",  # Update subtitle accordingly
    x = "Percentage of Cells (%)",
    y = "Chromosomal Band",
    fill = "CNV Type"
  ) +
  theme_minimal(base_size = 14) +  # Adjust text size for readability
  theme(
    axis.title.x = element_text(size = 14, face = "bold"),
    axis.title.y = element_text(size = 14, face = "bold"),
    axis.text.y = element_text(size = 12),
    axis.text.x = element_text(size = 12),
    legend.title = element_text(size = 12, face = "bold"),
    legend.text = element_text(size = 10)
  )

NA
NA
NA
NA
LS0tCnRpdGxlOiAiSW5mZXJDTlYgQW5hbHlzaXMtU2lsdmlhLVNjcmlwdHMiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgI3JtZGZvcm1hdHM6OnJlYWR0aGVkb3duCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCi0tLQoKIyAxLiBsb2FkIGxpYnJhcmllcwpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCgojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKCgpgYGAKCgojIDIuIHBlcmZvcm0gaW5mZXJjbnYgb3BlcmF0aW9ucyB0byByZXZlYWwgY252IHNpZ25hbApgYGB7ciBDTlZfc2lnbmFsLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCiMjdGhpcyBpcyB0byBtYXRjaCB0aGUgY2hyLXJlZ2lvbnMgdG8gdGhlIGNoci1hcm1zCiMgaGczOCA9IHJlYWQuZGVsaW0oIi4uL2N5dG9CYW5kX2hnMzgudHh0IiwgaGVhZGVyID0gRikKIyBjbnYgPSByZWFkLnRhYmxlKCIuLi9MMS9ITU1fQ05WX3ByZWRpY3Rpb25zLkhNTWk2LnJhbmRfdHJlZXMuaG1tX21vZGUtc3ViY2x1c3RlcnMuUG5vcm1fMC41LnByZWRfY252X3JlZ2lvbnMuZGF0IixoZWFkZXIgPSBUKSAjI2Zyb20gaW5mZXJDTlYgcmVzdWx0aW5nIGZpbGVzCiMgCiMgY3l0b2JhbmQgPSBoZzM4CiMgY3l0b2JhbmQgPC0gZGF0YS5mcmFtZShWMT1nc3ViKCJjaHIiLCAiIiwgY3l0b2JhbmRbLDFdKSwgVjI9Y3l0b2JhbmRbLDJdLCBWMz1jeXRvYmFuZFssM10sIFY0PXN1YnN0cmluZyhjeXRvYmFuZCRWNCwgMSwgMSksIHN0cmluZ3NBc0ZhY3RvcnM9RikKIyBzdGFydCA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoc3BsaXQoY3l0b2JhbmQkVjIsIHBhc3RlMChjeXRvYmFuZCRWMSwgY3l0b2JhbmQkVjQpKSwgbWluKSkKIyBlbmQgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KHNwbGl0KGN5dG9iYW5kJFYzLCBwYXN0ZTAoY3l0b2JhbmQkVjEsIGN5dG9iYW5kJFY0KSksIG1heCkpCiMgY3l0b2JhbmQgPC0gZGF0YS5mcmFtZShWMT1nc3ViKCJwIiwgIiIsIGdzdWIoInEiLCAiIiwgcm93bmFtZXMoc3RhcnQpKSksIFYyPXN0YXJ0LCBWMz1lbmQsIFY0PXJvd25hbWVzKHN0YXJ0KSwgc3RyaW5nc0FzRmFjdG9ycz1GKQojIGN5dG9iYW5kIDwtIGN5dG9iYW5kIFthcy52ZWN0b3IodW5saXN0KHNhcHBseShjKDE6MjIsICJYIiksIGZ1bmN0aW9uKHgpIHdoaWNoKGN5dG9iYW5kJFYxICVpbiUgeCkpKSksIF0KIyBjeXRvYmFuZCRWNFtncmVwKCJxIiwgY3l0b2JhbmQkVjQpXSA8LSAicSIKIyBjeXRvYmFuZCRWNFtncmVwKCJwIiwgY3l0b2JhbmQkVjQpXSA8LSAicCIKIyByb3duYW1lcyhjeXRvYmFuZCkgPC0gTlVMTAojIG5hbWVzKGN5dG9iYW5kKSA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAiYXJtIikKIyBjeXRvYmFuZCRjaHJfYXJtID0gcGFzdGUwKGN5dG9iYW5kJGNociwgY3l0b2JhbmQkYXJtKQojIGN5dG9iYW5kJGNocm9tb3NvbWUgPSBwYXN0ZTAoImNociIsIGN5dG9iYW5kJGNocikKIyBjeXRvYmFuZCRjaHIgPSBjeXRvYmFuZCRjaHJvbW9zb21lCiMgY3l0b2JhbmQgPSBjeXRvYmFuZFssMTo1XQojIAojIAojIGxpYnJhcnkoZHBseXIpCiMgY252JGNociA9IGFzLmNoYXJhY3RlcihjbnYkY2hyKQojIGN5dG9iYW5kJGNociA9IGFzLmNoYXJhY3RlcihjeXRvYmFuZCRjaHIpCiMgY252JG1pZCA9IChhcy5udW1lcmljKGNudiRzdGFydCkgKyBhcy5udW1lcmljKGNudiRlbmQpKS8yCiMgICAgIG5ldyA9IGlubmVyX2pvaW4oY252LGN5dG9iYW5kLCBieT1jKCJjaHIiKSklPiUKIyAgICAgICAgICAgbXV0YXRlKGFybSA9IGlmZWxzZShtaWQgPj0gYXMubnVtZXJpYyhzdGFydC55KSAmIG1pZCA8PSBhcy5udW1lcmljKGVuZC55KSwgY2hyX2FybSwgTkEpKSU+JQojICAgICAgICAgICBncm91cF9ieShjaHIpJT4lCiMgICAgICAgICAgIGZpbHRlcighaXMubmEoYXJtKXxuKCk9PTEpCiMgICAgICAgICAgIGZpbmFsX2NudiA9IG5ld1ssYygxOjYsIDEwKV0KIyAKIyBuYW1lcyhmaW5hbF9jbnYpID0gYygiY2VsbF9ncm91cF9uYW1lIiwgImNudl9uYW1lIiwgInN0YXRlIiwgImNociIsICJzdGFydCIsICJlbmQiLCAiYXJtIikKIyAKIyBmaW5hbF9jbnYkZXZlbnQgPSBpZmVsc2UoZmluYWxfY252JHN0YXRlID49NCwgImdhaW4iLCAibG9zcyIpCiMgCiMgZmluYWxfY252JGxhcmdlX2V2ZW50ID0gcGFzdGUoZmluYWxfY252JGFybSwgZmluYWxfY252JGV2ZW50LCBzZXAgPSAiICIpCiMgCiMgZmluYWxfY252ID0gZmluYWxfY252WyFkdXBsaWNhdGVkKGZpbmFsX2NudlssYygnY2VsbF9ncm91cF9uYW1lJywgJ2xhcmdlX2V2ZW50JyldKSxdCiMgCiMgbGFyZ2VfZXZlbnRzID0gdW5pcXVlKGZpbmFsX2NudiRsYXJnZV9ldmVudCkKIyAKIyBmaW5hbF9jbnYkZ3JvdXAgPSBnc3ViKCJzYW1wbGUuIiwgIiIsIGZpbmFsX2NudiRjZWxsX2dyb3VwX25hbWUpCiMgCiMgIyNjaGFuZ2UgdGhlIGRhdGEgZnJhbWUgdG8gd2lkZSB0byBzdW1tYXJpemUgdGhlIGV2ZW50CiMgbGlicmFyeShyZXNoYXBlMikKIyB3aWRlID0gcmVzaGFwZTI6OmRjYXN0KGZpbmFsX2NudiwgbGFyZ2VfZXZlbnQgfiBncm91cCwgdmFsdWUudmFyID0gImV2ZW50IiwgZnVuLmFnZ3JlZ2F0ZSA9IGxlbmd0aCkKIyAjI2NoYW5nZSB0aGUgdGFibGUgdG8gMC8xCiMgcm93bmFtZXMod2lkZSkgPSB3aWRlJGxhcmdlX2V2ZW50CiMgd2lkZSA9IHdpZGVbLC0xXQojIHdpZGUgPSBhcy5tYXRyaXgoaWZlbHNlKHdpZGUgPj0gMSwgMSwgMCkpCiMgd2lkZSA9IGFzLmRhdGEuZnJhbWUoY2JpbmQod2lkZSwgdG90YWwgPSByb3dTdW1zKHdpZGUpKSkKIyBuZXcgPSB3aWRlW29yZGVyKC13aWRlJHRvdGFsKSxdCiMgbmV3JCIxLjEuMSIgPSBpZmVsc2UoKG5ldyRgMS4xLjEuMWAgKyBuZXckYDEuMS4xLjJgKSA+PTIsIDEsIDApCiMgbmV3JCIxLjEuMiIgPSBpZmVsc2UoKG5ldyRgMS4xLjIuMWAgKyBuZXckYDEuMS4yLjJgKSA+PTIsIDEsIDApCiMgbmV3JCIxLjEiID0gaWZlbHNlKChuZXckYDEuMS4xYCArIG5ldyRgMS4xLjJgKSA+PTIsIDEsIDApCiMgbmV3JCIxLjIuMSIgPSBpZmVsc2UoKG5ldyRgMS4yLjEuMWAgKyBuZXckYDEuMi4xLjJgKSA+PSAyLCAxLCAwKQojICNuZXckIjEuMi4yIiA9IGlmZWxzZSgobmV3JGAxLjIuMi4xYCArIG5ldyRgMS4yLjIuMmApID49IDIsIDEsIDApCiMgbmV3JCIxLjIiID0gaWZlbHNlKChuZXckYDEuMi4xYCArIG5ldyRgMS4yLjJgKSA+PTIsIDEsIDApCiMgbmV3JCIxIiA9IGlmZWxzZSgobmV3JGAxLjFgICsgbmV3JGAxLjJgKSA+PTIsIDEsIDApCiMgbmV3ID0gbmV3WyxjKDE0LDExLDksMSwyLDEwLDMsNCwxMywxMiw1LDYsNyw4KV0KIyB3cml0ZS5jc3YobmV3LCAiLi4vTDEvZXZlbnRzLmNzdiIpCiMgCiMgIyNyZWFkIGluIHRoZSBjZWxsIGdyb3VwaW5nIGRhdGEgZnJvbSBVUGh5bG9wbG90MiB0byBjYWxjdWxhdGUgdGhlIGNlbGwgbnVtYmVyIGluIGVhY2ggYnJhbmNoCiMgY2VsbHMgPSByZWFkLnRhYmxlKCIuLi8uLi91cGh5bG9wbG90Mi0yLjMvSW5wdXRzL0wxLmNlbGxfZ3JvdXBpbmdzIiwgaGVhZGVyID0gVCkKIyBzdW0gPSBhcy5kYXRhLmZyYW1lKHRhYmxlKGNlbGxzJGNlbGxfZ3JvdXBfbmFtZSkpCiMgd3JpdGUuY3N2KHN1bSwgIi4uL0wxL2NlbGxfZ3JvdXBfZnJlcXVlbmN5LmNzdiIpCiMgIyNjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZWFjaCBDTlYgZXZlbnQKIyBjZWxsX2dyb3VwID0gcmVhZC5jc3YoIjE3X0hNTV9wcmVkSE1NaTYucmFuZF90cmVlcy5obW1fbW9kZS1zdWJjbHVzdGVycy5jZWxsX2dyb3VwaW5ncyIsIGhlYWRlciA9IEYpCiMgZ3JvdXAgPSBhcy5kYXRhLmZyYW1lKGNlbGxfZ3JvdXBbLDJdKQojIHJvd25hbWVzKGdyb3VwKSA9IGNlbGxfZ3JvdXBbLDFdCiMgcGVyID0gbmV3WywtMTRdCiMgcGVyY2VudGFnZSA9IHBlcipncm91cFssMV1bY29sKHBlcildCiMgcGVyY2VudGFnZSRzYW1wbGUgPSByb3dTdW1zKHBlcmNlbnRhZ2UpCiMgd3JpdGUuY3N2KHBlcmNlbnRhZ2UsICIuLi9MMS9zYW1wbGVfZXZlbnRzX3BlcmNlbnRhZ2UuY3N2IikKCmBgYAojIDMuIHBlcmZvcm0gaW5mZXJjbnYgb3BlcmF0aW9ucyB0byByZXZlYWwgY252IHNpZ25hbApgYGB7ciBDTlZfc2lnbmFsMiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJlc2hhcGUyKQoKIyBSZWFkIGlucHV0IGZpbGVzCmhnMzggPSByZWFkLmRlbGltKCIuLi9jeXRvQmFuZF9oZzM4LnR4dCIsIGhlYWRlciA9IEYpCmNudiA9IHJlYWQudGFibGUoIi4uL0wxL0hNTV9DTlZfcHJlZGljdGlvbnMuSE1NaTYucmFuZF90cmVlcy5obW1fbW9kZS1zdWJjbHVzdGVycy5Qbm9ybV8wLjUucHJlZF9jbnZfcmVnaW9ucy5kYXQiLCBoZWFkZXIgPSBUKQoKIyBQcm9jZXNzIGN5dG9iYW5kIGRhdGEKY3l0b2JhbmQgPSBoZzM4CmN5dG9iYW5kIDwtIGRhdGEuZnJhbWUoVjE9Z3N1YigiY2hyIiwgIiIsIGN5dG9iYW5kWywxXSksIFYyPWN5dG9iYW5kWywyXSwgVjM9Y3l0b2JhbmRbLDNdLCBWND1zdWJzdHJpbmcoY3l0b2JhbmQkVjQsIDEsIDEpLCBzdHJpbmdzQXNGYWN0b3JzPUYpCnN0YXJ0IDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShzcGxpdChjeXRvYmFuZCRWMiwgcGFzdGUwKGN5dG9iYW5kJFYxLCBjeXRvYmFuZCRWNCkpLCBtaW4pKQplbmQgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KHNwbGl0KGN5dG9iYW5kJFYzLCBwYXN0ZTAoY3l0b2JhbmQkVjEsIGN5dG9iYW5kJFY0KSksIG1heCkpCmN5dG9iYW5kIDwtIGRhdGEuZnJhbWUoVjE9Z3N1YigicCIsICIiLCBnc3ViKCJxIiwgIiIsIHJvd25hbWVzKHN0YXJ0KSkpLCBWMj1zdGFydCwgVjM9ZW5kLCBWND1yb3duYW1lcyhzdGFydCksIHN0cmluZ3NBc0ZhY3RvcnM9RikKY3l0b2JhbmQgPC0gY3l0b2JhbmRbYXMudmVjdG9yKHVubGlzdChzYXBwbHkoYygxOjIyLCAiWCIpLCBmdW5jdGlvbih4KSB3aGljaChjeXRvYmFuZCRWMSAlaW4lIHgpKSkpLCBdCmN5dG9iYW5kJFY0W2dyZXAoInEiLCBjeXRvYmFuZCRWNCldIDwtICJxIgpjeXRvYmFuZCRWNFtncmVwKCJwIiwgY3l0b2JhbmQkVjQpXSA8LSAicCIKcm93bmFtZXMoY3l0b2JhbmQpIDwtIE5VTEwKbmFtZXMoY3l0b2JhbmQpID0gYygiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJhcm0iKQpjeXRvYmFuZCRjaHJfYXJtID0gcGFzdGUwKGN5dG9iYW5kJGNociwgY3l0b2JhbmQkYXJtKQpjeXRvYmFuZCRjaHJvbW9zb21lID0gcGFzdGUwKCJjaHIiLCBjeXRvYmFuZCRjaHIpCmN5dG9iYW5kJGNociA9IGN5dG9iYW5kJGNocm9tb3NvbWUKY3l0b2JhbmQgPSBjeXRvYmFuZFssMTo1XQoKIyBQcm9jZXNzIENOViBkYXRhCmNudiRjaHIgPSBhcy5jaGFyYWN0ZXIoY252JGNocikKY3l0b2JhbmQkY2hyID0gYXMuY2hhcmFjdGVyKGN5dG9iYW5kJGNocikKY252JG1pZCA9IChhcy5udW1lcmljKGNudiRzdGFydCkgKyBhcy5udW1lcmljKGNudiRlbmQpKS8yCgojIEpvaW4gQ05WIGFuZCBjeXRvYmFuZCBkYXRhCm5ldyA9IGlubmVyX2pvaW4oY252LCBjeXRvYmFuZCwgYnk9YygiY2hyIikpICU+JQogICAgICBtdXRhdGUoYXJtID0gaWZlbHNlKG1pZCA+PSBhcy5udW1lcmljKHN0YXJ0LnkpICYgbWlkIDw9IGFzLm51bWVyaWMoZW5kLnkpLCBjaHJfYXJtLCBOQSkpICU+JQogICAgICBncm91cF9ieShjaHIpICU+JQogICAgICBmaWx0ZXIoIWlzLm5hKGFybSkgfCBuKCk9PTEpCmZpbmFsX2NudiA9IG5ld1ssYygxOjYsIDEwKV0KCm5hbWVzKGZpbmFsX2NudikgPSBjKCJjZWxsX2dyb3VwX25hbWUiLCAiY252X25hbWUiLCAic3RhdGUiLCAiY2hyIiwgInN0YXJ0IiwgImVuZCIsICJhcm0iKQoKZmluYWxfY252JGV2ZW50ID0gaWZlbHNlKGZpbmFsX2NudiRzdGF0ZSA+PSA0LCAiZ2FpbiIsICJsb3NzIikKZmluYWxfY252JGxhcmdlX2V2ZW50ID0gcGFzdGUoZmluYWxfY252JGFybSwgZmluYWxfY252JGV2ZW50LCBzZXAgPSAiICIpCmZpbmFsX2NudiA9IGZpbmFsX2NudlshZHVwbGljYXRlZChmaW5hbF9jbnZbLGMoJ2NlbGxfZ3JvdXBfbmFtZScsICdsYXJnZV9ldmVudCcpXSksXQpmaW5hbF9jbnYkZ3JvdXAgPSBnc3ViKCJzYW1wbGUuIiwgIiIsIGZpbmFsX2NudiRjZWxsX2dyb3VwX25hbWUpCgojIENyZWF0ZSB3aWRlIGZvcm1hdCBkYXRhCndpZGUgPSBkY2FzdChmaW5hbF9jbnYsIGxhcmdlX2V2ZW50IH4gZ3JvdXAsIHZhbHVlLnZhciA9ICJldmVudCIsIGZ1bi5hZ2dyZWdhdGUgPSBsZW5ndGgpCnJvd25hbWVzKHdpZGUpID0gd2lkZSRsYXJnZV9ldmVudAp3aWRlID0gd2lkZVssLTFdCndpZGUgPSBhcy5tYXRyaXgoaWZlbHNlKHdpZGUgPj0gMSwgMSwgMCkpCndpZGUgPSBhcy5kYXRhLmZyYW1lKGNiaW5kKHdpZGUsIHRvdGFsID0gcm93U3Vtcyh3aWRlKSkpCm5ldyA9IHdpZGVbb3JkZXIoLXdpZGUkdG90YWwpLF0KCiMgQ3JlYXRlIG5ldyBjb2x1bW5zIGJhc2VkIG9uIGV4aXN0aW5nIG9uZXMKbmV3JCJMMS5MMS4xLjEiID0gaWZlbHNlKChuZXckTDEuTDEuMS4xLjEuMSArIG5ldyRMMS5MMS4xLjEuMS4yKSA+PSAyLCAxLCAwKQpuZXckIkwxLkwxLjEuMiIgPSBpZmVsc2UoKG5ldyRMMS5MMS4xLjIuMS4xICsgbmV3JEwxLkwxLjEuMi4xLjIpID49IDIsIDEsIDApCm5ldyQiTDEuTDEuMSIgPSBpZmVsc2UoKG5ldyRMMS5MMS4xLjEgKyBuZXckTDEuTDEuMS4yKSA+PSAyLCAxLCAwKQpuZXckIkwxLkwxLjIuMSIgPSBpZmVsc2UoKG5ldyRMMS5MMS4xLjIuMi4xICsgbmV3JEwxLkwxLjEuMi4yLjIpID49IDIsIDEsIDApCm5ldyQiTDEuTDEuMiIgPSBuZXckTDEuTDEuMi4xCm5ldyQiTDEuTDEiID0gaWZlbHNlKChuZXckTDEuTDEuMSArIG5ldyRMMS5MMS4yKSA+PSAyLCAxLCAwKQoKIyBSZW9yZGVyIGNvbHVtbnMKbmV3X29yZGVyID0gYygiTDEuTDEiLCAiTDEuTDEuMSIsICJMMS5MMS4xLjEiLCAiTDEuTDEuMS4xLjEuMSIsICJMMS5MMS4xLjEuMS4yIiwgCiAgICAgICAgICAgICAgIkwxLkwxLjEuMiIsICJMMS5MMS4xLjIuMS4xIiwgIkwxLkwxLjEuMi4xLjIiLCAKICAgICAgICAgICAgICAiTDEuTDEuMiIsICJMMS5MMS4yLjEiLCAiTDEuTDEuMS4yLjIuMSIsICJMMS5MMS4xLjIuMi4yIiwgInRvdGFsIikKbmV3ID0gbmV3WywgYyhuZXdfb3JkZXIsIHNldGRpZmYobmFtZXMobmV3KSwgbmV3X29yZGVyKSldCgp3cml0ZS5jc3YobmV3LCAiLi4vTDEvZXZlbnRzLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCgojIENhbGN1bGF0ZSBwZXJjZW50YWdlIG9mIGVhY2ggQ05WIGV2ZW50CnRyeUNhdGNoKHsKICAjIFJlYWQgdGhlIGZpbGUgYXMgYSBzaW5nbGUgY29sdW1uCiAgY2VsbF9ncm91cCA9IHJlYWQuY3N2KCIuLi8uLi91cGh5bG9wbG90Mi0yLjMvSW5wdXRzL0wxLmNlbGxfZ3JvdXBpbmdzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IEZBTFNFLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgCiAgIyBTcGxpdCB0aGUgY29sdW1uIGludG8gdHdvIGJhc2VkIG9uIHRoZSB0YWIgY2hhcmFjdGVyCiAgY2VsbF9ncm91cCA9IGRhdGEuZnJhbWUoZG8uY2FsbCgncmJpbmQnLCBzdHJzcGxpdChhcy5jaGFyYWN0ZXIoY2VsbF9ncm91cCRWMSksICdcdCcsIGZpeGVkPVRSVUUpKSkKICBjb2xuYW1lcyhjZWxsX2dyb3VwKSA9IGMoImNlbGxfZ3JvdXBfbmFtZSIsICJjZWxsIikKICAKICAjIFJlbW92ZSB0aGUgaGVhZGVyIHJvdwogIGNlbGxfZ3JvdXAgPSBjZWxsX2dyb3VwWy0xLF0KICAKICBwcmludCgiU3RydWN0dXJlIG9mIGNlbGxfZ3JvdXA6IikKICBwcmludChzdHIoY2VsbF9ncm91cCkpCiAgCiAgIyBDcmVhdGUgZ3JvdXAgZGF0YWZyYW1lCiAgZ3JvdXAgPSBhcy5kYXRhLmZyYW1lKHRhYmxlKGNlbGxfZ3JvdXAkY2VsbF9ncm91cF9uYW1lKSkKICBjb2xuYW1lcyhncm91cCkgPSBjKCJjZWxsX2dyb3VwX25hbWUiLCAiY291bnQiKQogIHJvd25hbWVzKGdyb3VwKSA9IGdyb3VwJGNlbGxfZ3JvdXBfbmFtZQogIAogIHByaW50KCJTdHJ1Y3R1cmUgb2YgZ3JvdXA6IikKICBwcmludChzdHIoZ3JvdXApKQogIAogICMgQXNzdW1pbmcgJ25ldycgaXMgeW91ciBkYXRhZnJhbWUgd2l0aCBDTlYgZXZlbnRzCiAgcGVyID0gbmV3Wywgc2V0ZGlmZihuYW1lcyhuZXcpLCAidG90YWwiKV0KICAKICBwcmludCgiQ29sdW1ucyBvZiBwZXI6IikKICBwcmludChjb2xuYW1lcyhwZXIpKQogIAogIHByaW50KCJSb3dzIG9mIGdyb3VwOiIpCiAgcHJpbnQocm93bmFtZXMoZ3JvdXApKQogIAogIG1hdGNoaW5nX3Jvd3MgPSBpbnRlcnNlY3Qocm93bmFtZXMoZ3JvdXApLCBjb2xuYW1lcyhwZXIpKQogIGlmKGxlbmd0aChtYXRjaGluZ19yb3dzKSA9PSAwKSB7CiAgICBzdG9wKCJObyBtYXRjaGluZyByb3cgbmFtZXMgYmV0d2VlbiBncm91cCBhbmQgY29sdW1ucyBvZiBwZXIuIikKICB9CiAgCiAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZXMKICBwZXJjZW50YWdlID0gcGVyWywgbWF0Y2hpbmdfcm93c10gKiBncm91cFttYXRjaGluZ19yb3dzLCAiY291bnQiXQogIAogICMgQ2FsY3VsYXRlIHRvdGFsIGNlbGxzIGZvciBlYWNoIENOViBldmVudAogIHRvdGFsX2NlbGxzID0gcm93U3VtcyhwZXJjZW50YWdlKQogIAogICMgQ29udmVydCBjb3VudHMgdG8gcGVyY2VudGFnZXMKICBwZXJjZW50YWdlID0gc3dlZXAocGVyY2VudGFnZSwgMSwgdG90YWxfY2VsbHMsICIvIikgKiAxMDAKICAKICAjIEFkZCB0b3RhbCBwZXJjZW50YWdlIGNvbHVtbgogIHBlcmNlbnRhZ2Ukc2FtcGxlID0gcm93U3VtcyhwZXJjZW50YWdlKQogIAogIHdyaXRlLmNzdihwZXJjZW50YWdlLCAiLi4vTDEvc2FtcGxlX2V2ZW50c19wZXJjZW50YWdlLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCiAgCiAgcHJpbnQoIlBlcmNlbnRhZ2UgY2FsY3VsYXRpb24gY29tcGxldGVkIHN1Y2Nlc3NmdWxseS4iKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICBwcmludChwYXN0ZSgiQW4gZXJyb3Igb2NjdXJyZWQ6IiwgZSRtZXNzYWdlKSkKfSkKYGBgCgojIDIuIHBlcmZvcm0gaW5mZXJjbnYgb3BlcmF0aW9ucyB0byByZXZlYWwgY252IHNpZ25hbApgYGB7ciBDTlZfc2lnbmFsMywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgoKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKCiMgUmVhZCB0aGUgLmNlbGxfZ3JvdXBpbmdzIGZpbGUsIHNraXBwaW5nIHRoZSBmaXJzdCByb3cgd2hpY2ggaXMgYW4gZXh0cmEgaGVhZGVyCmNlbGxfZ3JvdXBpbmdzX2ZpbGUgPC0gIi4uL0w3L0w3LmNlbGxfZ3JvdXBpbmdzIgpjZWxsX21hcHBpbmcgPC0gcmVhZF90c3YoY2VsbF9ncm91cGluZ3NfZmlsZSwgY29sX25hbWVzID0gYygiY2VsbF9ncm91cF9uYW1lIiwgImNlbGxfaWQiKSkKCiMgRmlsdGVyIGZvciBvbmx5IEwxIGNlbGxzCmNlbGxfbWFwcGluZyA8LSBjZWxsX21hcHBpbmcgJT4lCiAgZmlsdGVyKGdyZXBsKCJeTDdfIiwgY2VsbF9pZCkpCgojIFdyaXRlIHRoZSBtYXBwaW5nIHRvIGEgQ1NWIGZpbGUKd3JpdGVfY3N2KGNlbGxfbWFwcGluZywgIi4uL0w3L2NlbGxfdG9fZ3JvdXBfbWFwcGluZy5jc3YiKQoKIyBQcmludCB0aGUgZmlyc3QgZmV3IHJvd3MgdG8gdmVyaWZ5CnByaW50KGhlYWQoY2VsbF9tYXBwaW5nKSkKCiMgUHJpbnQgdGhlIG51bWJlciBvZiByb3dzIHRvIHZlcmlmeSBpdCdzIG5vdCBlbXB0eQpwcmludChwYXN0ZSgiTnVtYmVyIG9mIHJvd3MgaW4gY2VsbF9tYXBwaW5nOiIsIG5yb3coY2VsbF9tYXBwaW5nKSkpCgoKCgoKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCgojIFJlYWQgdGhlIENOViBkYXRhCmNudl9kYXRhIDwtIHJlYWQuY3N2KCIuLi9MNy9MN19pbmZlcmNudl93aXRoX2Nocl9iYW5kcy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFJlYWQgdGhlIGNlbGwgdG8gY2VsbCBncm91cCBtYXBwaW5nIGZpbGUKIyBUaGlzIGZpbGUgc2hvdWxkIGhhdmUgY29sdW1uczogY2VsbF9pZCwgY2VsbF9ncm91cF9uYW1lCmNlbGxfbWFwcGluZyA8LSByZWFkLmNzdigiLi4vTDcvY2VsbF90b19ncm91cF9tYXBwaW5nLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiMgSm9pbiB0aGUgQ05WIGRhdGEgd2l0aCB0aGUgY2VsbCBtYXBwaW5nCmV4cGFuZGVkX2Nudl9kYXRhIDwtIGNudl9kYXRhICU+JQogIGxlZnRfam9pbihjZWxsX21hcHBpbmcsIGJ5ID0gImNlbGxfZ3JvdXBfbmFtZSIpICU+JQogIHNlbGVjdCgtY2VsbF9ncm91cF9uYW1lKSAlPiUgICMgUmVtb3ZlIHRoZSBjZWxsIGdyb3VwIGNvbHVtbgogIHJlbmFtZShjZWxsX2lkID0gY2VsbF9pZCkgICMgUmVuYW1lIGZvciBjbGFyaXR5CgojIENvdW50IHRvdGFsIG51bWJlciBvZiBjZWxscwp0b3RhbF9jZWxscyA8LSBucm93KGNlbGxfbWFwcGluZykKCiMgUHJvY2VzcyB0aGUgZXhwYW5kZWQgZGF0YQpjbnZfc3VtbWFyeSA8LSBleHBhbmRlZF9jbnZfZGF0YSAlPiUKICAjIEdyb3VwIGJ5IGNocm9tb3NvbWUgYmFuZCBhbmQgQ05WIHN0YXRlCiAgZ3JvdXBfYnkoY2hyX2JhbmQsIHN0YXRlKSAlPiUKICAjIENvdW50IGNlbGxzIGZvciBlYWNoIENOViBldmVudAogIHN1bW1hcml6ZSgKICAgIGNlbGxfY291bnQgPSBuKCksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKSAlPiUKICAjIENhbGN1bGF0ZSBwZXJjZW50YWdlCiAgbXV0YXRlKAogICAgcGVyY2VudGFnZSA9IChjZWxsX2NvdW50IC8gdG90YWxfY2VsbHMpICogMTAwLAogICAgY252X3R5cGUgPSBjYXNlX3doZW4oCiAgICAgIHN0YXRlID09IDEgfiAiQ29tcGxldGUgTG9zcyAoMHgpIiwKICAgICAgc3RhdGUgPT0gMiB+ICJMb3NzIG9mIE9uZSBDb3B5ICgwLjV4KSIsCiAgICAgIHN0YXRlID09IDMgfiAiTmV1dHJhbCAoMXgpIiwKICAgICAgc3RhdGUgPT0gNCB+ICJBZGRpdGlvbiBvZiBPbmUgQ29weSAoMS41eCkiLAogICAgICBzdGF0ZSA9PSA1IH4gIkFkZGl0aW9uIG9mIFR3byBDb3BpZXMgKDJ4KSIsCiAgICAgIHN0YXRlID09IDYgfiAiUGxhY2Vob2xkZXIgZm9yID4yeCBDb3BpZXMgKDN4KSIKICAgICkKICApICU+JQogICMgU2VsZWN0IHJlbGV2YW50IGNvbHVtbnMgYW5kIHNvcnQKICBzZWxlY3QoY2hyX2JhbmQsIGNudl90eXBlLCBjZWxsX2NvdW50LCBwZXJjZW50YWdlKSAlPiUKICBhcnJhbmdlKGRlc2MocGVyY2VudGFnZSkpCgojIERpc3BsYXkgdGhlIHJlc3VsdHMKcHJpbnQoY252X3N1bW1hcnkpCgojIE9wdGlvbmFsbHksIHdyaXRlIHRvIGEgQ1NWIGZpbGUKd3JpdGUuY3N2KGNudl9zdW1tYXJ5LCAiLi4vTDcvY252X2V2ZW50X3BlcmNlbnRhZ2VzX2J5X2NlbGwuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCgojIyBWaXN1YWxpemF0aW9uX0wxCmBgYHtyIHZpc3VhbGl6ZTEsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQoKIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGd0YWJsZSkKCiMgU3RlcCAxOiBSZWFkIHRoZSBDTlYgZGF0YSBmaWxlCnNpZ25pZmljYW50X2Nudl9kYXRhIDwtIHJlYWRfY3N2KCIuLi9MMS9jbnZfZXZlbnRfcGVyY2VudGFnZXNfYnlfY2VsbC5jc3YiKQoKIyBWZXJpZnkgdGhhdCB0aGUgZGF0YSB3YXMgcmVhZCBjb3JyZWN0bHkKcHJpbnQoaGVhZChzaWduaWZpY2FudF9jbnZfZGF0YSkpCgojIFN0ZXAgMjogRmlsdGVyIGRhdGEgdG8gb25seSBpbmNsdWRlIHJvd3Mgd2l0aCBhIHBlcmNlbnRhZ2UgPiA1JQpmaWx0ZXJlZF9jbnZfZGF0YSA8LSBzaWduaWZpY2FudF9jbnZfZGF0YSAlPiUKICBmaWx0ZXIocGVyY2VudGFnZSA+IDEwKSAgIyBDaGFuZ2UgNSB0byA5MCBpZiB5b3Ugd2FudCB0byBmaWx0ZXIgZm9yID45MCUKCiMgU3RlcCAzOiBDcmVhdGUgdGhlIGJhciBwbG90IHVzaW5nIHRoZSBmaWx0ZXJlZCBkYXRhCmdncGxvdChmaWx0ZXJlZF9jbnZfZGF0YSwgYWVzKHggPSBwZXJjZW50YWdlLCB5ID0gcmVvcmRlcihjaHJfYmFuZCwgcGVyY2VudGFnZSksIGZpbGwgPSBjbnZfdHlwZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuOCkgKyAgIyBBZGp1c3RlZCBiYXIgd2lkdGgKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJDb21wbGV0ZSBMb3NzICgweCkiID0gIiNmZGFlNjEiLCAgIyBPcmFuZ2UgZm9yIGNvbXBsZXRlIGxvc3MKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMb3NzIG9mIE9uZSBDb3B5ICgwLjV4KSIgPSAiIzMxMzY5NSIsICAjIEJsdWUgZm9yIHBhcnRpYWwgbG9zcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFkZGl0aW9uIG9mIE9uZSBDb3B5ICgxLjV4KSIgPSAicmVkIiwgICMgUmVkIGZvciBnYWluCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWRkaXRpb24gb2YgVHdvIENvcGllcyAoMngpIiA9ICJkYXJrZ3JlZW4iKSkgKyAgIyBHcmVlbiBmb3IgaGlnaGVyIGdhaW4KICBsYWJzKAogICAgdGl0bGUgPSAiU2lnbmlmaWNhbnQgQ05WcyBBZmZlY3RpbmcgPjEwJSBvZiBDZWxscyIsICAjIFVwZGF0ZSB0aXRsZSBhY2NvcmRpbmdseQogICAgc3VidGl0bGUgPSAiQ2hyb21vc29tYWwgQmFuZHMgd2l0aCBDTlZzIGluID4xMCUgb2YgQ2VsbHMiLCAgIyBVcGRhdGUgc3VidGl0bGUgYWNjb3JkaW5nbHkKICAgIHggPSAiUGVyY2VudGFnZSBvZiBDZWxscyAoJSkiLAogICAgeSA9ICJDaHJvbW9zb21hbCBCYW5kIiwKICAgIGZpbGwgPSAiQ05WIFR5cGUiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKyAgIyBBZGp1c3QgdGV4dCBzaXplIGZvciByZWFkYWJpbGl0eQogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApCiAgKQoKCgoKYGBgCgoKIyMgVmlzdWFsaXphdGlvbl9MMgpgYGB7ciB2aXN1YWxpemUyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShndGFibGUpCgojIFN0ZXAgMTogUmVhZCB0aGUgQ05WIGRhdGEgZmlsZQpzaWduaWZpY2FudF9jbnZfZGF0YSA8LSByZWFkX2NzdigiLi4vTDIvY252X2V2ZW50X3BlcmNlbnRhZ2VzX2J5X2NlbGwuY3N2IikKCiMgVmVyaWZ5IHRoYXQgdGhlIGRhdGEgd2FzIHJlYWQgY29ycmVjdGx5CnByaW50KGhlYWQoc2lnbmlmaWNhbnRfY252X2RhdGEpKQoKIyBTdGVwIDI6IEZpbHRlciBkYXRhIHRvIG9ubHkgaW5jbHVkZSByb3dzIHdpdGggYSBwZXJjZW50YWdlID4gNSUKZmlsdGVyZWRfY252X2RhdGEgPC0gc2lnbmlmaWNhbnRfY252X2RhdGEgJT4lCiAgZmlsdGVyKHBlcmNlbnRhZ2UgPiAxNSkgICMgQ2hhbmdlIDUgdG8gOTAgaWYgeW91IHdhbnQgdG8gZmlsdGVyIGZvciA+OTAlCgojIFN0ZXAgMzogQ3JlYXRlIHRoZSBiYXIgcGxvdCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YQpnZ3Bsb3QoZmlsdGVyZWRfY252X2RhdGEsIGFlcyh4ID0gcGVyY2VudGFnZSwgeSA9IHJlb3JkZXIoY2hyX2JhbmQsIHBlcmNlbnRhZ2UpLCBmaWxsID0gY252X3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjgpICsgICMgQWRqdXN0ZWQgYmFyIHdpZHRoCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGxldGUgTG9zcyAoMHgpIiA9ICIjZmRhZTYxIiwgICMgT3JhbmdlIGZvciBjb21wbGV0ZSBsb3NzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9zcyBvZiBPbmUgQ29weSAoMC41eCkiID0gIiMzMTM2OTUiLCAgIyBCbHVlIGZvciBwYXJ0aWFsIGxvc3MKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRpdGlvbiBvZiBPbmUgQ29weSAoMS41eCkiID0gInJlZCIsICAjIFJlZCBmb3IgZ2FpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFkZGl0aW9uIG9mIFR3byBDb3BpZXMgKDJ4KSIgPSAiZGFya2dyZWVuIikpICsgICMgR3JlZW4gZm9yIGhpZ2hlciBnYWluCiAgbGFicygKICAgIHRpdGxlID0gIlNpZ25pZmljYW50IENOVnMgQWZmZWN0aW5nID4xNSUgb2YgQ2VsbHMiLCAgIyBVcGRhdGUgdGl0bGUgYWNjb3JkaW5nbHkKICAgIHN1YnRpdGxlID0gIkNocm9tb3NvbWFsIEJhbmRzIHdpdGggQ05WcyBpbiA+MTUlIG9mIENlbGxzIiwgICMgVXBkYXRlIHN1YnRpdGxlIGFjY29yZGluZ2x5CiAgICB4ID0gIlBlcmNlbnRhZ2Ugb2YgQ2VsbHMgKCUpIiwKICAgIHkgPSAiQ2hyb21vc29tYWwgQmFuZCIsCiAgICBmaWxsID0gIkNOViBUeXBlIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsgICMgQWRqdXN0IHRleHQgc2l6ZSBmb3IgcmVhZGFiaWxpdHkKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQogICkKCgoKCmBgYAoKCiMjIFZpc3VhbGl6YXRpb25fTDMKYGBge3IgdmlzdWFsaXplMywgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CgojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ3RhYmxlKQoKIyBTdGVwIDE6IFJlYWQgdGhlIENOViBkYXRhIGZpbGUKc2lnbmlmaWNhbnRfY252X2RhdGEgPC0gcmVhZF9jc3YoIi4uL0wzL2Nudl9ldmVudF9wZXJjZW50YWdlc19ieV9jZWxsLmNzdiIpCgojIFZlcmlmeSB0aGF0IHRoZSBkYXRhIHdhcyByZWFkIGNvcnJlY3RseQpwcmludChoZWFkKHNpZ25pZmljYW50X2Nudl9kYXRhKSkKCiMgU3RlcCAyOiBGaWx0ZXIgZGF0YSB0byBvbmx5IGluY2x1ZGUgcm93cyB3aXRoIGEgcGVyY2VudGFnZSA+IDUlCmZpbHRlcmVkX2Nudl9kYXRhIDwtIHNpZ25pZmljYW50X2Nudl9kYXRhICU+JQogIGZpbHRlcihwZXJjZW50YWdlID4gMTUpICAjIENoYW5nZSA1IHRvIDkwIGlmIHlvdSB3YW50IHRvIGZpbHRlciBmb3IgPjkwJQoKIyBTdGVwIDM6IENyZWF0ZSB0aGUgYmFyIHBsb3QgdXNpbmcgdGhlIGZpbHRlcmVkIGRhdGEKZ2dwbG90KGZpbHRlcmVkX2Nudl9kYXRhLCBhZXMoeCA9IHBlcmNlbnRhZ2UsIHkgPSByZW9yZGVyKGNocl9iYW5kLCBwZXJjZW50YWdlKSwgZmlsbCA9IGNudl90eXBlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHdpZHRoID0gMC44KSArICAjIEFkanVzdGVkIGJhciB3aWR0aAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNvbXBsZXRlIExvc3MgKDB4KSIgPSAiI2ZkYWU2MSIsICAjIE9yYW5nZSBmb3IgY29tcGxldGUgbG9zcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxvc3Mgb2YgT25lIENvcHkgKDAuNXgpIiA9ICIjMzEzNjk1IiwgICMgQmx1ZSBmb3IgcGFydGlhbCBsb3NzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWRkaXRpb24gb2YgT25lIENvcHkgKDEuNXgpIiA9ICJyZWQiLCAgIyBSZWQgZm9yIGdhaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRpdGlvbiBvZiBUd28gQ29waWVzICgyeCkiID0gImRhcmtncmVlbiIpKSArICAjIEdyZWVuIGZvciBoaWdoZXIgZ2FpbgogIGxhYnMoCiAgICB0aXRsZSA9ICJTaWduaWZpY2FudCBDTlZzIEFmZmVjdGluZyA+MTUlIG9mIENlbGxzIiwgICMgVXBkYXRlIHRpdGxlIGFjY29yZGluZ2x5CiAgICBzdWJ0aXRsZSA9ICJDaHJvbW9zb21hbCBCYW5kcyB3aXRoIENOVnMgaW4gPjE1JSBvZiBDZWxscyIsICAjIFVwZGF0ZSBzdWJ0aXRsZSBhY2NvcmRpbmdseQogICAgeCA9ICJQZXJjZW50YWdlIG9mIENlbGxzICglKSIsCiAgICB5ID0gIkNocm9tb3NvbWFsIEJhbmQiLAogICAgZmlsbCA9ICJDTlYgVHlwZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArICAjIEFkanVzdCB0ZXh0IHNpemUgZm9yIHJlYWRhYmlsaXR5CiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkKICApCgoKCgpgYGAKCgoKIyMgVmlzdWFsaXphdGlvbl9MNApgYGB7ciB2aXN1YWxpemU0LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShndGFibGUpCgojIFN0ZXAgMTogUmVhZCB0aGUgQ05WIGRhdGEgZmlsZQpzaWduaWZpY2FudF9jbnZfZGF0YSA8LSByZWFkX2NzdigiLi4vTDQvY252X2V2ZW50X3BlcmNlbnRhZ2VzX2J5X2NlbGwuY3N2IikKCiMgVmVyaWZ5IHRoYXQgdGhlIGRhdGEgd2FzIHJlYWQgY29ycmVjdGx5CnByaW50KGhlYWQoc2lnbmlmaWNhbnRfY252X2RhdGEpKQoKIyBTdGVwIDI6IEZpbHRlciBkYXRhIHRvIG9ubHkgaW5jbHVkZSByb3dzIHdpdGggYSBwZXJjZW50YWdlID4gNSUKZmlsdGVyZWRfY252X2RhdGEgPC0gc2lnbmlmaWNhbnRfY252X2RhdGEgJT4lCiAgZmlsdGVyKHBlcmNlbnRhZ2UgPiAxNSkgICMgQ2hhbmdlIDUgdG8gOTAgaWYgeW91IHdhbnQgdG8gZmlsdGVyIGZvciA+OTAlCgojIFN0ZXAgMzogQ3JlYXRlIHRoZSBiYXIgcGxvdCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YQpnZ3Bsb3QoZmlsdGVyZWRfY252X2RhdGEsIGFlcyh4ID0gcGVyY2VudGFnZSwgeSA9IHJlb3JkZXIoY2hyX2JhbmQsIHBlcmNlbnRhZ2UpLCBmaWxsID0gY252X3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjgpICsgICMgQWRqdXN0ZWQgYmFyIHdpZHRoCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGxldGUgTG9zcyAoMHgpIiA9ICIjZmRhZTYxIiwgICMgT3JhbmdlIGZvciBjb21wbGV0ZSBsb3NzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9zcyBvZiBPbmUgQ29weSAoMC41eCkiID0gIiMzMTM2OTUiLCAgIyBCbHVlIGZvciBwYXJ0aWFsIGxvc3MKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRpdGlvbiBvZiBPbmUgQ29weSAoMS41eCkiID0gInJlZCIsICAjIFJlZCBmb3IgZ2FpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFkZGl0aW9uIG9mIFR3byBDb3BpZXMgKDJ4KSIgPSAiZGFya2dyZWVuIikpICsgICMgR3JlZW4gZm9yIGhpZ2hlciBnYWluCiAgbGFicygKICAgIHRpdGxlID0gIlNpZ25pZmljYW50IENOVnMgQWZmZWN0aW5nID4xNSUgb2YgQ2VsbHMiLCAgIyBVcGRhdGUgdGl0bGUgYWNjb3JkaW5nbHkKICAgIHN1YnRpdGxlID0gIkNocm9tb3NvbWFsIEJhbmRzIHdpdGggQ05WcyBpbiA+MTUlIG9mIENlbGxzIiwgICMgVXBkYXRlIHN1YnRpdGxlIGFjY29yZGluZ2x5CiAgICB4ID0gIlBlcmNlbnRhZ2Ugb2YgQ2VsbHMgKCUpIiwKICAgIHkgPSAiQ2hyb21vc29tYWwgQmFuZCIsCiAgICBmaWxsID0gIkNOViBUeXBlIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsgICMgQWRqdXN0IHRleHQgc2l6ZSBmb3IgcmVhZGFiaWxpdHkKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQogICkKCgoKCmBgYAoKIyMgVmlzdWFsaXphdGlvbl9MNwpgYGB7ciB2aXN1YWxpemU3LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KCiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShndGFibGUpCgojIFN0ZXAgMTogUmVhZCB0aGUgQ05WIGRhdGEgZmlsZQpzaWduaWZpY2FudF9jbnZfZGF0YSA8LSByZWFkX2NzdigiLi4vTDcvY252X2V2ZW50X3BlcmNlbnRhZ2VzX2J5X2NlbGwuY3N2IikKCiMgVmVyaWZ5IHRoYXQgdGhlIGRhdGEgd2FzIHJlYWQgY29ycmVjdGx5CnByaW50KGhlYWQoc2lnbmlmaWNhbnRfY252X2RhdGEpKQoKIyBTdGVwIDI6IEZpbHRlciBkYXRhIHRvIG9ubHkgaW5jbHVkZSByb3dzIHdpdGggYSBwZXJjZW50YWdlID4gNSUKZmlsdGVyZWRfY252X2RhdGEgPC0gc2lnbmlmaWNhbnRfY252X2RhdGEgJT4lCiAgZmlsdGVyKHBlcmNlbnRhZ2UgPiAxNSkgICMgQ2hhbmdlIDUgdG8gOTAgaWYgeW91IHdhbnQgdG8gZmlsdGVyIGZvciA+OTAlCgojIFN0ZXAgMzogQ3JlYXRlIHRoZSBiYXIgcGxvdCB1c2luZyB0aGUgZmlsdGVyZWQgZGF0YQpnZ3Bsb3QoZmlsdGVyZWRfY252X2RhdGEsIGFlcyh4ID0gcGVyY2VudGFnZSwgeSA9IHJlb3JkZXIoY2hyX2JhbmQsIHBlcmNlbnRhZ2UpLCBmaWxsID0gY252X3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjgpICsgICMgQWRqdXN0ZWQgYmFyIHdpZHRoCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGxldGUgTG9zcyAoMHgpIiA9ICIjZmRhZTYxIiwgICMgT3JhbmdlIGZvciBjb21wbGV0ZSBsb3NzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTG9zcyBvZiBPbmUgQ29weSAoMC41eCkiID0gIiMzMTM2OTUiLCAgIyBCbHVlIGZvciBwYXJ0aWFsIGxvc3MKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRpdGlvbiBvZiBPbmUgQ29weSAoMS41eCkiID0gInJlZCIsICAjIFJlZCBmb3IgZ2FpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFkZGl0aW9uIG9mIFR3byBDb3BpZXMgKDJ4KSIgPSAiZGFya2dyZWVuIikpICsgICMgR3JlZW4gZm9yIGhpZ2hlciBnYWluCiAgbGFicygKICAgIHRpdGxlID0gIlNpZ25pZmljYW50IENOVnMgQWZmZWN0aW5nID4xNSUgb2YgQ2VsbHMiLCAgIyBVcGRhdGUgdGl0bGUgYWNjb3JkaW5nbHkKICAgIHN1YnRpdGxlID0gIkNocm9tb3NvbWFsIEJhbmRzIHdpdGggQ05WcyBpbiA+MTUlIG9mIENlbGxzIiwgICMgVXBkYXRlIHN1YnRpdGxlIGFjY29yZGluZ2x5CiAgICB4ID0gIlBlcmNlbnRhZ2Ugb2YgQ2VsbHMgKCUpIiwKICAgIHkgPSAiQ2hyb21vc29tYWwgQmFuZCIsCiAgICBmaWxsID0gIkNOViBUeXBlIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsgICMgQWRqdXN0IHRleHQgc2l6ZSBmb3IgcmVhZGFiaWxpdHkKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQogICkKCgoKCmBgYAoKCgoKCg==