Differential Expression Workflow
Here we will take the results from the previous module and operate on
them a bit further. This will wrap up the preceding exercises, leaving
us well-poised to begin differential expression, which we will discuss
today and tomorrow.
Alignment Statistics with MultiQC
After aligning reads it is often helpful to know how many reads were
uniquely aligned, mapped to multiple loci, or not mapped at all. The
sample_NLog.final.out
file which is output alongside the
alignments in sample_N.temp/
folder (we used the
--keep-intermediate-files
flag), reports this
information:
Started job on | Oct 02 13:09:23
Started mapping on | Oct 02 13:09:51
Finished on | Oct 02 13:12:47
Mapping speed, Million of reads per hour | 238.82
Number of input reads | 11675504
Average input read length | 146
UNIQUE READS:
Uniquely mapped reads number | 10609591
Uniquely mapped reads % | 90.87%
Average mapped length | 146.37
Number of splices: Total | 2755543
Number of splices: Annotated (sjdb) | 2734730
Number of splices: GT/AG | 2739697
Number of splices: GC/AG | 13204
Number of splices: AT/AC | 1744
Number of splices: Non-canonical | 898
Mismatch rate per base, % | 0.18%
Deletion rate per base | 0.01%
Deletion average length | 1.60
Insertion rate per base | 0.01%
Insertion average length | 1.29
MULTI-MAPPING READS:
Number of reads mapped to multiple loci | 599915
% of reads mapped to multiple loci | 5.14%
Number of reads mapped to too many loci | 12786
% of reads mapped to too many loci | 0.11%
UNMAPPED READS:
Number of reads unmapped: too many mismatches | 20381
% of reads unmapped: too many mismatches | 0.17%
Number of reads unmapped: too short | 389960
% of reads unmapped: too short | 3.34%
Number of reads unmapped: other | 42871
% of reads unmapped: other | 0.37%
CHIMERIC READS:
Number of chimeric reads | 0
% of chimeric reads | 0.00%
MultiQC
While the information is incredibly useful, it can be tedious to look
at the report for each sample separately, while keeping track of what
trends emerge. It would be much easier to look at all the data compiled
into a single report. MultiQC is a
tool that does exactly this.
MultiQC is designed to interpret and aggregate reports from various tools and
output a single report as an HTML document.
MultiQC Details
MultiQC’s main output is the report file in HTML format. This can be
viewed in a web browser. Additionally, it creates a data
directory with text files containing the data that MultiQC gathered
during its execution - this same data is what is shown in the
report.
Given an output directory out_multiqc, we should see something like
the following:
# directory of multiqc data files
out_multiqc/multiqc_data/multiqc.log
out_multiqc/multiqc_data/multiqc_data.json
out_multiqc/multiqc_data/multiqc_general_stats.txt
out_multiqc/multiqc_data/multiqc_rsem.txt
out_multiqc/multiqc_data/multiqc_sources.txt
# multiqc report
out_multiqc/multiqc_report.html
In a moment we will run multiqc
, and it will detect
these reports from STAR and include them in the report.
If we then open the MultiQC report (HTML), the newly included STAR
section will look something like the following:
Example of
STAR alignment statistics in MultiQC.
Source: MultiQC
example report
MultiQC Exercise:
- Note the contents of our analysis directory, and those of the
subdirectories we’ve created for each task
- Construct a MultiQC command and execute it on the entire analysis
directory
- Verify that the MultiQC report was created
# Ensure that we're in our analysis directory, note the contents
cd ~/RSD_Shell/analysis
tree . | less
# View MultiQC help page
multiqc --help
# Construct a MultiQC command and execute it
multiqc --outdir out_multiqc_all .
# Verify that the output files are present
ls -l out_multiqc_all
We just learned how to view all of our QC details in one report with
the help of MultiQC. MultiQC is extremely helpful, and we’ll notice how
it will ingest various files from the different steps of our pipeline,
and create several modules of summary figures for each of them.
Transfer MultiQC Reports With scp
Exercise
Before starting our file transfer exercise, we should make sure that
we are on the same page. Follow the link below:
Link to report transfer
exercise
Creating the count matrix
We have viewed some of the gene expression quantification results
individually. It can be useful to combine these expression values into a
count matrix. This is helpful when gathering expression-level QC
metrics, as well as for input into a differential gene expression
program such as DESeq2.
There are many ways to combine these results into a count matrix. For
this workshop, we’ll use a small python script to
combine.py
that we’ve made for this purpose. To understand
the process a bit more, let’s review the .genes.results
files that we want to combine and discuss some details of the script.
Finally, we’ll end with an exercise creating a count matrix.
If we review the *.genes.results files, we can see various columns of
data output from RSEM that we discussed in the last module.
# Review of *.genes.results file contents
gene_id transcript_id(s) length effective_length expected_count TPM FPKM
ENSMUSG00000000001 ENSMUST00000000001 3262.00 3116.28 601.00 45.50 36.70
ENSMUSG00000000003 ENSMUST00000000003,ENSMUST00000114041 799.50 653.78 0.00 0.00 0.00
We’ll take the expected_count
column from each sample’s
data, and combine these so that we have an aggregated data matrix with a
row for each gene and a column for each sample.
The input for this step will be the directory of *.genes.results
files from RSEM, and the output will be a tab-separated count matrix
file which we can use for count-level QC and differential expression
analysis.
Contents of combine.py script
Here
are the contents of the python script we’ll use,
combine.py
:
Count Matrix Exercise:
- View the help file of
combine.py
- Construct / execute a command to combine our results into a count
matrix
- View the resulting count matrix
# View the help file of combine.py
combine.py --help
# Construct and execute the command to combine.py
combine.py --input_path "out_rsem/*.genes.results" --output_file combined_counts.txt -c expected_count --id_columns gene_id
# View the resulting count matrix
less -S combined_counts.txt
These materials have been adapted and extended from materials created
by the Harvard Chan
Bioinformatics Core (HBC). These are open access materials
distributed under the terms of the Creative Commons
Attribution license (CC BY 4.0), which permits unrestricted use,
distribution, and reproduction in any medium, provided the original
author and source are credited.
LS0tCnRpdGxlOiAiQWxpZ25tZW50IFFDIGFuZCBRdWFudGlmaWNhdGlvbiIKYXV0aG9yOiAiVU0gQmlvaW5mb3JtYXRpY3MgQ29yZSIKb3V0cHV0OgogICAgICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgICAgICAgIGluY2x1ZGVzOgogICAgICAgICAgICAgICAgaW5faGVhZGVyOiBoZWFkZXIuaHRtbAogICAgICAgICAgICB0aGVtZTogcGFwZXIKICAgICAgICAgICAgdG9jOiB0cnVlCiAgICAgICAgICAgIHRvY19kZXB0aDogNAogICAgICAgICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgICAgICAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgICAgICAgICBtYXJrZG93bjogR0ZNCiAgICAgICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHl7IC8qIE5vcm1hbCAgKi8KICAgICAgZm9udC1zaXplOiAxNHB0OwogIH0KcHJlIHsKICBmb250LXNpemU6IDEycHQKfQo8L3N0eWxlPgoKSW4gdGhpcyBtb2R1bGUsIHdlIHdpbGwgbGVhcm46CgoqIGFib3V0IHRoZSBNdWx0aVFDIHRvb2wgYW5kIGl0cyBjYXBhYmlsaXRpZXMKKiBob3cgdG8gcnVuIG11bHRpUUMgb24gYSByZW1vdGUgc3lzdGVtCiogaG93IE11bHRpUUMgZ2F0aGVycyBpbmZvcm1hdGlvbiBmb3IgUUMgcHVycG9zZXMKKiBob3cgTXVsdGlRQyBwcmVzZW50cyB0aGUgcmVzdWx0cyBvZiBjdXRhZGFwdCB0cmltbWluZyBhbmQgU1RBUiBhbGlnbm1lbnQKKiBob3cgdG8gY29tYmluZSBnZW5lLWxldmVsIHJlc3VsdHMgaW50byBhIGNvdW50IG1hdHJpeAoKIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBXb3JrZmxvdwoKSGVyZSB3ZSB3aWxsIHRha2UgdGhlIHJlc3VsdHMgZnJvbSB0aGUgcHJldmlvdXMgbW9kdWxlIGFuZCBvcGVyYXRlIG9uIHRoZW0gYSBiaXQgZnVydGhlci4gVGhpcyB3aWxsIHdyYXAgdXAgdGhlIHByZWNlZGluZyBleGVyY2lzZXMsIGxlYXZpbmcgdXMgd2VsbC1wb2lzZWQgdG8gYmVnaW4gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIHdoaWNoIHdlIHdpbGwgZGlzY3VzcyB0b2RheSBhbmQgdG9tb3Jyb3cuCgohW10oaW1hZ2VzL3dheWZpbmRlci93YXlmaW5kZXItQWxpZ25tZW50X1FDX2FuZF9RdWFudGlmaWNhdGlvbi5wbmcpCjxicj4KPGJyPgo8YnI+Cjxicj4KCiMjIEFsaWdubWVudCBTdGF0aXN0aWNzIHdpdGggTXVsdGlRQwoKQWZ0ZXIgYWxpZ25pbmcgcmVhZHMgaXQgaXMgb2Z0ZW4gaGVscGZ1bCB0byBrbm93IGhvdyBtYW55IHJlYWRzIHdlcmUgdW5pcXVlbHkgYWxpZ25lZCwgbWFwcGVkIHRvIG11bHRpcGxlIGxvY2ksIG9yIG5vdCBtYXBwZWQgYXQgYWxsLiBUaGUgYHNhbXBsZV9OTG9nLmZpbmFsLm91dGAgZmlsZSB3aGljaCBpcyBvdXRwdXQgYWxvbmdzaWRlIHRoZSBhbGlnbm1lbnRzIGluIGBzYW1wbGVfTi50ZW1wL2AgZm9sZGVyICh3ZSB1c2VkIHRoZSBgLS1rZWVwLWludGVybWVkaWF0ZS1maWxlc2AgZmxhZyksIHJlcG9ydHMgdGhpcyBpbmZvcm1hdGlvbjoKCmBgYAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydGVkIGpvYiBvbiB8CU9jdCAwMiAxMzowOToyMwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0ZWQgbWFwcGluZyBvbiB8CU9jdCAwMiAxMzowOTo1MQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGaW5pc2hlZCBvbiB8CU9jdCAwMiAxMzoxMjo0NwogICAgICAgTWFwcGluZyBzcGVlZCwgTWlsbGlvbiBvZiByZWFkcyBwZXIgaG91ciB8CTIzOC44MgoKICAgICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIgb2YgaW5wdXQgcmVhZHMgfAkxMTY3NTUwNAogICAgICAgICAgICAgICAgICAgICAgQXZlcmFnZSBpbnB1dCByZWFkIGxlbmd0aCB8CTE0NgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVTklRVUUgUkVBRFM6CiAgICAgICAgICAgICAgICAgICBVbmlxdWVseSBtYXBwZWQgcmVhZHMgbnVtYmVyIHwJMTA2MDk1OTEKICAgICAgICAgICAgICAgICAgICAgICAgVW5pcXVlbHkgbWFwcGVkIHJlYWRzICUgfAk5MC44NyUKICAgICAgICAgICAgICAgICAgICAgICAgICBBdmVyYWdlIG1hcHBlZCBsZW5ndGggfAkxNDYuMzcKICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIgb2Ygc3BsaWNlczogVG90YWwgfAkyNzU1NTQzCiAgICAgICAgICAgIE51bWJlciBvZiBzcGxpY2VzOiBBbm5vdGF0ZWQgKHNqZGIpIHwJMjczNDczMAogICAgICAgICAgICAgICAgICAgICAgIE51bWJlciBvZiBzcGxpY2VzOiBHVC9BRyB8CTI3Mzk2OTcKICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIgb2Ygc3BsaWNlczogR0MvQUcgfAkxMzIwNAogICAgICAgICAgICAgICAgICAgICAgIE51bWJlciBvZiBzcGxpY2VzOiBBVC9BQyB8CTE3NDQKICAgICAgICAgICAgICAgTnVtYmVyIG9mIHNwbGljZXM6IE5vbi1jYW5vbmljYWwgfAk4OTgKICAgICAgICAgICAgICAgICAgICAgIE1pc21hdGNoIHJhdGUgcGVyIGJhc2UsICUgfAkwLjE4JQogICAgICAgICAgICAgICAgICAgICAgICAgRGVsZXRpb24gcmF0ZSBwZXIgYmFzZSB8CTAuMDElCiAgICAgICAgICAgICAgICAgICAgICAgIERlbGV0aW9uIGF2ZXJhZ2UgbGVuZ3RoIHwJMS42MAogICAgICAgICAgICAgICAgICAgICAgICBJbnNlcnRpb24gcmF0ZSBwZXIgYmFzZSB8CTAuMDElCiAgICAgICAgICAgICAgICAgICAgICAgSW5zZXJ0aW9uIGF2ZXJhZ2UgbGVuZ3RoIHwJMS4yOQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1VTFRJLU1BUFBJTkcgUkVBRFM6CiAgICAgICAgTnVtYmVyIG9mIHJlYWRzIG1hcHBlZCB0byBtdWx0aXBsZSBsb2NpIHwJNTk5OTE1CiAgICAgICAgICAgICAlIG9mIHJlYWRzIG1hcHBlZCB0byBtdWx0aXBsZSBsb2NpIHwJNS4xNCUKICAgICAgICBOdW1iZXIgb2YgcmVhZHMgbWFwcGVkIHRvIHRvbyBtYW55IGxvY2kgfAkxMjc4NgogICAgICAgICAgICAgJSBvZiByZWFkcyBtYXBwZWQgdG8gdG9vIG1hbnkgbG9jaSB8CTAuMTElCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVTk1BUFBFRCBSRUFEUzoKICBOdW1iZXIgb2YgcmVhZHMgdW5tYXBwZWQ6IHRvbyBtYW55IG1pc21hdGNoZXMgfAkyMDM4MQogICAgICAgJSBvZiByZWFkcyB1bm1hcHBlZDogdG9vIG1hbnkgbWlzbWF0Y2hlcyB8CTAuMTclCiAgICAgICAgICAgIE51bWJlciBvZiByZWFkcyB1bm1hcHBlZDogdG9vIHNob3J0IHwJMzg5OTYwCiAgICAgICAgICAgICAgICAgJSBvZiByZWFkcyB1bm1hcHBlZDogdG9vIHNob3J0IHwJMy4zNCUKICAgICAgICAgICAgICAgIE51bWJlciBvZiByZWFkcyB1bm1hcHBlZDogb3RoZXIgfAk0Mjg3MQogICAgICAgICAgICAgICAgICAgICAlIG9mIHJlYWRzIHVubWFwcGVkOiBvdGhlciB8CTAuMzclCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDSElNRVJJQyBSRUFEUzoKICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIgb2YgY2hpbWVyaWMgcmVhZHMgfAkwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAlIG9mIGNoaW1lcmljIHJlYWRzIHwJMC4wMCUKYGBgCgojIE11bHRpUUMKCldoaWxlIHRoZSBpbmZvcm1hdGlvbiBpcyBpbmNyZWRpYmx5IHVzZWZ1bCwgaXQgY2FuIGJlIHRlZGlvdXMgdG8gbG9vayBhdCB0aGUgcmVwb3J0IGZvciBlYWNoIHNhbXBsZSBzZXBhcmF0ZWx5LCB3aGlsZSBrZWVwaW5nIHRyYWNrIG9mIHdoYXQgdHJlbmRzIGVtZXJnZS4gSXQgd291bGQgYmUgbXVjaCBlYXNpZXIgdG8gbG9vayBhdCBhbGwgdGhlIGRhdGEgY29tcGlsZWQgaW50byBhIHNpbmdsZSByZXBvcnQuIFtNdWx0aVFDXShodHRwczovL211bHRpcWMuaW5mby8pIGlzIGEgdG9vbCB0aGF0IGRvZXMgZXhhY3RseSB0aGlzLgoKTXVsdGlRQyBpcyBkZXNpZ25lZCB0byBpbnRlcnByZXQgYW5kIGFnZ3JlZ2F0ZSByZXBvcnRzIGZyb20gW3ZhcmlvdXMgdG9vbHNdKGh0dHBzOi8vbXVsdGlxYy5pbmZvLyNzdXBwb3J0ZWQtdG9vbHMpIGFuZCBvdXRwdXQgYSBzaW5nbGUgcmVwb3J0IGFzIGFuIEhUTUwgZG9jdW1lbnQuCgojIyBNdWx0aVFDIERldGFpbHMKCk11bHRpUUMncyBtYWluIG91dHB1dCBpcyB0aGUgcmVwb3J0IGZpbGUgaW4gSFRNTCBmb3JtYXQuIFRoaXMgY2FuIGJlIHZpZXdlZCBpbiBhIHdlYiBicm93c2VyLiBBZGRpdGlvbmFsbHksIGl0IGNyZWF0ZXMgYSBgZGF0YWAgZGlyZWN0b3J5IHdpdGggdGV4dCBmaWxlcyBjb250YWluaW5nIHRoZSBkYXRhIHRoYXQgTXVsdGlRQyBnYXRoZXJlZCBkdXJpbmcgaXRzIGV4ZWN1dGlvbiAtIHRoaXMgc2FtZSBkYXRhIGlzIHdoYXQgaXMgc2hvd24gaW4gdGhlIHJlcG9ydC4KCkdpdmVuIGFuIG91dHB1dCBkaXJlY3Rvcnkgb3V0X211bHRpcWMsIHdlIHNob3VsZCBzZWUgc29tZXRoaW5nIGxpa2UgdGhlIGZvbGxvd2luZzoKCiAgICAjIGRpcmVjdG9yeSBvZiBtdWx0aXFjIGRhdGEgZmlsZXMKICAgIG91dF9tdWx0aXFjL211bHRpcWNfZGF0YS9tdWx0aXFjLmxvZwogICAgb3V0X211bHRpcWMvbXVsdGlxY19kYXRhL211bHRpcWNfZGF0YS5qc29uCiAgICBvdXRfbXVsdGlxYy9tdWx0aXFjX2RhdGEvbXVsdGlxY19nZW5lcmFsX3N0YXRzLnR4dAogICAgb3V0X211bHRpcWMvbXVsdGlxY19kYXRhL211bHRpcWNfcnNlbS50eHQKICAgIG91dF9tdWx0aXFjL211bHRpcWNfZGF0YS9tdWx0aXFjX3NvdXJjZXMudHh0CiAgICAjIG11bHRpcWMgcmVwb3J0CiAgICBvdXRfbXVsdGlxYy9tdWx0aXFjX3JlcG9ydC5odG1sCgoKSW4gYSBtb21lbnQgd2Ugd2lsbCBydW4gYG11bHRpcWNgLCBhbmQgaXQgd2lsbCBkZXRlY3QgdGhlc2UgcmVwb3J0cyBmcm9tIFNUQVIgYW5kIGluY2x1ZGUgdGhlbSBpbiB0aGUgcmVwb3J0LgoKSWYgd2UgdGhlbiBvcGVuIHRoZSBNdWx0aVFDIHJlcG9ydCAoSFRNTCksIHRoZSBuZXdseSBpbmNsdWRlZCBTVEFSIHNlY3Rpb24gd2lsbCBsb29rIHNvbWV0aGluZyBsaWtlIHRoZSBmb2xsb3dpbmc6Cgo8Y2VudGVyPgoKIVtFeGFtcGxlIG9mIFNUQVIgYWxpZ25tZW50IHN0YXRpc3RpY3MgaW4gTXVsdGlRQy5dKGltYWdlcy9tdWx0aXFjX3N0YXIucG5nKQpFeGFtcGxlIG9mIFNUQVIgYWxpZ25tZW50IHN0YXRpc3RpY3MgaW4gTXVsdGlRQy4KClNvdXJjZTogW011bHRpUUMgZXhhbXBsZSByZXBvcnRdKGh0dHBzOi8vbXVsdGlxYy5pbmZvL2V4YW1wbGVzL3JuYS1zZXEvbXVsdGlxY19yZXBvcnQuaHRtbCNzdGFyKQoKPC9jZW50ZXI+Cjxicj4KPGJyPgoKIyMgTXVsdGlRQyBFeGVyY2lzZToKCjEuIE5vdGUgdGhlIGNvbnRlbnRzIG9mIG91ciBhbmFseXNpcyBkaXJlY3RvcnksIGFuZCB0aG9zZSBvZiB0aGUgc3ViZGlyZWN0b3JpZXMgd2UndmUgY3JlYXRlZCBmb3IgZWFjaCB0YXNrCjIuIENvbnN0cnVjdCBhIE11bHRpUUMgY29tbWFuZCBhbmQgZXhlY3V0ZSBpdCBvbiB0aGUgZW50aXJlIGFuYWx5c2lzIGRpcmVjdG9yeQozLiBWZXJpZnkgdGhhdCB0aGUgTXVsdGlRQyByZXBvcnQgd2FzIGNyZWF0ZWQKCmBgYAojIEVuc3VyZSB0aGF0IHdlJ3JlIGluIG91ciBhbmFseXNpcyBkaXJlY3RvcnksIG5vdGUgdGhlIGNvbnRlbnRzCmNkIH4vUlNEX1NoZWxsL2FuYWx5c2lzCnRyZWUgLiB8IGxlc3MKIyBWaWV3IE11bHRpUUMgaGVscCBwYWdlCm11bHRpcWMgLS1oZWxwCiMgQ29uc3RydWN0IGEgTXVsdGlRQyBjb21tYW5kIGFuZCBleGVjdXRlIGl0Cm11bHRpcWMgLS1vdXRkaXIgb3V0X211bHRpcWNfYWxsIC4KIyBWZXJpZnkgdGhhdCB0aGUgb3V0cHV0IGZpbGVzIGFyZSBwcmVzZW50CmxzIC1sIG91dF9tdWx0aXFjX2FsbApgYGAKCldlIGp1c3QgbGVhcm5lZCBob3cgdG8gdmlldyBhbGwgb2Ygb3VyIFFDIGRldGFpbHMgaW4gb25lIHJlcG9ydCB3aXRoIHRoZSBoZWxwIG9mIE11bHRpUUMuIE11bHRpUUMgaXMgZXh0cmVtZWx5IGhlbHBmdWwsIGFuZCB3ZSdsbCBub3RpY2UgaG93IGl0IHdpbGwgaW5nZXN0IHZhcmlvdXMgZmlsZXMgZnJvbSB0aGUgZGlmZmVyZW50IHN0ZXBzIG9mIG91ciBwaXBlbGluZSwgYW5kIGNyZWF0ZSBzZXZlcmFsIG1vZHVsZXMgb2Ygc3VtbWFyeSBmaWd1cmVzIGZvciBlYWNoIG9mIHRoZW0uCjxicj4KPGJyPgoKIyMgVHJhbnNmZXIgTXVsdGlRQyBSZXBvcnRzIFdpdGggYHNjcGAgRXhlcmNpc2UKCkJlZm9yZSBzdGFydGluZyBvdXIgZmlsZSB0cmFuc2ZlciBleGVyY2lzZSwgd2Ugc2hvdWxkIG1ha2Ugc3VyZSB0aGF0IHdlIGFyZSBvbiB0aGUgc2FtZSBwYWdlLiBGb2xsb3cgdGhlIGxpbmsgYmVsb3c6CgpbTGluayB0byByZXBvcnQgdHJhbnNmZXIgZXhlcmNpc2VdKE1vZHVsZTA0X2JyZWFrb3V0MDNfZXguaHRtbCkKCgo8YnI+Cjxicj4KCiMjIENyZWF0aW5nIHRoZSBjb3VudCBtYXRyaXgKCldlIGhhdmUgdmlld2VkIHNvbWUgb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBxdWFudGlmaWNhdGlvbiByZXN1bHRzIGluZGl2aWR1YWxseS4gSXQgY2FuIGJlIHVzZWZ1bCB0byBjb21iaW5lIHRoZXNlIGV4cHJlc3Npb24gdmFsdWVzIGludG8gYSBjb3VudCBtYXRyaXguIFRoaXMgaXMgaGVscGZ1bCB3aGVuIGdhdGhlcmluZyBleHByZXNzaW9uLWxldmVsIFFDIG1ldHJpY3MsIGFzIHdlbGwgYXMgZm9yIGlucHV0IGludG8gYSBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIHByb2dyYW0gc3VjaCBhcyBERVNlcTIuCgpUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNvbWJpbmUgdGhlc2UgcmVzdWx0cyBpbnRvIGEgY291bnQgbWF0cml4LiBGb3IgdGhpcyB3b3Jrc2hvcCwgd2UnbGwgdXNlIGEgc21hbGwgcHl0aG9uIHNjcmlwdCB0byBgY29tYmluZS5weWAgdGhhdCB3ZSd2ZSBtYWRlIGZvciB0aGlzIHB1cnBvc2UuIFRvIHVuZGVyc3RhbmQgdGhlIHByb2Nlc3MgYSBiaXQgbW9yZSwgbGV0J3MgcmV2aWV3IHRoZSBgLmdlbmVzLnJlc3VsdHNgIGZpbGVzIHRoYXQgd2Ugd2FudCB0byBjb21iaW5lIGFuZCBkaXNjdXNzIHNvbWUgZGV0YWlscyBvZiB0aGUgc2NyaXB0LiBGaW5hbGx5LCB3ZSdsbCBlbmQgd2l0aCBhbiBleGVyY2lzZSBjcmVhdGluZyBhIGNvdW50IG1hdHJpeC4KCgpJZiB3ZSByZXZpZXcgdGhlICouZ2VuZXMucmVzdWx0cyBmaWxlcywgd2UgY2FuIHNlZSB2YXJpb3VzIGNvbHVtbnMgb2YgZGF0YSBvdXRwdXQgZnJvbSBSU0VNIHRoYXQgd2UgZGlzY3Vzc2VkIGluIHRoZSBsYXN0IG1vZHVsZS4KCiAgICAjIFJldmlldyBvZiAqLmdlbmVzLnJlc3VsdHMgZmlsZSBjb250ZW50cwogICAgZ2VuZV9pZCAgICAgICAgICAgICAgICAgdHJhbnNjcmlwdF9pZChzKSAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aCAgZWZmZWN0aXZlX2xlbmd0aCAgICAgICAgZXhwZWN0ZWRfY291bnQgIFRQTSAgICAgRlBLTQogICAgRU5TTVVTRzAwMDAwMDAwMDAxICAgICAgRU5TTVVTVDAwMDAwMDAwMDAxICAgICAgICAgICAgICAgICAgICAgIDMyNjIuMDAgMzExNi4yOCAgICAgICAgICAgICAgICAgNjAxLjAwICAgICAgICAgIDQ1LjUwICAgMzYuNzAKICAgIEVOU01VU0cwMDAwMDAwMDAwMyAgICAgIEVOU01VU1QwMDAwMDAwMDAwMyxFTlNNVVNUMDAwMDAxMTQwNDEgICA3OTkuNTAgIDY1My43OCAgICAgICAgICAgICAgICAgIDAuMDAgICAgICAgICAgICAwLjAwICAgIDAuMDAKCldlJ2xsIHRha2UgdGhlIGBleHBlY3RlZF9jb3VudGAgY29sdW1uIGZyb20gZWFjaCBzYW1wbGUncyBkYXRhLCBhbmQgY29tYmluZSB0aGVzZSBzbyB0aGF0IHdlIGhhdmUgYW4gYWdncmVnYXRlZCBkYXRhIG1hdHJpeCB3aXRoIGEgcm93IGZvciBlYWNoIGdlbmUgYW5kIGEgY29sdW1uIGZvciBlYWNoIHNhbXBsZS4KClRoZSBpbnB1dCBmb3IgdGhpcyBzdGVwIHdpbGwgYmUgdGhlIGRpcmVjdG9yeSBvZiAqLmdlbmVzLnJlc3VsdHMgZmlsZXMgZnJvbSBSU0VNLCBhbmQgdGhlIG91dHB1dCB3aWxsIGJlIGEgdGFiLXNlcGFyYXRlZCBjb3VudCBtYXRyaXggZmlsZSB3aGljaCB3ZSBjYW4gdXNlIGZvciBjb3VudC1sZXZlbCBRQyBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMuCgo8YnI+PGJyPgohW0NyZWF0aW5nIHRoZSBjb3VudCBtYXRyaXhdKGltYWdlcy9jb21iaW5lX2NvdW50cy5wbmcpCjxicj48YnI+Cgo8ZGV0YWlscz4KPHN1bW1hcnk+Q29udGVudHMgb2YgY29tYmluZS5weSBzY3JpcHQ8L3N1bW1hcnk+CgpbSGVyZV0oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vdHdzYWFyaS8xMmM1YWEyNzczMjkyYzA5YzE4MDlkNWEzZGI2NjkwMykgYXJlIHRoZSBjb250ZW50cyBvZiB0aGUgcHl0aG9uIHNjcmlwdCB3ZSdsbCB1c2UsIGBjb21iaW5lLnB5YDoKPC9kZXRhaWxzPgoKIyMgQ291bnQgTWF0cml4IEV4ZXJjaXNlOgoKMS4gVmlldyB0aGUgaGVscCBmaWxlIG9mIGBjb21iaW5lLnB5YAoyLiBDb25zdHJ1Y3QgLyBleGVjdXRlIGEgY29tbWFuZCB0byBjb21iaW5lIG91ciByZXN1bHRzIGludG8gYSBjb3VudCBtYXRyaXgKMy4gVmlldyB0aGUgcmVzdWx0aW5nIGNvdW50IG1hdHJpeAoKYGBgCiMgVmlldyB0aGUgaGVscCBmaWxlIG9mIGNvbWJpbmUucHkKY29tYmluZS5weSAtLWhlbHAKIyBDb25zdHJ1Y3QgYW5kIGV4ZWN1dGUgdGhlIGNvbW1hbmQgdG8gY29tYmluZS5weQpjb21iaW5lLnB5IC0taW5wdXRfcGF0aCAib3V0X3JzZW0vKi5nZW5lcy5yZXN1bHRzIiAtLW91dHB1dF9maWxlIGNvbWJpbmVkX2NvdW50cy50eHQgLWMgZXhwZWN0ZWRfY291bnQgLS1pZF9jb2x1bW5zIGdlbmVfaWQKIyBWaWV3IHRoZSByZXN1bHRpbmcgY291bnQgbWF0cml4Cmxlc3MgLVMgY29tYmluZWRfY291bnRzLnR4dApgYGAKCjxicj4KPGJyPgoKLS0tCgpUaGVzZSBtYXRlcmlhbHMgaGF2ZSBiZWVuIGFkYXB0ZWQgYW5kIGV4dGVuZGVkIGZyb20gbWF0ZXJpYWxzIGNyZWF0ZWQgYnkgdGhlIFtIYXJ2YXJkIENoYW4gQmlvaW5mb3JtYXRpY3MgQ29yZSAoSEJDKV0oaHR0cDovL2Jpb2luZm9ybWF0aWNzLnNwaC5oYXJ2YXJkLmVkdS8pLiBUaGVzZSBhcmUgb3BlbiBhY2Nlc3MgbWF0ZXJpYWxzIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgW0NyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gbGljZW5zZSAoQ0MgQlkgNC4wKV0oaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvNC4wLyksIHdoaWNoIHBlcm1pdHMgdW5yZXN0cmljdGVkIHVzZSwgZGlzdHJpYnV0aW9uLCBhbmQgcmVwcm9kdWN0aW9uIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoZSBvcmlnaW5hbCBhdXRob3IgYW5kIHNvdXJjZSBhcmUgY3JlZGl0ZWQuCgo8YnIvPgo8YnIvPgo8aHIvPgp8IFtQcmV2aW91cyBsZXNzb25dKE1vZHVsZTAzYl9BbGlnbm1lbnQuaHRtbCkgfCBbVG9wIG9mIHRoaXMgbGVzc29uXSgjdG9wKSB8IFtOZXh0IGxlc3Nvbl0oTW9kdWxlMDVfQWRkaXRpb25hbF9EZXRhaWxzLmh0bWwpIHwKfCA6LS0tIHwgOi0tLS06IHwgLS0tOiB8Cg==