Lineage aware variant correction

Introduction

This vignette intends to present a ‘lineage aware’ variant calling pipeline that uses GATK4 in conjunction with a custom script heranca

Heranca

High false positive rates in SNP and Indel predictions from GATK4 make using the output directly difficult.

This vignette focuses on a heranca, a custom script that seeks to flag likely low-quality predictions originating from homopolymer / polynucleotide runs or those the mutations that break the infinite site assumption, occurring in at least three unrelated strains. Heranca relies on a tab-delimited file to specify the variant names, vcf file locations, and lineage of strains.

Heranca is described more deeply here

Notes on additional tools

Requirements

  • Heranca assumes the .VCF files are generated by GATK4 - potential issues may arise if other versions or other tools are used.
  • Heranca looks up homopolymer / polynucleotide runs within the reference genome that the reads were originally aligned to, as such the reference genome fasta file is also required.
  • Heranca requires the pairwise2 package from biopython, please ensure that biopython is installed.

GATK4

  • Ensure that GATK4 is using the correct ploidy for your organism (eg --sampleploidy). The Gresham lab frequently uses haploid yeast which will result in lower GATK4 performance if used with default (diploid) settings.
  • A comparison of GATK4 variant calling and Nanopore long reads suggests the VariantFiltration -filter-name "MQ_filter" -filter "MQ < 40.0" is too strict and should be relaxed to 30.
  • These changes have been implemented in a modified nextflow script for NYU HPC Greene users here

Demonstration

git clone https://github.com/pspealman/heranca.git
cd heranca
python heranca.py

Using the defaults the demo will filter each of the VCFs. Edited VCFs and Filter summary logs are produced for each VCF and saved in the output_path if defined or the current working directory. Some details are printed to screen as excerpted below:

Edited vcf file saved to:  /scratch/ps163/Anc_heranca.vcf
Log file saved to:  /scratch/ps163/Anc_heranca.log
MQ_FILTER       1
PASS    6
QH_exceeds_polyn        8
SOR_FILTER      1

Edited vcf file saved to:  /scratch/ps163/S1_heranca.vcf
Log file saved to:  /scratch/ps163/S1_heranca.log
MQ_FILTER       1
PASS    5
QH_exceeds_polyn        16
QH_fails_ISA    2
QH_indel_fails_ISA      4
SOR_FILTER      3

Quick start guide

Step 1. Set up metadata file

Heranca uses a tab delimited metadata file to coordinate information. This metadata file consists of three columns. 1. Name column for the strain/sample must be unique in the file 2. File_path column with an absolute path to the VCF file 3. Lineage column containing the comma-delimited Names of strains it is descended from.

Note: a strain with it’s own name in it’s Lineage field will be treated as an ancestor, that is to say it will not be descended from any other strains.

Example of a metadata file

The figure below shows a schematic relating 7 strains - one ancestor (Anc), five direct descendants (S1-S5), and one strain descended from previous strain (S6).

To represent these relationships in the metadata file we first specify names, locations, and then lineages. For the ancestor (Anc) we put it’s own name in the lineage field, denoting it’s ancestral status. Because all other strains are descended from the ancestor (Anc) we also populate those fields with that name as well. Finally, because S6 is also descended from S5 we include it’s name in the lineage field as well, using a comma as a separator.

Anc   demo/Anc.vcf  Anc
S1    demo/S1.vcf   Anc
S2    demo/S2.vcf   Anc
S3    demo/S3.vcf   Anc
S4    demo/S4.vcf   Anc
S5    demo/S5.vcf   Anc
S6    demo/S6.vcf   Anc, S5

Step 2. Run using your own data

Standard format will result in VCFs listed in the <input_metadata_file.tab> being corrected and output to the directory along with summary log files.

python heranca.py \
  -i <input_metadata_file.tab> \
  -fa <reference_genome_fasta_file> \
  -o <output_path>
Worked out example:

input_metadata_file: Project_Carolino_new/combine_vcf_metadata_indels.txt

DGY1657   Project_Carolino_new/HG7CVAFXX_mini02_40_filtered_indels_2.vcf   DGY1657
DGY1726   Project_Carolino_new/HKFYTBGX2_mini02_partii_61_filtered_indels_2.vcf    DGY1657

reference_genome_fasta_file: Saccharomyces_cerevisiae.R64-1-1.dna.toplevel.fa output_path:

mkdir heranca
python heranca.py \
  -i Project_Carolino_new/combine_vcf_metadata_indels.txt
  -fa Ensembl/Saccharomyces_cerevisiae.R64-1-1.dna.toplevel.fa \
  -o heranca/example_

This will produce two edited VCF files and two summary log files:

heranca/example_HG7CVAFXX_mini02_40_filtered_indels_2_heranca.vcf
heranca/example_HG7CVAFXX_mini02_40_filtered_indels_2_heranca.log
heranca/example_HKFYTBGX2_mini02_partii_61_filtered_indels_2_heranca.vcf
heranca/example_HKFYTBGX2_mini02_partii_61_filtered_indels_2_heranca.log

