1 Introduction

This document provides the definitive end-to-end bioinformatics pipeline to analyze the Whole Exome Sequencing (WES) data for Patient 1 and its derived cell lines.

Key Findings & Strategy: 1. The original WES BAM files are missing critical @RG (Read Group) sample name information, and the gnomAD reference file has an incompatible chromosome naming scheme. 2. The scRNA-seq data was processed on hg38, while the WES data is on hg19. 3. Therefore, the correct strategy is: a. First, create new, corrected BAM files with the proper @RG headers. b. Second, create a new, corrected gnomAD file with the proper chromosome names and index. c. Perform all WES analyses in hg19 using these new, corrected files. d. Use liftOver to convert the final CNV results to hg38 for direct comparison.

Sample Information: * N1: Normal (Constitutional DNA) * T1: Primary Tumor (Fresh Sézary Cells) * X1: In-vivo derived Cell Line (from Mouse) * XX1: Secondary Cell Line (cultured from X1)

2 Setup and Configuration

This chunk defines all necessary paths and global variables for the entire pipeline.

#!/bin/bash
# Activate the conda environment to make its tools available
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- DEFINE GLOBAL VARIABLES ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
REF_GENOME="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19.fa"
INTERVAL_LIST="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/reference/PJ1610240_covered.bed"
LIFTOVER_CHAIN="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19ToHg38.over.chain.gz"
VEP_PATH="/home/bioinfo/tools/ensembl-vep/vep"
JAVA_OPTS="-Xmx16g -DGATK_STACKTRACE_ON_USER_EXCEPTION=true"

# --- This is the path to the gnomAD file we will CREATE in the prepare_gnomad step ---
GNOMAD_HG19_CORRECTED="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/reference/gnomad.exomes.r2.0.2.sites.chr.vcf.gz"

# --- OUTPUT DIRECTORIES ---
mkdir -p $BASE_DIR/hg19_analysis/bams_with_rg
mkdir -p $BASE_DIR/hg19_analysis/cnv_results
mkdir -p $BASE_DIR/hg19_analysis/somatic_variants
mkdir -p $BASE_DIR/hg19_analysis/liftover_results
mkdir -p $BASE_DIR/hg19_analysis/visualizations

echo "Configuration loaded and output directories created."

3 Prepare BAM Files by Adding Read Groups

This step fixes the missing @RG (Read Group) headers in the original BAM files. This is a one-time operation that creates new, analysis-ready BAMs.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
OUTPUT_BAM_DIR="$BASE_DIR/hg19_analysis/bams_with_rg"

# --- Loop through each sample to add Read Groups ---
for SAMPLE_ID in N1 T1 X1 XX1; do
  INPUT_BAM="$BASE_DIR/$SAMPLE_ID/sorted.bam"
  OUTPUT_BAM="$OUTPUT_BAM_DIR/${SAMPLE_ID}.with_rg.bam"

  if [ -f "$OUTPUT_BAM" ]; then
    echo "Corrected BAM for $SAMPLE_ID already exists. Skipping."
    continue
  fi

  echo "--- Adding Read Group to $SAMPLE_ID ---"
picard AddOrReplaceReadGroups \
  I="$INPUT_BAM" \
  O="$OUTPUT_BAM" \
  RGID="$SAMPLE_ID" \
  RGLB="lib1" \
  RGPL="illumina" \
  RGPU="unit1" \
  RGSM="$SAMPLE_ID" \
  VALIDATION_STRINGENCY=LENIENT  # <--- THE CRITICAL FIX
    
  samtools index "$OUTPUT_BAM"
done

echo "BAM file preparation complete. New files are in $OUTPUT_BAM_DIR"

This step corrects the chromosome naming scheme in the gnomAD VCF file to be compatible with GATK.

This step ensures that all the newly created BAM files have a corresponding .bai index, which is a strict requirement for GATK.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
BAM_DIR="$BASE_DIR/hg19_analysis/bams_with_rg"

# --- Loop through each corrected BAM to create the index ---
for SAMPLE_ID in N1 T1 X1 XX1; do
  BAM_FILE="$BAM_DIR/${SAMPLE_ID}.with_rg.bam"
  
  # Check if the index already exists
  if [ -f "${BAM_FILE}.bai" ]; then
    echo "Index for $SAMPLE_ID already exists. Skipping."
  else
    echo "--- Indexing corrected BAM for $SAMPLE_ID ---"
    samtools index "$BAM_FILE"
  fi
done

echo "BAM file indexing complete."

4 Prepare gnomAD Reference File

This one-time step ensures the gnomAD VCF uses the chr prefix and has the correct .tbi index for GATK.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
REFERENCE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/reference"
OLD_GNOMAD="$REFERENCE_DIR/gnomad.exomes.r2.0.2.sites.vcf.gz"
NEW_GNOMAD="$REFERENCE_DIR/gnomad.exomes.r2.0.2.sites.chr.vcf.gz"
MAP_FILE="$REFERENCE_DIR/chr_name_map.txt"

if [ -f "$NEW_GNOMAD" ] && [ -f "${NEW_GNOMAD}.tbi" ]; then
  echo "Corrected gnomAD file and its .tbi index already exist. Skipping preparation."
else
  echo "Corrected gnomAD file or its index not found. Starting preparation..."

  if [ ! -f "$MAP_FILE" ]; then
    echo "Creating chromosome name map file: $MAP_FILE"
    for i in {1..22} X Y M; do echo "$i chr$i"; done > "$MAP_FILE"
  fi

  echo "Starting bcftools annotation... this will take several minutes."
  bcftools annotate --rename-chrs "$MAP_FILE" --threads 8 -o "$NEW_GNOMAD" -O z "$OLD_GNOMAD"

  echo "Annotation complete. Now creating a Tabix (.tbi) index..."
  bcftools index -t "$NEW_GNOMAD"

  echo "Preparation complete. The new file '$NEW_GNOMAD' and its .tbi index are ready."
fi

5 Somatic CNV Analysis (in hg19)

This step uses CNVkit on the newly created BAM files with correct headers.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
REF_GENOME="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19.fa"
INTERVAL_LIST="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/reference/PJ1610240_covered.bed"
BAM_DIR="$BASE_DIR/hg19_analysis/bams_with_rg"
NORMAL_BAM="$BAM_DIR/N1.with_rg.bam"
REFERENCE_CNN="$BASE_DIR/hg19_analysis/cnv_results/reference.cnn"

echo "Building reference from N1 (using corrected BAM)..."
cnvkit.py batch "$NORMAL_BAM" \
  --normal \
  --targets "$INTERVAL_LIST" \
  --fasta "$REF_GENOME" \
  --output-reference "$REFERENCE_CNN" \
  --output-dir "$BASE_DIR/hg19_analysis/cnv_results/N1" \
  -p 8  # <--- CORRECTED

for SAMPLE in T1 X1 XX1; do
  echo "--- Calling CNVs for $SAMPLE in hg19 (using corrected BAM) ---"
  SAMPLE_BAM="$BAM_DIR/${SAMPLE}.with_rg.bam"
  
  cnvkit.py batch "$SAMPLE_BAM" \
    --reference "$REFERENCE_CNN" \
    --output-dir "$BASE_DIR/hg19_analysis/cnv_results/$SAMPLE" \
    -p 8  # <--- CORRECTED
done

echo "hg19 CNVkit analysis complete."

6 LiftOver CNV Results to hg38

This step converts the coordinates of the final .cns segment files from hg19 to hg38 using the robust liftOver tool.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
LIFTOVER_CHAIN="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19ToHg38.over.chain.gz"

echo "--- Lifting over CNV segments from hg19 to hg38 using liftOver ---"

for SAMPLE in T1 X1 XX1; do
  # --- CORRECTED FILENAME ---
  # CNVkit names the output file based on the input BAM's basename, which was "SAMPLE.with_rg"
  CNS_HG19="$BASE_DIR/hg19_analysis/cnv_results/$SAMPLE/${SAMPLE}.with_rg.cns"
  # --------------------------
  
  CNS_HG38="$BASE_DIR/hg19_analysis/liftover_results/${SAMPLE}.hg38.cns"
  UNMAPPED_FILE="$BASE_DIR/hg19_analysis/liftover_results/${SAMPLE}.unmapped.txt"
  
  if [ -f "$CNS_HG38" ]; then
    echo "Lifted file for $SAMPLE already exists, skipping."
    continue
  fi
  
  # Check if the input file exists before trying to lift it over
  if [ ! -f "$CNS_HG19" ]; then
    echo "ERROR: Input file $CNS_HG19 not found. Cannot perform liftover."
    continue # Skip to the next sample
  fi

  echo "Lifting over $CNS_HG19 -> $CNS_HG38"
  tail -n +2 "$CNS_HG19" | liftOver -bedPlus=4 stdin "$LIFTOVER_CHAIN" "$CNS_HG38" "$UNMAPPED_FILE"
done

echo "LiftOver complete. hg38-coordinate results are in hg19_analysis/liftover_results/"

7 Somatic Variant Calling (in hg19)

This step uses GATK Mutect2 and is now fully corrected and optimized.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
REF_GENOME="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19.fa"
GNOMAD_HG19_CORRECTED="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/reference/gnomad.exomes.r2.0.2.sites.chr.vcf.gz"
BAM_DIR="$BASE_DIR/hg19_analysis/bams_with_rg"
NORMAL_BAM="$BAM_DIR/N1.with_rg.bam"
JAVA_OPTS="-Xmx16g -DGATK_STACKTRACE_ON_USER_EXCEPTION=true"

for TUMOR in T1 X1 XX1; do
  echo "--- Calling somatic variants for $TUMOR vs N1 in hg19 ---"
  
  TUMOR_BAM="$BAM_DIR/${TUMOR}.with_rg.bam"
  RAW_VCF_OUT="$BASE_DIR/hg19_analysis/somatic_variants/${TUMOR}.hg19.raw.vcf.gz"
  FILTERED_VCF_OUT="$BASE_DIR/hg19_analysis/somatic_variants/${TUMOR}.hg19.filtered.vcf.gz"

  gatk --java-options "$JAVA_OPTS" Mutect2 \
    -R "$REF_GENOME" \
    -I "$TUMOR_BAM" \
    -I "$NORMAL_BAM" \
    -tumor "$TUMOR" \
    -normal "N1" \
    --germline-resource "$GNOMAD_HG19_CORRECTED" \
    --native-pair-hmm-threads 8 \
    -O "$RAW_VCF_OUT"

  if [ -f "$RAW_VCF_OUT" ]; then
    echo "Successfully created raw VCF for $TUMOR. Now filtering..."
    gatk --java-options "$JAVA_OPTS" FilterMutectCalls \
      -V "$RAW_VCF_OUT" \
      -R "$REF_GENOME" \
      -O "$FILTERED_VCF_OUT"
  else
    echo "ERROR: Mutect2 failed to create the raw VCF for $TUMOR. Halting."
    exit 1
  fi
done

echo "Somatic variant calling and filtering complete."

8 Annotate Somatic Variants with VEP

This step annotates the filtered VCF files, preparing them for visualization.

#!/bin/bash
# Activate the DEDICATED VEP environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate vep_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
REF_GENOME="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19/hg19.fa"
VEP_SCRIPT_PATH="/home/bioinfo/tools/ensembl-vep/vep"

echo "--- Annotating somatic variants with VEP ---"

