Review of Yesterday
Very briefly, yesterday after learning about storage best practices and various storage options available to UMich researchers, we gained direct experience using these options by transferring our dataset to our own Data Den and Turbo storage locations.
We learned about a broadly-available and very generous compute package available to UMich researchers - the UMRCP - and now we’ll take a few moments to briefly review that.
We also discussed HPC compute clusters managed by ARC and had some opportunities to use the Great Lakes cluster, utilizing some of the web-based connection methods.
We talked about a pattern that may be new to us. In order to really use the HPC cluster, we had to request the appropriate resources from the system ahead of time. Let’s take a few moments to briefly review our experiences there. Today we’ll extend this idea.
Today we’re going to discuss more in depth about additional, powerful methods for connecting to the Great Lakes cluster, requesting resources, and ultimately running jobs in a more reproducible and automatable way. We’ll add more concrete detail about how this works, and gain experience through our exercises.
Great Lakes HPC
Again, we’ll provide the link to ARC’s general overview page on Great Lakes here: https://arc.umich.edu/greatlakes/
Let’s not go there right now, but I’d just like to point out that there’s a good deal of informational resources available on ARC’s website.
A More Detailed Look at How Great Lakes Works
We may have briefly mentioned the concept of a login node and a worker node when getting acquainted with Great Lakes, but we kept the explanation minimal, and only stated the fact that resources must be specified ahead of time for our tasks. With this figure we can dive a bit deeper into how this works.
Software Modules Available on Great Lakes
For our benefit, ARC has made available a plethora of widely used and oft-requested software tools, via their module system. We may refer to this module system as LMOD. We won’t cover the details of how it works, however we’ll demonstrate their usage and get a feel for using these LMOD modules on Great Lakes in our exercises.
The usage is very simple:
module load <name-of-module>
to enable a particular module
module unload <name-of-module>
to disable that module
module purge
to unload all modules
module keyword <keyword>
to search the modules for a particular keyword
module spider <name-of-module>
to view all versions of a particular software - many different versions may be available
We’ll use these command-line methods for exploring and using LMOD modules in our exercises shortly, but it may also be helpful to later review this link to all software modules available on various ARC HPC clusters.
Exercise - Log in to Great Lakes using ssh
Following along with the instructor, we’ll all log in to the Great Lakes cluster using ssh. Once there, we’ll get a brief introduction to using the module system.
Scheduled Jobs
We’ve taken a look into how, but now we’re going to go a little deeper on the why aspect - why is the HPC cluster set up this way?
Remember, this infrastructure must support the entire university. This means that we need a system to provide resources in a controlled, efficient, and reasonably fair way.
By having formal mechanisms for requesting resources, and utilizing a job queue and a scheduler to allocate resources and assign them to jobs, we can achieve these goals.
Interactive and Scripted Jobs
We’ve gained a little experience with some types of interactive jobs, for instance during our RStudio
demonstration or when we verified the file integrity of our BAMs with md5sum
using the OpenOnDemand ‘Basic Desktop’ app. During that exercise, we mentioned that there are other ways of doing this, which we’ll introduce here.
We’ve just logged in using SSH to the Great Lakes HPC, and now we’re all interacting with the login node. Thinking back to yesterday when we were writing the README file, we were similarly interacting with the login node. We mentioned that we can’t do anything compute-intensive here, and instead offered the OpenOnDemand apps as an alternative.
What we didn’t discuss was that where we are now - on the login node - we have the ability to request resources and run jobs via the command line. These are the powerful abilities that we alluded to, and we have two ways of doing this - interactive and scripted jobs.
Interactive Jobs
When we speak of interactive jobs on the command line, what we really mean is that we request resources in a special way so that once they are granted, our shell will be ‘sent’ into a worker node, and we will be able to interact with a command-line interface that is running inside of our worker node. We’ll have all of our desired resources, and we’ll be able to execute our compute-intensive tasks in an interactive way.
In some of the educational material provided by ARC, a lot of times they will introduce this idea later on, or briefly mentioned as an aside. However, we want to introduce it right away, because it’s very useful as a starting point, and is a great way to ‘right-size’ your scripted jobs, which we’ll cover in a moment.
When would we want to run an interactive job?
- When we’re not quite sure about the resources needed
- When we want to verify that our commands will work correctly
- When runtimes are relatively short and commands are fairly straightforward
How do we launch an interactive job from the command line? See the example here:
srun --pty --job-name=${USER}_calculate_md5sum --account=bioinf_wkshp_class --partition standard --mem=2000 --cpus-per-task=1 --time=00:30:00 /bin/bash
Scripted Jobs
When we talk about scripted jobs, generally we mean that inside of a file we place commands that we want to run in order - a script - along with the resource requirements.
In this case, when the resources become available, the contents of the script are executed on a worker node. There is no interaction with the running job. Any feedback that we’d normally receive in the terminal, can go to a log file. We’ll see an example of this.
When would we want to run scripted jobs?
- When we’re confident that our script/processes are correct and do what we want
- When we’re confident that we are requesting adequate resources
- When we want reproducibility
- When we want scalability, we have the ability of creating many scripted jobs ahead of time, and launching them all at once
What does a scripted job look like? See the dropdown section here:
SBATCH example
#!/bin/bash
# The interpreter used to execute the script
#“#SBATCH” directives that convey submission options:
#SBATCH --job-name=Hello_SBATCH
#SBATCH --cpus-per-task=1
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --mem-per-cpu=400m
#SBATCH --time=00:05:00
#SBATCH --account=bioinf_wkshp_class
#SBATCH --partition=standard
#SBATCH --output=/nfs/turbo/umms-bioinf-wkshp/workshop/home/%u/sleeping_bear/logs/%x-%j.log
# The application(s) to execute along with its input arguments and options:
hostname
pwd
echo "Hello, SBATCH!"
sleep 60
Briefly, we place our resource requirements at the top of our file - the preamble - and then we place our scripted commands until the end of the file. Once we have our file written - our SBATCH file - we’ll launch it with the command sbatch
. For example:
sbatch <name-of-SBATCH-file>
We’ll have a chance to try this in a moment, after we get warmed up with some interactive jobs.
Note: We’re just going to demonstrate some of the most salient bits of requesting resources. There are a lot more informational resources available at ARC’s SLURM user guide.
Exercise SBATCH Hello World
Following along with the instructor, we will inspect the hello_SBATCH.sh
shell script that each of us have in our $WORKSHOP_HOME
directory, review the preamble and body of it, and then submit it with sbatch
. Once it is running, we will use squeue
to view the status of the job. After it completes, we’ll view its log.
SBATCH Hello World - Solution
source /nfs/turbo/umms-bioinf-wkshp/workshop/home/${USER}/source_me_for_shortcut.txt
cd ${WORKSHOP_HOME}/project_analysis
sbatch ../intro_scripts/hello_SBATCH.sh
While the job is running, check the job queue with: squeue -u $USER
Exercise srun
with LMOD - Indexing our BAM Files
Following along with the instructor, we’ll launch an interactive job with srun
, load the samtools module, and use samtools to index our BAM files. This is a required step for some of our later processes, so we’ll take care of it now. Additionally, we should do a baseline sanity check of the number of entries in each sample.
srun
with LMOD Indexing BAMs - Solution
srun --pty --job-name=${USER}_index_bams --account=bioinf_wkshp_class --partition standard --mem=2000 --cpus-per-task=2 --time=00:30:00 /bin/bash
module load Bioinformatics; module load samtools
for f in *.bam ; do echo $f ; samtools index $f ; done
for f in *.bam ; do echo -n "${f}: " ; samtools view $f | wc -l ; done
Note: Type the command exit
to exit from a running interactive job. This will put you back onto the log in node and free up remaining resources.
Exercise srun
with LMOD - Filtering our BAM Files
Following along with the instructor, we’ll launch an interactive job with srun
, load the samtools module, and use samtools to filter our sample_A BAM file to select only alignments from chromosome 19.
srun
with LMOD Filtering BAM - Solution
srun --pty --job-name=${USER}_filter_sample_A --account=bioinf_wkshp_class --partition standard --mem=2000 --cpus-per-task=2 --time=00:30:00 /bin/bash
module load Bioinformatics; module load samtools
mkdir filter_lmod
samtools view -o filter_lmod/sample_A.chr19.bam input_bams/sample_A.genome.bam 19
Note: We re-create this same filtered BAM file in the additional SBATCH exercises below
Exercise SBATCH with LMOD - Filtering our BAM Files Cont’d
Following along with the instructor, we’ll create an SBATCH script that is similar to our previous srun
exercise, and use that to filter our sample_B BAM file in the same fashion. We will launch it with sbatch
and inspect the results. If it is successful, we will continue this exercise by creating and running two more SBATCH scripts for sample_C and sample_D.
SBATCH with LMOD Filtering BAMs Cont’d - Solution
cp ../intro_scripts/hello_SBATCH.sh scripts/filter_lmod_sample_A_sbatch.sh
nano scripts/filter_lmod_sample_A_sbatch.sh # Edit the file appropriately
sbatch scripts/filter_lmod_sample_A_sbatch.sh
When we’re happy with how sample_A turned out, we’ll copy our sbatch file and set it up for sample_B etc.
cp scripts/filter_lmod_sample_A_sbatch.sh scripts/filter_lmod_sample_B_sbatch.sh
nano scripts/filter_lmod_sample_B_sbatch.sh
sbatch scripts/filter_lmod_sample_B_sbatch.sh
Contents of filter_lmod_sample_A_sbatch.sh
#!/bin/bash
# The interpreter used to execute the script
#“#SBATCH” directives that convey submission options:
#SBATCH --job-name=Filter_sample_A
#SBATCH --cpus-per-task=2
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --mem-per-cpu=2000m
#SBATCH --time=00:20:00
#SBATCH --account=bioinf_wkshp_class
#SBATCH --partition=standard
#SBATCH --output=/nfs/turbo/umms-bioinf-wkshp/workshop/home/%u/project_analysis/logs/%x-%j.log
# The application(s) to execute along with its input arguments and options:
hostname
pwd
module load Bioinformatics
module load samtools
samtools view -o filter_lmod/sample_A.chr19.bam input_bams/sample_A.genome.bam 19
Note: Make sure to unload the samtools module, so that it does not interfere with the conda exercises in the next section!
LS0tCnRpdGxlOiAiR3JlYXQgTGFrZXMgSFBDIENsdXN0ZXIiCmF1dGhvcjogIlVNIEJpb2luZm9ybWF0aWNzIENvcmUiCm91dHB1dDoKICAgICAgICBodG1sX2RvY3VtZW50OgogICAgICAgICAgICBpbmNsdWRlczoKICAgICAgICAgICAgICAgIGluX2hlYWRlcjogaGVhZGVyLmh0bWwKICAgICAgICAgICAgdGhlbWU6IHBhcGVyCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgICAgICAgICAgZmlnX2NhcHRpb246IHRydWUKICAgICAgICAgICAgbWFya2Rvd246IEdGTQogICAgICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5eyAvKiBOb3JtYWwgICovCiAgICAgIGZvbnQtc2l6ZTogMTRwdDsKICB9CnByZSB7CiAgZm9udC1zaXplOiAxMnB0Cn0KPC9zdHlsZT4KCkluIHRoaXMgbW9kdWxlLCB3ZSB3aWxsOgoKKiBkaXNjdXNzIHRoZSBHcmVhdCBMYWtlcyBIUEMgY2x1c3RlciBhbmQgcmV2aWV3IGl0cyB1c2FnZQoqIGRpc2N1c3Mgc29mdHdhcmUgbW9kdWxlcyBhdmFpbGFibGUgb24gR3JlYXQgTGFrZXMKKiBsb2cgaW4gdG8gdGhlIEdyZWF0IExha2VzIGNsdXN0ZXIgdXNpbmcgYHNzaGAKKiByZXZpZXcgc29tZSBvZiB0aGUgZnVuZGFtZW50YWwgaGVscGVyIGNvbW1hbmRzIG9uIEdyZWF0IExha2VzCiogcmV2aWV3IFNCQVRDSCBhbmQgc3VibWl0IGpvYnMgZm9yIG91ciBhbmFseXNpcwoKIyMgUmV2aWV3IG9mIFllc3RlcmRheQoKVmVyeSBicmllZmx5LCB5ZXN0ZXJkYXkgYWZ0ZXIgbGVhcm5pbmcgYWJvdXQgc3RvcmFnZSBiZXN0IHByYWN0aWNlcyBhbmQgdmFyaW91cyBzdG9yYWdlIG9wdGlvbnMgYXZhaWxhYmxlIHRvIFVNaWNoIHJlc2VhcmNoZXJzLCB3ZSBnYWluZWQgZGlyZWN0IGV4cGVyaWVuY2UgdXNpbmcgdGhlc2Ugb3B0aW9ucyBieSB0cmFuc2ZlcnJpbmcgb3VyIGRhdGFzZXQgdG8gb3VyIG93biBEYXRhIERlbiBhbmQgVHVyYm8gc3RvcmFnZSBsb2NhdGlvbnMuCgo8YnI+CgpXZSBsZWFybmVkIGFib3V0IGEgYnJvYWRseS1hdmFpbGFibGUgYW5kIHZlcnkgZ2VuZXJvdXMgY29tcHV0ZSBwYWNrYWdlIGF2YWlsYWJsZSB0byBVTWljaCByZXNlYXJjaGVycyAtIHRoZSBVTVJDUCAtIGFuZCBub3cgd2UnbGwgdGFrZSBhIGZldyBtb21lbnRzIHRvIGJyaWVmbHkgcmV2aWV3IHRoYXQuCgohW10oaW1hZ2VzL01vZHVsZTAxX1VNUkNQX3Byb3ZpZGVzLnBuZykKCjxicj4KCldlIGFsc28gZGlzY3Vzc2VkIEhQQyBjb21wdXRlIGNsdXN0ZXJzIG1hbmFnZWQgYnkgQVJDIGFuZCBoYWQgc29tZSBvcHBvcnR1bml0aWVzIHRvIHVzZSB0aGUgR3JlYXQgTGFrZXMgY2x1c3RlciwgIHV0aWxpemluZyBzb21lIG9mIHRoZSB3ZWItYmFzZWQgY29ubmVjdGlvbiBtZXRob2RzLgoKV2UgdGFsa2VkIGFib3V0IGEgcGF0dGVybiB0aGF0IG1heSBiZSBuZXcgdG8gdXMuIEluIG9yZGVyIHRvIHJlYWxseSB1c2UgdGhlIEhQQyBjbHVzdGVyLCB3ZSBoYWQgdG8gcmVxdWVzdCB0aGUgYXBwcm9wcmlhdGUgcmVzb3VyY2VzIGZyb20gdGhlIHN5c3RlbSBhaGVhZCBvZiB0aW1lLiBMZXQncyB0YWtlIGEgZmV3IG1vbWVudHMgdG8gYnJpZWZseSByZXZpZXcgb3VyIGV4cGVyaWVuY2VzIHRoZXJlLiBUb2RheSB3ZSdsbCBleHRlbmQgdGhpcyBpZGVhLgoKPGJyPgoKVG9kYXkgd2UncmUgZ29pbmcgdG8gZGlzY3VzcyBtb3JlIGluIGRlcHRoIGFib3V0IGFkZGl0aW9uYWwsIHBvd2VyZnVsIG1ldGhvZHMgZm9yIGNvbm5lY3RpbmcgdG8gdGhlIEdyZWF0IExha2VzIGNsdXN0ZXIsIHJlcXVlc3RpbmcgcmVzb3VyY2VzLCBhbmQgdWx0aW1hdGVseSBydW5uaW5nIGpvYnMgaW4gYSBtb3JlIHJlcHJvZHVjaWJsZSBhbmQgYXV0b21hdGFibGUgd2F5LiBXZSdsbCBhZGQgbW9yZSBjb25jcmV0ZSBkZXRhaWwgYWJvdXQgaG93IHRoaXMgd29ya3MsIGFuZCBnYWluIGV4cGVyaWVuY2UgdGhyb3VnaCBvdXIgZXhlcmNpc2VzLgoKIyMgR3JlYXQgTGFrZXMgSFBDCgpBZ2Fpbiwgd2UnbGwgcHJvdmlkZSB0aGUgbGluayB0byBBUkMncyBnZW5lcmFsIG92ZXJ2aWV3IHBhZ2Ugb24gR3JlYXQgTGFrZXMgaGVyZTogaHR0cHM6Ly9hcmMudW1pY2guZWR1L2dyZWF0bGFrZXMvCgohW10oaW1hZ2VzL01vZHVsZTAzYl9hcmNfc2l0ZV9uYXZiYXIucG5nKQoKTGV0J3Mgbm90IGdvIHRoZXJlIHJpZ2h0IG5vdywgYnV0IEknZCBqdXN0IGxpa2UgdG8gcG9pbnQgb3V0IHRoYXQgdGhlcmUncyBhIGdvb2QgZGVhbCBvZiBpbmZvcm1hdGlvbmFsIHJlc291cmNlcyBhdmFpbGFibGUgb24gQVJDJ3Mgd2Vic2l0ZS4KCjxicj4KPGJyPgo8YnI+CgojIyMgQSBNb3JlIERldGFpbGVkIExvb2sgYXQgSG93IEdyZWF0IExha2VzIFdvcmtzCiFbXShpbWFnZXMvTW9kdWxlMDNfY2x1c3Rlcl9vdmVydmlldy5wbmcpCgpXZSBtYXkgaGF2ZSBicmllZmx5IG1lbnRpb25lZCB0aGUgY29uY2VwdCBvZiBhIGxvZ2luIG5vZGUgYW5kIGEgd29ya2VyIG5vZGUgd2hlbiBnZXR0aW5nIGFjcXVhaW50ZWQgd2l0aCBHcmVhdCBMYWtlcywgYnV0IHdlIGtlcHQgdGhlIGV4cGxhbmF0aW9uIG1pbmltYWwsIGFuZCBvbmx5IHN0YXRlZCB0aGUgZmFjdCB0aGF0IHJlc291cmNlcyBtdXN0IGJlIHNwZWNpZmllZCBhaGVhZCBvZiB0aW1lIGZvciBvdXIgdGFza3MuIFdpdGggdGhpcyBmaWd1cmUgd2UgY2FuIGRpdmUgYSBiaXQgZGVlcGVyIGludG8gaG93IHRoaXMgd29ya3MuCgo8YnI+CgojIyMgU29mdHdhcmUgTW9kdWxlcyBBdmFpbGFibGUgb24gR3JlYXQgTGFrZXMKCkZvciBvdXIgYmVuZWZpdCwgQVJDIGhhcyBtYWRlIGF2YWlsYWJsZSBhIHBsZXRob3JhIG9mIHdpZGVseSB1c2VkIGFuZCBvZnQtcmVxdWVzdGVkIHNvZnR3YXJlIHRvb2xzLCB2aWEgdGhlaXIgbW9kdWxlIHN5c3RlbS4gV2UgbWF5IHJlZmVyIHRvIHRoaXMgbW9kdWxlIHN5c3RlbSBhcyBMTU9ELiBXZSB3b24ndCBjb3ZlciB0aGUgZGV0YWlscyBvZiBob3cgaXQgd29ya3M8IS0tIExJVkVfTk9URTogbm90ZSB3ZSB3aWxsIHJldmlzaXQgdGhpcyBpZGVhIHdoZW4gY29tcGFyaW5nIHdpdGggb3RoZXIgc29mdHdhcmUgbWFuYWdlbWVudCBzb2x1dGlvbnMgbGF0ZXIgLS0+LCBob3dldmVyIHdlJ2xsIGRlbW9uc3RyYXRlIHRoZWlyIHVzYWdlIGFuZCBnZXQgYSBmZWVsIGZvciB1c2luZyB0aGVzZSBMTU9EIG1vZHVsZXMgb24gR3JlYXQgTGFrZXMgaW4gb3VyIGV4ZXJjaXNlcy4KClRoZSB1c2FnZSBpcyB2ZXJ5IHNpbXBsZToKCi0gYG1vZHVsZSBsb2FkIDxuYW1lLW9mLW1vZHVsZT5gIHRvIGVuYWJsZSBhIHBhcnRpY3VsYXIgbW9kdWxlCi0gYG1vZHVsZSB1bmxvYWQgPG5hbWUtb2YtbW9kdWxlPmAgdG8gZGlzYWJsZSB0aGF0IG1vZHVsZQotIGBtb2R1bGUgcHVyZ2VgIHRvIHVubG9hZCBhbGwgbW9kdWxlcwotIGBtb2R1bGUga2V5d29yZCA8a2V5d29yZD5gIHRvIHNlYXJjaCB0aGUgbW9kdWxlcyBmb3IgYSBwYXJ0aWN1bGFyIGtleXdvcmQKLSBgbW9kdWxlIHNwaWRlciA8bmFtZS1vZi1tb2R1bGU+YCB0byB2aWV3IGFsbCB2ZXJzaW9ucyBvZiBhIHBhcnRpY3VsYXIgc29mdHdhcmUgLSBtYW55IGRpZmZlcmVudCB2ZXJzaW9ucyBtYXkgYmUgYXZhaWxhYmxlCgpXZSdsbCB1c2UgdGhlc2UgY29tbWFuZC1saW5lIG1ldGhvZHMgZm9yIGV4cGxvcmluZyBhbmQgdXNpbmcgTE1PRCBtb2R1bGVzIGluIG91ciBleGVyY2lzZXMgc2hvcnRseSwgYnV0IGl0IG1heSBhbHNvIGJlIGhlbHBmdWwgdG8gbGF0ZXIgcmV2aWV3IHRoaXMgW2xpbmsgdG8gYWxsIHNvZnR3YXJlIG1vZHVsZXMgYXZhaWxhYmxlIG9uIHZhcmlvdXMgQVJDIEhQQyBjbHVzdGVyc10oaHR0cHM6Ly9hcmMudW1pY2guZWR1L3NvZnR3YXJlLykuCgojIyMgRXhlcmNpc2UgLSBMb2cgaW4gdG8gR3JlYXQgTGFrZXMgdXNpbmcgc3NoCgpGb2xsb3dpbmcgYWxvbmcgd2l0aCB0aGUgaW5zdHJ1Y3Rvciwgd2UnbGwgYWxsIGxvZyBpbiB0byB0aGUgR3JlYXQgTGFrZXMgY2x1c3RlciB1c2luZyBzc2guIE9uY2UgdGhlcmUsIHdlJ2xsIGdldCBhIGJyaWVmIGludHJvZHVjdGlvbiB0byB1c2luZyB0aGUgbW9kdWxlIHN5c3RlbS4KCjxicj4KCiMjIyBTY2hlZHVsZWQgSm9icwoKIVtdKGltYWdlcy9Nb2R1bGUwM19zY2hlZHVsZWRfam9icy5wbmcpCgpXZSd2ZSB0YWtlbiBhIGxvb2sgaW50byBob3csIGJ1dCBub3cgd2UncmUgZ29pbmcgdG8gZ28gYSBsaXR0bGUgZGVlcGVyIG9uIHRoZSB3aHkgYXNwZWN0IC0gd2h5IGlzIHRoZSBIUEMgY2x1c3RlciBzZXQgdXAgdGhpcyB3YXk/IAoKUmVtZW1iZXIsIHRoaXMgaW5mcmFzdHJ1Y3R1cmUgbXVzdCBzdXBwb3J0IHRoZSBlbnRpcmUgdW5pdmVyc2l0eS4gVGhpcyBtZWFucyB0aGF0IHdlIG5lZWQgYSBzeXN0ZW0gdG8gcHJvdmlkZSByZXNvdXJjZXMgaW4gYSBjb250cm9sbGVkLCBlZmZpY2llbnQsIGFuZCByZWFzb25hYmx5IGZhaXIgd2F5LgoKQnkgaGF2aW5nIGZvcm1hbCBtZWNoYW5pc21zIGZvciByZXF1ZXN0aW5nIHJlc291cmNlcywgYW5kIHV0aWxpemluZyBhIGpvYiBxdWV1ZSBhbmQgYSBzY2hlZHVsZXIgdG8gYWxsb2NhdGUgcmVzb3VyY2VzIGFuZCBhc3NpZ24gdGhlbSB0byBqb2JzLCB3ZSBjYW4gYWNoaWV2ZSB0aGVzZSBnb2Fscy4KCjwhLS0gTElWRV9OT1RFOiBSZWxhdGUgdGhlIGVmZmljaWVuY3kgb2YgdGhlIHNjaGVkdWxlZCBqb2JzIGluIHRoZSBmaWd1cmUuIElkbGUgdGltZSBpcyBtaW5pbWl6ZWQsIHdoaWxlIG1hbnkgZGlmZmVyZW50bHktc2l6ZWQgam9icyBjYW4gcnVuIHNpbXVsdGFuZW91c2x5IC0tPgoKPGJyPgoKIyMjIEludGVyYWN0aXZlIGFuZCBTY3JpcHRlZCBKb2JzCgpXZSd2ZSBnYWluZWQgYSBsaXR0bGUgZXhwZXJpZW5jZSB3aXRoIHNvbWUgdHlwZXMgb2YgaW50ZXJhY3RpdmUgam9icywgZm9yIGluc3RhbmNlIGR1cmluZyBvdXIgYFJTdHVkaW9gIGRlbW9uc3RyYXRpb24gb3Igd2hlbiB3ZSB2ZXJpZmllZCB0aGUgZmlsZSBpbnRlZ3JpdHkgb2Ygb3VyIEJBTXMgd2l0aCBgbWQ1c3VtYCB1c2luZyB0aGUgT3Blbk9uRGVtYW5kICdCYXNpYyBEZXNrdG9wJyBhcHAuIER1cmluZyB0aGF0IGV4ZXJjaXNlLCB3ZSBtZW50aW9uZWQgdGhhdCB0aGVyZSBhcmUgb3RoZXIgd2F5cyBvZiBkb2luZyB0aGlzLCB3aGljaCB3ZSdsbCBpbnRyb2R1Y2UgaGVyZS4KCldlJ3ZlIGp1c3QgbG9nZ2VkIGluIHVzaW5nIFNTSCB0byB0aGUgR3JlYXQgTGFrZXMgSFBDLCBhbmQgbm93IHdlJ3JlIGFsbCBpbnRlcmFjdGluZyB3aXRoIHRoZSBsb2dpbiBub2RlLiBUaGlua2luZyBiYWNrIHRvIHllc3RlcmRheSB3aGVuIHdlIHdlcmUgd3JpdGluZyB0aGUgUkVBRE1FIGZpbGUsIHdlIHdlcmUgc2ltaWxhcmx5IGludGVyYWN0aW5nIHdpdGggdGhlIGxvZ2luIG5vZGUuICBXZSBtZW50aW9uZWQgdGhhdCB3ZSBjYW4ndCBkbyBhbnl0aGluZyBjb21wdXRlLWludGVuc2l2ZSBoZXJlLCBhbmQgaW5zdGVhZCBvZmZlcmVkIHRoZSBPcGVuT25EZW1hbmQgYXBwcyBhcyBhbiBhbHRlcm5hdGl2ZS4KCldoYXQgd2UgZGlkbid0IGRpc2N1c3Mgd2FzIHRoYXQgd2hlcmUgd2UgYXJlIG5vdyAtIG9uIHRoZSBsb2dpbiBub2RlIC0gd2UgaGF2ZSB0aGUgYWJpbGl0eSB0byByZXF1ZXN0IHJlc291cmNlcyBhbmQgcnVuIGpvYnMgdmlhIHRoZSBjb21tYW5kIGxpbmUuIFRoZXNlIGFyZSB0aGUgcG93ZXJmdWwgYWJpbGl0aWVzIHRoYXQgd2UgYWxsdWRlZCB0bywgYW5kIHdlIGhhdmUgdHdvIHdheXMgb2YgZG9pbmcgdGhpcyAtIGludGVyYWN0aXZlIGFuZCBzY3JpcHRlZCBqb2JzLgoKPCEtLSBMSVZFX05PVEU6IFRoZXNlIGFyZSBib3RoIGV4YW1wbGVzIG9mIHNjaGVkdWxlZCBqb2JzLCBlaXRoZXIgd2F5IHdlJ2xsIHJlcXVlc3QgcmVzb3VyY2VzIGFuZCB1c2UgdGhlbSBvbmNlIGdyYW50ZWQgLS0+Cgo8YnI+CgojIyMgSW50ZXJhY3RpdmUgSm9icwoKV2hlbiB3ZSBzcGVhayBvZiBpbnRlcmFjdGl2ZSBqb2JzIG9uIHRoZSBjb21tYW5kIGxpbmUsIHdoYXQgd2UgcmVhbGx5IG1lYW4gaXMgdGhhdCB3ZSByZXF1ZXN0IHJlc291cmNlcyBpbiBhIHNwZWNpYWwgd2F5IHNvIHRoYXQgb25jZSB0aGV5IGFyZSBncmFudGVkLCBvdXIgc2hlbGwgd2lsbCBiZSAnc2VudCcgaW50byBhIHdvcmtlciBub2RlLCBhbmQgd2Ugd2lsbCBiZSBhYmxlIHRvIGludGVyYWN0IHdpdGggYSBjb21tYW5kLWxpbmUgaW50ZXJmYWNlIHRoYXQgaXMgcnVubmluZyBpbnNpZGUgb2Ygb3VyIHdvcmtlciBub2RlLiBXZSdsbCBoYXZlIGFsbCBvZiBvdXIgZGVzaXJlZCByZXNvdXJjZXMsIGFuZCB3ZSdsbCBiZSBhYmxlIHRvIGV4ZWN1dGUgb3VyIGNvbXB1dGUtaW50ZW5zaXZlIHRhc2tzIGluIGFuIGludGVyYWN0aXZlIHdheS4KCkluIHNvbWUgb2YgdGhlIGVkdWNhdGlvbmFsIG1hdGVyaWFsIHByb3ZpZGVkIGJ5IEFSQywgYSBsb3Qgb2YgdGltZXMgdGhleSB3aWxsIGludHJvZHVjZSB0aGlzIGlkZWEgbGF0ZXIgb24sIG9yIGJyaWVmbHkgbWVudGlvbmVkIGFzIGFuIGFzaWRlLiBIb3dldmVyLCB3ZSB3YW50IHRvIGludHJvZHVjZSBpdCByaWdodCBhd2F5LCBiZWNhdXNlIGl0J3MgdmVyeSB1c2VmdWwgYXMgYSBzdGFydGluZyBwb2ludCwgYW5kIGlzIGEgZ3JlYXQgd2F5IHRvICdyaWdodC1zaXplJyB5b3VyIHNjcmlwdGVkIGpvYnMsIHdoaWNoIHdlJ2xsIGNvdmVyIGluIGEgbW9tZW50LgoKV2hlbiB3b3VsZCB3ZSB3YW50IHRvIHJ1biBhbiBpbnRlcmFjdGl2ZSBqb2I/CgotIFdoZW4gd2UncmUgbm90IHF1aXRlIHN1cmUgYWJvdXQgdGhlIHJlc291cmNlcyBuZWVkZWQKLSBXaGVuIHdlIHdhbnQgdG8gdmVyaWZ5IHRoYXQgb3VyIGNvbW1hbmRzIHdpbGwgd29yayBjb3JyZWN0bHkKLSBXaGVuIHJ1bnRpbWVzIGFyZSByZWxhdGl2ZWx5IHNob3J0IGFuZCBjb21tYW5kcyBhcmUgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZAoKPCEtLSBMSVZFX05PVEU6IENvbW1hbmRzIGluc2lkZSBvZiB0aGUgaW50ZXJhY3RpdmUgam9iIG1heSBsYWNrIHJlcHJvZHVjaWJpbGl0eSwgd2UgaGF2ZSB0byBtYW51YWxseSByZWNvcmQgd2hhdCB3ZSBkbyB3aXRoaW4gdGhlIGludGVyYWN0aXZlIGpvYi4gLS0+CgpIb3cgZG8gd2UgbGF1bmNoIGFuIGludGVyYWN0aXZlIGpvYiBmcm9tIHRoZSBjb21tYW5kIGxpbmU/IFNlZSB0aGUgZXhhbXBsZSBoZXJlOgoKYGBgCnNydW4gLS1wdHkgLS1qb2ItbmFtZT0ke1VTRVJ9X2NhbGN1bGF0ZV9tZDVzdW0gLS1hY2NvdW50PWJpb2luZl93a3NocF9jbGFzcyAtLXBhcnRpdGlvbiBzdGFuZGFyZCAtLW1lbT0yMDAwIC0tY3B1cy1wZXItdGFzaz0xIC0tdGltZT0wMDozMDowMCAvYmluL2Jhc2gKYGBgCgo8YnI+CgojIyMgU2NyaXB0ZWQgSm9icwoKV2hlbiB3ZSB0YWxrIGFib3V0IHNjcmlwdGVkIGpvYnMsIGdlbmVyYWxseSB3ZSBtZWFuIHRoYXQgaW5zaWRlIG9mIGEgZmlsZSB3ZSBwbGFjZSBjb21tYW5kcyB0aGF0IHdlIHdhbnQgdG8gcnVuIGluIG9yZGVyIC0gYSBzY3JpcHQgLSBhbG9uZyB3aXRoIHRoZSByZXNvdXJjZSByZXF1aXJlbWVudHMuCgpJbiB0aGlzIGNhc2UsIHdoZW4gdGhlIHJlc291cmNlcyBiZWNvbWUgYXZhaWxhYmxlLCB0aGUgY29udGVudHMgb2YgdGhlIHNjcmlwdCBhcmUgZXhlY3V0ZWQgb24gYSB3b3JrZXIgbm9kZS4gVGhlcmUgaXMgbm8gaW50ZXJhY3Rpb24gd2l0aCB0aGUgcnVubmluZyBqb2I8IS0tKipMSVZFX05PVEU6IEV4Y2VwdCBtYXliZSB0byBvYnNlcnZlIGl0KiogLS0+LiBBbnkgZmVlZGJhY2sgdGhhdCB3ZSdkIG5vcm1hbGx5IHJlY2VpdmUgaW4gdGhlIHRlcm1pbmFsLCBjYW4gZ28gdG8gYSBsb2cgZmlsZS4gV2UnbGwgc2VlIGFuIGV4YW1wbGUgb2YgdGhpcy4KCldoZW4gd291bGQgd2Ugd2FudCB0byBydW4gc2NyaXB0ZWQgam9icz8KCi0gV2hlbiB3ZSdyZSBjb25maWRlbnQgdGhhdCBvdXIgc2NyaXB0L3Byb2Nlc3NlcyBhcmUgY29ycmVjdCBhbmQgZG8gd2hhdCB3ZSB3YW50Ci0gV2hlbiB3ZSdyZSBjb25maWRlbnQgdGhhdCB3ZSBhcmUgcmVxdWVzdGluZyBhZGVxdWF0ZSByZXNvdXJjZXMKLSBXaGVuIHdlIHdhbnQgcmVwcm9kdWNpYmlsaXR5Ci0gV2hlbiB3ZSB3YW50IHNjYWxhYmlsaXR5LCB3ZSBoYXZlIHRoZSBhYmlsaXR5IG9mIGNyZWF0aW5nIG1hbnkgc2NyaXB0ZWQgam9icyBhaGVhZCBvZiB0aW1lLCBhbmQgbGF1bmNoaW5nIHRoZW0gYWxsIGF0IG9uY2UKCjwhLS0gTElWRV9OT1RFOiBUaGVyZSBhcmUgbWFueSBzb2x1dGlvbnMgZm9yIHNjYWxhYmlsaXR5LCB0aGF0IGNhbiBsZXZlcmVnZSBzY3JpcHRlZCBqb2JzIHdpdGhvdXQgYXMgbXVjaCB1cGZyb250IHdvcmsuIENocmlzIHdpbGwgY292ZXIgdGhlc2UgdG9tb3Jyb3cgLS0+CgpXaGF0IGRvZXMgYSBzY3JpcHRlZCBqb2IgbG9vayBsaWtlPyBTZWUgdGhlIGRyb3Bkb3duIHNlY3Rpb24gaGVyZToKCjwhLS0gTElWRV9OT1RFOiBXZSdsbCBzZWUgdGhpcyBpbiBqdXN0IGEgbW9tZW50LCBubyBuZWVkIHRvIGxvb2sgYXQgaXQgaGVyZSAtLT4KCjxkZXRhaWxzPgo8c3VtbWFyeT5TQkFUQ0ggZXhhbXBsZTwvc3VtbWFyeT4KCmBgYAojIS9iaW4vYmFzaAojIFRoZSBpbnRlcnByZXRlciB1c2VkIHRvIGV4ZWN1dGUgdGhlIHNjcmlwdAoKI+KAnCNTQkFUQ0jigJ0gZGlyZWN0aXZlcyB0aGF0IGNvbnZleSBzdWJtaXNzaW9uIG9wdGlvbnM6CgojU0JBVENIIC0tam9iLW5hbWU9SGVsbG9fU0JBVENICiNTQkFUQ0ggLS1jcHVzLXBlci10YXNrPTEKI1NCQVRDSCAtLW5vZGVzPTEKI1NCQVRDSCAtLW50YXNrcy1wZXItbm9kZT0xCiNTQkFUQ0ggLS1tZW0tcGVyLWNwdT00MDBtCiNTQkFUQ0ggLS10aW1lPTAwOjA1OjAwCiNTQkFUQ0ggLS1hY2NvdW50PWJpb2luZl93a3NocF9jbGFzcwojU0JBVENIIC0tcGFydGl0aW9uPXN0YW5kYXJkCiNTQkFUQ0ggLS1vdXRwdXQ9L25mcy90dXJiby91bW1zLWJpb2luZi13a3NocC93b3Jrc2hvcC9ob21lLyV1L3NsZWVwaW5nX2JlYXIvbG9ncy8leC0lai5sb2cKCiMgVGhlIGFwcGxpY2F0aW9uKHMpIHRvIGV4ZWN1dGUgYWxvbmcgd2l0aCBpdHMgaW5wdXQgYXJndW1lbnRzIGFuZCBvcHRpb25zOgoKaG9zdG5hbWUKcHdkCgplY2hvICJIZWxsbywgU0JBVENIISIKCnNsZWVwIDYwCmBgYAoKPC9kZXRhaWxzPgoKPGJyPgoKQnJpZWZseSwgd2UgcGxhY2Ugb3VyIHJlc291cmNlIHJlcXVpcmVtZW50cyBhdCB0aGUgdG9wIG9mIG91ciBmaWxlIC0gdGhlIHByZWFtYmxlIC0gYW5kIHRoZW4gd2UgcGxhY2Ugb3VyIHNjcmlwdGVkIGNvbW1hbmRzIHVudGlsIHRoZSBlbmQgb2YgdGhlIGZpbGUuIE9uY2Ugd2UgaGF2ZSBvdXIgZmlsZSB3cml0dGVuIC0gb3VyIFNCQVRDSCBmaWxlIC0gd2UnbGwgbGF1bmNoIGl0IHdpdGggdGhlIGNvbW1hbmQgYHNiYXRjaGAuIEZvciBleGFtcGxlOgoKYHNiYXRjaCA8bmFtZS1vZi1TQkFUQ0gtZmlsZT5gCgpXZSdsbCBoYXZlIGEgY2hhbmNlIHRvIHRyeSB0aGlzIGluIGEgbW9tZW50LCBhZnRlciB3ZSBnZXQgd2FybWVkIHVwIHdpdGggc29tZSBpbnRlcmFjdGl2ZSBqb2JzLgoKPk5vdGU6IFdlJ3JlIGp1c3QgZ29pbmcgdG8gZGVtb25zdHJhdGUgc29tZSBvZiB0aGUgbW9zdCBzYWxpZW50IGJpdHMgb2YgcmVxdWVzdGluZyByZXNvdXJjZXMuIFRoZXJlIGFyZSBhIGxvdCBtb3JlIGluZm9ybWF0aW9uYWwgcmVzb3VyY2VzIGF2YWlsYWJsZSBhdCBbQVJDJ3MgU0xVUk0gdXNlciBndWlkZV0oaHR0cHM6Ly9hcmMudW1pY2guZWR1L2dyZWF0bGFrZXMvc2x1cm0tdXNlci1ndWlkZS8pLgoKPGJyPgoKIyMgRXhlcmNpc2UgU0JBVENIIEhlbGxvIFdvcmxkCgpGb2xsb3dpbmcgYWxvbmcgd2l0aCB0aGUgaW5zdHJ1Y3Rvciwgd2Ugd2lsbCBpbnNwZWN0IHRoZSBgaGVsbG9fU0JBVENILnNoYCBzaGVsbCBzY3JpcHQgdGhhdCBlYWNoIG9mIHVzIGhhdmUgaW4gb3VyIGAkV09SS1NIT1BfSE9NRWAgZGlyZWN0b3J5LCByZXZpZXcgdGhlIHByZWFtYmxlIGFuZCBib2R5IG9mIGl0LCBhbmQgdGhlbiBzdWJtaXQgaXQgd2l0aCBgc2JhdGNoYC4gT25jZSBpdCBpcyBydW5uaW5nLCB3ZSB3aWxsIHVzZSBgc3F1ZXVlYCB0byB2aWV3IHRoZSBzdGF0dXMgb2YgdGhlIGpvYi4gQWZ0ZXIgaXQgY29tcGxldGVzLCB3ZSdsbCB2aWV3IGl0cyBsb2cuCgo8ZGV0YWlscz4KPHN1bW1hcnk+U0JBVENIIEhlbGxvIFdvcmxkIC0gU29sdXRpb248L3N1bW1hcnk+Cgpgc291cmNlIC9uZnMvdHVyYm8vdW1tcy1iaW9pbmYtd2tzaHAvd29ya3Nob3AvaG9tZS8ke1VTRVJ9L3NvdXJjZV9tZV9mb3Jfc2hvcnRjdXQudHh0YAoKYGNkICR7V09SS1NIT1BfSE9NRX0vcHJvamVjdF9hbmFseXNpc2AKCmBzYmF0Y2ggLi4vaW50cm9fc2NyaXB0cy9oZWxsb19TQkFUQ0guc2hgCgpXaGlsZSB0aGUgam9iIGlzIHJ1bm5pbmcsIGNoZWNrIHRoZSBqb2IgcXVldWUgd2l0aDoKYHNxdWV1ZSAtdSAkVVNFUmAKCjwvZGV0YWlscz4KCjxicj4KCiMjIEV4ZXJjaXNlIGBzcnVuYCB3aXRoIExNT0QgLSBJbmRleGluZyBvdXIgQkFNIEZpbGVzCgpGb2xsb3dpbmcgYWxvbmcgd2l0aCB0aGUgaW5zdHJ1Y3Rvciwgd2UnbGwgbGF1bmNoIGFuIGludGVyYWN0aXZlIGpvYiB3aXRoIGBzcnVuYCwgbG9hZCB0aGUgc2FtdG9vbHMgbW9kdWxlLCBhbmQgdXNlIHNhbXRvb2xzIHRvIGluZGV4IG91ciBCQU0gZmlsZXMuIFRoaXMgaXMgYSByZXF1aXJlZCBzdGVwIGZvciBzb21lIG9mIG91ciBsYXRlciBwcm9jZXNzZXMsIHNvIHdlJ2xsIHRha2UgY2FyZSBvZiBpdCBub3cuIEFkZGl0aW9uYWxseSwgd2Ugc2hvdWxkIGRvIGEgYmFzZWxpbmUgc2FuaXR5IGNoZWNrIG9mIHRoZSBudW1iZXIgb2YgZW50cmllcyBpbiBlYWNoIHNhbXBsZS4KCjxkZXRhaWxzPgo8c3VtbWFyeT5gc3J1bmAgd2l0aCBMTU9EIEluZGV4aW5nIEJBTXMgLSBTb2x1dGlvbjwvc3VtbWFyeT4KCmBzcnVuIC0tcHR5IC0tam9iLW5hbWU9JHtVU0VSfV9pbmRleF9iYW1zIC0tYWNjb3VudD1iaW9pbmZfd2tzaHBfY2xhc3MgLS1wYXJ0aXRpb24gc3RhbmRhcmQgLS1tZW09MjAwMCAtLWNwdXMtcGVyLXRhc2s9MiAtLXRpbWU9MDA6MzA6MDAgL2Jpbi9iYXNoYAoKYG1vZHVsZSBsb2FkIEJpb2luZm9ybWF0aWNzOyBtb2R1bGUgbG9hZCBzYW10b29sc2AKCmBmb3IgZiBpbiAqLmJhbSA7IGRvIGVjaG8gJGYgOyBzYW10b29scyBpbmRleCAkZiA7IGRvbmVgCgo8IS0tIExJVkVfTk9URTogTmVlZCB0byBkbyBhIGJhc2VsaW5lIHNhbml0eSBjaGVjayBoZXJlOiAtLT4KYGZvciBmIGluICouYmFtIDsgZG8gZWNobyAtbiAiJHtmfTogIiA7IHNhbXRvb2xzIHZpZXcgJGYgfCB3YyAtbCA7IGRvbmVgCgo+Tm90ZTogVHlwZSB0aGUgY29tbWFuZCBgZXhpdGAgdG8gZXhpdCBmcm9tIGEgcnVubmluZyBpbnRlcmFjdGl2ZSBqb2IuIFRoaXMgd2lsbCBwdXQgeW91IGJhY2sgb250byB0aGUgbG9nIGluIG5vZGUgYW5kIGZyZWUgdXAgcmVtYWluaW5nIHJlc291cmNlcy4KCjwvZGV0YWlscz4KCjxicj4KCiMjIEV4ZXJjaXNlIGBzcnVuYCB3aXRoIExNT0QgLSBGaWx0ZXJpbmcgb3VyIEJBTSBGaWxlcwoKRm9sbG93aW5nIGFsb25nIHdpdGggdGhlIGluc3RydWN0b3IsIHdlJ2xsIGxhdW5jaCBhbiBpbnRlcmFjdGl2ZSBqb2Igd2l0aCBgc3J1bmAsIGxvYWQgdGhlIHNhbXRvb2xzIG1vZHVsZSwgYW5kIHVzZSBzYW10b29scyB0byBmaWx0ZXIgb3VyIHNhbXBsZV9BIEJBTSBmaWxlIHRvIHNlbGVjdCBvbmx5IGFsaWdubWVudHMgZnJvbSBjaHJvbW9zb21lIDE5LgoKPGRldGFpbHM+CjxzdW1tYXJ5PmBzcnVuYCB3aXRoIExNT0QgRmlsdGVyaW5nIEJBTSAtIFNvbHV0aW9uPC9zdW1tYXJ5PgoKYHNydW4gLS1wdHkgLS1qb2ItbmFtZT0ke1VTRVJ9X2ZpbHRlcl9zYW1wbGVfQSAtLWFjY291bnQ9YmlvaW5mX3drc2hwX2NsYXNzIC0tcGFydGl0aW9uIHN0YW5kYXJkIC0tbWVtPTIwMDAgLS1jcHVzLXBlci10YXNrPTIgLS10aW1lPTAwOjMwOjAwIC9iaW4vYmFzaGAKCmBtb2R1bGUgbG9hZCBCaW9pbmZvcm1hdGljczsgbW9kdWxlIGxvYWQgc2FtdG9vbHNgCgpgbWtkaXIgZmlsdGVyX2xtb2RgCgpgc2FtdG9vbHMgdmlldyAtbyBmaWx0ZXJfbG1vZC9zYW1wbGVfQS5jaHIxOS5iYW0gaW5wdXRfYmFtcy9zYW1wbGVfQS5nZW5vbWUuYmFtIDE5YAoKPk5vdGU6IFdlIHJlLWNyZWF0ZSB0aGlzIHNhbWUgZmlsdGVyZWQgQkFNIGZpbGUgaW4gdGhlIGFkZGl0aW9uYWwgU0JBVENIIGV4ZXJjaXNlcyBiZWxvdwoKPC9kZXRhaWxzPgoKPGJyPgoKIyMgRXhlcmNpc2UgU0JBVENIIHdpdGggTE1PRCAtIEZpbHRlcmluZyBvdXIgQkFNIEZpbGVzIENvbnQnZAoKRm9sbG93aW5nIGFsb25nIHdpdGggdGhlIGluc3RydWN0b3IsIHdlJ2xsIGNyZWF0ZSBhbiBTQkFUQ0ggc2NyaXB0IHRoYXQgaXMgc2ltaWxhciB0byBvdXIgcHJldmlvdXMgYHNydW5gIGV4ZXJjaXNlLCBhbmQgdXNlIHRoYXQgdG8gZmlsdGVyIG91ciBzYW1wbGVfQiBCQU0gZmlsZSBpbiB0aGUgc2FtZSBmYXNoaW9uLiBXZSB3aWxsIGxhdW5jaCBpdCB3aXRoIGBzYmF0Y2hgIGFuZCBpbnNwZWN0IHRoZSByZXN1bHRzLiBJZiBpdCBpcyBzdWNjZXNzZnVsLCB3ZSB3aWxsIGNvbnRpbnVlIHRoaXMgZXhlcmNpc2UgYnkgY3JlYXRpbmcgYW5kIHJ1bm5pbmcgdHdvIG1vcmUgU0JBVENIIHNjcmlwdHMgZm9yIHNhbXBsZV9DIGFuZCBzYW1wbGVfRC4KCjxkZXRhaWxzPgo8c3VtbWFyeT5TQkFUQ0ggd2l0aCBMTU9EIEZpbHRlcmluZyBCQU1zIENvbnQnZCAtIFNvbHV0aW9uPC9zdW1tYXJ5PgoKYGNwIC4uL2ludHJvX3NjcmlwdHMvaGVsbG9fU0JBVENILnNoIHNjcmlwdHMvZmlsdGVyX2xtb2Rfc2FtcGxlX0Ffc2JhdGNoLnNoYAoKYG5hbm8gc2NyaXB0cy9maWx0ZXJfbG1vZF9zYW1wbGVfQV9zYmF0Y2guc2ggIyBFZGl0IHRoZSBmaWxlIGFwcHJvcHJpYXRlbHlgCgpgc2JhdGNoIHNjcmlwdHMvZmlsdGVyX2xtb2Rfc2FtcGxlX0Ffc2JhdGNoLnNoYAoKV2hlbiB3ZSdyZSBoYXBweSB3aXRoIGhvdyBzYW1wbGVfQSB0dXJuZWQgb3V0LCB3ZSdsbCBjb3B5IG91ciBzYmF0Y2ggZmlsZSBhbmQgc2V0IGl0IHVwIGZvciBzYW1wbGVfQiBldGMuCgpgY3Agc2NyaXB0cy9maWx0ZXJfbG1vZF9zYW1wbGVfQV9zYmF0Y2guc2ggc2NyaXB0cy9maWx0ZXJfbG1vZF9zYW1wbGVfQl9zYmF0Y2guc2hgCgpgbmFubyBzY3JpcHRzL2ZpbHRlcl9sbW9kX3NhbXBsZV9CX3NiYXRjaC5zaGAKCmBzYmF0Y2ggc2NyaXB0cy9maWx0ZXJfbG1vZF9zYW1wbGVfQl9zYmF0Y2guc2hgCgo8YnI+CgpDb250ZW50cyBvZiBgZmlsdGVyX2xtb2Rfc2FtcGxlX0Ffc2JhdGNoLnNoYApgYGAKIyEvYmluL2Jhc2gKIyBUaGUgaW50ZXJwcmV0ZXIgdXNlZCB0byBleGVjdXRlIHRoZSBzY3JpcHQKCiPigJwjU0JBVENI4oCdIGRpcmVjdGl2ZXMgdGhhdCBjb252ZXkgc3VibWlzc2lvbiBvcHRpb25zOgoKI1NCQVRDSCAtLWpvYi1uYW1lPUZpbHRlcl9zYW1wbGVfQQojU0JBVENIIC0tY3B1cy1wZXItdGFzaz0yCiNTQkFUQ0ggLS1ub2Rlcz0xCiNTQkFUQ0ggLS1udGFza3MtcGVyLW5vZGU9MQojU0JBVENIIC0tbWVtLXBlci1jcHU9MjAwMG0KI1NCQVRDSCAtLXRpbWU9MDA6MjA6MDAKI1NCQVRDSCAtLWFjY291bnQ9YmlvaW5mX3drc2hwX2NsYXNzCiNTQkFUQ0ggLS1wYXJ0aXRpb249c3RhbmRhcmQKI1NCQVRDSCAtLW91dHB1dD0vbmZzL3R1cmJvL3VtbXMtYmlvaW5mLXdrc2hwL3dvcmtzaG9wL2hvbWUvJXUvcHJvamVjdF9hbmFseXNpcy9sb2dzLyV4LSVqLmxvZwoKIyBUaGUgYXBwbGljYXRpb24ocykgdG8gZXhlY3V0ZSBhbG9uZyB3aXRoIGl0cyBpbnB1dCBhcmd1bWVudHMgYW5kIG9wdGlvbnM6Cgpob3N0bmFtZQpwd2QKCm1vZHVsZSBsb2FkIEJpb2luZm9ybWF0aWNzCm1vZHVsZSBsb2FkIHNhbXRvb2xzCnNhbXRvb2xzIHZpZXcgLW8gZmlsdGVyX2xtb2Qvc2FtcGxlX0EuY2hyMTkuYmFtIGlucHV0X2JhbXMvc2FtcGxlX0EuZ2Vub21lLmJhbSAxOQpgYGAKCjwvZGV0YWlscz4KCjxicj4KCjwhLS0gTElWRV9OT1RFOiBXZSB3b3VsZCBsaWtlIHRvIGFsc28gdmlzdWFsaXplIG91ciBzYW1wbGVzLCB3ZSBrbm93IHRoYXQgd2UgY2FuIHVzZSBgYmFtQ292ZXJhZ2VgIGZyb20gdGhlIGBkZWVwdG9vbHMgcGFja2FnZSwgaG93ZXZlciBpdCdzIG5vdCBhdmFpbGFibGUgYXMgYW4gTE1PRCBtb2R1bGUuIC0tPgoKPCEtLSBMSVZFX05PVEU6IE1ha2Ugc3VyZSB3ZSB1bmxvYWQgc2FtdG9vbHMgbW9kdWxlISAtLT4KCj5Ob3RlOiBNYWtlIHN1cmUgdG8gdW5sb2FkIHRoZSBzYW10b29scyBtb2R1bGUsIHNvIHRoYXQgaXQgZG9lcyBub3QgaW50ZXJmZXJlIHdpdGggdGhlIGNvbmRhIGV4ZXJjaXNlcyBpbiB0aGUgbmV4dCBzZWN0aW9uIQoKLS0tCgoKfCBbUHJldmlvdXMgbGVzc29uXShNb2R1bGUwM2Ffc25lYWtfcGVla19ncmVhdF9sYWtlcy5odG1sKSB8IFtUb3Agb2YgdGhpcyBsZXNzb25dKCN0b3ApIHwgW05leHQgbGVzc29uXShNb2R1bGUwNF9zb2Z0d2FyZV9tYW5hZ2VtZW50X2NvbmRhLmh0bWwpIHwKfCA6LS0tIHwgOi0tLS06IHwgLS0tOiB8Cg==