Before you run this, please remember:

  1. Dependencies: You need to have all the software installed and available in your system’s PATH. This includes bwa, samtools, picard, gatk, cnvkit, and vep.
  2. Reference Files: You must download the required reference files (human genome FASTA, dbSNP VCF, gnomAD VCF, etc.) and update the paths in the “Setup and Configuration” section.
  3. BAM Files: The pipeline assumes you will start with the sorted.bam files you have. The initial steps will create analysis-ready BAM files (.final.bam).
  4. Execution: You can run each chunk interactively in RStudio or use knitr::purl to extract the shell commands into a script if you prefer to run it directly in your terminal.

Here is the R Markdown file content:

1 Introduction

This document provides a comprehensive, end-to-end bioinformatics pipeline to process and analyze Whole Exome Sequencing (WES) data for Patient 1. The dataset includes a matched normal sample (N1) and three tumor/cell line samples (T1, X1, XX1).

The primary goals of this analysis are: 1. To perform quality control and pre-processing on the existing BAM files. 2. To call somatic single nucleotide variants (SNVs) and insertions/deletions (indels). 3. To identify somatic copy number variations (CNVs). 4. To produce visualizations that can be integrated with and used to validate findings from single-cell RNA sequencing analyses (inferCNV, scevan).

This pipeline follows GATK Best Practices for somatic variant discovery and uses CNVkit for CNV detection.

2 Step 0: Setup and Configuration

This chunk defines all the necessary paths for tools, reference genomes, and data. You must edit these paths to match your system’s configuration before running any part of this pipeline.

#!/bin/bash
# -----------------------------------------------------------------
# USER-DEFINED VARIABLES: PLEASE EDIT THESE PATHS
# -----------------------------------------------------------------

# Base directory where N1, T1, X1, XX1 folders are located
BASE_DIR="~/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 genome files (must be indexed with .fai and .dict)
REF_GENOME="/path/to/your/reference/hg38.fa"

# Known sites VCFs for GATK
DBSNP="/path/to/your/dbsnp_138.hg38.vcf.gz"
GNOMAD="/path/to/your/af-only-gnomad.hg38.vcf.gz"

# Interval list for the exome capture kit used
# This is CRITICAL for accurate CNV analysis and targeted variant calling.
INTERVAL_LIST="/path/to/your/exome_capture_kit.bed" # Can be in BED or Picard interval_list format

# Software paths (if not in system PATH, provide full path)
GATK="gatk"
PICARD="picard"
CNVKIT="cnvkit.py"
VEP_PATH="/path/to/your/ensembl-vep" # Path to VEP directory

# Create output directories
mkdir -p $BASE_DIR/01_preprocessed_bams
mkdir -p $BASE_DIR/02_mutect2_results
mkdir -p $BASE_DIR/03_cnvkit_results
mkdir -p $BASE_DIR/04_visualizations

3 Step 1: BAM Pre-processing

The provided sorted.bam files are the starting point. We will perform duplicate marking and Base Quality Score Recalibration (BQSR) to generate analysis-ready BAM files.

3.1 Mark and Remove PCR Duplicates

Duplicates arise from PCR amplification during library preparation and can bias variant calls. We use Picard’s MarkDuplicates to identify and remove them.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

for SAMPLE in N1 T1 X1 XX1; do
  echo "--- Marking duplicates for $SAMPLE ---"
  
  INPUT_BAM="$BASE_DIR/$SAMPLE/sorted.bam"
  OUTPUT_BAM="$BASE_DIR/01_preprocessed_bams/${SAMPLE}.dedup.bam"
  METRICS_FILE="$BASE_DIR/01_preprocessed_bams/${SAMPLE}.dedup_metrics.txt"
  
  if [ -f "$OUTPUT_BAM" ]; then
    echo "$OUTPUT_BAM already exists, skipping."
    continue
  fi

  $PICARD MarkDuplicates \
    I=$INPUT_BAM \
    O=$OUTPUT_BAM \
    M=$METRICS_FILE \
    REMOVE_DUPLICATES=true \
    CREATE_INDEX=true \
    VALIDATION_STRINGENCY=SILENT
done

3.2 Base Quality Score Recalibration (BQSR)

BQSR adjusts base quality scores to correct for systematic technical errors from the sequencing process, improving variant call accuracy.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

for SAMPLE in N1 T1 X1 XX1; do
  echo "--- Running BQSR for $SAMPLE ---"
  
  DEDUP_BAM="$BASE_DIR/01_preprocessed_bams/${SAMPLE}.dedup.bam"
  RECAL_TABLE="$BASE_DIR/01_preprocessed_bams/${SAMPLE}.recal_data.table"
  FINAL_BAM="$BASE_DIR/01_preprocessed_bams/${SAMPLE}.final.bam"

  if [ -f "$FINAL_BAM" ]; then
    echo "$FINAL_BAM already exists, skipping."
    continue
  fi

  # Step 1: Generate recalibration table
  $GATK BaseRecalibrator \
    -R $REF_GENOME \
    -I $DEDUP_BAM \
    --known-sites $DBSNP \
    -O $RECAL_TABLE

  # Step 2: Apply recalibration
  $GATK ApplyBQSR \
    -R $REF_GENOME \
    -I $DEDUP_BAM \
    --bqsr-recal-file $RECAL_TABLE \
    -O $FINAL_BAM
done

4 Step 2: Somatic Variant Calling (Mutect2)

We use GATK’s Mutect2 in tumor-normal mode to call somatic SNVs and indels for each tumor sample (T1, X1, XX1) against the matched normal (N1).

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

NORMAL_BAM="$BASE_DIR/01_preprocessed_bams/N1.final.bam"

for TUMOR in T1 X1 XX1; do
  echo "--- Calling somatic variants for $TUMOR vs N1 ---"
  
  TUMOR_BAM="$BASE_DIR/01_preprocessed_bams/${TUMOR}.final.bam"
  VCF_OUT="$BASE_DIR/02_mutect2_results/${TUMOR}.somatic.raw.vcf.gz"
  
  if [ -f "$VCF_OUT" ]; then
    echo "$VCF_OUT already exists, skipping."
    continue
  fi

  $GATK Mutect2 \
    -R $REF_GENOME \
    -I $TUMOR_BAM \
    -I $NORMAL_BAM \
    -normal N1 \
    --germline-resource $GNOMAD \
    -O $VCF_OUT
done

5 Step 3: Variant Filtering and Annotation

Raw variant calls must be filtered to remove false positives and then annotated to predict their functional effects.

5.1 Filter Mutect2 Calls

FilterMutectCalls applies a series of filters to the raw VCF from Mutect2 to increase precision.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

for TUMOR in T1 X1 XX1; do
  echo "--- Filtering variant calls for $TUMOR ---"
  
  RAW_VCF="$BASE_DIR/02_mutect2_results/${TUMOR}.somatic.raw.vcf.gz"
  FILTERED_VCF="$BASE_DIR/02_mutect2_results/${TUMOR}.somatic.filtered.vcf.gz"

  if [ -f "$FILTERED_VCF" ]; then
    echo "$FILTERED_VCF already exists, skipping."
    continue
  fi

  $GATK FilterMutectCalls \
    -R $REF_GENOME \
    -V $RAW_VCF \
    -O $FILTERED_VCF
done

5.2 Annotate with Ensembl VEP

We use Ensembl Variant Effect Predictor (VEP) to annotate the filtered variants with information about genes, transcripts, and predicted protein-level consequences.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