for TUMOR in T1 X1 XX1; do
  FILTERED_VCF="$BASE_DIR/hg19_analysis/somatic_variants/${TUMOR}.hg19.filtered.vcf.gz"
  ANNOTATED_VCF="$BASE_DIR/hg19_analysis/somatic_variants/${TUMOR}.hg19.annotated.vcf"

  if [ -f "$ANNOTATED_VCF" ]; then
    echo "Annotated file for $TUMOR already exists, skipping."
    continue
  fi

  # --- CORRECTED COMMAND ---
  perl "$VEP_SCRIPT_PATH" \
    --input_file "$FILTERED_VCF" \
    --output_file "$ANNOTATED_VCF" \
    --format vcf \
    --vcf \
    --symbol \
    --terms SO \
    --tsl \
    --hgvs \
    --fasta "$REF_GENOME" \
    --cache \
    --force_overwrite \
    --fork 8 \
    --offline \
    --assembly GRCh37 # <--- ADDED THESE TWO FLAGS

done

echo "VEP annotation complete."

9 Visualization and Integration

This final section generates the key plots for your analysis.

9.1 CNV Heatmap (from hg38-lifted data)

This heatmap is generated from the hg38 coordinate files for direct comparison with your inferCNV plots.

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

# --- Define Paths ---
BASE_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1"
CNV_DIR="$BASE_DIR/hg19_analysis/cnv_results"
VIS_DIR="$BASE_DIR/hg19_analysis/visualizations"

# Create the visualization directory if it doesn't exist
mkdir -p "$VIS_DIR"

echo "--- Generating CNV heatmap from hg19 .cnr files ---"

# The heatmap command works with .cnr files, not .cns files.
# We will use the original hg19 .cnr files for this gene-centric view.
cnvkit.py heatmap \
  "$CNV_DIR/T1/T1.with_rg.cnr" \
  "$CNV_DIR/X1/X1.with_rg.cnr" \
  "$CNV_DIR/XX1/XX1.with_rg.cnr" \
  -o "$VIS_DIR/WES_CNV_Heatmap_TopGenes_hg19.pdf"

echo "CNV heatmap of top variable genes saved to $VIS_DIR/WES_CNV_Heatmap_TopGenes_hg19.pdf"
# Load necessary libraries
library(dplyr)
library(ggplot2)
library(patchwork) # For combining plots

# --- Define Paths ---
liftover_dir <- "/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19_analysis/liftover_results"
samples <- c("T1", "X1", "XX1")

# --- Read and Combine Data ---
# Create a list to hold the data for each sample
all_cns_data <- list()

for (sample_id in samples) {
  file_path <- file.path(liftover_dir, paste0(sample_id, ".hg38.cns"))
  
  # Read the data and add a column for the sample name
  cns_data <- read.delim(file_path, header = TRUE, sep = "\t") %>%
    mutate(sample = sample_id)
  
  all_cns_data[[sample_id]] <- cns_data
}

# Combine all data frames into one
combined_data <- bind_rows(all_cns_data)

# --- Prepare Chromosome Ordering ---
# Ensure chromosomes are ordered numerically then by letter (chr1, chr2, ..., chrX)
combined_data$chromosome <- factor(combined_data$chromosome, 
                                   levels = paste0("chr", c(1:22, "X", "Y")))

# --- Create the Plot ---
cnv_plot <- ggplot(combined_data, aes(x = start / 1e6, y = log2)) +
  geom_point(aes(color = log2), size = 0.7) +
  # Use facet_grid to create a separate plot for each sample, arranged vertically
  facet_grid(sample ~ chromosome, scales = "free_x", space = "free_x") +
  scale_color_gradient2(low = "blue", mid = "grey", high = "red", midpoint = 0) +
  labs(
    title = "Combined CNV Scatter Plot (hg38 Coordinates)",
    x = "Chromosome",
    y = "Copy Ratio (log2)"
  ) +
  theme_bw() +
  theme(
    axis.text.x = element_blank(), # Hide the x-axis numbers
    axis.ticks.x = element_blank(),
    panel.spacing.x = unit(0.1, "lines"),
    strip.text.x = element_text(angle = 90, size = 8), # Rotate chromosome labels
    legend.position = "bottom"
  )

# Print the plot
print(cnv_plot)

By running these two chunks, you will get both visualizations you need: 1. A PDF heatmap showing the copy number of the most variable genes across your samples. 2. A combined scatter plot showing the complete genome-wide CNV profile for all three samples, perfect for comparing with inferCNV.

9.2 OncoPrint of Somatic Mutations (from hg19 data)

#!/bin/bash
# Activate the conda environment
source /home/bioinfo/miniconda3/etc/profile.d/conda.sh
conda activate wes_env

VCF_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19_analysis/somatic_variants"

echo "--- Checking for 'PASS' variants in annotated VCF files ---"

for TUMOR in T1 X1 XX1; do
  VCF_FILE="$VCF_DIR/${TUMOR}.hg19.annotated.vcf"
  if [ -f "$VCF_FILE" ]; then
    # Use grep to count lines that are not comments and contain 'PASS'
    PASS_COUNT=$(grep -v "^#" "$VCF_FILE" | grep -c "PASS")
    echo "Found $PASS_COUNT 'PASS' variants in $VCF_FILE"
  else
    echo "ERROR: File not found: $VCF_FILE"
  fi
done
#!/bin/bash
# This script performs a step-by-step dissection of the VEP annotation string.

VCF_FILE="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19_analysis/somatic_variants/T1.hg19.annotated.vcf"

echo "--- Final Check: Dissecting the first PASS variant's annotation ---"

# 1. Get the full INFO field from the first PASS variant
INFO_FIELD=$(grep -v "^#" "$VCF_FILE" | grep "PASS" | head -n 1 | awk '{print $8}')

# 2. Isolate the full CSQ string from the INFO field
CSQ_STRING=$(echo "$INFO_FIELD" | grep -o "CSQ=[^;]*" | sed 's/CSQ=//')

echo "------------------------------------------------"
echo "Step 1: Full CSQ string:"
echo "$CSQ_STRING"
echo "------------------------------------------------"

# 3. Isolate the VERY FIRST annotation (everything before the first comma)
FIRST_ANNOTATION=$(echo "$CSQ_STRING" | cut -d ',' -f 1)

echo "Step 2: First annotation block:"
echo "$FIRST_ANNOTATION"
echo "------------------------------------------------"

# 4. Split the first annotation by '|' and extract fields 2 and 4
CONSEQUENCE=$(echo "$FIRST_ANNOTATION" | cut -d '|' -f 2)
GENE_SYMBOL=$(echo "$FIRST_ANNOTATION" | cut -d '|' -f 4)

echo "Step 3: Final Extracted Fields:"
echo "  - Consequence (Field 2): $CONSEQUENCE"
echo "  - Gene Symbol (Field 4): $GENE_SYMBOL"
echo "------------------------------------------------"

if [ -n "$GENE_SYMBOL" ]; then
    echo "Conclusion: Bash check successful. Gene Symbol was found in Field 4."
else
    echo "Conclusion: Bash check FAILED. Gene Symbol was NOT found in Field 4."
fi

This R chunk visualizes the somatic mutation landscape to show clonal relationships.

# Load necessary libraries
library(vcfR)
library(dplyr)
library(stringr)
library(ComplexHeatmap)

# --- Final, Corrected function to parse VEP CSQ field ---
parse_mutect_vcf_final <- function(vcf_file, sample_name) {
  if (!file.exists(vcf_file)) {
    warning(paste("VCF file not found:", vcf_file))
    return(NULL)
  }
  
  vcf <- read.vcfR(vcf_file, verbose = FALSE)
  
  if (!"PASS" %in% getFILTER(vcf)) return(NULL)
  pass_vcf <- vcf[getFILTER(vcf) == "PASS", ]
  if (nrow(pass_vcf) == 0) return(NULL)
  
  csq <- extract.info(pass_vcf, "CSQ")
  
  results <- lapply(csq, function(variant_csq) {
    if (is.na(variant_csq)) return(NULL)
    
    annotations <- strsplit(variant_csq, ",")[[1]]
    
    best_gene <- NA
    best_consequence_type <- "other"
    
    for (a in annotations) {
      fields <- strsplit(a, "\\|")[[1]]
      
      # --- THIS IS THE CRITICAL FIX ---
      # Explicitly get the 4th field for the gene. This will be a single string.
      current_gene <- fields[4]
      current_consequence_str <- fields[2]
      
      current_mut_type <- "other"
      if (grepl("missense_variant", current_consequence_str)) current_mut_type <- "missense"
      if (grepl("frameshift_variant|stop_gained|splice_acceptor|splice_donor", current_consequence_str)) current_mut_type <- "truncating"
      
      # Prioritize finding the most damaging mutation and its associated gene
      if (current_mut_type == "truncating") {
        best_consequence_type <- "truncating"
        best_gene <- current_gene
        break 
      } else if (current_mut_type == "missense" && best_consequence_type != "truncating") {
        best_consequence_type <- "missense"
        best_gene <- current_gene
      } else if (best_consequence_type == "other") {
        best_gene <- current_gene
      }
    }
    
    # The 'if' statement will now work because best_gene is a single value
    if (is.na(best_gene) || best_gene == "") return(NULL)
    
    return(data.frame(gene = best_gene, mut_type = best_consequence_type, sample = sample_name))
  })
  
  df <- do.call(rbind, results)
  return(df)
}

# --- Process each annotated VCF file ---
vcf_dir <- "/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19_analysis/somatic_variants" 
t1_muts <- parse_mutect_vcf_final(file.path(vcf_dir, "T1.hg19.annotated.vcf"), "T1")
x1_muts <- parse_mutect_vcf_final(file.path(vcf_dir, "X1.hg19.annotated.vcf"), "X1")
xx1_muts <- parse_mutect_vcf_final(file.path(vcf_dir, "XX1.hg19.annotated.vcf"), "XX1")

all_muts <- rbind(t1_muts, x1_muts, xx1_muts)

# --- Create the matrix for OncoPrint ---
if (!is.null(all_muts) && nrow(all_muts) > 0) {
  genes <- unique(all_muts$gene)
  samples <- c("T1", "X1", "XX1")
  mat <- matrix("", nrow = length(genes), ncol = length(samples), dimnames = list(genes, samples))

  for (i in 1:nrow(all_muts)) {
    gene_i <- all_muts$gene[i]
    sample_i <- all_muts$sample[i]
    mut_type_i <- all_muts$mut_type[i]
    current_val <- mat[gene_i, sample_i]
    if (current_val == "" || (current_val == "other" && mut_type_i != "other") || (current_val == "missense" && mut_type_i == "truncating")) {
      mat[gene_i, sample_i] <- mut_type_i
    }
  }

  num_mutated_across_samples <- rowSums(mat != "")
  num_to_plot <- min(30, sum(num_mutated_across_samples > 0))
  top_genes <- names(sort(num_mutated_across_samples, decreasing = TRUE)[1:num_to_plot])
  mat_filtered <- mat[top_genes, , drop = FALSE]

  col <- c("truncating" = "#922B21", "missense" = "#2471A3", "other" = "#D5D8DC")
  alter_fun <- list(
      background = function(x, y, w, h) grid.rect(x, y, w-unit(2,"pt"), h-unit(2,"pt"), gp=gpar(fill="#f0f0f0", col=NA)),
      truncating = function(x, y, w, h) grid.rect(x, y, w-unit(2,"pt"), h-unit(2,"pt"), gp=gpar(fill=col["truncating"], col=NA)),
      missense = function(x, y, w, h) grid.rect(x, y, w-unit(2,"pt"), h*0.5, gp=gpar(fill=col["missense"], col=NA)),
      other = function(x, y, w, h) grid.rect(x, y, w-unit(2,"pt"), h*0.2, gp=gpar(fill=col["other"], col=NA))
  )

  oncoPrint(mat_filtered,
            alter_fun = alter_fun, 
            col = col,
            row_order = rownames(mat_filtered),
            column_title = "Somatic Mutation Landscape (Top Genes)",
            heatmap_legend_param = list(title = "Alterations", at = c("truncating", "missense", "other")))
            
} else {
  print("No mutations found to plot. This indicates a persistent issue with VCF parsing.")
}

