1. load libraries

#Differential Expression Analysis

2. load seurat object and save metadata file for samples

#Load Seurat Object L7
load("/home/bioinfo/0-imp_Robj/Harmony_integrated_All_samples_Merged_with_PBMC10x_with_harmony_clustering.Robj")
# sct_data <- GetAssayData(All_samples_Merged, assay = "SCT", layer = "data")

# memory.limit(size = 64000)
# 
# # Transpose the data so that cells are rows and genes are columns
# transposed_data <- t(as.data.frame(sct_data))
# 
# # Specify the file name and save as CSV
# write.csv(transposed_data, file = "table/SCT_data_All_samples_Merged_transposed.csv", row.names = TRUE)
# 
# 
# 
# 
# 
# # Extract metadata from Seurat object
# metadata <- All_samples_Merged@meta.data
# 
# # Write metadata to CSV
# write.csv(metadata, file = "Extra/Metadata_All_samples_Merged.csv", row.names = TRUE)

2. create barplot of CD4 cells in all samples

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

# Load your CSV file
data <- read.csv("Extra/Step_by_step_DE_Analysis/1-Metadata_All_samples_Merged/All_Samples_metadata/Metadata_All_samples_Merged.csv")

# Filter rows where all three predicted columns contain "CD4 T"
filtered_data <- data %>%
  filter(grepl("CD4", predicted.celltype.l1) & 
         grepl("CD4", predicted.celltype.l2) & 
         grepl("CD4", predicted.celltype.l3))

# Count the number of CD4 T cells in each orig.ident group
cd4_t_counts <- filtered_data %>%
  group_by(orig.ident) %>%
  summarise(count = n())

# Print the counts
print(cd4_t_counts)

# Define colors for the samples (optional)
sample_colors <- c("L1" = "#1f77b4", "L2" = "#ff7f0e", "L3" = "#2ca02c", "L4" = "#d62728", 
                   "L5" = "#9467bd", "L6" = "#8c564b", "L7" = "#e377c2", "PBMC" = "#7f7f7f", 
                   "PBMC10x" = "#bcbd22")

# Create the bar plot
celltype_plot <- ggplot(cd4_t_counts, aes(x = orig.ident, y = count, fill = orig.ident)) +
  geom_col() +
  theme_classic() +
  geom_text(aes(label = count), 
            position = position_dodge(width = 0.9), 
            vjust = -0.25) +
  scale_fill_manual(values = sample_colors) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5)) +
  ggtitle("Count of CD4  Cells by Sample") +
  xlab("Sample") +
  ylab("Number of CD4  Cells")

# Print the plot
print(celltype_plot)

2. create PBMC CD4 cells (Control) file

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

# Load your CSV file
data <- read.csv("Extra/NewFiles/PBMC/pbmc_METADATA.csv")

# Filter rows where all three predicted columns contain "CD4 T"
filtered_data <- data %>%
  filter(grepl("CD4", predicted.celltype.l1) & 
         grepl("CD4", predicted.celltype.l2) & 
         grepl("CD4", predicted.celltype.l3))

write.csv(filtered_data, "Extra/Step_by_step_DE_Analysis/1-Metadata_All_samples_Merged/Control_CD4Tcells/CD4_cells_PBMC_Control.csv", row.names = FALSE)

# Save the first column (PBMC cells) to a txt file without header
write.table(filtered_data[, 1], "Extra/Step_by_step_DE_Analysis/1-Metadata_All_samples_Merged/Control_CD4Tcells/CD4_Control.txt", row.names = FALSE, col.names = FALSE, quote = FALSE)

#Differential Expression Analysis

3. FC SCanner for DE

library(foreach)
library(doParallel)

setwd("/home/bioinfo/17-SingleCellFCscanner/")

source("scFCscanner_028_in_list.r")

Script to calculate logFC, Filter logFC >2 & logfc <-1.5, exclude lines when mean_L1_L7 <0.2 & control_group <0.2

# # Load necessary libraries
# library(dplyr)
# library(readr)
# 
# # Define the file processing function
# process_file <- function(file_path, output_dir) {
#   # Read the TSV file
#   Exp_Allsample <- read_tsv(file_path)
#   
#   # Check if the first column name is missing, and if so, set it to "gene"
#   if (colnames(Exp_Allsample)[1] == "...1") {
#     colnames(Exp_Allsample)[1] <- "gene"
#   }
#   
#   # Sanitize column names to handle spaces
#   colnames(Exp_Allsample) <- make.names(colnames(Exp_Allsample), unique = TRUE)
#   
#   # Identify the FC and mean columns dynamically
#   fc_column <- grep("^FC\\.", colnames(Exp_Allsample), value = TRUE)  # FC column with spaces replaced by dots
#   mean_columns <- grep("^mean\\.", colnames(Exp_Allsample), value = TRUE)  # Mean columns with spaces replaced by dots
#   
#   # Ensure the required columns are present
#   if (length(fc_column) != 1 || length(mean_columns) != 2) {
#     stop(paste("Required columns not found in file:", file_path))
#   }
#   
#   # Dynamically assign mean column names for clarity
#   mean_P2 <- mean_columns[1]
#   mean_P3 <- mean_columns[2]
#   
#   # Calculate log2 fold-change directly within the pipe
#   Exp_Allsample <- Exp_Allsample %>%
#     mutate(log2FC = log2(!!sym(fc_column)))  # Add log2FC as a new column
#   
#   # Define thresholds
#   threshold_positive <- 1.5    # Positive log2FC threshold
#   threshold_negative <- -1 # Negative log2FC threshold
#   
#   # Filter rows based on log2FC and mean thresholds
#   filtered_data_final <- Exp_Allsample %>%
#     filter(log2FC > threshold_positive | log2FC < threshold_negative) %>%
#     filter(!(!!sym(mean_P2) < 0.2 & !!sym(mean_P3) < 0.2))
#   
#   # Generate output file path
#   output_file <- file.path(output_dir, paste0("2-filtered_", basename(file_path)))
#   
#   # Write the filtered data to a CSV file
#   write.csv(filtered_data_final, output_file, row.names = FALSE)
#   
#   # Return the output file path for logging
#   return(output_file)
# }
# 
# # Set the input directory, output directory, and file list
# input_dir <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/"
# output_dir <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/Filtered/"
# file_list <- list.files(input_dir, pattern = "\\.csv$", full.names = TRUE)
# 
# # Create the output directory if it doesn't exist
# if (!dir.exists(output_dir)) {
#   dir.create(output_dir, recursive = TRUE)
# }
# 
# # Apply the process_file function to each file
# output_files <- lapply(file_list, process_file, output_dir = output_dir)
# 
# # Print completion message
# cat("Processing complete. Filtered files saved in the directory:", output_dir, "\n")