for TUMOR in T1 X1 XX1; do
  echo "--- Annotating variants for $TUMOR with VEP ---"
  
  FILTERED_VCF="$BASE_DIR/02_mutect2_results/${TUMOR}.somatic.filtered.vcf.gz"
  ANNOTATED_VCF="$BASE_DIR/02_mutect2_results/${TUMOR}.somatic.annotated.vcf"

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

  # Run VEP. Assumes VEP cache is installed.
  $VEP_PATH/vep \
    --input_file $FILTERED_VCF \
    --output_file $ANNOTATED_VCF \
    --format vcf \
    --vcf \
    --symbol \
    --terms SO \
    --tsl \
    --hgvs \
    --fasta $REF_GENOME \
    --cache \
    --force_overwrite
done

6 Step 4: Copy Number Variation (CNV) Analysis

We use CNVkit to detect somatic copy number changes. It builds a reference profile from the normal sample and then calls gains and losses in the tumor samples relative to that reference.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

echo "--- Running CNVkit pipeline ---"

NORMAL_BAM="$BASE_DIR/01_preprocessed_bams/N1.final.bam"
REFERENCE_CNN="$BASE_DIR/03_cnvkit_results/reference.cnn"

# Step 4.1: Build the reference from the normal sample
# In a real-world scenario, a pool of normals is better, but one is sufficient.
$CNVKIT batch $NORMAL_BAM \
  --normal \
  --targets $INTERVAL_LIST \
  --fasta $REF_GENOME \
  --output-reference $REFERENCE_CNN \
  --output-dir $BASE_DIR/03_cnvkit_results/N1

# Step 4.2: Analyze each tumor sample against the reference
for TUMOR in T1 X1 XX1; do
  echo "--- Calling CNVs for $TUMOR ---"
  TUMOR_BAM="$BASE_DIR/01_preprocessed_bams/${TUMOR}.final.bam"
  
  $CNVKIT batch $TUMOR_BAM \
    --reference $REFERENCE_CNN \
    --output-dir $BASE_DIR/03_cnvkit_results/$TUMOR
done

7 Step 5: Visualization for Integration

This final step generates plots that are crucial for comparing WES results with your scRNA-seq inferCNV and scevan outputs.

7.1 CNV Heatmap

A heatmap provides a genome-wide overview of copy number changes across all tumor samples, making it easy to spot shared alterations.

#!/bin/bash
# Load variables from the configuration chunk
source <(sed -n '/^#/,/USER-DEFINED/d;/^```{bash, chunk_name="configuration"}/,/^```/p' wes_analysis.Rmd | grep -v "```")

echo "--- Generating CNV heatmap ---"

