This is part of the analysis pipeline for the hermes insertion mutagenesis in CNV strains experiment.

This includes 9 independent insertion experiments:

1657-1 and 1657-2 are biological replicates of the insertion mutagenesis performed on DGY1657, the ancestral euploid strain with a GAP1 CNV reporter.

This also includes the following technical replicates:

Library preps in France and NYC had slightly different protocols and sequencing set-ups - see methods. Each library prep was performed from a single DNA extraction, prepped once at a location, and then the same library prep was sequenced two times at the same facility.

Scripts must be run in the order shown in this notebook.

Clean Reads

Allowing More Variability at Beginning of Read

We search for the reads which have the expected Hermes TIR sequence following the primer. We then get rid of reads that have have the plasmid sequence (slightly different for each restriction enzyme) following the TIR ### For strains sequenced at BGI

bashbash

#!/bin/bash                     
#SBATCH --job-name=BGIcleanreads
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-2
#SBATCH --mem=8GB
#SBATCH --mail-type=END
#SBATCH -o bgiclean.%N.%j.out        # STDOUT
#SBATCH -e bgiclean.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

## get first set of fq files from BGI
V1_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*1.fq.gz))
V1_R2=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*2.fq.gz))

## get second set of fq files from BGI
V2_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/*/*1.fq.gz))
V2_R2=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/*/*2.fq.gz))


##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
V1R=${V1_R2[$SLURM_ARRAY_TASK_ID]}
V2F=${V2_R1[$SLURM_ARRAY_TASK_ID]}
V2R=${V2_R2[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:48:-41}

## make directories
mkdir bgi/v1_${NAME}
mkdir bgi/v2_${NAME}

## set seq & plasmid
PREINSERT=\Xtcataagtagcaagtggcgcataagtatcaaaataagccacttgttgttgttctctg\
PLASM=\^ggatcccccgggctgcaggaattcgatatcaagcttatcgata\
PLASM2=\^ggatcgttgtgctttcgctctccaaaagcataaggca\

    ## 3 successive cleaning steps
    ## - trim the plasmidic sequence before the insertion point, remove the untrimmed reads 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of 1 enzyme) 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of the other enzyme) 

module load cutadapt/1.16

## V1
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v1_${NAME}/${NAME}_F_trimmed_vOld.fq ${V1F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_F_cleanTmp_vOld.fq bgi/v1_${NAME}/${NAME}_F_trimmed_vOld.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_F_clean_vOld.fq bgi/v1_${NAME}/${NAME}_F_cleanTmp_vOld.fq

cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v1_${NAME}/${NAME}_R_trimmed_vOld.fq ${V1R}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_R_cleanTmp_vOld.fq bgi/v1_${NAME}/${NAME}_R_trimmed_vOld.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_R_clean_vOld.fq bgi/v1_${NAME}/${NAME}_R_cleanTmp_vOld.fq

## V2
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v2_${NAME}/${NAME}_F_trimmed_vOld.fq ${V2F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_F_cleanTmp_vOld.fq bgi/v2_${NAME}/${NAME}_F_trimmed_vOld.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_F_clean_vOld.fq bgi/v2_${NAME}/${NAME}_F_cleanTmp_vOld.fq


cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v2_${NAME}/${NAME}_R_trimmed_vOld.fq ${V2R}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_R_cleanTmp_vOld.fq bgi/v2_${NAME}/${NAME}_R_trimmed_vOld.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_R_clean_vOld.fq bgi/v2_${NAME}/${NAME}_R_cleanTmp_vOld.fq

For strains sequenced at NYC

bashbash

#!/bin/bash                     
#SBATCH --job-name=nyccleanreads
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=3
#SBATCH --array=0-8
#SBATCH --mem=10GB
#SBATCH --mail-type=END
#SBATCH -o nycclean.%N.%j.out        # STDOUT
#SBATCH -e nycclean.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

###THESE RUNS ONLY HAD R1####
## get  set of fq files from NYC Jan 2020
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))

##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

###GET BY REFERENCING NAME##
## get set of fq files from NYC Feb 2020
V2F=/scratch/cgsb/gencore/out/Gresham/2020-02-19_H2JHGAFX2/merged/*${NAME}*2.fastq.gz

##make a directory for this specific sample
mkdir nyc/v1_${NAME}
mkdir nyc/v2_${NAME}

## Not great manual step to remove directories for samples not sequenced in second run
rm -r nyc/v2_1728
rm -r nyc/v2_1736
rm -r nyc/v2_1740

## set seq & plasmid
PREINSERT=\XNNNNNNNtcataagtagcaagtggcgcataagtatcaaaataagccacttgttgttgttctctg\
PLASM=\^ggatcccccgggctgcaggaattcgatatcaagcttatcgata\
PLASM2=\^ggatcgttgtgctttcgctctccaaaagcataaggca\

    ## 3 successive cleaning steps
    ## - trim the plasmidic sequence before the insertion point, remove the untrimmed reads 
        ## in this version we also need to trim the N sequence added by the primer for base complexity
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of 1 enzyme) 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of the other enzyme) 

module load cutadapt/1.16

## V1
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o nyc/v1_${NAME}/${NAME}_F_trimmed_vOld.fq ${V1F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o nyc/v1_${NAME}/${NAME}_F_cleanTmp_vOld.fq nyc/v1_${NAME}/${NAME}_F_trimmed_vOld.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o nyc/v1_${NAME}/${NAME}_F_clean_vOld.fq nyc/v1_${NAME}/${NAME}_F_cleanTmp_vOld.fq

#if V2 exists do this
if [[ -d nyc/v2_${NAME} ]] 
then
  ## V2
  cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o nyc/v2_${NAME}/${NAME}_F_trimmed_vOld.fq ${V2F}
  cutadapt -g ${PLASM} -O 30 --discard-trimmed -o nyc/v2_${NAME}/${NAME}_F_cleanTmp_vOld.fq nyc/v2_${NAME}/${NAME}_F_trimmed_vOld.fq
  cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o nyc/v2_${NAME}/${NAME}_F_clean_vOld.fq nyc/v2_${NAME}/${NAME}_F_cleanTmp_vOld.fq
fi

Allowing Less Variability at Beginning of Read

For strains sequenced at BGI

bashbash

#!/bin/bash                     
#SBATCH --job-name=BGIcleanreads2
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-2
#SBATCH --mem=8GB
#SBATCH --mail-type=END
#SBATCH -o bgiclean2.%N.%j.out        # STDOUT
#SBATCH -e bgiclean2.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu
#SBATCH --dependency=afterok:8082091


## get first set of fq files from BGI
V1_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*1.fq.gz))
V1_R2=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*2.fq.gz))

## get second set of fq files from BGI
V2_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/*/*1.fq.gz))
V2_R2=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/*/*2.fq.gz))


##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
V1R=${V1_R2[$SLURM_ARRAY_TASK_ID]}
V2F=${V2_R1[$SLURM_ARRAY_TASK_ID]}
V2R=${V2_R2[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:48:-41}

## set seq & plasmid
PREINSERT=\^tcataagtagcaagtggcgcataagtatcaaaataagccacttgttgttgttctctg\
PLASM=\^ggatcccccgggctgcaggaattcgatatcaagcttatcgata\
PLASM2=\^ggatcgttgtgctttcgctctccaaaagcataaggca\

    ## 3 successive cleaning steps
    ## - trim the plasmidic sequence before the insertion point, remove the untrimmed reads 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of 1 enzyme) 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of the other enzyme) 

module load cutadapt/1.16

## V1
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v1_${NAME}/${NAME}_F_trimmed.fq ${V1F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_F_cleanTmp.fq bgi/v1_${NAME}/${NAME}_F_trimmed.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_F_clean.fq bgi/v1_${NAME}/${NAME}_F_cleanTmp.fq


cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v1_${NAME}/${NAME}_R_trimmed.fq ${V1R}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_R_cleanTmp.fq bgi/v1_${NAME}/${NAME}_R_trimmed.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v1_${NAME}/${NAME}_R_clean.fq bgi/v1_${NAME}/${NAME}_R_cleanTmp.fq

## V2
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v2_${NAME}/${NAME}_F_trimmed.fq ${V2F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_F_cleanTmp.fq bgi/v2_${NAME}/${NAME}_F_trimmed.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_F_clean.fq bgi/v2_${NAME}/${NAME}_F_cleanTmp.fq


cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o bgi/v2_${NAME}/${NAME}_R_trimmed.fq ${V2R}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_R_cleanTmp.fq bgi/v2_${NAME}/${NAME}_R_trimmed.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o bgi/v2_${NAME}/${NAME}_R_clean.fq bgi/v2_${NAME}/${NAME}_R_cleanTmp.fq

For strains sequenced at NYC

bashbash

#!/bin/bash                     
#SBATCH --job-name=Newcleanreads
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=3
#SBATCH --array=0-8
#SBATCH --mem=10GB
#SBATCH --mail-type=END
#SBATCH -o newclean.%N.%j.out        # STDOUT
#SBATCH -e newclean.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

###THESE RUNS ONLY HAD R1####
## get  set of fq files from NYC Jan 2020
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))

##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

###GET BY REFERENCING NAME##
## get set of fq files from NYC Feb 2020
V2F=/scratch/cgsb/gencore/out/Gresham/2020-02-19_H2JHGAFX2/merged/*${NAME}*2.fastq.gz

## set seq & plasmid
PREINSERT=\^NNNNNNNtcataagtagcaagtggcgcataagtatcaaaataagccacttgttgttgttctctg\
PLASM=\^ggatcccccgggctgcaggaattcgatatcaagcttatcgata\
PLASM2=\^ggatcgttgtgctttcgctctccaaaagcataaggca\

    ## 3 successive cleaning steps
    ## - trim the plasmidic sequence before the insertion point, remove the untrimmed reads 
            ## in this version we also need to trim the N sequence added by the primer for base complexity
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of 1 enzyme) 
    ## - remove reads that contains plasmidic sequences after the trimmed regions (in case of the other enzyme) 

module load cutadapt/1.16

## V1
cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o nyc/v1_${NAME}/${NAME}_F_trimmed.fq ${V1F}
cutadapt -g ${PLASM} -O 30 --discard-trimmed -o nyc/v1_${NAME}/${NAME}_F_cleanTmp.fq nyc/v1_${NAME}/${NAME}_F_trimmed.fq
cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o nyc/v1_${NAME}/${NAME}_F_clean.fq nyc/v1_${NAME}/${NAME}_F_cleanTmp.fq

#if V2 exits do this
if [[ -d nyc/v2_${NAME} ]]
then
  ## V2
  cutadapt -g ${PREINSERT} -O 40 --discard-untrimmed -o nyc/v2_${NAME}/${NAME}_F_trimmed.fq ${V2F}
  cutadapt -g ${PLASM} -O 30 --discard-trimmed -o nyc/v2_${NAME}/${NAME}_F_cleanTmp.fq nyc/v2_${NAME}/${NAME}_F_trimmed.fq
  cutadapt -g ${PLASM2} -O 30 --discard-trimmed -o nyc/v2_${NAME}/${NAME}_F_clean.fq nyc/v2_${NAME}/${NAME}_F_cleanTmp.fq
fi

Post Cleaning Read Treatment

For strains sequenced at BGI

launchReadsCleaningPostTreatment.sh

bashbash

#!/bin/bash                     
#SBATCH --job-name=BGIpost1
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=3
#SBATCH --array=0-2
#SBATCH --mem=50GB
#SBATCH --mail-type=END
#SBATCH -o postclean.%N.%j.out        # STDOUT
#SBATCH -e postclean.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

## remove temp files
rm bgi/v*/*cleanTmp*.fq

## get names of files
V1_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*1.fq.gz))
V1_R2=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*2.fq.gz))
V1_F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
V1_R=${V1_R2[$SLURM_ARRAY_TASK_ID]}
NAME=${V1_F:48:-41}

## TCATAAGTAGCAAGTGGCGC
PRIMER=\/scratch/ga824/hermes_insertions_semifinal_Mar20/onHPC_fastq_to_insertions_files/primer2_hermes.fasta\

