library(tidyverse)

Soybean Gall Midge.

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.

Contaminant searching with Blobtoolkit

Pip install

Install instructions Installs version 3.2.6

pip install blobtoolkit
pip install fastjsonschema

Generate coverage file

minimap2 -ax map-ont -t 24 consensus.fasta sgm-total.fastq | samtools sort -@16 -O BAM -o consensus.sorted.bam -

Generate coverage .txt samtools coverage consensus.sorted.bam > consensus.coverage.txt.

Create blobdir

blobtoolkit v3.2.6

Download taxdump from NCBI, unzip, and moved all the resulting .dmp files to the directory taxdump.

Create the blobdir and load it with files.

blobtools create --fasta consensus.fasta --meta data/midge.yaml --taxid 2494512 --taxdump taxdump/ datasets/midge
#Add BUSCO
blobtools add --busco full_table.tsv datasets/midge
#Add coverage
blobtools add --text consensus.coverage.txt --text-header --text-cols '#rname=identifier,meandepth=midge_reads_cov' datasets/midge
#Fix axes
blobtools add --key plot.y=midge_reads_cov datasets/midge

View

blobtools view --local --interactive --ports 4000-4999 datasets/midge

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

Install

Downloaded v0.3.3 binary from Github release page.

Run

  1. 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

  2. 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.

  1. First build database from consensus fasta.
    /usr/local/RepeatModeler-2.0.2a/BuildDatabase -name "sgm-genome" ../final-assembly/consensus.clean.fasta
  2. Run RepeatModeler2.
    nohup <RepeatModelerPath>/RepeatModeler -database sgm-genome -pa 14 -LTRStruct >& run.out &
  3. 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.

  1. Blast against reads from the R10 flow cell: mtblaster.py sgm-bug3.fastq Orseolia_oryzae-KM888183.1.fasta

  2. Filter reads higher than 15 kb with quality >Q30. nanofilt -l 15000 -q 30 reads_w_hits.fastq > reads_w_hits15kq30.fastq

  3. 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

  4. 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

  5. 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

  6. 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.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. Run Pavian from inside R to generate graphics. pavian::runApp(port=5000)

NCBI Submission

Link

Used command line to upload folder:

  1. Navigate to the source folder where the files for submission are;
  2. Establish an FTP connection using the credentials below: Address: ftp-private.ncbi.nlm.nih.gov Username: subftp Password: <sent via email>
  3. 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==