This is part of the analysis pipeline for the hermes insertion mutagenesis in CNV strains experiment.
This includes 9 independent insertion experiments:
- 1657-1 a.k.a. euploid-1
- 1657-2 a.k.a. euploid-2
- 1728 a.k.a. CNV-A
- 1734 a.k.a. CNV-B
- 1736 a.k.a. CNV-C
- 1740 a.k.a. CNV-D
- 1744 a.k.a. CNV-E
- 1747 a.k.a. CNV-F
- 1751 a.k.a. CNV-G
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:
- 1728, prepared in France, sequenced at BGI first time
- 1728, prepared in France, sequenced at BGI second time
- 1736, prepared in France, sequenced at BGI first time
- 1736, prepared in France, sequenced at BGI second time
- 1740, prepared in France, sequenced at BGI first time
1740, prepared in France, sequenced at BGI second time
- 1657-1, prepared in NYC, sequenced at NYU first time
- 1657-1, prepared in NYC, sequenced at NYU second time
- 1657-2, prepared in NYC, sequenced at NYU first time
- 1657-2, prepared in NYC, sequenced at NYU second time
- 1728, prepared in NYC, sequenced at NYU first time
- 1728, prepared in NYC, sequenced at NYU second time
- 1734, prepared in NYC, sequenced at NYU first time
- 1734, prepared in NYC, sequenced at NYU second time
- 1736, prepared in NYC, sequenced at NYU first time
- 1740, prepared in NYC, sequenced at NYU first time
- 1744, prepared in NYC, sequenced at NYU first time
- 1744, prepared in NYC, sequenced at NYU second time
- 1747, prepared in NYC, sequenced at NYU first time
- 1747, prepared in NYC, sequenced at NYU second time
- 1751, prepared in NYC, sequenced at NYU first time
1751, prepared in NYC, sequenced at NYU second time
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
LS0tCnRpdGxlOiAiSGVybWVzIGluc2VydGlvbiBsaWJyYXJ5IGFuYWx5c2lzIC0gZmFzdHEgdG8gaW5zZXJ0aW9uIHBvc2l0aW9ucyIKYXV0aG9yOiAiR3JhY2UgQXZlY2lsbGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KClRoaXMgaXMgcGFydCBvZiB0aGUgYW5hbHlzaXMgcGlwZWxpbmUgZm9yIHRoZSBoZXJtZXMgaW5zZXJ0aW9uIG11dGFnZW5lc2lzIGluIENOViBzdHJhaW5zIGV4cGVyaW1lbnQuCgpUaGlzIGluY2x1ZGVzIDkgaW5kZXBlbmRlbnQgaW5zZXJ0aW9uIGV4cGVyaW1lbnRzOiAgCgoqIDE2NTctMSBhLmsuYS4gZXVwbG9pZC0xCiogMTY1Ny0yIGEuay5hLiBldXBsb2lkLTIKKiAxNzI4IGEuay5hLiBDTlYtQQoqIDE3MzQgYS5rLmEuIENOVi1CCiogMTczNiBhLmsuYS4gQ05WLUMKKiAxNzQwIGEuay5hLiBDTlYtRAoqIDE3NDQgYS5rLmEuIENOVi1FCiogMTc0NyBhLmsuYS4gQ05WLUYKKiAxNzUxIGEuay5hLiBDTlYtRwoKMTY1Ny0xIGFuZCAxNjU3LTIgYXJlIGJpb2xvZ2ljYWwgcmVwbGljYXRlcyBvZiB0aGUgaW5zZXJ0aW9uIG11dGFnZW5lc2lzIHBlcmZvcm1lZCBvbiBER1kxNjU3LCB0aGUgYW5jZXN0cmFsIGV1cGxvaWQgc3RyYWluIHdpdGggYSAqR0FQMSogQ05WIHJlcG9ydGVyLgoKVGhpcyBhbHNvIGluY2x1ZGVzIHRoZSBmb2xsb3dpbmcgdGVjaG5pY2FsIHJlcGxpY2F0ZXM6ICAKCiogMTcyOCwgcHJlcGFyZWQgaW4gRnJhbmNlLCBzZXF1ZW5jZWQgYXQgQkdJIGZpcnN0IHRpbWUKKiAxNzI4LCBwcmVwYXJlZCBpbiBGcmFuY2UsIHNlcXVlbmNlZCBhdCBCR0kgc2Vjb25kIHRpbWUKKiAxNzM2LCBwcmVwYXJlZCBpbiBGcmFuY2UsIHNlcXVlbmNlZCBhdCBCR0kgZmlyc3QgdGltZQoqIDE3MzYsIHByZXBhcmVkIGluIEZyYW5jZSwgc2VxdWVuY2VkIGF0IEJHSSBzZWNvbmQgdGltZQoqIDE3NDAsIHByZXBhcmVkIGluIEZyYW5jZSwgc2VxdWVuY2VkIGF0IEJHSSBmaXJzdCB0aW1lCiogMTc0MCwgcHJlcGFyZWQgaW4gRnJhbmNlLCBzZXF1ZW5jZWQgYXQgQkdJIHNlY29uZCB0aW1lCgoKKiAxNjU3LTEsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTY1Ny0xLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNjU3LTIsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTY1Ny0yLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNzI4LCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3MjgsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBzZWNvbmQgdGltZQoqIDE3MzQsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTczNCwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIHNlY29uZCB0aW1lCiogMTczNiwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIGZpcnN0IHRpbWUKKiAxNzQwLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3NDQsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBmaXJzdCB0aW1lCiogMTc0NCwgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIHNlY29uZCB0aW1lCiogMTc0NywgcHJlcGFyZWQgaW4gTllDLCBzZXF1ZW5jZWQgYXQgTllVIGZpcnN0IHRpbWUKKiAxNzQ3LCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgc2Vjb25kIHRpbWUKKiAxNzUxLCBwcmVwYXJlZCBpbiBOWUMsIHNlcXVlbmNlZCBhdCBOWVUgZmlyc3QgdGltZQoqIDE3NTEsIHByZXBhcmVkIGluIE5ZQywgc2VxdWVuY2VkIGF0IE5ZVSBzZWNvbmQgdGltZQoKKkxpYnJhcnkgcHJlcHMgaW4gRnJhbmNlIGFuZCBOWUMgaGFkIHNsaWdodGx5IGRpZmZlcmVudCBwcm90b2NvbHMgYW5kIHNlcXVlbmNpbmcgc2V0LXVwcyAtIHNlZSBtZXRob2RzLiBFYWNoIGxpYnJhcnkgcHJlcCB3YXMgcGVyZm9ybWVkIGZyb20gYSBzaW5nbGUgRE5BIGV4dHJhY3Rpb24sIHByZXBwZWQgb25jZSBhdCBhIGxvY2F0aW9uLCBhbmQgdGhlbiB0aGUgc2FtZSBsaWJyYXJ5IHByZXAgd2FzIHNlcXVlbmNlZCB0d28gdGltZXMgYXQgdGhlIHNhbWUgZmFjaWxpdHkuKgoKCioqU2NyaXB0cyBtdXN0IGJlIHJ1biBpbiB0aGUgb3JkZXIgc2hvd24gaW4gdGhpcyBub3RlYm9vay4qKgoKIyBDbGVhbiBSZWFkcwojIyBBbGxvd2luZyBNb3JlIFZhcmlhYmlsaXR5IGF0IEJlZ2lubmluZyBvZiBSZWFkCldlIHNlYXJjaCBmb3IgdGhlIHJlYWRzIHdoaWNoIGhhdmUgdGhlIGV4cGVjdGVkIEhlcm1lcyBUSVIgc2VxdWVuY2UgZm9sbG93aW5nIHRoZSBwcmltZXIuIFdlIHRoZW4gZ2V0IHJpZCBvZiByZWFkcyB0aGF0IGhhdmUgaGF2ZSB0aGUgcGxhc21pZCBzZXF1ZW5jZSAoc2xpZ2h0bHkgZGlmZmVyZW50IGZvciBlYWNoIHJlc3RyaWN0aW9uIGVuenltZSkgZm9sbG93aW5nIHRoZSBUSVIKIyMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKYGBge2Jhc2ggQkdJSGlTZXFSZWFkc0NsZWFuaW5nX3ZPbGQuc2h9CiMhL2Jpbi9iYXNoICAgICAgICAgICAgICAgICAgICAgCiNTQkFUQ0ggLS1qb2ItbmFtZT1CR0ljbGVhbnJlYWRzCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtMgojU0JBVENIIC0tbWVtPThHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIGJnaWNsZWFuLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBiZ2ljbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMgZ2V0IGZpcnN0IHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0EvKi8qMi5mcS5neikpCgojIyBnZXQgc2Vjb25kIHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMl9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQV92Mi8qLyoxLmZxLmd6KSkKVjJfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvKi8qMi5mcS5neikpCgoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpWMVI9JHtWMV9SMlskU0xVUk1fQVJSQVlfVEFTS19JRF19ClYyRj0ke1YyX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjJSPSR7VjJfUjJbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCiMjIG1ha2UgZGlyZWN0b3JpZXMKbWtkaXIgYmdpL3YxXyR7TkFNRX0KbWtkaXIgYmdpL3YyXyR7TkFNRX0KCiMjIHNldCBzZXEgJiBwbGFzbWlkClBSRUlOU0VSVD0iWHRjYXRhYWd0YWdjYWFndGdnY2djYXRhYWd0YXRjYWFhYXRhYWdjY2FjdHRndHRndHRndHRjdGN0ZyIKUExBU009Il5nZ2F0Y2NjY2NnZ2djdGdjYWdnYWF0dGNnYXRhdGNhYWdjdHRhdGNnYXRhIgpQTEFTTTI9Il5nZ2F0Y2d0dGd0Z2N0dHRjZ2N0Y3RjY2FhYWFnY2F0YWFnZ2NhIgoKICAgICMjIDMgc3VjY2Vzc2l2ZSBjbGVhbmluZyBzdGVwcwogICAgIyMgLSB0cmltIHRoZSBwbGFzbWlkaWMgc2VxdWVuY2UgYmVmb3JlIHRoZSBpbnNlcnRpb24gcG9pbnQsIHJlbW92ZSB0aGUgdW50cmltbWVkIHJlYWRzIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjFGfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcQoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcSAke1YxUn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEKCiMjIFYyCmN1dGFkYXB0IC1nICR7UFJFSU5TRVJUfSAtTyA0MCAtLWRpc2NhcmQtdW50cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEgJHtWMkZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEKY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhbl92T2xkLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxCgoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcSAke1YyUn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWRfdk9sZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuVG1wX3ZPbGQuZnEKYGBgCgojIyMgRm9yIHN0cmFpbnMgc2VxdWVuY2VkIGF0IE5ZQwpgYGB7YmFzaCBOZXh0U2VxUmVhZHNDbGVhbmluZ192T2xkLnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9bnljY2xlYW5yZWFkcwojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0zCiNTQkFUQ0ggLS1hcnJheT0wLTgKI1NCQVRDSCAtLW1lbT0xMEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gbnljY2xlYW4uJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIG55Y2NsZWFuLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyNUSEVTRSBSVU5TIE9OTFkgSEFEIFIxIyMjIwojIyBnZXQgIHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBKYW4gMjAyMApWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMS0xMF9IVjJKMkJHWEMvbWVyZ2VkL0hWMkoyQkdYQ19uMDEqMi5mYXN0cS5neikpCgojI3RoaXMgaXMgZ29pbmcgdG8gYXNzaWduIHRoZSB2YXJpYWJsZXMgdG8gZmlsZSBuYW1lcwpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKIyMjR0VUIEJZIFJFRkVSRU5DSU5HIE5BTUUjIwojIyBnZXQgc2V0IG9mIGZxIGZpbGVzIGZyb20gTllDIEZlYiAyMDIwClYyRj0vc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMi0xOV9IMkpIR0FGWDIvbWVyZ2VkLyoke05BTUV9KjIuZmFzdHEuZ3oKCiMjbWFrZSBhIGRpcmVjdG9yeSBmb3IgdGhpcyBzcGVjaWZpYyBzYW1wbGUKbWtkaXIgbnljL3YxXyR7TkFNRX0KbWtkaXIgbnljL3YyXyR7TkFNRX0KCiMjIE5vdCBncmVhdCBtYW51YWwgc3RlcCB0byByZW1vdmUgZGlyZWN0b3JpZXMgZm9yIHNhbXBsZXMgbm90IHNlcXVlbmNlZCBpbiBzZWNvbmQgcnVuCnJtIC1yIG55Yy92Ml8xNzI4CnJtIC1yIG55Yy92Ml8xNzM2CnJtIC1yIG55Yy92Ml8xNzQwCgojIyBzZXQgc2VxICYgcGxhc21pZApQUkVJTlNFUlQ9IlhOTk5OTk5OdGNhdGFhZ3RhZ2NhYWd0Z2djZ2NhdGFhZ3RhdGNhYWFhdGFhZ2NjYWN0dGd0dGd0dGd0dGN0Y3RnIgpQTEFTTT0iXmdnYXRjY2NjY2dnZ2N0Z2NhZ2dhYXR0Y2dhdGF0Y2FhZ2N0dGF0Y2dhdGEiClBMQVNNMj0iXmdnYXRjZ3R0Z3RnY3R0dGNnY3RjdGNjYWFhYWdjYXRhYWdnY2EiCgogICAgIyMgMyBzdWNjZXNzaXZlIGNsZWFuaW5nIHN0ZXBzCiAgICAjIyAtIHRyaW0gdGhlIHBsYXNtaWRpYyBzZXF1ZW5jZSBiZWZvcmUgdGhlIGluc2VydGlvbiBwb2ludCwgcmVtb3ZlIHRoZSB1bnRyaW1tZWQgcmVhZHMgCiAgICAgICAgIyMgaW4gdGhpcyB2ZXJzaW9uIHdlIGFsc28gbmVlZCB0byB0cmltIHRoZSBOIHNlcXVlbmNlIGFkZGVkIGJ5IHRoZSBwcmltZXIgZm9yIGJhc2UgY29tcGxleGl0eQogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjFGfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXBfdk9sZC5mcQoKI2lmIFYyIGV4aXN0cyBkbyB0aGlzCmlmIFtbIC1kIG55Yy92Ml8ke05BTUV9IF1dIAp0aGVuCiAgIyMgVjIKICBjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBueWMvdjJfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZF92T2xkLmZxICR7VjJGfQogIGN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcF92T2xkLmZxIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkX3ZPbGQuZnEKICBjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuX3ZPbGQuZnEgbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wX3ZPbGQuZnEKZmkKYGBgCgoKIyMgQWxsb3dpbmcgTGVzcyBWYXJpYWJpbGl0eSBhdCBCZWdpbm5pbmcgb2YgUmVhZAoKIyMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKYGBge2Jhc2ggQkdJSGlTZXFSZWFkc0NsZWFuaW5nLnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9QkdJY2xlYW5yZWFkczIKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MQojU0JBVENIIC0tYXJyYXk9MC0yCiNTQkFUQ0ggLS1tZW09OEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gYmdpY2xlYW4yLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBiZ2ljbGVhbjIuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazo4MDgyMDkxCgoKIyMgZ2V0IGZpcnN0IHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0EvKi8qMi5mcS5neikpCgojIyBnZXQgc2Vjb25kIHNldCBvZiBmcSBmaWxlcyBmcm9tIEJHSQpWMl9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQV92Mi8qLyoxLmZxLmd6KSkKVjJfUjI9KCQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvKi8qMi5mcS5neikpCgoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpWMVI9JHtWMV9SMlskU0xVUk1fQVJSQVlfVEFTS19JRF19ClYyRj0ke1YyX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjJSPSR7VjJfUjJbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCiMjIHNldCBzZXEgJiBwbGFzbWlkClBSRUlOU0VSVD0iXnRjYXRhYWd0YWdjYWFndGdnY2djYXRhYWd0YXRjYWFhYXRhYWdjY2FjdHRndHRndHRndHRjdGN0ZyIKUExBU009Il5nZ2F0Y2NjY2NnZ2djdGdjYWdnYWF0dGNnYXRhdGNhYWdjdHRhdGNnYXRhIgpQTEFTTTI9Il5nZ2F0Y2d0dGd0Z2N0dHRjZ2N0Y3RjY2FhYWFnY2F0YWFnZ2NhIgoKICAgICMjIDMgc3VjY2Vzc2l2ZSBjbGVhbmluZyBzdGVwcwogICAgIyMgLSB0cmltIHRoZSBwbGFzbWlkaWMgc2VxdWVuY2UgYmVmb3JlIHRoZSBpbnNlcnRpb24gcG9pbnQsIHJlbW92ZSB0aGUgdW50cmltbWVkIHJlYWRzIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgMSBlbnp5bWUpIAogICAgIyMgLSByZW1vdmUgcmVhZHMgdGhhdCBjb250YWlucyBwbGFzbWlkaWMgc2VxdWVuY2VzIGFmdGVyIHRoZSB0cmltbWVkIHJlZ2lvbnMgKGluIGNhc2Ugb2YgdGhlIG90aGVyIGVuenltZSkJCgptb2R1bGUgbG9hZCBjdXRhZGFwdC8xLjE2CgojIyBWMQpjdXRhZGFwdCAtZyAke1BSRUlOU0VSVH0gLU8gNDAgLS1kaXNjYXJkLXVudHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcSAke1YxRn0KY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkLmZxCmN1dGFkYXB0IC1nICR7UExBU00yfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW4uZnEgYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxCgoKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWQuZnEgJHtWMVJ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fUl9jbGVhblRtcC5mcSBiZ2kvdjFfJHtOQU1FfS8ke05BTUV9X1JfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YxXyR7TkFNRX0vJHtOQU1FfV9SX2NsZWFuLmZxIGJnaS92MV8ke05BTUV9LyR7TkFNRX1fUl9jbGVhblRtcC5mcQoKIyMgVjIKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMkZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcSBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuLmZxIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcQoKCmN1dGFkYXB0IC1nICR7UFJFSU5TRVJUfSAtTyA0MCAtLWRpc2NhcmQtdW50cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fUl90cmltbWVkLmZxICR7VjJSfQpjdXRhZGFwdCAtZyAke1BMQVNNfSAtTyAzMCAtLWRpc2NhcmQtdHJpbW1lZCAtbyBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X1JfY2xlYW5UbXAuZnEgYmdpL3YyXyR7TkFNRX0vJHtOQU1FfV9SX3RyaW1tZWQuZnEKY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIGJnaS92Ml8ke05BTUV9LyR7TkFNRX1fUl9jbGVhbi5mcSBiZ2kvdjJfJHtOQU1FfS8ke05BTUV9X1JfY2xlYW5UbXAuZnEKYGBgCgojIyMgRm9yIHN0cmFpbnMgc2VxdWVuY2VkIGF0IE5ZQwpgYGB7YmFzaCBOZXh0U2VxUmVhZHNDbGVhbmluZy5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPU5ld2NsZWFucmVhZHMKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tYXJyYXk9MC04CiNTQkFUQ0ggLS1tZW09MTBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIG5ld2NsZWFuLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBuZXdjbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMjVEhFU0UgUlVOUyBPTkxZIEhBRCBSMSMjIyMKIyMgZ2V0ICBzZXQgb2YgZnEgZmlsZXMgZnJvbSBOWUMgSmFuIDIwMjAKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCiMjI0dFVCBCWSBSRUZFUkVOQ0lORyBOQU1FIyMKIyMgZ2V0IHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBGZWIgMjAyMApWMkY9L3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDItMTlfSDJKSEdBRlgyL21lcmdlZC8qJHtOQU1FfSoyLmZhc3RxLmd6CgojIyBzZXQgc2VxICYgcGxhc21pZApQUkVJTlNFUlQ9Il5OTk5OTk5OdGNhdGFhZ3RhZ2NhYWd0Z2djZ2NhdGFhZ3RhdGNhYWFhdGFhZ2NjYWN0dGd0dGd0dGd0dGN0Y3RnIgpQTEFTTT0iXmdnYXRjY2NjY2dnZ2N0Z2NhZ2dhYXR0Y2dhdGF0Y2FhZ2N0dGF0Y2dhdGEiClBMQVNNMj0iXmdnYXRjZ3R0Z3RnY3R0dGNnY3RjdGNjYWFhYWdjYXRhYWdnY2EiCgogICAgIyMgMyBzdWNjZXNzaXZlIGNsZWFuaW5nIHN0ZXBzCiAgICAjIyAtIHRyaW0gdGhlIHBsYXNtaWRpYyBzZXF1ZW5jZSBiZWZvcmUgdGhlIGluc2VydGlvbiBwb2ludCwgcmVtb3ZlIHRoZSB1bnRyaW1tZWQgcmVhZHMgCiAgICAgICAgICAgICMjIGluIHRoaXMgdmVyc2lvbiB3ZSBhbHNvIG5lZWQgdG8gdHJpbSB0aGUgTiBzZXF1ZW5jZSBhZGRlZCBieSB0aGUgcHJpbWVyIGZvciBiYXNlIGNvbXBsZXhpdHkKICAgICMjIC0gcmVtb3ZlIHJlYWRzIHRoYXQgY29udGFpbnMgcGxhc21pZGljIHNlcXVlbmNlcyBhZnRlciB0aGUgdHJpbW1lZCByZWdpb25zIChpbiBjYXNlIG9mIDEgZW56eW1lKSAKICAgICMjIC0gcmVtb3ZlIHJlYWRzIHRoYXQgY29udGFpbnMgcGxhc21pZGljIHNlcXVlbmNlcyBhZnRlciB0aGUgdHJpbW1lZCByZWdpb25zIChpbiBjYXNlIG9mIHRoZSBvdGhlciBlbnp5bWUpCQoKbW9kdWxlIGxvYWQgY3V0YWRhcHQvMS4xNgoKIyMgVjEKY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gbnljL3YxXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMUZ9CmN1dGFkYXB0IC1nICR7UExBU019IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92MV8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcSBueWMvdjFfJHtOQU1FfS8ke05BTUV9X0ZfdHJpbW1lZC5mcQpjdXRhZGFwdCAtZyAke1BMQVNNMn0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YxXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuLmZxIG55Yy92MV8ke05BTUV9LyR7TkFNRX1fRl9jbGVhblRtcC5mcQoKI2lmIFYyIGV4aXRzIGRvIHRoaXMKaWYgW1sgLWQgbnljL3YyXyR7TkFNRX0gXV0KdGhlbgogICMjIFYyCiAgY3V0YWRhcHQgLWcgJHtQUkVJTlNFUlR9IC1PIDQwIC0tZGlzY2FyZC11bnRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX3RyaW1tZWQuZnEgJHtWMkZ9CiAgY3V0YWRhcHQgLWcgJHtQTEFTTX0gLU8gMzAgLS1kaXNjYXJkLXRyaW1tZWQgLW8gbnljL3YyXyR7TkFNRX0vJHtOQU1FfV9GX2NsZWFuVG1wLmZxIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl90cmltbWVkLmZxCiAgY3V0YWRhcHQgLWcgJHtQTEFTTTJ9IC1PIDMwIC0tZGlzY2FyZC10cmltbWVkIC1vIG55Yy92Ml8ke05BTUV9LyR7TkFNRX1fRl9jbGVhbi5mcSBueWMvdjJfJHtOQU1FfS8ke05BTUV9X0ZfY2xlYW5UbXAuZnEKZmkKYGBgCgoKIyBQb3N0IENsZWFuaW5nIFJlYWQgVHJlYXRtZW50CiMjIEZvciBzdHJhaW5zIHNlcXVlbmNlZCBhdCBCR0kKIyMjIGxhdW5jaFJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50LnNoCmBgYHtiYXNoIEJHSVJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50LnNofQojIS9iaW4vYmFzaCAgICAgICAgICAgICAgICAgICAgIAojU0JBVENIIC0tam9iLW5hbWU9QkdJcG9zdDEKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tYXJyYXk9MC0yCiNTQkFUQ0ggLS1tZW09NTBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIHBvc3RjbGVhbi4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgcG9zdGNsZWFuLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyByZW1vdmUgdGVtcCBmaWxlcwpybSBiZ2kvdiovKmNsZWFuVG1wKi5mcQoKIyMgZ2V0IG5hbWVzIG9mIGZpbGVzClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBLyovKjEuZnEuZ3opKQpWMV9SMj0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoyLmZxLmd6KSkKVjFfRj0ke1YxX1IxWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KVjFfUj0ke1YxX1IyWyRTTFVSTV9BUlJBWV9UQVNLX0lEXX0KTkFNRT0ke1YxX0Y6NDg6LTQxfQoKIyMgVENBVEFBR1RBR0NBQUdUR0dDR0MKUFJJTUVSPSIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvb25IUENfZmFzdHFfdG9faW5zZXJ0aW9uc19maWxlcy9wcmltZXIyX2hlcm1lcy5mYXN0YSIKCmZvciBESVIgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwL2JnaS92MV8ke05BTUV9LyAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vCmRvCiAgY2QgIiRESVIiCiAgCiAgIyMgZ2V0IGZxcyBmb3Igc2Vjb25kIHNlcXVlbmNpbmcgcnVuCiAgaWYgW1sgIiRESVIiID09ICIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vIiBdXQogIHRoZW4KICAgIFYxRj0kKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBX3YyLyR7TkFNRX0qLyoxLmZxLmd6KQogICAgVjFSPSQobHMgL3NjcmF0Y2gvY2dzYi9ncmVzaGFtL2dyYWNlLWdsb2J1cy1zaGFyZS1kaXIvR0FfdjIvJHtOQU1FfSovKjIuZnEuZ3opCiAgZWxzZQogICAgVjFGPSIkVjFfRiIKICAgIFYxUj0iJFYxX1IiCiAgZmkKICAjIyBnZXQgY2xlYW4gSUQgZnJvbSBQRTEgYW5kIFBFMgogIGdyZXAgIjpOOjAkIiAke05BTUV9X0ZfY2xlYW4uZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fSURsaXN0CiAgZ3JlcCAiOk46MCQiICR7TkFNRX1fUl9jbGVhbi5mcSB8YXdrICd7cHJpbnQgJDF9J3xzZWQgLWUgJ3MvQC8vJz4gJHtOQU1FfV9JRGxpc3QKICBncmVwICI6TjowJCIgJHtOQU1FfV9GX2NsZWFuX3ZPbGQuZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fdk9sZF9JRGxpc3QKICBncmVwICI6TjowJCIgJHtOQU1FfV9SX2NsZWFuX3ZPbGQuZnEgfGF3ayAne3ByaW50ICQxfSd8c2VkIC1lICdzL0AvLyc+ICR7TkFNRX1fdk9sZF9JRGxpc3QKCQogICMjIGdldCB0aGUgc2VxdWVuY2Ugb2YgdGhlIDJuZCBvZiB0aGUgcGFpcgogIHpjYXQgIiRWMUYiIHwgemdyZXAgLS1uby1ncm91cC1zZXBhcmF0b3IgLUEgMSAtRmYgICR7TkFNRX1fSURsaXN0IHwgc2VkIC1lICdzL0AvPi8nID4gJHtOQU1FfV8xc2VxVG9UZXN0IAogIHpjYXQgIiRWMVIiIHwgZ3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV9JRGxpc3QgfHNlZCAtZSAncy9ALz4vJz4gJHtOQU1FfV8yc2VxVG9UZXN0CiAgemNhdCAiJFYxRiIgfCB6Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV92T2xkX0lEbGlzdCB8IHNlZCAtZSAncy9ALz4vJyA+ICR7TkFNRX1fdk9sZF8xc2VxVG9UZXN0IAogIHpjYXQgIiRWMVIiIHwgZ3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAxIC1GZiAgJHtOQU1FfV92T2xkX0lEbGlzdCB8c2VkIC1lICdzL0AvPi8nPiAke05BTUV9X3ZPbGRfMnNlcVRvVGVzdAoKICAjIyBtZXJnZSB0aGVzZSBzZXF1ZW5jZXMKICBjYXQgJHtOQU1FfV8xc2VxVG9UZXN0ICR7TkFNRX1fMnNlcVRvVGVzdCB8Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtdiAteCBcIl4tLVwiID4gJHtOQU1FfV9hbGxTZXFUb1Rlc3QuZmFzdGEKICBjYXQgJHtOQU1FfV92T2xkXzFzZXFUb1Rlc3QgJHtOQU1FfV92T2xkXzJzZXFUb1Rlc3QgfGdyZXAgLS1uby1ncm91cC1zZXBhcmF0b3IgLXYgLXggXCJeLS1cIiA+ICR7TkFNRX1fdk9sZF9hbGxTZXFUb1Rlc3QuZmFzdGEKCgogICMjIGJsYXN0IHRoZXNlIHNlcXVlbmNlcyB2cyB0aGUgcHJpbWVyMiBzZXF1ZW5jZQogIG1vZHVsZSBsb2FkIGJsYXN0Ky8yLjguMQogIGJsYXN0biAtcXVlcnkgJHtOQU1FfV9hbGxTZXFUb1Rlc3QuZmFzdGEgLXN1YmplY3QgJHtQUklNRVJ9IC10YXNrIGJsYXN0bi1zaG9ydCAtb3V0ICR7TkFNRX1fYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gLW91dGZtdCA2IC1udW1fdGhyZWFkcyAzCiAgYmxhc3RuIC1xdWVyeSAke05BTUV9X3ZPbGRfYWxsU2VxVG9UZXN0LmZhc3RhIC1zdWJqZWN0ICR7UFJJTUVSfSAtdGFzayBibGFzdG4tc2hvcnQgLW91dCAke05BTUV9X3ZPbGRfYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gLW91dGZtdCA2IC1udW1fdGhyZWFkcyAzCiAgbW9kdWxlIHB1cmdlCgogICMjIGdldCB0aGUgSUQgb2YgdGhlIG9uZXMgd2l0aCB0aGUgcHJpbWVyMiBzZXF1ZW5jZSBvbiB0aGUgMm5kCiAgY2F0ICR7TkFNRX1fYWxsU2VxVG9UZXN0X3ZzUHJpbWVyMi5ibGFzdG4gfCBhd2sgJ3twcmludCAkMX0nPiAke05BTUV9X2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gCiAgY2F0ICR7TkFNRX1fdk9sZF9hbGxTZXFUb1Rlc3RfdnNQcmltZXIyLmJsYXN0biB8IGF3ayAne3ByaW50ICQxfSc+ICR7TkFNRX1fdk9sZF9saXN0VG9FeHRyYWN0RnJvbUNsZWFuIAoKICAjIyBleHRyYWN0IGZyb20gdGhlIGNsZWFuIHRoZSBvbmVzIHdpdGggdGhlIHByaW1lcjIgb24gdGhlIDJuZAogIGNhdCAke05BTUV9X0ZfY2xlYW4uZnEgJHtOQU1FfV9SX2NsZWFuLmZxIHxncmVwIC0tbm8tZ3JvdXAtc2VwYXJhdG9yIC1BIDMgLUZmICR7TkFNRX1fbGlzdFRvRXh0cmFjdEZyb21DbGVhbiA+ICR7TkFNRX1fd2l0aFAyLmZxIAogIGNhdCAke05BTUV9X0ZfY2xlYW5fdk9sZC5mcSAke05BTUV9X1JfY2xlYW5fdk9sZC5mcSB8Z3JlcCAtLW5vLWdyb3VwLXNlcGFyYXRvciAtQSAzIC1GZiAke05BTUV9X3ZPbGRfbGlzdFRvRXh0cmFjdEZyb21DbGVhbiA+ICR7TkFNRX1fdk9sZF93aXRoUDIuZnEgCmRvbmUKYGBgCgojIyMgbGF1bmNoUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQyLnNoCmBgYHtiYXNoIEJHSVJlYWRzQ2xlYW5pbmdQb3N0VHJlYXRtZW50Mi5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPUJHSXBvc3QyCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtMgojU0JBVENIIC0tbWVtPTVHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIHBvc3RjbGVhbjIuJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIHBvc3RjbGVhbjIuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKCiMjIGdldCBuYW1lcyBvZiBmaWxlcwpWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dyZXNoYW0vZ3JhY2UtZ2xvYnVzLXNoYXJlLWRpci9HQS8qLyoxLmZxLmd6KSkKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjQ4Oi00MX0KCmZvciBESVIgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwL2JnaS92MV8ke05BTUV9LyAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YyXyR7TkFNRX0vCmRvCiAgY2QgIiRESVIiCiAgIyMgZ2V0IGRpZmZlcmVudGlhbCBJRCBiZXR3ZWVuIGNsZWFuIGFuZCBjbGVhbl92T2xkCiAgZGlmZiAke05BTUV9X2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gJHtOQU1FfV92T2xkX2xpc3RUb0V4dHJhY3RGcm9tQ2xlYW4gfCBncmVwICJePiAiIHxzZWQgLWUgJ3MvPiAvLycgPiAke05BTUV9LmRpZmYKICAjIyBnZXQgc2VxdWVuY2VzIGJhc2VkIG9uIGRpZmZlcmVudGlhbCBJRCBiZXR3ZWVuIGNsZWFuIGFuZCBjbGVhbl92T2xkIAogIGNhdCAke05BTUV9X3ZPbGRfd2l0aFAyLmZxIHxncmVwIC0tbm8tZ3JvdXAtc2VwYXJhdG9yIC1BIDMgLUZmICR7TkFNRX0uZGlmZiA+ICR7TkFNRX1fYWxsX3dpdGhQMi5mcSAKCiAgIyBmYXN0cWMgcmVwb3J0IGZvciBhbGwgdHlwZXMgb2YgcmVhZHMgd2l0aCBQMgogIG1vZHVsZSBsb2FkIGZhc3RxYy8wLjExLjggCiAgZmFzdHFjICR7TkFNRX0qX3dpdGhQMi5mcQpkb25lCmBgYAoKIyMjIGxhdW5jaFJlYWRzTWluTGVuZ3RoLnNoIApgYGB7YmFzaCBsYXVuY2hSZWFkc01pbkxlbmd0aC5zaH0KIyEvYmluL2Jhc2ggICAgICAgICAgICAgICAgICAgICAKI1NCQVRDSCAtLWpvYi1uYW1lPUJHSW1pbgojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS1hcnJheT0wLTIKI1NCQVRDSCAtLW1lbT0yNUdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gbWlubGVuZ3RoLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBtaW5sZW5ndGguJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ3Jlc2hhbS9ncmFjZS1nbG9idXMtc2hhcmUtZGlyL0dBLyovKjEuZnEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NDg6LTQxfQoKZm9yIERJUiBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvYmdpL3YxXyR7TkFNRX0vIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9iZ2kvdjJfJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyBrZWVwIHJlYWRzIHdpdGggYSBtaW4gbGVuZ3RoIG9mIDIwIGJwIGFmdGVyIGFsbCBjbGVhbmluZyBzdGVwcwogIG1vZHVsZSBsb2FkIGN1dGFkYXB0LzEuMTYKICBjdXRhZGFwdCAtbSAzMCAtbyAke05BTUV9X3dpdGhQMl9taW4yMC5mcSAke05BTUV9X3dpdGhQMi5mcQogIGN1dGFkYXB0IC1tIDMwIC1vICR7TkFNRX1fdk9sZF93aXRoUDJfbWluMjAuZnEgJHtOQU1FfV92T2xkX3dpdGhQMi5mcQogIGN1dGFkYXB0IC1tIDMwIC1vICR7TkFNRX1fYWxsX3dpdGhQMl9taW4yMC5mcSAke05BTUV9X2FsbF93aXRoUDIuZnEKZG9uZQpgYGAKCgojIyBGb3Igc3RyYWlucyBzZXF1ZW5jZWQgYXQgTllDCiMjIyBOZXh0ZXJhUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQuc2ggCkZvciB0aGUgTmV4dFNlcSBydW5zLCBpdCBpcyBzaW5nbGUgZW5kZWQuIFNvIHdlIHdpbGwganVzdCByZW1vdmUgTmV4dGVyYSB0cmFuc3Bvc2FzZSBzZXF1ZW5jZXMsIGRvIGZhc3RxYywgYW5kIGZpbHRlciB0byBrZWVwIG9ubHkgcmVhZHMgPjIwIGJwCgpgYGB7YmFzaCBOZXh0ZXJhUmVhZHNDbGVhbmluZ1Bvc3RUcmVhdG1lbnQuc2h9CiMhL2Jpbi9iYXNoICAgICAgICAgICAgICAgICAgICAgCiNTQkFUQ0ggLS1qb2ItbmFtZT1uZXh0ZXJhLWNsZWFuCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTIKI1NCQVRDSCAtLWFycmF5PTAtOAojU0JBVENIIC0tbWVtPTIwR0IKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtbyBuZXh0ZXJhY2xlYW4uJU4uJWoub3V0ICAgICAgICAjIFNURE9VVAojU0JBVENIIC1lIG5leHRlcmFjbGVhbi4lTi4lai5lcnIgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQoKIyMjVEhFU0UgUlVOUyBPTkxZIEhBRCBSMSMjIyMKIyMgZ2V0ICBzZXQgb2YgZnEgZmlsZXMgZnJvbSBOWUMgSmFuIDIwMjAKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQoKIyN0aGlzIGlzIGdvaW5nIHRvIGFzc2lnbiB0aGUgdmFyaWFibGVzIHRvIGZpbGUgbmFtZXMKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCk5FWFRFUkE9Jy9zaGFyZS9hcHBzL3RyaW1tb21hdGljLzAuMzYvYWRhcHRlcnMvTmV4dGVyYVBFLVBFLmZhJwoKZm9yIERJUiBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvbnljL3YxXyR7TkFNRX0vIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9ueWMvdjJfJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyByZW1vdmUgTmV4dGVyYSB0cmFuc3Bvc2FzZSBzZXF1ZW5jZQogICMjIGtlZXAgcmVhZHMgd2l0aCBhIG1pbiBsZW5ndGggb2YgMjAgYnAgYWZ0ZXIgYWxsIGNsZWFuaW5nIHN0ZXBzCiAgbW9kdWxlIGxvYWQgdHJpbW1vbWF0aWMvMC4zNgogIGphdmEgLWphciAvc2hhcmUvYXBwcy90cmltbW9tYXRpYy8wLjM2L3RyaW1tb21hdGljLTAuMzYuamFyIFNFICR7TkFNRX1fRl9jbGVhbl92T2xkLmZxICR7TkFNRX1fdk9sZF9taW4yMC5mcSBJTExVTUlOQUNMSVA6JHtORVhURVJBfToyOjMwOjEwIE1JTkxFTjoyMCAtdHJpbWxvZyAke05BTUV9X3ZPbGRfdHJpbW1vbWF0aWMubG9nIC10aHJlYWRzIDIKICBqYXZhIC1qYXIgL3NoYXJlL2FwcHMvdHJpbW1vbWF0aWMvMC4zNi90cmltbW9tYXRpYy0wLjM2LmphciBTRSAke05BTUV9X0ZfY2xlYW4uZnEgJHtOQU1FfV9taW4yMC5mcSBJTExVTUlOQUNMSVA6JHtORVhURVJBfToyOjMwOjEwIE1JTkxFTjoyMCAtdHJpbWxvZyAke05BTUV9X3RyaW1tb21hdGljLmxvZyAtdGhyZWFkcyAyCgogICMgZmFzdHFjIHJlcG9ydCBmb3IgYWxsIHR5cGVzIG9mIHJlYWRzCiAgbW9kdWxlIGxvYWQgZmFzdHFjLzAuMTEuOCAKICBmYXN0cWMgKl9taW4yMC5mcQpkb25lCmBgYAoKIyBNYXBwaW5nClNpbmdsZSBlbmRlZCBtYXBwaW5nIGZvciBhbGwgcmVhZHMsIGdldCBvbmx5IHVuaXF1ZWx5IG1hcHBlZCByZWFkcy4KYGBge2Jhc2ggTWFwcGluZ1NFX21lbS1hRm9yTXVsdGltYXBwZWQuc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1tYXAKI1NCQVRDSCAtLXRpbWU9MjQ6MDA6MDAKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MQojU0JBVENIIC0tYXJyYXk9MC04CiNTQkFUQ0ggLS1tZW09MjBHQgojU0JBVENIIC0tbWFpbC10eXBlPUVORAojU0JBVENIIC1vIG1hcC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgbWFwLiVOLiVqLmVyciAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CgojIyNUSEVTRSBSVU5TIE9OTFkgSEFEIFIxIyMjIwojIyBnZXQgIHNldCBvZiBmcSBmaWxlcyBmcm9tIE5ZQyBKYW4gMjAyMApWMV9SMT0oJChscyAvc2NyYXRjaC9jZ3NiL2dlbmNvcmUvb3V0L0dyZXNoYW0vMjAyMC0wMS0xMF9IVjJKMkJHWEMvbWVyZ2VkL0hWMkoyQkdYQ19uMDEqMi5mYXN0cS5neikpCgojI3RoaXMgaXMgZ29pbmcgdG8gYXNzaWduIHRoZSB2YXJpYWJsZXMgdG8gZmlsZSBuYW1lcwpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKClJFRj0iL2dlbm9taWNzL2dlbm9tZXMvSW5faG91c2UvRnVuZ2kvU2FjY2hhcm9teWNlc19jZXJldmlzaWFlL0dyZXNoYW0vR0NGXzAwMDE0NjA0NS4yX1I2NF9HQVAxL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLmZuYSIKR0ZGPSIvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvb25IUENfZmFzdHFfdG9faW5zZXJ0aW9uc19maWxlcy9HQ0ZfMDAwMTQ2MDQ1LjJfUjY0X2dlbm9taWNfR0FQMS5nZmYiCgpmb3IgRElSIGluIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC8qL3YqJHtOQU1FfS8KZG8KICBjZCAiJERJUiIKICAjIyBtYXAKICBtb2R1bGUgbG9hZCBid2EvaW50ZWwvMC43LjE1CiAgaWYgW1sgIiR7RElSOjQ5OjN9IiA9PSAiYmdpIiBdXQogIHRoZW4KICAgIGJ3YSBtZW0gLXQgMyAtYSAtTSAtUiAnQFJHXHRJRDpmb29cdFNNOmJhcicgJHtSRUZ9ICR7TkFNRX1fdk9sZF93aXRoUDJfbWluMjAuZnEgPiAke05BTUV9X21hcHBlZC5zYW0KICBlbHNlCiAgICBid2EgbWVtIC10IDMgLWEgLU0gLVIgJ0BSR1x0SUQ6Zm9vXHRTTTpiYXInICR7UkVGfSAke05BTUV9X3ZPbGRfbWluMjAuZnEgPiAke05BTUV9X21hcHBlZC5zYW0KICBmaQogIAogIG1vZHVsZSBwdXJnZQogIG1vZHVsZSBsb2FkIHNhbXRvb2xzL2ludGVsLzEuOQogICMjY29udmVydCB0byBiYW0KICAjIyBxIDEwIHRvIGdldCB1bmlxdWVseSBtYXBwZWQgcmVhZHMKICBzYW10b29scyB2aWV3IC1iUyAtcSAxMCAke05BTUV9X21hcHBlZC5zYW0gPiAke05BTUV9X21hcHBlZC5iYW0KCiAgIyMgZ2V0IHN0YXRzIGZyb20gYWxpZ25tZW50CiAgc2FtdG9vbHMgZmxhZ3N0YXQgJHtOQU1FfV9tYXBwZWQuYmFtID4gJHtOQU1FfV9mbGFnc3RhdC50eHQKICBzYW10b29scyBzb3J0IC1vICR7TkFNRX0uc29ydGVkLmJhbSAke05BTUV9X21hcHBlZC5iYW0KICBzYW10b29scyBpbmRleCAke05BTUV9LnNvcnRlZC5iYW0KZG9uZQpgYGAKCiMgSW5zZXJ0aW9uIHNpdGUgaWRlbnRpZmljYXRpb24KQWZ0ZXIgbWFwcGluZywgaW5zZXJ0aW9uIHNpdGUgaWRlbnRpZmljYXRpb24gaXMgZG9uZSBvbmUgZWFjaCBzZXF1ZW5jaW5nIHJ1biBpbmRpdmlkdWFsbHkuIFRoaXMgd2lsbCBhbGxvdyB1cyB0byBkZXRlcm1pbmUgY29ycmVsYXRpb24gYmV0d2VlbiBsaWJyYXJ5IHByZXBzIGFuZCBzZXF1ZW5jaW5nIHJ1bnMuCkFmdGVyIG1hcHBpbmcsIGJhbXMgZnJvbSBlYWNoIHJ1biBhcmUgYWxzbyBjb21iaW5lZCBpbnRvIG9uZSBiYW0gcGVyIHNhbXBsZSwgYW5kIGluc2VydGlvbiBzaXRlIGlkZW50aWZpY2F0aW9uIGlzIGRvbmUgb24gdGhlIGNvbWJpbmVkIGJhbS4gVGhpcyBtYWtlcyBkb3duIHN0cmVhbSBwcm9jZXNzaW5nIGVhc2llciwgYXMgaWRlbnRpY2FsIGluc2VydGlvbiBzaXRlcyBpZGVudGlmaWVkIGZyb20gZGlmZmVyZW50IHNlcXVlbmNpbmcgcnVucyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgY29tYmluZWQuCiMjIENvbWJpbmUgQkFNcwpgYGB7YmFzaCBjb21iaW5lX3NlcXVlbmNpbmcuc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1jb21iaW5lCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLWFycmF5PTAtOAojU0JBVENIIC0tbWVtPTEwR0IKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtbyBtZXJnZS4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgbWVyZ2UuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazo4Mzg1Mzk0CgojIyBnZXQgc2FtcGxlIG5hbWVzClYxX1IxPSgkKGxzIC9zY3JhdGNoL2Nnc2IvZ2VuY29yZS9vdXQvR3Jlc2hhbS8yMDIwLTAxLTEwX0hWMkoyQkdYQy9tZXJnZWQvSFYySjJCR1hDX24wMSoyLmZhc3RxLmd6KSkKVjFGPSR7VjFfUjFbJFNMVVJNX0FSUkFZX1RBU0tfSURdfQpOQU1FPSR7VjFGOjc2Oi0yM30KCiMgZ2V0IGFsbCBiYW1zIGZvciBlYWNoIHNhbXBsZQpueWNfYmFtcz1ueWMvdioke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQpiZ2lfYmFtcz1iZ2kvdioke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQppZiBbWyAiJHtOQU1FfSIgPT0gIjE3MjgiIHx8ICIke05BTUV9IiA9PSAiMTczNiIgfHwgIiR7TkFNRX0iID09ICIxNzQwIiBdXQp0aGVuCiAgYWxsX2JhbXM9IiQoZWNobyAkbnljX2JhbXMpICQoZWNobyAkYmdpX2JhbXMpIgplbHNlCiAgYWxsX2JhbXM9JChlY2hvICRueWNfYmFtcykKZmkKCiMjY2hlY2sgdG8gbWFrZSBzdXJlIGV2ZXJ5dGhpbmcgaXMgYmVpbmcgY29ycmVjdGx5IGNvbWJpbmVkCmVjaG8gJGFsbF9iYW1zCgojI2NoYW5nZSB0byBkaXJlY3RvcnkgZm9yIHRoaXMgc3BlY2lmaWMgc2FtcGxlIC0gQ09NQklORUQKbWtkaXIgY29tYmluZWQvJHtOQU1FfS8KCm1vZHVsZSBwdXJnZQptb2R1bGUgbG9hZCBzYW10b29scy9pbnRlbC8xLjkKIyMgbWVyZ2UgYmFtcwpzYW10b29scyBtZXJnZSBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX1fbWVyZ2VkLmJhbSAkYWxsX2JhbXMKc2FtdG9vbHMgc29ydCAtbyBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbSBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX1fbWVyZ2VkLmJhbQpzYW10b29scyBpbmRleCBjb21iaW5lZC8ke05BTUV9LyR7TkFNRX0uc29ydGVkLmJhbQpgYGAKCiMjIFBhcnNlIEJBTXMKQmF0Y2ggZmlsZQpgYGB7YmFzaCBQYXJzZUJhbS5zaH0KIyEvYmluL2Jhc2gKI1NCQVRDSCAtLWpvYi1uYW1lPXBhcnNlYmFtCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1tZW09MjVHQgojU0JBVENIIC0tY3B1cy1wZXItdGFzaz01CiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLW8gc2x1cm1QYXJzZUJhbS4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgc2x1cm1QYXJzZUJhbS4lTi4lai5lcnIgICAgICAgICMgU1RERVJSCiNTQkFUQ0ggLS1tYWlsLXVzZXI9Z2E4MjRAbnl1LmVkdQojI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazoKCm1vZHVsZSBsb2FkIHB5c2FtL2ludGVsLzAuMTEuMi4yCm1vZHVsZSBsb2FkIHNhbXRvb2xzL2ludGVsLzEuNgptb2R1bGUgbG9hZCBzYW1ibGFzdGVyL2ludGVsLzAuMS4yNAptb2R1bGUgbG9hZCBudW1weS9weXRob24yLjcvaW50ZWwvMS4xNC4wIAoKZnVuY3Rpb24gcnVuX3BhcmFsbGVsICgpCnsKc3J1biAtbjEgLS1leGNsdXNpdmUgIiRAIgp9CiNydW4KZm9yIGJhbSBpbiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvKi8qLypzb3J0ZWQuYmFtCmRvCglydW5fcGFyYWxsZWwgcHl0aG9uMi43IHBhcnNlQmFtLnB5ICRiYW0gJgpkb25lCndhaXQKYGBgClB5dGhvbiBmaWxlIHRoYXQgYWN0dWFsbHkgZG9lcyB0aGUgcGFyc2luZy4KYGBge3B5dGhvbiBwYXJzZUJhbS5weX0KIy91c3IvYmluL3B5dGhvbgppbXBvcnQgc3lzLHN0cmluZyxvcyxnbG9iLHJhbmRvbSxweXNhbSxyZSxhcmdwYXJzZQojI3N5cy5wYXRoLmluc2VydCgwLCAnL2hvbWUvYWZyaWVkcmljaC9TY3JpcHRzJykKIyNpbXBvcnQgZmFzdGEsZmlsZXMKCgpkZWYgcGFyc2VCYW0oYmFtRmlsZSk6CiAgICBwYXR0ZXJuID0gcmUuY29tcGlsZSgiXHMqIikKICAgIG91dGZpbGUgPSBiYW1GaWxlLnJlcGxhY2UoIi5zb3J0ZWQuYmFtIiwiX2luc2VydGlvblBvcy50eHQiKQogICAgb2YgPSBvcGVuKG91dGZpbGUsInciKQogICAgc2FtZmlsZT1weXNhbS5BbGlnbm1lbnRGaWxlKGJhbUZpbGUsY2hlY2tfc3E9RmFsc2UpCiAgICBjaHJvbT0iY2hyb21vc29tZTEiCiAgICBsaXN0UG9zPVtdCiAgICBjb3VudCA9IDAKICAgIGZvciByZWFkIGluIHNhbWZpbGUuZmV0Y2goKToKCQkjIHdyaXRlIHdoZW4gY2hhbmdpbmcgY2hyb21vc29tZQoJCWlmIGNocm9tICE9IHJlYWQucmVmZXJlbmNlX25hbWU6CgkJICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3MpOgoJCQkJb2Yud3JpdGUoIiVzXHQlc1x0JXNcbiIgJSAoY2hyb20scG9zLHBvcykpCgkJICAgIGNocm9tPXJlYWQucmVmZXJlbmNlX25hbWUKICAgICAgICAJICAgIGxpc3RQb3M9W10KCgkJY2xpcGluNSA9IDAKCQljaWdhciA9IHJlYWQuY2lnYXJzdHJpbmcKCgkJIyBpZiBzb2Z0Q2xpcHBlZCAKCQlpZiBjaWdhci5maW5kKCJTIikgIT0gLTE6CgkJCSMgYXJlIHRoZSBzb2Z0LWNsaXBwZWQgYmFzZXMgbG9jYXRlZCBhdCA1JyBlbmQKCQkJIyBpZiB5ZXMsIHdpbGwgbm90IGJlIGNvbnNpZGVyZWQgYXMgYW4gaW5zZXJ0b24gcG9zaXRpb24KCQkJaWYgcmVhZC5pc19yZXZlcnNlOgoJCQkJaWYgY2lnYXIucmZpbmQoIlMiKT5jaWdhci5maW5kKCJNIik6CgkJCQkJY2xpcGluNSA9IDEKCQkJZWxzZToKCQkJCWlmIGNpZ2FyLmZpbmQoIlMiKTxjaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQoJCSMgaWYgbm8gc29mdGNsaXBwZWQgaW4gNScKCQlpZiBjbGlwaW41ID09IDA6CgkJCWlmIHJlYWQuaXNfcmV2ZXJzZToKCQkJCXN0YXJ0ID0gcmVhZC5yZWZlcmVuY2VfZW5kCgkJCWVsc2U6CgkJCQlzdGFydCA9IHJlYWQucmVmZXJlbmNlX3N0YXJ0KzEKCQkJaWYgaW50KHN0YXJ0KSBub3QgaW4gbGlzdFBvczoKCQkJCWxpc3RQb3MuYXBwZW5kKGludChzdGFydCkpCgkjIGlmIG5vIG1pc21hdGNoIGF0IHRoZSBmaXJzdCBwb3NpdGlvbiwgc2hvdWxkIHRlc3QgMCBhcyBmaXJ0ICgvbGFzdCkgY2hhcmFjdGVyIG9mIHRoZSBmbGFnIGZvciByZWFkcyBpbiBmb3J3YXJkICgvcmV2ZXJzZSkKICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3MpOgoJCW9mLndyaXRlKCIlc1x0JXNcdCVzXG4iICUgKGNocm9tLHBvcyxwb3MpKQogICAgc2FtZmlsZS5jbG9zZSgpCiAgICBvZi5jbG9zZSgpCgoKZGVmIGdldFJlYWRQZXJQb3MoYmFtRmlsZSk6CiAgICBwYXR0ZXJuID0gcmUuY29tcGlsZSgiXHMqIikKICAgIG91dGZpbGUgPSBiYW1GaWxlLnJlcGxhY2UoIi5zb3J0ZWQuYmFtIiwiX3JlYWRQZXJQb3MudHh0IikKCW9mID0gb3BlbihvdXRmaWxlLCJ3IikKICAgICAgICBzYW1maWxlPXB5c2FtLkFsaWdubWVudEZpbGUoYmFtRmlsZSwicmIiKQogICAgICAgIGNocm9tPSJjaHJvbW9zb21lMSIKICAgICAgICBsaXN0UG9zPVtdCglsaXN0UG9zVW5pcT1bXQogICAgICAgIGNvdW50ID0gMAogICAgICAgIGZvciByZWFkIGluIHNhbWZpbGUuZmV0Y2goKToKICAgICAgICAgICAgICAgIGlmIGNocm9tICE9IHJlYWQucmVmZXJlbmNlX25hbWU6CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciBwb3MgaW4gc29ydGVkKGxpc3RQb3NVbmlxKToKCQkJCW9mLndyaXRlKCIlc1x0JXNcdCVzXG4iICUgKGNocm9tLHBvcyxsaXN0UG9zLmNvdW50KHBvcykpKQogICAgICAgICAgICAgICAgICAgICAgICBjaHJvbT1yZWFkLnJlZmVyZW5jZV9uYW1lCiAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RQb3M9W10KCQkJbGlzdFBvc1VuaXE9W10KCQljbGlwaW41ID0gMAogICAgICAgICAgICAgICAgY2lnYXIgPSByZWFkLmNpZ2Fyc3RyaW5nCiAgICAgICAgICAgICAgICAjIGlmIHNvZnRDbGlwcGVkIAogICAgICAgICAgICAgICAgaWYgY2lnYXIuZmluZCgiUyIpICE9IC0xOgogICAgICAgICAgICAgICAgICAgICAgICBpZiByZWFkLmlzX3JldmVyc2U6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgY2lnYXIucmZpbmQoIlMiKT5jaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGNpZ2FyLmZpbmQoIlMiKTxjaWdhci5maW5kKCJNIik6CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwaW41ID0gMQogICAgICAgICAgICAgICAgIyBpZiBubyBzb2Z0Y2xpcHBlZCBpbiA1JwogICAgICAgICAgICAgICAgaWYgY2xpcGluNSA9PSAwOgogICAgICAgICAgICAgICAgICAgICAgICBpZiByZWFkLmlzX3JldmVyc2U6CgkJCQlzdGFydCA9IHJlYWQucmVmZXJlbmNlX2VuZAogICAgICAgICAgICAgICAgICAgICAgICBlbHNlOgoJCQkJc3RhcnQgPSByZWFkLnJlZmVyZW5jZV9zdGFydCsxCgkJCWlmIGludChzdGFydCkgbm90IGluIGxpc3RQb3NVbmlxOgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3RQb3NVbmlxLmFwcGVuZChpbnQoc3RhcnQpKQoKCQkJbGlzdFBvcy5hcHBlbmQoaW50KHN0YXJ0KSkKCiAgICAgICAgZm9yIHBvcyBpbiBsaXN0UG9zVW5pcToKCQlvZi53cml0ZSgiJXNcdCVzXHQlc1xuIiAlIChjaHJvbSxwb3MsbGlzdFBvcy5jb3VudChwb3MpKSkKCiAgICAgICAgc2FtZmlsZS5jbG9zZSgpCglvZi5jbG9zZSgpCgoKCgpwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCnBhcnNlci5hZGRfYXJndW1lbnQoImZpbGUiKQphcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQoKI2FyZ3MgPSBzeXMuYXJndlsxOl0KI2FsbF9hcmdzID0gZmlsZXMuZ2V0X2FyZ3MoYXJncykKI3RyeToKIyAgICBzZXFmID0gYWxsX2FyZ3NbImYiXQojZXhjZXB0OgojICAgIHNlcWYgPSAiIgojdHJ5OiAKIyAgICBzZXFvID0gYWxsX2FyZ3NbIm8iXQojZXhjZXB0OgojICAgIHNlcW8gPSAiIgogCnBhcnNlQmFtKGFyZ3MuZmlsZSkKZ2V0UmVhZFBlclBvcyhhcmdzLmZpbGUpCgpgYGAKIyMgSW50ZXJzZWN0IEJFRApCYXRjaCBzY3JpcHQKYGBge2Jhc2ggSW50ZXJzZWN0QmVkLnNofQojIS9iaW4vYmFzaAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tbWVtPTE1R0IKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9NAojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC1vIGludGVyc2VjdEJlZC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgaW50ZXJzZWN0QmVkLiVOLiVqLmVyciAgICAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CiNTQkFUQ0ggLS1kZXBlbmRlbmN5PWFmdGVyb2s6ODIxMjkzMwoKbW9kdWxlIGxvYWQgYmVkdG9vbHMvaW50ZWwvMi4yNi4wIApHRkY9Ii9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLmdmZiIKCmZ1bmN0aW9uIHJ1bl9wYXJhbGxlbCAoKQp7CnNydW4gLW4xIC0tZXhjbHVzaXZlICIkQCIKfQoKZm9yIGluc2VyUG9zIGluIC9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC8qLyovKl9pbnNlcnRpb25Qb3MudHh0CmRvCglvdXRmaWxlPSR7aW5zZXJQb3MvLnR4dC9fYW5ub3RhdGVkLmJlZCB9CglydW5fcGFyYWxsZWwgaW50ZXJzZWN0QmVkIC13YiAtYSAkaW5zZXJQb3MgLWIgJHtHRkZ9ID4gJG91dGZpbGUgJgoKZG9uZQp3YWl0CmBgYAoKQSBtYW51YWwgc3RlcCB0byBnZXQgQ0RTIGxpbmVzIGluIGJlZGZpbGUgYW5kIGdldCByaWQgb2YgYW55dGhpbmcgbm90IGluIGEgQ0RTLgpBIGxpdHRsZSBlbWJhcmFzc2luZyBidXQgd2hhdGV2ZXIKYGBge2Jhc2ggZ2V0X0NEUy5zaH0KIyEvYmluL2Jhc2gKI1NCQVRDSCAtLWpvYi1uYW1lPWdldGNkcwojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLW8gZ2V0Q0RTLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBnZXRDRFMuJU4uJWouZXJyICAgICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKI1NCQVRDSCAtLWFycmF5PTAtOAojI1NCQVRDSCAtLWRlcGVuZGVuY3k9YWZ0ZXJvazoKCiMjIGdldCBzYW1wbGUgbmFtZXMKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKZm9yIGZpbGUgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwLyovKiR7TkFNRX0vJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkLmJlZApkbwogIHBhdGg9JChlY2hvICRmaWxlIHwgY3V0IC1kJy8nIC1mIDEsMiwzLDQsNSw2KQogIGdyZXAgQ0RTICR7ZmlsZX0gPiAkcGF0aC8ke05BTUV9X2luc2VydGlvblBvc19hbm5vdGF0ZWRDRFMuYmVkCiAgYXdrICckNiA9PSAiQ0RTIicgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTLmJlZCA+ICRwYXRoLyR7TkFNRX1faW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUzEuYmVkCiAgbXYgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTMS5iZWQgJHBhdGgvJHtOQU1FfV9pbnNlcnRpb25Qb3NfYW5ub3RhdGVkQ0RTLmJlZApkb25lCmBgYAoKIyMgQmVkIFBvc3QgVHJlYXRtZW50CkJhdGNoIHNjcmlwdApgYGB7YmFzaCBCZWRQb3N0VHJlYXRtZW50LnNofQojIS9iaW4vYmFzaAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tbWVtPTE1R0IKI1NCQVRDSCAtLWNwdXMtcGVyLXRhc2s9MwojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC1vIEJlZC4lTi4lai5vdXQgICAgICAgICMgU1RET1VUCiNTQkFUQ0ggLWUgQmVkLiVOLiVqLmVyciAgICAgICAgIyBTVERFUlIKI1NCQVRDSCAtLW1haWwtdHlwZT1FTkQKI1NCQVRDSCAtLW1haWwtdXNlcj1nYTgyNEBueXUuZWR1CiNTQkFUQ0ggLS1kZXBlbmRlbmN5PWFmdGVyb2s6NzY0NjU5OAoKbW9kdWxlIGxvYWQgcHlzYW0vaW50ZWwvMC4xMS4yLjIKbW9kdWxlIGxvYWQgc2FtdG9vbHMvaW50ZWwvMS42Cm1vZHVsZSBsb2FkIHNhbWJsYXN0ZXIvaW50ZWwvMC4xLjI0Cm1vZHVsZSBsb2FkIG51bXB5L3B5dGhvbjIuNy9pbnRlbC8xLjE0LjAgCgpmdW5jdGlvbiBydW5fcGFyYWxsZWwgKCkKewpzcnVuIC1uMSAtLWV4Y2x1c2l2ZSAiJEAiCn0KCmZvciBzYW1wbGUgaW4gL3NjcmF0Y2gvZ2E4MjQvaGVybWVzX2luc2VydGlvbnNfc2VtaWZpbmFsX01hcjIwLyovKi8qX2luc2VydGlvblBvc19hbm5vdGF0ZWRDRFMuYmVkCmRvCglydW5fcGFyYWxsZWwgcHl0aG9uMi43IGJlZFBvc3RUcmVhdG1lbnQucHkgJHNhbXBsZSAmCgpkb25lCndhaXQKYGBgClB5dGhvbiBzY3JpcHQKYGBge3B5dGhvbiBiZWRQb3N0VHJlYXRtZW50LnB5fQojL3Vzci9iaW4vcHl0aG9uCmltcG9ydCBzeXMsc3RyaW5nLG9zLGdsb2IscmFuZG9tLHB5c2FtLHJlLGFyZ3BhcnNlCgoKZGVmIHBvc3RUcmVhdG1lbnQoc2FtcGxlKToKCXByaW50ICJnZXRHZW5lTGlzdCIKCWdlbmVMaXN0PWdldEdlbmVMaXN0KHNhbXBsZSkKCXByaW50ICJnZXRJbnNlcnRpb25QZXJHZW5lIgoJaW5zUGVyR2VuZT1nZXRJbnNlcnRpb25QZXJHZW5lKGdlbmVMaXN0KQoJcHJpbnQgImluc2VydGlvblBlcktiUGVyR2VuZSIKCWluc2VydGlvblBlcktiUGVyR2VuZShpbnNQZXJHZW5lKQoJcHJpbnQgImdldE5vSW5zR2VuZSIKCWdldE5vSW5zR2VuZShnZW5lTGlzdCkKCmRlZiBjcmVhdGVMZW5EaWNvKGluZmlsZSk6CglkaWNvID0ge30KICAgICAgICBsaW5lcyA9IG9wZW4oaW5maWxlLCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCiAgICAgICAgY2RzID0gIiIKICAgICAgICBsZW5ndGggPSAiIgogICAgICAgIGZvciBsaW5lIGluIGxpbmVzOgogICAgICAgICAgICAgICAgaWYgbGluZSAhPSAiIjoKCQkJY2RzID0gbGluZS5zcGxpdCgiXHQiKVswXQogICAgICAgICAgICAgICAgICAgIAlkaWNvW2Nkc10gPSBpbnQobGluZS5zcGxpdCgiXHQiKVsxXSkKICAgIAlyZXR1cm4gZGljbwoKCmRlZiBpbnNlcnRpb25QZXJLYlBlckdlbmUoaW5zRmlsZSk6CgljZHNMZW5ndGg9Ii9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL2Nkc0xlbmd0aC50YWIiCglkaWNvTGVuPWNyZWF0ZUxlbkRpY28oY2RzTGVuZ3RoKQoJI2luc0ZpbGU9Imluc2VydGlvblBlckdlbmUtcmVsLnRhYiIKCWluc0tiRmlsZT1pbnNGaWxlLnJlcGxhY2UoIlBlckdlbmUudHh0IiwiUGVyS2JQZXJHZW5lLnR4dCIpCglvZj1vcGVuKGluc0tiRmlsZSwidyIpCglsaW5lcz1vcGVuKGluc0ZpbGUsInIiKS5yZWFkKCkuc3BsaXQoIlxuIikKCWZvciBsaW5lIGluIGxpbmVzWzE6XToKCQlpZiBsaW5lICE9ICIiOgoJCQllbD1saW5lLnNwbGl0KCJcdCIpCgkJCW9mLndyaXRlKCIlc1x0JTAuMmZcbiIgJSAoZWxbMF0sZmxvYXQoZWxbMV0pKjEwMDAvZGljb0xlbltlbFswXV0pKQoJb2YuY2xvc2UoKQoKZGVmIHJlbW92ZVJlZHVuZGFudCgpOgoJaW5maWxlPSJsaXN0QWxsR2VuZXMudHh0IgoJb3V0ZmlsZT0ibGlzdEFsbE5SR2VuZXMudHh0IgoJb2Y9b3BlbihvdXRmaWxlLCJ3IikKCWluTGlzdD1vcGVuKGluZmlsZSwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQoJc2V0VW5pcXVlPXNldChpbkxpc3QpCglsaXN0VW5pcXVlPWxpc3Qoc2V0VW5pcXVlKQoJCglmb3IgZ2VuZSBpbiBzb3J0ZWQobGlzdFVuaXF1ZSk6CgkJaWYgZ2VuZSE9IiI6CgkJCW9mLndyaXRlKCclc1xuJyVnZW5lKQoJb2YuY2xvc2UoKQoKCmRlZiBnZXRHZW5lTGlzdChzYW1wbGUpOgogICAgICAgIGJlZGZpbGU9c2FtcGxlCglvdXRmaWxlPWJlZGZpbGUucmVwbGFjZSgiaW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUy5iZWQiLCJnZW5lc1dpdGhJbnNlcnRpb24udHh0IikKCW9mPW9wZW4ob3V0ZmlsZSwidyIpCglsaW5lcyA9IG9wZW4oYmVkZmlsZSwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQoJZm9yIGxpbmUgaW4gbGluZXM6CgkJaWYgbGluZSAhPSAiIjoKCQkJZWw9bGluZS5zcGxpdCgiXHQiKQoJCQlnZW5lPWVsWzExXS5zcGxpdCgiOyIpWzBdLnJlcGxhY2UoIlBhcmVudD0iLCIiKQoJCQlvZi53cml0ZSgiJXNcbiIgJSBnZW5lKQoJb2YuY2xvc2UoKQoJcmV0dXJuIG91dGZpbGUKCgpkZWYgZ2V0SW5zZXJ0aW9uUGVyR2VuZShnZW5lTGlzdCk6CiAgICAgICAgbGlzdFNBVEFZR2VuZXM9b3BlbihnZW5lTGlzdCwiciIpLnJlYWQoKS5zcGxpdCgiXG4iKQogICAgICAgIGxpc3RHZW5lc1dpdGhJbnNlcnRpb249c29ydGVkKGxpc3RTQVRBWUdlbmVzKQogICAgICAgIHNldFVuaXF1ZUdlbmVzV2l0aEluc2VydGlvbj1zZXQobGlzdEdlbmVzV2l0aEluc2VydGlvbikKICAgICAgICBsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uPWxpc3Qoc2V0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uKQoJb3V0ZmlsZT1nZW5lTGlzdC5yZXBsYWNlKCJnZW5lc1dpdGhJbnNlcnRpb24udHh0IiwiaW5zZXJ0aW9uUGVyR2VuZS50eHQiKQoJb2Y9b3BlbihvdXRmaWxlLCJ3IikKCW9mLndyaXRlKCJDRFNcdCNpbnNlcnRpb25cbiIpCiAgICAgICAgCiAgICAgICAgZm9yIGNkcyBpbiBsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uOgoJCWlmIGNkcyAhPSAiIjoKICAgICAgICAJCW9mLndyaXRlKCIlc1x0JXNcbiIgJSAoY2RzLGxpc3RHZW5lc1dpdGhJbnNlcnRpb24uY291bnQoY2RzKSkpCglvZi5jbG9zZSgpCglyZXR1cm4gb3V0ZmlsZQoKCmRlZiBnZXROb0luc0dlbmUoZ2VuZUxpc3QpOgoJbGlzdEFsbEdlbmVzPW9wZW4oIi9zY3JhdGNoL2dhODI0L2hlcm1lc19pbnNlcnRpb25zX3NlbWlmaW5hbF9NYXIyMC9vbkhQQ19mYXN0cV90b19pbnNlcnRpb25zX2ZpbGVzL2xpc3RBbGxHZW5lcy50eHQiLCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCglsaXN0U0FUQVlHZW5lcz1vcGVuKGdlbmVMaXN0LCJyIikucmVhZCgpLnNwbGl0KCJcbiIpCglvdXRmaWxlPWdlbmVMaXN0LnJlcGxhY2UoIkluc2VydGlvbiIsIk5vSW5zZXJ0aW9uIikKCW9mPW9wZW4ob3V0ZmlsZSwidyIpCglsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uPXNvcnRlZChsaXN0U0FUQVlHZW5lcykKCSNwcmludCBsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uCglzZXRVbmlxdWVHZW5lc1dpdGhJbnNlcnRpb249c2V0KGxpc3RHZW5lc1dpdGhJbnNlcnRpb24pCglsaXN0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uPWxpc3Qoc2V0VW5pcXVlR2VuZXNXaXRoSW5zZXJ0aW9uKQoJCgkjY29tcGFyZSBBbGwgZ2VuZXMgYW5kIGdlbmVzIHdpdGggYXQgbGVhc3QgMSBpbnNlcnRpb24KCSNwcmludCAiR2VuZXMgd2l0aCBubyBpbnNlcnRpb24iCglmb3IgZ2VuZSBpbiBsaXN0QWxsR2VuZXM6CgkJI3ByaW50IGdlbmUKCQkjaWYgZ2VuZSBub3QgaW4gbGlzdFVuaXF1ZUdlbmVzV2l0aEluc2VydGlvbjoKCQlpZiBnZW5lIG5vdCBpbiBsaXN0R2VuZXNXaXRoSW5zZXJ0aW9uOgoJCQkjcHJpbnQgInRoaXMgb25lIGluIG5vdCBpbiB0aGUgbGlzdCJpCgkJCW9mLndyaXRlKCIlc1xuIiAlIGdlbmUpCQkKCQkJI3ByaW50IGdlbmUKCW9mLmNsb3NlKCkKCgpwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCnBhcnNlci5hZGRfYXJndW1lbnQoImZpbGUiKQphcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQoKcG9zdFRyZWF0bWVudChhcmdzLmZpbGUpCgpgYGAKCiMgTnVtYmVyIG9mIGluc2VydGlvbiBzaXRlcyBvdmVyIG5vbiBvdmVybGFwcGluZyB3aW5kb3dzIG9mIDEwMCBiYXNlcGFpcnMgb3ZlciB0aGUgZ2Vub21lCkkgYW0gb25seSBkb2luZyB0aGlzIGZvciB0aGUgY29tYmluZWQgZmlsZXMKYGBge2Jhc2ggaW5zZXJ0X3dpbmRvd3Muc2h9CiMhL2Jpbi9iYXNoCiNTQkFUQ0ggLS1qb2ItbmFtZT1pbldpbgojU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC0tbm9kZXM9MQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS1hcnJheT0wLTgKI1NCQVRDSCAtLW1lbT0xMEdCCiNTQkFUQ0ggLS1tYWlsLXR5cGU9RU5ECiNTQkFUQ0ggLW8gaW5XaW5kb3dzLiVOLiVqLm91dCAgICAgICAgIyBTVERPVVQKI1NCQVRDSCAtZSBpbldpbmRvd3MuJU4uJWouZXJyICAgICAjIFNUREVSUgojU0JBVENIIC0tbWFpbC11c2VyPWdhODI0QG55dS5lZHUKCiMjIGdldCBzYW1wbGUgbmFtZXMKVjFfUjE9KCQobHMgL3NjcmF0Y2gvY2dzYi9nZW5jb3JlL291dC9HcmVzaGFtLzIwMjAtMDEtMTBfSFYySjJCR1hDL21lcmdlZC9IVjJKMkJHWENfbjAxKjIuZmFzdHEuZ3opKQpWMUY9JHtWMV9SMVskU0xVUk1fQVJSQVlfVEFTS19JRF19Ck5BTUU9JHtWMUY6NzY6LTIzfQoKI2dldCB0aGUgd2luZG93cyBmaWxlcwpXSU5ET1dTPScvc2NyYXRjaC9nYTgyNC9oZXJtZXNfd2dzL2JlZF93aW5kb3dzL0dDRl8wMDAxNDYwNDUuMl9SNjRfZ2Vub21pY19HQVAxLndpbmRvd3MnCgojZ2V0IG51bWJlciB1bmlxdWUgaW5zZXJ0aW9uIHNpdGVzIHBlciB3aW5kb3cKbW9kdWxlIGxvYWQgYmVkdG9vbHMvaW50ZWwvMi4yNy4xCmJlZHRvb2xzIGNvdmVyYWdlIC1jb3VudHMgLXNvcnRlZCAtYSAkV0lORE9XUyAtYiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvY29tYmluZWQvJHtOQU1FfS8ke05BTUV9X2luc2VydGlvblBvcy50eHQgPiAvc2NyYXRjaC9nYTgyNC9oZXJtZXNfaW5zZXJ0aW9uc19zZW1pZmluYWxfTWFyMjAvY29tYmluZWQvJHtOQU1FfS8ke05BTUV9X2luc2VydGlvbldpbmRvd3MuY292CmBgYAoKCiMgT3V0cHV0cyBmcm9tIHRoaXMgc2NyaXB0IHRoYXQgYXJlIGlucHV0cyBpbnRvIG5leHQgKFIgYmFzZWQpIGFuYWx5c2lzIHNjcmlwdApFYWNoIG9mIHRoZSBmb2xsb3dpbmcgaXMgb3V0cHV0IGZvciBlYWNoIHNhbXBsZToKKiBmYXN0cWMgZmlsZXMgZm9yIGVhY2ggc2VxdWVuY2luZyBydW4KKiByZWFkUGVyUG9zLnR4dAoqIGluc2VydGlvblBvcy50eHQKKiBnZW5lc1dpdGhOb0luc2VydGlvbi50eHQKKiBpbnNlcnRpb25QZXJHZW5lLnR4dAoqIGluc2VydGlvblBlcktiUGVyR2VuZS50eHQKKiBnZW5lc1dpdGhJbnNlcnRpb24udHh0CiogaW5zZXJ0aW9uUG9zX2Fubm90YXRlZENEUy5iZWQgPwoqIGluc2VydGlvblBvc19hbm5vdGF0ZWQuYmVkID8KKiBpbnNlcnRpb25XaW5kb3dzLmNvdiAob25seSBkb25lIGZvciBjb21iaW5lZCkKCg==