Step 3. Evaluating the output

Output will be a modified VCF file inluding all variants present in the original, but with those candidates that failed the polynucelotide or ISA criteria flagged as described above.

Modified VCF files
  • Original: In the original VCF file four variants are marked with PASS and would be evaluated by downstream analysis
XIII    680936  .   T   C   1282.06 PASS    AC=2;AF=1.00;AN=2;DP=30;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=34.37;SOR=1.143    GT:AD:DP:GQ:PL  1/1:0,30:30:90:1296,90,0
XIII    680940  .   C   T   1226.06 PASS    AC=2;AF=1.00;AN=2;DP=29;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=28.70;SOR=1.179    GT:AD:DP:GQ:PL  1/1:0,28:28:84:1240,84,0
XIII    809198  .   A   G   2052.06 PASS    AC=2;AF=1.00;AN=2;DP=57;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=32.78;SOR=0.846    GT:AD:DP:GQ:PL  1/1:0,54:54:99:2066,162,0
XIII    908174  .   G   T   567.64  PASS    AC=1;AF=0.500;AN=2;BaseQRankSum=0.372;DP=57;ExcessHet=3.0103;FS=0.000;MLEAC=1;MLEAF=0.500;MQ=55.71;MQRankSum=-2.084;QD=11.58;ReadPosRankSum=-3.264;SOR=0.681    GT:AD:DP:GQ:PL  0/1:32,17:49:99:575,0,1292
  • Output (using default remove_filtered = True): Heranca finds two of theses variants fail and omits these records
XIII    680936  .   T   C   1282.06 PASS    AC=2;AF=1.00;AN=2;DP=30;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=34.37;SOR=1.143    GT:AD:DP:GQ:PL  1/1:0,30:30:90:1296,90,0
XIII    809198  .   A   G   2052.06 PASS    AC=2;AF=1.00;AN=2;DP=57;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=32.78;SOR=0.846    GT:AD:DP:GQ:PL  1/1:0,54:54:99:2066,162,0
  • Output (using remove_filtered = False): Setting Heranca to include filtered reads, we find rows 2 (XIII:680940) and 4 (XIII:908174)
XIII    680936  .   T   C   1282.06 PASS    AC=2;AF=1.00;AN=2;DP=30;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=34.37;SOR=1.143    GT:AD:DP:GQ:PL  1/1:0,30:30:90:1296,90,0
XIII    680940  .   C   T   1226.06 QH_Filter_exceeds_polyn_5   AC=2;AF=1.00;AN=2;DP=29;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=28.70;SOR=1.179    GT:AD:DP:GQ:PL  1/1:0,28:28:84:1240,84,0
XIII    809198  .   A   G   2052.06 PASS    AC=2;AF=1.00;AN=2;DP=57;ExcessHet=3.0103;FS=0.000;MLEAC=2;MLEAF=1.00;MQ=60.00;QD=32.78;SOR=0.846    GT:AD:DP:GQ:PL  1/1:0,54:54:99:2066,162,0
XIII    908174  .   G   T   567.64  QH_fails_ISA_5  AC=1;AF=0.500;AN=2;BaseQRankSum=0.372;DP=57;ExcessHet=3.0103;FS=0.000;MLEAC=1;MLEAF=0.500;MQ=55.71;MQRankSum=-2.084;QD=11.58;ReadPosRankSum=-3.264;SOR=0.681    GT:AD:DP:GQ:PL  0/1:32,17:49:99:575,0,1292
Summary log files

Heranca will also generate summary log files of the counts of variant filter status categories. A complete description of the ‘QH’ filters is available here

  • Example of Ancestral log file:
MQ_FILTER   4
PASS    55
QH_exceeds_polyn    23
QH_low_genotype_relative_likelihood 6
SOR_FILTER  4

Here we see variants filtered by GATK4 include 4 filtered for MQ, and SOR criteria. 23 are filtered by heranca for exceeding the polyN criteria and 6 fail to meet the relative genotype likelihood criteria. Finally, 55 variants meet all the criteria. Notably, no variants are filtered for violating the ISA criteria as this is a ancestral strain.

  • Example of Descendant log file:
PASS    27
QH_exceeds_polyn    22
QH_indel_fails_ISA  15
QH_low_genotype_relative_likelihood 1

Here we see that no variants were filtered by GATK4. 22 are filtered by heranca for exceeding the polyN criteria and 1 fails to meet the relative genotype likelihood criteria. 15 variants are filtered for violating ISA. Only, 27 variants meet all the criteria.

