Preprocessing
The preprocessing is mostly a normal DNA sequencing pipeline:
- Trim the reads.
- Map them against the plasmid, pDONR201.
- Map the unmapped reads from #2 against PA01.
- Count the reads by locus_tag to identify missing genes.
- Use freebayes to identify variant positions.
- Parse the freebayes output down to an easy to interpret format.
Trimming
This is my default trimomatic invocation.
cd preprocessing
start=$(pwd)
for i in $(/bin/ls); do
cd ${i}
cyoa --task trim --method trim --input $(/bin/ls *.gz | tr '\n' ':' | sed 's/:$//g')
cd $start
done
Here is the script which resulted for the poola sample:
I still have an old check in it from an earlier version of trimomatic which would sometimes fail.
Individual trimming script
#SBATCH --export=ALL
#SBATCH --mail-type=NONE
#SBATCH --open-mode=append
#SBATCH --chdir=/fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola
#SBATCH --partition=dpart
#SBATCH --qos=workstation --nice=10
#SBATCH --nodes=1 --requeue
#SBATCH --time=24:00:00
#SBATCH --job-name=01trim_ORFeome_Pool_A_S1_R1_001
#SBATCH --mem=24G
#SBATCH --cpus-per-task=3
#SBATCH --output=outputs/log.txt.sbatch
set -o errexit
set -o errtrace
set -o pipefail
export LESS='--buffers 0'
script="$(pwd)/$0"
err() {
echo "Error occurred:"
awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$script }' L=$1 $script
}
trap 'err $LINENO' ERR
echo "## Started /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/scripts/01trim_ORFeome_Pool_A_S1_R1_001.sh at $(date) on $(hostname) with id ${SLURM_JOBID}." >> outputs/log.txt
module add trimomatic
## This call to trimomatic removes illumina and epicentre adapters from ORFeome_Pool_A_S1_R1_001.fastq.gz:ORFeome_Pool_A_S1_R2_001.fastq.gz.
## It also performs a sliding window removal of anything with quality <25;
## cutadapt provides an alternative to this tool.
## The original sequence data is recompressed and saved in the sequences/ directory.
mkdir -p outputs/01trimomatic
## Note that trimomatic prints all output and errors to STDERR, so send both to output
trimmomatic PE \
-threads 1 \
-phred33 \
<(less r1.fastq.gz) <(less r2.fastq.gz) \
ORFeome_Pool_A_S1_R1_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R1_001-trimmed_unpaired.fastq \
ORFeome_Pool_A_S1_R2_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R2_001-trimmed_unpaired.fastq \
ILLUMINACLIP:/cbcb/sw/RedHat-7-x86_64/common/local/perl/5.34/lib/site_perl/5.34.0/auto/share/dist/Bio-Adventure/genome/adapters.fa:2:20:10:2:keepBothReads \
SLIDINGWINDOW:4:20 MINLEN:40 \
1>outputs/01trimomatic/ORFeome_Pool_A_S1_R1_001-trimomatic.stdout \
2>outputs/01trimomatic/ORFeome_Pool_A_S1_R1_001-trimomatic.stderr
excepted=$( { grep "Exception" "outputs/01trimomatic/ORFeome_Pool_A_S1_R1_001-trimomatic.stdout" || test $? = 1; } )
## The following is in case the illumina clipping fails, which it does if this has already been run I think.
if [[ "${excepted}" != "" ]]; then
trimmomatic PE \
-threads 1 \
-phred33 \
<(less r1.fastq.gz) <(less r2.fastq.gz) \
ORFeome_Pool_A_S1_R1_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R1_001-trimmed_unpaired.fastq \
ORFeome_Pool_A_S1_R2_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R2_001-trimmed_unpaired.fastq \
SLIDINGWINDOW:4:25 MINLEN:50\
1>outputs/01trimomatic/ORFeome_Pool_A_S1_R1_001-trimomatic.stdout \
2>outputs/01trimomatic/ORFeome_Pool_A_S1_R1_001-trimomatic.stderr
fi
sleep 10
mv ORFeome_Pool_A_S1_R1_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R1_001-trimmed.fastq
mv ORFeome_Pool_A_S1_R2_001-trimmed_paired.fastq ORFeome_Pool_A_S1_R2_001-trimmed.fastq
## Recompress the unpaired reads, this should not take long.
xz -9e -f ORFeome_Pool_A_S1_R1_001-trimmed_unpaired.fastq
xz -9e -f ORFeome_Pool_A_S1_R2_001-trimmed_unpaired.fastq
## Recompress the paired reads.
xz -9e -f ORFeome_Pool_A_S1_R1_001-trimmed.fastq
xz -9e -f ORFeome_Pool_A_S1_R2_001-trimmed.fastq
ln -sf ORFeome_Pool_A_S1_R1_001-trimmed.fastq.xz r1_trimmed.fastq.xz
ln -sf ORFeome_Pool_A_S1_R2_001-trimmed.fastq.xz r2_trimmed.fastq.xz
## The following lines give status codes and some logging
echo "## Job status: $? " >> outputs/log.txt
echo "## $(hostname) Finished ${SLURM_JOBID} 01trim_ORFeome_Pool_A_S1_R1_001.sh at $(date), it took $(( SECONDS / 60 )) minutes." >> outputs/log.txt
if [[ -x "$(command -v sstat)" && ! -z "${SLURM_JOBID}" ]]; then
walltime=$(scontrol show job "${SLURM_JOBID}" | grep RunTime | perl -F'/\s+|=/' -lane '{print $F[2]}' 2>/dev/null)
echo "#### walltime used by ${SLURM_JOBID} was: ${walltime:-null}" >> outputs/log.txt
maxmem=$(sstat --format=MaxVMSize -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### maximum memory used by ${SLURM_JOBID} was: ${maxmem:-null}" >> outputs/log.txt
avecpu=$(sstat --format=AveCPU -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### average cpu used by ${SLURM_JOBID} was: ${avecpu:-null}" >> outputs/log.txt
fi
## Adding a little logic to have skip finished jobs.
touch outputs/logs/01trim_ORFeome_Pool_A_S1_R1_001.finished
Mapping against pDONR
This was followed by my default mapping against the plasmid via hisat2.
I previously downloaded a copy of pDONR201 and ran the following on it:
cyoa --task index --method indexhisat --input pDONR201.fasta --species pDONR201
I did not generate a gff file for this, so htseq is not run.
The following invocation queues 2 jobs on the cluster, 1 for the mapping and 1 to sort/compress/index the alignment.
cd preprocessing
start=$(pwd)
for i in $(/bin/ls); do
cd ${i}
cyoa --task map --method hisat --species pDONR201 --input r1_trimmed.fastq.xz:r2_trimmed.fastq.xz
cd $start
done
Individual pDONR mapping script
#!/usr/bin/env bash
#SBATCH --export=ALL
#SBATCH --mail-type=NONE
#SBATCH --open-mode=append
#SBATCH --chdir=/fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola
#SBATCH --partition=dpart
#SBATCH --qos=workstation --nice=10
#SBATCH --nodes=1 --requeue
#SBATCH --time=10:00:00
#SBATCH --job-name=40hisat2_pDONR201_genome
#SBATCH --mem=24G
#SBATCH --cpus-per-task=4
#SBATCH --output=outputs/log.txt.sbatch
set -o errexit
set -o errtrace
set -o pipefail
export LESS='--buffers 0'
script="$(pwd)/$0"
err() {
echo "Error occurred:"
awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$script }' L=$1 $script
}
trap 'err $LINENO' ERR
echo "## Started /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/scripts/40hisat2_pDONR201_genome.sh at $(date) on $(hostname) with id ${SLURM_JOBID}." >> outputs/log.txt
module add hisat2 samtools htseq bamtools
## This is a hisat2 alignment of -1 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/r1_trimmed.fastq.xz) -2 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/r2_trimmed.fastq.xz) against /cbcbhomes/abelew/libraries/genome/indexes/pDONR201
mkdir -p outputs/40hisat2_pDONR201
hisat2 -x /cbcbhomes/abelew/libraries/genome/indexes/pDONR201 \
-p 4 \
-q -1 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/r1_trimmed.fastq.xz) -2 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/r2_trimmed.fastq.xz) \
--phred33 \
--un outputs/40hisat2_pDONR201/poola_unaldis_pDONR201_genome.fastq \
--al outputs/40hisat2_pDONR201/poola_aldis_pDONR201_genome.fastq \
--un-conc outputs/40hisat2_pDONR201/poola_unalcon_pDONR201_genome.fastq \
--al-conc outputs/40hisat2_pDONR201/poola_alcon_pDONR201_genome.fastq \
-S outputs/40hisat2_pDONR201/poola_pDONR201_genome.sam \
2>outputs/40hisat2_pDONR201/hisat2_pDONR201_genome_poola.stderr \
1>outputs/40hisat2_pDONR201/hisat2_pDONR201_genome_poola.stdout
## The following lines give status codes and some logging
echo "## Job status: $? " >> outputs/log.txt
echo "## $(hostname) Finished ${SLURM_JOBID} 40hisat2_pDONR201_genome.sh at $(date), it took $(( SECONDS / 60 )) minutes." >> outputs/log.txt
if [[ -x "$(command -v sstat)" && ! -z "${SLURM_JOBID}" ]]; then
walltime=$(scontrol show job "${SLURM_JOBID}" | grep RunTime | perl -F'/\s+|=/' -lane '{print $F[2]}' 2>/dev/null)
echo "#### walltime used by ${SLURM_JOBID} was: ${walltime:-null}" >> outputs/log.txt
maxmem=$(sstat --format=MaxVMSize -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### maximum memory used by ${SLURM_JOBID} was: ${maxmem:-null}" >> outputs/log.txt
avecpu=$(sstat --format=AveCPU -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### average cpu used by ${SLURM_JOBID} was: ${avecpu:-null}" >> outputs/log.txt
fi
## Adding a little logic to have skip finished jobs.
touch outputs/logs/40hisat2_pDONR201_genome.finished
The cyoa invocation which generated the above script also creates the following script along with a group of compression jobs which aggressively compress the fastq output files. I leave that as an exercise to the reader.
#!/usr/bin/env bash
#SBATCH --export=ALL
#SBATCH --mail-type=NONE
#SBATCH --open-mode=append
#SBATCH --chdir=/fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola
#SBATCH --partition=dpart
#SBATCH --qos=throughput --nice=10
#SBATCH --nodes=1 --requeue
#SBATCH --time=12:00:00
#SBATCH --job-name=40_2s2b_hisat2_pDONR201
#SBATCH --mem=12G
#SBATCH --cpus-per-task=1
#SBATCH --output=outputs/log.txt.sbatch
set -o errexit
set -o errtrace
set -o pipefail
export LESS='--buffers 0'
script="$(pwd)/$0"
err() {
echo "Error occurred:"
awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$script }' L=$1 $script
}
trap 'err $LINENO' ERR
echo "## Started /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/scripts/40_2s2b_hisat2_pDONR201.sh at $(date) on $(hostname) with id ${SLURM_JOBID}." >> outputs/log.txt
module add samtools bamtools
## Converting the text sam to a compressed, sorted, indexed bamfile.
## Also printing alignment statistics to outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam.stats
## This job depended on: 240110
echo "Starting samtools"
if [[ ! -f "outputs/40hisat2_pDONR201/poola_pDONR201_genome.sam" ]]; then
echo "Could not find the samtools input file."
exit 1
fi
samtools view -u -t /cbcbhomes/abelew/libraries/genome/pDONR201.fasta \
-S outputs/40hisat2_pDONR201/poola_pDONR201_genome.sam -o outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam \
2>outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam.err 1>outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam.out && \
echo 0
samtools sort -l 9 outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam -o outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted.bam \
2>outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted.stderr \
1>outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted.stdout && \
rm outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam && \
rm outputs/40hisat2_pDONR201/poola_pDONR201_genome.sam && \
mv outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted.bam outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam && samtools index outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam
echo 0
bamtools stats -in outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam 2>outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam.stats 1>&2
echo 0
## The following will fail if this is single-ended.
samtools view -b -f 2 -o outputs/40hisat2_pDONR201/poola_pDONR201_genome-paired.bam outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam && samtools index outputs/40hisat2_pDONR201/poola_pDONR201_genome-paired.bam
bamtools stats -in outputs/40hisat2_pDONR201/poola_pDONR201_genome-paired.bam 2>outputs/40hisat2_pDONR201/poola_pDONR201_genome-paired.stats 1>&2
bamtools filter -tag XM:0 -in outputs/40hisat2_pDONR201/poola_pDONR201_genome.bam -out outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted_nomismatch.bam &&
samtools index outputs/40hisat2_pDONR201/poola_pDONR201_genome-sorted_nomismatch.bam
## The following lines give status codes and some logging
echo "## Job status: $? " >> outputs/log.txt
echo "## $(hostname) Finished ${SLURM_JOBID} 40_2s2b_hisat2_pDONR201.sh at $(date), it took $(( SECONDS / 60 )) minutes." >> outputs/log.txt
if [[ -x "$(command -v sstat)" && ! -z "${SLURM_JOBID}" ]]; then
walltime=$(scontrol show job "${SLURM_JOBID}" | grep RunTime | perl -F'/\s+|=/' -lane '{print $F[2]}' 2>/dev/null)
echo "#### walltime used by ${SLURM_JOBID} was: ${walltime:-null}" >> outputs/log.txt
maxmem=$(sstat --format=MaxVMSize -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### maximum memory used by ${SLURM_JOBID} was: ${maxmem:-null}" >> outputs/log.txt
avecpu=$(sstat --format=AveCPU -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### average cpu used by ${SLURM_JOBID} was: ${avecpu:-null}" >> outputs/log.txt
fi
## Adding a little logic to have skip finished jobs.
touch outputs/logs/40_2s2b_hisat2_pDONR201.finished
Mapping against PA01
Before mapping against the PA01 strain, I previously downloaded the reference assembly from NCBI as a complete genbank file and put it in my “${LIBDIR}/genome/” directory as ‘paeruginosa_pa01.gb’.
I then performed the following to convert it to fasta/gff and index it (note I did this quite a while ago, I am just writing it here for completeness), also here is an extra salmon index operation for fun:
start=$(pwd)
cd ~/libraries/genome
cyoa --task convert --method gb2gff --input paeruginosa_pa01.gb
cyoa --task index --method indexhisat --input paeruginosa_pa01.fasta --species paeruginosa_pa01
cyoa --task index --method indexsalmon --input paeruginosa_pa01_cds.fasta --species paeruginosa_pa01
cd $start
This is nearly identical to the previous step, except it uses the unaligned reads from the previous step, and I explicitly state that I want htseq to count the genes by the locus_tag tags.
cd preprocessing
start=$(pwd)
for i in $(/bin/ls); do
cd ${i}
cyoa --task map --method hisat --species paeruginosa_pa01 \
--htseq_type gene --htseq_id locus_tag \
--input $(/bin/ls outputs/40hisat2_pDONR201/*unalcon*.fastq.xz | tr '\n' ':' | sed 's/:$//g')
cd $start
done
The resulting scripts are nearly identical to those for pDONR, except of course the species used and inputs:
#!/usr/bin/env bash
#SBATCH --export=ALL
#SBATCH --mail-type=NONE
#SBATCH --open-mode=append
#SBATCH --chdir=/fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola
#SBATCH --partition=dpart
#SBATCH --qos=workstation --nice=10
#SBATCH --nodes=1 --requeue
#SBATCH --time=10:00:00
#SBATCH --job-name=40hisat2_paeruginosa_pa01_genome
#SBATCH --mem=24G
#SBATCH --cpus-per-task=4
#SBATCH --output=outputs/log.txt.sbatch
set -o errexit
set -o errtrace
set -o pipefail
export LESS='--buffers 0'
script="$(pwd)/$0"
err() {
echo "Error occurred:"
awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$script }' L=$1 $script
}
trap 'err $LINENO' ERR
echo "## Started /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/scripts/40hisat2_paeruginosa_pa01_genome.sh at $(date) on $(hostname) with id ${SLURM_JOBID}." >> outputs/log.txt
module add hisat2 samtools htseq bamtools
## This is a hisat2 alignment of -1 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/outputs/40hisat2_pDONR201/poola_unalcon_pDONR201_genome.1.fastq.xz) -2 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/outputs/40hisat2_pDONR201/poola_unalcon_pDONR201_genome.2.fastq.xz) against /cbcbhomes/abelew/libraries/genome/indexes/paeruginosa_pa01
mkdir -p outputs/40hisat2_paeruginosa_pa01
hisat2 -x /cbcbhomes/abelew/libraries/genome/indexes/paeruginosa_pa01 \
-p 4 \
-q -1 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/outputs/40hisat2_pDONR201/poola_unalcon_pDONR201_genome.1.fastq.xz) -2 <(less /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/outputs/40hisat2_pDONR201/poola_unalcon_pDONR201_genome.2.fastq.xz) \
--phred33 \
--un outputs/40hisat2_paeruginosa_pa01/poola_unaldis_paeruginosa_pa01_genome.fastq \
--al outputs/40hisat2_paeruginosa_pa01/poola_aldis_paeruginosa_pa01_genome.fastq \
--un-conc outputs/40hisat2_paeruginosa_pa01/poola_unalcon_paeruginosa_pa01_genome.fastq \
--al-conc outputs/40hisat2_paeruginosa_pa01/poola_alcon_paeruginosa_pa01_genome.fastq \
-S outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome.sam \
2>outputs/40hisat2_paeruginosa_pa01/hisat2_paeruginosa_pa01_genome_poola.stderr \
1>outputs/40hisat2_paeruginosa_pa01/hisat2_paeruginosa_pa01_genome_poola.stdout
## The following lines give status codes and some logging
echo "## Job status: $? " >> outputs/log.txt
echo "## $(hostname) Finished ${SLURM_JOBID} 40hisat2_paeruginosa_pa01_genome.sh at $(date), it took $(( SECONDS / 60 )) minutes." >> outputs/log.txt
if [[ -x "$(command -v sstat)" && ! -z "${SLURM_JOBID}" ]]; then
walltime=$(scontrol show job "${SLURM_JOBID}" | grep RunTime | perl -F'/\s+|=/' -lane '{print $F[2]}' 2>/dev/null)
echo "#### walltime used by ${SLURM_JOBID} was: ${walltime:-null}" >> outputs/log.txt
maxmem=$(sstat --format=MaxVMSize -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### maximum memory used by ${SLURM_JOBID} was: ${maxmem:-null}" >> outputs/log.txt
avecpu=$(sstat --format=AveCPU -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### average cpu used by ${SLURM_JOBID} was: ${avecpu:-null}" >> outputs/log.txt
fi
## Adding a little logic to have skip finished jobs.
touch outputs/logs/40hisat2_paeruginosa_pa01_genome.finished
I will leave the nearly identical conversion of the sam alignments to compressed/sorted/indexed bam as an exercise to the reader, but here is the resulting htseq script:
#!/usr/bin/env bash
#SBATCH --export=ALL
#SBATCH --mail-type=NONE
#SBATCH --open-mode=append
#SBATCH --chdir=/fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola
#SBATCH --partition=dpart
#SBATCH --qos=throughput --nice=10
#SBATCH --nodes=1 --requeue
#SBATCH --time=12:00:00
#SBATCH --job-name=40_3hts_poola_all_hisat2_paeruginosa_pa01_sno_gene_Alias
#SBATCH --mem=6G
#SBATCH --cpus-per-task=1
#SBATCH --output=outputs/log.txt.sbatch
set -o errexit
set -o errtrace
set -o pipefail
export LESS='--buffers 0'
script="$(pwd)/$0"
err() {
echo "Error occurred:"
awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$script }' L=$1 $script
}
trap 'err $LINENO' ERR
echo "## Started /fs/cbcb-lab/nelsayed/scratch/atb/dnaseq/paeruginosa_plasmids_2022/preprocessing/poola/scripts/40_3hts_poola_all_hisat2_paeruginosa_pa01_sno_gene_Alias.sh at $(date) on $(hostname) with id ${SLURM_JOBID}." >> outputs/log.txt
module add htseq
## Counting the number of hits in outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired.bam for each feature found in /cbcbhomes/abelew/libraries/genome/paeruginosa_pa01.gff
htseq-count --help 2>&1 | tail -n 3
htseq-count \
-q -f bam -s no --type gene --idattr locus_tag \
outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired.bam \
/cbcbhomes/abelew/libraries_fs/genome/paeruginosa_pa01.gff \
2>outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired_all_sno_gene_Alias.stderr \
1>outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired_all_sno_gene_Alias.count && \
xz -f -9e outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired_all_sno_gene_Alias.count 2>outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired_all_sno_gene_Alias.stderr.xz 1>outputs/40hisat2_paeruginosa_pa01/poola_paeruginosa_pa01_genome-paired_all_sno_gene_Alias.count.xz
## The following lines give status codes and some logging
echo "## Job status: $? " >> outputs/log.txt
echo "## $(hostname) Finished ${SLURM_JOBID} 40_3hts_poola_all_hisat2_paeruginosa_pa01_sno_gene_Alias.sh at $(date), it took $(( SECONDS / 60 )) minutes." >> outputs/log.txt
if [[ -x "$(command -v sstat)" && ! -z "${SLURM_JOBID}" ]]; then
walltime=$(scontrol show job "${SLURM_JOBID}" | grep RunTime | perl -F'/\s+|=/' -lane '{print $F[2]}' 2>/dev/null)
echo "#### walltime used by ${SLURM_JOBID} was: ${walltime:-null}" >> outputs/log.txt
maxmem=$(sstat --format=MaxVMSize -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### maximum memory used by ${SLURM_JOBID} was: ${maxmem:-null}" >> outputs/log.txt
avecpu=$(sstat --format=AveCPU -n "${SLURM_JOBID}.batch" 2>/dev/null)
echo "#### average cpu used by ${SLURM_JOBID} was: ${avecpu:-null}" >> outputs/log.txt
fi
## Adding a little logic to have skip finished jobs.
touch outputs/logs/40_3hts_poola_all_hisat2_paeruginosa_pa01_sno_gene_locus_tag.finished
Vince’s Requests
Here is my email from Vince with his initial, pared down queries:
" Based on the data you have analyzed, can you please share with me a Excel spreadsheet (or CSV file) with 2 columns for each library and each PA gene:
- Coverage (RPKM) or 0 for no reads
- Number of SNPs "
Annotation
I always grab my favorite annotation sources, even if I will not really use them. I usually copy the gff and fasta for the version of the genome I used to the local directory, but I did not bother for this.
pa01_gff <- load_gff_annotations("~/libraries_fs/genome/paeruginosa_pa01.gff", id_col="locus_tag")
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = TRUE)
## Trying attempt: rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = FALSE)
## Had a successful gff import with rtracklayer::import.gff3(gff, sequenceRegionsAsSeqinfo = FALSE)
## Returning a df with 15 columns and 5697 rows.
rownames(pa01_gff) <- pa01_gff[["locus_tag"]]
Expressionset
Let us now pull out the htseq count tables in order to make an rpkm table. This uses the metadata sample sheet I created in the sample_sheets/ directory.
I bolded the two most important columns for the purposes of these tasks.
pa01_expt <- create_expt("sample_sheets/all_samples.xlsx", gene_info=pa01_gff)
## Reading the sample metadata.
## The sample definitions comprises: 10 rows(samples) and 7 columns(metadata fields).
## Matched 5697 annotations and counts.
## Bringing together the count matrix and gene information.
## Some annotations were lost in merging, setting them to 'undefined'.
## Saving the expressionset to 'expt.rda'.
## The final expressionset has 5697 rows and 10 columns.
pa01_rpkm <- normalize_expt(pa01_expt, convert="rpkm")
## Plot a log-scale density of rpkm values.
plot_boxplot(pa01_expt)
## 12590 entries are 0. We are on a log scale, adding 1 to the data.

plot_density(normalize_expt(pa01_rpkm, transform="log2", filter=TRUE))
## Removing 255 low-count genes (5442 remaining).
## transform_counts: Found 10104 values equal to 0, adding 1 to the matrix.
## $plot

##
## $condition_summary
## condition min 1st median mean 3rd max
## 1: a 0 6.468 7.348 6.833 7.767 9.282
## 2: b 0 6.174 7.332 6.796 7.811 9.268
## 3: c 0 6.566 7.413 6.871 7.773 9.105
## 4: d 0 6.535 7.335 6.756 7.766 9.166
## 5: pmg 0 0.000 0.000 1.420 0.000 11.833
##
## $batch_summary
## batch min 1st median mean 3rd max
## 1: notopo 0 5.083 7.111 5.740 7.747 11.58
## 2: topo 0 5.121 7.105 5.731 7.719 11.83
##
## $sample_summary
## sample min 1st median mean 3rd max
## 1: poola 0 6.499 7.375 6.848 7.779 9.282
## 2: poolb 0 6.119 7.318 6.783 7.827 9.268
## 3: poolc 0 6.572 7.422 6.876 7.786 9.087
## 4: poold 0 6.543 7.356 6.766 7.789 9.085
## 5: poolpmg 0 0.000 0.000 1.425 0.000 11.584
## 6: poola_topo 0 6.441 7.319 6.818 7.756 9.165
## 7: poolb_topo 0 6.233 7.345 6.809 7.798 9.149
## 8: poolc_topo 0 6.560 7.405 6.866 7.762 9.105
## 9: poold_topo 0 6.529 7.308 6.746 7.739 9.166
## 10: poolpmg_tp 0 0.000 0.000 1.414 0.000 11.833
##
## $table
## id sample counts condition batch
## 1: PA0001 poola 7.797 a notopo
## 2: PA0002 poola 7.957 a notopo
## 3: PA0003 poola 8.387 a notopo
## 4: PA0004 poola 7.627 a notopo
## 5: PA0005 poola 7.700 a notopo
## ---
## 54416: PA5566 poolpmg_tp 0.000 pmg topo
## 54417: PA5567 poolpmg_tp 0.000 pmg topo
## 54418: PA5568 poolpmg_tp 0.000 pmg topo
## 54419: PA5569 poolpmg_tp 0.000 pmg topo
## 54420: PA5570 poolpmg_tp 0.000 pmg topo
plot_nonzero(pa01_expt)$plot

rpkm_df <- as.data.frame(exprs(pa01_rpkm)) %>%
round(2)
wanted_annotations <- fData(pa01_expt)[, c("gene", "locus_tag")]
wanted_data <- merge(wanted_annotations, rpkm_df,
by="row.names")
rownames(wanted_data) <- wanted_data[["Row.names"]]
wanted_data[["Row.names"]] <- NULL
Gathering mutations numbers by gene
I do not have an instant function for this task, but it should not prove difficult.
wanted_v2 <- wanted_data
for (sample in rownames(pData(pa01_expt))) {
input_file <- glue::glue("preprocessing/{sample}/outputs/40freebayes_paeruginosa_pa01/paeruginosa_pa01_hits_by_gene.txt.xz")
input_data <- readr::read_tsv(input_file, col_names=c("gene", "chr", "postion", "nt_string", "aa_string"))
input_column <- input_data %>%
dplyr::group_by(gene) %>%
dplyr::summarize(n=n())
colnames(input_column) <- c("gene", paste0(sample, "_n"))
wanted_v2 <- merge(wanted_v2, input_column, by.x="row.names", by.y="gene")
rownames(wanted_v2) <- wanted_v2[["Row.names"]]
wanted_v2[["Row.names"]] <- NULL
}
## Rows: 2586 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2390 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2596 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2665 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 245 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2776 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2734 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2816 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 2921 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 280 Columns: 5
## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (4): gene, chr, nt_string, aa_string
## dbl (1): postion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Write it out
written <- write_xlsx(data=wanted_v2, excel="excel/rpkm_mutations_per_gene.xlsx")
pander::pander(sessionInfo())
message(paste0("This is hpgltools commit: ", get_git_commit()))
this_save <- paste0(gsub(pattern="\\.Rmd", replace="", x=rmd_file), "-v", ver, ".rda.xz")
message(paste0("Saving to ", this_save))
tmp <- sm(saveme(filename=this_save))
LS0tCnRpdGxlOiAiRXhhbWluaW5nIHRoZSBQc2V1ZG9tb25hcyBPUkZlb21lIHZpYSBkZWVwIHNlcXVlbmNpbmcgb2YgYSBwbGFzbWlkIGxpYnJhcnkuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB3aWR0aDogMzAwCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgQmlvY1N0eWxlOjpodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQpydW5kYXRlIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCBmb3JtYXQ9IiVZJW0lZCIpCnByZXZpb3VzX2ZpbGUgPC0gIiIKdmVyIDwtIGZvcm1hdChTeXMuRGF0ZSgpLCAiJVklbSVkIikKCiMjdG1wIDwtIHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKQpybWRfZmlsZSA8LSAiaW5kZXguUm1kIgpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IHNlZWtzIHRvIGxheSBvdXQgdGhlIHN0cmF0ZWd5IGVtcGxveWVkIGZvciBhbgpleGFtaW5hdGlvbiBvZiB0aGUgc2VxdWVuY2luZyByZXN1bHRzIGZyb20gYSBncm91cCBvZiBwbGFzbWlkCmxpYnJhcmllcyBmcm9tIFBzZXVkbW9uYXMgYWVydWdpbm9zYSBQQTAxLgoKVGhlc2Ugc2FtcGxlcyBhcmUgaW4gNSBtYWluIGxpYnJhcmllcywgZWFjaCBvZiB3aGljaCB3YXMgZG9uZSB0d2ljZSwKb25jZSB3aXRoIGEgdG9wb2lzb21lcmFzZSBkdXJpbmcgaXNvbGF0aW9uIGFuZCBvbmNlIHdpdGhvdXQuCgpUaGUgaW1tZWRpYXRlIGdvYWwgb2YgdGhpcyBleHBlcmltZW50IGlzIHRvIGxlYXJuIHdoYXQgT1JGcyBleGlzdCBpbgp0aGUgbGlicmFyeSBhbmQgd2hhdCBtdXRhdGlvbnMgaGF2ZSBhcHBlYXJlZCBpbiB0aGVtLgoKIyBQcmVwcm9jZXNzaW5nCgpUaGUgcHJlcHJvY2Vzc2luZyBpcyBtb3N0bHkgYSBub3JtYWwgRE5BIHNlcXVlbmNpbmcgcGlwZWxpbmU6CgoxLiAgVHJpbSB0aGUgcmVhZHMuCjIuICBNYXAgdGhlbSBhZ2FpbnN0IHRoZSBwbGFzbWlkLCBwRE9OUjIwMS4KMy4gIE1hcCB0aGUgdW5tYXBwZWQgcmVhZHMgZnJvbSAjMiBhZ2FpbnN0IFBBMDEuCjQuICBDb3VudCB0aGUgcmVhZHMgYnkgbG9jdXNfdGFnIHRvIGlkZW50aWZ5IG1pc3NpbmcgZ2VuZXMuCjUuICBVc2UgZnJlZWJheWVzIHRvIGlkZW50aWZ5IHZhcmlhbnQgcG9zaXRpb25zLgo2LiAgUGFyc2UgdGhlIGZyZWViYXllcyBvdXRwdXQgZG93biB0byBhbiBlYXN5IHRvIGludGVycHJldCBmb3JtYXQuCgojIyBUcmltbWluZwoKVGhpcyBpcyBteSBkZWZhdWx0IHRyaW1vbWF0aWMgaW52b2NhdGlvbi4KCgpgYGB7YmFzaCB0cmltbWluZywgZXZhbD1GQUxTRX0KY2QgcHJlcHJvY2Vzc2luZwpzdGFydD0kKHB3ZCkKZm9yIGkgaW4gJCgvYmluL2xzKTsgZG8KICAgIGNkICR7aX0KICAgIGN5b2EgLS10YXNrIHRyaW0gLS1tZXRob2QgdHJpbSAtLWlucHV0ICQoL2Jpbi9scyAqLmd6IHwgdHIgJ1xuJyAnOicgfCBzZWQgJ3MvOiQvL2cnKQogICAgY2QgJHN0YXJ0CmRvbmUKYGBgCgpIZXJlIGlzIHRoZSBzY3JpcHQgd2hpY2ggcmVzdWx0ZWQgZm9yIHRoZSBwb29sYSBzYW1wbGU6CgpJIHN0aWxsIGhhdmUgYW4gb2xkIGNoZWNrIGluIGl0IGZyb20gYW4gZWFybGllciB2ZXJzaW9uIG9mIHRyaW1vbWF0aWMKd2hpY2ggd291bGQgc29tZXRpbWVzIGZhaWwuCgojIyMgSW5kaXZpZHVhbCB0cmltbWluZyBzY3JpcHQKCmBgYHtiYXNoIHBvb2xhX3RyaW1fc2NyaXB0LCBldmFsPUZBTFNFfQojU0JBVENIIC0tZXhwb3J0PUFMTAojU0JBVENIIC0tbWFpbC10eXBlPU5PTkUKI1NCQVRDSCAtLW9wZW4tbW9kZT1hcHBlbmQKI1NCQVRDSCAtLWNoZGlyPS9mcy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhCiNTQkFUQ0ggLS1wYXJ0aXRpb249ZHBhcnQKI1NCQVRDSCAtLXFvcz13b3Jrc3RhdGlvbiAtLW5pY2U9MTAKI1NCQVRDSCAtLW5vZGVzPTEgLS1yZXF1ZXVlCiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLS1qb2ItbmFtZT0wMXRyaW1fT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxCiNTQkFUQ0ggLS1tZW09MjRHCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTMKI1NCQVRDSCAtLW91dHB1dD1vdXRwdXRzL2xvZy50eHQuc2JhdGNoCnNldCAtbyBlcnJleGl0CnNldCAtbyBlcnJ0cmFjZQpzZXQgLW8gcGlwZWZhaWwKZXhwb3J0IExFU1M9Jy0tYnVmZmVycyAwJwpzY3JpcHQ9IiQocHdkKS8kMCIKZXJyKCkgewogICAgZWNobyAiRXJyb3Igb2NjdXJyZWQ6IgogICAgYXdrICdOUj5MLTQgJiYgTlI8TCs0IHsgcHJpbnRmICIlLTVkJTNzJXNcbiIsTlIsKE5SPT1MPyI+Pj4iOiIiKSwkc2NyaXB0IH0nIEw9JDEgJHNjcmlwdAp9CnRyYXAgJ2VyciAkTElORU5PJyBFUlIKCmVjaG8gIiMjIFN0YXJ0ZWQgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvc2NyaXB0cy8wMXRyaW1fT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLnNoIGF0ICQoZGF0ZSkgb24gJChob3N0bmFtZSkgd2l0aCBpZCAke1NMVVJNX0pPQklEfS4iID4+IG91dHB1dHMvbG9nLnR4dAoKbW9kdWxlIGFkZCB0cmltb21hdGljCgojIyBUaGlzIGNhbGwgdG8gdHJpbW9tYXRpYyByZW1vdmVzIGlsbHVtaW5hIGFuZCBlcGljZW50cmUgYWRhcHRlcnMgZnJvbSBPUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEuZmFzdHEuZ3o6T1JGZW9tZV9Qb29sX0FfUzFfUjJfMDAxLmZhc3RxLmd6LgojIyBJdCBhbHNvIHBlcmZvcm1zIGEgc2xpZGluZyB3aW5kb3cgcmVtb3ZhbCBvZiBhbnl0aGluZyB3aXRoIHF1YWxpdHkgPDI1OwojIyBjdXRhZGFwdCBwcm92aWRlcyBhbiBhbHRlcm5hdGl2ZSB0byB0aGlzIHRvb2wuCiMjIFRoZSBvcmlnaW5hbCBzZXF1ZW5jZSBkYXRhIGlzIHJlY29tcHJlc3NlZCBhbmQgc2F2ZWQgaW4gdGhlIHNlcXVlbmNlcy8gZGlyZWN0b3J5Lgpta2RpciAtcCBvdXRwdXRzLzAxdHJpbW9tYXRpYwojIyBOb3RlIHRoYXQgdHJpbW9tYXRpYyBwcmludHMgYWxsIG91dHB1dCBhbmQgZXJyb3JzIHRvIFNUREVSUiwgc28gc2VuZCBib3RoIHRvIG91dHB1dAp0cmltbW9tYXRpYyBQRSBcCiAgLXRocmVhZHMgMSBcCiAgLXBocmVkMzMgXAogIDwobGVzcyByMS5mYXN0cS5neikgPChsZXNzIHIyLmZhc3RxLmd6KSBcCiAgT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLXRyaW1tZWRfcGFpcmVkLmZhc3RxIE9SRmVvbWVfUG9vbF9BX1MxX1IxXzAwMS10cmltbWVkX3VucGFpcmVkLmZhc3RxIFwKICBPUkZlb21lX1Bvb2xfQV9TMV9SMl8wMDEtdHJpbW1lZF9wYWlyZWQuZmFzdHEgT1JGZW9tZV9Qb29sX0FfUzFfUjJfMDAxLXRyaW1tZWRfdW5wYWlyZWQuZmFzdHEgXAogICBJTExVTUlOQUNMSVA6L2NiY2Ivc3cvUmVkSGF0LTcteDg2XzY0L2NvbW1vbi9sb2NhbC9wZXJsLzUuMzQvbGliL3NpdGVfcGVybC81LjM0LjAvYXV0by9zaGFyZS9kaXN0L0Jpby1BZHZlbnR1cmUvZ2Vub21lL2FkYXB0ZXJzLmZhOjI6MjA6MTA6MjprZWVwQm90aFJlYWRzIFwKICBTTElESU5HV0lORE9XOjQ6MjAgTUlOTEVOOjQwIFwKICAxPm91dHB1dHMvMDF0cmltb21hdGljL09SRmVvbWVfUG9vbF9BX1MxX1IxXzAwMS10cmltb21hdGljLnN0ZG91dCBcCiAgMj5vdXRwdXRzLzAxdHJpbW9tYXRpYy9PUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW9tYXRpYy5zdGRlcnIKZXhjZXB0ZWQ9JCggeyBncmVwICJFeGNlcHRpb24iICJvdXRwdXRzLzAxdHJpbW9tYXRpYy9PUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW9tYXRpYy5zdGRvdXQiIHx8IHRlc3QgJD8gPSAxOyB9ICkKIyMgVGhlIGZvbGxvd2luZyBpcyBpbiBjYXNlIHRoZSBpbGx1bWluYSBjbGlwcGluZyBmYWlscywgd2hpY2ggaXQgZG9lcyBpZiB0aGlzIGhhcyBhbHJlYWR5IGJlZW4gcnVuIEkgdGhpbmsuCmlmIFtbICIke2V4Y2VwdGVkfSIgIT0gIiIgXV07IHRoZW4KICB0cmltbW9tYXRpYyBQRSBcCiAgICAtdGhyZWFkcyAxIFwKICAgIC1waHJlZDMzIFwKICAgIDwobGVzcyByMS5mYXN0cS5neikgPChsZXNzIHIyLmZhc3RxLmd6KSBcCiAgICBPUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW1lZF9wYWlyZWQuZmFzdHEgT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLXRyaW1tZWRfdW5wYWlyZWQuZmFzdHEgXAogICAgT1JGZW9tZV9Qb29sX0FfUzFfUjJfMDAxLXRyaW1tZWRfcGFpcmVkLmZhc3RxIE9SRmVvbWVfUG9vbF9BX1MxX1IyXzAwMS10cmltbWVkX3VucGFpcmVkLmZhc3RxIFwKICAgICBTTElESU5HV0lORE9XOjQ6MjUgTUlOTEVOOjUwXAogICAgMT5vdXRwdXRzLzAxdHJpbW9tYXRpYy9PUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW9tYXRpYy5zdGRvdXQgXAogICAgMj5vdXRwdXRzLzAxdHJpbW9tYXRpYy9PUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW9tYXRpYy5zdGRlcnIKZmkKc2xlZXAgMTAKbXYgT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLXRyaW1tZWRfcGFpcmVkLmZhc3RxIE9SRmVvbWVfUG9vbF9BX1MxX1IxXzAwMS10cmltbWVkLmZhc3RxCm12IE9SRmVvbWVfUG9vbF9BX1MxX1IyXzAwMS10cmltbWVkX3BhaXJlZC5mYXN0cSBPUkZlb21lX1Bvb2xfQV9TMV9SMl8wMDEtdHJpbW1lZC5mYXN0cQoKIyMgUmVjb21wcmVzcyB0aGUgdW5wYWlyZWQgcmVhZHMsIHRoaXMgc2hvdWxkIG5vdCB0YWtlIGxvbmcuCnh6IC05ZSAtZiBPUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW1lZF91bnBhaXJlZC5mYXN0cQp4eiAtOWUgLWYgT1JGZW9tZV9Qb29sX0FfUzFfUjJfMDAxLXRyaW1tZWRfdW5wYWlyZWQuZmFzdHEKIyMgUmVjb21wcmVzcyB0aGUgcGFpcmVkIHJlYWRzLgp4eiAtOWUgLWYgT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLXRyaW1tZWQuZmFzdHEKeHogLTllIC1mIE9SRmVvbWVfUG9vbF9BX1MxX1IyXzAwMS10cmltbWVkLmZhc3RxCmxuIC1zZiBPUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEtdHJpbW1lZC5mYXN0cS54eiByMV90cmltbWVkLmZhc3RxLnh6CmxuIC1zZiBPUkZlb21lX1Bvb2xfQV9TMV9SMl8wMDEtdHJpbW1lZC5mYXN0cS54eiByMl90cmltbWVkLmZhc3RxLnh6CgoKIyMgVGhlIGZvbGxvd2luZyBsaW5lcyBnaXZlIHN0YXR1cyBjb2RlcyBhbmQgc29tZSBsb2dnaW5nCmVjaG8gIiMjIEpvYiBzdGF0dXM6ICQ/ICIgPj4gb3V0cHV0cy9sb2cudHh0CmVjaG8gIiMjICQoaG9zdG5hbWUpIEZpbmlzaGVkICR7U0xVUk1fSk9CSUR9IDAxdHJpbV9PUkZlb21lX1Bvb2xfQV9TMV9SMV8wMDEuc2ggYXQgJChkYXRlKSwgaXQgdG9vayAkKCggU0VDT05EUyAvIDYwICkpIG1pbnV0ZXMuIiA+PiBvdXRwdXRzL2xvZy50eHQKCmlmIFtbIC14ICIkKGNvbW1hbmQgLXYgc3N0YXQpIiAmJiAhIC16ICIke1NMVVJNX0pPQklEfSIgXV07IHRoZW4KICB3YWxsdGltZT0kKHNjb250cm9sIHNob3cgam9iICIke1NMVVJNX0pPQklEfSIgfCBncmVwIFJ1blRpbWUgfCBwZXJsIC1GJy9ccyt8PS8nIC1sYW5lICd7cHJpbnQgJEZbMl19JyAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIHdhbGx0aW1lIHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke3dhbGx0aW1lOi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CiAgbWF4bWVtPSQoc3N0YXQgLS1mb3JtYXQ9TWF4Vk1TaXplIC1uICIke1NMVVJNX0pPQklEfS5iYXRjaCIgMj4vZGV2L251bGwpCiAgZWNobyAiIyMjIyBtYXhpbXVtIG1lbW9yeSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHttYXhtZW06LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKICBhdmVjcHU9JChzc3RhdCAtLWZvcm1hdD1BdmVDUFUgLW4gIiR7U0xVUk1fSk9CSUR9LmJhdGNoIiAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIGF2ZXJhZ2UgY3B1IHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke2F2ZWNwdTotbnVsbH0iID4+IG91dHB1dHMvbG9nLnR4dApmaQojIyBBZGRpbmcgYSBsaXR0bGUgbG9naWMgdG8gaGF2ZSBza2lwIGZpbmlzaGVkIGpvYnMuCnRvdWNoIG91dHB1dHMvbG9ncy8wMXRyaW1fT1JGZW9tZV9Qb29sX0FfUzFfUjFfMDAxLmZpbmlzaGVkCmBgYAoKIyMgTWFwcGluZyBhZ2FpbnN0IHBET05SCgpUaGlzIHdhcyBmb2xsb3dlZCBieSBteSBkZWZhdWx0IG1hcHBpbmcgYWdhaW5zdCB0aGUgcGxhc21pZCB2aWEKaGlzYXQyLgoKSSBwcmV2aW91c2x5IGRvd25sb2FkZWQgYSBjb3B5IG9mIHBET05SMjAxIGFuZCByYW4gdGhlIGZvbGxvd2luZyBvbgppdDoKCmBgYHtiYXNoIHBkb25yX2luZGV4LCBldmFsPUZBTFNFfQpjeW9hIC0tdGFzayBpbmRleCAtLW1ldGhvZCBpbmRleGhpc2F0IC0taW5wdXQgcERPTlIyMDEuZmFzdGEgLS1zcGVjaWVzIHBET05SMjAxCmBgYAoKSSBkaWQgbm90IGdlbmVyYXRlIGEgZ2ZmIGZpbGUgZm9yIHRoaXMsIHNvIGh0c2VxIGlzIG5vdCBydW4uCgpUaGUgZm9sbG93aW5nIGludm9jYXRpb24gcXVldWVzIDIgam9icyBvbiB0aGUgY2x1c3RlciwgMSBmb3IgdGhlCm1hcHBpbmcgYW5kIDEgdG8gc29ydC9jb21wcmVzcy9pbmRleCB0aGUgYWxpZ25tZW50LgoKYGBge2Jhc2ggcGRvbnJfaGlzYXQsIGV2YWw9RkFMU0V9CmNkIHByZXByb2Nlc3NpbmcKc3RhcnQ9JChwd2QpCmZvciBpIGluICQoL2Jpbi9scyk7IGRvCiAgICBjZCAke2l9CiAgICBjeW9hIC0tdGFzayBtYXAgLS1tZXRob2QgaGlzYXQgLS1zcGVjaWVzIHBET05SMjAxIC0taW5wdXQgcjFfdHJpbW1lZC5mYXN0cS54ejpyMl90cmltbWVkLmZhc3RxLnh6CiAgICBjZCAkc3RhcnQKZG9uZQpgYGAKCiMjIyBJbmRpdmlkdWFsIHBET05SIG1hcHBpbmcgc2NyaXB0CgpgYGB7YmFzaCBwZG9ub3JfbWFwcGluZ19zY3JpcHQsIGV2YWw9RkFMU0V9CiMhL3Vzci9iaW4vZW52IGJhc2gKI1NCQVRDSCAtLWV4cG9ydD1BTEwKI1NCQVRDSCAtLW1haWwtdHlwZT1OT05FCiNTQkFUQ0ggLS1vcGVuLW1vZGU9YXBwZW5kCiNTQkFUQ0ggLS1jaGRpcj0vZnMvY2JjYi1sYWIvbmVsc2F5ZWQvc2NyYXRjaC9hdGIvZG5hc2VxL3BhZXJ1Z2lub3NhX3BsYXNtaWRzXzIwMjIvcHJlcHJvY2Vzc2luZy9wb29sYQojU0JBVENIIC0tcGFydGl0aW9uPWRwYXJ0CiNTQkFUQ0ggLS1xb3M9d29ya3N0YXRpb24gLS1uaWNlPTEwCiNTQkFUQ0ggLS1ub2Rlcz0xIC0tcmVxdWV1ZQojU0JBVENIIC0tdGltZT0xMDowMDowMAojU0JBVENIIC0tam9iLW5hbWU9NDBoaXNhdDJfcERPTlIyMDFfZ2Vub21lCiNTQkFUQ0ggLS1tZW09MjRHCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTQKI1NCQVRDSCAtLW91dHB1dD1vdXRwdXRzL2xvZy50eHQuc2JhdGNoCnNldCAtbyBlcnJleGl0CnNldCAtbyBlcnJ0cmFjZQpzZXQgLW8gcGlwZWZhaWwKZXhwb3J0IExFU1M9Jy0tYnVmZmVycyAwJwpzY3JpcHQ9IiQocHdkKS8kMCIKZXJyKCkgewogICAgZWNobyAiRXJyb3Igb2NjdXJyZWQ6IgogICAgYXdrICdOUj5MLTQgJiYgTlI8TCs0IHsgcHJpbnRmICIlLTVkJTNzJXNcbiIsTlIsKE5SPT1MPyI+Pj4iOiIiKSwkc2NyaXB0IH0nIEw9JDEgJHNjcmlwdAp9CnRyYXAgJ2VyciAkTElORU5PJyBFUlIKCmVjaG8gIiMjIFN0YXJ0ZWQgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvc2NyaXB0cy80MGhpc2F0Ml9wRE9OUjIwMV9nZW5vbWUuc2ggYXQgJChkYXRlKSBvbiAkKGhvc3RuYW1lKSB3aXRoIGlkICR7U0xVUk1fSk9CSUR9LiIgPj4gb3V0cHV0cy9sb2cudHh0Cgptb2R1bGUgYWRkIGhpc2F0MiBzYW10b29scyBodHNlcSBiYW10b29scwoKIyMgVGhpcyBpcyBhIGhpc2F0MiBhbGlnbm1lbnQgb2YgIC0xIDwobGVzcyAvZnMvY2JjYi1sYWIvbmVsc2F5ZWQvc2NyYXRjaC9hdGIvZG5hc2VxL3BhZXJ1Z2lub3NhX3BsYXNtaWRzXzIwMjIvcHJlcHJvY2Vzc2luZy9wb29sYS9yMV90cmltbWVkLmZhc3RxLnh6KSAtMiA8KGxlc3MgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvcjJfdHJpbW1lZC5mYXN0cS54eikgIGFnYWluc3QgL2NiY2Job21lcy9hYmVsZXcvbGlicmFyaWVzL2dlbm9tZS9pbmRleGVzL3BET05SMjAxCgpta2RpciAtcCBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxCmhpc2F0MiAteCAvY2JjYmhvbWVzL2FiZWxldy9saWJyYXJpZXMvZ2Vub21lL2luZGV4ZXMvcERPTlIyMDEgIFwKICAtcCA0IFwKICAtcSAgIC0xIDwobGVzcyAvZnMvY2JjYi1sYWIvbmVsc2F5ZWQvc2NyYXRjaC9hdGIvZG5hc2VxL3BhZXJ1Z2lub3NhX3BsYXNtaWRzXzIwMjIvcHJlcHJvY2Vzc2luZy9wb29sYS9yMV90cmltbWVkLmZhc3RxLnh6KSAtMiA8KGxlc3MgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvcjJfdHJpbW1lZC5mYXN0cS54eikgIFwKICAtLXBocmVkMzMgXAogIC0tdW4gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV91bmFsZGlzX3BET05SMjAxX2dlbm9tZS5mYXN0cSBcCiAgLS1hbCBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX2FsZGlzX3BET05SMjAxX2dlbm9tZS5mYXN0cSBcCiAgLS11bi1jb25jIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfdW5hbGNvbl9wRE9OUjIwMV9nZW5vbWUuZmFzdHEgXAogIC0tYWwtY29uYyBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX2FsY29uX3BET05SMjAxX2dlbm9tZS5mYXN0cSBcCiAgLVMgb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuc2FtIFwKICAyPm91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvaGlzYXQyX3BET05SMjAxX2dlbm9tZV9wb29sYS5zdGRlcnIgXAogIDE+b3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9oaXNhdDJfcERPTlIyMDFfZ2Vub21lX3Bvb2xhLnN0ZG91dAoKCiMjIFRoZSBmb2xsb3dpbmcgbGluZXMgZ2l2ZSBzdGF0dXMgY29kZXMgYW5kIHNvbWUgbG9nZ2luZwplY2hvICIjIyBKb2Igc3RhdHVzOiAkPyAiID4+IG91dHB1dHMvbG9nLnR4dAplY2hvICIjIyAkKGhvc3RuYW1lKSBGaW5pc2hlZCAke1NMVVJNX0pPQklEfSA0MGhpc2F0Ml9wRE9OUjIwMV9nZW5vbWUuc2ggYXQgJChkYXRlKSwgaXQgdG9vayAkKCggU0VDT05EUyAvIDYwICkpIG1pbnV0ZXMuIiA+PiBvdXRwdXRzL2xvZy50eHQKCmlmIFtbIC14ICIkKGNvbW1hbmQgLXYgc3N0YXQpIiAmJiAhIC16ICIke1NMVVJNX0pPQklEfSIgXV07IHRoZW4KICB3YWxsdGltZT0kKHNjb250cm9sIHNob3cgam9iICIke1NMVVJNX0pPQklEfSIgfCBncmVwIFJ1blRpbWUgfCBwZXJsIC1GJy9ccyt8PS8nIC1sYW5lICd7cHJpbnQgJEZbMl19JyAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIHdhbGx0aW1lIHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke3dhbGx0aW1lOi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CiAgbWF4bWVtPSQoc3N0YXQgLS1mb3JtYXQ9TWF4Vk1TaXplIC1uICIke1NMVVJNX0pPQklEfS5iYXRjaCIgMj4vZGV2L251bGwpCiAgZWNobyAiIyMjIyBtYXhpbXVtIG1lbW9yeSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHttYXhtZW06LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKICBhdmVjcHU9JChzc3RhdCAtLWZvcm1hdD1BdmVDUFUgLW4gIiR7U0xVUk1fSk9CSUR9LmJhdGNoIiAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIGF2ZXJhZ2UgY3B1IHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke2F2ZWNwdTotbnVsbH0iID4+IG91dHB1dHMvbG9nLnR4dApmaQojIyBBZGRpbmcgYSBsaXR0bGUgbG9naWMgdG8gaGF2ZSBza2lwIGZpbmlzaGVkIGpvYnMuCnRvdWNoIG91dHB1dHMvbG9ncy80MGhpc2F0Ml9wRE9OUjIwMV9nZW5vbWUuZmluaXNoZWQKYGBgCgpUaGUgY3lvYSBpbnZvY2F0aW9uIHdoaWNoIGdlbmVyYXRlZCB0aGUgYWJvdmUgc2NyaXB0IGFsc28gY3JlYXRlcyB0aGUKZm9sbG93aW5nIHNjcmlwdCBhbG9uZyB3aXRoIGEgZ3JvdXAgb2YgY29tcHJlc3Npb24gam9icyB3aGljaAphZ2dyZXNzaXZlbHkgY29tcHJlc3MgdGhlIGZhc3RxIG91dHB1dCBmaWxlcy4gIEkgbGVhdmUgdGhhdCBhcyBhbgpleGVyY2lzZSB0byB0aGUgcmVhZGVyLgoKYGBge2Jhc2ggc2FtMmJhbV9wRE9OUiwgZXZhbD1GQUxTRX0KIyEvdXNyL2Jpbi9lbnYgYmFzaAojU0JBVENIIC0tZXhwb3J0PUFMTAojU0JBVENIIC0tbWFpbC10eXBlPU5PTkUKI1NCQVRDSCAtLW9wZW4tbW9kZT1hcHBlbmQKI1NCQVRDSCAtLWNoZGlyPS9mcy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhCiNTQkFUQ0ggLS1wYXJ0aXRpb249ZHBhcnQKI1NCQVRDSCAtLXFvcz10aHJvdWdocHV0IC0tbmljZT0xMAojU0JBVENIIC0tbm9kZXM9MSAtLXJlcXVldWUKI1NCQVRDSCAtLXRpbWU9MTI6MDA6MDAKI1NCQVRDSCAtLWpvYi1uYW1lPTQwXzJzMmJfaGlzYXQyX3BET05SMjAxCiNTQkFUQ0ggLS1tZW09MTJHCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLW91dHB1dD1vdXRwdXRzL2xvZy50eHQuc2JhdGNoCnNldCAtbyBlcnJleGl0CnNldCAtbyBlcnJ0cmFjZQpzZXQgLW8gcGlwZWZhaWwKZXhwb3J0IExFU1M9Jy0tYnVmZmVycyAwJwpzY3JpcHQ9IiQocHdkKS8kMCIKZXJyKCkgewogICAgZWNobyAiRXJyb3Igb2NjdXJyZWQ6IgogICAgYXdrICdOUj5MLTQgJiYgTlI8TCs0IHsgcHJpbnRmICIlLTVkJTNzJXNcbiIsTlIsKE5SPT1MPyI+Pj4iOiIiKSwkc2NyaXB0IH0nIEw9JDEgJHNjcmlwdAp9CnRyYXAgJ2VyciAkTElORU5PJyBFUlIKCmVjaG8gIiMjIFN0YXJ0ZWQgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvc2NyaXB0cy80MF8yczJiX2hpc2F0Ml9wRE9OUjIwMS5zaCBhdCAkKGRhdGUpIG9uICQoaG9zdG5hbWUpIHdpdGggaWQgJHtTTFVSTV9KT0JJRH0uIiA+PiBvdXRwdXRzL2xvZy50eHQKCm1vZHVsZSBhZGQgc2FtdG9vbHMgYmFtdG9vbHMKCiMjIENvbnZlcnRpbmcgdGhlIHRleHQgc2FtIHRvIGEgY29tcHJlc3NlZCwgc29ydGVkLCBpbmRleGVkIGJhbWZpbGUuCiMjIEFsc28gcHJpbnRpbmcgYWxpZ25tZW50IHN0YXRpc3RpY3MgdG8gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtLnN0YXRzCiMjIFRoaXMgam9iIGRlcGVuZGVkIG9uOiAyNDAxMTAKCmVjaG8gIlN0YXJ0aW5nIHNhbXRvb2xzIgppZiBbWyAhIC1mICJvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS5zYW0iIF1dOyB0aGVuCiAgICBlY2hvICJDb3VsZCBub3QgZmluZCB0aGUgc2FtdG9vbHMgaW5wdXQgZmlsZS4iCiAgICBleGl0IDEKZmkKc2FtdG9vbHMgdmlldyAtdSAtdCAvY2JjYmhvbWVzL2FiZWxldy9saWJyYXJpZXMvZ2Vub21lL3BET05SMjAxLmZhc3RhIFwKICAtUyBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS5zYW0gLW8gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtICBcCiAgMj5vdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS5iYW0uZXJyIDE+b3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtLm91dCAmJiBcCmVjaG8gMAogIHNhbXRvb2xzIHNvcnQgLWwgOSBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS5iYW0gLW8gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUtc29ydGVkLmJhbSBcCiAgMj5vdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS1zb3J0ZWQuc3RkZXJyIFwKICAxPm91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLXNvcnRlZC5zdGRvdXQgJiYgXAogIHJtIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLmJhbSAmJiBcCiAgcm0gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuc2FtICYmIFwKICBtdiBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS1zb3J0ZWQuYmFtIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLmJhbSAmJiAgc2FtdG9vbHMgaW5kZXggb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtCmVjaG8gMApiYW10b29scyBzdGF0cyAtaW4gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtIDI+b3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtLnN0YXRzIDE+JjIKZWNobyAwCgojIyBUaGUgZm9sbG93aW5nIHdpbGwgZmFpbCBpZiB0aGlzIGlzIHNpbmdsZS1lbmRlZC4Kc2FtdG9vbHMgdmlldyAtYiAtZiAyIC1vIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLXBhaXJlZC5iYW0gb3V0cHV0cy80MGhpc2F0Ml9wRE9OUjIwMS9wb29sYV9wRE9OUjIwMV9nZW5vbWUuYmFtICYmIHNhbXRvb2xzIGluZGV4IG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLXBhaXJlZC5iYW0KYmFtdG9vbHMgc3RhdHMgLWluIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfcERPTlIyMDFfZ2Vub21lLXBhaXJlZC5iYW0gMj5vdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS1wYWlyZWQuc3RhdHMgMT4mMgpiYW10b29scyBmaWx0ZXIgLXRhZyBYTTowIC1pbiBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS5iYW0gLW91dCBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS1zb3J0ZWRfbm9taXNtYXRjaC5iYW0gJiYKICBzYW10b29scyBpbmRleCBvdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3BET05SMjAxX2dlbm9tZS1zb3J0ZWRfbm9taXNtYXRjaC5iYW0KCiMjIFRoZSBmb2xsb3dpbmcgbGluZXMgZ2l2ZSBzdGF0dXMgY29kZXMgYW5kIHNvbWUgbG9nZ2luZwplY2hvICIjIyBKb2Igc3RhdHVzOiAkPyAiID4+IG91dHB1dHMvbG9nLnR4dAplY2hvICIjIyAkKGhvc3RuYW1lKSBGaW5pc2hlZCAke1NMVVJNX0pPQklEfSA0MF8yczJiX2hpc2F0Ml9wRE9OUjIwMS5zaCBhdCAkKGRhdGUpLCBpdCB0b29rICQoKCBTRUNPTkRTIC8gNjAgKSkgbWludXRlcy4iID4+IG91dHB1dHMvbG9nLnR4dAoKaWYgW1sgLXggIiQoY29tbWFuZCAtdiBzc3RhdCkiICYmICEgLXogIiR7U0xVUk1fSk9CSUR9IiBdXTsgdGhlbgogIHdhbGx0aW1lPSQoc2NvbnRyb2wgc2hvdyBqb2IgIiR7U0xVUk1fSk9CSUR9IiB8IGdyZXAgUnVuVGltZSB8IHBlcmwgLUYnL1xzK3w9LycgLWxhbmUgJ3twcmludCAkRlsyXX0nIDI+L2Rldi9udWxsKQogIGVjaG8gIiMjIyMgd2FsbHRpbWUgdXNlZCBieSAke1NMVVJNX0pPQklEfSB3YXM6ICR7d2FsbHRpbWU6LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKICBtYXhtZW09JChzc3RhdCAtLWZvcm1hdD1NYXhWTVNpemUgLW4gIiR7U0xVUk1fSk9CSUR9LmJhdGNoIiAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIG1heGltdW0gbWVtb3J5IHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke21heG1lbTotbnVsbH0iID4+IG91dHB1dHMvbG9nLnR4dAogIGF2ZWNwdT0kKHNzdGF0IC0tZm9ybWF0PUF2ZUNQVSAtbiAiJHtTTFVSTV9KT0JJRH0uYmF0Y2giIDI+L2Rldi9udWxsKQogIGVjaG8gIiMjIyMgYXZlcmFnZSBjcHUgdXNlZCBieSAke1NMVVJNX0pPQklEfSB3YXM6ICR7YXZlY3B1Oi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CmZpCiMjIEFkZGluZyBhIGxpdHRsZSBsb2dpYyB0byBoYXZlIHNraXAgZmluaXNoZWQgam9icy4KdG91Y2ggb3V0cHV0cy9sb2dzLzQwXzJzMmJfaGlzYXQyX3BET05SMjAxLmZpbmlzaGVkCmBgYAoKIyMgTWFwcGluZyBhZ2FpbnN0IFBBMDEKCkJlZm9yZSBtYXBwaW5nIGFnYWluc3QgdGhlIFBBMDEgc3RyYWluLCBJIHByZXZpb3VzbHkgZG93bmxvYWRlZCB0aGUKcmVmZXJlbmNlIGFzc2VtYmx5IGZyb20gTkNCSSBhcyBhIGNvbXBsZXRlIGdlbmJhbmsgZmlsZSBhbmQgcHV0IGl0IGluCm15ICIke0xJQkRJUn0vZ2Vub21lLyIgZGlyZWN0b3J5IGFzICdwYWVydWdpbm9zYV9wYTAxLmdiJy4KCkkgdGhlbiBwZXJmb3JtZWQgdGhlIGZvbGxvd2luZyB0byBjb252ZXJ0IGl0IHRvIGZhc3RhL2dmZiBhbmQgaW5kZXgKaXQgKG5vdGUgSSBkaWQgdGhpcyBxdWl0ZSBhIHdoaWxlIGFnbywgSSBhbSBqdXN0IHdyaXRpbmcgaXQgaGVyZSBmb3IKY29tcGxldGVuZXNzKSwgYWxzbyBoZXJlIGlzIGFuIGV4dHJhIHNhbG1vbiBpbmRleCBvcGVyYXRpb24gZm9yIGZ1bjoKCmBgYHtiYXNoIGNvbnZlcnRfaW5kZXhfcGEwMSwgZXZhbD1GQUxTRX0Kc3RhcnQ9JChwd2QpCmNkIH4vbGlicmFyaWVzL2dlbm9tZQpjeW9hIC0tdGFzayBjb252ZXJ0IC0tbWV0aG9kIGdiMmdmZiAtLWlucHV0IHBhZXJ1Z2lub3NhX3BhMDEuZ2IKY3lvYSAtLXRhc2sgaW5kZXggLS1tZXRob2QgaW5kZXhoaXNhdCAtLWlucHV0IHBhZXJ1Z2lub3NhX3BhMDEuZmFzdGEgLS1zcGVjaWVzIHBhZXJ1Z2lub3NhX3BhMDEKY3lvYSAtLXRhc2sgaW5kZXggLS1tZXRob2QgaW5kZXhzYWxtb24gLS1pbnB1dCBwYWVydWdpbm9zYV9wYTAxX2Nkcy5mYXN0YSAtLXNwZWNpZXMgcGFlcnVnaW5vc2FfcGEwMQpjZCAkc3RhcnQKYGBgCgpUaGlzIGlzIG5lYXJseSBpZGVudGljYWwgdG8gdGhlIHByZXZpb3VzIHN0ZXAsIGV4Y2VwdCBpdCB1c2VzIHRoZQp1bmFsaWduZWQgcmVhZHMgZnJvbSB0aGUgcHJldmlvdXMgc3RlcCwgYW5kIEkgZXhwbGljaXRseSBzdGF0ZSB0aGF0IEkKd2FudCBodHNlcSB0byBjb3VudCB0aGUgZ2VuZXMgYnkgdGhlIGxvY3VzX3RhZyB0YWdzLgoKYGBge2Jhc2ggaGlzYXRfcGEwMV91bmFsaWduZWQsIGV2YWw9RkFMU0V9CmNkIHByZXByb2Nlc3NpbmcKc3RhcnQ9JChwd2QpCmZvciBpIGluICQoL2Jpbi9scyk7IGRvCiAgICBjZCAke2l9CiAgICBjeW9hIC0tdGFzayBtYXAgLS1tZXRob2QgaGlzYXQgLS1zcGVjaWVzIHBhZXJ1Z2lub3NhX3BhMDEgXAogICAgICAgICAtLWh0c2VxX3R5cGUgZ2VuZSAtLWh0c2VxX2lkIGxvY3VzX3RhZyBcCiAgICAgICAgIC0taW5wdXQgJCgvYmluL2xzIG91dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvKnVuYWxjb24qLmZhc3RxLnh6IHwgdHIgJ1xuJyAnOicgfCBzZWQgJ3MvOiQvL2cnKQogICAgY2QgJHN0YXJ0CmRvbmUKYGBgCgpUaGUgcmVzdWx0aW5nIHNjcmlwdHMgYXJlIG5lYXJseSBpZGVudGljYWwgdG8gdGhvc2UgZm9yIHBET05SLCBleGNlcHQKb2YgY291cnNlIHRoZSBzcGVjaWVzIHVzZWQgYW5kIGlucHV0czoKCmBgYHtiYXNoIGhpc2F0X3BhZXJ1Z2lub3NhLCBldmFsPUZBTFNFfQojIS91c3IvYmluL2VudiBiYXNoCiNTQkFUQ0ggLS1leHBvcnQ9QUxMCiNTQkFUQ0ggLS1tYWlsLXR5cGU9Tk9ORQojU0JBVENIIC0tb3Blbi1tb2RlPWFwcGVuZAojU0JBVENIIC0tY2hkaXI9L2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEKI1NCQVRDSCAtLXBhcnRpdGlvbj1kcGFydAojU0JBVENIIC0tcW9zPXdvcmtzdGF0aW9uIC0tbmljZT0xMAojU0JBVENIIC0tbm9kZXM9MSAtLXJlcXVldWUKI1NCQVRDSCAtLXRpbWU9MTA6MDA6MDAKI1NCQVRDSCAtLWpvYi1uYW1lPTQwaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lCiNTQkFUQ0ggLS1tZW09MjRHCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTQKI1NCQVRDSCAtLW91dHB1dD1vdXRwdXRzL2xvZy50eHQuc2JhdGNoCnNldCAtbyBlcnJleGl0CnNldCAtbyBlcnJ0cmFjZQpzZXQgLW8gcGlwZWZhaWwKZXhwb3J0IExFU1M9Jy0tYnVmZmVycyAwJwpzY3JpcHQ9IiQocHdkKS8kMCIKZXJyKCkgewogICAgZWNobyAiRXJyb3Igb2NjdXJyZWQ6IgogICAgYXdrICdOUj5MLTQgJiYgTlI8TCs0IHsgcHJpbnRmICIlLTVkJTNzJXNcbiIsTlIsKE5SPT1MPyI+Pj4iOiIiKSwkc2NyaXB0IH0nIEw9JDEgJHNjcmlwdAp9CnRyYXAgJ2VyciAkTElORU5PJyBFUlIKCmVjaG8gIiMjIFN0YXJ0ZWQgL2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvc2NyaXB0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxX2dlbm9tZS5zaCBhdCAkKGRhdGUpIG9uICQoaG9zdG5hbWUpIHdpdGggaWQgJHtTTFVSTV9KT0JJRH0uIiA+PiBvdXRwdXRzL2xvZy50eHQKCm1vZHVsZSBhZGQgaGlzYXQyIHNhbXRvb2xzIGh0c2VxIGJhbXRvb2xzCgojIyBUaGlzIGlzIGEgaGlzYXQyIGFsaWdubWVudCBvZiAgLTEgPChsZXNzIC9mcy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhL291dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfdW5hbGNvbl9wRE9OUjIwMV9nZW5vbWUuMS5mYXN0cS54eikgLTIgPChsZXNzIC9mcy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhL291dHB1dHMvNDBoaXNhdDJfcERPTlIyMDEvcG9vbGFfdW5hbGNvbl9wRE9OUjIwMV9nZW5vbWUuMi5mYXN0cS54eikgIGFnYWluc3QgL2NiY2Job21lcy9hYmVsZXcvbGlicmFyaWVzL2dlbm9tZS9pbmRleGVzL3BhZXJ1Z2lub3NhX3BhMDEKCm1rZGlyIC1wIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMQpoaXNhdDIgLXggL2NiY2Job21lcy9hYmVsZXcvbGlicmFyaWVzL2dlbm9tZS9pbmRleGVzL3BhZXJ1Z2lub3NhX3BhMDEgIFwKICAtcCA0IFwKICAtcSAgIC0xIDwobGVzcyAvZnMvY2JjYi1sYWIvbmVsc2F5ZWQvc2NyYXRjaC9hdGIvZG5hc2VxL3BhZXJ1Z2lub3NhX3BsYXNtaWRzXzIwMjIvcHJlcHJvY2Vzc2luZy9wb29sYS9vdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3VuYWxjb25fcERPTlIyMDFfZ2Vub21lLjEuZmFzdHEueHopIC0yIDwobGVzcyAvZnMvY2JjYi1sYWIvbmVsc2F5ZWQvc2NyYXRjaC9hdGIvZG5hc2VxL3BhZXJ1Z2lub3NhX3BsYXNtaWRzXzIwMjIvcHJlcHJvY2Vzc2luZy9wb29sYS9vdXRwdXRzLzQwaGlzYXQyX3BET05SMjAxL3Bvb2xhX3VuYWxjb25fcERPTlIyMDFfZ2Vub21lLjIuZmFzdHEueHopICBcCiAgLS1waHJlZDMzIFwKICAtLXVuIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9wb29sYV91bmFsZGlzX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLmZhc3RxIFwKICAtLWFsIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9wb29sYV9hbGRpc19wYWVydWdpbm9zYV9wYTAxX2dlbm9tZS5mYXN0cSBcCiAgLS11bi1jb25jIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9wb29sYV91bmFsY29uX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLmZhc3RxIFwKICAtLWFsLWNvbmMgb3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxL3Bvb2xhX2FsY29uX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLmZhc3RxIFwKICAtUyBvdXRwdXRzLzQwaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDEvcG9vbGFfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWUuc2FtIFwKICAyPm91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9oaXNhdDJfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWVfcG9vbGEuc3RkZXJyIFwKICAxPm91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9oaXNhdDJfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWVfcG9vbGEuc3Rkb3V0CgoKIyMgVGhlIGZvbGxvd2luZyBsaW5lcyBnaXZlIHN0YXR1cyBjb2RlcyBhbmQgc29tZSBsb2dnaW5nCmVjaG8gIiMjIEpvYiBzdGF0dXM6ICQ/ICIgPj4gb3V0cHV0cy9sb2cudHh0CmVjaG8gIiMjICQoaG9zdG5hbWUpIEZpbmlzaGVkICR7U0xVUk1fSk9CSUR9IDQwaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLnNoIGF0ICQoZGF0ZSksIGl0IHRvb2sgJCgoIFNFQ09ORFMgLyA2MCApKSBtaW51dGVzLiIgPj4gb3V0cHV0cy9sb2cudHh0CgppZiBbWyAteCAiJChjb21tYW5kIC12IHNzdGF0KSIgJiYgISAteiAiJHtTTFVSTV9KT0JJRH0iIF1dOyB0aGVuCiAgd2FsbHRpbWU9JChzY29udHJvbCBzaG93IGpvYiAiJHtTTFVSTV9KT0JJRH0iIHwgZ3JlcCBSdW5UaW1lIHwgcGVybCAtRicvXHMrfD0vJyAtbGFuZSAne3ByaW50ICRGWzJdfScgMj4vZGV2L251bGwpCiAgZWNobyAiIyMjIyB3YWxsdGltZSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHt3YWxsdGltZTotbnVsbH0iID4+IG91dHB1dHMvbG9nLnR4dAogIG1heG1lbT0kKHNzdGF0IC0tZm9ybWF0PU1heFZNU2l6ZSAtbiAiJHtTTFVSTV9KT0JJRH0uYmF0Y2giIDI+L2Rldi9udWxsKQogIGVjaG8gIiMjIyMgbWF4aW11bSBtZW1vcnkgdXNlZCBieSAke1NMVVJNX0pPQklEfSB3YXM6ICR7bWF4bWVtOi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CiAgYXZlY3B1PSQoc3N0YXQgLS1mb3JtYXQ9QXZlQ1BVIC1uICIke1NMVVJNX0pPQklEfS5iYXRjaCIgMj4vZGV2L251bGwpCiAgZWNobyAiIyMjIyBhdmVyYWdlIGNwdSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHthdmVjcHU6LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKZmkKIyMgQWRkaW5nIGEgbGl0dGxlIGxvZ2ljIHRvIGhhdmUgc2tpcCBmaW5pc2hlZCBqb2JzLgp0b3VjaCBvdXRwdXRzL2xvZ3MvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWUuZmluaXNoZWQKYGBgCgpJIHdpbGwgbGVhdmUgdGhlIG5lYXJseSBpZGVudGljYWwgY29udmVyc2lvbiBvZiB0aGUgc2FtIGFsaWdubWVudHMgdG8KY29tcHJlc3NlZC9zb3J0ZWQvaW5kZXhlZCBiYW0gYXMgYW4gZXhlcmNpc2UgdG8gdGhlIHJlYWRlciwgYnV0IGhlcmUKaXMgdGhlIHJlc3VsdGluZyBodHNlcSBzY3JpcHQ6CgpgYGB7YmFzaCBodHNlcV9leGFtcGxlLCBldmFsPUZBTFNFfQojIS91c3IvYmluL2VudiBiYXNoCiNTQkFUQ0ggLS1leHBvcnQ9QUxMCiNTQkFUQ0ggLS1tYWlsLXR5cGU9Tk9ORQojU0JBVENIIC0tb3Blbi1tb2RlPWFwcGVuZAojU0JBVENIIC0tY2hkaXI9L2ZzL2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEKI1NCQVRDSCAtLXBhcnRpdGlvbj1kcGFydAojU0JBVENIIC0tcW9zPXRocm91Z2hwdXQgLS1uaWNlPTEwCiNTQkFUQ0ggLS1ub2Rlcz0xIC0tcmVxdWV1ZQojU0JBVENIIC0tdGltZT0xMjowMDowMAojU0JBVENIIC0tam9iLW5hbWU9NDBfM2h0c19wb29sYV9hbGxfaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDFfc25vX2dlbmVfQWxpYXMKI1NCQVRDSCAtLW1lbT02RwojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0xCiNTQkFUQ0ggLS1vdXRwdXQ9b3V0cHV0cy9sb2cudHh0LnNiYXRjaApzZXQgLW8gZXJyZXhpdApzZXQgLW8gZXJydHJhY2UKc2V0IC1vIHBpcGVmYWlsCmV4cG9ydCBMRVNTPSctLWJ1ZmZlcnMgMCcKc2NyaXB0PSIkKHB3ZCkvJDAiCmVycigpIHsKICAgIGVjaG8gIkVycm9yIG9jY3VycmVkOiIKICAgIGF3ayAnTlI+TC00ICYmIE5SPEwrNCB7IHByaW50ZiAiJS01ZCUzcyVzXG4iLE5SLChOUj09TD8iPj4+IjoiIiksJHNjcmlwdCB9JyBMPSQxICRzY3JpcHQKfQp0cmFwICdlcnIgJExJTkVOTycgRVJSCgplY2hvICIjIyBTdGFydGVkIC9mcy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhL3NjcmlwdHMvNDBfM2h0c19wb29sYV9hbGxfaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDFfc25vX2dlbmVfQWxpYXMuc2ggYXQgJChkYXRlKSBvbiAkKGhvc3RuYW1lKSB3aXRoIGlkICR7U0xVUk1fSk9CSUR9LiIgPj4gb3V0cHV0cy9sb2cudHh0Cgptb2R1bGUgYWRkIGh0c2VxCgojIyBDb3VudGluZyB0aGUgbnVtYmVyIG9mIGhpdHMgaW4gb3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxL3Bvb2xhX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLXBhaXJlZC5iYW0gZm9yIGVhY2ggZmVhdHVyZSBmb3VuZCBpbiAvY2JjYmhvbWVzL2FiZWxldy9saWJyYXJpZXMvZ2Vub21lL3BhZXJ1Z2lub3NhX3BhMDEuZ2ZmCmh0c2VxLWNvdW50ICAtLWhlbHAgMj4mMSB8IHRhaWwgLW4gMwpodHNlcS1jb3VudCBcCiAgLXEgLWYgYmFtIC1zIG5vICAtLXR5cGUgZ2VuZSAgLS1pZGF0dHIgbG9jdXNfdGFnIFwKICBvdXRwdXRzLzQwaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDEvcG9vbGFfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWUtcGFpcmVkLmJhbSBcCiAgL2NiY2Job21lcy9hYmVsZXcvbGlicmFyaWVzX2ZzL2dlbm9tZS9wYWVydWdpbm9zYV9wYTAxLmdmZiBcCiAgMj5vdXRwdXRzLzQwaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDEvcG9vbGFfcGFlcnVnaW5vc2FfcGEwMV9nZW5vbWUtcGFpcmVkX2FsbF9zbm9fZ2VuZV9BbGlhcy5zdGRlcnIgXAogIDE+b3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxL3Bvb2xhX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLXBhaXJlZF9hbGxfc25vX2dlbmVfQWxpYXMuY291bnQgJiYgXAogICAgeHogLWYgLTllIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9wb29sYV9wYWVydWdpbm9zYV9wYTAxX2dlbm9tZS1wYWlyZWRfYWxsX3Nub19nZW5lX0FsaWFzLmNvdW50IDI+b3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxL3Bvb2xhX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLXBhaXJlZF9hbGxfc25vX2dlbmVfQWxpYXMuc3RkZXJyLnh6IDE+b3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxL3Bvb2xhX3BhZXJ1Z2lub3NhX3BhMDFfZ2Vub21lLXBhaXJlZF9hbGxfc25vX2dlbmVfQWxpYXMuY291bnQueHoKCgojIyBUaGUgZm9sbG93aW5nIGxpbmVzIGdpdmUgc3RhdHVzIGNvZGVzIGFuZCBzb21lIGxvZ2dpbmcKZWNobyAiIyMgSm9iIHN0YXR1czogJD8gIiA+PiBvdXRwdXRzL2xvZy50eHQKZWNobyAiIyMgJChob3N0bmFtZSkgRmluaXNoZWQgJHtTTFVSTV9KT0JJRH0gNDBfM2h0c19wb29sYV9hbGxfaGlzYXQyX3BhZXJ1Z2lub3NhX3BhMDFfc25vX2dlbmVfQWxpYXMuc2ggYXQgJChkYXRlKSwgaXQgdG9vayAkKCggU0VDT05EUyAvIDYwICkpIG1pbnV0ZXMuIiA+PiBvdXRwdXRzL2xvZy50eHQKCmlmIFtbIC14ICIkKGNvbW1hbmQgLXYgc3N0YXQpIiAmJiAhIC16ICIke1NMVVJNX0pPQklEfSIgXV07IHRoZW4KICB3YWxsdGltZT0kKHNjb250cm9sIHNob3cgam9iICIke1NMVVJNX0pPQklEfSIgfCBncmVwIFJ1blRpbWUgfCBwZXJsIC1GJy9ccyt8PS8nIC1sYW5lICd7cHJpbnQgJEZbMl19JyAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIHdhbGx0aW1lIHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke3dhbGx0aW1lOi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CiAgbWF4bWVtPSQoc3N0YXQgLS1mb3JtYXQ9TWF4Vk1TaXplIC1uICIke1NMVVJNX0pPQklEfS5iYXRjaCIgMj4vZGV2L251bGwpCiAgZWNobyAiIyMjIyBtYXhpbXVtIG1lbW9yeSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHttYXhtZW06LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKICBhdmVjcHU9JChzc3RhdCAtLWZvcm1hdD1BdmVDUFUgLW4gIiR7U0xVUk1fSk9CSUR9LmJhdGNoIiAyPi9kZXYvbnVsbCkKICBlY2hvICIjIyMjIGF2ZXJhZ2UgY3B1IHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke2F2ZWNwdTotbnVsbH0iID4+IG91dHB1dHMvbG9nLnR4dApmaQojIyBBZGRpbmcgYSBsaXR0bGUgbG9naWMgdG8gaGF2ZSBza2lwIGZpbmlzaGVkIGpvYnMuCnRvdWNoIG91dHB1dHMvbG9ncy80MF8zaHRzX3Bvb2xhX2FsbF9oaXNhdDJfcGFlcnVnaW5vc2FfcGEwMV9zbm9fZ2VuZV9sb2N1c190YWcuZmluaXNoZWQKYGBgCgojIFZhcmlhbnQgc2VhcmNoaW5nCgpJIGhhdmUgdHdvIG1ldGhvZHMgb2YgdmFyaWFudCBzZWFyY2hpbmcgaW4gbXkgcmVwZXRvaXJlLCBtcGlsZXVwIGFuZApmcmVlYmF5ZXMuICBJIG9ubHkgbGVhcm5lZCBmcmVlYmF5ZXMgcmVjZW50bHkgYW5kIHNvIGNob3NlIGl0LiAgTXkKY3VycmVudCBpbXBsZW1lbnRhdGlvbiBhbHNvIHNwaW5zIG9mZiBhIHNlcmllcyBvZiBzY3JpcHRzIHRvIHBhcnNlIHRoZQpmcmVlYmF5ZXMgb3V0cHV0IGRvd24gaW50byBhIHNpbXBsZXIgdHN2IGZvcm1hdC4gIEFsc28sIHVubGlrZSB0aGUKbWFwcGluZyBzY3JpcHQgYWJvdmUsIHRoZSBmcmVlYmF5ZXMgaW52b2NhdGlvbiBpdHNlbGYgaW5jbHVkZXMgdGhlCmNvbnZlcnNpb24gb2YgdGhlIHRleHQgdmNmIGZvcm1hdCB0byBhIHNvcnRlZC9jb21wcmVzc2VkL2luZGV4IGJjZgpmb3JtYXQuCgpOb3RlIGFsc28gdGhhdCB0aGUgcHJldmlvdXMgc3RlcCBhbHNvIGNyZWF0ZXMgMyBiYW0gZmlsZXM6CgoxLiAgJHtzYW1wbGV9XyR7c3BlY2llc31fZ2Vub21lLmJhbTogQWxsIGFsaWdubWVudHMKMi4gICR7c2FtcGxlfV8ke3NwZWNpZXN9X2dlbm9tZS1wYWlyZWQuYmFtOiBBbGwgcHJvcGVybHkgcGFpcmVkCiAgICBhbGlnbm1lbnRzLCB0aGlzIGlzIHRoZSBkZWZhdWx0IHVzZWQgYnkgaHRzZXEgd2hlbiBhdmFpbGFibGUuCjMuICAke3NhbXBsZX1fJHtzcGVjaWVzfV9nZW5vbWUtc29ydGVkX25vbWlzbWF0Y2guYmFtOiBUaGlzIGlzCiAgICBmaWx0ZXJlZCBmb3IgdGhlIHNldCBvZiBhbGlnbm1lbnRzIHdpdGggbm8gbWlzbWF0Y2hlcy4KClNpbmNlIHJ1bm5pbmcgdGhlc2Ugc2FtcGxlcywgSSBhZGRlZCBhbm90aGVyIHN1ZmZpeCB0byB0aGUgaGlzYXQKb3V0cHV0IGRpcmVjdG9yaWVzLCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgLWsgcGFyYW1ldGVyIGlzIHVzZWQgdG8KbGltaXQgdGhlIG51bWJlciBvZiBhbGlnbm1lbnRzIHJlcG9ydGVkLiAgVGhhdCBpcyBub3QgcGFydGljdWxhcmx5CnJlbGV2YW50IGhlcmUsIGJ1dCB3b3J0aCBub3RpbmcuCgpgYGB7YmFzaCBmcmVlYmF5ZXMsIGV2YWw9RkFMU0V9CmNkIHByZXByb2Nlc3NpbmcKc3RhcnQ9JChwd2QpCmZvciBpIGluICQoL2Jpbi9scyk7IGRvCiAgICBjZCAke2l9CiAgICBjeW9hIC0tdGFzayBzbnAgLS1tZXRob2QgZnJlZWJheWVzIC0tc3BlY2llcyBwYWVydWdpbm9zYV9wYTAxIFwKICAgICAgICAgLS1pbnB1dCAkKC9iaW4vbHMgb3V0cHV0cy80MGhpc2F0Ml9wYWVydWdpbm9zYV9wYTAxLypfZ2Vub21lLmJhbSkKICAgIGNkICRzdGFydApkb25lCmBgYAoKIyMjIFNpbmdsZSBmcmVlYmF5ZXMgaW52b2NhdGlvbgoKYGBge2Jhc2ggZnJlZWJheWVzX3NjcmlwdCwgZXZhbD1GQUxTRX0KIyEvdXNyL2Jpbi9lbnYgYmFzaAojU0JBVENIIC0tZXhwb3J0PUFMTAojU0JBVENIIC0tbWFpbC10eXBlPU5PTkUKI1NCQVRDSCAtLW9wZW4tbW9kZT1hcHBlbmQKI1NCQVRDSCAtLWNoZGlyPS9tbnQvY2JjYi9mczAxX2FiZWxldy9jYmNiLWxhYi9uZWxzYXllZC9zY3JhdGNoL2F0Yi9kbmFzZXEvcGFlcnVnaW5vc2FfcGxhc21pZHNfMjAyMi9wcmVwcm9jZXNzaW5nL3Bvb2xhCiNTQkFUQ0ggLS1wYXJ0aXRpb249ZHBhcnQKI1NCQVRDSCAtLXFvcz13b3Jrc3RhdGlvbiAtLW5pY2U9MTAKI1NCQVRDSCAtLW5vZGVzPTEgLS1yZXF1ZXVlCiNTQkFUQ0ggLS10aW1lPTEwOjAwOjAwCiNTQkFUQ0ggLS1qb2ItbmFtZT00MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxCiNTQkFUQ0ggLS1tZW09NDhHCiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTQKI1NCQVRDSCAtLW91dHB1dD1vdXRwdXRzL2xvZy50eHQuc2JhdGNoCnNldCAtbyBlcnJleGl0CnNldCAtbyBlcnJ0cmFjZQpzZXQgLW8gcGlwZWZhaWwKZXhwb3J0IExFU1M9Jy0tYnVmZmVycyAwJwpzY3JpcHQ9IiQocHdkKS8kMCIKZXJyKCkgewogICAgZWNobyAiRXJyb3Igb2NjdXJyZWQ6IgogICAgYXdrICdOUj5MLTQgJiYgTlI8TCs0IHsgcHJpbnRmICIlLTVkJTNzJXNcbiIsTlIsKE5SPT1MPyI+Pj4iOiIiKSwkc2NyaXB0IH0nIEw9JDEgJHNjcmlwdAp9CnRyYXAgJ2VyciAkTElORU5PJyBFUlIKCmVjaG8gIiMjIFN0YXJ0ZWQgL21udC9jYmNiL2ZzMDFfYWJlbGV3L2NiY2ItbGFiL25lbHNheWVkL3NjcmF0Y2gvYXRiL2RuYXNlcS9wYWVydWdpbm9zYV9wbGFzbWlkc18yMDIyL3ByZXByb2Nlc3NpbmcvcG9vbGEvc2NyaXB0cy80MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxLnNoIGF0ICQoZGF0ZSkgb24gJChob3N0bmFtZSkgd2l0aCBpZCAke1NMVVJNX0pPQklEfS4iID4+IG91dHB1dHMvbG9nLnR4dAoKbW9kdWxlIGFkZCBmcmVlYmF5ZXMgbGliZ3NsLzIuNy4xIGxpYmh0cy8xLjEzIHNhbXRvb2xzLzEuMTMgYmNmdG9vbHMgdmNmdG9vbHMKCiMjIFVzZSBmcmVlYmF5ZXMsIGJjZnRvb2xzLCBhbmQgdmNmdXRpbHMgdG8gZ2V0IHNvbWUgaWRlYSBhYm91dCBob3cgbWFueSB2YXJpYW50IHBvc2l0aW9ucyBhcmUgaW4gdGhlIGRhdGEuCgpta2RpciAtcCBvdXRwdXRzLzQwZnJlZWJheWVzX3BhZXJ1Z2lub3NhX3BhMDEKZnJlZWJheWVzIC1mIC9ob21lL3RyZXkvbGlicmFyaWVzX2ZzL2dlbm9tZS9wYWVydWdpbm9zYV9wYTAxLmZhc3RhIFwKICAtdiBvdXRwdXRzLzQwZnJlZWJheWVzX3BhZXJ1Z2lub3NhX3BhMDEvcGFlcnVnaW5vc2FfcGEwMS52Y2YgXAogIG91dHB1dHMvNDBoaXNhdDJfcGFlcnVnaW5vc2FfcGEwMS9wb29sYV9wYWVydWdpbm9zYV9wYTAxX2dlbm9tZS5iYW0gXAogIDE+b3V0cHV0cy80MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxL3BhZXJ1Z2lub3NhX3BhMDEuc3Rkb3V0IFwKICAyPm91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLnN0ZGVycgpiY2Z0b29scyBjb252ZXJ0IG91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLnZjZiBcCiAgLU9iIC1vIG91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLmJjZiBcCiAgMj4+b3V0cHV0cy80MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxL3BhZXJ1Z2lub3NhX3BhMDEuc3RkZXJyIFwKICAxPm91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLnN0ZG91dApiY2Z0b29scyBpbmRleCBvdXRwdXRzLzQwZnJlZWJheWVzX3BhZXJ1Z2lub3NhX3BhMDEvcGFlcnVnaW5vc2FfcGEwMS5iY2YgXAogIDI+Pm91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLnN0ZGVyciBcCiAgMT4+b3V0cHV0cy80MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxL3BhZXJ1Z2lub3NhX3BhMDEuc3Rkb3V0CnJtIG91dHB1dHMvNDBmcmVlYmF5ZXNfcGFlcnVnaW5vc2FfcGEwMS9wYWVydWdpbm9zYV9wYTAxLnZjZgoKCiMjIFRoZSBmb2xsb3dpbmcgbGluZXMgZ2l2ZSBzdGF0dXMgY29kZXMgYW5kIHNvbWUgbG9nZ2luZwplY2hvICJKb2Igc3RhdHVzOiAkPyAiID4+IG91dHB1dHMvbG9nLnR4dAplY2hvICIgICQoaG9zdG5hbWUpIEZpbmlzaGVkICR7U0xVUk1fSk9CSUR9IDQwZnJlZWJheWVzX3BhZXJ1Z2lub3NhX3BhMDEuc2ggYXQgJChkYXRlKSwgaXQgdG9vayAkKCggU0VDT05EUyAvIDYwICkpIG1pbnV0ZXMuIiA+PiBvdXRwdXRzL2xvZy50eHQKCmlmIFtbIC14ICIkKGNvbW1hbmQgLXYgc3N0YXQpIiAmJiAhIC16ICIke1NMVVJNX0pPQklEfSIgXV07IHRoZW4KICB3YWxsdGltZT0kKHNjb250cm9sIHNob3cgam9iICIke1NMVVJNX0pPQklEfSIgfCBncmVwIFJ1blRpbWUgfCBwZXJsIC1GJy9ccyt8PS8nIC1sYW5lICd7cHJpbnQgJEZbMl19JyB8IGhlYWQgLW4gMSAyPi9kZXYvbnVsbCkKICBlY2hvICIgIHdhbGx0aW1lIHVzZWQgYnkgJHtTTFVSTV9KT0JJRH0gd2FzOiAke3dhbGx0aW1lOi1udWxsfSIgPj4gb3V0cHV0cy9sb2cudHh0CiAgbWF4bWVtPSQoc3N0YXQgLS1mb3JtYXQ9TWF4Vk1TaXplIC1uICIke1NMVVJNX0pPQklEfS5iYXRjaCIgMj4vZGV2L251bGwpCiAgZWNobyAiICBtYXhpbXVtIG1lbW9yeSB1c2VkIGJ5ICR7U0xVUk1fSk9CSUR9IHdhczogJHttYXhtZW06LW51bGx9IiA+PiBvdXRwdXRzL2xvZy50eHQKICBlY2hvICIiID4+IG91dHB1dHMvbG9nLnR4dApmaQojIyBBZGRpbmcgYSBsaXR0bGUgbG9naWMgdG8gaGF2ZSBza2lwIGZpbmlzaGVkIGpvYnMuCnRvdWNoIG91dHB1dHMvbG9ncy80MGZyZWViYXllc19wYWVydWdpbm9zYV9wYTAxLmZpbmlzaGVkCmBgYAoKVXBvbiBjb21wbGV0aW9uIHdlIGhhdmUgYSBzZXJpZXMgb2YgZmlsZXMgd2hpY2ggaW4gdGhlb3J5IHNob3VsZApwcm92aWRlIGV2ZXJ5dGhpbmcgb2YgaW50ZXJlc3QgdG8gVmluY2UuICBMZXRzIHBva2UgYXQgdGhlbSBpbiBSIQoKIyBWaW5jZSdzIFJlcXVlc3RzCgpIZXJlIGlzIG15IGVtYWlsIGZyb20gVmluY2Ugd2l0aCBoaXMgaW5pdGlhbCwgcGFyZWQgZG93biBxdWVyaWVzOgoKIgpCYXNlZCBvbiB0aGUgZGF0YSB5b3UgaGF2ZSBhbmFseXplZCwgY2FuIHlvdSBwbGVhc2Ugc2hhcmUgd2l0aCBtZSBhCkV4Y2VsIHNwcmVhZHNoZWV0IChvciBDU1YgZmlsZSkgd2l0aCAyIGNvbHVtbnMgZm9yIGVhY2ggbGlicmFyeSBhbmQKZWFjaCBQQSBnZW5lOgoKMS4gQ292ZXJhZ2UgKFJQS00pIG9yIDAgZm9yIG5vIHJlYWRzCjIuIE51bWJlciBvZiBTTlBzCiIKCiMjIEFubm90YXRpb24KCkkgYWx3YXlzIGdyYWIgbXkgZmF2b3JpdGUgYW5ub3RhdGlvbiBzb3VyY2VzLCBldmVuIGlmIEkgd2lsbCBub3QKcmVhbGx5IHVzZSB0aGVtLiAgSSB1c3VhbGx5IGNvcHkgdGhlIGdmZiBhbmQgZmFzdGEgZm9yIHRoZSB2ZXJzaW9uIG9mCnRoZSBnZW5vbWUgSSB1c2VkIHRvIHRoZSBsb2NhbCBkaXJlY3RvcnksIGJ1dCBJIGRpZCBub3QgYm90aGVyIGZvciB0aGlzLgoKYGBge3IgYW5ub3RhdGlvbn0KcGEwMV9nZmYgPC0gbG9hZF9nZmZfYW5ub3RhdGlvbnMoIn4vbGlicmFyaWVzX2ZzL2dlbm9tZS9wYWVydWdpbm9zYV9wYTAxLmdmZiIsIGlkX2NvbD0ibG9jdXNfdGFnIikKcm93bmFtZXMocGEwMV9nZmYpIDwtIHBhMDFfZ2ZmW1sibG9jdXNfdGFnIl1dCmBgYAoKIyMgRXhwcmVzc2lvbnNldAoKTGV0IHVzIG5vdyBwdWxsIG91dCB0aGUgaHRzZXEgY291bnQgdGFibGVzIGluIG9yZGVyIHRvIG1ha2UgYW4gcnBrbQp0YWJsZS4gIFRoaXMgdXNlcyB0aGUgbWV0YWRhdGEgc2FtcGxlIHNoZWV0IEkgY3JlYXRlZCBpbiB0aGUKc2FtcGxlX3NoZWV0cy8gZGlyZWN0b3J5LgoKSSBib2xkZWQgdGhlIHR3byBtb3N0IGltcG9ydGFudCBjb2x1bW5zIGZvciB0aGUgcHVycG9zZXMgb2YgdGhlc2UgdGFza3MuCgpgYGB7ciBleHByc30KcGEwMV9leHB0IDwtIGNyZWF0ZV9leHB0KCJzYW1wbGVfc2hlZXRzL2FsbF9zYW1wbGVzLnhsc3giLCBnZW5lX2luZm89cGEwMV9nZmYpCnBhMDFfcnBrbSA8LSBub3JtYWxpemVfZXhwdChwYTAxX2V4cHQsIGNvbnZlcnQ9InJwa20iKQoKIyMgUGxvdCBhIGxvZy1zY2FsZSBkZW5zaXR5IG9mIHJwa20gdmFsdWVzLgpwbG90X2JveHBsb3QocGEwMV9leHB0KQpwbG90X2RlbnNpdHkobm9ybWFsaXplX2V4cHQocGEwMV9ycGttLCB0cmFuc2Zvcm09ImxvZzIiLCBmaWx0ZXI9VFJVRSkpCnBsb3Rfbm9uemVybyhwYTAxX2V4cHQpJHBsb3QKCnJwa21fZGYgPC0gYXMuZGF0YS5mcmFtZShleHBycyhwYTAxX3Jwa20pKSAlPiUKICByb3VuZCgyKQp3YW50ZWRfYW5ub3RhdGlvbnMgPC0gZkRhdGEocGEwMV9leHB0KVssIGMoImdlbmUiLCAibG9jdXNfdGFnIildCndhbnRlZF9kYXRhIDwtIG1lcmdlKHdhbnRlZF9hbm5vdGF0aW9ucywgcnBrbV9kZiwKICAgICAgICAgICAgICAgICAgICAgYnk9InJvdy5uYW1lcyIpCnJvd25hbWVzKHdhbnRlZF9kYXRhKSA8LSB3YW50ZWRfZGF0YVtbIlJvdy5uYW1lcyJdXQp3YW50ZWRfZGF0YVtbIlJvdy5uYW1lcyJdXSA8LSBOVUxMCmBgYAoKIyBHYXRoZXJpbmcgbXV0YXRpb25zIG51bWJlcnMgYnkgZ2VuZQoKSSBkbyBub3QgaGF2ZSBhbiBpbnN0YW50IGZ1bmN0aW9uIGZvciB0aGlzIHRhc2ssIGJ1dCBpdCBzaG91bGQgbm90CnByb3ZlIGRpZmZpY3VsdC4KCmBgYHtyIGdhdGhlcl9tdXRhdGlvbnN9CndhbnRlZF92MiA8LSB3YW50ZWRfZGF0YQpmb3IgKHNhbXBsZSBpbiByb3duYW1lcyhwRGF0YShwYTAxX2V4cHQpKSkgewogIGlucHV0X2ZpbGUgPC0gZ2x1ZTo6Z2x1ZSgicHJlcHJvY2Vzc2luZy97c2FtcGxlfS9vdXRwdXRzLzQwZnJlZWJheWVzX3BhZXJ1Z2lub3NhX3BhMDEvcGFlcnVnaW5vc2FfcGEwMV9oaXRzX2J5X2dlbmUudHh0Lnh6IikKICBpbnB1dF9kYXRhIDwtIHJlYWRyOjpyZWFkX3RzdihpbnB1dF9maWxlLCBjb2xfbmFtZXM9YygiZ2VuZSIsICJjaHIiLCAicG9zdGlvbiIsICJudF9zdHJpbmciLCAiYWFfc3RyaW5nIikpCiAgaW5wdXRfY29sdW1uIDwtIGlucHV0X2RhdGEgJT4lCiAgICBkcGx5cjo6Z3JvdXBfYnkoZ2VuZSkgJT4lCiAgICBkcGx5cjo6c3VtbWFyaXplKG49bigpKQogIGNvbG5hbWVzKGlucHV0X2NvbHVtbikgPC0gYygiZ2VuZSIsIHBhc3RlMChzYW1wbGUsICJfbiIpKQogIHdhbnRlZF92MiA8LSBtZXJnZSh3YW50ZWRfdjIsIGlucHV0X2NvbHVtbiwgYnkueD0icm93Lm5hbWVzIiwgYnkueT0iZ2VuZSIpCiAgcm93bmFtZXMod2FudGVkX3YyKSA8LSB3YW50ZWRfdjJbWyJSb3cubmFtZXMiXV0KICB3YW50ZWRfdjJbWyJSb3cubmFtZXMiXV0gPC0gTlVMTAp9CgojIyBXcml0ZSBpdCBvdXQKd3JpdHRlbiA8LSB3cml0ZV94bHN4KGRhdGE9d2FudGVkX3YyLCBleGNlbD0iZXhjZWwvcnBrbV9tdXRhdGlvbnNfcGVyX2dlbmUueGxzeCIpCmBgYAoKCmBgYHtyIHNhdmVtZSwgZXZhbD1GQUxTRX0KcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKbWVzc2FnZShwYXN0ZTAoIlRoaXMgaXMgaHBnbHRvb2xzIGNvbW1pdDogIiwgZ2V0X2dpdF9jb21taXQoKSkpCnRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCm1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKdG1wIDwtIHNtKHNhdmVtZShmaWxlbmFtZT10aGlzX3NhdmUpKQpgYGAK