for DIR in /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v1_${NAME}/ /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v2_${NAME}/
do
  cd \$DIR\
  
  ## get fqs for second sequencing run
  if [[ \$DIR\ == \/scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v2_${NAME}/\ ]]
  then
    V1F=$(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/${NAME}*/*1.fq.gz)
    V1R=$(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA_v2/${NAME}*/*2.fq.gz)
  else
    V1F=\$V1_F\
    V1R=\$V1_R\
  fi
  ## get clean ID from PE1 and PE2
  grep \:N:0$\ ${NAME}_F_clean.fq |awk '{print $1}'|sed -e 's/@//'> ${NAME}_IDlist
  grep \:N:0$\ ${NAME}_R_clean.fq |awk '{print $1}'|sed -e 's/@//'> ${NAME}_IDlist
  grep \:N:0$\ ${NAME}_F_clean_vOld.fq |awk '{print $1}'|sed -e 's/@//'> ${NAME}_vOld_IDlist
  grep \:N:0$\ ${NAME}_R_clean_vOld.fq |awk '{print $1}'|sed -e 's/@//'> ${NAME}_vOld_IDlist
    
  ## get the sequence of the 2nd of the pair
  zcat \$V1F\ | zgrep --no-group-separator -A 1 -Ff  ${NAME}_IDlist | sed -e 's/@/>/' > ${NAME}_1seqToTest 
  zcat \$V1R\ | grep --no-group-separator -A 1 -Ff  ${NAME}_IDlist |sed -e 's/@/>/'> ${NAME}_2seqToTest
  zcat \$V1F\ | zgrep --no-group-separator -A 1 -Ff  ${NAME}_vOld_IDlist | sed -e 's/@/>/' > ${NAME}_vOld_1seqToTest 
  zcat \$V1R\ | grep --no-group-separator -A 1 -Ff  ${NAME}_vOld_IDlist |sed -e 's/@/>/'> ${NAME}_vOld_2seqToTest

  ## merge these sequences
  cat ${NAME}_1seqToTest ${NAME}_2seqToTest |grep --no-group-separator -v -x \\^--\\ > ${NAME}_allSeqToTest.fasta
  cat ${NAME}_vOld_1seqToTest ${NAME}_vOld_2seqToTest |grep --no-group-separator -v -x \\^--\\ > ${NAME}_vOld_allSeqToTest.fasta


  ## blast these sequences vs the primer2 sequence
  module load blast+/2.8.1
  blastn -query ${NAME}_allSeqToTest.fasta -subject ${PRIMER} -task blastn-short -out ${NAME}_allSeqToTest_vsPrimer2.blastn -outfmt 6 -num_threads 3
  blastn -query ${NAME}_vOld_allSeqToTest.fasta -subject ${PRIMER} -task blastn-short -out ${NAME}_vOld_allSeqToTest_vsPrimer2.blastn -outfmt 6 -num_threads 3
  module purge

  ## get the ID of the ones with the primer2 sequence on the 2nd
  cat ${NAME}_allSeqToTest_vsPrimer2.blastn | awk '{print $1}'> ${NAME}_listToExtractFromClean 
  cat ${NAME}_vOld_allSeqToTest_vsPrimer2.blastn | awk '{print $1}'> ${NAME}_vOld_listToExtractFromClean 

  ## extract from the clean the ones with the primer2 on the 2nd
  cat ${NAME}_F_clean.fq ${NAME}_R_clean.fq |grep --no-group-separator -A 3 -Ff ${NAME}_listToExtractFromClean > ${NAME}_withP2.fq 
  cat ${NAME}_F_clean_vOld.fq ${NAME}_R_clean_vOld.fq |grep --no-group-separator -A 3 -Ff ${NAME}_vOld_listToExtractFromClean > ${NAME}_vOld_withP2.fq 
done

launchReadsCleaningPostTreatment2.sh

bashbash

#!/bin/bash                     
#SBATCH --job-name=BGIpost2
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-2
#SBATCH --mem=5GB
#SBATCH --mail-type=END
#SBATCH -o postclean2.%N.%j.out        # STDOUT
#SBATCH -e postclean2.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

## get names of files
V1_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*1.fq.gz))
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:48:-41}

for DIR in /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v1_${NAME}/ /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v2_${NAME}/
do
  cd \$DIR\
  ## get differential ID between clean and clean_vOld
  diff ${NAME}_listToExtractFromClean ${NAME}_vOld_listToExtractFromClean | grep \^> \ |sed -e 's/> //' > ${NAME}.diff
  ## get sequences based on differential ID between clean and clean_vOld 
  cat ${NAME}_vOld_withP2.fq |grep --no-group-separator -A 3 -Ff ${NAME}.diff > ${NAME}_all_withP2.fq 

  # fastqc report for all types of reads with P2
  module load fastqc/0.11.8 
  fastqc ${NAME}*_withP2.fq
done

launchReadsMinLength.sh

bashbash

#!/bin/bash                     
#SBATCH --job-name=BGImin
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-2
#SBATCH --mem=25GB
#SBATCH --mail-type=END
#SBATCH -o minlength.%N.%j.out        # STDOUT
#SBATCH -e minlength.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