Script to calculate logFC, Filter logFC >2 & logfc <-1.5, exclude lines when mean_L1_L7 <0.2 & control_group <0.2

# # Load necessary libraries
# library(dplyr)
# library(readr)
# 
# # Enhanced file processing function
# process_file <- function(file_path, output_dir) {
#   tryCatch({
#     # Read the TSV file with explicit column types
#     Exp_Allsample <- read_tsv(file_path, col_types = cols(.default = col_guess()))
#     
#     # Check if the first column name is missing, and if so, set it to "gene"
#     if (colnames(Exp_Allsample)[1] == "...1") {
#       colnames(Exp_Allsample)[1] <- "gene"
#     }
#     
#     # Sanitize column names to handle spaces and special characters
#     colnames(Exp_Allsample) <- make.names(colnames(Exp_Allsample), unique = TRUE)
#     
#     # Identify the FC column dynamically
#     fc_column <- grep("^FC\\.", colnames(Exp_Allsample), value = TRUE)  # FC column with spaces replaced by dots
#     
#     # Dynamically identify mean columns by matching specific patterns (e.g., columns starting with "mean")
#     mean_columns <- grep("^mean\\.", colnames(Exp_Allsample), value = TRUE)  # Mean columns with spaces replaced by dots
#     
#     # If the mean column names are inconsistent, use alternative logic
#     if (length(mean_columns) < 2) {
#       # Attempt to identify mean columns by finding numeric columns with distinct naming patterns
#       numeric_columns <- colnames(Exp_Allsample)[sapply(Exp_Allsample, is.numeric)]
#       mean_columns <- numeric_columns[grep("Mean|mean|Average|avg", numeric_columns, ignore.case = TRUE)]
#     }
#     
#     # Ensure the required columns are present
#     if (length(fc_column) != 1 || length(mean_columns) < 2) {
#       stop(paste("Required columns not found in file:", file_path))
#     }
#     
#     # Select the first two mean columns dynamically
#     mean_P2 <- mean_columns[1]
#     mean_P3 <- mean_columns[2]
#     
#     # Calculate log2 fold-change directly within the pipe
#     Exp_Allsample <- Exp_Allsample %>%
#       mutate(log2FC = log2(!!sym(fc_column)))  # Add log2FC as a new column
#     
#     # Define thresholds
#     threshold_positive <- 1.5    # Positive log2FC threshold
#     threshold_negative <- -1 # Negative log2FC threshold
#     
#     # Filter rows based on log2FC and mean thresholds
#     filtered_data_final <- Exp_Allsample %>%
#       filter(log2FC > threshold_positive | log2FC < threshold_negative) %>%
#       filter(!(!!sym(mean_P2) < 0.2 & !!sym(mean_P3) < 0.2))
#     
#     # Extract the portion of the filename after the prefix "tab_" (if present)
#     base_filename <- basename(file_path)
#     new_filename <- if (grepl("tab_", base_filename)) {
#       sub("^.*tab_", "", base_filename)
#     } else {
#       base_filename
#     }
#     
#     # Generate output file path
#     output_file <- file.path(output_dir, paste0("2-filtered_", new_filename))
#     
#     # Write the filtered data to a CSV file
#     write.csv(filtered_data_final, output_file, row.names = FALSE)
#     
#     # Return the output file path for logging
#     return(output_file)
#   }, error = function(e) {
#     # Log error message
#     message(paste("Error processing file:", file_path, "\n", e))
#     return(NULL)
#   })
# }
# 
# # Set the input directory, output directory, and file list
# input_dir <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/"
# output_dir <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/Filtered2/"
# file_list <- list.files(input_dir, pattern = "\\.csv$", full.names = TRUE)
# 
# # Create the output directory if it doesn't exist
# if (!dir.exists(output_dir)) {
#   dir.create(output_dir, recursive = TRUE)
# }
# 
# # Apply the process_file function to each file and log any errors
# output_files <- lapply(file_list, function(file) {
#   message("Processing file:", file)
#   process_file(file, output_dir)
# })
# 
# # Print completion message
# cat("Processing complete. Filtered files saved in the directory:", output_dir, "\n")
# 
# 

Barplot for up and down regulated genes

# Load necessary libraries
library(readr)
library(dplyr)
library(stringr)

# Define file paths
input_file <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/Filtered2/2-filtered_Cluster19_cells_vs_CD4_Control.csv"
output_folder <- "Comparisons_Postprocessing/Step_by_step_DE_Analysis/3-FC-Comparison_to_Control/6-All_Files_Together_for_Filtering/TEST/Filtered2/Enrichment_Analysis_Files_for_Autocompare/C19_cells_vs_CD4_Control/"

# Ensure output folder exists
if (!dir.exists(output_folder)) {
  dir.create(output_folder, recursive = TRUE)
}

data <- tryCatch({
  read.csv(input_file, stringsAsFactors = FALSE)
}, error = function(e) {
  stop("Error reading input file. Check the file path or format.")
})



# Check if the necessary columns exist
if (!all(c("log2FC", "gene") %in% colnames(data))) {
  stop("Required columns ('log2FC' and 'gene') are missing in the data.")
}

# Choose your own log2FC threshold for both positive and negative values
threshold_positive <- 3.5 # Set your chosen threshold for positive log2FC
threshold_negative <- -1  # Set your chosen threshold for negative log2FC

# Filter the data based on log2FC criteria
filtered_data <- data %>%
  filter(log2FC > threshold_positive | log2FC < threshold_negative)

# Filter for upregulated and downregulated genes based on the filtered data
upregulated_genes <- filtered_data %>% filter(log2FC > threshold_positive)
downregulated_genes <- filtered_data %>% filter(log2FC < threshold_negative)

# Extract only gene names as vectors
upregulated_gene_names <- upregulated_genes %>% pull(gene)
downregulated_gene_names <- downregulated_genes %>% pull(gene)

# Extract base name for the input file (without extension) and remove the "2-filtered_" prefix
base_name <- tools::file_path_sans_ext(basename(input_file))  # Extract base name without extension
base_name <- gsub("^2-filtered_", "", base_name)  # Remove "2-filtered_" prefix

# Create output file paths with dynamic names
upregulated_file <- file.path(output_folder, paste0(base_name, "_upregulated_genes.txt"))
downregulated_file <- file.path(output_folder, paste0(base_name, "_downregulated_genes.txt"))

# Save the gene names to text files
write_lines(upregulated_gene_names, upregulated_file)
write_lines(downregulated_gene_names, downregulated_file)