LS0tDQp0aXRsZTogImhlcmFuY2EiDQphdXRob3I6ICJQaWV0ZXIgU3BlYWxtYW4iDQpkYXRlOiAiMjAyMi8wOC8xNCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgTGluZWFnZSBhd2FyZSB2YXJpYW50IGNvcnJlY3Rpb24NCg0KIyMgSW50cm9kdWN0aW9uDQpUaGlzIHZpZ25ldHRlIGludGVuZHMgdG8gcHJlc2VudCBhICdsaW5lYWdlIGF3YXJlJyB2YXJpYW50IGNhbGxpbmcgcGlwZWxpbmUgdGhhdCB1c2VzIEdBVEs0IGluIGNvbmp1bmN0aW9uIHdpdGggYSBjdXN0b20gc2NyaXB0IF9oZXJhbmNhXyAgDQoNCiMjIyBIZXJhbmNhIA0KSGlnaCBmYWxzZSBwb3NpdGl2ZSByYXRlcyBpbiBTTlAgYW5kIEluZGVsIHByZWRpY3Rpb25zIGZyb20gR0FUSzQgbWFrZSB1c2luZyB0aGUgb3V0cHV0IGRpcmVjdGx5IGRpZmZpY3VsdC4NCg0KVGhpcyB2aWduZXR0ZSBmb2N1c2VzIG9uIGEgaGVyYW5jYSwgYSBjdXN0b20gc2NyaXB0IHRoYXQgc2Vla3MgdG8gZmxhZyBsaWtlbHkgbG93LXF1YWxpdHkgcHJlZGljdGlvbnMgb3JpZ2luYXRpbmcgZnJvbSBob21vcG9seW1lciAvIHBvbHludWNsZW90aWRlIHJ1bnMgb3IgdGhvc2UgdGhlIG11dGF0aW9ucyB0aGF0IGJyZWFrIHRoZSBpbmZpbml0ZSBzaXRlIGFzc3VtcHRpb24sIG9jY3VycmluZyBpbiBhdCBsZWFzdCB0aHJlZSB1bnJlbGF0ZWQgc3RyYWlucy4gSGVyYW5jYSByZWxpZXMgb24gYSB0YWItZGVsaW1pdGVkIGZpbGUgdG8gc3BlY2lmeSB0aGUgdmFyaWFudCBuYW1lcywgdmNmIGZpbGUgbG9jYXRpb25zLCBhbmQgbGluZWFnZSBvZiBzdHJhaW5zLiAgDQoNCkhlcmFuY2EgaXMgZGVzY3JpYmVkIG1vcmUgZGVlcGx5IFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vcHNwZWFsbWFuL2hlcmFuY2EpDQoNCiMjIyBOb3RlcyBvbiBhZGRpdGlvbmFsIHRvb2xzDQojIyMjIFJlcXVpcmVtZW50cw0KKiBIZXJhbmNhIGFzc3VtZXMgdGhlIC5WQ0YgZmlsZXMgYXJlIGdlbmVyYXRlZCBieSBHQVRLNCAtIHBvdGVudGlhbCBpc3N1ZXMgbWF5IGFyaXNlIGlmIG90aGVyIHZlcnNpb25zIG9yIG90aGVyIHRvb2xzIGFyZSB1c2VkLg0KKiBIZXJhbmNhIGxvb2tzIHVwIGhvbW9wb2x5bWVyIC8gcG9seW51Y2xlb3RpZGUgcnVucyB3aXRoaW4gdGhlIHJlZmVyZW5jZSBnZW5vbWUgdGhhdCB0aGUgcmVhZHMgd2VyZSBvcmlnaW5hbGx5IGFsaWduZWQgdG8sIGFzIHN1Y2ggdGhlIHJlZmVyZW5jZSBnZW5vbWUgZmFzdGEgZmlsZSBpcyBhbHNvIHJlcXVpcmVkLg0KKiBIZXJhbmNhIHJlcXVpcmVzIHRoZSBwYWlyd2lzZTIgcGFja2FnZSBmcm9tIGJpb3B5dGhvbiwgcGxlYXNlIGVuc3VyZSB0aGF0IGJpb3B5dGhvbiBpcyBpbnN0YWxsZWQuDQoNCiMjIyMgR0FUSzQNCiogRW5zdXJlIHRoYXQgR0FUSzQgaXMgdXNpbmcgdGhlIGNvcnJlY3QgcGxvaWR5IGZvciB5b3VyIG9yZ2FuaXNtIChlZyBgYGAtLXNhbXBsZXBsb2lkeWBgYCkuIFRoZSBHcmVzaGFtIGxhYiBmcmVxdWVudGx5IHVzZXMgaGFwbG9pZCB5ZWFzdCB3aGljaCB3aWxsIHJlc3VsdCBpbiBsb3dlciBHQVRLNCBwZXJmb3JtYW5jZSBpZiB1c2VkIHdpdGggZGVmYXVsdCAoZGlwbG9pZCkgc2V0dGluZ3MuDQoqIEEgY29tcGFyaXNvbiBvZiBHQVRLNCB2YXJpYW50IGNhbGxpbmcgYW5kIE5hbm9wb3JlIGxvbmcgcmVhZHMgc3VnZ2VzdHMgdGhlIGBgYFZhcmlhbnRGaWx0cmF0aW9uIC1maWx0ZXItbmFtZSAiTVFfZmlsdGVyIiAtZmlsdGVyICJNUSA8IDQwLjAiYGBgIGlzIHRvbyBzdHJpY3QgYW5kIHNob3VsZCBiZSByZWxheGVkIHRvIDMwLg0KKiBUaGVzZSBjaGFuZ2VzIGhhdmUgYmVlbiBpbXBsZW1lbnRlZCBpbiBhIG1vZGlmaWVkIG5leHRmbG93IHNjcmlwdCBmb3IgTllVIEhQQyBHcmVlbmUgdXNlcnMgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9wc3BlYWxtYW4vaGVyYW5jYS9ibG9iL21haW4vUkVBRE1FLm1kI25vdGUtZm9yLW55dS1ncmVlbmUtaHBjLXVzZXJzKQ0KDQojIyMgRGVtb25zdHJhdGlvbiANCmBgYA0KZ2l0IGNsb25lIGh0dHBzOi8vZ2l0aHViLmNvbS9wc3BlYWxtYW4vaGVyYW5jYS5naXQNCmNkIGhlcmFuY2ENCnB5dGhvbiBoZXJhbmNhLnB5DQpgYGANCg0KVXNpbmcgdGhlIGRlZmF1bHRzIHRoZSBkZW1vIHdpbGwgZmlsdGVyIGVhY2ggb2YgdGhlIFZDRnMuIEVkaXRlZCBWQ0ZzIGFuZCBGaWx0ZXIgc3VtbWFyeSBsb2dzIGFyZSBwcm9kdWNlZCBmb3IgZWFjaCBWQ0YgYW5kIHNhdmVkIGluIHRoZSBvdXRwdXRfcGF0aCBpZiBkZWZpbmVkIG9yIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LiBTb21lIGRldGFpbHMgYXJlIHByaW50ZWQgdG8gc2NyZWVuIGFzIGV4Y2VycHRlZCBiZWxvdzoNCg0KYGBgDQpFZGl0ZWQgdmNmIGZpbGUgc2F2ZWQgdG86ICAvc2NyYXRjaC9wczE2My9BbmNfaGVyYW5jYS52Y2YNCkxvZyBmaWxlIHNhdmVkIHRvOiAgL3NjcmF0Y2gvcHMxNjMvQW5jX2hlcmFuY2EubG9nDQpNUV9GSUxURVIgICAgICAgMQ0KUEFTUyAgICA2DQpRSF9leGNlZWRzX3BvbHluICAgICAgICA4DQpTT1JfRklMVEVSICAgICAgMQ0KDQpFZGl0ZWQgdmNmIGZpbGUgc2F2ZWQgdG86ICAvc2NyYXRjaC9wczE2My9TMV9oZXJhbmNhLnZjZg0KTG9nIGZpbGUgc2F2ZWQgdG86ICAvc2NyYXRjaC9wczE2My9TMV9oZXJhbmNhLmxvZw0KTVFfRklMVEVSICAgICAgIDENClBBU1MgICAgNQ0KUUhfZXhjZWVkc19wb2x5biAgICAgICAgMTYNClFIX2ZhaWxzX0lTQSAgICAyDQpRSF9pbmRlbF9mYWlsc19JU0EgICAgICA0DQpTT1JfRklMVEVSICAgICAgMw0KYGBgDQoNCiMjIFF1aWNrIHN0YXJ0IGd1aWRlDQoNCiMjIyMgU3RlcCAxLiBTZXQgdXAgbWV0YWRhdGEgZmlsZQ0KSGVyYW5jYSB1c2VzIGEgdGFiIGRlbGltaXRlZCBtZXRhZGF0YSBmaWxlIHRvIGNvb3JkaW5hdGUgaW5mb3JtYXRpb24uIFRoaXMgbWV0YWRhdGEgZmlsZSBjb25zaXN0cyBvZiB0aHJlZSBjb2x1bW5zLg0KMS4gKipOYW1lKiogY29sdW1uIGZvciB0aGUgc3RyYWluL3NhbXBsZSBtdXN0IGJlIHVuaXF1ZSBpbiB0aGUgZmlsZQ0KMi4gKipGaWxlX3BhdGgqKiBjb2x1bW4gd2l0aCBhbiBhYnNvbHV0ZSBwYXRoIHRvIHRoZSBWQ0YgZmlsZQ0KMy4gKipMaW5lYWdlKiogY29sdW1uIGNvbnRhaW5pbmcgdGhlIGNvbW1hLWRlbGltaXRlZCAqKk5hbWVzKiogb2Ygc3RyYWlucyBpdCBpcyBkZXNjZW5kZWQgZnJvbS4gDQoNCioqTm90ZSoqOiBhIHN0cmFpbiB3aXRoIGl0J3Mgb3duIG5hbWUgaW4gaXQncyAqKkxpbmVhZ2UqKiBmaWVsZCB3aWxsIGJlIHRyZWF0ZWQgYXMgYW4gYW5jZXN0b3IsIHRoYXQgaXMgdG8gc2F5IGl0IHdpbGwgbm90IGJlIGRlc2NlbmRlZCBmcm9tIGFueSBvdGhlciBzdHJhaW5zLiAgDQoNCiMjIyMjIEV4YW1wbGUgb2YgYSBtZXRhZGF0YSBmaWxlDQpUaGUgZmlndXJlIGJlbG93IHNob3dzIGEgc2NoZW1hdGljIHJlbGF0aW5nIDcgc3RyYWlucyAtIG9uZSBhbmNlc3RvciAoQW5jKSwgZml2ZSBkaXJlY3QgZGVzY2VuZGFudHMgKFMxLVM1KSwgYW5kIG9uZSBzdHJhaW4gZGVzY2VuZGVkIGZyb20gcHJldmlvdXMgc3RyYWluIChTNikuIA0KDQohW10oQzovR3Jlc2hhbS90aW55X3Byb2plY3RzL3ZpZ2VudHRlcy9oZXJhbmNhL3NpbXBsZV9saW5lYWdlcy5wbmcpDQpUbyByZXByZXNlbnQgdGhlc2UgcmVsYXRpb25zaGlwcyBpbiB0aGUgbWV0YWRhdGEgZmlsZSB3ZSBmaXJzdCBzcGVjaWZ5IG5hbWVzLCBsb2NhdGlvbnMsIGFuZCB0aGVuIGxpbmVhZ2VzLiBGb3IgdGhlIGFuY2VzdG9yIChBbmMpIHdlIHB1dCBpdCdzIG93biBuYW1lIGluIHRoZSBsaW5lYWdlIGZpZWxkLCBkZW5vdGluZyBpdCdzIGFuY2VzdHJhbCBzdGF0dXMuIEJlY2F1c2UgYWxsIG90aGVyIHN0cmFpbnMgYXJlIGRlc2NlbmRlZCBmcm9tIHRoZSBhbmNlc3RvciAoQW5jKSB3ZSBhbHNvIHBvcHVsYXRlIHRob3NlIGZpZWxkcyB3aXRoIHRoYXQgbmFtZSBhcyB3ZWxsLiBGaW5hbGx5LCBiZWNhdXNlIFM2IGlzIGFsc28gZGVzY2VuZGVkIGZyb20gUzUgd2UgaW5jbHVkZSBpdCdzIG5hbWUgaW4gdGhlIGxpbmVhZ2UgZmllbGQgYXMgd2VsbCwgdXNpbmcgYSBjb21tYSBhcyBhIHNlcGFyYXRvci4NCg0KYGBgDQpBbmMgICBkZW1vL0FuYy52Y2YgIEFuYw0KUzEgICAgZGVtby9TMS52Y2YgICBBbmMNClMyICAgIGRlbW8vUzIudmNmICAgQW5jDQpTMyAgICBkZW1vL1MzLnZjZiAgIEFuYw0KUzQgICAgZGVtby9TNC52Y2YgICBBbmMNClM1ICAgIGRlbW8vUzUudmNmICAgQW5jDQpTNiAgICBkZW1vL1M2LnZjZiAgIEFuYywgUzUNCmBgYA0KDQojIyMjIFN0ZXAgMi4gUnVuIHVzaW5nIHlvdXIgb3duIGRhdGENCg0KU3RhbmRhcmQgZm9ybWF0IHdpbGwgcmVzdWx0IGluIFZDRnMgbGlzdGVkIGluIHRoZSA8aW5wdXRfbWV0YWRhdGFfZmlsZS50YWI+IGJlaW5nIGNvcnJlY3RlZCBhbmQgb3V0cHV0IHRvIHRoZSA8b3V0cHV0X3BhdGg+IGRpcmVjdG9yeSBhbG9uZyB3aXRoIHN1bW1hcnkgbG9nIGZpbGVzLg0KYGBgDQpweXRob24gaGVyYW5jYS5weSBcDQogIC1pIDxpbnB1dF9tZXRhZGF0YV9maWxlLnRhYj4gXA0KICAtZmEgPHJlZmVyZW5jZV9nZW5vbWVfZmFzdGFfZmlsZT4gXA0KICAtbyA8b3V0cHV0X3BhdGg+DQpgYGANCg0KIyMjIyMgV29ya2VkIG91dCBleGFtcGxlOg0KaW5wdXRfbWV0YWRhdGFfZmlsZTogYGBgUHJvamVjdF9DYXJvbGlub19uZXcvY29tYmluZV92Y2ZfbWV0YWRhdGFfaW5kZWxzLnR4dGBgYA0KDQpgYGANCkRHWTE2NTcgICBQcm9qZWN0X0Nhcm9saW5vX25ldy9IRzdDVkFGWFhfbWluaTAyXzQwX2ZpbHRlcmVkX2luZGVsc18yLnZjZiAgIERHWTE2NTcNCkRHWTE3MjYgICBQcm9qZWN0X0Nhcm9saW5vX25ldy9IS0ZZVEJHWDJfbWluaTAyX3BhcnRpaV82MV9maWx0ZXJlZF9pbmRlbHNfMi52Y2YgICAgREdZMTY1Nw0KYGBgDQpyZWZlcmVuY2VfZ2Vub21lX2Zhc3RhX2ZpbGU6IGBgYFNhY2NoYXJvbXljZXNfY2VyZXZpc2lhZS5SNjQtMS0xLmRuYS50b3BsZXZlbC5mYWBgYA0Kb3V0cHV0X3BhdGg6IA0KYGBgDQpta2RpciBoZXJhbmNhDQpgYGANCg0KYGBgDQpweXRob24gaGVyYW5jYS5weSBcDQogIC1pIFByb2plY3RfQ2Fyb2xpbm9fbmV3L2NvbWJpbmVfdmNmX21ldGFkYXRhX2luZGVscy50eHQNCiAgLWZhIEVuc2VtYmwvU2FjY2hhcm9teWNlc19jZXJldmlzaWFlLlI2NC0xLTEuZG5hLnRvcGxldmVsLmZhIFwNCiAgLW8gaGVyYW5jYS9leGFtcGxlXw0KYGBgDQpUaGlzIHdpbGwgcHJvZHVjZSB0d28gZWRpdGVkIFZDRiBmaWxlcyBhbmQgdHdvIHN1bW1hcnkgbG9nIGZpbGVzOg0KYGBgDQpoZXJhbmNhL2V4YW1wbGVfSEc3Q1ZBRlhYX21pbmkwMl80MF9maWx0ZXJlZF9pbmRlbHNfMl9oZXJhbmNhLnZjZg0KaGVyYW5jYS9leGFtcGxlX0hHN0NWQUZYWF9taW5pMDJfNDBfZmlsdGVyZWRfaW5kZWxzXzJfaGVyYW5jYS5sb2cNCmhlcmFuY2EvZXhhbXBsZV9IS0ZZVEJHWDJfbWluaTAyX3BhcnRpaV82MV9maWx0ZXJlZF9pbmRlbHNfMl9oZXJhbmNhLnZjZg0KaGVyYW5jYS9leGFtcGxlX0hLRllUQkdYMl9taW5pMDJfcGFydGlpXzYxX2ZpbHRlcmVkX2luZGVsc18yX2hlcmFuY2EubG9nDQpgYGANCg0KIyMjIyBTdGVwIDMuIEV2YWx1YXRpbmcgdGhlIG91dHB1dA0KDQpPdXRwdXQgd2lsbCBiZSBhIG1vZGlmaWVkIFZDRiBmaWxlIGlubHVkaW5nIGFsbCB2YXJpYW50cyBwcmVzZW50IGluIHRoZSBvcmlnaW5hbCwgYnV0IHdpdGggdGhvc2UgY2FuZGlkYXRlcyB0aGF0IGZhaWxlZCB0aGUgcG9seW51Y2Vsb3RpZGUgb3IgSVNBIGNyaXRlcmlhIGZsYWdnZWQgYXMgZGVzY3JpYmVkIGFib3ZlLiANCg0KIyMjIyMgTW9kaWZpZWQgVkNGIGZpbGVzDQoqIE9yaWdpbmFsOiANCkluIHRoZSBvcmlnaW5hbCBWQ0YgZmlsZSBmb3VyIHZhcmlhbnRzIGFyZSBtYXJrZWQgd2l0aCAqKlBBU1MqKiBhbmQgd291bGQgYmUgZXZhbHVhdGVkIGJ5IGRvd25zdHJlYW0gYW5hbHlzaXMNCmBgYA0KWElJSQk2ODA5MzYJLglUCUMJMTI4Mi4wNglQQVNTCUFDPTI7QUY9MS4wMDtBTj0yO0RQPTMwO0V4Y2Vzc0hldD0zLjAxMDM7RlM9MC4wMDA7TUxFQUM9MjtNTEVBRj0xLjAwO01RPTYwLjAwO1FEPTM0LjM3O1NPUj0xLjE0MwlHVDpBRDpEUDpHUTpQTAkxLzE6MCwzMDozMDo5MDoxMjk2LDkwLDANClhJSUkJNjgwOTQwCS4JQwlUCTEyMjYuMDYJUEFTUwlBQz0yO0FGPTEuMDA7QU49MjtEUD0yOTtFeGNlc3NIZXQ9My4wMTAzO0ZTPTAuMDAwO01MRUFDPTI7TUxFQUY9MS4wMDtNUT02MC4wMDtRRD0yOC43MDtTT1I9MS4xNzkJR1Q6QUQ6RFA6R1E6UEwJMS8xOjAsMjg6Mjg6ODQ6MTI0MCw4NCwwDQpYSUlJCTgwOTE5OAkuCUEJRwkyMDUyLjA2CVBBU1MJQUM9MjtBRj0xLjAwO0FOPTI7RFA9NTc7RXhjZXNzSGV0PTMuMDEwMztGUz0wLjAwMDtNTEVBQz0yO01MRUFGPTEuMDA7TVE9NjAuMDA7UUQ9MzIuNzg7U09SPTAuODQ2CUdUOkFEOkRQOkdROlBMCTEvMTowLDU0OjU0Ojk5OjIwNjYsMTYyLDANClhJSUkJOTA4MTc0CS4JRwlUCTU2Ny42NAlQQVNTCUFDPTE7QUY9MC41MDA7QU49MjtCYXNlUVJhbmtTdW09MC4zNzI7RFA9NTc7RXhjZXNzSGV0PTMuMDEwMztGUz0wLjAwMDtNTEVBQz0xO01MRUFGPTAuNTAwO01RPTU1LjcxO01RUmFua1N1bT0tMi4wODQ7UUQ9MTEuNTg7UmVhZFBvc1JhbmtTdW09LTMuMjY0O1NPUj0wLjY4MQlHVDpBRDpEUDpHUTpQTAkwLzE6MzIsMTc6NDk6OTk6NTc1LDAsMTI5Mg0KYGBgDQoqIE91dHB1dCAodXNpbmcgZGVmYXVsdCBgYGByZW1vdmVfZmlsdGVyZWQgPSBUcnVlYGBgKToNCkhlcmFuY2EgZmluZHMgdHdvIG9mIHRoZXNlcyB2YXJpYW50cyBmYWlsIGFuZCBvbWl0cyB0aGVzZSByZWNvcmRzDQpgYGANClhJSUkJNjgwOTM2CS4JVAlDCTEyODIuMDYJUEFTUwlBQz0yO0FGPTEuMDA7QU49MjtEUD0zMDtFeGNlc3NIZXQ9My4wMTAzO0ZTPTAuMDAwO01MRUFDPTI7TUxFQUY9MS4wMDtNUT02MC4wMDtRRD0zNC4zNztTT1I9MS4xNDMJR1Q6QUQ6RFA6R1E6UEwJMS8xOjAsMzA6MzA6OTA6MTI5Niw5MCwwDQpYSUlJCTgwOTE5OAkuCUEJRwkyMDUyLjA2CVBBU1MJQUM9MjtBRj0xLjAwO0FOPTI7RFA9NTc7RXhjZXNzSGV0PTMuMDEwMztGUz0wLjAwMDtNTEVBQz0yO01MRUFGPTEuMDA7TVE9NjAuMDA7UUQ9MzIuNzg7U09SPTAuODQ2CUdUOkFEOkRQOkdROlBMCTEvMTowLDU0OjU0Ojk5OjIwNjYsMTYyLDANCmBgYCAgDQoNCiogT3V0cHV0ICh1c2luZyBgYGByZW1vdmVfZmlsdGVyZWQgPSBGYWxzZWBgYCk6DQpTZXR0aW5nIEhlcmFuY2EgdG8gaW5jbHVkZSBmaWx0ZXJlZCByZWFkcywgd2UgZmluZCByb3dzIDIgKFhJSUk6NjgwOTQwKSBhbmQgNCAoWElJSTo5MDgxNzQpDQpgYGANClhJSUkgICAgNjgwOTM2ICAuICAgVCAgIEMgICAxMjgyLjA2IFBBU1MgICAgQUM9MjtBRj0xLjAwO0FOPTI7RFA9MzA7RXhjZXNzSGV0PTMuMDEwMztGUz0wLjAwMDtNTEVBQz0yO01MRUFGPTEuMDA7TVE9NjAuMDA7UUQ9MzQuMzc7U09SPTEuMTQzICAgIEdUOkFEOkRQOkdROlBMICAxLzE6MCwzMDozMDo5MDoxMjk2LDkwLDANClhJSUkgICAgNjgwOTQwICAuICAgQyAgIFQgICAxMjI2LjA2IFFIX0ZpbHRlcl9leGNlZWRzX3BvbHluXzUgICBBQz0yO0FGPTEuMDA7QU49MjtEUD0yOTtFeGNlc3NIZXQ9My4wMTAzO0ZTPTAuMDAwO01MRUFDPTI7TUxFQUY9MS4wMDtNUT02MC4wMDtRRD0yOC43MDtTT1I9MS4xNzkgICAgR1Q6QUQ6RFA6R1E6UEwgIDEvMTowLDI4OjI4Ojg0OjEyNDAsODQsMA0KWElJSSAgICA4MDkxOTggIC4gICBBICAgRyAgIDIwNTIuMDYgUEFTUyAgICBBQz0yO0FGPTEuMDA7QU49MjtEUD01NztFeGNlc3NIZXQ9My4wMTAzO0ZTPTAuMDAwO01MRUFDPTI7TUxFQUY9MS4wMDtNUT02MC4wMDtRRD0zMi43ODtTT1I9MC44NDYgICAgR1Q6QUQ6RFA6R1E6UEwgIDEvMTowLDU0OjU0Ojk5OjIwNjYsMTYyLDANClhJSUkgICAgOTA4MTc0ICAuICAgRyAgIFQgICA1NjcuNjQgIFFIX2ZhaWxzX0lTQV81ICBBQz0xO0FGPTAuNTAwO0FOPTI7QmFzZVFSYW5rU3VtPTAuMzcyO0RQPTU3O0V4Y2Vzc0hldD0zLjAxMDM7RlM9MC4wMDA7TUxFQUM9MTtNTEVBRj0wLjUwMDtNUT01NS43MTtNUVJhbmtTdW09LTIuMDg0O1FEPTExLjU4O1JlYWRQb3NSYW5rU3VtPS0zLjI2NDtTT1I9MC42ODEgICAgR1Q6QUQ6RFA6R1E6UEwgIDAvMTozMiwxNzo0OTo5OTo1NzUsMCwxMjkyDQpgYGANCg0KIyMjIyMgU3VtbWFyeSBsb2cgZmlsZXMNCkhlcmFuY2Egd2lsbCBhbHNvIGdlbmVyYXRlIHN1bW1hcnkgbG9nIGZpbGVzIG9mIHRoZSBjb3VudHMgb2YgdmFyaWFudCBmaWx0ZXIgc3RhdHVzIGNhdGVnb3JpZXMuIEEgY29tcGxldGUgZGVzY3JpcHRpb24gb2YgdGhlICdRSCcgZmlsdGVycyBpcyBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9wc3BlYWxtYW4vaGVyYW5jYSkNCg0KKiBFeGFtcGxlIG9mIEFuY2VzdHJhbCBsb2cgZmlsZToNCmBgYA0KTVFfRklMVEVSCTQNClBBU1MJNTUNClFIX2V4Y2VlZHNfcG9seW4JMjMNClFIX2xvd19nZW5vdHlwZV9yZWxhdGl2ZV9saWtlbGlob29kCTYNClNPUl9GSUxURVIJNA0KYGBgDQpIZXJlIHdlIHNlZSB2YXJpYW50cyBmaWx0ZXJlZCBieSBHQVRLNCBpbmNsdWRlIDQgZmlsdGVyZWQgZm9yIE1RLCBhbmQgU09SIGNyaXRlcmlhLiAyMyBhcmUgZmlsdGVyZWQgYnkgaGVyYW5jYSBmb3IgZXhjZWVkaW5nIHRoZSBwb2x5TiBjcml0ZXJpYSBhbmQgNiBmYWlsIHRvIG1lZXQgdGhlIHJlbGF0aXZlIGdlbm90eXBlIGxpa2VsaWhvb2QgY3JpdGVyaWEuIEZpbmFsbHksIDU1IHZhcmlhbnRzIG1lZXQgYWxsIHRoZSBjcml0ZXJpYS4gTm90YWJseSwgbm8gdmFyaWFudHMgYXJlIGZpbHRlcmVkIGZvciB2aW9sYXRpbmcgdGhlIElTQSBjcml0ZXJpYSBhcyB0aGlzIGlzIGEgYW5jZXN0cmFsIHN0cmFpbi4NCg0KKiBFeGFtcGxlIG9mIERlc2NlbmRhbnQgbG9nIGZpbGU6DQpgYGANClBBU1MJMjcNClFIX2V4Y2VlZHNfcG9seW4JMjINClFIX2luZGVsX2ZhaWxzX0lTQQkxNQ0KUUhfbG93X2dlbm90eXBlX3JlbGF0aXZlX2xpa2VsaWhvb2QJMQ0KYGBgDQpIZXJlIHdlIHNlZSB0aGF0IG5vIHZhcmlhbnRzIHdlcmUgZmlsdGVyZWQgYnkgR0FUSzQuIDIyIGFyZSBmaWx0ZXJlZCBieSBoZXJhbmNhIGZvciBleGNlZWRpbmcgdGhlIHBvbHlOIGNyaXRlcmlhIGFuZCAxIGZhaWxzIHRvIG1lZXQgdGhlIHJlbGF0aXZlIGdlbm90eXBlIGxpa2VsaWhvb2QgY3JpdGVyaWEuIDE1IHZhcmlhbnRzIGFyZSBmaWx0ZXJlZCBmb3IgdmlvbGF0aW5nIElTQS4gT25seSwgMjcgdmFyaWFudHMgbWVldCBhbGwgdGhlIGNyaXRlcmlhLiANCg0KDQo=