V1_R1=($(ls /scratch/cgsb/gresham/grace-globus-share-dir/GA/*/*1.fq.gz))
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:48:-41}

for DIR in /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v1_${NAME}/ /scratch/ga824/hermes_insertions_semifinal_Mar20/bgi/v2_${NAME}/
do
  cd \$DIR\
  ## keep reads with a min length of 20 bp after all cleaning steps
  module load cutadapt/1.16
  cutadapt -m 30 -o ${NAME}_withP2_min20.fq ${NAME}_withP2.fq
  cutadapt -m 30 -o ${NAME}_vOld_withP2_min20.fq ${NAME}_vOld_withP2.fq
  cutadapt -m 30 -o ${NAME}_all_withP2_min20.fq ${NAME}_all_withP2.fq
done

For strains sequenced at NYC

NexteraReadsCleaningPostTreatment.sh

For the NextSeq runs, it is single ended. So we will just remove Nextera transposase sequences, do fastqc, and filter to keep only reads >20 bp

bashbash

#!/bin/bash                     
#SBATCH --job-name=nextera-clean
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=2
#SBATCH --array=0-8
#SBATCH --mem=20GB
#SBATCH --mail-type=END
#SBATCH -o nexteraclean.%N.%j.out        # STDOUT
#SBATCH -e nexteraclean.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

###THESE RUNS ONLY HAD R1####
## get  set of fq files from NYC Jan 2020
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))

##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

NEXTERA='/share/apps/trimmomatic/0.36/adapters/NexteraPE-PE.fa'

for DIR in /scratch/ga824/hermes_insertions_semifinal_Mar20/nyc/v1_${NAME}/ /scratch/ga824/hermes_insertions_semifinal_Mar20/nyc/v2_${NAME}/
do
  cd \$DIR\
  ## remove Nextera transposase sequence
  ## keep reads with a min length of 20 bp after all cleaning steps
  module load trimmomatic/0.36
  java -jar /share/apps/trimmomatic/0.36/trimmomatic-0.36.jar SE ${NAME}_F_clean_vOld.fq ${NAME}_vOld_min20.fq ILLUMINACLIP:${NEXTERA}:2:30:10 MINLEN:20 -trimlog ${NAME}_vOld_trimmomatic.log -threads 2
  java -jar /share/apps/trimmomatic/0.36/trimmomatic-0.36.jar SE ${NAME}_F_clean.fq ${NAME}_min20.fq ILLUMINACLIP:${NEXTERA}:2:30:10 MINLEN:20 -trimlog ${NAME}_trimmomatic.log -threads 2

  # fastqc report for all types of reads
  module load fastqc/0.11.8 
  fastqc *_min20.fq
done

Mapping

Single ended mapping for all reads, get only uniquely mapped reads.

bashbash

#!/bin/bash
#SBATCH --job-name=map
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-8
#SBATCH --mem=20GB
#SBATCH --mail-type=END
#SBATCH -o map.%N.%j.out        # STDOUT
#SBATCH -e map.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

###THESE RUNS ONLY HAD R1####
## get  set of fq files from NYC Jan 2020
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))

##this is going to assign the variables to file names
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}


REF=\/genomics/genomes/In_house/Fungi/Saccharomyces_cerevisiae/Gresham/GCF_000146045.2_R64_GAP1/GCF_000146045.2_R64_genomic_GAP1.fna\
GFF=\/genomics/genomes/In_house/Fungi/Saccharomyces_cerevisiae/Gresham/GCF_000146045.2_R64_GAP1/GCF_000146045.2_R64_genomic_GAP1.gff\

for DIR in /scratch/ga824/hermes_insertions_semifinal_Mar20/*/v*${NAME}/
do
  cd \$DIR\
  ## map
  module load bwa/intel/0.7.15
  if [[ \${DIR:49:3}\ == \bgi\ ]]
  then
    bwa mem -t 3 -a -M -R '@RG\tID:foo\tSM:bar' ${REF} ${NAME}_vOld_withP2_min20.fq > ${NAME}_mapped.sam
  else
    bwa mem -t 3 -a -M -R '@RG\tID:foo\tSM:bar' ${REF} ${NAME}_vOld_min20.fq > ${NAME}_mapped.sam
  fi
  
  module purge
  module load samtools/intel/1.9
  ##convert to bam
  ## q 10 to get uniquely mapped reads
  samtools view -bS -q 10 ${NAME}_mapped.sam > ${NAME}_mapped.bam

  ## get stats from alignment
  samtools flagstat ${NAME}_mapped.bam > ${NAME}_flagstat.txt
  samtools sort -o ${NAME}.sorted.bam ${NAME}_mapped.bam
  samtools index ${NAME}.sorted.bam
done

Insertion site identification

After mapping, insertion site identification is done one each sequencing run individually. This will allow us to determine correlation between library preps and sequencing runs. After mapping, bams from each run are also combined into one bam per sample, and insertion site identification is done on the combined bam. This makes down stream processing easier, as identical insertion sites identified from different sequencing runs will be automatically combined. ## Combine BAMs

bashbash

#!/bin/bash
#SBATCH --job-name=combine
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-8
#SBATCH --mem=10GB
#SBATCH --mail-type=END
#SBATCH -o merge.%N.%j.out        # STDOUT
#SBATCH -e merge.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu
#SBATCH --dependency=afterok:8385394

## get sample names
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

# get all bams for each sample
nyc_bams=nyc/v*${NAME}/${NAME}.sorted.bam
bgi_bams=bgi/v*${NAME}/${NAME}.sorted.bam
if [[ \${NAME}\ == \1728\ || \${NAME}\ == \1736\ || \${NAME}\ == \1740\ ]]
then
  all_bams=\$(echo $nyc_bams) $(echo $bgi_bams)\
else
  all_bams=$(echo $nyc_bams)
fi

##check to make sure everything is being correctly combined
echo $all_bams

##change to directory for this specific sample - COMBINED
mkdir combined/${NAME}/

module purge
module load samtools/intel/1.9
## merge bams
samtools merge combined/${NAME}/${NAME}_merged.bam $all_bams
samtools sort -o combined/${NAME}/${NAME}.sorted.bam combined/${NAME}/${NAME}_merged.bam
samtools index combined/${NAME}/${NAME}.sorted.bam

Parse BAMs

Batch file

bashbash

#!/bin/bash
#SBATCH --job-name=parsebam
#SBATCH --nodes=1
#SBATCH --mem=25GB
#SBATCH --cpus-per-task=5
#SBATCH --time=24:00:00
#SBATCH -o slurmParseBam.%N.%j.out        # STDOUT
#SBATCH -e slurmParseBam.%N.%j.err        # STDERR
#SBATCH --mail-user=ga824@nyu.edu
##SBATCH --dependency=afterok:

module load pysam/intel/0.11.2.2
module load samtools/intel/1.6
module load samblaster/intel/0.1.24
module load numpy/python2.7/intel/1.14.0 

function run_parallel ()
{
srun -n1 --exclusive \$@\
}
#run
for bam in /scratch/ga824/hermes_insertions_semifinal_Mar20/*/*/*sorted.bam
do
    run_parallel python2.7 parseBam.py $bam &
done
wait

Python file that actually does the parsing.

#/usr/bin/python
import sys,string,os,glob,random,pysam,re,argparse
##sys.path.insert(0, '/home/afriedrich/Scripts')
##import fasta,files


def parseBam(bamFile):
    pattern = re.compile("\s*")
    outfile = bamFile.replace(".sorted.bam","_insertionPos.txt")
    of = open(outfile,"w")
    samfile=pysam.AlignmentFile(bamFile,check_sq=False)
    chrom="chromosome1"
    listPos=[]
    count = 0
    for read in samfile.fetch():
        # write when changing chromosome
        if chrom != read.reference_name:
            for pos in sorted(listPos):
                of.write("%s\t%s\t%s\n" % (chrom,pos,pos))
            chrom=read.reference_name
                listPos=[]

        clipin5 = 0
        cigar = read.cigarstring

        # if softClipped 
        if cigar.find("S") != -1:
            # are the soft-clipped bases located at 5' end
            # if yes, will not be considered as an inserton position
            if read.is_reverse:
                if cigar.rfind("S")>cigar.find("M"):
                    clipin5 = 1
            else:
                if cigar.find("S")<cigar.find("M"):
                                        clipin5 = 1
        # if no softclipped in 5'
        if clipin5 == 0:
            if read.is_reverse:
                start = read.reference_end
            else:
                start = read.reference_start+1
            if int(start) not in listPos:
                listPos.append(int(start))
    # if no mismatch at the first position, should test 0 as firt (/last) character of the flag for reads in forward (/reverse)
    for pos in sorted(listPos):
        of.write("%s\t%s\t%s\n" % (chrom,pos,pos))
    samfile.close()
    of.close()


def getReadPerPos(bamFile):
    pattern = re.compile("\s*")
    outfile = bamFile.replace(".sorted.bam","_readPerPos.txt")
    of = open(outfile,"w")
        samfile=pysam.AlignmentFile(bamFile,"rb")
        chrom="chromosome1"
        listPos=[]
    listPosUniq=[]
        count = 0
        for read in samfile.fetch():
                if chrom != read.reference_name:
                        for pos in sorted(listPosUniq):
                of.write("%s\t%s\t%s\n" % (chrom,pos,listPos.count(pos)))
                        chrom=read.reference_name
                        listPos=[]
            listPosUniq=[]
        clipin5 = 0
                cigar = read.cigarstring
                # if softClipped 
                if cigar.find("S") != -1:
                        if read.is_reverse:
                                if cigar.rfind("S")>cigar.find("M"):
                                        clipin5 = 1
                        else:
                                if cigar.find("S")<cigar.find("M"):
                                        clipin5 = 1
                # if no softclipped in 5'
                if clipin5 == 0:
                        if read.is_reverse:
                start = read.reference_end
                        else:
                start = read.reference_start+1
            if int(start) not in listPosUniq:
                                listPosUniq.append(int(start))

            listPos.append(int(start))

        for pos in listPosUniq:
        of.write("%s\t%s\t%s\n" % (chrom,pos,listPos.count(pos)))

        samfile.close()
    of.close()




parser = argparse.ArgumentParser()
parser.add_argument("file")
args = parser.parse_args()

#args = sys.argv[1:]
#all_args = files.get_args(args)
#try:
#    seqf = all_args["f"]
#except:
#    seqf = ""
#try: 
#    seqo = all_args["o"]
#except:
#    seqo = ""
 
parseBam(args.file)
getReadPerPos(args.file)

Intersect BED

Batch script

#!/bin/bash
#SBATCH --nodes=1
#SBATCH --mem=15GB
#SBATCH --cpus-per-task=4
#SBATCH --time=24:00:00
#SBATCH -o intersectBed.%N.%j.out        # STDOUT
#SBATCH -e intersectBed.%N.%j.err        # STDERR
#SBATCH --mail-user=ga824@nyu.edu
#SBATCH --dependency=afterok:8212933

module load bedtools/intel/2.26.0 
GFF="/scratch/ga824/hermes_insertions_semifinal_Mar20/onHPC_fastq_to_insertions_files/GCF_000146045.2_R64_genomic_GAP1.gff"

function run_parallel ()
{
srun -n1 --exclusive "$@"
}

for inserPos in /scratch/ga824/hermes_insertions_semifinal_Mar20/*/*/*_insertionPos.txt
do
    outfile=${inserPos/.txt/_annotated.bed }
    run_parallel intersectBed -wb -a $inserPos -b ${GFF} > $outfile &

done
wait

A manual step to get CDS lines in bedfile and get rid of anything not in a CDS. A little embarassing but whatever

#!/bin/bash
#SBATCH --job-name=getcds
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --time=24:00:00
#SBATCH -o getCDS.%N.%j.out        # STDOUT
#SBATCH -e getCDS.%N.%j.err        # STDERR
#SBATCH --mail-user=ga824@nyu.edu
#SBATCH --array=0-8
##SBATCH --dependency=afterok:

## get sample names
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

for file in /scratch/ga824/hermes_insertions_semifinal_Mar20/*/*${NAME}/${NAME}_insertionPos_annotated.bed
do
  path=$(echo $file | cut -d'/' -f 1,2,3,4,5,6)
  grep CDS ${file} > $path/${NAME}_insertionPos_annotatedCDS.bed
  awk '$6 == "CDS"' $path/${NAME}_insertionPos_annotatedCDS.bed > $path/${NAME}_insertionPos_annotatedCDS1.bed
  mv $path/${NAME}_insertionPos_annotatedCDS1.bed $path/${NAME}_insertionPos_annotatedCDS.bed
done

Bed Post Treatment

Batch script

#!/bin/bash
#SBATCH --nodes=1
#SBATCH --mem=15GB
#SBATCH --cpus-per-task=3
#SBATCH --time=24:00:00
#SBATCH -o Bed.%N.%j.out        # STDOUT
#SBATCH -e Bed.%N.%j.err        # STDERR
#SBATCH --mail-type=END
#SBATCH --mail-user=ga824@nyu.edu
#SBATCH --dependency=afterok:7646598

module load pysam/intel/0.11.2.2
module load samtools/intel/1.6
module load samblaster/intel/0.1.24
module load numpy/python2.7/intel/1.14.0 

function run_parallel ()
{
srun -n1 --exclusive "$@"
}

for sample in /scratch/ga824/hermes_insertions_semifinal_Mar20/*/*/*_insertionPos_annotatedCDS.bed
do
    run_parallel python2.7 bedPostTreatment.py $sample &

done
wait

Python script

#/usr/bin/python
import sys,string,os,glob,random,pysam,re,argparse


def postTreatment(sample):
    print "getGeneList"
    geneList=getGeneList(sample)
    print "getInsertionPerGene"
    insPerGene=getInsertionPerGene(geneList)
    print "insertionPerKbPerGene"
    insertionPerKbPerGene(insPerGene)
    print "getNoInsGene"
    getNoInsGene(geneList)

def createLenDico(infile):
    dico = {}
        lines = open(infile,"r").read().split("\n")
        cds = ""
        length = ""
        for line in lines:
                if line != "":
            cds = line.split("\t")[0]
                        dico[cds] = int(line.split("\t")[1])
        return dico


def insertionPerKbPerGene(insFile):
    cdsLength="/scratch/ga824/hermes_insertions_semifinal_Mar20/onHPC_fastq_to_insertions_files/cdsLength.tab"
    dicoLen=createLenDico(cdsLength)
    #insFile="insertionPerGene-rel.tab"
    insKbFile=insFile.replace("PerGene.txt","PerKbPerGene.txt")
    of=open(insKbFile,"w")
    lines=open(insFile,"r").read().split("\n")
    for line in lines[1:]:
        if line != "":
            el=line.split("\t")
            of.write("%s\t%0.2f\n" % (el[0],float(el[1])*1000/dicoLen[el[0]]))
    of.close()

def removeRedundant():
    infile="listAllGenes.txt"
    outfile="listAllNRGenes.txt"
    of=open(outfile,"w")
    inList=open(infile,"r").read().split("\n")
    setUnique=set(inList)
    listUnique=list(setUnique)
    
    for gene in sorted(listUnique):
        if gene!="":
            of.write('%s\n'%gene)
    of.close()


def getGeneList(sample):
        bedfile=sample
    outfile=bedfile.replace("insertionPos_annotatedCDS.bed","genesWithInsertion.txt")
    of=open(outfile,"w")
    lines = open(bedfile,"r").read().split("\n")
    for line in lines:
        if line != "":
            el=line.split("\t")
            gene=el[11].split(";")[0].replace("Parent=","")
            of.write("%s\n" % gene)
    of.close()
    return outfile


def getInsertionPerGene(geneList):
        listSATAYGenes=open(geneList,"r").read().split("\n")
        listGenesWithInsertion=sorted(listSATAYGenes)
        setUniqueGenesWithInsertion=set(listGenesWithInsertion)
        listUniqueGenesWithInsertion=list(setUniqueGenesWithInsertion)
    outfile=geneList.replace("genesWithInsertion.txt","insertionPerGene.txt")
    of=open(outfile,"w")
    of.write("CDS\t#insertion\n")
        
        for cds in listUniqueGenesWithInsertion:
        if cds != "":
                of.write("%s\t%s\n" % (cds,listGenesWithInsertion.count(cds)))
    of.close()
    return outfile


def getNoInsGene(geneList):
    listAllGenes=open("/scratch/ga824/hermes_insertions_semifinal_Mar20/onHPC_fastq_to_insertions_files/listAllGenes.txt","r").read().split("\n")
    listSATAYGenes=open(geneList,"r").read().split("\n")
    outfile=geneList.replace("Insertion","NoInsertion")
    of=open(outfile,"w")
    listGenesWithInsertion=sorted(listSATAYGenes)
    #print listGenesWithInsertion
    setUniqueGenesWithInsertion=set(listGenesWithInsertion)
    listUniqueGenesWithInsertion=list(setUniqueGenesWithInsertion)
    
    #compare All genes and genes with at least 1 insertion
    #print "Genes with no insertion"
    for gene in listAllGenes:
        #print gene
        #if gene not in listUniqueGenesWithInsertion:
        if gene not in listGenesWithInsertion:
            #print "this one in not in the list"i
            of.write("%s\n" % gene)     
            #print gene
    of.close()


parser = argparse.ArgumentParser()
parser.add_argument("file")
args = parser.parse_args()

postTreatment(args.file)

Number of insertion sites over non overlapping windows of 100 basepairs over the genome

I am only doing this for the combined files

#!/bin/bash
#SBATCH --job-name=inWin
#SBATCH --time=24:00:00
#SBATCH --nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-8
#SBATCH --mem=10GB
#SBATCH --mail-type=END
#SBATCH -o inWindows.%N.%j.out        # STDOUT
#SBATCH -e inWindows.%N.%j.err     # STDERR
#SBATCH --mail-user=ga824@nyu.edu

## get sample names
V1_R1=($(ls /scratch/cgsb/gencore/out/Gresham/2020-01-10_HV2J2BGXC/merged/HV2J2BGXC_n01*2.fastq.gz))
V1F=${V1_R1[$SLURM_ARRAY_TASK_ID]}
NAME=${V1F:76:-23}

#get the windows files
WINDOWS='/scratch/ga824/hermes_wgs/bed_windows/GCF_000146045.2_R64_genomic_GAP1.windows'

#get number unique insertion sites per window
module load bedtools/intel/2.27.1
bedtools coverage -counts -sorted -a $WINDOWS -b /scratch/ga824/hermes_insertions_semifinal_Mar20/combined/${NAME}/${NAME}_insertionPos.txt > /scratch/ga824/hermes_insertions_semifinal_Mar20/combined/${NAME}/${NAME}_insertionWindows.cov

Outputs from this script that are inputs into next (R based) analysis script

Each of the following is output for each sample: * fastqc files for each sequencing run * readPerPos.txt * insertionPos.txt * genesWithNoInsertion.txt * insertionPerGene.txt * insertionPerKbPerGene.txt * genesWithInsertion.txt * insertionPos_annotatedCDS.bed ? * insertionPos_annotated.bed ? * insertionWindows.cov (only done for combined)

LS0tCnRpdGxlOiAiSGVybWVzIGluc2VydGlvbiBsaWJyYXJ5IGFuYWx5c2lzIC0gZmFzdHEgdG8gaW5zZXJ0aW9uIHBvc2l0aW9ucyIKYXV0aG9yOiAiR3JhY2UgQXZlY2lsbGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KClRoaXMgaXMgcGFydCBvZiB0aGUgYW5hbHlzaXMgcGlwZWxpbmUgZm9yIHRoZSBoZXJtZXMgaW5zZXJ0aW9uIG11dGFnZW5lc2lzIGluIENOViBzdHJhaW5zIGV4cGVyaW1lbnQuCgpUaGlzIGluY2x1ZGVzIDkgaW5kZXBlbmRlbnQgaW5zZXJ0aW9uIGV4cGVyaW1lbnRzOiAgCgoqIDE2NTctMSBhLmsuYS4gZXVwbG9pZC0xCiogMTY1Ny0yIGEuay5hLiBldXBsb2lkLTIKKiAxNzI4IGEuay5hLiBDTlYtQQoqIDE3MzQgYS5rLmEuIENOVi1CCiogMTczNiBhLmsuYS4gQ05WLUMKKiAxNzQwIGEuay5hLiBDTlYtRAoqIDE3NDQgYS5rLmEuIENOVi1FCiogMTc0NyBhLmsuYS4gQ05WLUYKKiAxNzUxIGEuay5hLiBDTlYtRwoKMTY1Ny0xIGFuZCAxNjU3LTIgYXJlIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBvZiB0aGUgaW5zZXJ0aW9uIG11dGFnZW5lc2lzIHBlcmZvcm1lZCBvbiBER1kxNjU3LCB0aGUgYW5jZXN0cmFsIGV1cGxvaWQgc3RyYWluIHdpdGggYSAqR0FQMSogQ05WIHJlcG9ydGVyLgoKVGhpcyBhbHNvIGluY2x1ZGVzIHRoZSBmb2xsb3dpbmcgdGVjaG5pY2FsIHJlcGxpY2F0ZXM6ICAKCiogMTcyOCwgcHJlcGFyZWQgaW4gRnJhbmNlLCBzZXF1ZW5jZWQgYXQgQkdJIGZpcnN0IHRpbWUKKiAxNzI4LCBwcmVwYXJlZCBpbiBGcmFuY2UsIHNlcXVlbmNlZCBhdCBCR0kgc2Vjb25kIHRpbWUKKiAxNzM2LCBwcmVwYXJlZCBpbiBGcmFuY2UsIHNlcXVlbmNlZCBhdCBCR0kgZmlyc3QgdGltZQoqIDE3MzYsIHByZXBhcmVkIGluIEZyYW5jZSwgc2VxdWVuY2VkIGF0IEJHSSBzZWNvbmQgdGltZQoqIDE3NDAsIHByZXBhcmVkIGluIEZyYW5jZSwgc2VxdWVuY2VkIGF0IEJHSSBmaXJzdCB0aW1lCiogMTc0MCwgcHJlcGFyZWQgaW4gRnJhbmNlLCBzZXF1ZW5jZWQgYXQgQkdJIHNlY29uZCB0aW1lCgoKKiAxNjU3LTEsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTY1Ny0xLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNjU3LTIsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTY1Ny0yLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNzI4LCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3MjgsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBzZWNvbmQgdGltZQoqIDE3MzQsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTczNCwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIHNlY29uZCB0aW1lCiogMTczNiwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIGZpcnN0IHRpbWUKKiAxNzQwLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3NDQsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTc0NCwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIHNlY29uZCB0aW1lCiogMTc0NywgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIGZpcnN0IHRpbWUKKiAxNzQ3LCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNzUxLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3NTEsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBzZWNvbmQgdGltZQoKKkxpYnJhcnkgcHJlcHMgaW4gRnJhbmNlIGFuZCBOWUMgaGFkIHNsaWdodGx5IGRpZmZlcmVudCBwcm90b2NvbHMgYW5kIHNlcXVlbmNpbmcgc2V0LXVwcyAtIHNlZSBtZXRob2RzLiBFYWNoIGxpYnJhcnkgcHJlcCB3YXMgcGVyZm9ybWVkIGZyb20gYSBzaW5nbGUgRE5BIGV4dHJhY3Rpb24sIHByZXBwZWQgb25jZSBhdCBhIGxvY2F0aW9uLCBhbmQgdGhlbiB0aGUgc2FtZSBsaWJyYXJ5IHByZXAgd2FzIHNlcXVlbmNlZCB0d28gdGltZXMgYXQgdGhlIHNhbWUgZmFjaWxpdHkuKgoKCioqU2NyaXB0cyBtdXN0IGJlIHJ1biBpbiB0aGUgb3JkZXIgc2hvd24gaW4gdGhpcyBub3RlYm9vay4qKgoKIyBDbGVhbiBSZWFkcwojIyBBbGxvd2luZyBNb3JlIFZhcmlhYmlsaXR5IGF0IEJlZ2lubmluZyBvZiBSZWFkCldlIHNlYXJjaCBmb3IgdGhlIHJlYWRzIHdoaWNoIGhhdmUgdGhlIGV4cGVjdGVkIEhlcm1lcyBUSVIgc2VxdWVuY2UgZm9sbG93aW5nIHRoZSBwcmltZXIuIFdlIHRoZW4gZ2V0IHJpZCBvZiByZWFkcyB0aGF0IGhhdmUgaGF2ZSB0aGUgcGxhc21pZCBzZXF1ZW5jZSAoc2xpZ2h0bHkgZGlmZmVyZW50IGZvciBlYWNoIHJlc3RyaWN0aW9uIGVuenltZSkgZm9sbG93aW5nIHRoZSBUSVIKIyMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKYGBge2Jhc2ggQkdJSGlTZXFSZWFkc0NsZWFuaW5nX3ZPbGQuc2h9CiMhL2Jpbi9iYXNoICAgICAgICAgICAgICAgICAgICAgCiNTQkFUQ0ggLS1qb2ItbmFtZT1CR0ljbGVhbnJlYWRzCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtMgojU0JBVENIIC0tbWVtPThHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIGJnaWNsZWFuLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBiZ2ljbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMgZ2V0IGZpcnN0IHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0EvKi8qMi5mcS5neikpCgojIyBnZXQgc2Vjb25kIHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMl9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQV92Mi8qLyoxLmZxLmd6KSkKVjJfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvKi8qMi5mcS5neikpCgoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpWMVI9JHtWMV9SMlskU0xVUk1fQVJSQVlfVEFTS19JRF19ClYyRj0ke1YyX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjJSPSR7VjJfUjJbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCiMjIG1ha2UgZGlyZWN0b3JpZXMKbWtkaXIgYmdpL3YxXyR7TkFNRX0KbWtkaXIgYmdpL3YyXyR7TkFNRX0KCiMjIHNldCBzZXEgJiBwbGFzbWlkClBSRUlOU0VSVD0iWHRjYXRhYWd0YWdjYWFndGdnY2djYXRhYWd0YXRjYWFhYXRhYWdjY2FjdHRndHRndHRndHRjdGN0ZyIKUExBU009Il5nZ2F0Y2NjY2NnZ2djdGdjYWdnYWF0dGNnYXRhdGNhYWdjdHRhdGNnYXRhIgpQTEFTTTI9Il5nZ2F0Y2d0dGd0Z2N0dHRjZ2N0Y3RjY2FhYWFnY2F0YWFnZ2NhIgoKICAgICMjIDMgc3VjY2Vzc2l2ZSBjbGVhbmluZyBzdGVwcwogICAgIyMgLSB0cmltIHRoZSBwbGFzbWlkaWMgc2VxdWVuY2UgYmVmb3JlIHRoZSBpbnNlcnRpb24gcG9pbnQsIHJlbW92ZSB0aGUgdW50cmltbWVkIHJlYWRzIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjFGfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcQoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcSAke1YxUn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEKCiMjIFYyCmN1dGFkYXB0IC1nICR7UFJFSU5TRVJUfSAtTyA0MCAtLWRpc2NhcmQtdW50cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEgJHtWMkZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEKY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhbl92T2xkLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxCgoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcSAke1YyUn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEKYGBgCgojIyMgRm9yIHN0cmFpbnMgc2VxdWVuY2VkIGF0IE5ZQwpgYGB7YmFzaCBOZXh0U2VxUmVhZHNDbGVhbmluZ192T2xkLnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9bnljY2xlYW5yZWFkcwojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0zCiNTQkFUQ0ggLS1hcnJheT0wLTgKI1NCQVRDSCAtLW1lbT0xMEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gbnljY2xlYW4uJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIG55Y2NsZWFuLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyNUSEVTRSBSVU5TIE9OTFkgSEFEIFIxIyMjIwojIyBnZXQgIHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBKYW4gMjAyMApWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMS0xMF9IVjJKMkJHWEMvbWVyZ2VkL0hWMkoyQkdYQ19uMDEqMi5mYXN0cS5neikpCgojI3RoaXMgaXMgZ29pbmcgdG8gYXNzaWduIHRoZSB2YXJpYWJsZXMgdG8gZmlsZSBuYW1lcwpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKIyMjR0VUIEJZIFJFRkVSRU5DSU5HIE5BTUUjIwojIyBnZXQgc2V0IG9mIGZxIGZpbGVzIGZyb20gTllDIEZlYiAyMDIwClYyRj0vc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMi0xOV9IMkpIR0FGWDIvbWVyZ2VkLyoke05BTUV9KjIuZmFzdHEuZ3oKCiMjbWFrZSBhIGRpcmVjdG9yeSBmb3IgdGhpcyBzcGVjaWZpYyBzYW1wbGUKbWtkaXIgbnljL3YxXyR7TkFNRX0KbWtkaXIgbnljL3YyXyR7TkFNRX0KCiMjIE5vdCBncmVhdCBtYW51YWwgc3RlcCB0byByZW1vdmUgZGlyZWN0b3JpZXMgZm9yIHNhbXBsZXMgbm90IHNlcXVlbmNlZCBpbiBzZWNvbmQgcnVuCnJtIC1yIG55Yy92Ml8xNzI4CnJtIC1yIG55Yy92Ml8xNzM2CnJtIC1yIG55Yy92Ml8xNzQwCgojIyBzZXQgc2VxICYgcGxhc21pZApQUkVJTlNFUlQ9IlhOTk5OTk5OdGNhdGFhZ3RhZ2NhYWd0Z2djZ2NhdGFhZ3RhdGNhYWFhdGFhZ2NjYWN0dGd0dGd0dGd0dGN0Y3RnIgpQTEFTTT0iXmdnYXRjY2NjY2dnZ2N0Z2NhZ2dhYXR0Y2dhdGF0Y2FhZ2N0dGF0Y2dhdGEiClBMQVNNMj0iXmdnYXRjZ3R0Z3RnY3R0dGNnY3RjdGNjYWFhYWdjYXRhYWdnY2EiCgogICAgIyMgMyBzdWNjZXNzaXZlIGNsZWFuaW5nIHN0ZXBzCiAgICAjIyAtIHRyaW0gdGhlIHBsYXNtaWRpYyBzZXF1ZW5jZSBiZWZvcmUgdGhlIGluc2VydGlvbiBwb2ludCwgcmVtb3ZlIHRoZSB1bnRyaW1tZWQgcmVhZHMgCiAgICAgICAgIyMgaW4gdGhpcyB2ZXJzaW9uIHdlIGFsc28gbmVlZCB0byB0cmltIHRoZSBOIHNlcXVlbmNlIGFkZGVkIGJ5IHRoZSBwcmltZXIgZm9yIGJhc2UgY29tcGxleGl0eQogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjFGfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcQoKI2lmIFYyIGV4aXN0cyBkbyB0aGlzCmlmIFtbIC1kIG55Yy92Ml8ke05BTUV9IF1dIAp0aGVuCiAgIyMgVjIKICBjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBueWMvdjJfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjJGfQogIGN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEKICBjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuX3ZPbGQuZnEgbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wX3ZPbGQuZnEKZmkKYGBgCgoKIyMgQWxsb3dpbmcgTGVzcyBWYXJpYWJpbGl0eSBhdCBCZWdpbm5pbmcgb2YgUmVhZAoKIyMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKYGBge2Jhc2ggQkdJSGlTZXFSZWFkc0NsZWFuaW5nLnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9QkdJY2xlYW5yZWFkczIKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MQojU0JBVENIIC0tYXJyYXk9MC0yCiNTQkFUQ0ggLS1tZW09OEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gYmdpY2xlYW4yLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBiZ2ljbGVhbjIuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazo4MDgyMDkxCgoKIyMgZ2V0IGZpcnN0IHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0EvKi8qMi5mcS5neikpCgojIyBnZXQgc2Vjb25kIHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMl9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQV92Mi8qLyoxLmZxLmd6KSkKVjJfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvKi8qMi5mcS5neikpCgoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpWMVI9JHtWMV9SMlskU0xVUk1fQVJSQVlfVEFTS19JRF19ClYyRj0ke1YyX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjJSPSR7VjJfUjJbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCiMjIHNldCBzZXEgJiBwbGFzbWlkClBSRUlOU0VSVD0iXnRjYXRhYWd0YWdjYWFndGdnY2djYXRhYWd0YXRjYWFhYXRhYWdjY2FjdHRndHRndHRndHRjdGN0ZyIKUExBU009Il5nZ2F0Y2NjY2NnZ2djdGdjYWdnYWF0dGNnYXRhdGNhYWdjdHRhdGNnYXRhIgpQTEFTTTI9Il5nZ2F0Y2d0dGd0Z2N0dHRjZ2N0Y3RjY2FhYWFnY2F0YWFnZ2NhIgoKICAgICMjIDMgc3VjY2Vzc2l2ZSBjbGVhbmluZyBzdGVwcwogICAgIyMgLSB0cmltIHRoZSBwbGFzbWlkaWMgc2VxdWVuY2UgYmVmb3JlIHRoZSBpbnNlcnRpb24gcG9pbnQsIHJlbW92ZSB0aGUgdW50cmltbWVkIHJlYWRzIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcSAke1YxRn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW4uZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxCgoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWQuZnEgJHtWMVJ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fUl9jbGVhblRtcC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X1JfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuLmZxIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fUl9jbGVhblRtcC5mcQoKIyMgVjIKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMkZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcSBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcQoKCmN1dGFkYXB0IC1nICR7UFJFSU5TRVJUfSAtTyA0MCAtLWRpc2NhcmQtdW50cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fUl90cmltbWVkLmZxICR7VjJSfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X1JfY2xlYW5UbXAuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWQuZnEKY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fUl9jbGVhbi5mcSBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X1JfY2xlYW5UbXAuZnEKYGBgCgojIyMgRm9yIHN0cmFpbnMgc2VxdWVuY2VkIGF0IE5ZQwpgYGB7YmFzaCBOZXh0U2VxUmVhZHNDbGVhbmluZy5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPU5ld2NsZWFucmVhZHMKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tYXJyYXk9MC04CiNTQkFUQ0ggLS1tZW09MTBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIG5ld2NsZWFuLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBuZXdjbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMjVEhFU0UgUlVOUyBPTkxZIEhBRCBSMSMjIyMKIyMgZ2V0ICBzZXQgb2YgZnEgZmlsZXMgZnJvbSBOWUMgSmFuIDIwMjAKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCiMjI0dFVCBCWSBSRUZFUkVOQ0lORyBOQU1FIyMKIyMgZ2V0IHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBGZWIgMjAyMApWMkY9L3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDItMTlfSDJKSEdBRlgyL21lcmdlZC8qJHtOQU1FfSoyLmZhc3RxLmd6CgojIyBzZXQgc2VxICYgcGxhc21pZApQUkVJTlNFUlQ9Il5OTk5OTk5OdGNhdGFhZ3RhZ2NhYWd0Z2djZ2NhdGFhZ3RhdGNhYWFhdGFhZ2NjYWN0dGd0dGd0dGd0dGN0Y3RnIgpQTEFTTT0iXmdnYXRjY2NjY2dnZ2N0Z2NhZ2dhYXR0Y2dhdGF0Y2FhZ2N0dGF0Y2dhdGEiClBMQVNNMj0iXmdnYXRjZ3R0Z3RnY3R0dGNnY3RjdGNjYWFhYWdjYXRhYWdnY2EiCgogICAgIyMgMyBzdWNjZXNzaXZlIGNsZWFuaW5nIHN0ZXBzCiAgICAjIyAtIHRyaW0gdGhlIHBsYXNtaWRpYyBzZXF1ZW5jZSBiZWZvcmUgdGhlIGluc2VydGlvbiBwb2ludCwgcmVtb3ZlIHRoZSB1bnRyaW1tZWQgcmVhZHMgCiAgICAgICAgICAgICMjIGluIHRoaXMgdmVyc2lvbiB3ZSBhbHNvIG5lZWQgdG8gdHJpbSB0aGUgTiBzZXF1ZW5jZSBhZGRlZCBieSB0aGUgcHJpbWVyIGZvciBiYXNlIGNvbXBsZXhpdHkKICAgICMjIC0gcmVtb3ZlIHJlYWRzIHRoYXQgY29udGFpbnMgcGxhc21pZGljIHNlcXVlbmNlcyBhZnRlciB0aGUgdHJpbW1lZCByZWdpb25zIChpbiBjYXNlIG9mIDEgZW56eW1lKSAKICAgICMjIC0gcmVtb3ZlIHJlYWRzIHRoYXQgY29udGFpbnMgcGxhc21pZGljIHNlcXVlbmNlcyBhZnRlciB0aGUgdHJpbW1lZCByZWdpb25zIChpbiBjYXNlIG9mIHRoZSBvdGhlciBlbnp5bWUpCQoKbW9kdWxlIGxvYWQgY3V0YWRhcHQvMS4xNgoKIyMgVjEKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gbnljL3YxXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMUZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92MV8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuLmZxIG55Yy92MV8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcQoKI2lmIFYyIGV4aXRzIGRvIHRoaXMKaWYgW1sgLWQgbnljL3YyXyR7TkFNRX0gXV0KdGhlbgogICMjIFYyCiAgY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMkZ9CiAgY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkLmZxCiAgY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhbi5mcSBueWMvdjJfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXAuZnEKZmkKYGBgCgoKIyBQb3N0IENsZWFuaW5nIFJlYWQgVHJlYXRtZW50CiMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKIyMjIGxhdW5jaFJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50LnNoCmBgYHtiYXNoIEJHSVJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50LnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9QkdJcG9zdDEKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tYXJyYXk9MC0yCiNTQkFUQ0ggLS1tZW09NTBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIHBvc3RjbGVhbi4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgcG9zdGNsZWFuLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyByZW1vdmUgdGVtcCBmaWxlcwpybSBiZ2kvdiovKmNsZWFuVG1wKi5mcQoKIyMgZ2V0IG5hbWVzIG9mIGZpbGVzClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBLyovKjEuZnEuZ3opKQpWMV9SMj0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoyLmZxLmd6KSkKVjFfRj0ke1YxX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjFfUj0ke1YxX1IyWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KTkFNRT0ke1YxX0Y6NDg6LTQxfQoKIyMgVENBVEFBR1RBR0NBQUdUR0dDR0MKUFJJTUVSPSIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvb25IUENfZmFzdHFfdG9faW5zZXJ0aW9uc19maWxlcy9wcmltZXIyX2hlcm1lcy5mYXN0YSIKCmZvciBESVIgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwL2JnaS92MV8ke05BTUV9LyAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vCmRvCiAgY2QgIiRESVIiCiAgCiAgIyMgZ2V0IGZxcyBmb3Igc2Vjb25kIHNlcXVlbmNpbmcgcnVuCiAgaWYgW1sgIiRESVIiID09ICIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vIiBdXQogIHRoZW4KICAgIFYxRj0kKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBX3YyLyR7TkFNRX0qLyoxLmZxLmd6KQogICAgVjFSPSQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvJHtOQU1FfSovKjIuZnEuZ3opCiAgZWxzZQogICAgVjFGPSIkVjFfRiIKICAgIFYxUj0iJFYxX1IiCiAgZmkKICAjIyBnZXQgY2xlYW4gSUQgZnJvbSBQRTEgYW5kIFBFMgogIGdyZXAgIjpOOjAkIiAke05BTUV9X0ZfY2xlYW4uZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fSURsaXN0CiAgZ3JlcCAiOk46MCQiICR7TkFNRX1fUl9jbGVhbi5mcSB8YXdrICd7cHJpbnQgJDF9J3xzZWQgLWUgJ3MvQC8vJz4gJHtOQU1FfV9JRGxpc3QKICBncmVwICI6TjowJCIgJHtOQU1FfV9GX2NsZWFuX3ZPbGQuZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fdk9sZF9JRGxpc3QKICBncmVwICI6TjowJCIgJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fdk9sZF9JRGxpc3QKCQogICMjIGdldCB0aGUgc2VxdWVuY2Ugb2YgdGhlIDJuZCBvZiB0aGUgcGFpcgogIHpjYXQgIiRWMUYiIHwgemdyZXAgLS1uby1ncm91cC1zZXBhcmF0b3IgLUEgMSAtRmYgICR7TkFNRX1fSURsaXN0IHwgc2VkIC1lICdzL0AvPi8nID4gJHtOQU1FfV8xc2VxVG9UZXN0IAogIHpjYXQgIiRWMVIiIHwgZ3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV9JRGxpc3QgfHNlZCAtZSAncy9ALz4vJz4gJHtOQU1FfV8yc2VxVG9UZXN0CiAgemNhdCAiJFYxRiIgfCB6Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV92T2xkX0lEbGlzdCB8IHNlZCAtZSAncy9ALz4vJyA+ICR7TkFNRX1fdk9sZF8xc2VxVG9UZXN0IAogIHpjYXQgIiRWMVIiIHwgZ3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV92T2xkX0lEbGlzdCB8c2VkIC1lICdzL0AvPi8nPiAke05BTUV9X3ZPbGRfMnNlcVRvVGVzdAoKICAjIyBtZXJnZSB0aGVzZSBzZXF1ZW5jZXMKICBjYXQgJHtOQU1FfV8xc2VxVG9UZXN0ICR7TkFNRX1fMnNlcVRvVGVzdCB8Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtdiAteCBcIl4tLVwiID4gJHtOQU1FfV9hbGxTZXFUb1Rlc3QuZmFzdGEKICBjYXQgJHtOQU1FfV92T2xkXzFzZXFUb1Rlc3QgJHtOQU1FfV92T2xkXzJzZXFUb1Rlc3QgfGdyZXAgLS1uby1ncm91cC1zZXBhcmF0b3IgLXYgLXggXCJeLS1cIiA+ICR7TkFNRX1fdk9sZF9hbGxTZXFUb1Rlc3QuZmFzdGEKCgogICMjIGJsYXN0IHRoZXNlIHNlcXVlbmNlcyB2cyB0aGUgcHJpbWVyMiBzZXF1ZW5jZQogIG1vZHVsZSBsb2FkIGJsYXN0Ky8yLjguMQogIGJsYXN0biAtcXVlcnkgJHtOQU1FfV9hbGxTZXFUb1Rlc3QuZmFzdGEgLXN1YmplY3QgJHtQUklNRVJ9IC10YXNrIGJsYXN0bi1zaG9ydCAtb3V0ICR7TkFNRX1fYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gLW91dGZtdCA2IC1udW1fdGhyZWFkcyAzCiAgYmxhc3RuIC1xdWVyeSAke05BTUV9X3ZPbGRfYWxsU2VxVG9UZXN0LmZhc3RhIC1zdWJqZWN0ICR7UFJJTUVSfSAtdGFzayBibGFzdG4tc2hvcnQgLW91dCAke05BTUV9X3ZPbGRfYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gLW91dGZtdCA2IC1udW1fdGhyZWFkcyAzCiAgbW9kdWxlIHB1cmdlCgogICMjIGdldCB0aGUgSUQgb2YgdGhlIG9uZXMgd2l0aCB0aGUgcHJpbWVyMiBzZXF1ZW5jZSBvbiB0aGUgMm5kCiAgY2F0ICR7TkFNRX1fYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gfCBhd2sgJ3twcmludCAkMX0nPiAke05BTUV9X2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gCiAgY2F0ICR7TkFNRX1fdk9sZF9hbGxTZXFUb1Rlc3RfdnNQcmltZXIyLmJsYXN0biB8IGF3ayAne3ByaW50ICQxfSc+ICR7TkFNRX1fdk9sZF9saXN0VG9FeHRyYWN0RnJvbUNsZWFuIAoKICAjIyBleHRyYWN0IGZyb20gdGhlIGNsZWFuIHRoZSBvbmVzIHdpdGggdGhlIHByaW1lcjIgb24gdGhlIDJuZAogIGNhdCAke05BTUV9X0ZfY2xlYW4uZnEgJHtOQU1FfV9SX2NsZWFuLmZxIHxncmVwIC0tbm8tZ3JvdXAtc2VwYXJhdG9yIC1BIDMgLUZmICR7TkFNRX1fbGlzdFRvRXh0cmFjdEZyb21DbGVhbiA+ICR7TkFNRX1fd2l0aFAyLmZxIAogIGNhdCAke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSAke05BTUV9X1JfY2xlYW5fdk9sZC5mcSB8Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAzIC1GZiAke05BTUV9X3ZPbGRfbGlzdFRvRXh0cmFjdEZyb21DbGVhbiA+ICR7TkFNRX1fdk9sZF93aXRoUDIuZnEgCmRvbmUKYGBgCgojIyMgbGF1bmNoUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQyLnNoCmBgYHtiYXNoIEJHSVJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50Mi5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPUJHSXBvc3QyCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtMgojU0JBVENIIC0tbWVtPTVHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIHBvc3RjbGVhbjIuJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIHBvc3RjbGVhbjIuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKCiMjIGdldCBuYW1lcyBvZiBmaWxlcwpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCmZvciBESVIgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwL2JnaS92MV8ke05BTUV9LyAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vCmRvCiAgY2QgIiRESVIiCiAgIyMgZ2V0IGRpZmZlcmVudGlhbCBJRCBiZXR3ZWVuIGNsZWFuIGFuZCBjbGVhbl92T2xkCiAgZGlmZiAke05BTUV9X2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gJHtOQU1FfV92T2xkX2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gfCBncmVwICJePiAiIHxzZWQgLWUgJ3MvPiAvLycgPiAke05BTUV9LmRpZmYKICAjIyBnZXQgc2VxdWVuY2VzIGJhc2VkIG9uIGRpZmZlcmVudGlhbCBJRCBiZXR3ZWVuIGNsZWFuIGFuZCBjbGVhbl92T2xkIAogIGNhdCAke05BTUV9X3ZPbGRfd2l0aFAyLmZxIHxncmVwIC0tbm8tZ3JvdXAtc2VwYXJhdG9yIC1BIDMgLUZmICR7TkFNRX0uZGlmZiA+ICR7TkFNRX1fYWxsX3dpdGhQMi5mcSAKCiAgIyBmYXN0cWMgcmVwb3J0IGZvciBhbGwgdHlwZXMgb2YgcmVhZHMgd2l0aCBQMgogIG1vZHVsZSBsb2FkIGZhc3RxYy8wLjExLjggCiAgZmFzdHFjICR7TkFNRX0qX3dpdGhQMi5mcQpkb25lCmBgYAoKIyMjIGxhdW5jaFJlYWRzTWluTGVuZ3RoLnNoIApgYGB7YmFzaCBsYXVuY2hSZWFkc01pbkxlbmd0aC5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPUJHSW1pbgojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS1hcnJheT0wLTIKI1NCQVRDSCAtLW1lbT0yNUdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gbWlubGVuZ3RoLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBtaW5sZW5ndGguJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBLyovKjEuZnEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NDg6LTQxfQoKZm9yIERJUiBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YxXyR7TkFNRX0vIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9iZ2kvdjJfJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyBrZWVwIHJlYWRzIHdpdGggYSBtaW4gbGVuZ3RoIG9mIDIwIGJwIGFmdGVyIGFsbCBjbGVhbmluZyBzdGVwcwogIG1vZHVsZSBsb2FkIGN1dGFkYXB0LzEuMTYKICBjdXRhZGFwdCAtbSAzMCAtbyAke05BTUV9X3dpdGhQMl9taW4yMC5mcSAke05BTUV9X3dpdGhQMi5mcQogIGN1dGFkYXB0IC1tIDMwIC1vICR7TkFNRX1fdk9sZF93aXRoUDJfbWluMjAuZnEgJHtOQU1FfV92T2xkX3dpdGhQMi5mcQogIGN1dGFkYXB0IC1tIDMwIC1vICR7TkFNRX1fYWxsX3dpdGhQMl9taW4yMC5mcSAke05BTUV9X2FsbF93aXRoUDIuZnEKZG9uZQpgYGAKCgojIyBGb3Igc3RyYWlucyBzZXF1ZW5jZWQgYXQgTllDCiMjIyBOZXh0ZXJhUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQuc2ggCkZvciB0aGUgTmV4dFNlcSBydW5zLCBpdCBpcyBzaW5nbGUgZW5kZWQuIFNvIHdlIHdpbGwganVzdCByZW1vdmUgTmV4dGVyYSB0cmFuc3Bvc2FzZSBzZXF1ZW5jZXMsIGRvIGZhc3RxYywgYW5kIGZpbHRlciB0byBrZWVwIG9ubHkgcmVhZHMgPjIwIGJwCgpgYGB7YmFzaCBOZXh0ZXJhUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQuc2h9CiMhL2Jpbi9iYXNoICAgICAgICAgICAgICAgICAgICAgCiNTQkFUQ0ggLS1qb2ItbmFtZT1uZXh0ZXJhLWNsZWFuCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTIKI1NCQVRDSCAtLWFycmF5PTAtOAojU0JBVENIIC0tbWVtPTIwR0IKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtbyBuZXh0ZXJhY2xlYW4uJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIG5leHRlcmFjbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMjVEhFU0UgUlVOUyBPTkxZIEhBRCBSMSMjIyMKIyMgZ2V0ICBzZXQgb2YgZnEgZmlsZXMgZnJvbSBOWUMgSmFuIDIwMjAKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCk5FWFRFUkE9Jy9zaGFyZS9hcHBzL3RyaW1tb21hdGljLzAuMzYvYWRhcHRlcnMvTmV4dGVyYVBFLVBFLmZhJwoKZm9yIERJUiBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvbnljL3YxXyR7TkFNRX0vIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9ueWMvdjJfJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyByZW1vdmUgTmV4dGVyYSB0cmFuc3Bvc2FzZSBzZXF1ZW5jZQogICMjIGtlZXAgcmVhZHMgd2l0aCBhIG1pbiBsZW5ndGggb2YgMjAgYnAgYWZ0ZXIgYWxsIGNsZWFuaW5nIHN0ZXBzCiAgbW9kdWxlIGxvYWQgdHJpbW1vbWF0aWMvMC4zNgogIGphdmEgLWphciAvc2hhcmUvYXBwcy90cmltbW9tYXRpYy8wLjM2L3RyaW1tb21hdGljLTAuMzYuamFyIFNFICR7TkFNRX1fRl9jbGVhbl92T2xkLmZxICR7TkFNRX1fdk9sZF9taW4yMC5mcSBJTExVTUlOQUNMSVA6JHtORVhURVJBfToyOjMwOjEwIE1JTkxFTjoyMCAtdHJpbWxvZyAke05BTUV9X3ZPbGRfdHJpbW1vbWF0aWMubG9nIC10aHJlYWRzIDIKICBqYXZhIC1qYXIgL3NoYXJlL2FwcHMvdHJpbW1vbWF0aWMvMC4zNi90cmltbW9tYXRpYy0wLjM2LmphciBTRSAke05BTUV9X0ZfY2xlYW4uZnEgJHtOQU1FfV9taW4yMC5mcSBJTExVTUlOQUNMSVA6JHtORVhURVJBfToyOjMwOjEwIE1JTkxFTjoyMCAtdHJpbWxvZyAke05BTUV9X3RyaW1tb21hdGljLmxvZyAtdGhyZWFkcyAyCgogICMgZmFzdHFjIHJlcG9ydCBmb3IgYWxsIHR5cGVzIG9mIHJlYWRzCiAgbW9kdWxlIGxvYWQgZmFzdHFjLzAuMTEuOCAKICBmYXN0cWMgKl9taW4yMC5mcQpkb25lCmBgYAoKIyBNYXBwaW5nClNpbmdsZSBlbmRlZCBtYXBwaW5nIGZvciBhbGwgcmVhZHMsIGdldCBvbmx5IHVuaXF1ZWx5IG1hcHBlZCByZWFkcy4KYGBge2Jhc2ggTWFwcGluZ1NFX21lbS1hRm9yTXVsdGltYXBwZWQuc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1tYXAKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MQojU0JBVENIIC0tYXJyYXk9MC04CiNTQkFUQ0ggLS1tZW09MjBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIG1hcC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgbWFwLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyNUSEVTRSBSVU5TIE9OTFkgSEFEIFIxIyMjIwojIyBnZXQgIHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBKYW4gMjAyMApWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMS0xMF9IVjJKMkJHWEMvbWVyZ2VkL0hWMkoyQkdYQ19uMDEqMi5mYXN0cS5neikpCgojI3RoaXMgaXMgZ29pbmcgdG8gYXNzaWduIHRoZSB2YXJpYWJsZXMgdG8gZmlsZSBuYW1lcwpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKClJFRj0iL2dlbm9taWNzL2dlbm9tZXMvSW5faG91c2UvRnVuZ2kvU2FjY2hhcm9teWNlc19jZXJldmlzaWFlL0dyZXNoYW0vR0NGXzAwMDE0NjA0NS4yX1I2NF9HQVAxL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLmZuYSIKR0ZGPSIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvb25IUENfZmFzdHFfdG9faW5zZXJ0aW9uc19maWxlcy9HQ0ZfMDAwMTQ2MDQ1LjJfUjY0X2dlbm9taWNfR0FQMS5nZmYiCgpmb3IgRElSIGluIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC8qL3YqJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyBtYXAKICBtb2R1bGUgbG9hZCBid2EvaW50ZWwvMC43LjE1CiAgaWYgW1sgIiR7RElSOjQ5OjN9IiA9PSAiYmdpIiBdXQogIHRoZW4KICAgIGJ3YSBtZW0gLXQgMyAtYSAtTSAtUiAnQFJHXHRJRDpmb29cdFNNOmJhcicgJHtSRUZ9ICR7TkFNRX1fdk9sZF93aXRoUDJfbWluMjAuZnEgPiAke05BTUV9X21hcHBlZC5zYW0KICBlbHNlCiAgICBid2EgbWVtIC10IDMgLWEgLU0gLVIgJ0BSR1x0SUQ6Zm9vXHRTTTpiYXInICR7UkVGfSAke05BTUV9X3ZPbGRfbWluMjAuZnEgPiAke05BTUV9X21hcHBlZC5zYW0KICBmaQogIAogIG1vZHVsZSBwdXJnZQogIG1vZHVsZSBsb2FkIHNhbXRvb2xzL2ludGVsLzEuOQogICMjY29udmVydCB0byBiYW0KICAjIyBxIDEwIHRvIGdldCB1bmlxdWVseSBtYXBwZWQgcmVhZHMKICBzYW10b29scyB2aWV3IC1iUyAtcSAxMCAke05BTUV9X21hcHBlZC5zYW0gPiAke05BTUV9X21hcHBlZC5iYW0KCiAgIyMgZ2V0IHN0YXRzIGZyb20gYWxpZ25tZW50CiAgc2FtdG9vbHMgZmxhZ3N0YXQgJHtOQU1FfV9tYXBwZWQuYmFtID4gJHtOQU1FfV9mbGFnc3RhdC50eHQKICBzYW10b29scyBzb3J0IC1vICR7TkFNRX0uc29ydGVkLmJhbSAke05BTUV9X21hcHBlZC5iYW0KICBzYW10b29scyBpbmRleCAke05BTUV9LnNvcnRlZC5iYW0KZG9uZQpgYGAKCiMgSW5zZXJ0aW9uIHNpdGUgaWRlbnRpZmljYXRpb24KQWZ0ZXIgbWFwcGluZywgaW5zZXJ0aW9uIHNpdGUgaWRlbnRpZmljYXRpb24gaXMgZG9uZSBvbmUgZWFjaCBzZXF1ZW5jaW5nIHJ1biBpbmRpdmlkdWFsbHkuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBkZXRlcm1pbmUgY29ycmVsYXRpb24gYmV0d2VlbiBsaWJyYXJ5IHByZXBzIGFuZCBzZXF1ZW5jaW5nIHJ1bnMuCkFmdGVyIG1hcHBpbmcsIGJhbXMgZnJvbSBlYWNoIHJ1biBhcmUgYWxzbyBjb21iaW5lZCBpbnRvIG9uZSBiYW0gcGVyIHNhbXBsZSwgYW5kIGluc2VydGlvbiBzaXRlIGlkZW50aWZpY2F0aW9uIGlzIGRvbmUgb24gdGhlIGNvbWJpbmVkIGJhbS4gVGhpcyBtYWtlcyBkb3duIHN0cmVhbSBwcm9jZXNzaW5nIGVhc2llciwgYXMgaWRlbnRpY2FsIGluc2VydGlvbiBzaXRlcyBpZGVudGlmaWVkIGZyb20gZGlmZmVyZW50IHNlcXVlbmNpbmcgcnVucyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgY29tYmluZWQuCiMjIENvbWJpbmUgQkFNcwpgYGB7YmFzaCBjb21iaW5lX3NlcXVlbmNpbmcuc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1jb21iaW5lCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtOAojU0JBVENIIC0tbWVtPTEwR0IKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtbyBtZXJnZS4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgbWVyZ2UuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazo4Mzg1Mzk0CgojIyBnZXQgc2FtcGxlIG5hbWVzClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ2VuY29yZS9vdXQvR3Jlc2hhbS8yMDIwLTAxLTEwX0hWMkoyQkdYQy9tZXJnZWQvSFYySjJCR1hDX24wMSoyLmZhc3RxLmd6KSkKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCiMgZ2V0IGFsbCBiYW1zIGZvciBlYWNoIHNhbXBsZQpueWNfYmFtcz1ueWMvdioke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQpiZ2lfYmFtcz1iZ2kvdioke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQppZiBbWyAiJHtOQU1FfSIgPT0gIjE3MjgiIHx8ICIke05BTUV9IiA9PSAiMTczNiIgfHwgIiR7TkFNRX0iID09ICIxNzQwIiBdXQp0aGVuCiAgYWxsX2JhbXM9IiQoZWNobyAkbnljX2JhbXMpICQoZWNobyAkYmdpX2JhbXMpIgplbHNlCiAgYWxsX2JhbXM9JChlY2hvICRueWNfYmFtcykKZmkKCiMjY2hlY2sgdG8gbWFrZSBzdXJlIGV2ZXJ5dGhpbmcgaXMgYmVpbmcgY29ycmVjdGx5IGNvbWJpbmVkCmVjaG8gJGFsbF9iYW1zCgojI2NoYW5nZSB0byBkaXJlY3RvcnkgZm9yIHRoaXMgc3BlY2lmaWMgc2FtcGxlIC0gQ09NQklORUQKbWtkaXIgY29tYmluZWQvJHtOQU1FfS8KCm1vZHVsZSBwdXJnZQptb2R1bGUgbG9hZCBzYW10b29scy9pbnRlbC8xLjkKIyMgbWVyZ2UgYmFtcwpzYW10b29scyBtZXJnZSBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX1fbWVyZ2VkLmJhbSAkYWxsX2JhbXMKc2FtdG9vbHMgc29ydCAtbyBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbSBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX1fbWVyZ2VkLmJhbQpzYW10b29scyBpbmRleCBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQpgYGAKCiMjIFBhcnNlIEJBTXMKQmF0Y2ggZmlsZQpgYGB7YmFzaCBQYXJzZUJhbS5zaH0KIyEvYmluL2Jhc2gKI1NCQVRDSCAtLWpvYi1uYW1lPXBhcnNlYmFtCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1tZW09MjVHQgojU0JBVENIIC0tY3B1cy1wZXItdGFzaz01CiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLW8gc2x1cm1QYXJzZUJhbS4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgc2x1cm1QYXJzZUJhbS4lTi4lai5lcnIgICAgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQojI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazoKCm1vZHVsZSBsb2FkIHB5c2FtL2ludGVsLzAuMTEuMi4yCm1vZHVsZSBsb2FkIHNhbXRvb2xzL2ludGVsLzEuNgptb2R1bGUgbG9hZCBzYW1ibGFzdGVyL2ludGVsLzAuMS4yNAptb2R1bGUgbG9hZCBudW1weS9weXRob24yLjcvaW50ZWwvMS4xNC4wIAoKZnVuY3Rpb24gcnVuX3BhcmFsbGVsICgpCnsKc3J1biAtbjEgLS1leGNsdXNpdmUgIiRAIgp9CiNydW4KZm9yIGJhbSBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvKi8qLypzb3J0ZWQuYmFtCmRvCglydW5fcGFyYWxsZWwgcHl0aG9uMi43IHBhcnNlQmFtLnB5ICRiYW0gJgpkb25lCndhaXQKYGBgClB5dGhvbiBmaWxlIHRoYXQgYWN0dWFsbHkgZG9lcyB0aGUgcGFyc2luZy4KYGBge3B5dGhvbiBwYXJzZUJhbS5weX0KIy91c3IvYmluL3B5dGhvbgppbXBvcnQgc3lzLHN0cmluZyxvcyxnbG9iLHJhbmRvbSxweXNhbSxyZSxhcmdwYXJzZQojI3N5cy5wYXRoLmluc2VydCgwLCAnL2hvbWUvYWZyaWVkcmljaC9TY3JpcHRzJykKIyNpbXBvcnQgZmFzdGEsZmlsZXMKCgpkZWYgcGFyc2VCYW0oYmFtRmlsZSk6CiAgICBwYXR0ZXJuID0gcmUuY29tcGlsZSgiXHMqIikKICAgIG91dGZpbGUgPSBiYW1GaWxlLnJlcGxhY2UoIi5zb3J0ZWQuYmFtIiwiX2luc2VydGlvblBvcy50eHQiKQogICAgb2YgPSBvcGVuKG91dGZpbGUsInciKQogICAgc2FtZmlsZT1weXNhbS5BbGlnbm1lbnRGaWxlKGJhbUZpbGUsY2hlY2tfc3E9RmFsc2UpCiAgICBjaHJvbT0iY2hyb21vc29tZTEiCiAgICBsaXN0UG9zPVtdCiAgICBjb3VudCA9IDAKICAgIGZvciByZWFkIGluIHNhbWZpbGUuZmV0Y2goKToKCQkjIHdyaXRlIHdoZW4gY2hhbmdpbmcgY2hyb21vc29tZQoJCWlmIGNocm9tICE9IHJlYWQucmVmZXJlbmNlX25hbWU6CgkJICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3MpOgoJCQkJb2Yud3JpdGUoIiVzXHQlc1x0JXNcbiIgJSAoY2hyb20scG9zLHBvcykpCgkJICAgIGNocm9tPXJlYWQucmVmZXJlbmNlX25hbWUKICAgICAgICAJICAgIGxpc3RQb3M9W10KCgkJY2xpcGluNSA9IDAKCQljaWdhciA9IHJlYWQuY2lnYXJzdHJpbmcKCgkJIyBpZiBzb2Z0Q2xpcHBlZCAKCQlpZiBjaWdhci5maW5kKCJTIikgIT0gLTE6CgkJCSMgYXJlIHRoZSBzb2Z0LWNsaXBwZWQgYmFzZXMgbG9jYXRlZCBhdCA1JyBlbmQKCQkJIyBpZiB5ZXMsIHdpbGwgbm90IGJlIGNvbnNpZGVyZWQgYXMgYW4gaW5zZXJ0b24gcG9zaXRpb24KCQkJaWYgcmVhZC5pc19yZXZlcnNlOgoJCQkJaWYgY2lnYXIucmZpbmQoIlMiKT5jaWdhci5maW5kKCJNIik6CgkJCQkJY2xpcGluNSA9IDEKCQkJZWxzZToKCQkJCWlmIGNpZ2FyLmZpbmQoIlMiKTxjaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQoJCSMgaWYgbm8gc29mdGNsaXBwZWQgaW4gNScKCQlpZiBjbGlwaW41ID09IDA6CgkJCWlmIHJlYWQuaXNfcmV2ZXJzZToKCQkJCXN0YXJ0ID0gcmVhZC5yZWZlcmVuY2VfZW5kCgkJCWVsc2U6CgkJCQlzdGFydCA9IHJlYWQucmVmZXJlbmNlX3N0YXJ0KzEKCQkJaWYgaW50KHN0YXJ0KSBub3QgaW4gbGlzdFBvczoKCQkJCWxpc3RQb3MuYXBwZW5kKGludChzdGFydCkpCgkjIGlmIG5vIG1pc21hdGNoIGF0IHRoZSBmaXJzdCBwb3NpdGlvbiwgc2hvdWxkIHRlc3QgMCBhcyBmaXJ0ICgvbGFzdCkgY2hhcmFjdGVyIG9mIHRoZSBmbGFnIGZvciByZWFkcyBpbiBmb3J3YXJkICgvcmV2ZXJzZSkKICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3MpOgoJCW9mLndyaXRlKCIlc1x0JXNcdCVzXG4iICUgKGNocm9tLHBvcyxwb3MpKQogICAgc2FtZmlsZS5jbG9zZSgpCiAgICBvZi5jbG9zZSgpCgoKZGVmIGdldFJlYWRQZXJQb3MoYmFtRmlsZSk6CiAgICBwYXR0ZXJuID0gcmUuY29tcGlsZSgiXHMqIikKICAgIG91dGZpbGUgPSBiYW1GaWxlLnJlcGxhY2UoIi5zb3J0ZWQuYmFtIiwiX3JlYWRQZXJQb3MudHh0IikKCW9mID0gb3BlbihvdXRmaWxlLCJ3IikKICAgICAgICBzYW1maWxlPXB5c2FtLkFsaWdubWVudEZpbGUoYmFtRmlsZSwicmIiKQogICAgICAgIGNocm9tPSJjaHJvbW9zb21lMSIKICAgICAgICBsaXN0UG9zPVtdCglsaXN0UG9zVW5pcT1bXQogICAgICAgIGNvdW50ID0gMAogICAgICAgIGZvciByZWFkIGluIHNhbWZpbGUuZmV0Y2goKToKICAgICAgICAgICAgICAgIGlmIGNocm9tICE9IHJlYWQucmVmZXJlbmNlX25hbWU6CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3NVbmlxKToKCQkJCW9mLndyaXRlKCIlc1x0JXNcdCVzXG4iICUgKGNocm9tLHBvcyxsaXN0UG9zLmNvdW50KHBvcykpKQogICAgICAgICAgICAgICAgICAgICAgICBjaHJvbT1yZWFkLnJlZmVyZW5jZV9uYW1lCiAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RQb3M9W10KCQkJbGlzdFBvc1VuaXE9W10KCQljbGlwaW41ID0gMAogICAgICAgICAgICAgICAgY2lnYXIgPSByZWFkLmNpZ2Fyc3RyaW5nCiAgICAgICAgICAgICAgICAjIGlmIHNvZnRDbGlwcGVkIAogICAgICAgICAgICAgICAgaWYgY2lnYXIuZmluZCgiUyIpICE9IC0xOgogICAgICAgICAgICAgICAgICAgICAgICBpZiByZWFkLmlzX3JldmVyc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgY2lnYXIucmZpbmQoIlMiKT5jaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGNpZ2FyLmZpbmQoIlMiKTxjaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQogICAgICAgICAgICAgICAgIyBpZiBubyBzb2Z0Y2xpcHBlZCBpbiA1JwogICAgICAgICAgICAgICAgaWYgY2xpcGluNSA9PSAwOgogICAgICAgICAgICAgICAgICAgICAgICBpZiByZWFkLmlzX3JldmVyc2U6CgkJCQlzdGFydCA9IHJlYWQucmVmZXJlbmNlX2VuZAogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgoJCQkJc3RhcnQgPSByZWFkLnJlZmVyZW5jZV9zdGFydCsxCgkJCWlmIGludChzdGFydCkgbm90IGluIGxpc3RQb3NVbmlxOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RQb3NVbmlxLmFwcGVuZChpbnQoc3RhcnQpKQoKCQkJbGlzdFBvcy5hcHBlbmQoaW50KHN0YXJ0KSkKCiAgICAgICAgZm9yIHBvcyBpbiBsaXN0UG9zVW5pcToKCQlvZi53cml0ZSgiJXNcdCVzXHQlc1xuIiAlIChjaHJvbSxwb3MsbGlzdFBvcy5jb3VudChwb3MpKSkKCiAgICAgICAgc2FtZmlsZS5jbG9zZSgpCglvZi5jbG9zZSgpCgoKCgpwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCnBhcnNlci5hZGRfYXJndW1lbnQoImZpbGUiKQphcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQoKI2FyZ3MgPSBzeXMuYXJndlsxOl0KI2FsbF9hcmdzID0gZmlsZXMuZ2V0X2FyZ3MoYXJncykKI3RyeToKIyAgICBzZXFmID0gYWxsX2FyZ3NbImYiXQojZXhjZXB0OgojICAgIHNlcWYgPSAiIgojdHJ5OiAKIyAgICBzZXFvID0gYWxsX2FyZ3NbIm8iXQojZXhjZXB0OgojICAgIHNlcW8gPSAiIgogCnBhcnNlQmFtKGFyZ3MuZmlsZSkKZ2V0UmVhZFBlclBvcyhhcmdzLmZpbGUpCgpgYGAKIyMgSW50ZXJzZWN0IEJFRApCYXRjaCBzY3JpcHQKYGBge2Jhc2ggSW50ZXJzZWN0QmVkLnNofQojIS9iaW4vYmFzaAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tbWVtPTE1R0IKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9NAojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC1vIGludGVyc2VjdEJlZC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgaW50ZXJzZWN0QmVkLiVOLiVqLmVyciAgICAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CiNTQkFUQ0ggLS1kZXBlbmRlbmN5PWFmdGVyb2s6ODIxMjkzMwoKbW9kdWxlIGxvYWQgYmVkdG9vbHMvaW50ZWwvMi4yNi4wIApHRkY9Ii9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLmdmZiIKCmZ1bmN0aW9uIHJ1bl9wYXJhbGxlbCAoKQp7CnNydW4gLW4xIC0tZXhjbHVzaXZlICIkQCIKfQoKZm9yIGluc2VyUG9zIGluIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC8qLyovKl9pbnNlcnRpb25Qb3MudHh0CmRvCglvdXRmaWxlPSR7aW5zZXJQb3MvLnR4dC9fYW5ub3RhdGVkLmJlZCB9CglydW5fcGFyYWxsZWwgaW50ZXJzZWN0QmVkIC13YiAtYSAkaW5zZXJQb3MgLWIgJHtHRkZ9ID4gJG91dGZpbGUgJgoKZG9uZQp3YWl0CmBgYAoKQSBtYW51YWwgc3RlcCB0byBnZXQgQ0RTIGxpbmVzIGluIGJlZGZpbGUgYW5kIGdldCByaWQgb2YgYW55dGhpbmcgbm90IGluIGEgQ0RTLgpBIGxpdHRsZSBlbWJhcmFzc2luZyBidXQgd2hhdGV2ZXIKYGBge2Jhc2ggZ2V0X0NEUy5zaH0KIyEvYmluL2Jhc2gKI1NCQVRDSCAtLWpvYi1uYW1lPWdldGNkcwojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLW8gZ2V0Q0RTLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBnZXRDRFMuJU4uJWouZXJyICAgICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWFycmF5PTAtOAojI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazoKCiMjIGdldCBzYW1wbGUgbmFtZXMKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKZm9yIGZpbGUgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwLyovKiR7TkFNRX0vJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkLmJlZApkbwogIHBhdGg9JChlY2hvICRmaWxlIHwgY3V0IC1kJy8nIC1mIDEsMiwzLDQsNSw2KQogIGdyZXAgQ0RTICR7ZmlsZX0gPiAkcGF0aC8ke05BTUV9X2luc2VydGlvblBvc19hbm5vdGF0ZWRDRFMuYmVkCiAgYXdrICckNiA9PSAiQ0RTIicgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTLmJlZCA+ICRwYXRoLyR7TkFNRX1faW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUzEuYmVkCiAgbXYgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTMS5iZWQgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTLmJlZApkb25lCmBgYAoKIyMgQmVkIFBvc3QgVHJlYXRtZW50CkJhdGNoIHNjcmlwdApgYGB7YmFzaCBCZWRQb3N0VHJlYXRtZW50LnNofQojIS9iaW4vYmFzaAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tbWVtPTE1R0IKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC1vIEJlZC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgQmVkLiVOLiVqLmVyciAgICAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CiNTQkFUQ0ggLS1kZXBlbmRlbmN5PWFmdGVyb2s6NzY0NjU5OAoKbW9kdWxlIGxvYWQgcHlzYW0vaW50ZWwvMC4xMS4yLjIKbW9kdWxlIGxvYWQgc2FtdG9vbHMvaW50ZWwvMS42Cm1vZHVsZSBsb2FkIHNhbWJsYXN0ZXIvaW50ZWwvMC4xLjI0Cm1vZHVsZSBsb2FkIG51bXB5L3B5dGhvbjIuNy9pbnRlbC8xLjE0LjAgCgpmdW5jdGlvbiBydW5fcGFyYWxsZWwgKCkKewpzcnVuIC1uMSAtLWV4Y2x1c2l2ZSAiJEAiCn0KCmZvciBzYW1wbGUgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwLyovKi8qX2luc2VydGlvblBvc19hbm5vdGF0ZWRDRFMuYmVkCmRvCglydW5fcGFyYWxsZWwgcHl0aG9uMi43IGJlZFBvc3RUcmVhdG1lbnQucHkgJHNhbXBsZSAmCgpkb25lCndhaXQKYGBgClB5dGhvbiBzY3JpcHQKYGBge3B5dGhvbiBiZWRQb3N0VHJlYXRtZW50LnB5fQojL3Vzci9iaW4vcHl0aG9uCmltcG9ydCBzeXMsc3RyaW5nLG9zLGdsb2IscmFuZG9tLHB5c2FtLHJlLGFyZ3BhcnNlCgoKZGVmIHBvc3RUcmVhdG1lbnQoc2FtcGxlKToKCXByaW50ICJnZXRHZW5lTGlzdCIKCWdlbmVMaXN0PWdldEdlbmVMaXN0KHNhbXBsZSkKCXByaW50ICJnZXRJbnNlcnRpb25QZXJHZW5lIgoJaW5zUGVyR2VuZT1nZXRJbnNlcnRpb25QZXJHZW5lKGdlbmVMaXN0KQoJcHJpbnQgImluc2VydGlvblBlcktiUGVyR2VuZSIKCWluc2VydGlvblBlcktiUGVyR2VuZShpbnNQZXJHZW5lKQoJcHJpbnQgImdldE5vSW5zR2VuZSIKCWdldE5vSW5zR2VuZShnZW5lTGlzdCkKCmRlZiBjcmVhdGVMZW5EaWNvKGluZmlsZSk6CglkaWNvID0ge30KICAgICAgICBsaW5lcyA9IG9wZW4oaW5maWxlLCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCiAgICAgICAgY2RzID0gIiIKICAgICAgICBsZW5ndGggPSAiIgogICAgICAgIGZvciBsaW5lIGluIGxpbmVzOgogICAgICAgICAgICAgICAgaWYgbGluZSAhPSAiIjoKCQkJY2RzID0gbGluZS5zcGxpdCgiXHQiKVswXQogICAgICAgICAgICAgICAgICAgIAlkaWNvW2Nkc10gPSBpbnQobGluZS5zcGxpdCgiXHQiKVsxXSkKICAgIAlyZXR1cm4gZGljbwoKCmRlZiBpbnNlcnRpb25QZXJLYlBlckdlbmUoaW5zRmlsZSk6CgljZHNMZW5ndGg9Ii9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL2Nkc0xlbmd0aC50YWIiCglkaWNvTGVuPWNyZWF0ZUxlbkRpY28oY2RzTGVuZ3RoKQoJI2luc0ZpbGU9Imluc2VydGlvblBlckdlbmUtcmVsLnRhYiIKCWluc0tiRmlsZT1pbnNGaWxlLnJlcGxhY2UoIlBlckdlbmUudHh0IiwiUGVyS2JQZXJHZW5lLnR4dCIpCglvZj1vcGVuKGluc0tiRmlsZSwidyIpCglsaW5lcz1vcGVuKGluc0ZpbGUsInIiKS5yZWFkKCkuc3BsaXQoIlxuIikKCWZvciBsaW5lIGluIGxpbmVzWzE6XToKCQlpZiBsaW5lICE9ICIiOgoJCQllbD1saW5lLnNwbGl0KCJcdCIpCgkJCW9mLndyaXRlKCIlc1x0JTAuMmZcbiIgJSAoZWxbMF0sZmxvYXQoZWxbMV0pKjEwMDAvZGljb0xlbltlbFswXV0pKQoJb2YuY2xvc2UoKQoKZGVmIHJlbW92ZVJlZHVuZGFudCgpOgoJaW5maWxlPSJsaXN0QWxsR2VuZXMudHh0IgoJb3V0ZmlsZT0ibGlzdEFsbE5SR2VuZXMudHh0IgoJb2Y9b3BlbihvdXRmaWxlLCJ3IikKCWluTGlzdD1vcGVuKGluZmlsZSwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQoJc2V0VW5pcXVlPXNldChpbkxpc3QpCglsaXN0VW5pcXVlPWxpc3Qoc2V0VW5pcXVlKQoJCglmb3IgZ2VuZSBpbiBzb3J0ZWQobGlzdFVuaXF1ZSk6CgkJaWYgZ2VuZSE9IiI6CgkJCW9mLndyaXRlKCclc1xuJyVnZW5lKQoJb2YuY2xvc2UoKQoKCmRlZiBnZXRHZW5lTGlzdChzYW1wbGUpOgogICAgICAgIGJlZGZpbGU9c2FtcGxlCglvdXRmaWxlPWJlZGZpbGUucmVwbGFjZSgiaW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUy5iZWQiLCJnZW5lc1dpdGhJbnNlcnRpb24udHh0IikKCW9mPW9wZW4ob3V0ZmlsZSwidyIpCglsaW5lcyA9IG9wZW4oYmVkZmlsZSwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQoJZm9yIGxpbmUgaW4gbGluZXM6CgkJaWYgbGluZSAhPSAiIjoKCQkJZWw9bGluZS5zcGxpdCgiXHQiKQoJCQlnZW5lPWVsWzExXS5zcGxpdCgiOyIpWzBdLnJlcGxhY2UoIlBhcmVudD0iLCIiKQoJCQlvZi53cml0ZSgiJXNcbiIgJSBnZW5lKQoJb2YuY2xvc2UoKQoJcmV0dXJuIG91dGZpbGUKCgpkZWYgZ2V0SW5zZXJ0aW9uUGVyR2VuZShnZW5lTGlzdCk6CiAgICAgICAgbGlzdFNBVEFZR2VuZXM9b3BlbihnZW5lTGlzdCwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQogICAgICAgIGxpc3RHZW5lc1dpdGhJbnNlcnRpb249c29ydGVkKGxpc3RTQVRBWUdlbmVzKQogICAgICAgIHNldFVuaXF1ZUdlbmVzV2l0aEluc2VydGlvbj1zZXQobGlzdEdlbmVzV2l0aEluc2VydGlvbikKICAgICAgICBsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uPWxpc3Qoc2V0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uKQoJb3V0ZmlsZT1nZW5lTGlzdC5yZXBsYWNlKCJnZW5lc1dpdGhJbnNlcnRpb24udHh0IiwiaW5zZXJ0aW9uUGVyR2VuZS50eHQiKQoJb2Y9b3BlbihvdXRmaWxlLCJ3IikKCW9mLndyaXRlKCJDRFNcdCNpbnNlcnRpb25cbiIpCiAgICAgICAgCiAgICAgICAgZm9yIGNkcyBpbiBsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uOgoJCWlmIGNkcyAhPSAiIjoKICAgICAgICAJCW9mLndyaXRlKCIlc1x0JXNcbiIgJSAoY2RzLGxpc3RHZW5lc1dpdGhJbnNlcnRpb24uY291bnQoY2RzKSkpCglvZi5jbG9zZSgpCglyZXR1cm4gb3V0ZmlsZQoKCmRlZiBnZXROb0luc0dlbmUoZ2VuZUxpc3QpOgoJbGlzdEFsbEdlbmVzPW9wZW4oIi9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL2xpc3RBbGxHZW5lcy50eHQiLCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCglsaXN0U0FUQVlHZW5lcz1vcGVuKGdlbmVMaXN0LCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCglvdXRmaWxlPWdlbmVMaXN0LnJlcGxhY2UoIkluc2VydGlvbiIsIk5vSW5zZXJ0aW9uIikKCW9mPW9wZW4ob3V0ZmlsZSwidyIpCglsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uPXNvcnRlZChsaXN0U0FUQVlHZW5lcykKCSNwcmludCBsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uCglzZXRVbmlxdWVHZW5lc1dpdGhJbnNlcnRpb249c2V0KGxpc3RHZW5lc1dpdGhJbnNlcnRpb24pCglsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uPWxpc3Qoc2V0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uKQoJCgkjY29tcGFyZSBBbGwgZ2VuZXMgYW5kIGdlbmVzIHdpdGggYXQgbGVhc3QgMSBpbnNlcnRpb24KCSNwcmludCAiR2VuZXMgd2l0aCBubyBpbnNlcnRpb24iCglmb3IgZ2VuZSBpbiBsaXN0QWxsR2VuZXM6CgkJI3ByaW50IGdlbmUKCQkjaWYgZ2VuZSBub3QgaW4gbGlzdFVuaXF1ZUdlbmVzV2l0aEluc2VydGlvbjoKCQlpZiBnZW5lIG5vdCBpbiBsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uOgoJCQkjcHJpbnQgInRoaXMgb25lIGluIG5vdCBpbiB0aGUgbGlzdCJpCgkJCW9mLndyaXRlKCIlc1xuIiAlIGdlbmUpCQkKCQkJI3ByaW50IGdlbmUKCW9mLmNsb3NlKCkKCgpwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCnBhcnNlci5hZGRfYXJndW1lbnQoImZpbGUiKQphcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQoKcG9zdFRyZWF0bWVudChhcmdzLmZpbGUpCgpgYGAKCiMgTnVtYmVyIG9mIGluc2VydGlvbiBzaXRlcyBvdmVyIG5vbiBvdmVybGFwcGluZyB3aW5kb3dzIG9mIDEwMCBiYXNlcGFpcnMgb3ZlciB0aGUgZ2Vub21lCkkgYW0gb25seSBkb2luZyB0aGlzIGZvciB0aGUgY29tYmluZWQgZmlsZXMKYGBge2Jhc2ggaW5zZXJ0X3dpbmRvd3Muc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1pbldpbgojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS1hcnJheT0wLTgKI1NCQVRDSCAtLW1lbT0xMEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gaW5XaW5kb3dzLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBpbldpbmRvd3MuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKCiMjIGdldCBzYW1wbGUgbmFtZXMKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKI2dldCB0aGUgd2luZG93cyBmaWxlcwpXSU5ET1dTPScvc2NyYXRjaC9nYTgyNC9oZXJtZXNfd2dzL2JlZF93aW5kb3dzL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLndpbmRvd3MnCgojZ2V0IG51bWJlciB1bmlxdWUgaW5zZXJ0aW9uIHNpdGVzIHBlciB3aW5kb3cKbW9kdWxlIGxvYWQgYmVkdG9vbHMvaW50ZWwvMi4yNy4xCmJlZHRvb2xzIGNvdmVyYWdlIC1jb3VudHMgLXNvcnRlZCAtYSAkV0lORE9XUyAtYiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvY29tYmluZWQvJHtOQU1FfS8ke05BTUV9X2luc2VydGlvblBvcy50eHQgPiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvY29tYmluZWQvJHtOQU1FfS8ke05BTUV9X2luc2VydGlvbldpbmRvd3MuY292CmBgYAoKCiMgT3V0cHV0cyBmcm9tIHRoaXMgc2NyaXB0IHRoYXQgYXJlIGlucHV0cyBpbnRvIG5leHQgKFIgYmFzZWQpIGFuYWx5c2lzIHNjcmlwdApFYWNoIG9mIHRoZSBmb2xsb3dpbmcgaXMgb3V0cHV0IGZvciBlYWNoIHNhbXBsZToKKiBmYXN0cWMgZmlsZXMgZm9yIGVhY2ggc2VxdWVuY2luZyBydW4KKiByZWFkUGVyUG9zLnR4dAoqIGluc2VydGlvblBvcy50eHQKKiBnZW5lc1dpdGhOb0luc2VydGlvbi50eHQKKiBpbnNlcnRpb25QZXJHZW5lLnR4dAoqIGluc2VydGlvblBlcktiUGVyR2VuZS50eHQKKiBnZW5lc1dpdGhJbnNlcnRpb24udHh0CiogaW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUy5iZWQgPwoqIGluc2VydGlvblBvc19hbm5vdGF0ZWQuYmVkID8KKiBpbnNlcnRpb25XaW5kb3dzLmNvdiAob25seSBkb25lIGZvciBjb21iaW5lZCkKCg==