library(tidyverse)

Sequencing and Basecalling
Sequencing was performed on two flow cells, an R9.4.1 and an R10.4.1.
Each cell was loaded and run for 24 hours, then nuclease flushed and
reloaded an additional 24 hours for a total of 72 hours. Post-hoc
basecalling was performed using guppy with the following parameters to
include modified basecalling at CpG sites.
guppy_basecaller --input_path . -r -s sgm-output/ -c dna_r10.4.1_e8.2_400bps_modbases_5mc_cg_sup.cfg --bam_out --compress_fastq --nested_output_folder --min_qscore 10`
Full Assembly
Flye --asm-coverage 128
Assemblies were compared with the full read set and a subset of
>3400 bp reads. The full read set yielded better assemblies as
measured by BUSCO and was used for all further processing.
Install
Flye 2.9.1-b1780 was installed from github via conda
conda env create -n flye -c bioconda flye=2.9.1
conda activate flye
Run
The --asm-coverage
option limits the minimum required
coverage for the initial disjointig extension state, a memory bottleneck
in the program. Setting --genome-size
also reduces memory
usage.
flye --nano-hq sgm-total.fastq --out-dir flye_results_sgmtotal --genome-size 200m --asm-coverage 128 --threads 23 --no-alt-contigs
The run completed in ~3 hours on a 12 core AMD 5900.
BUSCO
BUSCO scores are used to assess assembly quality without reliance on
inherent non-biologically relevant characteristics of the assembly. It
identifies phylum-unique genes within the assembly. So, this assembly
should contain a high number of the genes unique to Diptera
Install
The command line package busco
v5.4.2 was installed in a
mamba
virtual environment on via
mamba install -c bioconda -c conda-forge busco=5.4.2
.
Note: the mamba documentation says you should still use conda to
activate and deactivate. Full environment specs in
busco_conda_env.txt
.
Run
busco
in genome mode was run in a mamba (conda) virtual
environment, taking approximately 15 minutes.
Diptera lineage
busco -i assembly.fasta -o busco_output_draft -m genome --lineage diptera -c 24
Results via auto-generated short_summary text file:
# BUSCO version is: 5.4.2
# The lineage dataset is: diptera_odb10 (Creation date: 2020-08-05, number of genomes: 56, number of BUSCOs: 3285)
# Summarized benchmarking in BUSCO notation for file /home/cfaulk/Desktop/ont-sequencing_runs/soybean_gall_midge/sgm-analysis/flye_results_sgmtotal/medaka-results/consensus.fasta
# BUSCO was run in mode: euk_genome_met
# Gene predictor used: metaeuk
***** Results: *****
C:87.9%[S:85.1%,D:2.8%],F:1.9%,M:10.2%,n:3285
2886 Complete BUSCOs (C)
2795 Complete and single-copy BUSCOs (S)
91 Complete and duplicated BUSCOs (D)
63 Fragmented BUSCOs (F)
336 Missing BUSCOs (M)
3285 Total BUSCO groups searched
Assembly Statistics:
2613 Number of scaffolds
2613 Number of contigs
211232549 Total length
0.000% Percent gaps
698 KB Scaffold N50
698 KB Contigs N50
Dependencies and versions:
hmmsearch: 3.1
bbtools: 39.01
metaeuk: 5.34c21f2
busco: 5.4.2
Polish
Medaka v1.7.2 was used to polish the assembly.
conda env create -n medaka -c bioconda flye=1.7.2
conda activate medaka
#Note that r941_min_sup_g507 model was used because some of the data came from an r9 flow cell.
medaka_consensus -b 100 -i sgm-total.fasq -d assembly.fasta -o medaka-results -t 24 -m r941_min_sup_g507
BUSCO
/home/cfaulk/miniconda3/bin/busco -i medaka-results/consensus.fasta -o sgm-total-medaka-busco -m genome -l diptera -c 24
Result:
C:87.9%[S:85.1%,D:2.8%],F:1.9%,M:10.2%,n:3285
Purge haplotigs
Skipped purge_haplotigs, since separate peaks were not obvious,
indicating lack of demonstrated haplotig presence.
minimap2 -t 24 -ax map-ont consensus.fasta ../sgm-total.fastq | samtools sort -m 1G -o aligned.bam -T tmp.ali
purge_haplotigs hist -b aligned.bam -g consensus.fasta -t 24
BLAST for contaminants
Blast was performed and provided to Blobtools as input. A local
installation of blast++ and the non-redundant (nr) database were used to
identify contigs.
blastn -query consensus.fasta -task megablast -db ~/Desktop/genomes/nt/nt -outfmt '6 qseqid staxids bitscore std sscinames sskingdoms stitle' -culling_limit 10 -num_threads 23 -evalue 1e-3 -out consensus.fasta.vs.nt.cul5.1e3.megablast.out
Megablast results are saved as
consensus.fasta.vs.nt.cul5.1e3.megablast.out
, assembly as
consensus.fasta
, coverage information as
consensus.coverage.txt
, and BUSCO results as
full_table.tsv
. These files are ready for Blobtoolkit
input.
Decontamination
We filter on the following criteria to remove short and low coverage
contigs. These filter settings result in no loss of full length
BUSCOs.
Remove length less than 8000 bp.
Remove coverage less than 20X and greater than 200X.
Filtered contigs are exported in .csv format from blobtools
2613 Original Contigs
1009 Remaining Contigs saved as 1009.clean.contigs.csv
Filter assembly
Use seqkit to filter the consensus assembly to only the 1009 contigs
from decontamination.
seqkit grep -f 1009.contigs.id.txt ../blobtools-out/consensus.fasta -o clean.consensus.fasta
Final BUSCO
busco -i clean.consensus.fasta -o busco-cleanconsensus -m genome -l ~/Desktop/genomes/busco_downloads/lineages/diptera_odb10 -c 24
Result:
***** Results: *****
C:87.8%[S:85.2%,D:2.6%],F:1.9%,M:10.3%,n:3285
2886 Complete BUSCOs (C)
2800 Complete and single-copy BUSCOs (S)
86 Complete and duplicated BUSCOs (D)
63 Fragmented BUSCOs (F)
336 Missing BUSCOs (M)
3285 Total BUSCO groups searched
Methylation
Use the unmapped .bam files generated during the guppy basecalling.
Cat together modbams for each flow cell directory:
samtools cat -o sgm-mod.unmapped.bam bug1/*.bam bug2/*.bam bug3/*.bam
Map Unmapped Bams.
Map, convert and sort all in one command. The -T Mm,Ml
flag carries over the modifications from bam to fastq. In newer bams the
flags are -T MM, ML
. The -y
flag copies input
fastq commands to output.
samtools fastq -T Mm,Ml sgm-mod.unmapped.bam | minimap2 -y -ax map-ont ../final_assembly/clean.consensus.fasta - -t 24 | samtools view -u - | samtools sort -@ 24 -o sgm.modmapped.bam; samtools index sgm.modmapped.bam -@ 24
Convert to bed format. The -d
flag limits depth to save
memory. The aggregate flag adds together bases on either strand and
creates and aggregate.bed file. The -cpg
flag limits to cpg
sites.
modbam2bed -m 5mC -t 23 -e -d 300 -p sgm.modmapped --aggregate --cpg clean.consensus.fasta sgm.modmapped.bam > sgm.modmapped.bed
Assess global DNA methylation as a percentage by adding up all
canonical (column 12) and modified (column 13) cytosine base calls at
CpG sites. Divide the modified by the total and print.
awk '$5>0 {can+=$12; mod+=$13} END{print 100*(mod/(can+mod))}' sgm.mapped.bed
Global Methylation
1.07294 is the global methylation in Soybean Gall Midge
Mosdepth Assembly Stats
Depth statistics generated with mosdepth
Run
Overall depth stats:
mosdepth -n --fast-mode -t 8 sgm.modmapped ../methylation/sgm.modmapped.bam
chrom length bases mean min max
total 206036186 13366775054 64.88 0 43586
For 500 bp windows:
mosdepth -n --fast-mode --by 500 -t 8 500bpwindow.sgm.modmapped ../methylation/sgm.modmapped.bam
chrom length bases mean min max
total_region 206036186 13366775054 64.88 0 43586
Repeats
Repeat Identification
Since annotated repeats in insect genomes are sparse, repeat
identification requires two stages. First de novo repeat
identification was performed with RepeatModler2.
Second, the libraries generated with RepeatModeler2 were used as input
to RepeatMasker to create a
complete genome annotation of repeats with existing names for classes,
families, and subfamilies where known and novel IDs for previously
unknown families.
RepeatModeler was run to identify repeat content. Takes about 24
hours on a 300 Mb insect genome.
- First build database from consensus fasta.
/usr/local/RepeatModeler-2.0.2a/BuildDatabase -name "sgm-genome" ../final-assembly/consensus.clean.fasta
- Run RepeatModeler2.
nohup <RepeatModelerPath>/RepeatModeler -database sgm-genome -pa 14 -LTRStruct >& run.out &
- RepeatMasker was then run to determine genomic repeat content
specifying the custom library created with RepeatModeler.
RepeatMasker -pa 14 -s -xsmall -lib sgm-genome-families.fa ../final-assembly/consensus.clean.fasta
Comparison to other midge genomes was performed using Dfam v3.6 and
by ab initio identification using the same RepeatModeler2 pipeline as
above.
GeMoMa Gene Annotation
Wiki
Install
Install depencency mmseq
:
conda install -c conda-forge -c bioconda mmseqs2
Installed version 1.9 by downloading .zip
file from website
vs. Drosophila melanogaster (dm6) and Swede midge (Contarinia
nasturtii)
Two annotations of diptera were used as a reference based on close
phylogenetic proximity to the soybean gall midge and annotation
availability. FASTA and GFF files were downloaded from NCBI’s Assembly
page. Note: A hardmasked version of the genome (repeats
replaced with N’s) was used for input to eliminate transposon derived
genes.
java -Xmx50g -jar gemoma-java/GeMoMa-1.9.jar CLI GeMoMaPipeline threads=23 outdir=combined_Dmel_swedemidge GeMoMa.Score=ReAlign AnnotationFinalizer.r=NO o=true t=clean.consensus.hardmasked.fasta s=own i=swede_gall_midge a=GCF_009176525.2_AAFC_CNas_1.1_genomic.gff g=GCF_009176525.2_AAFC_CNas_1.1_genomic.fna s=own i=D_mel g=GCA_000001215.4_Release_6_plus_ISO1_MT_genomic.fna a=GCA_000001215.4_Release_6_plus_ISO1_MT_genomic.gff
BUSCO was used to assess completeness in protein mode:
busco -i predicted_proteins.fasta -o busco -m protein -l diptera -c 24
--------------------------------------------------
|Results from dataset diptera_odb10 |
--------------------------------------------------
|C:89.9%[S:85.5%,D:4.4%],F:0.7%,M:9.4%,n:3285 |
|2952 Complete BUSCOs (C) |
|2808 Complete and single-copy BUSCOs (S) |
|144 Complete and duplicated BUSCOs (D) |
|24 Fragmented BUSCOs (F) |
|309 Missing BUSCOs (M) |
|3285 Total BUSCO groups searched |
--------------------------------------------------
2023-01-05 18:39:09 INFO: BUSCO analysis done. Total running time: 110 seconds
2023-01-05 18:39:09 INFO: Results written in /home/cfaulk/Desktop/ont-sequencing_runs/soybean_gall_midge/sgm-analysis/gemoma-out/combined_Dmel_swedemidge/busco-combined-protein
Mitochondrial genome
Total reads were first blasted by mtblaster (https://github.com/nidafra92/squirrel-project/blob/master/mtblaster.py))
using the Orseolia oryzae mitogenome (KM888183) to select for reads with
high identity to a gall midge mitochondria sequence. We blasted against
reads only from the R10 flowcell to ensure higher accuracy. Next,
resulting reads were filtered by nanofilt (https://github.com/wdecoster/nanofilt))
to keep only reads above 15 kbp in length and average Q-score above 30.
Finally, flye was used to perform mitogenome assembly (Kolmogorov et al.
2020). A single circular contig was recovered with 785X coverage. The
assembly was polished using four rounds of racon (https://github.com/lbcb-sci/racon) followed by medaka
with the same parameters as the nuclear assembly.
Blast against reads from the R10 flow cell:
mtblaster.py sgm-bug3.fastq Orseolia_oryzae-KM888183.1.fasta
Filter reads higher than 15 kb with quality >Q30.
nanofilt -l 15000 -q 30 reads_w_hits.fastq > reads_w_hits15kq30.fastq
Run flye to assemble genome using the asm parameter.
flye --nano-hq reads_w_hits15kq30.fastq --out-dir flye-mitogenome-highasm --genome-size 16k --threads 24 --asm 256
Run 4 rounds of Racon polishing,
minimap2 -ax map-ont assembly.fasta ../reads_w_hits15kq30.fastq > assembly.sam
racon -t 24 ../reads_w_hits15kq30.fastq assembly.sam assembly.fasta > assembly.racon1.fasta
Final polish with medaka.
medaka_consensus -i ../reads_w_hits15kq30.fastq -d assembly.racon4.fasta -o medaka-results/ -t 23 -m r1041_e82_400bps_sup_g615
Save consensus.fasta
as
sgm_mitogenome_consensus.fasta
Wolbachia detection
Collect panel of 9 genomes into a single fasta file and match against
the total SGM read set. Identify any resulting matches against the
kracken2 standard database. The genomes were downloaded from NCBI and
are listed in the manuscript.
Match reads to Wolbachia genomes.
minimap2 -ax map-ont wolbachia-panel/wolbachia-panel.fna ../sgm-total.fastq.gz -t 23 > wolbachia-panel.vs.sgm-total.sam
Sort and convert to bam format.
samtools sort -@24 -O BAM -o sgm-total.vs.wolbachia-panel.sorted.bam wolbachia-panel.vs.sgm-total.sam
Filter alignment file for only mapped reads.
samtools fasta -F 4 sgm-total.vs.wolbachia-panel.sorted.bam > sgm-total.vs.wolbachia-panel.sorted.hits.bam
Remove duplicates.
awk '/^>/{f=!d[$1];d[$1]=1}f' sgm-total.vs.wolbachia-panel.sorted.hits.fasta > sgm-total.vs.wolbachia-panel.sorted.nodups.fasta
Run through Kraken2.
kraken2 --db /mnt/data16Tb/kraken_db/k2_standard_16gb_20220607 --threads 23 --use-names --report sgm.vs.wolbachia-panel.report.txt --output sgm.vs.wolbachia-panel.txt sgm-total.vs.wolbachia-panel.sorted.nodups.fasta
Run Pavian from inside R to generate graphics.
pavian::runApp(port=5000)
NCBI Submission
Link
Used command line to upload folder:
- Navigate to the source folder where the files for submission
are;
- Establish an FTP connection using the credentials below: Address:
ftp-private.ncbi.nlm.nih.gov
Username: subftp
Password: <sent via email>
- Navigate to your account folder: From the command line use the ‘cd’
command:
cd uploads/<folder_sent_by_email>
When using a GUI FTP client (eg: Filezilla, NcFTP, Cyberduck, etc.),
after you’ve connected to the FTP server, paste your account folder
(uploads/<folder_sent_by_email>
) into the “Remote
Site” or “Remote Directory” box on the interface and press “Enter”.
Then you will be able to create the data sub-directory for your
submission. Until you do this, you will see a message stating “550 /:
Permission denied” or “Failed to read the directory listing”. We prevent
directory listing in the default sign in folder for security
reasons.
Create a subfolder (required!) with a meaningful name. Navigate to
the target folder you just created. Copy your files into the target
folder:
<mitogenome>.fa.gz <nuclear_genome>.fa.gz
Press “New submission” in browser.
LS0tCnRpdGxlOiAiU295YmVhbiBHYWxsIE1pZGdlIEdlbm9tZSBOb3RlYm9vayIKYXV0aG9yOiAiQ2hyaXMgRmF1bGsiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBkZl9wcmludDogdGliYmxlCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIVtTb3liZWFuIEdhbGwgTWlkZ2UuXShpbWFnZXMvc2dtX2ltYWdlLmpwZykKCiFbXShpbWFnZXMvam9uZXMlMjBnYWxsJTIwbWlkZ2UlMjBpbGx1c3RyYXRpb24uanBnKQoKIyBTZXF1ZW5jaW5nIGFuZCBCYXNlY2FsbGluZwoKU2VxdWVuY2luZyB3YXMgcGVyZm9ybWVkIG9uIHR3byBmbG93IGNlbGxzLCBhbiBSOS40LjEgYW5kIGFuIFIxMC40LjEuCkVhY2ggY2VsbCB3YXMgbG9hZGVkIGFuZCBydW4gZm9yIDI0IGhvdXJzLCB0aGVuIG51Y2xlYXNlIGZsdXNoZWQgYW5kCnJlbG9hZGVkIGFuIGFkZGl0aW9uYWwgMjQgaG91cnMgZm9yIGEgdG90YWwgb2YgNzIgaG91cnMuIFBvc3QtaG9jCmJhc2VjYWxsaW5nIHdhcyBwZXJmb3JtZWQgdXNpbmcgZ3VwcHkgd2l0aCB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgdG8KaW5jbHVkZSBtb2RpZmllZCBiYXNlY2FsbGluZyBhdCBDcEcgc2l0ZXMuCgpgYGAgeyNndXBweV9iYXNlY2FsbCAuYmFzaH0KZ3VwcHlfYmFzZWNhbGxlciAtLWlucHV0X3BhdGggLiAtciAtcyBzZ20tb3V0cHV0LyAtYyBkbmFfcjEwLjQuMV9lOC4yXzQwMGJwc19tb2RiYXNlc181bWNfY2dfc3VwLmNmZyAtLWJhbV9vdXQgLS1jb21wcmVzc19mYXN0cSAtLW5lc3RlZF9vdXRwdXRfZm9sZGVyIC0tbWluX3FzY29yZSAxMGAKYGBgCgojIEZ1bGwgQXNzZW1ibHkKCiMjIyBGbHllIGAtLWFzbS1jb3ZlcmFnZSAxMjhgCgpBc3NlbWJsaWVzIHdlcmUgY29tcGFyZWQgd2l0aCB0aGUgZnVsbCByZWFkIHNldCBhbmQgYSBzdWJzZXQgb2YgXD4zNDAwCmJwIHJlYWRzLiBUaGUgZnVsbCByZWFkIHNldCB5aWVsZGVkIGJldHRlciBhc3NlbWJsaWVzIGFzIG1lYXN1cmVkIGJ5CkJVU0NPIGFuZCB3YXMgdXNlZCBmb3IgYWxsIGZ1cnRoZXIgcHJvY2Vzc2luZy4KCiMjIyBJbnN0YWxsCgpGbHllIDIuOS4xLWIxNzgwIHdhcyBpbnN0YWxsZWQgZnJvbSBnaXRodWIgdmlhIGNvbmRhCgpgYGAgeyNmbHllX2luc3RhbGwgLmJhc2h9CmNvbmRhIGVudiBjcmVhdGUgLW4gZmx5ZSAtYyBiaW9jb25kYSBmbHllPTIuOS4xCmNvbmRhIGFjdGl2YXRlIGZseWUKYGBgCgojIyMgUnVuCgpUaGUgYC0tYXNtLWNvdmVyYWdlYCBvcHRpb24gbGltaXRzIHRoZSBtaW5pbXVtIHJlcXVpcmVkIGNvdmVyYWdlIGZvciB0aGUKaW5pdGlhbCBkaXNqb2ludGlnIGV4dGVuc2lvbiBzdGF0ZSwgYSBtZW1vcnkgYm90dGxlbmVjayBpbiB0aGUgcHJvZ3JhbS4KU2V0dGluZyBgLS1nZW5vbWUtc2l6ZWAgYWxzbyByZWR1Y2VzIG1lbW9yeSB1c2FnZS4KCmBgYCB7I2ZseWVfYXNtX3J1biAuYmFzaH0KZmx5ZSAtLW5hbm8taHEgc2dtLXRvdGFsLmZhc3RxIC0tb3V0LWRpciBmbHllX3Jlc3VsdHNfc2dtdG90YWwgLS1nZW5vbWUtc2l6ZSAyMDBtIC0tYXNtLWNvdmVyYWdlIDEyOCAtLXRocmVhZHMgMjMgLS1uby1hbHQtY29udGlncwpgYGAKClRoZSBydW4gY29tcGxldGVkIGluIFx+MyBob3VycyBvbiBhIDEyIGNvcmUgQU1EIDU5MDAuCgojIyMgQlVTQ08KCkJVU0NPIHNjb3JlcyBhcmUgdXNlZCB0byBhc3Nlc3MgYXNzZW1ibHkgcXVhbGl0eSB3aXRob3V0IHJlbGlhbmNlIG9uCmluaGVyZW50IG5vbi1iaW9sb2dpY2FsbHkgcmVsZXZhbnQgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBhc3NlbWJseS4gSXQKaWRlbnRpZmllcyBwaHlsdW0tdW5pcXVlIGdlbmVzIHdpdGhpbiB0aGUgYXNzZW1ibHkuIFNvLCB0aGlzIGFzc2VtYmx5CnNob3VsZCBjb250YWluIGEgaGlnaCBudW1iZXIgb2YgdGhlIGdlbmVzIHVuaXF1ZSB0byBEaXB0ZXJhCgojIyMjIEluc3RhbGwKClRoZSBjb21tYW5kIGxpbmUgcGFja2FnZSBgYnVzY29gIHY1LjQuMiB3YXMgaW5zdGFsbGVkIGluIGEgYG1hbWJhYAp2aXJ0dWFsIGVudmlyb25tZW50IG9uIHZpYQpgbWFtYmEgaW5zdGFsbCAtYyBiaW9jb25kYSAtYyBjb25kYS1mb3JnZSBidXNjbz01LjQuMmAuICpOb3RlOiB0aGUgbWFtYmEKZG9jdW1lbnRhdGlvbiBzYXlzIHlvdSBzaG91bGQgc3RpbGwgdXNlIGNvbmRhIHRvIGFjdGl2YXRlIGFuZApkZWFjdGl2YXRlKi4gRnVsbCBlbnZpcm9ubWVudCBzcGVjcyBpbiBgYnVzY29fY29uZGFfZW52LnR4dGAuCgojIyMjIFJ1bgoKYGJ1c2NvYCBpbiBnZW5vbWUgbW9kZSB3YXMgcnVuIGluIGEgbWFtYmEgKGNvbmRhKSB2aXJ0dWFsIGVudmlyb25tZW50LAp0YWtpbmcgYXBwcm94aW1hdGVseSAxNSBtaW51dGVzLgoKIyMjIyBEaXB0ZXJhIGxpbmVhZ2UKCmBidXNjbyAtaSBhc3NlbWJseS5mYXN0YSAtbyBidXNjb19vdXRwdXRfZHJhZnQgLW0gZ2Vub21lIC0tbGluZWFnZSBkaXB0ZXJhIC1jIDI0YAoKUmVzdWx0cyB2aWEgYXV0by1nZW5lcmF0ZWQgc2hvcnRfc3VtbWFyeSB0ZXh0IGZpbGU6CgpgYGAgeyNzZ21fdG90YWxfYnVzY28gLmJhc2h9CiMgQlVTQ08gdmVyc2lvbiBpczogNS40LjIgCiMgVGhlIGxpbmVhZ2UgZGF0YXNldCBpczogZGlwdGVyYV9vZGIxMCAoQ3JlYXRpb24gZGF0ZTogMjAyMC0wOC0wNSwgbnVtYmVyIG9mIGdlbm9tZXM6IDU2LCBudW1iZXIgb2YgQlVTQ09zOiAzMjg1KQojIFN1bW1hcml6ZWQgYmVuY2htYXJraW5nIGluIEJVU0NPIG5vdGF0aW9uIGZvciBmaWxlIC9ob21lL2NmYXVsay9EZXNrdG9wL29udC1zZXF1ZW5jaW5nX3J1bnMvc295YmVhbl9nYWxsX21pZGdlL3NnbS1hbmFseXNpcy9mbHllX3Jlc3VsdHNfc2dtdG90YWwvbWVkYWthLXJlc3VsdHMvY29uc2Vuc3VzLmZhc3RhCiMgQlVTQ08gd2FzIHJ1biBpbiBtb2RlOiBldWtfZ2Vub21lX21ldAojIEdlbmUgcHJlZGljdG9yIHVzZWQ6IG1ldGFldWsKCiAgICAqKioqKiBSZXN1bHRzOiAqKioqKgogICAgQzo4Ny45JVtTOjg1LjElLEQ6Mi44JV0sRjoxLjklLE06MTAuMiUsbjozMjg1ICAgICAgCiAgICAyODg2ICAgIENvbXBsZXRlIEJVU0NPcyAoQykgICAgICAgICAgICAKICAgIDI3OTUgICAgQ29tcGxldGUgYW5kIHNpbmdsZS1jb3B5IEJVU0NPcyAoUykgICAgCiAgICA5MSAgQ29tcGxldGUgYW5kIGR1cGxpY2F0ZWQgQlVTQ09zIChEKSAgICAgCiAgICA2MyAgRnJhZ21lbnRlZCBCVVNDT3MgKEYpICAgICAgICAgICAgICAKICAgIDMzNiBNaXNzaW5nIEJVU0NPcyAoTSkgICAgICAgICAgICAgCiAgICAzMjg1ICAgIFRvdGFsIEJVU0NPIGdyb3VwcyBzZWFyY2hlZCAgICAgICAgCgpBc3NlbWJseSBTdGF0aXN0aWNzOgogICAgMjYxMyAgICBOdW1iZXIgb2Ygc2NhZmZvbGRzCiAgICAyNjEzICAgIE51bWJlciBvZiBjb250aWdzCiAgICAyMTEyMzI1NDkgICBUb3RhbCBsZW5ndGgKICAgIDAuMDAwJSAgUGVyY2VudCBnYXBzCiAgICA2OTggS0IgIFNjYWZmb2xkIE41MAogICAgNjk4IEtCICBDb250aWdzIE41MAoKRGVwZW5kZW5jaWVzIGFuZCB2ZXJzaW9uczoKICAgIGhtbXNlYXJjaDogMy4xCiAgICBiYnRvb2xzOiAzOS4wMQogICAgbWV0YWV1azogNS4zNGMyMWYyCiAgICBidXNjbzogNS40LjIKYGBgCgojIyMgUG9saXNoCgpNZWRha2EgdjEuNy4yIHdhcyB1c2VkIHRvIHBvbGlzaCB0aGUgYXNzZW1ibHkuCgpgYGAgeyNtZWRha2FfaW5zdGFsbCAuYmFzaH0KCmNvbmRhIGVudiBjcmVhdGUgLW4gbWVkYWthIC1jIGJpb2NvbmRhIGZseWU9MS43LjIKY29uZGEgYWN0aXZhdGUgbWVkYWthCgojTm90ZSB0aGF0IHI5NDFfbWluX3N1cF9nNTA3IG1vZGVsIHdhcyB1c2VkIGJlY2F1c2Ugc29tZSBvZiB0aGUgZGF0YSBjYW1lIGZyb20gYW4gcjkgZmxvdyBjZWxsLgptZWRha2FfY29uc2Vuc3VzIC1iIDEwMCAtaSBzZ20tdG90YWwuZmFzcSAtZCBhc3NlbWJseS5mYXN0YSAtbyBtZWRha2EtcmVzdWx0cyAtdCAyNCAtbSByOTQxX21pbl9zdXBfZzUwNwpgYGAKCiMjIyMjIEJVU0NPCgpgL2hvbWUvY2ZhdWxrL21pbmljb25kYTMvYmluL2J1c2NvIC1pIG1lZGFrYS1yZXN1bHRzL2NvbnNlbnN1cy5mYXN0YSAtbyBzZ20tdG90YWwtbWVkYWthLWJ1c2NvIC1tIGdlbm9tZSAtbCBkaXB0ZXJhIC1jIDI0YAoKUmVzdWx0OiBgQzo4Ny45JVtTOjg1LjElLEQ6Mi44JV0sRjoxLjklLE06MTAuMiUsbjozMjg1YAoKIyMjIFB1cmdlIGhhcGxvdGlncwoKU2tpcHBlZCBwdXJnZV9oYXBsb3RpZ3MsIHNpbmNlIHNlcGFyYXRlIHBlYWtzIHdlcmUgbm90IG9idmlvdXMsCmluZGljYXRpbmcgbGFjayBvZiBkZW1vbnN0cmF0ZWQgaGFwbG90aWcgcHJlc2VuY2UuCgpgYGAgeyNwdXJnZV9oYXBsb3RpZ3MgLmJhc2h9Cm1pbmltYXAyIC10IDI0IC1heCBtYXAtb250IGNvbnNlbnN1cy5mYXN0YSAuLi9zZ20tdG90YWwuZmFzdHEgfCBzYW10b29scyBzb3J0IC1tIDFHIC1vIGFsaWduZWQuYmFtIC1UIHRtcC5hbGkKcHVyZ2VfaGFwbG90aWdzICBoaXN0ICAtYiBhbGlnbmVkLmJhbSAgLWcgY29uc2Vuc3VzLmZhc3RhICAtdCAyNApgYGAKCiMjIEJMQVNUIGZvciBjb250YW1pbmFudHMKCkJsYXN0IHdhcyBwZXJmb3JtZWQgYW5kIHByb3ZpZGVkIHRvIEJsb2J0b29scyBhcyBpbnB1dC4gQSBsb2NhbAppbnN0YWxsYXRpb24gb2YgYmxhc3QrKyBhbmQgdGhlIG5vbi1yZWR1bmRhbnQgKG5yKSBkYXRhYmFzZSB3ZXJlIHVzZWQgdG8KaWRlbnRpZnkgY29udGlncy4KCmBibGFzdG4gLXF1ZXJ5IGNvbnNlbnN1cy5mYXN0YSAtdGFzayBtZWdhYmxhc3QgLWRiIH4vRGVza3RvcC9nZW5vbWVzL250L250IC1vdXRmbXQgJzYgcXNlcWlkIHN0YXhpZHMgYml0c2NvcmUgc3RkIHNzY2luYW1lcyBzc2tpbmdkb21zIHN0aXRsZScgLWN1bGxpbmdfbGltaXQgMTAgLW51bV90aHJlYWRzIDIzIC1ldmFsdWUgMWUtMyAtb3V0IGNvbnNlbnN1cy5mYXN0YS52cy5udC5jdWw1LjFlMy5tZWdhYmxhc3Qub3V0YAoKTWVnYWJsYXN0IHJlc3VsdHMgYXJlIHNhdmVkIGFzCmBjb25zZW5zdXMuZmFzdGEudnMubnQuY3VsNS4xZTMubWVnYWJsYXN0Lm91dGAsIGFzc2VtYmx5IGFzCmBjb25zZW5zdXMuZmFzdGFgLCBjb3ZlcmFnZSBpbmZvcm1hdGlvbiBhcyBgY29uc2Vuc3VzLmNvdmVyYWdlLnR4dGAsIGFuZApCVVNDTyByZXN1bHRzIGFzIGBmdWxsX3RhYmxlLnRzdmAuIFRoZXNlIGZpbGVzIGFyZSByZWFkeSBmb3IgQmxvYnRvb2xraXQKaW5wdXQuCgojIyBDb250YW1pbmFudCBzZWFyY2hpbmcgd2l0aCBCbG9idG9vbGtpdAoKIyMjIFBpcCBpbnN0YWxsCgpbSW5zdGFsbCBpbnN0cnVjdGlvbnNdKGh0dHBzOi8vYmxvYnRvb2xraXQuZ2Vub21laHVicy5vcmcvaW5zdGFsbC8pCkluc3RhbGxzIHZlcnNpb24gMy4yLjYKCmBgYCB7I2Jsb2JfcGlwIC5iYXNofQpwaXAgaW5zdGFsbCBibG9idG9vbGtpdApwaXAgaW5zdGFsbCBmYXN0anNvbnNjaGVtYQpgYGAKCiMjIyBHZW5lcmF0ZSBjb3ZlcmFnZSBmaWxlCgpgYGAgeyNibG9iX2NvdmVyYWdlIC5iYXNofQptaW5pbWFwMiAtYXggbWFwLW9udCAtdCAyNCBjb25zZW5zdXMuZmFzdGEgc2dtLXRvdGFsLmZhc3RxIHwgc2FtdG9vbHMgc29ydCAtQDE2IC1PIEJBTSAtbyBjb25zZW5zdXMuc29ydGVkLmJhbSAtCmBgYAoKR2VuZXJhdGUgY292ZXJhZ2UgLnR4dApgc2FtdG9vbHMgY292ZXJhZ2UgY29uc2Vuc3VzLnNvcnRlZC5iYW0gPiBjb25zZW5zdXMuY292ZXJhZ2UudHh0YC4KCiMjIyBDcmVhdGUgYmxvYmRpcgoKYmxvYnRvb2xraXQgdjMuMi42CgpEb3dubG9hZCB0YXhkdW1wIGZyb20KW05DQkldKGh0dHBzOi8vZnRwLm5jYmkubmxtLm5paC5nb3YvcHViL3RheG9ub215L25ld190YXhkdW1wL25ld190YXhkdW1wLnRhci5neiksCnVuemlwLCBhbmQgbW92ZWQgYWxsIHRoZSByZXN1bHRpbmcgYC5kbXBgIGZpbGVzIHRvIHRoZSBkaXJlY3RvcnkKYHRheGR1bXBgLgoKQ3JlYXRlIHRoZSBibG9iZGlyIGFuZCBsb2FkIGl0IHdpdGggZmlsZXMuCgpgYGAgeyNibG9iZGlyIC5iYXNofQpibG9idG9vbHMgY3JlYXRlIC0tZmFzdGEgY29uc2Vuc3VzLmZhc3RhIC0tbWV0YSBkYXRhL21pZGdlLnlhbWwgLS10YXhpZCAyNDk0NTEyIC0tdGF4ZHVtcCB0YXhkdW1wLyBkYXRhc2V0cy9taWRnZQojQWRkIEJVU0NPCmJsb2J0b29scyBhZGQgLS1idXNjbyBmdWxsX3RhYmxlLnRzdiBkYXRhc2V0cy9taWRnZQojQWRkIGNvdmVyYWdlCmJsb2J0b29scyBhZGQgLS10ZXh0IGNvbnNlbnN1cy5jb3ZlcmFnZS50eHQgLS10ZXh0LWhlYWRlciAtLXRleHQtY29scyAnI3JuYW1lPWlkZW50aWZpZXIsbWVhbmRlcHRoPW1pZGdlX3JlYWRzX2NvdicgZGF0YXNldHMvbWlkZ2UKI0ZpeCBheGVzCmJsb2J0b29scyBhZGQgLS1rZXkgcGxvdC55PW1pZGdlX3JlYWRzX2NvdiBkYXRhc2V0cy9taWRnZQpgYGAKCiMjIyBWaWV3CgpgYmxvYnRvb2xzIHZpZXcgLS1sb2NhbCAtLWludGVyYWN0aXZlIC0tcG9ydHMgNDAwMC00OTk5IGRhdGFzZXRzL21pZGdlYAoKIyMgRGVjb250YW1pbmF0aW9uCgpXZSBmaWx0ZXIgb24gdGhlIGZvbGxvd2luZyBjcml0ZXJpYSB0byByZW1vdmUgc2hvcnQgYW5kIGxvdyBjb3ZlcmFnZQpjb250aWdzLiBUaGVzZSBmaWx0ZXIgc2V0dGluZ3MgcmVzdWx0IGluIG5vIGxvc3Mgb2YgZnVsbCBsZW5ndGggQlVTQ09zLgoKUmVtb3ZlIGxlbmd0aCBsZXNzIHRoYW4gODAwMCBicC5cClJlbW92ZSBjb3ZlcmFnZSBsZXNzIHRoYW4gMjBYIGFuZCBncmVhdGVyIHRoYW4gMjAwWC5cCkZpbHRlcmVkIGNvbnRpZ3MgYXJlIGV4cG9ydGVkIGluIC5jc3YgZm9ybWF0IGZyb20gYmxvYnRvb2xzCgoyNjEzIE9yaWdpbmFsIENvbnRpZ3NcCjEwMDkgUmVtYWluaW5nIENvbnRpZ3Mgc2F2ZWQgYXMgYDEwMDkuY2xlYW4uY29udGlncy5jc3ZgCgojIyMgRmlsdGVyIGFzc2VtYmx5CgpVc2Ugc2Vxa2l0IHRvIGZpbHRlciB0aGUgY29uc2Vuc3VzIGFzc2VtYmx5IHRvIG9ubHkgdGhlIDEwMDkgY29udGlncwpmcm9tIGRlY29udGFtaW5hdGlvbi4KCmBzZXFraXQgZ3JlcCAtZiAxMDA5LmNvbnRpZ3MuaWQudHh0IC4uL2Jsb2J0b29scy1vdXQvY29uc2Vuc3VzLmZhc3RhIC1vIGNsZWFuLmNvbnNlbnN1cy5mYXN0YWAKCiMjIEZpbmFsIEJVU0NPCgpgYnVzY28gLWkgY2xlYW4uY29uc2Vuc3VzLmZhc3RhIC1vIGJ1c2NvLWNsZWFuY29uc2Vuc3VzIC1tIGdlbm9tZSAtbCB+L0Rlc2t0b3AvZ2Vub21lcy9idXNjb19kb3dubG9hZHMvbGluZWFnZXMvZGlwdGVyYV9vZGIxMCAtYyAyNGAKClJlc3VsdDoKCmBgYCB7I2NsZWFuX2NvbnNlbnN1c19idXNjbyAuYmFzaH0KICAgICoqKioqIFJlc3VsdHM6ICoqKioqCgogICAgQzo4Ny44JVtTOjg1LjIlLEQ6Mi42JV0sRjoxLjklLE06MTAuMyUsbjozMjg1ICAgICAgCiAgICAyODg2ICAgIENvbXBsZXRlIEJVU0NPcyAoQykgICAgICAgICAgICAKICAgIDI4MDAgICAgQ29tcGxldGUgYW5kIHNpbmdsZS1jb3B5IEJVU0NPcyAoUykgICAgCiAgICA4NiAgQ29tcGxldGUgYW5kIGR1cGxpY2F0ZWQgQlVTQ09zIChEKSAgICAgCiAgICA2MyAgRnJhZ21lbnRlZCBCVVNDT3MgKEYpICAgICAgICAgICAgICAKICAgIDMzNiBNaXNzaW5nIEJVU0NPcyAoTSkgICAgICAgICAgICAgCiAgICAzMjg1ICAgIFRvdGFsIEJVU0NPIGdyb3VwcyBzZWFyY2hlZCAKYGBgCgojIyBNZXRoeWxhdGlvbgoKVXNlIHRoZSB1bm1hcHBlZCAuYmFtIGZpbGVzIGdlbmVyYXRlZCBkdXJpbmcgdGhlIGd1cHB5IGJhc2VjYWxsaW5nLiBDYXQKdG9nZXRoZXIgbW9kYmFtcyBmb3IgZWFjaCBmbG93IGNlbGwgZGlyZWN0b3J5Ogpgc2FtdG9vbHMgY2F0IC1vIHNnbS1tb2QudW5tYXBwZWQuYmFtIGJ1ZzEvKi5iYW0gYnVnMi8qLmJhbSBidWczLyouYmFtYAoKIyMjIE1hcCBVbm1hcHBlZCBCYW1zLgoKTWFwLCBjb252ZXJ0IGFuZCBzb3J0IGFsbCBpbiBvbmUgY29tbWFuZC4gVGhlIGAtVCBNbSxNbGAgZmxhZyBjYXJyaWVzCm92ZXIgdGhlIG1vZGlmaWNhdGlvbnMgZnJvbSBiYW0gdG8gZmFzdHEuIEluIG5ld2VyIGJhbXMgdGhlIGZsYWdzIGFyZQpgLVQgTU0sIE1MYC4gVGhlIGAteWAgZmxhZyBjb3BpZXMgaW5wdXQgZmFzdHEgY29tbWFuZHMgdG8gb3V0cHV0Lgpgc2FtdG9vbHMgZmFzdHEgLVQgTW0sTWwgc2dtLW1vZC51bm1hcHBlZC5iYW0gfCBtaW5pbWFwMiAteSAtYXggbWFwLW9udCAuLi9maW5hbF9hc3NlbWJseS9jbGVhbi5jb25zZW5zdXMuZmFzdGEgLSAtdCAyNCB8IHNhbXRvb2xzIHZpZXcgLXUgLSB8IHNhbXRvb2xzIHNvcnQgLUAgMjQgLW8gc2dtLm1vZG1hcHBlZC5iYW07IHNhbXRvb2xzIGluZGV4IHNnbS5tb2RtYXBwZWQuYmFtIC1AIDI0YAoKQ29udmVydCB0byBiZWQgZm9ybWF0LiBUaGUgYC1kYCBmbGFnIGxpbWl0cyBkZXB0aCB0byBzYXZlIG1lbW9yeS4gVGhlCmFnZ3JlZ2F0ZSBmbGFnIGFkZHMgdG9nZXRoZXIgYmFzZXMgb24gZWl0aGVyIHN0cmFuZCBhbmQgY3JlYXRlcyBhbmQKYWdncmVnYXRlLmJlZCBmaWxlLiBUaGUgYC1jcGdgIGZsYWcgbGltaXRzIHRvIGNwZyBzaXRlcy4KYG1vZGJhbTJiZWQgLW0gNW1DIC10IDIzIC1lIC1kIDMwMCAtcCBzZ20ubW9kbWFwcGVkIC0tYWdncmVnYXRlIC0tY3BnIGNsZWFuLmNvbnNlbnN1cy5mYXN0YSBzZ20ubW9kbWFwcGVkLmJhbSA+IHNnbS5tb2RtYXBwZWQuYmVkYAoKQXNzZXNzIGdsb2JhbCBETkEgbWV0aHlsYXRpb24gYXMgYSBwZXJjZW50YWdlIGJ5IGFkZGluZyB1cCBhbGwgY2Fub25pY2FsCihjb2x1bW4gMTIpIGFuZCBtb2RpZmllZCAoY29sdW1uIDEzKSBjeXRvc2luZSBiYXNlIGNhbGxzIGF0IENwRyBzaXRlcy4KRGl2aWRlIHRoZSBtb2RpZmllZCBieSB0aGUgdG90YWwgYW5kIHByaW50LgoKYGF3ayAnJDU+MCB7Y2FuKz0kMTI7IG1vZCs9JDEzfSBFTkR7cHJpbnQgMTAwKihtb2QvKGNhbittb2QpKX0nIHNnbS5tYXBwZWQuYmVkYAoKIyMjIEdsb2JhbCBNZXRoeWxhdGlvbgoKMS4wNzI5NCBpcyB0aGUgZ2xvYmFsIG1ldGh5bGF0aW9uIGluIFNveWJlYW4gR2FsbCBNaWRnZQoKIyMgTW9zZGVwdGggQXNzZW1ibHkgU3RhdHMKCkRlcHRoIHN0YXRpc3RpY3MgZ2VuZXJhdGVkIHdpdGggbW9zZGVwdGgKCiMjIyBJbnN0YWxsCgpEb3dubG9hZGVkIHYwLjMuMyBiaW5hcnkgZnJvbSBbR2l0aHViIHJlbGVhc2UKcGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL2JyZW50cC9tb3NkZXB0aC9yZWxlYXNlcykuCgojIyMgUnVuCgoxLiAgT3ZlcmFsbCBkZXB0aCBzdGF0czoKICAgIGBtb3NkZXB0aCAtbiAtLWZhc3QtbW9kZSAtdCA4IHNnbS5tb2RtYXBwZWQgLi4vbWV0aHlsYXRpb24vc2dtLm1vZG1hcHBlZC5iYW1gCgogICAgYGNocm9tICBsZW5ndGggIGJhc2VzICAgbWVhbiAgICBtaW4gbWF4YAoKICAgIGB0b3RhbCAgMjA2MDM2MTg2ICAgMTMzNjY3NzUwNTQgNjQuODggICAwICAgNDM1ODZgCgoyLiAgRm9yIDUwMCBicCB3aW5kb3dzOgogICAgYG1vc2RlcHRoIC1uIC0tZmFzdC1tb2RlIC0tYnkgNTAwIC10IDggNTAwYnB3aW5kb3cuc2dtLm1vZG1hcHBlZCAuLi9tZXRoeWxhdGlvbi9zZ20ubW9kbWFwcGVkLmJhbWAKCiAgICBgY2hyb20gIGxlbmd0aCAgYmFzZXMgICBtZWFuICAgIG1pbiBtYXhgCgogICAgYHRvdGFsX3JlZ2lvbiAgIDIwNjAzNjE4NiAgIDEzMzY2Nzc1MDU0IDY0Ljg4ICAgMCAgIDQzNTg2YAoKIyBSZXBlYXRzCgojIyBSZXBlYXQgSWRlbnRpZmljYXRpb24KClNpbmNlIGFubm90YXRlZCByZXBlYXRzIGluIGluc2VjdCBnZW5vbWVzIGFyZSBzcGFyc2UsIHJlcGVhdAppZGVudGlmaWNhdGlvbiByZXF1aXJlcyB0d28gc3RhZ2VzLiBGaXJzdCAqZGUgbm92byogcmVwZWF0CmlkZW50aWZpY2F0aW9uIHdhcyBwZXJmb3JtZWQgd2l0aApbUmVwZWF0TW9kbGVyMl0oaHR0cHM6Ly93d3cucmVwZWF0bWFza2VyLm9yZy9SZXBlYXRNb2RlbGVyLykuIFNlY29uZCwKdGhlIGxpYnJhcmllcyBnZW5lcmF0ZWQgd2l0aCBSZXBlYXRNb2RlbGVyMiB3ZXJlIHVzZWQgYXMgaW5wdXQgdG8KW1JlcGVhdE1hc2tlcl0oaHR0cHM6Ly93d3cucmVwZWF0bWFza2VyLm9yZykgdG8gY3JlYXRlIGEgY29tcGxldGUgZ2Vub21lCmFubm90YXRpb24gb2YgcmVwZWF0cyB3aXRoIGV4aXN0aW5nIG5hbWVzIGZvciBjbGFzc2VzLCBmYW1pbGllcywgYW5kCnN1YmZhbWlsaWVzIHdoZXJlIGtub3duIGFuZCBub3ZlbCBJRHMgZm9yIHByZXZpb3VzbHkgdW5rbm93biBmYW1pbGllcy4KClJlcGVhdE1vZGVsZXIgd2FzIHJ1biB0byBpZGVudGlmeSByZXBlYXQgY29udGVudC4gVGFrZXMgYWJvdXQgMjQgaG91cnMKb24gYSAzMDAgTWIgaW5zZWN0IGdlbm9tZS4KCjEuICBGaXJzdCBidWlsZCBkYXRhYmFzZSBmcm9tIGNvbnNlbnN1cyBmYXN0YS5cCiAgICBgL3Vzci9sb2NhbC9SZXBlYXRNb2RlbGVyLTIuMC4yYS9CdWlsZERhdGFiYXNlIC1uYW1lICJzZ20tZ2Vub21lIiAuLi9maW5hbC1hc3NlbWJseS9jb25zZW5zdXMuY2xlYW4uZmFzdGFgCjIuICBSdW4gUmVwZWF0TW9kZWxlcjIuXAogICAgYG5vaHVwIDxSZXBlYXRNb2RlbGVyUGF0aD4vUmVwZWF0TW9kZWxlciAtZGF0YWJhc2Ugc2dtLWdlbm9tZSAtcGEgMTQgLUxUUlN0cnVjdCA+JiBydW4ub3V0ICZgCjMuICBSZXBlYXRNYXNrZXIgd2FzIHRoZW4gcnVuIHRvIGRldGVybWluZSBnZW5vbWljIHJlcGVhdCBjb250ZW50CiAgICBzcGVjaWZ5aW5nIHRoZSBjdXN0b20gbGlicmFyeSBjcmVhdGVkIHdpdGggUmVwZWF0TW9kZWxlci5cCiAgICBgUmVwZWF0TWFza2VyIC1wYSAxNCAtcyAteHNtYWxsIC1saWIgc2dtLWdlbm9tZS1mYW1pbGllcy5mYSAuLi9maW5hbC1hc3NlbWJseS9jb25zZW5zdXMuY2xlYW4uZmFzdGFgCgpDb21wYXJpc29uIHRvIG90aGVyIG1pZGdlIGdlbm9tZXMgd2FzIHBlcmZvcm1lZCB1c2luZyBEZmFtIHYzLjYgYW5kIGJ5CmFiIGluaXRpbyBpZGVudGlmaWNhdGlvbiB1c2luZyB0aGUgc2FtZSBSZXBlYXRNb2RlbGVyMiBwaXBlbGluZSBhcwphYm92ZS4KCiMgR2VNb01hIEdlbmUgQW5ub3RhdGlvbgoKW1dpa2ldKGh0dHA6Ly93d3cuanN0YWNzLmRlL2luZGV4LnBocC9HZU1vTWEpCgojIyMgSW5zdGFsbAoKSW5zdGFsbCBkZXBlbmNlbmN5IGBtbXNlcWA6CgpgY29uZGEgaW5zdGFsbCAtYyBjb25kYS1mb3JnZSAtYyBiaW9jb25kYSBtbXNlcXMyYAoKSW5zdGFsbGVkIHZlcnNpb24gMS45IGJ5IGRvd25sb2FkaW5nIGAuemlwYCBmaWxlIGZyb20KW3dlYnNpdGVdKGh0dHBzOi8vd3d3LmpzdGFjcy5kZS9pbmRleC5waHAvR2VNb01hI1JlcXVpcmVtZW50cykKCiMjIyB2cy4gRHJvc29waGlsYSBtZWxhbm9nYXN0ZXIgKGRtNikgYW5kIFN3ZWRlIG1pZGdlIChbKkNvbnRhcmluaWEgbmFzdHVydGlpKl0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9kYXRhLWh1Yi90YXhvbm9teS8yNjU0NTgpKQoKVHdvIGFubm90YXRpb25zIG9mIGRpcHRlcmEgd2VyZSB1c2VkIGFzIGEgcmVmZXJlbmNlIGJhc2VkIG9uIGNsb3NlCnBoeWxvZ2VuZXRpYyBwcm94aW1pdHkgdG8gdGhlIHNveWJlYW4gZ2FsbCBtaWRnZSBhbmQgYW5ub3RhdGlvbgphdmFpbGFiaWxpdHkuIEZBU1RBIGFuZCBHRkYgZmlsZXMgd2VyZSBkb3dubG9hZGVkIGZyb20gTkNCSSdzIEFzc2VtYmx5CnBhZ2UuICoqTm90ZToqKiBBIGhhcmRtYXNrZWQgdmVyc2lvbiBvZiB0aGUgZ2Vub21lIChyZXBlYXRzIHJlcGxhY2VkCndpdGggTidzKSB3YXMgdXNlZCBmb3IgaW5wdXQgdG8gZWxpbWluYXRlIHRyYW5zcG9zb24gZGVyaXZlZCBnZW5lcy4KCmBqYXZhIC1YbXg1MGcgLWphciBnZW1vbWEtamF2YS9HZU1vTWEtMS45LmphciBDTEkgR2VNb01hUGlwZWxpbmUgdGhyZWFkcz0yMyBvdXRkaXI9Y29tYmluZWRfRG1lbF9zd2VkZW1pZGdlIEdlTW9NYS5TY29yZT1SZUFsaWduIEFubm90YXRpb25GaW5hbGl6ZXIucj1OTyBvPXRydWUgdD1jbGVhbi5jb25zZW5zdXMuaGFyZG1hc2tlZC5mYXN0YSBzPW93biBpPXN3ZWRlX2dhbGxfbWlkZ2UgYT1HQ0ZfMDA5MTc2NTI1LjJfQUFGQ19DTmFzXzEuMV9nZW5vbWljLmdmZiBnPUdDRl8wMDkxNzY1MjUuMl9BQUZDX0NOYXNfMS4xX2dlbm9taWMuZm5hIHM9b3duIGk9RF9tZWwgZz1HQ0FfMDAwMDAxMjE1LjRfUmVsZWFzZV82X3BsdXNfSVNPMV9NVF9nZW5vbWljLmZuYSBhPUdDQV8wMDAwMDEyMTUuNF9SZWxlYXNlXzZfcGx1c19JU08xX01UX2dlbm9taWMuZ2ZmYAoKQlVTQ08gd2FzIHVzZWQgdG8gYXNzZXNzIGNvbXBsZXRlbmVzcyBpbiBwcm90ZWluIG1vZGU6CgpgYnVzY28gLWkgcHJlZGljdGVkX3Byb3RlaW5zLmZhc3RhIC1vIGJ1c2NvIC1tIHByb3RlaW4gLWwgZGlwdGVyYSAtYyAyNGAKCmBgYCB7I3NnbV92c19EbWVsX3N3ZWRlbWlkZ2VfcHJvdF9idXNjbyAuYmFzaH0KICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICB8UmVzdWx0cyBmcm9tIGRhdGFzZXQgZGlwdGVyYV9vZGIxMCAgICAgICAgICAgICAgIHwKICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICB8Qzo4OS45JVtTOjg1LjUlLEQ6NC40JV0sRjowLjclLE06OS40JSxuOjMyODUgICAgIHwKICAgIHwyOTUyICAgQ29tcGxldGUgQlVTQ09zIChDKSAgICAgICAgICAgICAgICAgICAgICAgfAogICAgfDI4MDggICBDb21wbGV0ZSBhbmQgc2luZ2xlLWNvcHkgQlVTQ09zIChTKSAgICAgICB8CiAgICB8MTQ0ICAgIENvbXBsZXRlIGFuZCBkdXBsaWNhdGVkIEJVU0NPcyAoRCkgICAgICAgIHwKICAgIHwyNCBGcmFnbWVudGVkIEJVU0NPcyAoRikgICAgICAgICAgICAgICAgICAgICB8CiAgICB8MzA5ICAgIE1pc3NpbmcgQlVTQ09zIChNKSAgICAgICAgICAgICAgICAgICAgICAgIHwKICAgIHwzMjg1ICAgVG90YWwgQlVTQ08gZ3JvdXBzIHNlYXJjaGVkICAgICAgICAgICAgICAgfAogICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KMjAyMy0wMS0wNSAxODozOTowOSBJTkZPOiAgIEJVU0NPIGFuYWx5c2lzIGRvbmUuIFRvdGFsIHJ1bm5pbmcgdGltZTogMTEwIHNlY29uZHMKMjAyMy0wMS0wNSAxODozOTowOSBJTkZPOiAgIFJlc3VsdHMgd3JpdHRlbiBpbiAvaG9tZS9jZmF1bGsvRGVza3RvcC9vbnQtc2VxdWVuY2luZ19ydW5zL3NveWJlYW5fZ2FsbF9taWRnZS9zZ20tYW5hbHlzaXMvZ2Vtb21hLW91dC9jb21iaW5lZF9EbWVsX3N3ZWRlbWlkZ2UvYnVzY28tY29tYmluZWQtcHJvdGVpbgpgYGAKCiMgTWl0b2Nob25kcmlhbCBnZW5vbWUKClRvdGFsIHJlYWRzIHdlcmUgZmlyc3QgYmxhc3RlZCBieSBtdGJsYXN0ZXIKKFtodHRwczovL2dpdGh1Yi5jb20vbmlkYWZyYTkyL3NxdWlycmVsLXByb2plY3QvYmxvYi9tYXN0ZXIvbXRibGFzdGVyLnB5KV0oaHR0cHM6Ly9naXRodWIuY29tL25pZGFmcmE5Mi9zcXVpcnJlbC1wcm9qZWN0L2Jsb2IvbWFzdGVyL210Ymxhc3Rlci5weSkpCnVzaW5nIHRoZSBPcnNlb2xpYSBvcnl6YWUgbWl0b2dlbm9tZSAoS004ODgxODMpIHRvIHNlbGVjdCBmb3IgcmVhZHMgd2l0aApoaWdoIGlkZW50aXR5IHRvIGEgZ2FsbCBtaWRnZSBtaXRvY2hvbmRyaWEgc2VxdWVuY2UuIFdlIGJsYXN0ZWQgYWdhaW5zdApyZWFkcyBvbmx5IGZyb20gdGhlIFIxMCBmbG93Y2VsbCB0byBlbnN1cmUgaGlnaGVyIGFjY3VyYWN5LiBOZXh0LApyZXN1bHRpbmcgcmVhZHMgd2VyZSBmaWx0ZXJlZCBieSBuYW5vZmlsdAooW2h0dHBzOi8vZ2l0aHViLmNvbS93ZGVjb3N0ZXIvbmFub2ZpbHQpXShodHRwczovL2dpdGh1Yi5jb20vd2RlY29zdGVyL25hbm9maWx0KSkKdG8ga2VlcCBvbmx5IHJlYWRzIGFib3ZlIDE1IGticCBpbiBsZW5ndGggYW5kIGF2ZXJhZ2UgUS1zY29yZSBhYm92ZSAzMC4KRmluYWxseSwgZmx5ZSB3YXMgdXNlZCB0byBwZXJmb3JtIG1pdG9nZW5vbWUgYXNzZW1ibHkgKEtvbG1vZ29yb3YgZXQgYWwuCjIwMjApLiBBIHNpbmdsZSBjaXJjdWxhciBjb250aWcgd2FzIHJlY292ZXJlZCB3aXRoIDc4NVggY292ZXJhZ2UuIFRoZQphc3NlbWJseSB3YXMgcG9saXNoZWQgdXNpbmcgZm91ciByb3VuZHMgb2YgcmFjb24KKDxodHRwczovL2dpdGh1Yi5jb20vbGJjYi1zY2kvcmFjb24+KSBmb2xsb3dlZCBieSBtZWRha2Egd2l0aCB0aGUgc2FtZQpwYXJhbWV0ZXJzIGFzIHRoZSBudWNsZWFyIGFzc2VtYmx5LgoKMS4gIEJsYXN0IGFnYWluc3QgcmVhZHMgZnJvbSB0aGUgUjEwIGZsb3cgY2VsbDoKICAgIGBtdGJsYXN0ZXIucHkgc2dtLWJ1ZzMuZmFzdHEgT3JzZW9saWFfb3J5emFlLUtNODg4MTgzLjEuZmFzdGFgCgoyLiAgRmlsdGVyIHJlYWRzIGhpZ2hlciB0aGFuIDE1IGtiIHdpdGggcXVhbGl0eSBcPlEzMC4KICAgIGBuYW5vZmlsdCAtbCAxNTAwMCAtcSAzMCByZWFkc193X2hpdHMuZmFzdHEgPiByZWFkc193X2hpdHMxNWtxMzAuZmFzdHFgCgozLiAgUnVuIGZseWUgdG8gYXNzZW1ibGUgZ2Vub21lIHVzaW5nIHRoZSBhc20gcGFyYW1ldGVyLgogICAgYGZseWUgLS1uYW5vLWhxIHJlYWRzX3dfaGl0czE1a3EzMC5mYXN0cSAtLW91dC1kaXIgZmx5ZS1taXRvZ2Vub21lLWhpZ2hhc20gLS1nZW5vbWUtc2l6ZSAxNmsgLS10aHJlYWRzIDI0IC0tYXNtIDI1NmAKCjQuICBSdW4gNCByb3VuZHMgb2YgUmFjb24gcG9saXNoaW5nLAogICAgYG1pbmltYXAyIC1heCBtYXAtb250IGFzc2VtYmx5LmZhc3RhIC4uL3JlYWRzX3dfaGl0czE1a3EzMC5mYXN0cSA+IGFzc2VtYmx5LnNhbWAKCiAgICBgcmFjb24gLXQgMjQgLi4vcmVhZHNfd19oaXRzMTVrcTMwLmZhc3RxIGFzc2VtYmx5LnNhbSBhc3NlbWJseS5mYXN0YSA+IGFzc2VtYmx5LnJhY29uMS5mYXN0YWAKCjUuICBGaW5hbCBwb2xpc2ggd2l0aCBtZWRha2EuCiAgICBgbWVkYWthX2NvbnNlbnN1cyAtaSAuLi9yZWFkc193X2hpdHMxNWtxMzAuZmFzdHEgLWQgYXNzZW1ibHkucmFjb240LmZhc3RhIC1vIG1lZGFrYS1yZXN1bHRzLyAtdCAyMyAtbSByMTA0MV9lODJfNDAwYnBzX3N1cF9nNjE1YAoKNi4gIFNhdmUgYGNvbnNlbnN1cy5mYXN0YWAgYXMgYHNnbV9taXRvZ2Vub21lX2NvbnNlbnN1cy5mYXN0YWAKCiMgV29sYmFjaGlhIGRldGVjdGlvbgoKQ29sbGVjdCBwYW5lbCBvZiA5IGdlbm9tZXMgaW50byBhIHNpbmdsZSBmYXN0YSBmaWxlIGFuZCBtYXRjaCBhZ2FpbnN0CnRoZSB0b3RhbCBTR00gcmVhZCBzZXQuIElkZW50aWZ5IGFueSByZXN1bHRpbmcgbWF0Y2hlcyBhZ2FpbnN0IHRoZQprcmFja2VuMiBzdGFuZGFyZCBkYXRhYmFzZS4gVGhlIGdlbm9tZXMgd2VyZSBkb3dubG9hZGVkIGZyb20gTkNCSSBhbmQKYXJlIGxpc3RlZCBpbiB0aGUgbWFudXNjcmlwdC4KCjEuICBNYXRjaCByZWFkcyB0byBXb2xiYWNoaWEgZ2Vub21lcy4KICAgIGBtaW5pbWFwMiAtYXggbWFwLW9udCB3b2xiYWNoaWEtcGFuZWwvd29sYmFjaGlhLXBhbmVsLmZuYSAuLi9zZ20tdG90YWwuZmFzdHEuZ3ogLXQgMjMgPiB3b2xiYWNoaWEtcGFuZWwudnMuc2dtLXRvdGFsLnNhbWAKCjIuICBTb3J0IGFuZCBjb252ZXJ0IHRvIGJhbSBmb3JtYXQuCiAgICBgc2FtdG9vbHMgc29ydCAtQDI0IC1PIEJBTSAtbyBzZ20tdG90YWwudnMud29sYmFjaGlhLXBhbmVsLnNvcnRlZC5iYW0gd29sYmFjaGlhLXBhbmVsLnZzLnNnbS10b3RhbC5zYW1gCgozLiAgRmlsdGVyIGFsaWdubWVudCBmaWxlIGZvciBvbmx5IG1hcHBlZCByZWFkcy4KICAgIGBzYW10b29scyBmYXN0YSAtRiA0IHNnbS10b3RhbC52cy53b2xiYWNoaWEtcGFuZWwuc29ydGVkLmJhbSA+IHNnbS10b3RhbC52cy53b2xiYWNoaWEtcGFuZWwuc29ydGVkLmhpdHMuYmFtYAoKNC4gIFJlbW92ZSBkdXBsaWNhdGVzLgogICAgYGF3ayAnL14+L3tmPSFkWyQxXTtkWyQxXT0xfWYnIHNnbS10b3RhbC52cy53b2xiYWNoaWEtcGFuZWwuc29ydGVkLmhpdHMuZmFzdGEgPiBzZ20tdG90YWwudnMud29sYmFjaGlhLXBhbmVsLnNvcnRlZC5ub2R1cHMuZmFzdGFgCgo1LiAgUnVuIHRocm91Z2ggS3Jha2VuMi4KICAgIGBrcmFrZW4yIC0tZGIgL21udC9kYXRhMTZUYi9rcmFrZW5fZGIvazJfc3RhbmRhcmRfMTZnYl8yMDIyMDYwNyAtLXRocmVhZHMgMjMgLS11c2UtbmFtZXMgLS1yZXBvcnQgc2dtLnZzLndvbGJhY2hpYS1wYW5lbC5yZXBvcnQudHh0IC0tb3V0cHV0IHNnbS52cy53b2xiYWNoaWEtcGFuZWwudHh0IHNnbS10b3RhbC52cy53b2xiYWNoaWEtcGFuZWwuc29ydGVkLm5vZHVwcy5mYXN0YWAKCjYuICBSdW4gUGF2aWFuIGZyb20gaW5zaWRlIFIgdG8gZ2VuZXJhdGUgZ3JhcGhpY3MuCiAgICBgcGF2aWFuOjpydW5BcHAocG9ydD01MDAwKWAKCiMgTkNCSSBTdWJtaXNzaW9uCgpbTGlua10oaHR0cHM6Ly9zdWJtaXQubmNiaS5ubG0ubmloLmdvdi9zdWJzL2dlbm9tZS8pCgpVc2VkIGNvbW1hbmQgbGluZSB0byB1cGxvYWQgZm9sZGVyOgoKMS4gIE5hdmlnYXRlIHRvIHRoZSBzb3VyY2UgZm9sZGVyIHdoZXJlIHRoZSBmaWxlcyBmb3Igc3VibWlzc2lvbiBhcmU7CjIuICBFc3RhYmxpc2ggYW4gRlRQIGNvbm5lY3Rpb24gdXNpbmcgdGhlIGNyZWRlbnRpYWxzIGJlbG93OiBBZGRyZXNzOgogICAgYGZ0cC1wcml2YXRlLm5jYmkubmxtLm5paC5nb3ZgIFVzZXJuYW1lOiBgc3ViZnRwYCBQYXNzd29yZDoKICAgIGA8c2VudCB2aWEgZW1haWw+YAozLiAgTmF2aWdhdGUgdG8geW91ciBhY2NvdW50IGZvbGRlcjogRnJvbSB0aGUgY29tbWFuZCBsaW5lIHVzZSB0aGUgJ2NkJwogICAgY29tbWFuZDogYGNkIHVwbG9hZHMvPGZvbGRlcl9zZW50X2J5X2VtYWlsPmAKCldoZW4gdXNpbmcgYSBHVUkgRlRQIGNsaWVudCAoZWc6IEZpbGV6aWxsYSwgTmNGVFAsIEN5YmVyZHVjaywgZXRjLiksCmFmdGVyIHlvdSd2ZSBjb25uZWN0ZWQgdG8gdGhlIEZUUCBzZXJ2ZXIsIHBhc3RlIHlvdXIgYWNjb3VudCBmb2xkZXIKKGB1cGxvYWRzLzxmb2xkZXJfc2VudF9ieV9lbWFpbD5gKSBpbnRvIHRoZSAiUmVtb3RlIFNpdGUiIG9yICJSZW1vdGUKRGlyZWN0b3J5IiBib3ggb24gdGhlIGludGVyZmFjZSBhbmQgcHJlc3MgIkVudGVyIi4KClRoZW4geW91IHdpbGwgYmUgYWJsZSB0byBjcmVhdGUgdGhlIGRhdGEgc3ViLWRpcmVjdG9yeSBmb3IgeW91cgpzdWJtaXNzaW9uLiBVbnRpbCB5b3UgZG8gdGhpcywgeW91IHdpbGwgc2VlIGEgbWVzc2FnZSBzdGF0aW5nICI1NTAgLzoKUGVybWlzc2lvbiBkZW5pZWQiIG9yICJGYWlsZWQgdG8gcmVhZCB0aGUgZGlyZWN0b3J5IGxpc3RpbmciLiBXZSBwcmV2ZW50CmRpcmVjdG9yeSBsaXN0aW5nIGluIHRoZSBkZWZhdWx0IHNpZ24gaW4gZm9sZGVyIGZvciBzZWN1cml0eSByZWFzb25zLgoKQ3JlYXRlIGEgc3ViZm9sZGVyIChyZXF1aXJlZCEpIHdpdGggYSBtZWFuaW5nZnVsIG5hbWUuIE5hdmlnYXRlIHRvIHRoZQp0YXJnZXQgZm9sZGVyIHlvdSBqdXN0IGNyZWF0ZWQuIENvcHkgeW91ciBmaWxlcyBpbnRvIHRoZSB0YXJnZXQgZm9sZGVyOgpgPG1pdG9nZW5vbWU+LmZhLmd6IDxudWNsZWFyX2dlbm9tZT4uZmEuZ3pgCgpQcmVzcyAiTmV3IHN1Ym1pc3Npb24iIGluIGJyb3dzZXIuCg==