1. Connecting snakemake workflows

Yesterday we got a taste of the power of snakemake to conduct bioinformatics analyses. Today we are going to see how our Snakefile can be connected other downstream workflows modules.

The statement that allows integration of additional modules to our snakemake is include. Open the Snakefile you will see that at the very beginning there is an include statement that connects it with rules/00_download_data.skm, which correspond to a snakemake module that was run to download all the data from this course:

include: "rules/00_download_data.skm"

Use Atom (or any text editor) to open rules/00_download_data.skm file and take a look its code. You will see that the code start with some python code and the is followed up by some snakemake rules. This is possible because of Snakemake uses python as a background, so any python syntax works. The first part of the code tries to create some folders (FASTQ/, download/ and logs/). Then between lines 20-52, the scripts to download the samples are generated at download/ folder. At the same time SAMPLES object is created, and stores all the accession codes from NCBI_accession_list.txt. Thus, after these lines, SAMPLES correspond to a standard (python list)[https://www.programiz.com/python-programming/list] with the accession codes inside.

Exercise 1.1

As we have already downloaded all the data, we can disconnect rules/00_download_data.skm module from our Snakefile. To do this comment the first include statement by adding a # character at the first include statement, this will inactivate this line. Then on the second Snakefile’s line , create a list named SAMPLES that contain the accession values from NCBI_accession_list.txt. You can do this by introducing the following code at the second line of the Snakefile:

SAMPLES = ["SRR7889581", "SRR7889582", "SRR7889583", "SRR7889584", "SRR7889585", "SRR7889597", "SRR7889598", "SRR7889599", "SRR7889600"]

Next, save a new workflow visualisation in a new file and compare with the one we obtained yesterday. (Please take a look a the command to visualize the steps that is at (5.1 section)[https://bioinformatics-core-shared-training.github.io/RNAseq_March_2019/Course_Materials/00_Reproducible_RNA-Seq_Processing/Day1.nb.html]). Can you see some differences? Undo the canges before continue or just delete the # from the first line and add # at the beginning of the second)

Note: If you are interested to run this snakemake pipeline with your own samples, you can modify SAMPLES list and fill it with your own sample names. As long you place your own .fastq.gz files at FASTQ\, snakemake will be able to recognize your samples as input. If you want to work with a different species, you also need to modify Snakefile (and some files at rules\) to replace Genome/dm6.fa and “Gene_annotation/dm6.Ensembl.genes.gtf” by your own genome and gene annotation files.

2. Transcriptome Assembly:

In addition to quantifying gene expression, RNA-Seq data can be also used to annotate new transcripts. For this purpose, the algorithm tries to assemble the reads into scaffolds by finding common sequences among the reads. There are two main strategies to do this: * De novo transcriptome assembly: Which just take input the FASTQ files and it loads them into the RAM memory to a fast exploration of the possible solutions to assemble the reads as transcripts, therefore it requires large amounts of RAM memory. It is particularly useful when no good quality genome assembly is available. * Genome-guided transcriptome assembly: Which process the genomic alignments (BAM files) to assemble the transcripts. It is usually much faster and produces better results when the genome assembly is of good quality, like the ones you can find for model organisms (like D. melanogaster)

Exercise 2.1

include: "rules/01_stringtie.skm" connects our Snakefile with a module located at rules/01_stringtie.skm. Open this file and try to predict what commands are going to be executed by snakemake when we execute these rules.

2.1 Assembling reads into transcripts

The rule StringTie_Assemble execute stringtie for each BAM file. This will produce .assemble.gtf files at a StringTie\. Then all of these gene assembly files will be merged by StringTie_Merge by executing stringtie --merge and save it at StringTie/merged.assemble.gtf. Finnally, StringTie_gffcompare we compare this merged assembly with the reference transcript annotation using gffcompare, this will allow us to identify novel transcripts that are not currently annotated at D. melanogaster transcriptome.

Visualize these steps by targeting this StringTie_gffcompare rule and generate the DAG and transforming it to an image:

snakemake StringTie_gffcompare --dag | dot -Tpng > StringTie_Merge.png

Then look at the commands it will submit:

snakemake StringTie_gffcompare -np

Finally, run these steps:

snakemake StringTie_gffcompare --use-conda --cores 7

Exercise 2.1.1

Count the number of transcripts that were produced with the BAM file from the smallest and the largest sample. Then compare these values with the total amount of transcripts that you obtained after merging all the samples (hint: use awk '$3=="transcript"' GTF to filter the lines of the GTF files that match with transcript on the third column).

Exercise 2.1.2

Look at gffcompare\ folder and open the gffcompare.tracking file. The third line corresponds to a Transcript classification code. Follow this link to interpret these codes and count the number of unknown intergenic transcripts that you assembled.

Exercise 2.1.3

Load gffcompare.annotated.gtf at IGV and visualize some examples of unnanotated trancripts. What do you think there is the common characteristic?

2.2 Filtering the assembly

As you may notice, many of the new transcripts that StringTie generated with our data correspond to transcripts that only have one exon. Many of these can be false positives, thus we have coded for you a script in python (scripts/StringTie_filter.py) can filter this obtained assemblyes by transcript classification code and a minimum number of exons. This script is executed by StringTie_filer that is at rules/02_bridge.skm:

 rule StringTie_filer:
    input:
        gtf = "gffcompare/gffcompare.annotated.gtf",
        tracking = "gffcompare/gffcompare.tracking"
    params:
        min_number_of_exons = 3,
        gffcompare_allowed_classes = "k,m,n,j,x,i,y,u"
    output:
        gtf_filtered = "gffcompare/gffcompare.annotated.filtered.gtf"
    shell:
        "python scripts/StringTie_filter.py {input} {params} > {output}"

Where min_number_of_exons parameter correspond to the minimum number of exons that we allow in our filtering process. Also, as certain transcript types might not be reliable, gffcompare_allowed_classes parameter is a comma-separated list of the codes that we considered reliable and that it will be in our final filtered file. Finnaly, the next rule of 02_bridge.skm module, merges the filtered list of new transcripts with the reference transcripts.

Run these steps by using:

snakemake extrend_refrence --use-conda --cores 7

Exercise 2.2.1

How many new transcripts did we get in our filtered GTF file? How many of them are intergenic?

3. Alternative splicing analysis

To evaluate alternative splicing, we are going to use Whippet, a newly developed tool developed in julia. To do this, we need to activate a virtual environment that we already prepared for you:

conda activate julia_0.6.1

This virtual environment has a version of julia which is compatible with Whippet. To see more details about how we prepared this environment, please follow this link.

To visualize the stepts we are going to run we can plot the DAG using whippet_delta as a target:

snakemake whippet_delta --dag | dot -Tpng > whippet_delta.png

As this section might take a while, please run leave it running meanwhile we give you more details about Whippet:

snakemake whippet_delta --use-conda --cores 7

Whippet is a lightweight and fast program to perform alternative splicing analyses. Instead of mapping the reads to the genome, whippet is directly quantifying the genes, transcripts and splicing nodes by indexing the transcriptome. In this case, we providing to whippet the extended annotation that we got using StrigTie. To quantify splicing whippet define splicing nodes from the annotation and build a Contiguous Splice Graph (CSG):

This allows whippet to have a fast quantification at the event level. The indexing process is carried out by executing whippet-index.jl which in this case is the most time-consuming step. Then, we run whippet-quant.jl quantify the splicing nodes, which also at the same time quantifies gene and isoforms. And finally, whippet-delta.jl allow us to assess which exons are differentially included between two conditions. In our case, we grouped the samples by cell-type of origin, so we can assess alternative splicing between central neurons and glia.

Exercise 3.1.1

Following the indications from the authors, we deduced that we should use the following command to extract the significant changes from the final output:

zcat Delta/neuron_vs_glia_new.diff.gz | awk '($8>0.1||$8<0.1) && $9>=0.9'

By looking at Whippet documentation, can you make sense to this command? (hint awk is being used to filter columns, where || is interpreted as or and && as and)

Exercise 3.1.2

Which is the most frequent type of alternative splicing node?

Bonus Track

Explore the results using IGV. For this load all (or some) the sorted BAMs and the transcript annotations that we generated. For simplicity, you can start searching the coordinates of cassette exons (CE) that were detected as differentially included by whippet between central neurons and glia.

LS0tCnRpdGxlOiAiIFJlcHJvZHVjaWJsZSBSTkEtc2VxIFByb2NlZXNzaW5nIC0gRGF5MiAiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgMS4gQ29ubmVjdGluZyBzbmFrZW1ha2Ugd29ya2Zsb3dzICAKClllc3RlcmRheSB3ZSBnb3QgYSB0YXN0ZSBvZiB0aGUgcG93ZXIgb2Ygc25ha2VtYWtlIHRvIGNvbmR1Y3QgYmlvaW5mb3JtYXRpY3MgYW5hbHlzZXMuIFRvZGF5IHdlIGFyZSBnb2luZyB0byBzZWUgaG93IG91ciBgU25ha2VmaWxlYCBjYW4gYmUgY29ubmVjdGVkIG90aGVyIGRvd25zdHJlYW0gd29ya2Zsb3dzIG1vZHVsZXMuIAoKVGhlIHN0YXRlbWVudCB0aGF0IGFsbG93cyBpbnRlZ3JhdGlvbiBvZiBhZGRpdGlvbmFsIG1vZHVsZXMgdG8gb3VyIHNuYWtlbWFrZSBpcyBgaW5jbHVkZWAuIE9wZW4gdGhlIGBTbmFrZWZpbGVgIHlvdSB3aWxsIHNlZSB0aGF0IGF0IHRoZSB2ZXJ5IGJlZ2lubmluZyB0aGVyZSBpcyBhbiBpbmNsdWRlIHN0YXRlbWVudCB0aGF0IGNvbm5lY3RzIGl0IHdpdGggYHJ1bGVzLzAwX2Rvd25sb2FkX2RhdGEuc2ttYCwgd2hpY2ggY29ycmVzcG9uZCB0byBhIHNuYWtlbWFrZSBtb2R1bGUgdGhhdCB3YXMgcnVuIHRvIGRvd25sb2FkIGFsbCB0aGUgZGF0YSBmcm9tIHRoaXMgY291cnNlOgoKYGBge3B5dGhvbn0KaW5jbHVkZTogInJ1bGVzLzAwX2Rvd25sb2FkX2RhdGEuc2ttIgpgYGAgCgpVc2UgYEF0b21gIChvciBhbnkgdGV4dCBlZGl0b3IpIHRvIG9wZW4gYHJ1bGVzLzAwX2Rvd25sb2FkX2RhdGEuc2ttYCBmaWxlIGFuZCB0YWtlIGEgbG9vayBpdHMgY29kZS4gWW91IHdpbGwgc2VlIHRoYXQgdGhlIGNvZGUgc3RhcnQgd2l0aCBzb21lIHB5dGhvbiBjb2RlIGFuZCB0aGUgaXMgZm9sbG93ZWQgdXAgYnkgc29tZSBzbmFrZW1ha2UgcnVsZXMuIFRoaXMgaXMgcG9zc2libGUgYmVjYXVzZSBvZiBTbmFrZW1ha2UgdXNlcyBweXRob24gYXMgYSBiYWNrZ3JvdW5kLCBzbyBhbnkgcHl0aG9uIHN5bnRheCB3b3Jrcy4gVGhlIGZpcnN0IHBhcnQgb2YgdGhlIGNvZGUgdHJpZXMgdG8gY3JlYXRlIHNvbWUgZm9sZGVycyAoYEZBU1RRL2AsIGBkb3dubG9hZC9gIGFuZCBgbG9ncy9gKS4gVGhlbiBiZXR3ZWVuIGxpbmVzIDIwLTUyLCB0aGUgc2NyaXB0cyB0byBkb3dubG9hZCB0aGUgc2FtcGxlcyBhcmUgZ2VuZXJhdGVkIGF0IGBkb3dubG9hZC9gIGZvbGRlci4gQXQgdGhlIHNhbWUgdGltZSBgU0FNUExFU2Agb2JqZWN0IGlzIGNyZWF0ZWQsIGFuZCBzdG9yZXMgYWxsIHRoZSBhY2Nlc3Npb24gY29kZXMgZnJvbSBgTkNCSV9hY2Nlc3Npb25fbGlzdC50eHRgLiBUaHVzLCBhZnRlciB0aGVzZSBsaW5lcywgU0FNUExFUyBjb3JyZXNwb25kIHRvIGEgc3RhbmRhcmQgKHB5dGhvbiBsaXN0KVtodHRwczovL3d3dy5wcm9ncmFtaXouY29tL3B5dGhvbi1wcm9ncmFtbWluZy9saXN0XSB3aXRoIHRoZSBhY2Nlc3Npb24gY29kZXMgaW5zaWRlLgoKKipFeGVyY2lzZSAxLjEqKgoKQXMgd2UgaGF2ZSBhbHJlYWR5IGRvd25sb2FkZWQgYWxsIHRoZSBkYXRhLCB3ZSBjYW4gZGlzY29ubmVjdCBgcnVsZXMvMDBfZG93bmxvYWRfZGF0YS5za21gIG1vZHVsZSBmcm9tIG91ciBgU25ha2VmaWxlYC4gVG8gZG8gdGhpcyAqY29tbWVudCogdGhlIGZpcnN0IGluY2x1ZGUgc3RhdGVtZW50IGJ5IGFkZGluZyBhIGAjYCBjaGFyYWN0ZXIgYXQgdGhlIGZpcnN0IGluY2x1ZGUgc3RhdGVtZW50LCB0aGlzIHdpbGwgaW5hY3RpdmF0ZSB0aGlzIGxpbmUuIFRoZW4gb24gdGhlIHNlY29uZCBTbmFrZWZpbGUncyBsaW5lICwgY3JlYXRlIGEgbGlzdCBuYW1lZCBgU0FNUExFU2AgdGhhdCBjb250YWluIHRoZSBhY2Nlc3Npb24gdmFsdWVzIGZyb20gYE5DQklfYWNjZXNzaW9uX2xpc3QudHh0YC4gWW91IGNhbiBkbyB0aGlzIGJ5IGludHJvZHVjaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBhdCB0aGUgc2Vjb25kIGxpbmUgb2YgdGhlIGBTbmFrZWZpbGVgOgoKYGBge3B5dGhvbn0KU0FNUExFUyA9IFsiU1JSNzg4OTU4MSIsICJTUlI3ODg5NTgyIiwgIlNSUjc4ODk1ODMiLCAiU1JSNzg4OTU4NCIsICJTUlI3ODg5NTg1IiwgIlNSUjc4ODk1OTciLCAiU1JSNzg4OTU5OCIsICJTUlI3ODg5NTk5IiwgIlNSUjc4ODk2MDAiXQpgYGAgCk5leHQsIHNhdmUgYSBuZXcgd29ya2Zsb3cgdmlzdWFsaXNhdGlvbiBpbiBhIG5ldyBmaWxlIGFuZCBjb21wYXJlIHdpdGggdGhlIG9uZSB3ZSBvYnRhaW5lZCB5ZXN0ZXJkYXkuIChQbGVhc2UgdGFrZSBhIGxvb2sgYSB0aGUgY29tbWFuZCB0byB2aXN1YWxpemUgdGhlIHN0ZXBzIHRoYXQgaXMgYXQgKDUuMSBzZWN0aW9uKVtodHRwczovL2Jpb2luZm9ybWF0aWNzLWNvcmUtc2hhcmVkLXRyYWluaW5nLmdpdGh1Yi5pby9STkFzZXFfTWFyY2hfMjAxOS9Db3Vyc2VfTWF0ZXJpYWxzLzAwX1JlcHJvZHVjaWJsZV9STkEtU2VxX1Byb2Nlc3NpbmcvRGF5MS5uYi5odG1sXSkuIENhbiB5b3Ugc2VlIHNvbWUgZGlmZmVyZW5jZXM/IFVuZG8gdGhlIGNhbmdlcyBiZWZvcmUgY29udGludWUgb3IganVzdCBkZWxldGUgdGhlIGAjYCBmcm9tIHRoZSBmaXJzdCBsaW5lIGFuZCBhZGQgYCNgIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNlY29uZCkgCgoKKk5vdGU6KiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgdG8gcnVuIHRoaXMgc25ha2VtYWtlIHBpcGVsaW5lIHdpdGggeW91ciBvd24gc2FtcGxlcywgeW91IGNhbiBtb2RpZnkgYFNBTVBMRVNgIGxpc3QgYW5kIGZpbGwgaXQgd2l0aCB5b3VyIG93biBzYW1wbGUgbmFtZXMuIEFzIGxvbmcgeW91IHBsYWNlIHlvdXIgb3duIGAuZmFzdHEuZ3pgIGZpbGVzIGF0IGBGQVNUUVxgLCBzbmFrZW1ha2Ugd2lsbCBiZSBhYmxlIHRvIHJlY29nbml6ZSB5b3VyIHNhbXBsZXMgYXMgaW5wdXQuIElmIHlvdSB3YW50IHRvIHdvcmsgd2l0aCBhIGRpZmZlcmVudCBzcGVjaWVzLCB5b3UgYWxzbyBuZWVkIHRvIG1vZGlmeSBgU25ha2VmaWxlYCAoYW5kIHNvbWUgZmlsZXMgYXQgYHJ1bGVzXGApIHRvIHJlcGxhY2UgYEdlbm9tZS9kbTYuZmFgIGFuZCAgIkdlbmVfYW5ub3RhdGlvbi9kbTYuRW5zZW1ibC5nZW5lcy5ndGYiIGJ5IHlvdXIgb3duIGdlbm9tZSBhbmQgZ2VuZSBhbm5vdGF0aW9uIGZpbGVzLgoKCiMgMi4gVHJhbnNjcmlwdG9tZSBBc3NlbWJseToKCgoKICFbXShodHRwOi8vMi5icC5ibG9nc3BvdC5jb20vLUowZVhlb281U29jL1RkVjluNnJodkxJL0FBQUFBQUFBdUVrL2hOZm83enE3b1Q0L3MxNjAwL0Fzc2VtYmx5LnBuZykKCgoKSW4gYWRkaXRpb24gdG8gcXVhbnRpZnlpbmcgZ2VuZSBleHByZXNzaW9uLCBSTkEtU2VxIGRhdGEgY2FuIGJlIGFsc28gdXNlZCB0byBhbm5vdGF0ZSBuZXcgdHJhbnNjcmlwdHMuIEZvciB0aGlzIHB1cnBvc2UsIHRoZSBhbGdvcml0aG0gdHJpZXMgdG8gYXNzZW1ibGUgdGhlIHJlYWRzIGludG8gc2NhZmZvbGRzIGJ5IGZpbmRpbmcgY29tbW9uIHNlcXVlbmNlcyBhbW9uZyB0aGUgcmVhZHMuIFRoZXJlIGFyZSB0d28gbWFpbiBzdHJhdGVnaWVzIHRvIGRvIHRoaXM6CiogKkRlIG5vdm8qIHRyYW5zY3JpcHRvbWUgYXNzZW1ibHk6IFdoaWNoIGp1c3QgdGFrZSBpbnB1dCB0aGUgRkFTVFEgZmlsZXMgYW5kIGl0IGxvYWRzIHRoZW0gaW50byB0aGUgUkFNIG1lbW9yeSB0byBhIGZhc3QgZXhwbG9yYXRpb24gb2YgdGhlIHBvc3NpYmxlIHNvbHV0aW9ucyB0byBhc3NlbWJsZSB0aGUgcmVhZHMgYXMgdHJhbnNjcmlwdHMsIHRoZXJlZm9yZSBpdCByZXF1aXJlcyBsYXJnZSBhbW91bnRzIG9mIFJBTSBtZW1vcnkuIEl0IGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgd2hlbiBubyBnb29kIHF1YWxpdHkgZ2Vub21lIGFzc2VtYmx5IGlzIGF2YWlsYWJsZS4gCiogR2Vub21lLWd1aWRlZCB0cmFuc2NyaXB0b21lIGFzc2VtYmx5OiBXaGljaCBwcm9jZXNzIHRoZSBnZW5vbWljIGFsaWdubWVudHMgKEJBTSBmaWxlcykgdG8gYXNzZW1ibGUgdGhlIHRyYW5zY3JpcHRzLiBJdCBpcyB1c3VhbGx5IG11Y2ggZmFzdGVyIGFuZCBwcm9kdWNlcyBiZXR0ZXIgcmVzdWx0cyB3aGVuIHRoZSBnZW5vbWUgYXNzZW1ibHkgaXMgb2YgZ29vZCBxdWFsaXR5LCBsaWtlIHRoZSBvbmVzIHlvdSBjYW4gZmluZCBmb3IgbW9kZWwgb3JnYW5pc21zIChsaWtlICpELiBtZWxhbm9nYXN0ZXIqKQoKCioqRXhlcmNpc2UgMi4xKioKCmBpbmNsdWRlOiAicnVsZXMvMDFfc3RyaW5ndGllLnNrbSJgIGNvbm5lY3RzIG91ciBTbmFrZWZpbGUgd2l0aCBhIG1vZHVsZSBsb2NhdGVkIGF0IGBydWxlcy8wMV9zdHJpbmd0aWUuc2ttYC4gT3BlbiB0aGlzIGZpbGUgYW5kIHRyeSB0byBwcmVkaWN0IHdoYXQgY29tbWFuZHMgYXJlIGdvaW5nIHRvIGJlIGV4ZWN1dGVkIGJ5IHNuYWtlbWFrZSB3aGVuIHdlIGV4ZWN1dGUgdGhlc2UgcnVsZXMuIAoKIyAyLjEgQXNzZW1ibGluZyByZWFkcyBpbnRvIHRyYW5zY3JpcHRzCgpUaGUgcnVsZSBgU3RyaW5nVGllX0Fzc2VtYmxlYCBleGVjdXRlIGBzdHJpbmd0aWVgIGZvciBlYWNoIEJBTSBmaWxlLiBUaGlzIHdpbGwgcHJvZHVjZSBgLmFzc2VtYmxlLmd0ZmAgZmlsZXMgYXQgYSBgU3RyaW5nVGllXGAuIFRoZW4gYWxsIG9mIHRoZXNlIGdlbmUgYXNzZW1ibHkgZmlsZXMgd2lsbCBiZSBtZXJnZWQgYnkgYFN0cmluZ1RpZV9NZXJnZWAgYnkgZXhlY3V0aW5nIGBzdHJpbmd0aWUgLS1tZXJnZWAgYW5kIHNhdmUgaXQgYXQgYFN0cmluZ1RpZS9tZXJnZWQuYXNzZW1ibGUuZ3RmYC4gRmlubmFsbHksIGBTdHJpbmdUaWVfZ2ZmY29tcGFyZWAgd2UgY29tcGFyZSB0aGlzIG1lcmdlZCBhc3NlbWJseSB3aXRoIHRoZSByZWZlcmVuY2UgdHJhbnNjcmlwdCBhbm5vdGF0aW9uIHVzaW5nIGBnZmZjb21wYXJlYCwgdGhpcyB3aWxsIGFsbG93IHVzIHRvIGlkZW50aWZ5IG5vdmVsIHRyYW5zY3JpcHRzIHRoYXQgYXJlIG5vdCBjdXJyZW50bHkgYW5ub3RhdGVkIGF0ICpELiBtZWxhbm9nYXN0ZXIqIHRyYW5zY3JpcHRvbWUuIAoKClZpc3VhbGl6ZSB0aGVzZSBzdGVwcyBieSB0YXJnZXRpbmcgdGhpcyBgU3RyaW5nVGllX2dmZmNvbXBhcmUgYCBydWxlIGFuZCBnZW5lcmF0ZSB0aGUgREFHIGFuZCB0cmFuc2Zvcm1pbmcgaXQgdG8gYW4gaW1hZ2U6Cgpgc25ha2VtYWtlIFN0cmluZ1RpZV9nZmZjb21wYXJlIC0tZGFnIHwgZG90IC1UcG5nID4gU3RyaW5nVGllX01lcmdlLnBuZ2AKClRoZW4gbG9vayBhdCB0aGUgY29tbWFuZHMgaXQgd2lsbCBzdWJtaXQ6Cgpgc25ha2VtYWtlIFN0cmluZ1RpZV9nZmZjb21wYXJlIC1ucGAKCkZpbmFsbHksIHJ1biB0aGVzZSBzdGVwczoKCmBzbmFrZW1ha2UgU3RyaW5nVGllX2dmZmNvbXBhcmUgLS11c2UtY29uZGEgLS1jb3JlcyA3YAoKCioqRXhlcmNpc2UgMi4xLjEqKgoKQ291bnQgdGhlIG51bWJlciBvZiB0cmFuc2NyaXB0cyB0aGF0IHdlcmUgcHJvZHVjZWQgd2l0aCB0aGUgQkFNIGZpbGUgZnJvbSB0aGUgc21hbGxlc3QgYW5kIHRoZSBsYXJnZXN0IHNhbXBsZS4gVGhlbiBjb21wYXJlIHRoZXNlIHZhbHVlcyB3aXRoIHRoZSB0b3RhbCBhbW91bnQgb2YgdHJhbnNjcmlwdHMgdGhhdCB5b3Ugb2J0YWluZWQgYWZ0ZXIgbWVyZ2luZyBhbGwgdGhlIHNhbXBsZXMgKGhpbnQ6IHVzZSBgYXdrICckMz09InRyYW5zY3JpcHQiJyBHVEZgIHRvIGZpbHRlciB0aGUgbGluZXMgb2YgdGhlIEdURiBmaWxlcyB0aGF0IG1hdGNoIHdpdGggYHRyYW5zY3JpcHRgIG9uIHRoZSB0aGlyZCBjb2x1bW4pLgoKKipFeGVyY2lzZSAyLjEuMioqCgpMb29rIGF0IGBnZmZjb21wYXJlXGAgZm9sZGVyIGFuZCBvcGVuIHRoZSBgZ2ZmY29tcGFyZS50cmFja2luZ2AgZmlsZS4gVGhlIHRoaXJkIGxpbmUgY29ycmVzcG9uZHMgdG8gYSAgKipUcmFuc2NyaXB0IGNsYXNzaWZpY2F0aW9uIGNvZGUqKi4gRm9sbG93IHRoaXMgW2xpbmtdKGh0dHA6Ly9jY2Iuamh1LmVkdS9zb2Z0d2FyZS9zdHJpbmd0aWUvZ2ZmY29tcGFyZS5zaHRtbCN0cmFuc2ZyYWctY2xhc3MtY29kZXMpIHRvIGludGVycHJldCB0aGVzZSBjb2RlcyBhbmQgY291bnQgdGhlIG51bWJlciBvZiB1bmtub3duIGludGVyZ2VuaWMgdHJhbnNjcmlwdHMgdGhhdCB5b3UgYXNzZW1ibGVkLgoKKipFeGVyY2lzZSAyLjEuMyoqCgpMb2FkIGdmZmNvbXBhcmUuYW5ub3RhdGVkLmd0ZiBhdCBgSUdWYCBhbmQgdmlzdWFsaXplIHNvbWUgZXhhbXBsZXMgb2YgdW5uYW5vdGF0ZWQgdHJhbmNyaXB0cy4gV2hhdCBkbyB5b3UgdGhpbmsgdGhlcmUgaXMgdGhlIGNvbW1vbiBjaGFyYWN0ZXJpc3RpYz8gCgojIDIuMiBGaWx0ZXJpbmcgdGhlIGFzc2VtYmx5CgpBcyB5b3UgbWF5IG5vdGljZSwgbWFueSBvZiB0aGUgbmV3IHRyYW5zY3JpcHRzIHRoYXQgU3RyaW5nVGllIGdlbmVyYXRlZCB3aXRoIG91ciBkYXRhIGNvcnJlc3BvbmQgdG8gdHJhbnNjcmlwdHMgdGhhdCBvbmx5IGhhdmUgb25lIGV4b24uIE1hbnkgb2YgdGhlc2UgY2FuIGJlIGZhbHNlIHBvc2l0aXZlcywgdGh1cyB3ZSBoYXZlIGNvZGVkIGZvciB5b3UgYSBzY3JpcHQgaW4gcHl0aG9uIChgc2NyaXB0cy9TdHJpbmdUaWVfZmlsdGVyLnB5YCkgY2FuIGZpbHRlciB0aGlzIG9idGFpbmVkIGFzc2VtYmx5ZXMgYnkgdHJhbnNjcmlwdCBjbGFzc2lmaWNhdGlvbiBjb2RlIGFuZCBhIG1pbmltdW0gbnVtYmVyIG9mIGV4b25zLiBUaGlzIHNjcmlwdCBpcyBleGVjdXRlZCBieSBgU3RyaW5nVGllX2ZpbGVyYCB0aGF0IGlzIGF0IGBydWxlcy8wMl9icmlkZ2Uuc2ttYDoKCmBgYHtweXRob259CiBydWxlIFN0cmluZ1RpZV9maWxlcjoKICAgIGlucHV0OgogICAgICAgIGd0ZiA9ICJnZmZjb21wYXJlL2dmZmNvbXBhcmUuYW5ub3RhdGVkLmd0ZiIsCiAgICAgICAgdHJhY2tpbmcgPSAiZ2ZmY29tcGFyZS9nZmZjb21wYXJlLnRyYWNraW5nIgogICAgcGFyYW1zOgogICAgICAgIG1pbl9udW1iZXJfb2ZfZXhvbnMgPSAzLAogICAgICAgIGdmZmNvbXBhcmVfYWxsb3dlZF9jbGFzc2VzID0gImssbSxuLGoseCxpLHksdSIKICAgIG91dHB1dDoKICAgICAgICBndGZfZmlsdGVyZWQgPSAiZ2ZmY29tcGFyZS9nZmZjb21wYXJlLmFubm90YXRlZC5maWx0ZXJlZC5ndGYiCiAgICBzaGVsbDoKICAgICAgICAicHl0aG9uIHNjcmlwdHMvU3RyaW5nVGllX2ZpbHRlci5weSB7aW5wdXR9IHtwYXJhbXN9ID4ge291dHB1dH0iCmBgYCAKICAgIApXaGVyZSBgbWluX251bWJlcl9vZl9leG9uc2AgcGFyYW1ldGVyIGNvcnJlc3BvbmQgdG8gdGhlIG1pbmltdW0gbnVtYmVyIG9mIGV4b25zIHRoYXQgd2UgYWxsb3cgaW4gb3VyIGZpbHRlcmluZyBwcm9jZXNzLiBBbHNvLCBhcyBjZXJ0YWluIHRyYW5zY3JpcHQgdHlwZXMgbWlnaHQgbm90IGJlIHJlbGlhYmxlLCAgYGdmZmNvbXBhcmVfYWxsb3dlZF9jbGFzc2VzYCBwYXJhbWV0ZXIgaXMgYSBjb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiB0aGUgY29kZXMgdGhhdCB3ZSBjb25zaWRlcmVkIHJlbGlhYmxlIGFuZCB0aGF0IGl0IHdpbGwgYmUgaW4gb3VyIGZpbmFsIGZpbHRlcmVkIGZpbGUuIEZpbm5hbHksIHRoZSBuZXh0IHJ1bGUgb2YgYDAyX2JyaWRnZS5za21gIG1vZHVsZSwgbWVyZ2VzIHRoZSBmaWx0ZXJlZCBsaXN0IG9mIG5ldyB0cmFuc2NyaXB0cyB3aXRoIHRoZSByZWZlcmVuY2UgdHJhbnNjcmlwdHMuCgpSdW4gdGhlc2Ugc3RlcHMgYnkgdXNpbmc6Cgpgc25ha2VtYWtlIGV4dHJlbmRfcmVmcmVuY2UgIC0tdXNlLWNvbmRhIC0tY29yZXMgN2AKCgoqKkV4ZXJjaXNlIDIuMi4xKioKCkhvdyBtYW55IG5ldyB0cmFuc2NyaXB0cyBkaWQgd2UgZ2V0IGluIG91ciBmaWx0ZXJlZCBHVEYgZmlsZT8gSG93IG1hbnkgb2YgdGhlbSBhcmUgaW50ZXJnZW5pYz8KCgojIDMuIEFsdGVybmF0aXZlIHNwbGljaW5nIGFuYWx5c2lzCgpUbyBldmFsdWF0ZSBhbHRlcm5hdGl2ZSBzcGxpY2luZywgd2UgYXJlIGdvaW5nIHRvIHVzZSBbV2hpcHBldF0oaHR0cHM6Ly9naXRodWIuY29tL3RpbWJpdHovV2hpcHBldC5qbCksIGEgbmV3bHkgZGV2ZWxvcGVkIHRvb2wgZGV2ZWxvcGVkIGluIFtqdWxpYV0oaHR0cHM6Ly9qdWxpYWxhbmcub3JnLykuIFRvIGRvIHRoaXMsIHdlIG5lZWQgdG8gYWN0aXZhdGUgYSB2aXJ0dWFsIGVudmlyb25tZW50IHRoYXQgd2UgYWxyZWFkeSBwcmVwYXJlZCBmb3IgeW91OgoKYGNvbmRhIGFjdGl2YXRlIGp1bGlhXzAuNi4xYAoKVGhpcyB2aXJ0dWFsIGVudmlyb25tZW50IGhhcyBhIHZlcnNpb24gb2YgKipqdWxpYSoqIHdoaWNoIGlzIGNvbXBhdGlibGUgd2l0aCAqKldoaXBwZXQqKi4gVG8gc2VlIG1vcmUgZGV0YWlscyBhYm91dCBob3cgd2UgcHJlcGFyZWQgdGhpcyBlbnZpcm9ubWVudCwgcGxlYXNlIGZvbGxvdyB0aGlzIFtsaW5rXShodHRwczovL2dpdGh1Yi5jb20vYmlvaW5mb3JtYXRpY3MtY29yZS1zaGFyZWQtdHJhaW5pbmcvUk5Bc2VxX01hcmNoXzIwMTkvdHJlZS9tYXN0ZXIvQ291cnNlX01hdGVyaWFscy8wMF9SZXByb2R1Y2libGVfUk5BLVNlcV9Qcm9jZXNzaW5nL1doaXBwZXQpLgoKVG8gdmlzdWFsaXplIHRoZSBzdGVwdHMgd2UgYXJlIGdvaW5nIHRvIHJ1biB3ZSBjYW4gcGxvdCB0aGUgREFHIHVzaW5nIGB3aGlwcGV0X2RlbHRhYCBhcyBhIHRhcmdldDoKCmBzbmFrZW1ha2Ugd2hpcHBldF9kZWx0YSAtLWRhZyB8IGRvdCAtVHBuZyA+IHdoaXBwZXRfZGVsdGEucG5nYAoKQXMgdGhpcyBzZWN0aW9uIG1pZ2h0IHRha2UgYSB3aGlsZSwgcGxlYXNlIHJ1biBsZWF2ZSBpdCBydW5uaW5nIG1lYW53aGlsZSB3ZSBnaXZlIHlvdSBtb3JlIGRldGFpbHMgYWJvdXQgV2hpcHBldDoKCmBzbmFrZW1ha2Ugd2hpcHBldF9kZWx0YSAtLXVzZS1jb25kYSAtLWNvcmVzIDdgCgoKV2hpcHBldCBpcyBhIGxpZ2h0d2VpZ2h0IGFuZCBmYXN0IHByb2dyYW0gdG8gcGVyZm9ybSBhbHRlcm5hdGl2ZSBzcGxpY2luZyBhbmFseXNlcy4gSW5zdGVhZCBvZiBtYXBwaW5nIHRoZSByZWFkcyB0byB0aGUgZ2Vub21lLCB3aGlwcGV0IGlzIGRpcmVjdGx5IHF1YW50aWZ5aW5nIHRoZSBnZW5lcywgdHJhbnNjcmlwdHMgYW5kIHNwbGljaW5nIG5vZGVzIGJ5IGluZGV4aW5nIHRoZSB0cmFuc2NyaXB0b21lLiBJbiB0aGlzIGNhc2UsIHdlIHByb3ZpZGluZyB0byB3aGlwcGV0IHRoZSBleHRlbmRlZCBhbm5vdGF0aW9uIHRoYXQgd2UgZ290IHVzaW5nIFN0cmlnVGllLiBUbyBxdWFudGlmeSBzcGxpY2luZyB3aGlwcGV0IGRlZmluZSBzcGxpY2luZyBub2RlcyBmcm9tIHRoZSBhbm5vdGF0aW9uIGFuZCBidWlsZCBhIENvbnRpZ3VvdXMgU3BsaWNlIEdyYXBoIChDU0cpOgoKCiFbXShodHRwczovL2NhbW8uZ2l0aHVidXNlcmNvbnRlbnQuY29tL2E1YzJkZWYzZTA1MmFiNWI1ZmNkZWJlNjQzYzc2ZjgwYTJhNDFhZGUvNjg3NDc0NzA3MzNhMmYyZjc0Njk2ZDYyNjk3NDdhMmU2NzY5NzQ2ODc1NjIyZTY5NmYyZjY5NmQ2MTY3NjU3MzJmNTc2ODY5NzA3MDY1NzQyZDQ2Njk2NzMxMmU2NzY5NjYpIAoKClRoaXMgYWxsb3dzIHdoaXBwZXQgdG8gaGF2ZSBhIGZhc3QgcXVhbnRpZmljYXRpb24gYXQgdGhlIGV2ZW50IGxldmVsLiBUaGUgaW5kZXhpbmcgcHJvY2VzcyBpcyBjYXJyaWVkIG91dCBieSBleGVjdXRpbmcgYHdoaXBwZXQtaW5kZXguamxgIHdoaWNoIGluIHRoaXMgY2FzZSBpcyB0aGUgbW9zdCB0aW1lLWNvbnN1bWluZyBzdGVwLiBUaGVuLCB3ZSBydW4gYHdoaXBwZXQtcXVhbnQuamxgIHF1YW50aWZ5IHRoZSBzcGxpY2luZyBub2Rlcywgd2hpY2ggYWxzbyBhdCB0aGUgc2FtZSB0aW1lIHF1YW50aWZpZXMgZ2VuZSBhbmQgaXNvZm9ybXMuIEFuZCBmaW5hbGx5LCBgd2hpcHBldC1kZWx0YS5qbGAgYWxsb3cgdXMgdG8gYXNzZXNzIHdoaWNoIGV4b25zIGFyZSBkaWZmZXJlbnRpYWxseSBpbmNsdWRlZCBiZXR3ZWVuIHR3byBjb25kaXRpb25zLiBJbiBvdXIgY2FzZSwgd2UgZ3JvdXBlZCB0aGUgc2FtcGxlcyBieSBjZWxsLXR5cGUgb2Ygb3JpZ2luLCBzbyB3ZSBjYW4gYXNzZXNzIGFsdGVybmF0aXZlIHNwbGljaW5nIGJldHdlZW4gY2VudHJhbCBuZXVyb25zIGFuZCBnbGlhLiAKCioqRXhlcmNpc2UgMy4xLjEqKgoKRm9sbG93aW5nIHRoZSBpbmRpY2F0aW9ucyBmcm9tIHRoZSBhdXRob3JzLCB3ZSBkZWR1Y2VkIHRoYXQgd2Ugc2hvdWxkIHVzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQgdG8gZXh0cmFjdCB0aGUgc2lnbmlmaWNhbnQgY2hhbmdlcyBmcm9tIHRoZSBmaW5hbCBvdXRwdXQ6CgpgemNhdCBEZWx0YS9uZXVyb25fdnNfZ2xpYV9uZXcuZGlmZi5neiAgfCBhd2sgJygkOD4wLjF8fCQ4PDAuMSkgJiYgJDk+PTAuOSdgCgpCeSBsb29raW5nIGF0IFtXaGlwcGV0IGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZ2l0aHViLmNvbS90aW1iaXR6L1doaXBwZXQuamwpLCBjYW4geW91IG1ha2Ugc2Vuc2UgdG8gdGhpcyBjb21tYW5kPyAoaGludCBgYXdrYCBpcyBiZWluZyB1c2VkIHRvIGZpbHRlciBjb2x1bW5zLCB3aGVyZSBgfHxgIGlzIGludGVycHJldGVkIGFzIGBvcmAgYW5kIGAmJmAgYXMgYGFuZGApCgoqKkV4ZXJjaXNlIDMuMS4yKioKCldoaWNoIGlzIHRoZSBtb3N0IGZyZXF1ZW50IHR5cGUgb2YgYWx0ZXJuYXRpdmUgc3BsaWNpbmcgbm9kZT8KCioqQm9udXMgVHJhY2sqKgoKRXhwbG9yZSB0aGUgcmVzdWx0cyB1c2luZyBJR1YuIEZvciB0aGlzIGxvYWQgYWxsIChvciBzb21lKSB0aGUgc29ydGVkIEJBTXMgYW5kIHRoZSB0cmFuc2NyaXB0IGFubm90YXRpb25zIHRoYXQgd2UgZ2VuZXJhdGVkLiBGb3Igc2ltcGxpY2l0eSwgeW91IGNhbiBzdGFydCBzZWFyY2hpbmcgdGhlIGNvb3JkaW5hdGVzIG9mICoqY2Fzc2V0dGUgZXhvbnMqKiAoQ0UpICB0aGF0IHdlcmUgZGV0ZWN0ZWQgYXMgZGlmZmVyZW50aWFsbHkgaW5jbHVkZWQgYnkgd2hpcHBldCBiZXR3ZWVuIGNlbnRyYWwgbmV1cm9ucyBhbmQgZ2xpYS4=