# Print the number of upregulated and downregulated genes
cat("Number of upregulated genes:", length(upregulated_gene_names), "\n")
cat("Number of downregulated genes:", length(downregulated_gene_names), "\n")
cat("Gene names saved to:\n")
cat("  Upregulated genes: ", upregulated_file, "\n")
cat("  Downregulated genes: ", downregulated_file, "\n")
LS0tCnRpdGxlOiAiRkMgU2Nhbm5lciBmaWxlcyBmb3IgQW5hbHlzaXMtcGFydDIiCmF1dGhvcjogTmFzaXIgTWFobW9vZCBBYmJhc2kKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgIyBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICAjIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKICAjIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICAjcm1kZm9ybWF0czo6cmVhZHRoZWRvd24KICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKLS0tCgojIDEuIGxvYWQgbGlicmFyaWVzCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZm9yZWFjaCkKbGlicmFyeShkb1BhcmFsbGVsKQoKCgoKYGBgCiNEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcwoKIyAyLiBsb2FkIHNldXJhdCBvYmplY3QgYW5kIHNhdmUgbWV0YWRhdGEgZmlsZSBmb3Igc2FtcGxlcwpgYGB7ciBsb2FkX3NldXJhdCwgIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojTG9hZCBTZXVyYXQgT2JqZWN0IEw3CmxvYWQoIi9ob21lL2Jpb2luZm8vMC1pbXBfUm9iai9IYXJtb255X2ludGVncmF0ZWRfQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfUEJNQzEweF93aXRoX2hhcm1vbnlfY2x1c3RlcmluZy5Sb2JqIikKIyBzY3RfZGF0YSA8LSBHZXRBc3NheURhdGEoQWxsX3NhbXBsZXNfTWVyZ2VkLCBhc3NheSA9ICJTQ1QiLCBsYXllciA9ICJkYXRhIikKCiMgbWVtb3J5LmxpbWl0KHNpemUgPSA2NDAwMCkKIyAKIyAjIFRyYW5zcG9zZSB0aGUgZGF0YSBzbyB0aGF0IGNlbGxzIGFyZSByb3dzIGFuZCBnZW5lcyBhcmUgY29sdW1ucwojIHRyYW5zcG9zZWRfZGF0YSA8LSB0KGFzLmRhdGEuZnJhbWUoc2N0X2RhdGEpKQojIAojICMgU3BlY2lmeSB0aGUgZmlsZSBuYW1lIGFuZCBzYXZlIGFzIENTVgojIHdyaXRlLmNzdih0cmFuc3Bvc2VkX2RhdGEsIGZpbGUgPSAidGFibGUvU0NUX2RhdGFfQWxsX3NhbXBsZXNfTWVyZ2VkX3RyYW5zcG9zZWQuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkKIyAKIyAKIyAKIyAKIyAKIyAjIEV4dHJhY3QgbWV0YWRhdGEgZnJvbSBTZXVyYXQgb2JqZWN0CiMgbWV0YWRhdGEgPC0gQWxsX3NhbXBsZXNfTWVyZ2VkQG1ldGEuZGF0YQojIAojICMgV3JpdGUgbWV0YWRhdGEgdG8gQ1NWCiMgd3JpdGUuY3N2KG1ldGFkYXRhLCBmaWxlID0gIkV4dHJhL01ldGFkYXRhX0FsbF9zYW1wbGVzX01lcmdlZC5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQoKCmBgYAoKIyAyLiBjcmVhdGUgYmFycGxvdCBvZiBDRDQgY2VsbHMgaW4gYWxsIHNhbXBsZXMKYGBge3IgYmFycGxvdCwgIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQoKIyBMb2FkIHlvdXIgQ1NWIGZpbGUKZGF0YSA8LSByZWFkLmNzdigiRXh0cmEvU3RlcF9ieV9zdGVwX0RFX0FuYWx5c2lzLzEtTWV0YWRhdGFfQWxsX3NhbXBsZXNfTWVyZ2VkL0FsbF9TYW1wbGVzX21ldGFkYXRhL01ldGFkYXRhX0FsbF9zYW1wbGVzX01lcmdlZC5jc3YiKQoKIyBGaWx0ZXIgcm93cyB3aGVyZSBhbGwgdGhyZWUgcHJlZGljdGVkIGNvbHVtbnMgY29udGFpbiAiQ0Q0IFQiCmZpbHRlcmVkX2RhdGEgPC0gZGF0YSAlPiUKICBmaWx0ZXIoZ3JlcGwoIkNENCIsIHByZWRpY3RlZC5jZWxsdHlwZS5sMSkgJiAKICAgICAgICAgZ3JlcGwoIkNENCIsIHByZWRpY3RlZC5jZWxsdHlwZS5sMikgJiAKICAgICAgICAgZ3JlcGwoIkNENCIsIHByZWRpY3RlZC5jZWxsdHlwZS5sMykpCgojIENvdW50IHRoZSBudW1iZXIgb2YgQ0Q0IFQgY2VsbHMgaW4gZWFjaCBvcmlnLmlkZW50IGdyb3VwCmNkNF90X2NvdW50cyA8LSBmaWx0ZXJlZF9kYXRhICU+JQogIGdyb3VwX2J5KG9yaWcuaWRlbnQpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkKCiMgUHJpbnQgdGhlIGNvdW50cwpwcmludChjZDRfdF9jb3VudHMpCgojIERlZmluZSBjb2xvcnMgZm9yIHRoZSBzYW1wbGVzIChvcHRpb25hbCkKc2FtcGxlX2NvbG9ycyA8LSBjKCJMMSIgPSAiIzFmNzdiNCIsICJMMiIgPSAiI2ZmN2YwZSIsICJMMyIgPSAiIzJjYTAyYyIsICJMNCIgPSAiI2Q2MjcyOCIsIAogICAgICAgICAgICAgICAgICAgIkw1IiA9ICIjOTQ2N2JkIiwgIkw2IiA9ICIjOGM1NjRiIiwgIkw3IiA9ICIjZTM3N2MyIiwgIlBCTUMiID0gIiM3ZjdmN2YiLCAKICAgICAgICAgICAgICAgICAgICJQQk1DMTB4IiA9ICIjYmNiZDIyIikKCiMgQ3JlYXRlIHRoZSBiYXIgcGxvdApjZWxsdHlwZV9wbG90IDwtIGdncGxvdChjZDRfdF9jb3VudHMsIGFlcyh4ID0gb3JpZy5pZGVudCwgeSA9IGNvdW50LCBmaWxsID0gb3JpZy5pZGVudCkpICsKICBnZW9tX2NvbCgpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb3VudCksIAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBzYW1wbGVfY29sb3JzKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIGdndGl0bGUoIkNvdW50IG9mIENENCAgQ2VsbHMgYnkgU2FtcGxlIikgKwogIHhsYWIoIlNhbXBsZSIpICsKICB5bGFiKCJOdW1iZXIgb2YgQ0Q0ICBDZWxscyIpCgojIFByaW50IHRoZSBwbG90CnByaW50KGNlbGx0eXBlX3Bsb3QpCgoKYGBgCgoKIyAyLiBjcmVhdGUgUEJNQyBDRDQgY2VsbHMgKENvbnRyb2wpIGZpbGUKYGBge3IgQ29udHJvbCwgIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQoKIyBMb2FkIHlvdXIgQ1NWIGZpbGUKZGF0YSA8LSByZWFkLmNzdigiRXh0cmEvTmV3RmlsZXMvUEJNQy9wYm1jX01FVEFEQVRBLmNzdiIpCgojIEZpbHRlciByb3dzIHdoZXJlIGFsbCB0aHJlZSBwcmVkaWN0ZWQgY29sdW1ucyBjb250YWluICJDRDQgVCIKZmlsdGVyZWRfZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcihncmVwbCgiQ0Q0IiwgcHJlZGljdGVkLmNlbGx0eXBlLmwxKSAmIAogICAgICAgICBncmVwbCgiQ0Q0IiwgcHJlZGljdGVkLmNlbGx0eXBlLmwyKSAmIAogICAgICAgICBncmVwbCgiQ0Q0IiwgcHJlZGljdGVkLmNlbGx0eXBlLmwzKSkKCndyaXRlLmNzdihmaWx0ZXJlZF9kYXRhLCAiRXh0cmEvU3RlcF9ieV9zdGVwX0RFX0FuYWx5c2lzLzEtTWV0YWRhdGFfQWxsX3NhbXBsZXNfTWVyZ2VkL0NvbnRyb2xfQ0Q0VGNlbGxzL0NENF9jZWxsc19QQk1DX0NvbnRyb2wuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojIFNhdmUgdGhlIGZpcnN0IGNvbHVtbiAoUEJNQyBjZWxscykgdG8gYSB0eHQgZmlsZSB3aXRob3V0IGhlYWRlcgp3cml0ZS50YWJsZShmaWx0ZXJlZF9kYXRhWywgMV0sICJFeHRyYS9TdGVwX2J5X3N0ZXBfREVfQW5hbHlzaXMvMS1NZXRhZGF0YV9BbGxfc2FtcGxlc19NZXJnZWQvQ29udHJvbF9DRDRUY2VsbHMvQ0Q0X0NvbnRyb2wudHh0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQoKCmBgYAoKI0RpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzCgojIDMuIEZDIFNDYW5uZXIgZm9yIERFCmBgYHtyIEZDc2Nhbm5lciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoZm9yZWFjaCkKbGlicmFyeShkb1BhcmFsbGVsKQoKc2V0d2QoIi9ob21lL2Jpb2luZm8vMTctU2luZ2xlQ2VsbEZDc2Nhbm5lci8iKQoKc291cmNlKCJzY0ZDc2Nhbm5lcl8wMjhfaW5fbGlzdC5yIikKYGBgCgoKIyMgU2NyaXB0IHRvIGNhbGN1bGF0ZSBsb2dGQywgRmlsdGVyIGxvZ0ZDID4yICYgbG9nZmMgPC0xLjUsIGV4Y2x1ZGUgbGluZXMgd2hlbiBtZWFuX0wxX0w3IDwwLjIgJiBjb250cm9sX2dyb3VwIDwwLjIKYGBge3IgRmlsdGVyaW5nMSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CiMgIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKIyBsaWJyYXJ5KGRwbHlyKQojIGxpYnJhcnkocmVhZHIpCiMgCiMgIyBEZWZpbmUgdGhlIGZpbGUgcHJvY2Vzc2luZyBmdW5jdGlvbgojIHByb2Nlc3NfZmlsZSA8LSBmdW5jdGlvbihmaWxlX3BhdGgsIG91dHB1dF9kaXIpIHsKIyAgICMgUmVhZCB0aGUgVFNWIGZpbGUKIyAgIEV4cF9BbGxzYW1wbGUgPC0gcmVhZF90c3YoZmlsZV9wYXRoKQojICAgCiMgICAjIENoZWNrIGlmIHRoZSBmaXJzdCBjb2x1bW4gbmFtZSBpcyBtaXNzaW5nLCBhbmQgaWYgc28sIHNldCBpdCB0byAiZ2VuZSIKIyAgIGlmIChjb2xuYW1lcyhFeHBfQWxsc2FtcGxlKVsxXSA9PSAiLi4uMSIpIHsKIyAgICAgY29sbmFtZXMoRXhwX0FsbHNhbXBsZSlbMV0gPC0gImdlbmUiCiMgICB9CiMgICAKIyAgICMgU2FuaXRpemUgY29sdW1uIG5hbWVzIHRvIGhhbmRsZSBzcGFjZXMKIyAgIGNvbG5hbWVzKEV4cF9BbGxzYW1wbGUpIDwtIG1ha2UubmFtZXMoY29sbmFtZXMoRXhwX0FsbHNhbXBsZSksIHVuaXF1ZSA9IFRSVUUpCiMgICAKIyAgICMgSWRlbnRpZnkgdGhlIEZDIGFuZCBtZWFuIGNvbHVtbnMgZHluYW1pY2FsbHkKIyAgIGZjX2NvbHVtbiA8LSBncmVwKCJeRkNcXC4iLCBjb2xuYW1lcyhFeHBfQWxsc2FtcGxlKSwgdmFsdWUgPSBUUlVFKSAgIyBGQyBjb2x1bW4gd2l0aCBzcGFjZXMgcmVwbGFjZWQgYnkgZG90cwojICAgbWVhbl9jb2x1bW5zIDwtIGdyZXAoIl5tZWFuXFwuIiwgY29sbmFtZXMoRXhwX0FsbHNhbXBsZSksIHZhbHVlID0gVFJVRSkgICMgTWVhbiBjb2x1bW5zIHdpdGggc3BhY2VzIHJlcGxhY2VkIGJ5IGRvdHMKIyAgIAojICAgIyBFbnN1cmUgdGhlIHJlcXVpcmVkIGNvbHVtbnMgYXJlIHByZXNlbnQKIyAgIGlmIChsZW5ndGgoZmNfY29sdW1uKSAhPSAxIHx8IGxlbmd0aChtZWFuX2NvbHVtbnMpICE9IDIpIHsKIyAgICAgc3RvcChwYXN0ZSgiUmVxdWlyZWQgY29sdW1ucyBub3QgZm91bmQgaW4gZmlsZToiLCBmaWxlX3BhdGgpKQojICAgfQojICAgCiMgICAjIER5bmFtaWNhbGx5IGFzc2lnbiBtZWFuIGNvbHVtbiBuYW1lcyBmb3IgY2xhcml0eQojICAgbWVhbl9QMiA8LSBtZWFuX2NvbHVtbnNbMV0KIyAgIG1lYW5fUDMgPC0gbWVhbl9jb2x1bW5zWzJdCiMgICAKIyAgICMgQ2FsY3VsYXRlIGxvZzIgZm9sZC1jaGFuZ2UgZGlyZWN0bHkgd2l0aGluIHRoZSBwaXBlCiMgICBFeHBfQWxsc2FtcGxlIDwtIEV4cF9BbGxzYW1wbGUgJT4lCiMgICAgIG11dGF0ZShsb2cyRkMgPSBsb2cyKCEhc3ltKGZjX2NvbHVtbikpKSAgIyBBZGQgbG9nMkZDIGFzIGEgbmV3IGNvbHVtbgojICAgCiMgICAjIERlZmluZSB0aHJlc2hvbGRzCiMgICB0aHJlc2hvbGRfcG9zaXRpdmUgPC0gMS41ICAgICMgUG9zaXRpdmUgbG9nMkZDIHRocmVzaG9sZAojICAgdGhyZXNob2xkX25lZ2F0aXZlIDwtIC0xICMgTmVnYXRpdmUgbG9nMkZDIHRocmVzaG9sZAojICAgCiMgICAjIEZpbHRlciByb3dzIGJhc2VkIG9uIGxvZzJGQyBhbmQgbWVhbiB0aHJlc2hvbGRzCiMgICBmaWx0ZXJlZF9kYXRhX2ZpbmFsIDwtIEV4cF9BbGxzYW1wbGUgJT4lCiMgICAgIGZpbHRlcihsb2cyRkMgPiB0aHJlc2hvbGRfcG9zaXRpdmUgfCBsb2cyRkMgPCB0aHJlc2hvbGRfbmVnYXRpdmUpICU+JQojICAgICBmaWx0ZXIoISghIXN5bShtZWFuX1AyKSA8IDAuMiAmICEhc3ltKG1lYW5fUDMpIDwgMC4yKSkKIyAgIAojICAgIyBHZW5lcmF0ZSBvdXRwdXQgZmlsZSBwYXRoCiMgICBvdXRwdXRfZmlsZSA8LSBmaWxlLnBhdGgob3V0cHV0X2RpciwgcGFzdGUwKCIyLWZpbHRlcmVkXyIsIGJhc2VuYW1lKGZpbGVfcGF0aCkpKQojICAgCiMgICAjIFdyaXRlIHRoZSBmaWx0ZXJlZCBkYXRhIHRvIGEgQ1NWIGZpbGUKIyAgIHdyaXRlLmNzdihmaWx0ZXJlZF9kYXRhX2ZpbmFsLCBvdXRwdXRfZmlsZSwgcm93Lm5hbWVzID0gRkFMU0UpCiMgICAKIyAgICMgUmV0dXJuIHRoZSBvdXRwdXQgZmlsZSBwYXRoIGZvciBsb2dnaW5nCiMgICByZXR1cm4ob3V0cHV0X2ZpbGUpCiMgfQojIAojICMgU2V0IHRoZSBpbnB1dCBkaXJlY3RvcnksIG91dHB1dCBkaXJlY3RvcnksIGFuZCBmaWxlIGxpc3QKIyBpbnB1dF9kaXIgPC0gIkNvbXBhcmlzb25zX1Bvc3Rwcm9jZXNzaW5nL1N0ZXBfYnlfc3RlcF9ERV9BbmFseXNpcy8zLUZDLUNvbXBhcmlzb25fdG9fQ29udHJvbC82LUFsbF9GaWxlc19Ub2dldGhlcl9mb3JfRmlsdGVyaW5nL1RFU1QvIgojIG91dHB1dF9kaXIgPC0gIkNvbXBhcmlzb25zX1Bvc3Rwcm9jZXNzaW5nL1N0ZXBfYnlfc3RlcF9ERV9BbmFseXNpcy8zLUZDLUNvbXBhcmlzb25fdG9fQ29udHJvbC82LUFsbF9GaWxlc19Ub2dldGhlcl9mb3JfRmlsdGVyaW5nL1RFU1QvRmlsdGVyZWQvIgojIGZpbGVfbGlzdCA8LSBsaXN0LmZpbGVzKGlucHV0X2RpciwgcGF0dGVybiA9ICJcXC5jc3YkIiwgZnVsbC5uYW1lcyA9IFRSVUUpCiMgCiMgIyBDcmVhdGUgdGhlIG91dHB1dCBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdAojIGlmICghZGlyLmV4aXN0cyhvdXRwdXRfZGlyKSkgewojICAgZGlyLmNyZWF0ZShvdXRwdXRfZGlyLCByZWN1cnNpdmUgPSBUUlVFKQojIH0KIyAKIyAjIEFwcGx5IHRoZSBwcm9jZXNzX2ZpbGUgZnVuY3Rpb24gdG8gZWFjaCBmaWxlCiMgb3V0cHV0X2ZpbGVzIDwtIGxhcHBseShmaWxlX2xpc3QsIHByb2Nlc3NfZmlsZSwgb3V0cHV0X2RpciA9IG91dHB1dF9kaXIpCiMgCiMgIyBQcmludCBjb21wbGV0aW9uIG1lc3NhZ2UKIyBjYXQoIlByb2Nlc3NpbmcgY29tcGxldGUuIEZpbHRlcmVkIGZpbGVzIHNhdmVkIGluIHRoZSBkaXJlY3Rvcnk6Iiwgb3V0cHV0X2RpciwgIlxuIikKCgpgYGAKCgojIyBTY3JpcHQgdG8gY2FsY3VsYXRlIGxvZ0ZDLCBGaWx0ZXIgbG9nRkMgPjIgJiBsb2dmYyA8LTEuNSwgZXhjbHVkZSBsaW5lcyB3aGVuIG1lYW5fTDFfTDcgPDAuMiAmIGNvbnRyb2xfZ3JvdXAgPDAuMgpgYGB7ciBGaWx0ZXJpbmcyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KIyAjIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwojIGxpYnJhcnkoZHBseXIpCiMgbGlicmFyeShyZWFkcikKIyAKIyAjIEVuaGFuY2VkIGZpbGUgcHJvY2Vzc2luZyBmdW5jdGlvbgojIHByb2Nlc3NfZmlsZSA8LSBmdW5jdGlvbihmaWxlX3BhdGgsIG91dHB1dF9kaXIpIHsKIyAgIHRyeUNhdGNoKHsKIyAgICAgIyBSZWFkIHRoZSBUU1YgZmlsZSB3aXRoIGV4cGxpY2l0IGNvbHVtbiB0eXBlcwojICAgICBFeHBfQWxsc2FtcGxlIDwtIHJlYWRfdHN2KGZpbGVfcGF0aCwgY29sX3R5cGVzID0gY29scyguZGVmYXVsdCA9IGNvbF9ndWVzcygpKSkKIyAgICAgCiMgICAgICMgQ2hlY2sgaWYgdGhlIGZpcnN0IGNvbHVtbiBuYW1lIGlzIG1pc3NpbmcsIGFuZCBpZiBzbywgc2V0IGl0IHRvICJnZW5lIgojICAgICBpZiAoY29sbmFtZXMoRXhwX0FsbHNhbXBsZSlbMV0gPT0gIi4uLjEiKSB7CiMgICAgICAgY29sbmFtZXMoRXhwX0FsbHNhbXBsZSlbMV0gPC0gImdlbmUiCiMgICAgIH0KIyAgICAgCiMgICAgICMgU2FuaXRpemUgY29sdW1uIG5hbWVzIHRvIGhhbmRsZSBzcGFjZXMgYW5kIHNwZWNpYWwgY2hhcmFjdGVycwojICAgICBjb2xuYW1lcyhFeHBfQWxsc2FtcGxlKSA8LSBtYWtlLm5hbWVzKGNvbG5hbWVzKEV4cF9BbGxzYW1wbGUpLCB1bmlxdWUgPSBUUlVFKQojICAgICAKIyAgICAgIyBJZGVudGlmeSB0aGUgRkMgY29sdW1uIGR5bmFtaWNhbGx5CiMgICAgIGZjX2NvbHVtbiA8LSBncmVwKCJeRkNcXC4iLCBjb2xuYW1lcyhFeHBfQWxsc2FtcGxlKSwgdmFsdWUgPSBUUlVFKSAgIyBGQyBjb2x1bW4gd2l0aCBzcGFjZXMgcmVwbGFjZWQgYnkgZG90cwojICAgICAKIyAgICAgIyBEeW5hbWljYWxseSBpZGVudGlmeSBtZWFuIGNvbHVtbnMgYnkgbWF0Y2hpbmcgc3BlY2lmaWMgcGF0dGVybnMgKGUuZy4sIGNvbHVtbnMgc3RhcnRpbmcgd2l0aCAibWVhbiIpCiMgICAgIG1lYW5fY29sdW1ucyA8LSBncmVwKCJebWVhblxcLiIsIGNvbG5hbWVzKEV4cF9BbGxzYW1wbGUpLCB2YWx1ZSA9IFRSVUUpICAjIE1lYW4gY29sdW1ucyB3aXRoIHNwYWNlcyByZXBsYWNlZCBieSBkb3RzCiMgICAgIAojICAgICAjIElmIHRoZSBtZWFuIGNvbHVtbiBuYW1lcyBhcmUgaW5jb25zaXN0ZW50LCB1c2UgYWx0ZXJuYXRpdmUgbG9naWMKIyAgICAgaWYgKGxlbmd0aChtZWFuX2NvbHVtbnMpIDwgMikgewojICAgICAgICMgQXR0ZW1wdCB0byBpZGVudGlmeSBtZWFuIGNvbHVtbnMgYnkgZmluZGluZyBudW1lcmljIGNvbHVtbnMgd2l0aCBkaXN0aW5jdCBuYW1pbmcgcGF0dGVybnMKIyAgICAgICBudW1lcmljX2NvbHVtbnMgPC0gY29sbmFtZXMoRXhwX0FsbHNhbXBsZSlbc2FwcGx5KEV4cF9BbGxzYW1wbGUsIGlzLm51bWVyaWMpXQojICAgICAgIG1lYW5fY29sdW1ucyA8LSBudW1lcmljX2NvbHVtbnNbZ3JlcCgiTWVhbnxtZWFufEF2ZXJhZ2V8YXZnIiwgbnVtZXJpY19jb2x1bW5zLCBpZ25vcmUuY2FzZSA9IFRSVUUpXQojICAgICB9CiMgICAgIAojICAgICAjIEVuc3VyZSB0aGUgcmVxdWlyZWQgY29sdW1ucyBhcmUgcHJlc2VudAojICAgICBpZiAobGVuZ3RoKGZjX2NvbHVtbikgIT0gMSB8fCBsZW5ndGgobWVhbl9jb2x1bW5zKSA8IDIpIHsKIyAgICAgICBzdG9wKHBhc3RlKCJSZXF1aXJlZCBjb2x1bW5zIG5vdCBmb3VuZCBpbiBmaWxlOiIsIGZpbGVfcGF0aCkpCiMgICAgIH0KIyAgICAgCiMgICAgICMgU2VsZWN0IHRoZSBmaXJzdCB0d28gbWVhbiBjb2x1bW5zIGR5bmFtaWNhbGx5CiMgICAgIG1lYW5fUDIgPC0gbWVhbl9jb2x1bW5zWzFdCiMgICAgIG1lYW5fUDMgPC0gbWVhbl9jb2x1bW5zWzJdCiMgICAgIAojICAgICAjIENhbGN1bGF0ZSBsb2cyIGZvbGQtY2hhbmdlIGRpcmVjdGx5IHdpdGhpbiB0aGUgcGlwZQojICAgICBFeHBfQWxsc2FtcGxlIDwtIEV4cF9BbGxzYW1wbGUgJT4lCiMgICAgICAgbXV0YXRlKGxvZzJGQyA9IGxvZzIoISFzeW0oZmNfY29sdW1uKSkpICAjIEFkZCBsb2cyRkMgYXMgYSBuZXcgY29sdW1uCiMgICAgIAojICAgICAjIERlZmluZSB0aHJlc2hvbGRzCiMgICAgIHRocmVzaG9sZF9wb3NpdGl2ZSA8LSAxLjUgICAgIyBQb3NpdGl2ZSBsb2cyRkMgdGhyZXNob2xkCiMgICAgIHRocmVzaG9sZF9uZWdhdGl2ZSA8LSAtMSAjIE5lZ2F0aXZlIGxvZzJGQyB0aHJlc2hvbGQKIyAgICAgCiMgICAgICMgRmlsdGVyIHJvd3MgYmFzZWQgb24gbG9nMkZDIGFuZCBtZWFuIHRocmVzaG9sZHMKIyAgICAgZmlsdGVyZWRfZGF0YV9maW5hbCA8LSBFeHBfQWxsc2FtcGxlICU+JQojICAgICAgIGZpbHRlcihsb2cyRkMgPiB0aHJlc2hvbGRfcG9zaXRpdmUgfCBsb2cyRkMgPCB0aHJlc2hvbGRfbmVnYXRpdmUpICU+JQojICAgICAgIGZpbHRlcighKCEhc3ltKG1lYW5fUDIpIDwgMC4yICYgISFzeW0obWVhbl9QMykgPCAwLjIpKQojICAgICAKIyAgICAgIyBFeHRyYWN0IHRoZSBwb3J0aW9uIG9mIHRoZSBmaWxlbmFtZSBhZnRlciB0aGUgcHJlZml4ICJ0YWJfIiAoaWYgcHJlc2VudCkKIyAgICAgYmFzZV9maWxlbmFtZSA8LSBiYXNlbmFtZShmaWxlX3BhdGgpCiMgICAgIG5ld19maWxlbmFtZSA8LSBpZiAoZ3JlcGwoInRhYl8iLCBiYXNlX2ZpbGVuYW1lKSkgewojICAgICAgIHN1YigiXi4qdGFiXyIsICIiLCBiYXNlX2ZpbGVuYW1lKQojICAgICB9IGVsc2UgewojICAgICAgIGJhc2VfZmlsZW5hbWUKIyAgICAgfQojICAgICAKIyAgICAgIyBHZW5lcmF0ZSBvdXRwdXQgZmlsZSBwYXRoCiMgICAgIG91dHB1dF9maWxlIDwtIGZpbGUucGF0aChvdXRwdXRfZGlyLCBwYXN0ZTAoIjItZmlsdGVyZWRfIiwgbmV3X2ZpbGVuYW1lKSkKIyAgICAgCiMgICAgICMgV3JpdGUgdGhlIGZpbHRlcmVkIGRhdGEgdG8gYSBDU1YgZmlsZQojICAgICB3cml0ZS5jc3YoZmlsdGVyZWRfZGF0YV9maW5hbCwgb3V0cHV0X2ZpbGUsIHJvdy5uYW1lcyA9IEZBTFNFKQojICAgICAKIyAgICAgIyBSZXR1cm4gdGhlIG91dHB1dCBmaWxlIHBhdGggZm9yIGxvZ2dpbmcKIyAgICAgcmV0dXJuKG91dHB1dF9maWxlKQojICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiMgICAgICMgTG9nIGVycm9yIG1lc3NhZ2UKIyAgICAgbWVzc2FnZShwYXN0ZSgiRXJyb3IgcHJvY2Vzc2luZyBmaWxlOiIsIGZpbGVfcGF0aCwgIlxuIiwgZSkpCiMgICAgIHJldHVybihOVUxMKQojICAgfSkKIyB9CiMgCiMgIyBTZXQgdGhlIGlucHV0IGRpcmVjdG9yeSwgb3V0cHV0IGRpcmVjdG9yeSwgYW5kIGZpbGUgbGlzdAojIGlucHV0X2RpciA8LSAiQ29tcGFyaXNvbnNfUG9zdHByb2Nlc3NpbmcvU3RlcF9ieV9zdGVwX0RFX0FuYWx5c2lzLzMtRkMtQ29tcGFyaXNvbl90b19Db250cm9sLzYtQWxsX0ZpbGVzX1RvZ2V0aGVyX2Zvcl9GaWx0ZXJpbmcvVEVTVC8iCiMgb3V0cHV0X2RpciA8LSAiQ29tcGFyaXNvbnNfUG9zdHByb2Nlc3NpbmcvU3RlcF9ieV9zdGVwX0RFX0FuYWx5c2lzLzMtRkMtQ29tcGFyaXNvbl90b19Db250cm9sLzYtQWxsX0ZpbGVzX1RvZ2V0aGVyX2Zvcl9GaWx0ZXJpbmcvVEVTVC9GaWx0ZXJlZDIvIgojIGZpbGVfbGlzdCA8LSBsaXN0LmZpbGVzKGlucHV0X2RpciwgcGF0dGVybiA9ICJcXC5jc3YkIiwgZnVsbC5uYW1lcyA9IFRSVUUpCiMgCiMgIyBDcmVhdGUgdGhlIG91dHB1dCBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdAojIGlmICghZGlyLmV4aXN0cyhvdXRwdXRfZGlyKSkgewojICAgZGlyLmNyZWF0ZShvdXRwdXRfZGlyLCByZWN1cnNpdmUgPSBUUlVFKQojIH0KIyAKIyAjIEFwcGx5IHRoZSBwcm9jZXNzX2ZpbGUgZnVuY3Rpb24gdG8gZWFjaCBmaWxlIGFuZCBsb2cgYW55IGVycm9ycwojIG91dHB1dF9maWxlcyA8LSBsYXBwbHkoZmlsZV9saXN0LCBmdW5jdGlvbihmaWxlKSB7CiMgICBtZXNzYWdlKCJQcm9jZXNzaW5nIGZpbGU6IiwgZmlsZSkKIyAgIHByb2Nlc3NfZmlsZShmaWxlLCBvdXRwdXRfZGlyKQojIH0pCiMgCiMgIyBQcmludCBjb21wbGV0aW9uIG1lc3NhZ2UKIyBjYXQoIlByb2Nlc3NpbmcgY29tcGxldGUuIEZpbHRlcmVkIGZpbGVzIHNhdmVkIGluIHRoZSBkaXJlY3Rvcnk6Iiwgb3V0cHV0X2RpciwgIlxuIikKIyAKIyAKCmBgYAoKCgojIyBCYXJwbG90IGZvciB1cCBhbmQgZG93biByZWd1bGF0ZWQgZ2VuZXMKYGBge3IgY3JlYXRlVFh0LWZpbGVzLCBldmFsID0gRkFMU0V9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3RyaW5ncikKCiMgRGVmaW5lIGZpbGUgcGF0aHMKaW5wdXRfZmlsZSA8LSAiQ29tcGFyaXNvbnNfUG9zdHByb2Nlc3NpbmcvU3RlcF9ieV9zdGVwX0RFX0FuYWx5c2lzLzMtRkMtQ29tcGFyaXNvbl90b19Db250cm9sLzYtQWxsX0ZpbGVzX1RvZ2V0aGVyX2Zvcl9GaWx0ZXJpbmcvVEVTVC9GaWx0ZXJlZDIvMi1maWx0ZXJlZF9DbHVzdGVyMTlfY2VsbHNfdnNfQ0Q0X0NvbnRyb2wuY3N2IgpvdXRwdXRfZm9sZGVyIDwtICJDb21wYXJpc29uc19Qb3N0cHJvY2Vzc2luZy9TdGVwX2J5X3N0ZXBfREVfQW5hbHlzaXMvMy1GQy1Db21wYXJpc29uX3RvX0NvbnRyb2wvNi1BbGxfRmlsZXNfVG9nZXRoZXJfZm9yX0ZpbHRlcmluZy9URVNUL0ZpbHRlcmVkMi9FbnJpY2htZW50X0FuYWx5c2lzX0ZpbGVzX2Zvcl9BdXRvY29tcGFyZS9DMTlfY2VsbHNfdnNfQ0Q0X0NvbnRyb2wvIgoKIyBFbnN1cmUgb3V0cHV0IGZvbGRlciBleGlzdHMKaWYgKCFkaXIuZXhpc3RzKG91dHB1dF9mb2xkZXIpKSB7CiAgZGlyLmNyZWF0ZShvdXRwdXRfZm9sZGVyLCByZWN1cnNpdmUgPSBUUlVFKQp9CgpkYXRhIDwtIHRyeUNhdGNoKHsKICByZWFkLmNzdihpbnB1dF9maWxlLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCn0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogIHN0b3AoIkVycm9yIHJlYWRpbmcgaW5wdXQgZmlsZS4gQ2hlY2sgdGhlIGZpbGUgcGF0aCBvciBmb3JtYXQuIikKfSkKCgoKIyBDaGVjayBpZiB0aGUgbmVjZXNzYXJ5IGNvbHVtbnMgZXhpc3QKaWYgKCFhbGwoYygibG9nMkZDIiwgImdlbmUiKSAlaW4lIGNvbG5hbWVzKGRhdGEpKSkgewogIHN0b3AoIlJlcXVpcmVkIGNvbHVtbnMgKCdsb2cyRkMnIGFuZCAnZ2VuZScpIGFyZSBtaXNzaW5nIGluIHRoZSBkYXRhLiIpCn0KCiMgQ2hvb3NlIHlvdXIgb3duIGxvZzJGQyB0aHJlc2hvbGQgZm9yIGJvdGggcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIHZhbHVlcwp0aHJlc2hvbGRfcG9zaXRpdmUgPC0gMy41ICMgU2V0IHlvdXIgY2hvc2VuIHRocmVzaG9sZCBmb3IgcG9zaXRpdmUgbG9nMkZDCnRocmVzaG9sZF9uZWdhdGl2ZSA8LSAtMSAgIyBTZXQgeW91ciBjaG9zZW4gdGhyZXNob2xkIGZvciBuZWdhdGl2ZSBsb2cyRkMKCiMgRmlsdGVyIHRoZSBkYXRhIGJhc2VkIG9uIGxvZzJGQyBjcml0ZXJpYQpmaWx0ZXJlZF9kYXRhIDwtIGRhdGEgJT4lCiAgZmlsdGVyKGxvZzJGQyA+IHRocmVzaG9sZF9wb3NpdGl2ZSB8IGxvZzJGQyA8IHRocmVzaG9sZF9uZWdhdGl2ZSkKCiMgRmlsdGVyIGZvciB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lcyBiYXNlZCBvbiB0aGUgZmlsdGVyZWQgZGF0YQp1cHJlZ3VsYXRlZF9nZW5lcyA8LSBmaWx0ZXJlZF9kYXRhICU+JSBmaWx0ZXIobG9nMkZDID4gdGhyZXNob2xkX3Bvc2l0aXZlKQpkb3ducmVndWxhdGVkX2dlbmVzIDwtIGZpbHRlcmVkX2RhdGEgJT4lIGZpbHRlcihsb2cyRkMgPCB0aHJlc2hvbGRfbmVnYXRpdmUpCgojIEV4dHJhY3Qgb25seSBnZW5lIG5hbWVzIGFzIHZlY3RvcnMKdXByZWd1bGF0ZWRfZ2VuZV9uYW1lcyA8LSB1cHJlZ3VsYXRlZF9nZW5lcyAlPiUgcHVsbChnZW5lKQpkb3ducmVndWxhdGVkX2dlbmVfbmFtZXMgPC0gZG93bnJlZ3VsYXRlZF9nZW5lcyAlPiUgcHVsbChnZW5lKQoKIyBFeHRyYWN0IGJhc2UgbmFtZSBmb3IgdGhlIGlucHV0IGZpbGUgKHdpdGhvdXQgZXh0ZW5zaW9uKSBhbmQgcmVtb3ZlIHRoZSAiMi1maWx0ZXJlZF8iIHByZWZpeApiYXNlX25hbWUgPC0gdG9vbHM6OmZpbGVfcGF0aF9zYW5zX2V4dChiYXNlbmFtZShpbnB1dF9maWxlKSkgICMgRXh0cmFjdCBiYXNlIG5hbWUgd2l0aG91dCBleHRlbnNpb24KYmFzZV9uYW1lIDwtIGdzdWIoIl4yLWZpbHRlcmVkXyIsICIiLCBiYXNlX25hbWUpICAjIFJlbW92ZSAiMi1maWx0ZXJlZF8iIHByZWZpeAoKIyBDcmVhdGUgb3V0cHV0IGZpbGUgcGF0aHMgd2l0aCBkeW5hbWljIG5hbWVzCnVwcmVndWxhdGVkX2ZpbGUgPC0gZmlsZS5wYXRoKG91dHB1dF9mb2xkZXIsIHBhc3RlMChiYXNlX25hbWUsICJfdXByZWd1bGF0ZWRfZ2VuZXMudHh0IikpCmRvd25yZWd1bGF0ZWRfZmlsZSA8LSBmaWxlLnBhdGgob3V0cHV0X2ZvbGRlciwgcGFzdGUwKGJhc2VfbmFtZSwgIl9kb3ducmVndWxhdGVkX2dlbmVzLnR4dCIpKQoKIyBTYXZlIHRoZSBnZW5lIG5hbWVzIHRvIHRleHQgZmlsZXMKd3JpdGVfbGluZXModXByZWd1bGF0ZWRfZ2VuZV9uYW1lcywgdXByZWd1bGF0ZWRfZmlsZSkKd3JpdGVfbGluZXMoZG93bnJlZ3VsYXRlZF9nZW5lX25hbWVzLCBkb3ducmVndWxhdGVkX2ZpbGUpCgojIFByaW50IHRoZSBudW1iZXIgb2YgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKY2F0KCJOdW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXM6IiwgbGVuZ3RoKHVwcmVndWxhdGVkX2dlbmVfbmFtZXMpLCAiXG4iKQpjYXQoIk51bWJlciBvZiBkb3ducmVndWxhdGVkIGdlbmVzOiIsIGxlbmd0aChkb3ducmVndWxhdGVkX2dlbmVfbmFtZXMpLCAiXG4iKQpjYXQoIkdlbmUgbmFtZXMgc2F2ZWQgdG86XG4iKQpjYXQoIiAgVXByZWd1bGF0ZWQgZ2VuZXM6ICIsIHVwcmVndWxhdGVkX2ZpbGUsICJcbiIpCmNhdCgiICBEb3ducmVndWxhdGVkIGdlbmVzOiAiLCBkb3ducmVndWxhdGVkX2ZpbGUsICJcbiIpCgoKYGBgCgo=