$CNVKIT heatmap \
  $BASE_DIR/03_cnvkit_results/T1/*.cns \
  $BASE_DIR/03_cnvkit_results/X1/*.cns \
  $BASE_DIR/03_cnvkit_results/XX1/*.cns \
  -o $BASE_DIR/04_visualizations/CNV_heatmap.pdf

Interpretation: Compare the CNV_heatmap.pdf with your inferCNV heatmap. Consistent chromosomal gains (red) and losses (blue) between the bulk WES and single-cell data provide strong validation. This is key to confirming that the CNV events you see in the single cells are real and not computational artifacts.

7.2 OncoPrint of Somatic Mutations (R Script)

An OncoPrint is the standard way to visualize the landscape of somatic mutations across a cohort. The following R code chunk provides a template for creating one. You will need to parse your annotated VCF files to create the input matrix.

Note: This is an R code chunk. You will need to run this in an R environment with the ComplexHeatmap library installed (install.packages("ComplexHeatmap")).

# This chunk is set to 'eval=FALSE'. 
# You must run this code manually in your R console after installing packages.

# install.packages("vcfR")
# install.packages("ComplexHeatmap")
# BiocManager::install("ComplexHeatmap") # If not on CRAN

library(vcfR)
library(ComplexHeatmap)

# --- 1. Define a function to parse VCF and extract key mutations ---
# This is a simplified parser. You may want to add more filters (e.g., by allele frequency).
parse_mutect_vcf <- function(vcf_file, sample_name) {
  vcf <- read.vcfR(vcf_file)
  
  # Keep only PASS variants
  pass_vcf <- vcf[getFILTER(vcf) == "PASS", ]
  
  # Extract gene symbol and consequence from INFO field (VEP annotation)
  # The 'ANN' field format can vary, so you might need to adjust this.
  # Example format: Allele|Consequence|IMPACT|SYMBOL|...
  ann <- extract.info(pass_vcf, "ANN", as.is = TRUE)
  
  # A simple loop to get the most severe consequence per variant
  results <- lapply(ann, function(variant_ann) {
    # Split multiple annotations
    annotations <- strsplit(variant_ann, ",")[[1]]
    # Get the first annotation (often the most canonical)
    fields <- strsplit(annotations[1], "\\|")[[1]]
    
    consequence <- fields[2]
    gene <- fields[4]
    
    # Simplify consequences
    mut_type <- "other"
    if (grepl("missense", consequence)) mut_type <- "missense"
    if (grepl("frameshift|stop_gained|splice", consequence)) mut_type <- "truncating"
    
    return(data.frame(gene = gene, mut_type = mut_type, sample = sample_name))
  })
  
  # Combine results and remove empty entries
  df <- do.call(rbind, results)
  df <- df[df$gene != "", ]
  return(df)
}

# --- 2. Process each VCF file ---
vcf_dir <- "02_mutect2_results" # Relative to your R project directory
t1_muts <- parse_mutect_vcf(file.path(vcf_dir, "T1.somatic.annotated.vcf"), "T1")
x1_muts <- parse_mutect_vcf(file.path(vcf_dir, "X1.somatic.annotated.vcf"), "X1")
xx1_muts <- parse_mutect_vcf(file.path(vcf_dir, "XX1.somatic.annotated.vcf"), "XX1")

all_muts <- rbind(t1_muts, x1_muts, xx1_muts)

# --- 3. Create the matrix for OncoPrint ---
# Get unique genes and samples
genes <- unique(all_muts$gene)
samples <- c("T1", "X1", "XX1")

# Create an empty matrix
mat <- matrix("", nrow = length(genes), ncol = length(samples),
              dimnames = list(genes, samples))

# Populate the matrix
for (i in 1:nrow(all_muts)) {
  mat[all_muts$gene[i], all_muts$sample[i]] <- all_muts$mut_type[i]
}

# Optional: Filter for top mutated genes to make the plot readable
# For example, keep genes mutated in at least 2 samples
num_mutated <- rowSums(mat != "")
mat_filtered <- mat[num_mutated >= 1, ] # Keep genes mutated in at least one sample

# --- 4. Define the plotting style and create the OncoPrint ---
col <- c("truncating" = "maroon", "missense" = "royalblue")
alter_fun <- list(
    background = function(x, y, w, h) {
        grid.rect(x, y, w-unit(2, "pt"), h-unit(2, "pt"), 
                  gp = gpar(fill = "#e0e0e0", 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.4, 
                  gp = gpar(fill = col["missense"], col = NA))
    }
)

# Generate the plot
oncoPrint(mat_filtered,
          alter_fun = alter_fun, 
          col = col,
          row_order = sort(rownames(mat_filtered)),
          column_title = "Somatic Mutation Landscape in Patient 1 Samples")

# You can save this plot using ggsave or pdf() functions.

Interpretation: The OncoPrint will clearly show which genes are mutated in T1, X1, and XX1. This is your primary tool for confirming clonal relationships. If X1 and XX1 are indeed cell lines derived from Patient 1’s tumor (T1), they should share a substantial number of key driver mutations. ```

LS0tCnRpdGxlOiAiV0VTIFZBRiBBbmFseXNpczogUGF0aWVudDEgYW5kIENlbGwgTGluZXMiCmF1dGhvcjogIk5hc2lyIE1haG1vb2QgQWJiYXNpIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICB0aGVtZTogam91cm5hbAotLS0KCgoKKipCZWZvcmUgeW91IHJ1biB0aGlzLCBwbGVhc2UgcmVtZW1iZXI6KioKCjEuICAqKkRlcGVuZGVuY2llczoqKiBZb3UgbmVlZCB0byBoYXZlIGFsbCB0aGUgc29mdHdhcmUgaW5zdGFsbGVkIGFuZCBhdmFpbGFibGUgaW4geW91ciBzeXN0ZW0ncyBQQVRILiBUaGlzIGluY2x1ZGVzIGBid2FgLCBgc2FtdG9vbHNgLCBgcGljYXJkYCwgYGdhdGtgLCBgY252a2l0YCwgYW5kIGB2ZXBgLgoyLiAgKipSZWZlcmVuY2UgRmlsZXM6KiogWW91IG11c3QgZG93bmxvYWQgdGhlIHJlcXVpcmVkIHJlZmVyZW5jZSBmaWxlcyAoaHVtYW4gZ2Vub21lIEZBU1RBLCBkYlNOUCBWQ0YsIGdub21BRCBWQ0YsIGV0Yy4pIGFuZCB1cGRhdGUgdGhlIHBhdGhzIGluIHRoZSAiU2V0dXAgYW5kIENvbmZpZ3VyYXRpb24iIHNlY3Rpb24uCjMuICAqKkJBTSBGaWxlczoqKiBUaGUgcGlwZWxpbmUgYXNzdW1lcyB5b3Ugd2lsbCBzdGFydCB3aXRoIHRoZSBgc29ydGVkLmJhbWAgZmlsZXMgeW91IGhhdmUuIFRoZSBpbml0aWFsIHN0ZXBzIHdpbGwgY3JlYXRlIGFuYWx5c2lzLXJlYWR5IEJBTSBmaWxlcyAoYC5maW5hbC5iYW1gKS4KNC4gICoqRXhlY3V0aW9uOioqIFlvdSBjYW4gcnVuIGVhY2ggY2h1bmsgaW50ZXJhY3RpdmVseSBpbiBSU3R1ZGlvIG9yIHVzZSBga25pdHI6OnB1cmxgIHRvIGV4dHJhY3QgdGhlIHNoZWxsIGNvbW1hbmRzIGludG8gYSBzY3JpcHQgaWYgeW91IHByZWZlciB0byBydW4gaXQgZGlyZWN0bHkgaW4geW91ciB0ZXJtaW5hbC4KCkhlcmUgaXMgdGhlIFIgTWFya2Rvd24gZmlsZSBjb250ZW50OgoKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IHByb3ZpZGVzIGEgY29tcHJlaGVuc2l2ZSwgZW5kLXRvLWVuZCBiaW9pbmZvcm1hdGljcyBwaXBlbGluZSB0byBwcm9jZXNzIGFuZCBhbmFseXplIFdob2xlIEV4b21lIFNlcXVlbmNpbmcgKFdFUykgZGF0YSBmb3IgUGF0aWVudCAxLiBUaGUgZGF0YXNldCBpbmNsdWRlcyBhIG1hdGNoZWQgbm9ybWFsIHNhbXBsZSAoYE4xYCkgYW5kIHRocmVlIHR1bW9yL2NlbGwgbGluZSBzYW1wbGVzIChgVDFgLCBgWDFgLCBgWFgxYCkuCgpUaGUgcHJpbWFyeSBnb2FscyBvZiB0aGlzIGFuYWx5c2lzIGFyZToKMS4gIFRvIHBlcmZvcm0gcXVhbGl0eSBjb250cm9sIGFuZCBwcmUtcHJvY2Vzc2luZyBvbiB0aGUgZXhpc3RpbmcgQkFNIGZpbGVzLgoyLiAgVG8gY2FsbCBzb21hdGljIHNpbmdsZSBudWNsZW90aWRlIHZhcmlhbnRzIChTTlZzKSBhbmQgaW5zZXJ0aW9ucy9kZWxldGlvbnMgKGluZGVscykuCjMuICBUbyBpZGVudGlmeSBzb21hdGljIGNvcHkgbnVtYmVyIHZhcmlhdGlvbnMgKENOVnMpLgo0LiAgVG8gcHJvZHVjZSB2aXN1YWxpemF0aW9ucyB0aGF0IGNhbiBiZSBpbnRlZ3JhdGVkIHdpdGggYW5kIHVzZWQgdG8gdmFsaWRhdGUgZmluZGluZ3MgZnJvbSBzaW5nbGUtY2VsbCBSTkEgc2VxdWVuY2luZyBhbmFseXNlcyAoYGluZmVyQ05WYCwgYHNjZXZhbmApLgoKVGhpcyBwaXBlbGluZSBmb2xsb3dzIEdBVEsgQmVzdCBQcmFjdGljZXMgZm9yIHNvbWF0aWMgdmFyaWFudCBkaXNjb3ZlcnkgYW5kIHVzZXMgQ05Wa2l0IGZvciBDTlYgZGV0ZWN0aW9uLgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgU2V0IGRlZmF1bHQgb3B0aW9ucyBmb3IgY29kZSBjaHVua3MKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIGV2YWwgPSBGQUxTRSwgIyBJTVBPUlRBTlQ6IFNldCB0byBGQUxTRSB0byBwcmV2ZW50IGFjY2lkZW50YWwgZXhlY3V0aW9uIG9mIHRoZSBlbnRpcmUgcGlwZWxpbmUuCiAgZW5naW5lID0gImJhc2giICMgRGVmYXVsdCBlbmdpbmUgaXMgYmFzaAopCmBgYAoKIyBTdGVwIDA6IFNldHVwIGFuZCBDb25maWd1cmF0aW9uCgpUaGlzIGNodW5rIGRlZmluZXMgYWxsIHRoZSBuZWNlc3NhcnkgcGF0aHMgZm9yIHRvb2xzLCByZWZlcmVuY2UgZ2Vub21lcywgYW5kIGRhdGEuICoqWW91IG11c3QgZWRpdCB0aGVzZSBwYXRocyB0byBtYXRjaCB5b3VyIHN5c3RlbSdzIGNvbmZpZ3VyYXRpb24gYmVmb3JlIHJ1bm5pbmcgYW55IHBhcnQgb2YgdGhpcyBwaXBlbGluZS4qKgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImNvbmZpZ3VyYXRpb24ifQojIS9iaW4vYmFzaAojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgVVNFUi1ERUZJTkVEIFZBUklBQkxFUzogUExFQVNFIEVESVQgVEhFU0UgUEFUSFMKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBCYXNlIGRpcmVjdG9yeSB3aGVyZSBOMSwgVDEsIFgxLCBYWDEgZm9sZGVycyBhcmUgbG9jYXRlZApCQVNFX0RJUj0ifi8xLVRoZXNpc19GaW5hbF9ZZWFyXzIwMjUvMjAyNS1ZZWFyM19BbmFseXNpcy8xLXNjUk5BX1JFU1VMVFMtMTktMTEtMjAyNS8xNS1XRVNfUGF0aWVudDFfTDFfTDJfQW5hbHlzaXMtMTktMTEtMjAyNS9FeG9tZV9QYXRpZW50XzEiCgojIFJlZmVyZW5jZSBnZW5vbWUgZmlsZXMgKG11c3QgYmUgaW5kZXhlZCB3aXRoIC5mYWkgYW5kIC5kaWN0KQpSRUZfR0VOT01FPSIvcGF0aC90by95b3VyL3JlZmVyZW5jZS9oZzM4LmZhIgoKIyBLbm93biBzaXRlcyBWQ0ZzIGZvciBHQVRLCkRCU05QPSIvcGF0aC90by95b3VyL2Ric25wXzEzOC5oZzM4LnZjZi5neiIKR05PTUFEPSIvcGF0aC90by95b3VyL2FmLW9ubHktZ25vbWFkLmhnMzgudmNmLmd6IgoKIyBJbnRlcnZhbCBsaXN0IGZvciB0aGUgZXhvbWUgY2FwdHVyZSBraXQgdXNlZAojIFRoaXMgaXMgQ1JJVElDQUwgZm9yIGFjY3VyYXRlIENOViBhbmFseXNpcyBhbmQgdGFyZ2V0ZWQgdmFyaWFudCBjYWxsaW5nLgpJTlRFUlZBTF9MSVNUPSIvcGF0aC90by95b3VyL2V4b21lX2NhcHR1cmVfa2l0LmJlZCIgIyBDYW4gYmUgaW4gQkVEIG9yIFBpY2FyZCBpbnRlcnZhbF9saXN0IGZvcm1hdAoKIyBTb2Z0d2FyZSBwYXRocyAoaWYgbm90IGluIHN5c3RlbSBQQVRILCBwcm92aWRlIGZ1bGwgcGF0aCkKR0FUSz0iZ2F0ayIKUElDQVJEPSJwaWNhcmQiCkNOVktJVD0iY252a2l0LnB5IgpWRVBfUEFUSD0iL3BhdGgvdG8veW91ci9lbnNlbWJsLXZlcCIgIyBQYXRoIHRvIFZFUCBkaXJlY3RvcnkKCiMgQ3JlYXRlIG91dHB1dCBkaXJlY3Rvcmllcwpta2RpciAtcCAkQkFTRV9ESVIvMDFfcHJlcHJvY2Vzc2VkX2JhbXMKbWtkaXIgLXAgJEJBU0VfRElSLzAyX211dGVjdDJfcmVzdWx0cwpta2RpciAtcCAkQkFTRV9ESVIvMDNfY252a2l0X3Jlc3VsdHMKbWtkaXIgLXAgJEJBU0VfRElSLzA0X3Zpc3VhbGl6YXRpb25zCmBgYAoKIyBTdGVwIDE6IEJBTSBQcmUtcHJvY2Vzc2luZwoKVGhlIHByb3ZpZGVkIGBzb3J0ZWQuYmFtYCBmaWxlcyBhcmUgdGhlIHN0YXJ0aW5nIHBvaW50LiBXZSB3aWxsIHBlcmZvcm0gZHVwbGljYXRlIG1hcmtpbmcgYW5kIEJhc2UgUXVhbGl0eSBTY29yZSBSZWNhbGlicmF0aW9uIChCUVNSKSB0byBnZW5lcmF0ZSBhbmFseXNpcy1yZWFkeSBCQU0gZmlsZXMuCgojIyAgTWFyayBhbmQgUmVtb3ZlIFBDUiBEdXBsaWNhdGVzCgpEdXBsaWNhdGVzIGFyaXNlIGZyb20gUENSIGFtcGxpZmljYXRpb24gZHVyaW5nIGxpYnJhcnkgcHJlcGFyYXRpb24gYW5kIGNhbiBiaWFzIHZhcmlhbnQgY2FsbHMuIFdlIHVzZSBQaWNhcmQncyBgTWFya0R1cGxpY2F0ZXNgIHRvIGlkZW50aWZ5IGFuZCByZW1vdmUgdGhlbS4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJtYXJrX2R1cGxpY2F0ZXMifQojIS9iaW4vYmFzaAojIExvYWQgdmFyaWFibGVzIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24gY2h1bmsKc291cmNlIDwoc2VkIC1uICcvXiMvLC9VU0VSLURFRklORUQvZDsvXmBgYHtiYXNoLCBjaHVua19uYW1lPSJjb25maWd1cmF0aW9uIn0vLC9eYGBgL3AnIHdlc19hbmFseXNpcy5SbWQgfCBncmVwIC12ICJgYGAiKQoKZm9yIFNBTVBMRSBpbiBOMSBUMSBYMSBYWDE7IGRvCiAgZWNobyAiLS0tIE1hcmtpbmcgZHVwbGljYXRlcyBmb3IgJFNBTVBMRSAtLS0iCiAgCiAgSU5QVVRfQkFNPSIkQkFTRV9ESVIvJFNBTVBMRS9zb3J0ZWQuYmFtIgogIE9VVFBVVF9CQU09IiRCQVNFX0RJUi8wMV9wcmVwcm9jZXNzZWRfYmFtcy8ke1NBTVBMRX0uZGVkdXAuYmFtIgogIE1FVFJJQ1NfRklMRT0iJEJBU0VfRElSLzAxX3ByZXByb2Nlc3NlZF9iYW1zLyR7U0FNUExFfS5kZWR1cF9tZXRyaWNzLnR4dCIKICAKICBpZiBbIC1mICIkT1VUUFVUX0JBTSIgXTsgdGhlbgogICAgZWNobyAiJE9VVFBVVF9CQU0gYWxyZWFkeSBleGlzdHMsIHNraXBwaW5nLiIKICAgIGNvbnRpbnVlCiAgZmkKCiAgJFBJQ0FSRCBNYXJrRHVwbGljYXRlcyBcCiAgICBJPSRJTlBVVF9CQU0gXAogICAgTz0kT1VUUFVUX0JBTSBcCiAgICBNPSRNRVRSSUNTX0ZJTEUgXAogICAgUkVNT1ZFX0RVUExJQ0FURVM9dHJ1ZSBcCiAgICBDUkVBVEVfSU5ERVg9dHJ1ZSBcCiAgICBWQUxJREFUSU9OX1NUUklOR0VOQ1k9U0lMRU5UCmRvbmUKYGBgCgojIyAgQmFzZSBRdWFsaXR5IFNjb3JlIFJlY2FsaWJyYXRpb24gKEJRU1IpCgpCUVNSIGFkanVzdHMgYmFzZSBxdWFsaXR5IHNjb3JlcyB0byBjb3JyZWN0IGZvciBzeXN0ZW1hdGljIHRlY2huaWNhbCBlcnJvcnMgZnJvbSB0aGUgc2VxdWVuY2luZyBwcm9jZXNzLCBpbXByb3ZpbmcgdmFyaWFudCBjYWxsIGFjY3VyYWN5LgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImJxc3IifQojIS9iaW4vYmFzaAojIExvYWQgdmFyaWFibGVzIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24gY2h1bmsKc291cmNlIDwoc2VkIC1uICcvXiMvLC9VU0VSLURFRklORUQvZDsvXmBgYHtiYXNoLCBjaHVua19uYW1lPSJjb25maWd1cmF0aW9uIn0vLC9eYGBgL3AnIHdlc19hbmFseXNpcy5SbWQgfCBncmVwIC12ICJgYGAiKQoKZm9yIFNBTVBMRSBpbiBOMSBUMSBYMSBYWDE7IGRvCiAgZWNobyAiLS0tIFJ1bm5pbmcgQlFTUiBmb3IgJFNBTVBMRSAtLS0iCiAgCiAgREVEVVBfQkFNPSIkQkFTRV9ESVIvMDFfcHJlcHJvY2Vzc2VkX2JhbXMvJHtTQU1QTEV9LmRlZHVwLmJhbSIKICBSRUNBTF9UQUJMRT0iJEJBU0VfRElSLzAxX3ByZXByb2Nlc3NlZF9iYW1zLyR7U0FNUExFfS5yZWNhbF9kYXRhLnRhYmxlIgogIEZJTkFMX0JBTT0iJEJBU0VfRElSLzAxX3ByZXByb2Nlc3NlZF9iYW1zLyR7U0FNUExFfS5maW5hbC5iYW0iCgogIGlmIFsgLWYgIiRGSU5BTF9CQU0iIF07IHRoZW4KICAgIGVjaG8gIiRGSU5BTF9CQU0gYWxyZWFkeSBleGlzdHMsIHNraXBwaW5nLiIKICAgIGNvbnRpbnVlCiAgZmkKCiAgIyBTdGVwIDE6IEdlbmVyYXRlIHJlY2FsaWJyYXRpb24gdGFibGUKICAkR0FUSyBCYXNlUmVjYWxpYnJhdG9yIFwKICAgIC1SICRSRUZfR0VOT01FIFwKICAgIC1JICRERURVUF9CQU0gXAogICAgLS1rbm93bi1zaXRlcyAkREJTTlAgXAogICAgLU8gJFJFQ0FMX1RBQkxFCgogICMgU3RlcCAyOiBBcHBseSByZWNhbGlicmF0aW9uCiAgJEdBVEsgQXBwbHlCUVNSIFwKICAgIC1SICRSRUZfR0VOT01FIFwKICAgIC1JICRERURVUF9CQU0gXAogICAgLS1icXNyLXJlY2FsLWZpbGUgJFJFQ0FMX1RBQkxFIFwKICAgIC1PICRGSU5BTF9CQU0KZG9uZQpgYGAKCiMgU3RlcCAyOiBTb21hdGljIFZhcmlhbnQgQ2FsbGluZyAoTXV0ZWN0MikKCldlIHVzZSBHQVRLJ3MgTXV0ZWN0MiBpbiB0dW1vci1ub3JtYWwgbW9kZSB0byBjYWxsIHNvbWF0aWMgU05WcyBhbmQgaW5kZWxzIGZvciBlYWNoIHR1bW9yIHNhbXBsZSAoYFQxYCwgYFgxYCwgYFhYMWApIGFnYWluc3QgdGhlIG1hdGNoZWQgbm9ybWFsIChgTjFgKS4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJtdXRlY3QyIn0KIyEvYmluL2Jhc2gKIyBMb2FkIHZhcmlhYmxlcyBmcm9tIHRoZSBjb25maWd1cmF0aW9uIGNodW5rCnNvdXJjZSA8KHNlZCAtbiAnL14jLywvVVNFUi1ERUZJTkVEL2Q7L15gYGB7YmFzaCwgY2h1bmtfbmFtZT0iY29uZmlndXJhdGlvbiJ9LywvXmBgYC9wJyB3ZXNfYW5hbHlzaXMuUm1kIHwgZ3JlcCAtdiAiYGBgIikKCk5PUk1BTF9CQU09IiRCQVNFX0RJUi8wMV9wcmVwcm9jZXNzZWRfYmFtcy9OMS5maW5hbC5iYW0iCgpmb3IgVFVNT1IgaW4gVDEgWDEgWFgxOyBkbwogIGVjaG8gIi0tLSBDYWxsaW5nIHNvbWF0aWMgdmFyaWFudHMgZm9yICRUVU1PUiB2cyBOMSAtLS0iCiAgCiAgVFVNT1JfQkFNPSIkQkFTRV9ESVIvMDFfcHJlcHJvY2Vzc2VkX2JhbXMvJHtUVU1PUn0uZmluYWwuYmFtIgogIFZDRl9PVVQ9IiRCQVNFX0RJUi8wMl9tdXRlY3QyX3Jlc3VsdHMvJHtUVU1PUn0uc29tYXRpYy5yYXcudmNmLmd6IgogIAogIGlmIFsgLWYgIiRWQ0ZfT1VUIiBdOyB0aGVuCiAgICBlY2hvICIkVkNGX09VVCBhbHJlYWR5IGV4aXN0cywgc2tpcHBpbmcuIgogICAgY29udGludWUKICBmaQoKICAkR0FUSyBNdXRlY3QyIFwKICAgIC1SICRSRUZfR0VOT01FIFwKICAgIC1JICRUVU1PUl9CQU0gXAogICAgLUkgJE5PUk1BTF9CQU0gXAogICAgLW5vcm1hbCBOMSBcCiAgICAtLWdlcm1saW5lLXJlc291cmNlICRHTk9NQUQgXAogICAgLU8gJFZDRl9PVVQKZG9uZQpgYGAKCiMgU3RlcCAzOiBWYXJpYW50IEZpbHRlcmluZyBhbmQgQW5ub3RhdGlvbgoKUmF3IHZhcmlhbnQgY2FsbHMgbXVzdCBiZSBmaWx0ZXJlZCB0byByZW1vdmUgZmFsc2UgcG9zaXRpdmVzIGFuZCB0aGVuIGFubm90YXRlZCB0byBwcmVkaWN0IHRoZWlyIGZ1bmN0aW9uYWwgZWZmZWN0cy4KCiMjICBGaWx0ZXIgTXV0ZWN0MiBDYWxscwoKYEZpbHRlck11dGVjdENhbGxzYCBhcHBsaWVzIGEgc2VyaWVzIG9mIGZpbHRlcnMgdG8gdGhlIHJhdyBWQ0YgZnJvbSBNdXRlY3QyIHRvIGluY3JlYXNlIHByZWNpc2lvbi4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJmaWx0ZXJfbXV0ZWN0In0KIyEvYmluL2Jhc2gKIyBMb2FkIHZhcmlhYmxlcyBmcm9tIHRoZSBjb25maWd1cmF0aW9uIGNodW5rCnNvdXJjZSA8KHNlZCAtbiAnL14jLywvVVNFUi1ERUZJTkVEL2Q7L15gYGB7YmFzaCwgY2h1bmtfbmFtZT0iY29uZmlndXJhdGlvbiJ9LywvXmBgYC9wJyB3ZXNfYW5hbHlzaXMuUm1kIHwgZ3JlcCAtdiAiYGBgIikKCmZvciBUVU1PUiBpbiBUMSBYMSBYWDE7IGRvCiAgZWNobyAiLS0tIEZpbHRlcmluZyB2YXJpYW50IGNhbGxzIGZvciAkVFVNT1IgLS0tIgogIAogIFJBV19WQ0Y9IiRCQVNFX0RJUi8wMl9tdXRlY3QyX3Jlc3VsdHMvJHtUVU1PUn0uc29tYXRpYy5yYXcudmNmLmd6IgogIEZJTFRFUkVEX1ZDRj0iJEJBU0VfRElSLzAyX211dGVjdDJfcmVzdWx0cy8ke1RVTU9SfS5zb21hdGljLmZpbHRlcmVkLnZjZi5neiIKCiAgaWYgWyAtZiAiJEZJTFRFUkVEX1ZDRiIgXTsgdGhlbgogICAgZWNobyAiJEZJTFRFUkVEX1ZDRiBhbHJlYWR5IGV4aXN0cywgc2tpcHBpbmcuIgogICAgY29udGludWUKICBmaQoKICAkR0FUSyBGaWx0ZXJNdXRlY3RDYWxscyBcCiAgICAtUiAkUkVGX0dFTk9NRSBcCiAgICAtViAkUkFXX1ZDRiBcCiAgICAtTyAkRklMVEVSRURfVkNGCmRvbmUKYGBgCgojIyAgQW5ub3RhdGUgd2l0aCBFbnNlbWJsIFZFUAoKV2UgdXNlIEVuc2VtYmwgVmFyaWFudCBFZmZlY3QgUHJlZGljdG9yIChWRVApIHRvIGFubm90YXRlIHRoZSBmaWx0ZXJlZCB2YXJpYW50cyB3aXRoIGluZm9ybWF0aW9uIGFib3V0IGdlbmVzLCB0cmFuc2NyaXB0cywgYW5kIHByZWRpY3RlZCBwcm90ZWluLWxldmVsIGNvbnNlcXVlbmNlcy4KCmBgYHtiYXNoLCBjaHVua19uYW1lPSJ2ZXBfYW5ub3RhdGlvbiJ9CiMhL2Jpbi9iYXNoCiMgTG9hZCB2YXJpYWJsZXMgZnJvbSB0aGUgY29uZmlndXJhdGlvbiBjaHVuawpzb3VyY2UgPChzZWQgLW4gJy9eIy8sL1VTRVItREVGSU5FRC9kOy9eYGBge2Jhc2gsIGNodW5rX25hbWU9ImNvbmZpZ3VyYXRpb24ifS8sL15gYGAvcCcgd2VzX2FuYWx5c2lzLlJtZCB8IGdyZXAgLXYgImBgYCIpCgpmb3IgVFVNT1IgaW4gVDEgWDEgWFgxOyBkbwogIGVjaG8gIi0tLSBBbm5vdGF0aW5nIHZhcmlhbnRzIGZvciAkVFVNT1Igd2l0aCBWRVAgLS0tIgogIAogIEZJTFRFUkVEX1ZDRj0iJEJBU0VfRElSLzAyX211dGVjdDJfcmVzdWx0cy8ke1RVTU9SfS5zb21hdGljLmZpbHRlcmVkLnZjZi5neiIKICBBTk5PVEFURURfVkNGPSIkQkFTRV9ESVIvMDJfbXV0ZWN0Ml9yZXN1bHRzLyR7VFVNT1J9LnNvbWF0aWMuYW5ub3RhdGVkLnZjZiIKCiAgaWYgWyAtZiAiJEFOTk9UQVRFRF9WQ0YiIF07IHRoZW4KICAgIGVjaG8gIiRBTk5PVEFURURfVkNGIGFscmVhZHkgZXhpc3RzLCBza2lwcGluZy4iCiAgICBjb250aW51ZQogIGZpCgogICMgUnVuIFZFUC4gQXNzdW1lcyBWRVAgY2FjaGUgaXMgaW5zdGFsbGVkLgogICRWRVBfUEFUSC92ZXAgXAogICAgLS1pbnB1dF9maWxlICRGSUxURVJFRF9WQ0YgXAogICAgLS1vdXRwdXRfZmlsZSAkQU5OT1RBVEVEX1ZDRiBcCiAgICAtLWZvcm1hdCB2Y2YgXAogICAgLS12Y2YgXAogICAgLS1zeW1ib2wgXAogICAgLS10ZXJtcyBTTyBcCiAgICAtLXRzbCBcCiAgICAtLWhndnMgXAogICAgLS1mYXN0YSAkUkVGX0dFTk9NRSBcCiAgICAtLWNhY2hlIFwKICAgIC0tZm9yY2Vfb3ZlcndyaXRlCmRvbmUKYGBgCgojIFN0ZXAgNDogQ29weSBOdW1iZXIgVmFyaWF0aW9uIChDTlYpIEFuYWx5c2lzCgpXZSB1c2UgYENOVmtpdGAgdG8gZGV0ZWN0IHNvbWF0aWMgY29weSBudW1iZXIgY2hhbmdlcy4gSXQgYnVpbGRzIGEgcmVmZXJlbmNlIHByb2ZpbGUgZnJvbSB0aGUgbm9ybWFsIHNhbXBsZSBhbmQgdGhlbiBjYWxscyBnYWlucyBhbmQgbG9zc2VzIGluIHRoZSB0dW1vciBzYW1wbGVzIHJlbGF0aXZlIHRvIHRoYXQgcmVmZXJlbmNlLgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImNudmtpdCJ9CiMhL2Jpbi9iYXNoCiMgTG9hZCB2YXJpYWJsZXMgZnJvbSB0aGUgY29uZmlndXJhdGlvbiBjaHVuawpzb3VyY2UgPChzZWQgLW4gJy9eIy8sL1VTRVItREVGSU5FRC9kOy9eYGBge2Jhc2gsIGNodW5rX25hbWU9ImNvbmZpZ3VyYXRpb24ifS8sL15gYGAvcCcgd2VzX2FuYWx5c2lzLlJtZCB8IGdyZXAgLXYgImBgYCIpCgplY2hvICItLS0gUnVubmluZyBDTlZraXQgcGlwZWxpbmUgLS0tIgoKTk9STUFMX0JBTT0iJEJBU0VfRElSLzAxX3ByZXByb2Nlc3NlZF9iYW1zL04xLmZpbmFsLmJhbSIKUkVGRVJFTkNFX0NOTj0iJEJBU0VfRElSLzAzX2NudmtpdF9yZXN1bHRzL3JlZmVyZW5jZS5jbm4iCgojIFN0ZXAgNC4xOiBCdWlsZCB0aGUgcmVmZXJlbmNlIGZyb20gdGhlIG5vcm1hbCBzYW1wbGUKIyBJbiBhIHJlYWwtd29ybGQgc2NlbmFyaW8sIGEgcG9vbCBvZiBub3JtYWxzIGlzIGJldHRlciwgYnV0IG9uZSBpcyBzdWZmaWNpZW50LgokQ05WS0lUIGJhdGNoICROT1JNQUxfQkFNIFwKICAtLW5vcm1hbCBcCiAgLS10YXJnZXRzICRJTlRFUlZBTF9MSVNUIFwKICAtLWZhc3RhICRSRUZfR0VOT01FIFwKICAtLW91dHB1dC1yZWZlcmVuY2UgJFJFRkVSRU5DRV9DTk4gXAogIC0tb3V0cHV0LWRpciAkQkFTRV9ESVIvMDNfY252a2l0X3Jlc3VsdHMvTjEKCiMgU3RlcCA0LjI6IEFuYWx5emUgZWFjaCB0dW1vciBzYW1wbGUgYWdhaW5zdCB0aGUgcmVmZXJlbmNlCmZvciBUVU1PUiBpbiBUMSBYMSBYWDE7IGRvCiAgZWNobyAiLS0tIENhbGxpbmcgQ05WcyBmb3IgJFRVTU9SIC0tLSIKICBUVU1PUl9CQU09IiRCQVNFX0RJUi8wMV9wcmVwcm9jZXNzZWRfYmFtcy8ke1RVTU9SfS5maW5hbC5iYW0iCiAgCiAgJENOVktJVCBiYXRjaCAkVFVNT1JfQkFNIFwKICAgIC0tcmVmZXJlbmNlICRSRUZFUkVOQ0VfQ05OIFwKICAgIC0tb3V0cHV0LWRpciAkQkFTRV9ESVIvMDNfY252a2l0X3Jlc3VsdHMvJFRVTU9SCmRvbmUKYGBgCgojIFN0ZXAgNTogVmlzdWFsaXphdGlvbiBmb3IgSW50ZWdyYXRpb24KClRoaXMgZmluYWwgc3RlcCBnZW5lcmF0ZXMgcGxvdHMgdGhhdCBhcmUgY3J1Y2lhbCBmb3IgY29tcGFyaW5nIFdFUyByZXN1bHRzIHdpdGggeW91ciBzY1JOQS1zZXEgYGluZmVyQ05WYCBhbmQgYHNjZXZhbmAgb3V0cHV0cy4KCiMjICBDTlYgSGVhdG1hcAoKQSBoZWF0bWFwIHByb3ZpZGVzIGEgZ2Vub21lLXdpZGUgb3ZlcnZpZXcgb2YgY29weSBudW1iZXIgY2hhbmdlcyBhY3Jvc3MgYWxsIHR1bW9yIHNhbXBsZXMsIG1ha2luZyBpdCBlYXN5IHRvIHNwb3Qgc2hhcmVkIGFsdGVyYXRpb25zLgoKYGBge2Jhc2gsIGNodW5rX25hbWU9ImNudl9oZWF0bWFwIn0KIyEvYmluL2Jhc2gKIyBMb2FkIHZhcmlhYmxlcyBmcm9tIHRoZSBjb25maWd1cmF0aW9uIGNodW5rCnNvdXJjZSA8KHNlZCAtbiAnL14jLywvVVNFUi1ERUZJTkVEL2Q7L15gYGB7YmFzaCwgY2h1bmtfbmFtZT0iY29uZmlndXJhdGlvbiJ9LywvXmBgYC9wJyB3ZXNfYW5hbHlzaXMuUm1kIHwgZ3JlcCAtdiAiYGBgIikKCmVjaG8gIi0tLSBHZW5lcmF0aW5nIENOViBoZWF0bWFwIC0tLSIKCiRDTlZLSVQgaGVhdG1hcCBcCiAgJEJBU0VfRElSLzAzX2NudmtpdF9yZXN1bHRzL1QxLyouY25zIFwKICAkQkFTRV9ESVIvMDNfY252a2l0X3Jlc3VsdHMvWDEvKi5jbnMgXAogICRCQVNFX0RJUi8wM19jbnZraXRfcmVzdWx0cy9YWDEvKi5jbnMgXAogIC1vICRCQVNFX0RJUi8wNF92aXN1YWxpemF0aW9ucy9DTlZfaGVhdG1hcC5wZGYKYGBgCgoqKkludGVycHJldGF0aW9uOioqIENvbXBhcmUgdGhlIGBDTlZfaGVhdG1hcC5wZGZgIHdpdGggeW91ciBgaW5mZXJDTlZgIGhlYXRtYXAuIENvbnNpc3RlbnQgY2hyb21vc29tYWwgZ2FpbnMgKHJlZCkgYW5kIGxvc3NlcyAoYmx1ZSkgYmV0d2VlbiB0aGUgYnVsayBXRVMgYW5kIHNpbmdsZS1jZWxsIGRhdGEgcHJvdmlkZSBzdHJvbmcgdmFsaWRhdGlvbi4gVGhpcyBpcyBrZXkgdG8gY29uZmlybWluZyB0aGF0IHRoZSBDTlYgZXZlbnRzIHlvdSBzZWUgaW4gdGhlIHNpbmdsZSBjZWxscyBhcmUgcmVhbCBhbmQgbm90IGNvbXB1dGF0aW9uYWwgYXJ0aWZhY3RzLgoKIyMgIE9uY29QcmludCBvZiBTb21hdGljIE11dGF0aW9ucyAoUiBTY3JpcHQpCgpBbiBPbmNvUHJpbnQgaXMgdGhlIHN0YW5kYXJkIHdheSB0byB2aXN1YWxpemUgdGhlIGxhbmRzY2FwZSBvZiBzb21hdGljIG11dGF0aW9ucyBhY3Jvc3MgYSBjb2hvcnQuIFRoZSBmb2xsb3dpbmcgUiBjb2RlIGNodW5rIHByb3ZpZGVzIGEgdGVtcGxhdGUgZm9yIGNyZWF0aW5nIG9uZS4gWW91IHdpbGwgbmVlZCB0byBwYXJzZSB5b3VyIGFubm90YXRlZCBWQ0YgZmlsZXMgdG8gY3JlYXRlIHRoZSBpbnB1dCBtYXRyaXguCgoqKk5vdGU6KiogVGhpcyBpcyBhbiBSIGNvZGUgY2h1bmsuIFlvdSB3aWxsIG5lZWQgdG8gcnVuIHRoaXMgaW4gYW4gUiBlbnZpcm9ubWVudCB3aXRoIHRoZSBgQ29tcGxleEhlYXRtYXBgIGxpYnJhcnkgaW5zdGFsbGVkIChgaW5zdGFsbC5wYWNrYWdlcygiQ29tcGxleEhlYXRtYXAiKWApLgoKYGBge3IsIGVuZ2luZT0nUicsIGNodW5rX25hbWU9Im9uY29wcmludCIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVGhpcyBjaHVuayBpcyBzZXQgdG8gJ2V2YWw9RkFMU0UnLiAKIyBZb3UgbXVzdCBydW4gdGhpcyBjb2RlIG1hbnVhbGx5IGluIHlvdXIgUiBjb25zb2xlIGFmdGVyIGluc3RhbGxpbmcgcGFja2FnZXMuCgojIGluc3RhbGwucGFja2FnZXMoInZjZlIiKQojIGluc3RhbGwucGFja2FnZXMoIkNvbXBsZXhIZWF0bWFwIikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKSAjIElmIG5vdCBvbiBDUkFOCgpsaWJyYXJ5KHZjZlIpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCgojIC0tLSAxLiBEZWZpbmUgYSBmdW5jdGlvbiB0byBwYXJzZSBWQ0YgYW5kIGV4dHJhY3Qga2V5IG11dGF0aW9ucyAtLS0KIyBUaGlzIGlzIGEgc2ltcGxpZmllZCBwYXJzZXIuIFlvdSBtYXkgd2FudCB0byBhZGQgbW9yZSBmaWx0ZXJzIChlLmcuLCBieSBhbGxlbGUgZnJlcXVlbmN5KS4KcGFyc2VfbXV0ZWN0X3ZjZiA8LSBmdW5jdGlvbih2Y2ZfZmlsZSwgc2FtcGxlX25hbWUpIHsKICB2Y2YgPC0gcmVhZC52Y2ZSKHZjZl9maWxlKQogIAogICMgS2VlcCBvbmx5IFBBU1MgdmFyaWFudHMKICBwYXNzX3ZjZiA8LSB2Y2ZbZ2V0RklMVEVSKHZjZikgPT0gIlBBU1MiLCBdCiAgCiAgIyBFeHRyYWN0IGdlbmUgc3ltYm9sIGFuZCBjb25zZXF1ZW5jZSBmcm9tIElORk8gZmllbGQgKFZFUCBhbm5vdGF0aW9uKQogICMgVGhlICdBTk4nIGZpZWxkIGZvcm1hdCBjYW4gdmFyeSwgc28geW91IG1pZ2h0IG5lZWQgdG8gYWRqdXN0IHRoaXMuCiAgIyBFeGFtcGxlIGZvcm1hdDogQWxsZWxlfENvbnNlcXVlbmNlfElNUEFDVHxTWU1CT0x8Li4uCiAgYW5uIDwtIGV4dHJhY3QuaW5mbyhwYXNzX3ZjZiwgIkFOTiIsIGFzLmlzID0gVFJVRSkKICAKICAjIEEgc2ltcGxlIGxvb3AgdG8gZ2V0IHRoZSBtb3N0IHNldmVyZSBjb25zZXF1ZW5jZSBwZXIgdmFyaWFudAogIHJlc3VsdHMgPC0gbGFwcGx5KGFubiwgZnVuY3Rpb24odmFyaWFudF9hbm4pIHsKICAgICMgU3BsaXQgbXVsdGlwbGUgYW5ub3RhdGlvbnMKICAgIGFubm90YXRpb25zIDwtIHN0cnNwbGl0KHZhcmlhbnRfYW5uLCAiLCIpW1sxXV0KICAgICMgR2V0IHRoZSBmaXJzdCBhbm5vdGF0aW9uIChvZnRlbiB0aGUgbW9zdCBjYW5vbmljYWwpCiAgICBmaWVsZHMgPC0gc3Ryc3BsaXQoYW5ub3RhdGlvbnNbMV0sICJcXHwiKVtbMV1dCiAgICAKICAgIGNvbnNlcXVlbmNlIDwtIGZpZWxkc1syXQogICAgZ2VuZSA8LSBmaWVsZHNbNF0KICAgIAogICAgIyBTaW1wbGlmeSBjb25zZXF1ZW5jZXMKICAgIG11dF90eXBlIDwtICJvdGhlciIKICAgIGlmIChncmVwbCgibWlzc2Vuc2UiLCBjb25zZXF1ZW5jZSkpIG11dF90eXBlIDwtICJtaXNzZW5zZSIKICAgIGlmIChncmVwbCgiZnJhbWVzaGlmdHxzdG9wX2dhaW5lZHxzcGxpY2UiLCBjb25zZXF1ZW5jZSkpIG11dF90eXBlIDwtICJ0cnVuY2F0aW5nIgogICAgCiAgICByZXR1cm4oZGF0YS5mcmFtZShnZW5lID0gZ2VuZSwgbXV0X3R5cGUgPSBtdXRfdHlwZSwgc2FtcGxlID0gc2FtcGxlX25hbWUpKQogIH0pCiAgCiAgIyBDb21iaW5lIHJlc3VsdHMgYW5kIHJlbW92ZSBlbXB0eSBlbnRyaWVzCiAgZGYgPC0gZG8uY2FsbChyYmluZCwgcmVzdWx0cykKICBkZiA8LSBkZltkZiRnZW5lICE9ICIiLCBdCiAgcmV0dXJuKGRmKQp9CgojIC0tLSAyLiBQcm9jZXNzIGVhY2ggVkNGIGZpbGUgLS0tCnZjZl9kaXIgPC0gIjAyX211dGVjdDJfcmVzdWx0cyIgIyBSZWxhdGl2ZSB0byB5b3VyIFIgcHJvamVjdCBkaXJlY3RvcnkKdDFfbXV0cyA8LSBwYXJzZV9tdXRlY3RfdmNmKGZpbGUucGF0aCh2Y2ZfZGlyLCAiVDEuc29tYXRpYy5hbm5vdGF0ZWQudmNmIiksICJUMSIpCngxX211dHMgPC0gcGFyc2VfbXV0ZWN0X3ZjZihmaWxlLnBhdGgodmNmX2RpciwgIlgxLnNvbWF0aWMuYW5ub3RhdGVkLnZjZiIpLCAiWDEiKQp4eDFfbXV0cyA8LSBwYXJzZV9tdXRlY3RfdmNmKGZpbGUucGF0aCh2Y2ZfZGlyLCAiWFgxLnNvbWF0aWMuYW5ub3RhdGVkLnZjZiIpLCAiWFgxIikKCmFsbF9tdXRzIDwtIHJiaW5kKHQxX211dHMsIHgxX211dHMsIHh4MV9tdXRzKQoKIyAtLS0gMy4gQ3JlYXRlIHRoZSBtYXRyaXggZm9yIE9uY29QcmludCAtLS0KIyBHZXQgdW5pcXVlIGdlbmVzIGFuZCBzYW1wbGVzCmdlbmVzIDwtIHVuaXF1ZShhbGxfbXV0cyRnZW5lKQpzYW1wbGVzIDwtIGMoIlQxIiwgIlgxIiwgIlhYMSIpCgojIENyZWF0ZSBhbiBlbXB0eSBtYXRyaXgKbWF0IDwtIG1hdHJpeCgiIiwgbnJvdyA9IGxlbmd0aChnZW5lcyksIG5jb2wgPSBsZW5ndGgoc2FtcGxlcyksCiAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KGdlbmVzLCBzYW1wbGVzKSkKCiMgUG9wdWxhdGUgdGhlIG1hdHJpeApmb3IgKGkgaW4gMTpucm93KGFsbF9tdXRzKSkgewogIG1hdFthbGxfbXV0cyRnZW5lW2ldLCBhbGxfbXV0cyRzYW1wbGVbaV1dIDwtIGFsbF9tdXRzJG11dF90eXBlW2ldCn0KCiMgT3B0aW9uYWw6IEZpbHRlciBmb3IgdG9wIG11dGF0ZWQgZ2VuZXMgdG8gbWFrZSB0aGUgcGxvdCByZWFkYWJsZQojIEZvciBleGFtcGxlLCBrZWVwIGdlbmVzIG11dGF0ZWQgaW4gYXQgbGVhc3QgMiBzYW1wbGVzCm51bV9tdXRhdGVkIDwtIHJvd1N1bXMobWF0ICE9ICIiKQptYXRfZmlsdGVyZWQgPC0gbWF0W251bV9tdXRhdGVkID49IDEsIF0gIyBLZWVwIGdlbmVzIG11dGF0ZWQgaW4gYXQgbGVhc3Qgb25lIHNhbXBsZQoKIyAtLS0gNC4gRGVmaW5lIHRoZSBwbG90dGluZyBzdHlsZSBhbmQgY3JlYXRlIHRoZSBPbmNvUHJpbnQgLS0tCmNvbCA8LSBjKCJ0cnVuY2F0aW5nIiA9ICJtYXJvb24iLCAibWlzc2Vuc2UiID0gInJveWFsYmx1ZSIpCmFsdGVyX2Z1biA8LSBsaXN0KAogICAgYmFja2dyb3VuZCA9IGZ1bmN0aW9uKHgsIHksIHcsIGgpIHsKICAgICAgICBncmlkLnJlY3QoeCwgeSwgdy11bml0KDIsICJwdCIpLCBoLXVuaXQoMiwgInB0IiksIAogICAgICAgICAgICAgICAgICBncCA9IGdwYXIoZmlsbCA9ICIjZTBlMGUwIiwgY29sID0gTkEpKQogICAgfSwKICAgIHRydW5jYXRpbmcgPSBmdW5jdGlvbih4LCB5LCB3LCBoKSB7CiAgICAgICAgZ3JpZC5yZWN0KHgsIHksIHctdW5pdCgyLCAicHQiKSwgaC11bml0KDIsICJwdCIpLCAKICAgICAgICAgICAgICAgICAgZ3AgPSBncGFyKGZpbGwgPSBjb2xbInRydW5jYXRpbmciXSwgY29sID0gTkEpKQogICAgfSwKICAgIG1pc3NlbnNlID0gZnVuY3Rpb24oeCwgeSwgdywgaCkgewogICAgICAgIGdyaWQucmVjdCh4LCB5LCB3LXVuaXQoMiwgInB0IiksIGgqMC40LCAKICAgICAgICAgICAgICAgICAgZ3AgPSBncGFyKGZpbGwgPSBjb2xbIm1pc3NlbnNlIl0sIGNvbCA9IE5BKSkKICAgIH0KKQoKIyBHZW5lcmF0ZSB0aGUgcGxvdApvbmNvUHJpbnQobWF0X2ZpbHRlcmVkLAogICAgICAgICAgYWx0ZXJfZnVuID0gYWx0ZXJfZnVuLCAKICAgICAgICAgIGNvbCA9IGNvbCwKICAgICAgICAgIHJvd19vcmRlciA9IHNvcnQocm93bmFtZXMobWF0X2ZpbHRlcmVkKSksCiAgICAgICAgICBjb2x1bW5fdGl0bGUgPSAiU29tYXRpYyBNdXRhdGlvbiBMYW5kc2NhcGUgaW4gUGF0aWVudCAxIFNhbXBsZXMiKQoKIyBZb3UgY2FuIHNhdmUgdGhpcyBwbG90IHVzaW5nIGdnc2F2ZSBvciBwZGYoKSBmdW5jdGlvbnMuCmBgYAoKKipJbnRlcnByZXRhdGlvbjoqKiBUaGUgT25jb1ByaW50IHdpbGwgY2xlYXJseSBzaG93IHdoaWNoIGdlbmVzIGFyZSBtdXRhdGVkIGluIFQxLCBYMSwgYW5kIFhYMS4gVGhpcyBpcyB5b3VyIHByaW1hcnkgdG9vbCBmb3IgY29uZmlybWluZyBjbG9uYWwgcmVsYXRpb25zaGlwcy4gSWYgWDEgYW5kIFhYMSBhcmUgaW5kZWVkIGNlbGwgbGluZXMgZGVyaXZlZCBmcm9tIFBhdGllbnQgMSdzIHR1bW9yIChUMSksIHRoZXkgc2hvdWxkIHNoYXJlIGEgc3Vic3RhbnRpYWwgbnVtYmVyIG9mIGtleSBkcml2ZXIgbXV0YXRpb25zLgpgYGAKCgoKCgoKCgo=