#!/bin/bash
# Corrected VCF directory path
VCF_DIR="/home/bioinfo/1-Thesis_Final_Year_2025/2025-Year3_Analysis/1-scRNA_RESULTS-19-11-2025/15-WES_Patient1_L1_L2_Analysis-19-11-2025/Exome_Patient_1/hg19_analysis/somatic_variants"

echo "--- Searching for TP53 mutations in all samples (Corrected Path) ---"

for TUMOR in T1 X1 XX1; do
  VCF_FILE="$VCF_DIR/${TUMOR}.hg19.annotated.vcf"
  echo "--- Checking $TUMOR ---"
  
  if [ ! -f "$VCF_FILE" ]; then
      echo "ERROR: VCF file not found at $VCF_FILE"
      continue
  fi
  
  # Search for lines that are not comments, passed filters, and contain the gene symbol TP53
  # The CSQ field is what we need to search in.
  grep -v "^#" "$VCF_FILE" | grep "PASS" | grep "CSQ=" | grep -o 'SYMBOL=[^|;]*' | grep "TP53" || echo "No PASSing TP53 mutation found in $TUMOR."
  echo ""
done
LS0tCnRpdGxlOiAiV0VTIEFuYWx5c2lzIGZvciBQYXRpZW50IDEgKGhnMTkgd2l0aCBMaWZ0T3ZlcikiCmF1dGhvcjogIk5hc2lyIE1haG1vb2QgQWJiYXNpIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAotLS0KCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IHByb3ZpZGVzIHRoZSBkZWZpbml0aXZlIGVuZC10by1lbmQgYmlvaW5mb3JtYXRpY3MgcGlwZWxpbmUgdG8gYW5hbHl6ZSB0aGUgV2hvbGUgRXhvbWUgU2VxdWVuY2luZyAoV0VTKSBkYXRhIGZvciBQYXRpZW50IDEgYW5kIGl0cyBkZXJpdmVkIGNlbGwgbGluZXMuCgoqKktleSBGaW5kaW5ncyAmIFN0cmF0ZWd5OioqCjEuICBUaGUgb3JpZ2luYWwgV0VTIEJBTSBmaWxlcyBhcmUgbWlzc2luZyBjcml0aWNhbCBgQFJHYCAoUmVhZCBHcm91cCkgc2FtcGxlIG5hbWUgaW5mb3JtYXRpb24sIGFuZCB0aGUgZ25vbUFEIHJlZmVyZW5jZSBmaWxlIGhhcyBhbiBpbmNvbXBhdGlibGUgY2hyb21vc29tZSBuYW1pbmcgc2NoZW1lLgoyLiAgVGhlIHNjUk5BLXNlcSBkYXRhIHdhcyBwcm9jZXNzZWQgb24gYGhnMzhgLCB3aGlsZSB0aGUgV0VTIGRhdGEgaXMgb24gYGhnMTlgLgozLiAgVGhlcmVmb3JlLCB0aGUgY29ycmVjdCBzdHJhdGVneSBpczoKICAgIGEuIEZpcnN0LCBjcmVhdGUgbmV3LCBjb3JyZWN0ZWQgQkFNIGZpbGVzIHdpdGggdGhlIHByb3BlciBgQFJHYCBoZWFkZXJzLgogICAgYi4gU2Vjb25kLCBjcmVhdGUgYSBuZXcsIGNvcnJlY3RlZCBnbm9tQUQgZmlsZSB3aXRoIHRoZSBwcm9wZXIgY2hyb21vc29tZSBuYW1lcyBhbmQgaW5kZXguCiAgICBjLiBQZXJmb3JtIGFsbCBXRVMgYW5hbHlzZXMgaW4gYGhnMTlgIHVzaW5nIHRoZXNlIG5ldywgY29ycmVjdGVkIGZpbGVzLgogICAgZC4gVXNlIGBsaWZ0T3ZlcmAgdG8gY29udmVydCB0aGUgZmluYWwgQ05WIHJlc3VsdHMgdG8gYGhnMzhgIGZvciBkaXJlY3QgY29tcGFyaXNvbi4KCioqU2FtcGxlIEluZm9ybWF0aW9uOioqCiogICAqKk4xOioqIE5vcm1hbCAoQ29uc3RpdHV0aW9uYWwgRE5BKQoqICAgKipUMToqKiBQcmltYXJ5IFR1bW9yIChGcmVzaCBTw6l6YXJ5IENlbGxzKQoqICAgKipYMToqKiBJbi12aXZvIGRlcml2ZWQgQ2VsbCBMaW5lIChmcm9tIE1vdXNlKQoqICAgKipYWDE6KiogU2Vjb25kYXJ5IENlbGwgTGluZSAoY3VsdHVyZWQgZnJvbSBYMSkKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIFNldCBkZWZhdWx0IG9wdGlvbnMgZm9yIGNvZGUgY2h1bmtzCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICBldmFsID0gRkFMU0UsICMgSU1QT1JUQU5UOiBTZXQgdG8gRkFMU0UgdG8gcHJldmVudCBhY2NpZGVudGFsIGV4ZWN1dGlvbi4KICBlbmdpbmUgPSAiYmFzaCIKKQpgYGAKCiMgU2V0dXAgYW5kIENvbmZpZ3VyYXRpb24KClRoaXMgY2h1bmsgZGVmaW5lcyBhbGwgbmVjZXNzYXJ5IHBhdGhzIGFuZCBnbG9iYWwgdmFyaWFibGVzIGZvciB0aGUgZW50aXJlIHBpcGVsaW5lLgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImNvbmZpZ3VyYXRpb24ifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBjb25kYSBlbnZpcm9ubWVudCB0byBtYWtlIGl0cyB0b29scyBhdmFpbGFibGUKc291cmNlIC9ob21lL2Jpb2luZm8vbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCmNvbmRhIGFjdGl2YXRlIHdlc19lbnYKCiMgLS0tIERFRklORSBHTE9CQUwgVkFSSUFCTEVTIC0tLQpCQVNFX0RJUj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEiClJFRl9HRU5PTUU9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTkvaGcxOS5mYSIKSU5URVJWQUxfTElTVD0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvcmVmZXJlbmNlL1BKMTYxMDI0MF9jb3ZlcmVkLmJlZCIKTElGVE9WRVJfQ0hBSU49Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTkvaGcxOVRvSGczOC5vdmVyLmNoYWluLmd6IgpWRVBfUEFUSD0iL2hvbWUvYmlvaW5mby90b29scy9lbnNlbWJsLXZlcC92ZXAiCkpBVkFfT1BUUz0iLVhteDE2ZyAtREdBVEtfU1RBQ0tUUkFDRV9PTl9VU0VSX0VYQ0VQVElPTj10cnVlIgoKIyAtLS0gVGhpcyBpcyB0aGUgcGF0aCB0byB0aGUgZ25vbUFEIGZpbGUgd2Ugd2lsbCBDUkVBVEUgaW4gdGhlIHByZXBhcmVfZ25vbWFkIHN0ZXAgLS0tCkdOT01BRF9IRzE5X0NPUlJFQ1RFRD0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvcmVmZXJlbmNlL2dub21hZC5leG9tZXMucjIuMC4yLnNpdGVzLmNoci52Y2YuZ3oiCgojIC0tLSBPVVRQVVQgRElSRUNUT1JJRVMgLS0tCm1rZGlyIC1wICRCQVNFX0RJUi9oZzE5X2FuYWx5c2lzL2JhbXNfd2l0aF9yZwpta2RpciAtcCAkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9jbnZfcmVzdWx0cwpta2RpciAtcCAkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9zb21hdGljX3ZhcmlhbnRzCm1rZGlyIC1wICRCQVNFX0RJUi9oZzE5X2FuYWx5c2lzL2xpZnRvdmVyX3Jlc3VsdHMKbWtkaXIgLXAgJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvdmlzdWFsaXphdGlvbnMKCmVjaG8gIkNvbmZpZ3VyYXRpb24gbG9hZGVkIGFuZCBvdXRwdXQgZGlyZWN0b3JpZXMgY3JlYXRlZC4iCmBgYAoKIyBQcmVwYXJlIEJBTSBGaWxlcyBieSBBZGRpbmcgUmVhZCBHcm91cHMKClRoaXMgc3RlcCBmaXhlcyB0aGUgbWlzc2luZyBgQFJHYCAoUmVhZCBHcm91cCkgaGVhZGVycyBpbiB0aGUgb3JpZ2luYWwgQkFNIGZpbGVzLiBUaGlzIGlzIGEgb25lLXRpbWUgb3BlcmF0aW9uIHRoYXQgY3JlYXRlcyBuZXcsIGFuYWx5c2lzLXJlYWR5IEJBTXMuCgpgYGB7YmFzaCwgY2h1bmtfbmFtZT0icHJlcGFyZV9iYW1zIn0KIyEvYmluL2Jhc2gKIyBBY3RpdmF0ZSB0aGUgY29uZGEgZW52aXJvbm1lbnQKc291cmNlIC9ob21lL2Jpb2luZm8vbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCmNvbmRhIGFjdGl2YXRlIHdlc19lbnYKCiMgLS0tIERlZmluZSBQYXRocyAtLS0KQkFTRV9ESVI9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xIgpPVVRQVVRfQkFNX0RJUj0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvYmFtc193aXRoX3JnIgoKIyAtLS0gTG9vcCB0aHJvdWdoIGVhY2ggc2FtcGxlIHRvIGFkZCBSZWFkIEdyb3VwcyAtLS0KZm9yIFNBTVBMRV9JRCBpbiBOMSBUMSBYMSBYWDE7IGRvCiAgSU5QVVRfQkFNPSIkQkFTRV9ESVIvJFNBTVBMRV9JRC9zb3J0ZWQuYmFtIgogIE9VVFBVVF9CQU09IiRPVVRQVVRfQkFNX0RJUi8ke1NBTVBMRV9JRH0ud2l0aF9yZy5iYW0iCgogIGlmIFsgLWYgIiRPVVRQVVRfQkFNIiBdOyB0aGVuCiAgICBlY2hvICJDb3JyZWN0ZWQgQkFNIGZvciAkU0FNUExFX0lEIGFscmVhZHkgZXhpc3RzLiBTa2lwcGluZy4iCiAgICBjb250aW51ZQogIGZpCgogIGVjaG8gIi0tLSBBZGRpbmcgUmVhZCBHcm91cCB0byAkU0FNUExFX0lEIC0tLSIKcGljYXJkIEFkZE9yUmVwbGFjZVJlYWRHcm91cHMgXAogIEk9IiRJTlBVVF9CQU0iIFwKICBPPSIkT1VUUFVUX0JBTSIgXAogIFJHSUQ9IiRTQU1QTEVfSUQiIFwKICBSR0xCPSJsaWIxIiBcCiAgUkdQTD0iaWxsdW1pbmEiIFwKICBSR1BVPSJ1bml0MSIgXAogIFJHU009IiRTQU1QTEVfSUQiIFwKICBWQUxJREFUSU9OX1NUUklOR0VOQ1k9TEVOSUVOVCAgIyA8LS0tIFRIRSBDUklUSUNBTCBGSVgKICAgIAogIHNhbXRvb2xzIGluZGV4ICIkT1VUUFVUX0JBTSIKZG9uZQoKZWNobyAiQkFNIGZpbGUgcHJlcGFyYXRpb24gY29tcGxldGUuIE5ldyBmaWxlcyBhcmUgaW4gJE9VVFBVVF9CQU1fRElSIgpgYGAKCgoKVGhpcyBzdGVwIGNvcnJlY3RzIHRoZSBjaHJvbW9zb21lIG5hbWluZyBzY2hlbWUgaW4gdGhlIGdub21BRCBWQ0YgZmlsZSB0byBiZSBjb21wYXRpYmxlIHdpdGggR0FUSy4KCgpUaGlzIHN0ZXAgZW5zdXJlcyB0aGF0IGFsbCB0aGUgbmV3bHkgY3JlYXRlZCBCQU0gZmlsZXMgaGF2ZSBhIGNvcnJlc3BvbmRpbmcgYC5iYWlgIGluZGV4LCB3aGljaCBpcyBhIHN0cmljdCByZXF1aXJlbWVudCBmb3IgR0FUSy4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJpbmRleF9iYW1zIn0KIyEvYmluL2Jhc2gKIyBBY3RpdmF0ZSB0aGUgY29uZGEgZW52aXJvbm1lbnQKc291cmNlIC9ob21lL2Jpb2luZm8vbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCmNvbmRhIGFjdGl2YXRlIHdlc19lbnYKCiMgLS0tIERlZmluZSBQYXRocyAtLS0KQkFTRV9ESVI9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xIgpCQU1fRElSPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9iYW1zX3dpdGhfcmciCgojIC0tLSBMb29wIHRocm91Z2ggZWFjaCBjb3JyZWN0ZWQgQkFNIHRvIGNyZWF0ZSB0aGUgaW5kZXggLS0tCmZvciBTQU1QTEVfSUQgaW4gTjEgVDEgWDEgWFgxOyBkbwogIEJBTV9GSUxFPSIkQkFNX0RJUi8ke1NBTVBMRV9JRH0ud2l0aF9yZy5iYW0iCiAgCiAgIyBDaGVjayBpZiB0aGUgaW5kZXggYWxyZWFkeSBleGlzdHMKICBpZiBbIC1mICIke0JBTV9GSUxFfS5iYWkiIF07IHRoZW4KICAgIGVjaG8gIkluZGV4IGZvciAkU0FNUExFX0lEIGFscmVhZHkgZXhpc3RzLiBTa2lwcGluZy4iCiAgZWxzZQogICAgZWNobyAiLS0tIEluZGV4aW5nIGNvcnJlY3RlZCBCQU0gZm9yICRTQU1QTEVfSUQgLS0tIgogICAgc2FtdG9vbHMgaW5kZXggIiRCQU1fRklMRSIKICBmaQpkb25lCgplY2hvICJCQU0gZmlsZSBpbmRleGluZyBjb21wbGV0ZS4iCgpgYGAKCgojIFByZXBhcmUgZ25vbUFEIFJlZmVyZW5jZSBGaWxlCgpUaGlzIG9uZS10aW1lIHN0ZXAgZW5zdXJlcyB0aGUgZ25vbUFEIFZDRiB1c2VzIHRoZSBgY2hyYCBwcmVmaXggYW5kIGhhcyB0aGUgY29ycmVjdCBgLnRiaWAgaW5kZXggZm9yIEdBVEsuCgpgYGB7YmFzaCwgY2h1bmtfbmFtZT0icHJlcGFyZV9nbm9tYWQifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBjb25kYSBlbnZpcm9ubWVudApzb3VyY2UgL2hvbWUvYmlvaW5mby9taW5pY29uZGEzL2V0Yy9wcm9maWxlLmQvY29uZGEuc2gKY29uZGEgYWN0aXZhdGUgd2VzX2VudgoKIyAtLS0gRGVmaW5lIFBhdGhzIC0tLQpSRUZFUkVOQ0VfRElSPSIvaG9tZS9iaW9pbmZvLzEtVGhlc2lzX0ZpbmFsX1llYXJfMjAyNS8yMDI1LVllYXIzX0FuYWx5c2lzLzEtc2NSTkFfUkVTVUxUUy0xOS0xMS0yMDI1LzE1LVdFU19QYXRpZW50MV9MMV9MMl9BbmFseXNpcy0xOS0xMS0yMDI1L0V4b21lX1BhdGllbnRfMS9yZWZlcmVuY2UiCk9MRF9HTk9NQUQ9IiRSRUZFUkVOQ0VfRElSL2dub21hZC5leG9tZXMucjIuMC4yLnNpdGVzLnZjZi5neiIKTkVXX0dOT01BRD0iJFJFRkVSRU5DRV9ESVIvZ25vbWFkLmV4b21lcy5yMi4wLjIuc2l0ZXMuY2hyLnZjZi5neiIKTUFQX0ZJTEU9IiRSRUZFUkVOQ0VfRElSL2Nocl9uYW1lX21hcC50eHQiCgppZiBbIC1mICIkTkVXX0dOT01BRCIgXSAmJiBbIC1mICIke05FV19HTk9NQUR9LnRiaSIgXTsgdGhlbgogIGVjaG8gIkNvcnJlY3RlZCBnbm9tQUQgZmlsZSBhbmQgaXRzIC50YmkgaW5kZXggYWxyZWFkeSBleGlzdC4gU2tpcHBpbmcgcHJlcGFyYXRpb24uIgplbHNlCiAgZWNobyAiQ29ycmVjdGVkIGdub21BRCBmaWxlIG9yIGl0cyBpbmRleCBub3QgZm91bmQuIFN0YXJ0aW5nIHByZXBhcmF0aW9uLi4uIgoKICBpZiBbICEgLWYgIiRNQVBfRklMRSIgXTsgdGhlbgogICAgZWNobyAiQ3JlYXRpbmcgY2hyb21vc29tZSBuYW1lIG1hcCBmaWxlOiAkTUFQX0ZJTEUiCiAgICBmb3IgaSBpbiB7MS4uMjJ9IFggWSBNOyBkbyBlY2hvICIkaSBjaHIkaSI7IGRvbmUgPiAiJE1BUF9GSUxFIgogIGZpCgogIGVjaG8gIlN0YXJ0aW5nIGJjZnRvb2xzIGFubm90YXRpb24uLi4gdGhpcyB3aWxsIHRha2Ugc2V2ZXJhbCBtaW51dGVzLiIKICBiY2Z0b29scyBhbm5vdGF0ZSAtLXJlbmFtZS1jaHJzICIkTUFQX0ZJTEUiIC0tdGhyZWFkcyA4IC1vICIkTkVXX0dOT01BRCIgLU8geiAiJE9MRF9HTk9NQUQiCgogIGVjaG8gIkFubm90YXRpb24gY29tcGxldGUuIE5vdyBjcmVhdGluZyBhIFRhYml4ICgudGJpKSBpbmRleC4uLiIKICBiY2Z0b29scyBpbmRleCAtdCAiJE5FV19HTk9NQUQiCgogIGVjaG8gIlByZXBhcmF0aW9uIGNvbXBsZXRlLiBUaGUgbmV3IGZpbGUgJyRORVdfR05PTUFEJyBhbmQgaXRzIC50YmkgaW5kZXggYXJlIHJlYWR5LiIKZmkKYGBgCgoKIyBTb21hdGljIENOViBBbmFseXNpcyAoaW4gaGcxOSkKClRoaXMgc3RlcCB1c2VzIGBDTlZraXRgIG9uIHRoZSAqKm5ld2x5IGNyZWF0ZWQgQkFNIGZpbGVzKiogd2l0aCBjb3JyZWN0IGhlYWRlcnMuCgpgYGB7YmFzaCwgY2h1bmtfbmFtZT0iY252a2l0X2hnMTkifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBjb25kYSBlbnZpcm9ubWVudApzb3VyY2UgL2hvbWUvYmlvaW5mby9taW5pY29uZGEzL2V0Yy9wcm9maWxlLmQvY29uZGEuc2gKY29uZGEgYWN0aXZhdGUgd2VzX2VudgoKIyAtLS0gRGVmaW5lIFBhdGhzIC0tLQpCQVNFX0RJUj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEiClJFRl9HRU5PTUU9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTkvaGcxOS5mYSIKSU5URVJWQUxfTElTVD0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvcmVmZXJlbmNlL1BKMTYxMDI0MF9jb3ZlcmVkLmJlZCIKQkFNX0RJUj0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvYmFtc193aXRoX3JnIgpOT1JNQUxfQkFNPSIkQkFNX0RJUi9OMS53aXRoX3JnLmJhbSIKUkVGRVJFTkNFX0NOTj0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvY252X3Jlc3VsdHMvcmVmZXJlbmNlLmNubiIKCmVjaG8gIkJ1aWxkaW5nIHJlZmVyZW5jZSBmcm9tIE4xICh1c2luZyBjb3JyZWN0ZWQgQkFNKS4uLiIKY252a2l0LnB5IGJhdGNoICIkTk9STUFMX0JBTSIgXAogIC0tbm9ybWFsIFwKICAtLXRhcmdldHMgIiRJTlRFUlZBTF9MSVNUIiBcCiAgLS1mYXN0YSAiJFJFRl9HRU5PTUUiIFwKICAtLW91dHB1dC1yZWZlcmVuY2UgIiRSRUZFUkVOQ0VfQ05OIiBcCiAgLS1vdXRwdXQtZGlyICIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9jbnZfcmVzdWx0cy9OMSIgXAogIC1wIDggICMgPC0tLSBDT1JSRUNURUQKCmZvciBTQU1QTEUgaW4gVDEgWDEgWFgxOyBkbwogIGVjaG8gIi0tLSBDYWxsaW5nIENOVnMgZm9yICRTQU1QTEUgaW4gaGcxOSAodXNpbmcgY29ycmVjdGVkIEJBTSkgLS0tIgogIFNBTVBMRV9CQU09IiRCQU1fRElSLyR7U0FNUExFfS53aXRoX3JnLmJhbSIKICAKICBjbnZraXQucHkgYmF0Y2ggIiRTQU1QTEVfQkFNIiBcCiAgICAtLXJlZmVyZW5jZSAiJFJFRkVSRU5DRV9DTk4iIFwKICAgIC0tb3V0cHV0LWRpciAiJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvY252X3Jlc3VsdHMvJFNBTVBMRSIgXAogICAgLXAgOCAgIyA8LS0tIENPUlJFQ1RFRApkb25lCgplY2hvICJoZzE5IENOVmtpdCBhbmFseXNpcyBjb21wbGV0ZS4iCmBgYAoKIyBMaWZ0T3ZlciBDTlYgUmVzdWx0cyB0byBoZzM4CgpUaGlzIHN0ZXAgY29udmVydHMgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBmaW5hbCBgLmNuc2Agc2VnbWVudCBmaWxlcyBmcm9tIGBoZzE5YCB0byBgaGczOGAgdXNpbmcgdGhlIHJvYnVzdCBgbGlmdE92ZXJgIHRvb2wuCgpgYGB7YmFzaCwgY2h1bmtfbmFtZT0ibGlmdG92ZXJfY252In0KIyEvYmluL2Jhc2gKIyBBY3RpdmF0ZSB0aGUgY29uZGEgZW52aXJvbm1lbnQKc291cmNlIC9ob21lL2Jpb2luZm8vbWluaWNvbmRhMy9ldGMvcHJvZmlsZS5kL2NvbmRhLnNoCmNvbmRhIGFjdGl2YXRlIHdlc19lbnYKCiMgLS0tIERlZmluZSBQYXRocyAtLS0KQkFTRV9ESVI9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xIgpMSUZUT1ZFUl9DSEFJTj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvaGcxOS9oZzE5VG9IZzM4Lm92ZXIuY2hhaW4uZ3oiCgplY2hvICItLS0gTGlmdGluZyBvdmVyIENOViBzZWdtZW50cyBmcm9tIGhnMTkgdG8gaGczOCB1c2luZyBsaWZ0T3ZlciAtLS0iCgpmb3IgU0FNUExFIGluIFQxIFgxIFhYMTsgZG8KICAjIC0tLSBDT1JSRUNURUQgRklMRU5BTUUgLS0tCiAgIyBDTlZraXQgbmFtZXMgdGhlIG91dHB1dCBmaWxlIGJhc2VkIG9uIHRoZSBpbnB1dCBCQU0ncyBiYXNlbmFtZSwgd2hpY2ggd2FzICJTQU1QTEUud2l0aF9yZyIKICBDTlNfSEcxOT0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvY252X3Jlc3VsdHMvJFNBTVBMRS8ke1NBTVBMRX0ud2l0aF9yZy5jbnMiCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogIENOU19IRzM4PSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9saWZ0b3Zlcl9yZXN1bHRzLyR7U0FNUExFfS5oZzM4LmNucyIKICBVTk1BUFBFRF9GSUxFPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9saWZ0b3Zlcl9yZXN1bHRzLyR7U0FNUExFfS51bm1hcHBlZC50eHQiCiAgCiAgaWYgWyAtZiAiJENOU19IRzM4IiBdOyB0aGVuCiAgICBlY2hvICJMaWZ0ZWQgZmlsZSBmb3IgJFNBTVBMRSBhbHJlYWR5IGV4aXN0cywgc2tpcHBpbmcuIgogICAgY29udGludWUKICBmaQogIAogICMgQ2hlY2sgaWYgdGhlIGlucHV0IGZpbGUgZXhpc3RzIGJlZm9yZSB0cnlpbmcgdG8gbGlmdCBpdCBvdmVyCiAgaWYgWyAhIC1mICIkQ05TX0hHMTkiIF07IHRoZW4KICAgIGVjaG8gIkVSUk9SOiBJbnB1dCBmaWxlICRDTlNfSEcxOSBub3QgZm91bmQuIENhbm5vdCBwZXJmb3JtIGxpZnRvdmVyLiIKICAgIGNvbnRpbnVlICMgU2tpcCB0byB0aGUgbmV4dCBzYW1wbGUKICBmaQoKICBlY2hvICJMaWZ0aW5nIG92ZXIgJENOU19IRzE5IC0+ICRDTlNfSEczOCIKICB0YWlsIC1uICsyICIkQ05TX0hHMTkiIHwgbGlmdE92ZXIgLWJlZFBsdXM9NCBzdGRpbiAiJExJRlRPVkVSX0NIQUlOIiAiJENOU19IRzM4IiAiJFVOTUFQUEVEX0ZJTEUiCmRvbmUKCmVjaG8gIkxpZnRPdmVyIGNvbXBsZXRlLiBoZzM4LWNvb3JkaW5hdGUgcmVzdWx0cyBhcmUgaW4gaGcxOV9hbmFseXNpcy9saWZ0b3Zlcl9yZXN1bHRzLyIKYGBgCgojIFNvbWF0aWMgVmFyaWFudCBDYWxsaW5nIChpbiBoZzE5KQoKVGhpcyBzdGVwIHVzZXMgYEdBVEsgTXV0ZWN0MmAgYW5kIGlzIG5vdyBmdWxseSBjb3JyZWN0ZWQgYW5kIG9wdGltaXplZC4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJtdXRlY3QyX2hnMTkifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBjb25kYSBlbnZpcm9ubWVudApzb3VyY2UgL2hvbWUvYmlvaW5mby9taW5pY29uZGEzL2V0Yy9wcm9maWxlLmQvY29uZGEuc2gKY29uZGEgYWN0aXZhdGUgd2VzX2VudgoKIyAtLS0gRGVmaW5lIFBhdGhzIC0tLQpCQVNFX0RJUj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEiClJFRl9HRU5PTUU9Ii9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTkvaGcxOS5mYSIKR05PTUFEX0hHMTlfQ09SUkVDVEVEPSIvaG9tZS9iaW9pbmZvLzEtVGhlc2lzX0ZpbmFsX1llYXJfMjAyNS8yMDI1LVllYXIzX0FuYWx5c2lzLzEtc2NSTkFfUkVTVUxUUy0xOS0xMS0yMDI1LzE1LVdFU19QYXRpZW50MV9MMV9MMl9BbmFseXNpcy0xOS0xMS0yMDI1L0V4b21lX1BhdGllbnRfMS9yZWZlcmVuY2UvZ25vbWFkLmV4b21lcy5yMi4wLjIuc2l0ZXMuY2hyLnZjZi5neiIKQkFNX0RJUj0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvYmFtc193aXRoX3JnIgpOT1JNQUxfQkFNPSIkQkFNX0RJUi9OMS53aXRoX3JnLmJhbSIKSkFWQV9PUFRTPSItWG14MTZnIC1ER0FUS19TVEFDS1RSQUNFX09OX1VTRVJfRVhDRVBUSU9OPXRydWUiCgpmb3IgVFVNT1IgaW4gVDEgWDEgWFgxOyBkbwogIGVjaG8gIi0tLSBDYWxsaW5nIHNvbWF0aWMgdmFyaWFudHMgZm9yICRUVU1PUiB2cyBOMSBpbiBoZzE5IC0tLSIKICAKICBUVU1PUl9CQU09IiRCQU1fRElSLyR7VFVNT1J9LndpdGhfcmcuYmFtIgogIFJBV19WQ0ZfT1VUPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9zb21hdGljX3ZhcmlhbnRzLyR7VFVNT1J9LmhnMTkucmF3LnZjZi5neiIKICBGSUxURVJFRF9WQ0ZfT1VUPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9zb21hdGljX3ZhcmlhbnRzLyR7VFVNT1J9LmhnMTkuZmlsdGVyZWQudmNmLmd6IgoKICBnYXRrIC0tamF2YS1vcHRpb25zICIkSkFWQV9PUFRTIiBNdXRlY3QyIFwKICAgIC1SICIkUkVGX0dFTk9NRSIgXAogICAgLUkgIiRUVU1PUl9CQU0iIFwKICAgIC1JICIkTk9STUFMX0JBTSIgXAogICAgLXR1bW9yICIkVFVNT1IiIFwKICAgIC1ub3JtYWwgIk4xIiBcCiAgICAtLWdlcm1saW5lLXJlc291cmNlICIkR05PTUFEX0hHMTlfQ09SUkVDVEVEIiBcCiAgICAtLW5hdGl2ZS1wYWlyLWhtbS10aHJlYWRzIDggXAogICAgLU8gIiRSQVdfVkNGX09VVCIKCiAgaWYgWyAtZiAiJFJBV19WQ0ZfT1VUIiBdOyB0aGVuCiAgICBlY2hvICJTdWNjZXNzZnVsbHkgY3JlYXRlZCByYXcgVkNGIGZvciAkVFVNT1IuIE5vdyBmaWx0ZXJpbmcuLi4iCiAgICBnYXRrIC0tamF2YS1vcHRpb25zICIkSkFWQV9PUFRTIiBGaWx0ZXJNdXRlY3RDYWxscyBcCiAgICAgIC1WICIkUkFXX1ZDRl9PVVQiIFwKICAgICAgLVIgIiRSRUZfR0VOT01FIiBcCiAgICAgIC1PICIkRklMVEVSRURfVkNGX09VVCIKICBlbHNlCiAgICBlY2hvICJFUlJPUjogTXV0ZWN0MiBmYWlsZWQgdG8gY3JlYXRlIHRoZSByYXcgVkNGIGZvciAkVFVNT1IuIEhhbHRpbmcuIgogICAgZXhpdCAxCiAgZmkKZG9uZQoKZWNobyAiU29tYXRpYyB2YXJpYW50IGNhbGxpbmcgYW5kIGZpbHRlcmluZyBjb21wbGV0ZS4iCmBgYAoKIyBBbm5vdGF0ZSBTb21hdGljIFZhcmlhbnRzIHdpdGggVkVQCgpUaGlzIHN0ZXAgYW5ub3RhdGVzIHRoZSBmaWx0ZXJlZCBWQ0YgZmlsZXMsIHByZXBhcmluZyB0aGVtIGZvciB2aXN1YWxpemF0aW9uLgoKYGBge2Jhc2gsIGNodW5rX25hbWU9InZlcF9hbm5vdGF0aW9uX2hnMTkifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBERURJQ0FURUQgVkVQIGVudmlyb25tZW50CnNvdXJjZSAvaG9tZS9iaW9pbmZvL21pbmljb25kYTMvZXRjL3Byb2ZpbGUuZC9jb25kYS5zaApjb25kYSBhY3RpdmF0ZSB2ZXBfZW52CgojIC0tLSBEZWZpbmUgUGF0aHMgLS0tCkJBU0VfRElSPSIvaG9tZS9iaW9pbmZvLzEtVGhlc2lzX0ZpbmFsX1llYXJfMjAyNS8yMDI1LVllYXIzX0FuYWx5c2lzLzEtc2NSTkFfUkVTVUxUUy0xOS0xMS0yMDI1LzE1LVdFU19QYXRpZW50MV9MMV9MMl9BbmFseXNpcy0xOS0xMS0yMDI1L0V4b21lX1BhdGllbnRfMSIKUkVGX0dFTk9NRT0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvaGcxOS9oZzE5LmZhIgpWRVBfU0NSSVBUX1BBVEg9Ii9ob21lL2Jpb2luZm8vdG9vbHMvZW5zZW1ibC12ZXAvdmVwIgoKZWNobyAiLS0tIEFubm90YXRpbmcgc29tYXRpYyB2YXJpYW50cyB3aXRoIFZFUCAtLS0iCgpmb3IgVFVNT1IgaW4gVDEgWDEgWFgxOyBkbwogIEZJTFRFUkVEX1ZDRj0iJEJBU0VfRElSL2hnMTlfYW5hbHlzaXMvc29tYXRpY192YXJpYW50cy8ke1RVTU9SfS5oZzE5LmZpbHRlcmVkLnZjZi5neiIKICBBTk5PVEFURURfVkNGPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy9zb21hdGljX3ZhcmlhbnRzLyR7VFVNT1J9LmhnMTkuYW5ub3RhdGVkLnZjZiIKCiAgaWYgWyAtZiAiJEFOTk9UQVRFRF9WQ0YiIF07IHRoZW4KICAgIGVjaG8gIkFubm90YXRlZCBmaWxlIGZvciAkVFVNT1IgYWxyZWFkeSBleGlzdHMsIHNraXBwaW5nLiIKICAgIGNvbnRpbnVlCiAgZmkKCiAgIyAtLS0gQ09SUkVDVEVEIENPTU1BTkQgLS0tCiAgcGVybCAiJFZFUF9TQ1JJUFRfUEFUSCIgXAogICAgLS1pbnB1dF9maWxlICIkRklMVEVSRURfVkNGIiBcCiAgICAtLW91dHB1dF9maWxlICIkQU5OT1RBVEVEX1ZDRiIgXAogICAgLS1mb3JtYXQgdmNmIFwKICAgIC0tdmNmIFwKICAgIC0tc3ltYm9sIFwKICAgIC0tdGVybXMgU08gXAogICAgLS10c2wgXAogICAgLS1oZ3ZzIFwKICAgIC0tZmFzdGEgIiRSRUZfR0VOT01FIiBcCiAgICAtLWNhY2hlIFwKICAgIC0tZm9yY2Vfb3ZlcndyaXRlIFwKICAgIC0tZm9yayA4IFwKICAgIC0tb2ZmbGluZSBcCiAgICAtLWFzc2VtYmx5IEdSQ2gzNyAjIDwtLS0gQURERUQgVEhFU0UgVFdPIEZMQUdTCgpkb25lCgplY2hvICJWRVAgYW5ub3RhdGlvbiBjb21wbGV0ZS4iCmBgYAoKIyBWaXN1YWxpemF0aW9uIGFuZCBJbnRlZ3JhdGlvbgoKVGhpcyBmaW5hbCBzZWN0aW9uIGdlbmVyYXRlcyB0aGUga2V5IHBsb3RzIGZvciB5b3VyIGFuYWx5c2lzLgoKIyMgQ05WIEhlYXRtYXAgKGZyb20gaGczOC1saWZ0ZWQgZGF0YSkKClRoaXMgaGVhdG1hcCBpcyBnZW5lcmF0ZWQgZnJvbSB0aGUgYGhnMzhgIGNvb3JkaW5hdGUgZmlsZXMgZm9yIGRpcmVjdCBjb21wYXJpc29uIHdpdGggeW91ciBgaW5mZXJDTlZgIHBsb3RzLgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImNudl9oZWF0bWFwX2hnMzgifQojIS9iaW4vYmFzaAojIEFjdGl2YXRlIHRoZSBjb25kYSBlbnZpcm9ubWVudApzb3VyY2UgL2hvbWUvYmlvaW5mby9taW5pY29uZGEzL2V0Yy9wcm9maWxlLmQvY29uZGEuc2gKY29uZGEgYWN0aXZhdGUgd2VzX2VudgoKIyAtLS0gRGVmaW5lIFBhdGhzIC0tLQpCQVNFX0RJUj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEiCkNOVl9ESVI9IiRCQVNFX0RJUi9oZzE5X2FuYWx5c2lzL2Nudl9yZXN1bHRzIgpWSVNfRElSPSIkQkFTRV9ESVIvaGcxOV9hbmFseXNpcy92aXN1YWxpemF0aW9ucyIKCiMgQ3JlYXRlIHRoZSB2aXN1YWxpemF0aW9uIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC1wICIkVklTX0RJUiIKCmVjaG8gIi0tLSBHZW5lcmF0aW5nIENOViBoZWF0bWFwIGZyb20gaGcxOSAuY25yIGZpbGVzIC0tLSIKCiMgVGhlIGhlYXRtYXAgY29tbWFuZCB3b3JrcyB3aXRoIC5jbnIgZmlsZXMsIG5vdCAuY25zIGZpbGVzLgojIFdlIHdpbGwgdXNlIHRoZSBvcmlnaW5hbCBoZzE5IC5jbnIgZmlsZXMgZm9yIHRoaXMgZ2VuZS1jZW50cmljIHZpZXcuCmNudmtpdC5weSBoZWF0bWFwIFwKICAiJENOVl9ESVIvVDEvVDEud2l0aF9yZy5jbnIiIFwKICAiJENOVl9ESVIvWDEvWDEud2l0aF9yZy5jbnIiIFwKICAiJENOVl9ESVIvWFgxL1hYMS53aXRoX3JnLmNuciIgXAogIC1vICIkVklTX0RJUi9XRVNfQ05WX0hlYXRtYXBfVG9wR2VuZXNfaGcxOS5wZGYiCgplY2hvICJDTlYgaGVhdG1hcCBvZiB0b3AgdmFyaWFibGUgZ2VuZXMgc2F2ZWQgdG8gJFZJU19ESVIvV0VTX0NOVl9IZWF0bWFwX1RvcEdlbmVzX2hnMTkucGRmIgoKYGBgCgoKYGBge3IsIGNodW5rX25hbWU9ImNudl9zY2F0dGVyX3Bsb3RfUiIsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD05LCB3YXJuaW5nPUZBTFNFLCBldmFsPVRSVUV9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspICMgRm9yIGNvbWJpbmluZyBwbG90cwoKIyAtLS0gRGVmaW5lIFBhdGhzIC0tLQpsaWZ0b3Zlcl9kaXIgPC0gIi9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTlfYW5hbHlzaXMvbGlmdG92ZXJfcmVzdWx0cyIKc2FtcGxlcyA8LSBjKCJUMSIsICJYMSIsICJYWDEiKQoKIyAtLS0gUmVhZCBhbmQgQ29tYmluZSBEYXRhIC0tLQojIENyZWF0ZSBhIGxpc3QgdG8gaG9sZCB0aGUgZGF0YSBmb3IgZWFjaCBzYW1wbGUKYWxsX2Nuc19kYXRhIDwtIGxpc3QoKQoKZm9yIChzYW1wbGVfaWQgaW4gc2FtcGxlcykgewogIGZpbGVfcGF0aCA8LSBmaWxlLnBhdGgobGlmdG92ZXJfZGlyLCBwYXN0ZTAoc2FtcGxlX2lkLCAiLmhnMzguY25zIikpCiAgCiAgIyBSZWFkIHRoZSBkYXRhIGFuZCBhZGQgYSBjb2x1bW4gZm9yIHRoZSBzYW1wbGUgbmFtZQogIGNuc19kYXRhIDwtIHJlYWQuZGVsaW0oZmlsZV9wYXRoLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiKSAlPiUKICAgIG11dGF0ZShzYW1wbGUgPSBzYW1wbGVfaWQpCiAgCiAgYWxsX2Nuc19kYXRhW1tzYW1wbGVfaWRdXSA8LSBjbnNfZGF0YQp9CgojIENvbWJpbmUgYWxsIGRhdGEgZnJhbWVzIGludG8gb25lCmNvbWJpbmVkX2RhdGEgPC0gYmluZF9yb3dzKGFsbF9jbnNfZGF0YSkKCiMgLS0tIFByZXBhcmUgQ2hyb21vc29tZSBPcmRlcmluZyAtLS0KIyBFbnN1cmUgY2hyb21vc29tZXMgYXJlIG9yZGVyZWQgbnVtZXJpY2FsbHkgdGhlbiBieSBsZXR0ZXIgKGNocjEsIGNocjIsIC4uLiwgY2hyWCkKY29tYmluZWRfZGF0YSRjaHJvbW9zb21lIDwtIGZhY3Rvcihjb21iaW5lZF9kYXRhJGNocm9tb3NvbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHBhc3RlMCgiY2hyIiwgYygxOjIyLCAiWCIsICJZIikpKQoKIyAtLS0gQ3JlYXRlIHRoZSBQbG90IC0tLQpjbnZfcGxvdCA8LSBnZ3Bsb3QoY29tYmluZWRfZGF0YSwgYWVzKHggPSBzdGFydCAvIDFlNiwgeSA9IGxvZzIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBsb2cyKSwgc2l6ZSA9IDAuNykgKwogICMgVXNlIGZhY2V0X2dyaWQgdG8gY3JlYXRlIGEgc2VwYXJhdGUgcGxvdCBmb3IgZWFjaCBzYW1wbGUsIGFycmFuZ2VkIHZlcnRpY2FsbHkKICBmYWNldF9ncmlkKHNhbXBsZSB+IGNocm9tb3NvbWUsIHNjYWxlcyA9ICJmcmVlX3giLCBzcGFjZSA9ICJmcmVlX3giKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gImdyZXkiLCBoaWdoID0gInJlZCIsIG1pZHBvaW50ID0gMCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJDb21iaW5lZCBDTlYgU2NhdHRlciBQbG90IChoZzM4IENvb3JkaW5hdGVzKSIsCiAgICB4ID0gIkNocm9tb3NvbWUiLAogICAgeSA9ICJDb3B5IFJhdGlvIChsb2cyKSIKICApICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAjIEhpZGUgdGhlIHgtYXhpcyBudW1iZXJzCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5zcGFjaW5nLnggPSB1bml0KDAuMSwgImxpbmVzIiksCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDgpLCAjIFJvdGF0ZSBjaHJvbW9zb21lIGxhYmVscwogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCgojIFByaW50IHRoZSBwbG90CnByaW50KGNudl9wbG90KQpgYGAKCkJ5IHJ1bm5pbmcgdGhlc2UgdHdvIGNodW5rcywgeW91IHdpbGwgZ2V0IGJvdGggdmlzdWFsaXphdGlvbnMgeW91IG5lZWQ6CjEuICBBICoqUERGIGhlYXRtYXAqKiBzaG93aW5nIHRoZSBjb3B5IG51bWJlciBvZiB0aGUgbW9zdCB2YXJpYWJsZSBnZW5lcyBhY3Jvc3MgeW91ciBzYW1wbGVzLgoyLiAgQSAqKmNvbWJpbmVkIHNjYXR0ZXIgcGxvdCoqIHNob3dpbmcgdGhlIGNvbXBsZXRlIGdlbm9tZS13aWRlIENOViBwcm9maWxlIGZvciBhbGwgdGhyZWUgc2FtcGxlcywgcGVyZmVjdCBmb3IgY29tcGFyaW5nIHdpdGggYGluZmVyQ05WYC4KCgojIyBPbmNvUHJpbnQgb2YgU29tYXRpYyBNdXRhdGlvbnMgKGZyb20gaGcxOSBkYXRhKQoKCmBgYHtiYXNoLCBjaHVua19uYW1lPSJjaGVja192Y2ZfcGFzcyJ9CiMhL2Jpbi9iYXNoCiMgQWN0aXZhdGUgdGhlIGNvbmRhIGVudmlyb25tZW50CnNvdXJjZSAvaG9tZS9iaW9pbmZvL21pbmljb25kYTMvZXRjL3Byb2ZpbGUuZC9jb25kYS5zaApjb25kYSBhY3RpdmF0ZSB3ZXNfZW52CgpWQ0ZfRElSPSIvaG9tZS9iaW9pbmZvLzEtVGhlc2lzX0ZpbmFsX1llYXJfMjAyNS8yMDI1LVllYXIzX0FuYWx5c2lzLzEtc2NSTkFfUkVTVUxUUy0xOS0xMS0yMDI1LzE1LVdFU19QYXRpZW50MV9MMV9MMl9BbmFseXNpcy0xOS0xMS0yMDI1L0V4b21lX1BhdGllbnRfMS9oZzE5X2FuYWx5c2lzL3NvbWF0aWNfdmFyaWFudHMiCgplY2hvICItLS0gQ2hlY2tpbmcgZm9yICdQQVNTJyB2YXJpYW50cyBpbiBhbm5vdGF0ZWQgVkNGIGZpbGVzIC0tLSIKCmZvciBUVU1PUiBpbiBUMSBYMSBYWDE7IGRvCiAgVkNGX0ZJTEU9IiRWQ0ZfRElSLyR7VFVNT1J9LmhnMTkuYW5ub3RhdGVkLnZjZiIKICBpZiBbIC1mICIkVkNGX0ZJTEUiIF07IHRoZW4KICAgICMgVXNlIGdyZXAgdG8gY291bnQgbGluZXMgdGhhdCBhcmUgbm90IGNvbW1lbnRzIGFuZCBjb250YWluICdQQVNTJwogICAgUEFTU19DT1VOVD0kKGdyZXAgLXYgIl4jIiAiJFZDRl9GSUxFIiB8IGdyZXAgLWMgIlBBU1MiKQogICAgZWNobyAiRm91bmQgJFBBU1NfQ09VTlQgJ1BBU1MnIHZhcmlhbnRzIGluICRWQ0ZfRklMRSIKICBlbHNlCiAgICBlY2hvICJFUlJPUjogRmlsZSBub3QgZm91bmQ6ICRWQ0ZfRklMRSIKICBmaQpkb25lCmBgYAoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImZpbmFsX2Jhc2hfY2hlY2sifQojIS9iaW4vYmFzaAojIFRoaXMgc2NyaXB0IHBlcmZvcm1zIGEgc3RlcC1ieS1zdGVwIGRpc3NlY3Rpb24gb2YgdGhlIFZFUCBhbm5vdGF0aW9uIHN0cmluZy4KClZDRl9GSUxFPSIvaG9tZS9iaW9pbmZvLzEtVGhlc2lzX0ZpbmFsX1llYXJfMjAyNS8yMDI1LVllYXIzX0FuYWx5c2lzLzEtc2NSTkFfUkVTVUxUUy0xOS0xMS0yMDI1LzE1LVdFU19QYXRpZW50MV9MMV9MMl9BbmFseXNpcy0xOS0xMS0yMDI1L0V4b21lX1BhdGllbnRfMS9oZzE5X2FuYWx5c2lzL3NvbWF0aWNfdmFyaWFudHMvVDEuaGcxOS5hbm5vdGF0ZWQudmNmIgoKZWNobyAiLS0tIEZpbmFsIENoZWNrOiBEaXNzZWN0aW5nIHRoZSBmaXJzdCBQQVNTIHZhcmlhbnQncyBhbm5vdGF0aW9uIC0tLSIKCiMgMS4gR2V0IHRoZSBmdWxsIElORk8gZmllbGQgZnJvbSB0aGUgZmlyc3QgUEFTUyB2YXJpYW50CklORk9fRklFTEQ9JChncmVwIC12ICJeIyIgIiRWQ0ZfRklMRSIgfCBncmVwICJQQVNTIiB8IGhlYWQgLW4gMSB8IGF3ayAne3ByaW50ICQ4fScpCgojIDIuIElzb2xhdGUgdGhlIGZ1bGwgQ1NRIHN0cmluZyBmcm9tIHRoZSBJTkZPIGZpZWxkCkNTUV9TVFJJTkc9JChlY2hvICIkSU5GT19GSUVMRCIgfCBncmVwIC1vICJDU1E9W147XSoiIHwgc2VkICdzL0NTUT0vLycpCgplY2hvICItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0iCmVjaG8gIlN0ZXAgMTogRnVsbCBDU1Egc3RyaW5nOiIKZWNobyAiJENTUV9TVFJJTkciCmVjaG8gIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIKCiMgMy4gSXNvbGF0ZSB0aGUgVkVSWSBGSVJTVCBhbm5vdGF0aW9uIChldmVyeXRoaW5nIGJlZm9yZSB0aGUgZmlyc3QgY29tbWEpCkZJUlNUX0FOTk9UQVRJT049JChlY2hvICIkQ1NRX1NUUklORyIgfCBjdXQgLWQgJywnIC1mIDEpCgplY2hvICJTdGVwIDI6IEZpcnN0IGFubm90YXRpb24gYmxvY2s6IgplY2hvICIkRklSU1RfQU5OT1RBVElPTiIKZWNobyAiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIgoKIyA0LiBTcGxpdCB0aGUgZmlyc3QgYW5ub3RhdGlvbiBieSAnfCcgYW5kIGV4dHJhY3QgZmllbGRzIDIgYW5kIDQKQ09OU0VRVUVOQ0U9JChlY2hvICIkRklSU1RfQU5OT1RBVElPTiIgfCBjdXQgLWQgJ3wnIC1mIDIpCkdFTkVfU1lNQk9MPSQoZWNobyAiJEZJUlNUX0FOTk9UQVRJT04iIHwgY3V0IC1kICd8JyAtZiA0KQoKZWNobyAiU3RlcCAzOiBGaW5hbCBFeHRyYWN0ZWQgRmllbGRzOiIKZWNobyAiICAtIENvbnNlcXVlbmNlIChGaWVsZCAyKTogJENPTlNFUVVFTkNFIgplY2hvICIgIC0gR2VuZSBTeW1ib2wgKEZpZWxkIDQpOiAkR0VORV9TWU1CT0wiCmVjaG8gIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIKCmlmIFsgLW4gIiRHRU5FX1NZTUJPTCIgXTsgdGhlbgogICAgZWNobyAiQ29uY2x1c2lvbjogQmFzaCBjaGVjayBzdWNjZXNzZnVsLiBHZW5lIFN5bWJvbCB3YXMgZm91bmQgaW4gRmllbGQgNC4iCmVsc2UKICAgIGVjaG8gIkNvbmNsdXNpb246IEJhc2ggY2hlY2sgRkFJTEVELiBHZW5lIFN5bWJvbCB3YXMgTk9UIGZvdW5kIGluIEZpZWxkIDQuIgpmaQoKCmBgYAoKCgoKVGhpcyBSIGNodW5rIHZpc3VhbGl6ZXMgdGhlIHNvbWF0aWMgbXV0YXRpb24gbGFuZHNjYXBlIHRvIHNob3cgY2xvbmFsIHJlbGF0aW9uc2hpcHMuCgpgYGB7ciwgZW5naW5lPSdSJywgY2h1bmtfbmFtZT0ib25jb3ByaW50X3RydWx5X2ZpbmFsIiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTgsIGV2YWw9VFJVRX0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeSh2Y2ZSKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCgojIC0tLSBGaW5hbCwgQ29ycmVjdGVkIGZ1bmN0aW9uIHRvIHBhcnNlIFZFUCBDU1EgZmllbGQgLS0tCnBhcnNlX211dGVjdF92Y2ZfZmluYWwgPC0gZnVuY3Rpb24odmNmX2ZpbGUsIHNhbXBsZV9uYW1lKSB7CiAgaWYgKCFmaWxlLmV4aXN0cyh2Y2ZfZmlsZSkpIHsKICAgIHdhcm5pbmcocGFzdGUoIlZDRiBmaWxlIG5vdCBmb3VuZDoiLCB2Y2ZfZmlsZSkpCiAgICByZXR1cm4oTlVMTCkKICB9CiAgCiAgdmNmIDwtIHJlYWQudmNmUih2Y2ZfZmlsZSwgdmVyYm9zZSA9IEZBTFNFKQogIAogIGlmICghIlBBU1MiICVpbiUgZ2V0RklMVEVSKHZjZikpIHJldHVybihOVUxMKQogIHBhc3NfdmNmIDwtIHZjZltnZXRGSUxURVIodmNmKSA9PSAiUEFTUyIsIF0KICBpZiAobnJvdyhwYXNzX3ZjZikgPT0gMCkgcmV0dXJuKE5VTEwpCiAgCiAgY3NxIDwtIGV4dHJhY3QuaW5mbyhwYXNzX3ZjZiwgIkNTUSIpCiAgCiAgcmVzdWx0cyA8LSBsYXBwbHkoY3NxLCBmdW5jdGlvbih2YXJpYW50X2NzcSkgewogICAgaWYgKGlzLm5hKHZhcmlhbnRfY3NxKSkgcmV0dXJuKE5VTEwpCiAgICAKICAgIGFubm90YXRpb25zIDwtIHN0cnNwbGl0KHZhcmlhbnRfY3NxLCAiLCIpW1sxXV0KICAgIAogICAgYmVzdF9nZW5lIDwtIE5BCiAgICBiZXN0X2NvbnNlcXVlbmNlX3R5cGUgPC0gIm90aGVyIgogICAgCiAgICBmb3IgKGEgaW4gYW5ub3RhdGlvbnMpIHsKICAgICAgZmllbGRzIDwtIHN0cnNwbGl0KGEsICJcXHwiKVtbMV1dCiAgICAgIAogICAgICAjIC0tLSBUSElTIElTIFRIRSBDUklUSUNBTCBGSVggLS0tCiAgICAgICMgRXhwbGljaXRseSBnZXQgdGhlIDR0aCBmaWVsZCBmb3IgdGhlIGdlbmUuIFRoaXMgd2lsbCBiZSBhIHNpbmdsZSBzdHJpbmcuCiAgICAgIGN1cnJlbnRfZ2VuZSA8LSBmaWVsZHNbNF0KICAgICAgY3VycmVudF9jb25zZXF1ZW5jZV9zdHIgPC0gZmllbGRzWzJdCiAgICAgIAogICAgICBjdXJyZW50X211dF90eXBlIDwtICJvdGhlciIKICAgICAgaWYgKGdyZXBsKCJtaXNzZW5zZV92YXJpYW50IiwgY3VycmVudF9jb25zZXF1ZW5jZV9zdHIpKSBjdXJyZW50X211dF90eXBlIDwtICJtaXNzZW5zZSIKICAgICAgaWYgKGdyZXBsKCJmcmFtZXNoaWZ0X3ZhcmlhbnR8c3RvcF9nYWluZWR8c3BsaWNlX2FjY2VwdG9yfHNwbGljZV9kb25vciIsIGN1cnJlbnRfY29uc2VxdWVuY2Vfc3RyKSkgY3VycmVudF9tdXRfdHlwZSA8LSAidHJ1bmNhdGluZyIKICAgICAgCiAgICAgICMgUHJpb3JpdGl6ZSBmaW5kaW5nIHRoZSBtb3N0IGRhbWFnaW5nIG11dGF0aW9uIGFuZCBpdHMgYXNzb2NpYXRlZCBnZW5lCiAgICAgIGlmIChjdXJyZW50X211dF90eXBlID09ICJ0cnVuY2F0aW5nIikgewogICAgICAgIGJlc3RfY29uc2VxdWVuY2VfdHlwZSA8LSAidHJ1bmNhdGluZyIKICAgICAgICBiZXN0X2dlbmUgPC0gY3VycmVudF9nZW5lCiAgICAgICAgYnJlYWsgCiAgICAgIH0gZWxzZSBpZiAoY3VycmVudF9tdXRfdHlwZSA9PSAibWlzc2Vuc2UiICYmIGJlc3RfY29uc2VxdWVuY2VfdHlwZSAhPSAidHJ1bmNhdGluZyIpIHsKICAgICAgICBiZXN0X2NvbnNlcXVlbmNlX3R5cGUgPC0gIm1pc3NlbnNlIgogICAgICAgIGJlc3RfZ2VuZSA8LSBjdXJyZW50X2dlbmUKICAgICAgfSBlbHNlIGlmIChiZXN0X2NvbnNlcXVlbmNlX3R5cGUgPT0gIm90aGVyIikgewogICAgICAgIGJlc3RfZ2VuZSA8LSBjdXJyZW50X2dlbmUKICAgICAgfQogICAgfQogICAgCiAgICAjIFRoZSAnaWYnIHN0YXRlbWVudCB3aWxsIG5vdyB3b3JrIGJlY2F1c2UgYmVzdF9nZW5lIGlzIGEgc2luZ2xlIHZhbHVlCiAgICBpZiAoaXMubmEoYmVzdF9nZW5lKSB8fCBiZXN0X2dlbmUgPT0gIiIpIHJldHVybihOVUxMKQogICAgCiAgICByZXR1cm4oZGF0YS5mcmFtZShnZW5lID0gYmVzdF9nZW5lLCBtdXRfdHlwZSA9IGJlc3RfY29uc2VxdWVuY2VfdHlwZSwgc2FtcGxlID0gc2FtcGxlX25hbWUpKQogIH0pCiAgCiAgZGYgPC0gZG8uY2FsbChyYmluZCwgcmVzdWx0cykKICByZXR1cm4oZGYpCn0KCiMgLS0tIFByb2Nlc3MgZWFjaCBhbm5vdGF0ZWQgVkNGIGZpbGUgLS0tCnZjZl9kaXIgPC0gIi9ob21lL2Jpb2luZm8vMS1UaGVzaXNfRmluYWxfWWVhcl8yMDI1LzIwMjUtWWVhcjNfQW5hbHlzaXMvMS1zY1JOQV9SRVNVTFRTLTE5LTExLTIwMjUvMTUtV0VTX1BhdGllbnQxX0wxX0wyX0FuYWx5c2lzLTE5LTExLTIwMjUvRXhvbWVfUGF0aWVudF8xL2hnMTlfYW5hbHlzaXMvc29tYXRpY192YXJpYW50cyIgCnQxX211dHMgPC0gcGFyc2VfbXV0ZWN0X3ZjZl9maW5hbChmaWxlLnBhdGgodmNmX2RpciwgIlQxLmhnMTkuYW5ub3RhdGVkLnZjZiIpLCAiVDEiKQp4MV9tdXRzIDwtIHBhcnNlX211dGVjdF92Y2ZfZmluYWwoZmlsZS5wYXRoKHZjZl9kaXIsICJYMS5oZzE5LmFubm90YXRlZC52Y2YiKSwgIlgxIikKeHgxX211dHMgPC0gcGFyc2VfbXV0ZWN0X3ZjZl9maW5hbChmaWxlLnBhdGgodmNmX2RpciwgIlhYMS5oZzE5LmFubm90YXRlZC52Y2YiKSwgIlhYMSIpCgphbGxfbXV0cyA8LSByYmluZCh0MV9tdXRzLCB4MV9tdXRzLCB4eDFfbXV0cykKCiMgLS0tIENyZWF0ZSB0aGUgbWF0cml4IGZvciBPbmNvUHJpbnQgLS0tCmlmICghaXMubnVsbChhbGxfbXV0cykgJiYgbnJvdyhhbGxfbXV0cykgPiAwKSB7CiAgZ2VuZXMgPC0gdW5pcXVlKGFsbF9tdXRzJGdlbmUpCiAgc2FtcGxlcyA8LSBjKCJUMSIsICJYMSIsICJYWDEiKQogIG1hdCA8LSBtYXRyaXgoIiIsIG5yb3cgPSBsZW5ndGgoZ2VuZXMpLCBuY29sID0gbGVuZ3RoKHNhbXBsZXMpLCBkaW1uYW1lcyA9IGxpc3QoZ2VuZXMsIHNhbXBsZXMpKQoKICBmb3IgKGkgaW4gMTpucm93KGFsbF9tdXRzKSkgewogICAgZ2VuZV9pIDwtIGFsbF9tdXRzJGdlbmVbaV0KICAgIHNhbXBsZV9pIDwtIGFsbF9tdXRzJHNhbXBsZVtpXQogICAgbXV0X3R5cGVfaSA8LSBhbGxfbXV0cyRtdXRfdHlwZVtpXQogICAgY3VycmVudF92YWwgPC0gbWF0W2dlbmVfaSwgc2FtcGxlX2ldCiAgICBpZiAoY3VycmVudF92YWwgPT0gIiIgfHwgKGN1cnJlbnRfdmFsID09ICJvdGhlciIgJiYgbXV0X3R5cGVfaSAhPSAib3RoZXIiKSB8fCAoY3VycmVudF92YWwgPT0gIm1pc3NlbnNlIiAmJiBtdXRfdHlwZV9pID09ICJ0cnVuY2F0aW5nIikpIHsKICAgICAgbWF0W2dlbmVfaSwgc2FtcGxlX2ldIDwtIG11dF90eXBlX2kKICAgIH0KICB9CgogIG51bV9tdXRhdGVkX2Fjcm9zc19zYW1wbGVzIDwtIHJvd1N1bXMobWF0ICE9ICIiKQogIG51bV90b19wbG90IDwtIG1pbigzMCwgc3VtKG51bV9tdXRhdGVkX2Fjcm9zc19zYW1wbGVzID4gMCkpCiAgdG9wX2dlbmVzIDwtIG5hbWVzKHNvcnQobnVtX211dGF0ZWRfYWNyb3NzX3NhbXBsZXMsIGRlY3JlYXNpbmcgPSBUUlVFKVsxOm51bV90b19wbG90XSkKICBtYXRfZmlsdGVyZWQgPC0gbWF0W3RvcF9nZW5lcywgLCBkcm9wID0gRkFMU0VdCgogIGNvbCA8LSBjKCJ0cnVuY2F0aW5nIiA9ICIjOTIyQjIxIiwgIm1pc3NlbnNlIiA9ICIjMjQ3MUEzIiwgIm90aGVyIiA9ICIjRDVEOERDIikKICBhbHRlcl9mdW4gPC0gbGlzdCgKICAgICAgYmFja2dyb3VuZCA9IGZ1bmN0aW9uKHgsIHksIHcsIGgpIGdyaWQucmVjdCh4LCB5LCB3LXVuaXQoMiwicHQiKSwgaC11bml0KDIsInB0IiksIGdwPWdwYXIoZmlsbD0iI2YwZjBmMCIsIGNvbD1OQSkpLAogICAgICB0cnVuY2F0aW5nID0gZnVuY3Rpb24oeCwgeSwgdywgaCkgZ3JpZC5yZWN0KHgsIHksIHctdW5pdCgyLCJwdCIpLCBoLXVuaXQoMiwicHQiKSwgZ3A9Z3BhcihmaWxsPWNvbFsidHJ1bmNhdGluZyJdLCBjb2w9TkEpKSwKICAgICAgbWlzc2Vuc2UgPSBmdW5jdGlvbih4LCB5LCB3LCBoKSBncmlkLnJlY3QoeCwgeSwgdy11bml0KDIsInB0IiksIGgqMC41LCBncD1ncGFyKGZpbGw9Y29sWyJtaXNzZW5zZSJdLCBjb2w9TkEpKSwKICAgICAgb3RoZXIgPSBmdW5jdGlvbih4LCB5LCB3LCBoKSBncmlkLnJlY3QoeCwgeSwgdy11bml0KDIsInB0IiksIGgqMC4yLCBncD1ncGFyKGZpbGw9Y29sWyJvdGhlciJdLCBjb2w9TkEpKQogICkKCiAgb25jb1ByaW50KG1hdF9maWx0ZXJlZCwKICAgICAgICAgICAgYWx0ZXJfZnVuID0gYWx0ZXJfZnVuLCAKICAgICAgICAgICAgY29sID0gY29sLAogICAgICAgICAgICByb3dfb3JkZXIgPSByb3duYW1lcyhtYXRfZmlsdGVyZWQpLAogICAgICAgICAgICBjb2x1bW5fdGl0bGUgPSAiU29tYXRpYyBNdXRhdGlvbiBMYW5kc2NhcGUgKFRvcCBHZW5lcykiLAogICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGUgPSAiQWx0ZXJhdGlvbnMiLCBhdCA9IGMoInRydW5jYXRpbmciLCAibWlzc2Vuc2UiLCAib3RoZXIiKSkpCiAgICAgICAgICAgIAp9IGVsc2UgewogIHByaW50KCJObyBtdXRhdGlvbnMgZm91bmQgdG8gcGxvdC4gVGhpcyBpbmRpY2F0ZXMgYSBwZXJzaXN0ZW50IGlzc3VlIHdpdGggVkNGIHBhcnNpbmcuIikKfQoKYGBgCgpgYGB7YmFzaCwgY2h1bmtfbmFtZT0iY2hlY2tfdHA1MyJ9CgojIS9iaW4vYmFzaAojIENvcnJlY3RlZCBWQ0YgZGlyZWN0b3J5IHBhdGgKVkNGX0RJUj0iL2hvbWUvYmlvaW5mby8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEvaGcxOV9hbmFseXNpcy9zb21hdGljX3ZhcmlhbnRzIgoKZWNobyAiLS0tIFNlYXJjaGluZyBmb3IgVFA1MyBtdXRhdGlvbnMgaW4gYWxsIHNhbXBsZXMgKENvcnJlY3RlZCBQYXRoKSAtLS0iCgpmb3IgVFVNT1IgaW4gVDEgWDEgWFgxOyBkbwogIFZDRl9GSUxFPSIkVkNGX0RJUi8ke1RVTU9SfS5oZzE5LmFubm90YXRlZC52Y2YiCiAgZWNobyAiLS0tIENoZWNraW5nICRUVU1PUiAtLS0iCiAgCiAgaWYgWyAhIC1mICIkVkNGX0ZJTEUiIF07IHRoZW4KICAgICAgZWNobyAiRVJST1I6IFZDRiBmaWxlIG5vdCBmb3VuZCBhdCAkVkNGX0ZJTEUiCiAgICAgIGNvbnRpbnVlCiAgZmkKICAKICAjIFNlYXJjaCBmb3IgbGluZXMgdGhhdCBhcmUgbm90IGNvbW1lbnRzLCBwYXNzZWQgZmlsdGVycywgYW5kIGNvbnRhaW4gdGhlIGdlbmUgc3ltYm9sIFRQNTMKICAjIFRoZSBDU1EgZmllbGQgaXMgd2hhdCB3ZSBuZWVkIHRvIHNlYXJjaCBpbi4KICBncmVwIC12ICJeIyIgIiRWQ0ZfRklMRSIgfCBncmVwICJQQVNTIiB8IGdyZXAgIkNTUT0iIHwgZ3JlcCAtbyAnU1lNQk9MPVtefDtdKicgfCBncmVwICJUUDUzIiB8fCBlY2hvICJObyBQQVNTaW5nIFRQNTMgbXV0YXRpb24gZm91bmQgaW4gJFRVTU9SLiIKICBlY2hvICIiCmRvbmUKCmBgYAoKCgoKCgo=