In this module, we will:
- discuss reproducible computing in general
- discuss storage best practices for raw data, anlaysis files,
scripts, etc.
- learn about several institutional storage options (and associated
compute resources)
- learn about the UMRCP and how to request it
- make a plan for enrolling PIs in UMRCP and enabling access to all
researchers
Reproducible Computing
Reproducible computing has become increasingly important in recent
years. As experimental data volumes have increased exponentially, and as
research endeavors have employed more complicated analyses over time,
computation has become a fundamental aspect of virtually every type of
research.
Reproducibility itself is an integral part of the scientific process.
We describe our experiments with sufficient detail so that they can be
replicated and our findings can be confirmed by others, and so that
eventually others may build upon them.
So taking these two things together, the increasing use of computing
in research and the inherent need for reproducibility in the scientific
process, we can start to understand the importance of reproducible
computing.
There are some challenges we must overcome in this realm. When we try
to employ our typical methodologies for general scientific
reproducibility, they may not be sufficient to truly enable others to
recreate our work. In many cases, in order to credibly validate an
analysis, we must be able to not only see and understand the steps of an
analysis, but also to use the same software with the same input data and
perform these same data manipulations ourselves. Trying to achieve this
task with only a descriptive summary of our analysis methods,
particularly when using cutting-edge academic software, may often
produce little more than frustration.
Let’s take a moment to think about our own experiences with this
topic. Can we think of experiences where we encountered challenges while
trying to reproduce the analysis of others? Or while trying to share our
own analyses with colleagues?
There are a number of tools and techniques that have emerged to
address some of these challenges, and to really lower the barrier to
sharing and reproducing our results.
In this workshop we’ll discuss these tools and techniques, we’ll
provide specific guidance for University of Michigan researchers to
address reproducibility concerns, and we’ll use practical examples along
the way to gain experience and emphasize the concepts that we learn.
Storage Best Practices
One simple way to organize our thinking about storage best practices
is to divide the topic into raw data considerations, and considerations
for analysis projects. By separating and focusing on those two aspects,
we can effectively address many of the challenges associated with
each.
Note: The importance of documentation is universal to all aspects of
reproducible research. In considering best practices both for our raw
data and for our analysis projects, we will emphasize the importance of
documentation!
A Generalized Data Flow
Raw Data
When considering best practices for raw data storage, we can
generally orient ourselves around one task - ensure that the data are
safe.
Safe from:
- Accidental deletion
- Hardware failure
- Loss of access
With this in mind, we recommend placing your raw experimental data
into a specific designated location which is solely
dedicated to storing your raw data.
Soon we’ll talk about specific options for UMich researchers, but for
now we’ll just speak of the general process. Data that cannot easily be
re-obtained should be treated with great care. By following the
recommendations here, we can achieve this and have peace of mind that we
are preserving our raw data and our capabilities for reproducible
research well into the future.
Recommended:
- Designated location for storing raw data
- Limit write access of stored data files
- Use institutional storage
- Large file sizes and large total allocations
- Long-term support
- Hardware redundancy
- Location redundancy
Another thing to mention for raw data best practices is the procedure
of checking file integrity. Whenever transferring data from one storage
location to another, and especially while doing so over a network
connection, it is good practice to follow up with a file integrity
check. Briefly, we use software to inspect our files and determine if
any of the contents have changed. In a later module we’ll have a chance
to try this ourselves, using the md5sum
utility. This is a
relatively efficient way of verifying file integrity after a file
transfer.
Analysis Projects
We can begin thinking of our next task - handling data and organizing
files and artifacts for our analysis - by starting with the idea of the
data flow described above. One of the first tasks in this area is to set
up a new location for your analysis and make a copy of your raw data
there.
Some considerations:
- Fast storage, well suited for computation
- Project organization that facilitates reproducibility
- In-progress analyses, cleanup procedures, and end-to-end repeatable
analyses
When we think about fast storage that is well suited for computation,
we mostly contrast that with our long-term archival storage. A storage
option is well suited for computation if it is accessible via
high-throughput connection to sufficiently powerful processing hardware.
The speed of reading and writing from this location can greatly affect
processing times of your analysis, depending on the steps involved.
In terms of project organization, generally we want to have distinct
locations for specific purposes, and preferably organizing things in a
consistent manner for all of our projects.
In a particular project, you may want:
input_data
directory for copy of raw data
scripts
directory for analysis scripts
- Directories for intermediates, log files, and final outputs
README.txt
for the project
- Optional
docs
directory for extensive documentation,
supporting works, etc.
A useful idea for our project directory layouts is to think about the
project life cycle and work towards an end-goal of a reproducible
analysis. While at the beginning of an analysis many things may be
flexible, at the end we will want to be able to re-execute the analysis
starting from the raw input data and running all the way until it
produces the final outputs.
Taking time to segregate specific efforts within a project,
documenting our steps as we perform in-progress analyses, performing
cleanups where needed, and similar efforts will aid us as we work
towards that goal.
Think ahead when designing the layout of your projects. If you will
be trying several related analysis approaches using the same input data,
but intend on using results from only one of the evaluated methods, it
may make sense to intentionally subdivide the contents of your project
directory accordingly. If you have several distinct analyses that may
use the same input data, then perhaps creating separate projects for
each of them will make the most sense. It’s hard to be totally
prescriptive when making recommendations here, but through our example
we hope to spark the kinds of conversations and the types of thinking
that are required here.
One last note on handling and organizing analysis projects - use some
form of identification system for projects in your lab. This simplifies
communication and record keeping, in addition to the organizational
benefits.
Some ideas for project identification systems:
- Codenames
- Alphanumeric IDs
Storage Options for UMich Researchers
We’ve discussed best practices for data, analysis intermediates and
scripts, etc. in general terms, but now we’ll have the opportunity to
revisit these ideas while highlighting specific options and
recommendations for UMich researchers. By the end of this module, we
will understand our numerous storage options available to us. Looking
forward to future modules, we’ll also run exercises that interact with
some of these storage allocations as we proceed, including Data Den and
its unique characteristics and usage patterns.
What is ARC?
The vast majority of computing resources we’ll be discussing in the
workshop are provided and managed by ARC - Advanced Research Computing
at University of Michigan. The shared computing cluster that we’ll be
using in the workshop is run by ARC, and the storage allocations
likewise are provided by ARC. Their mission is to provide university
researchers with the advanced computing resources that they need, and
they’ve been working with research groups in various compute intensive
fields to achieve this.
Later in this module we’ll discuss in detail how to request resources
through ARC, but for now we’ll focus on the storage topic and cover some
important storage options that ARC provides.
Data Den
Data Den is a low-cost, highly durable storage system operated by
ARC.
- Tape-based archival storage
- The largest and most affordable storage available through ARC.
- Can only access this indirectly
- i.e. use Globus to interface with this storage.
Note: Data Den has a file size limitation - it does not handle large
amounts of small files. Optimal file size is in the multi-gigabyte
range. The limitation 10,000 files per TB of storage.
Turbo
Turbo is a high-capacity, reliable, and fast storage system operated
by ARC. It is more costly than Data Den.
- More costly than Data Den
- Tuned for files moderate to large in size, but can also easily
accomodate small files
- Can be accessed through the High-Performance Computing (HPC)
cluster
Fast storage like Turbo is well-equipped for computing direcly from
it. Turbo supports fast read/write times, and is an excellent place to
perform analyses.
Turbo and Data Den - Cost Difference
We discussed above that Data Den is slow, unsuited for analysis, yet
cost-effective, while Turbo is fast, well-tuned for analysis, and more
costly. To put some numbers to this price discussion, see the following
table of cost per TB per year:
Turbo |
$77.88 |
$156.22 |
Data Den |
NA |
$20.04 |
Notice that Turbo storage is about 8x more costly than Data Den for
the same amount of replicated storage.
Note: Data Den is only available in the replicated format.
Home, Scratch, tmp, and others
- Home directory (80 GB quota)
- Scratch directory (10 TB and 1,000,000 file quota)
- /scratch/account_root/account/uniqname
- Not persistent over time
- Automatically deleted if not accessed in 60 days
- Local disk (4 TB shared)
- /tmp
- Not persistent across machines
Institutional Storage vs Other Storage
Turbo |
Laptop Storage |
Data Den |
Storage on a Shared Lab Computer |
Home / Scratch* |
Portable Hard Drive / Flash Drive |
MiStorage |
Cloud Storage |
UMRCP
The figure above highlights the most important and impressive details
of the UMRCP, but you can find full details of the resources offered
through this program on the UMRCP
page of ARC’s website.
Signing up for the UMRCP
Within that site, there is another page that I highly recommend as a
great place to start - the UMRCP
Requesting Resources Guide. There you’ll find details about the
signup process. After signing up, you’ll be able to use some of the
numerous compute nodes available through ARC, as well as the various
storage tiers described above.
Additional Resources Available Through HITS RCI
In addition to the resources provided through the UMRCP, some
researchers within the medical system will have additonal resources
available through UM Health Information Technology & Services
(HITS). Through strategic investments in High Performance Computing by
Michigan Medicine, eligible researchers can enjoy additional allocations
for the described resources - most notably unlimited Data Den
storage.
In the documentation for the UMRCP and the UMRCI, you’ll see that
they recommend first using the UMRCP resources (available to all
university researchers) and then transitioning to these additional HITS
UMRCI resources (available to Michigan Medicine researchers) when
possible. In any case, since these allocations are managed by ARC for
all univerisity researchers - Michigan Medicne or otherwise - you’ll be
using the same forms and procedures to request resources and use them.
However, the billing details may change depending on this
eligibility.
Link
to HITS page on UMRCI
Great Lakes, Armis2, and Lighthouse Clusters
This module overall is primarily focused on storage-related topics.
We’ve briefly mentioned that in addition to storage resources, ARC also
provides access to high-performance computing (HPC) hardware as well.
While in this workshop we’ll just be focusing on one of them, in fact
there are several HPC clusters that are available to UMich researchers,
in order to meet various needs.
When discussing research needs, especially in anticipation of
requesting UMRCP resources and filling out the required form, we should
discuss a little bit about three HPC options provided through ARC:
- Great Lakes
- Armis2 (HIPAA-aligned)
- Lighthouse (Researcher-owned hardware)
We’ll be discussing Great Lakes at length throughout this workshop
and using it for our example analyses. We can think of it as a
general-purpose HPC cluster, which is suitable for many different kinds
of research.
Armis2 is similar in feel to the Great Lakes cluster, except it is
configured with specific security measures in place to enable analysis
of sensitive data, such as export-controlled or HIPAA protected data.
When filling out the UMRCP form, you can make selections for sensitive
data needs, which will provide CPU hours on Armis2 and associated
storage. We’ll see later, that we have flexibility in how we allocate
resources between e.g. Great Lakes and Armis2.
Note: There is a separate, security-enhanced Turbo allocation that is
also HIPAA aligned that should be used with Armis2.
Lighthouse is also similar in feel to the Great Lakes cluster, except
it is a cluster comprised entirely of researcher-owned hardware.
Contrasting this with Great Lakes where we are only responsible for the
cost of the resources we use, on Lighthouse, a researcher will fund the
entirety of the hardware and receive 100% of its availability. This can
be a good choice for researchers who are expected to have near-constant
compute usage needs, or who require instant availability of HPC
resources.
Main ideas:
- PI must be the one to fill out form
- PI will automatically become an administrator
- Others can become administrators (lab manager) or members
Administrators vs Users
PI |
✅ |
✅ |
⏳ |
⏳ |
✅ |
Lab Manager |
✅ |
✅ |
⏳ |
⏳ |
✅ |
Grad Student |
|
|
✅ |
✅ |
|
Legend:
✅ = Frequent
⏳ = Occasional
Resource Management Portal
A key part of how we will manage our ARC resources is through their
Resource Management Portal, shown here.
This portal can be found at https://portal.arc.umich.edu.
Let’s not go there just yet, but discuss what we see in this
screenshot, and then move on to the exercise. We’ll learn about some of
the differences that we may see depending on our current status and
existing resources, and we’ll learn that there are some differences in
the best way to request UMRCP resources depending on these details.
Exercise: Make a Game Plan for UMRCP
In this exercise we will determine the needs for UMRCP enrollment by
audience & their PIs.
There are two video links below. There’s a decent amount of overlap
in the content, and the main ideas are pretty similar. In either case,
we will be filling out the UMRCP web forms as shown in the videos.
Depending on our current status though, we may have different optimal
starting points and different things to consider.
UMRCP
How to Enroll - New to ARC Services
UMRCP
How to Enroll - Existing Owner of ARC Services
LS0tCnRpdGxlOiAiU3RvcmFnZSBCZXN0IFByYWN0aWNlcyBhbmQgdGhlIFVNUkNQIgphdXRob3I6ICJVTSBCaW9pbmZvcm1hdGljcyBDb3JlIgpvdXRwdXQ6CiAgICAgICAgaHRtbF9kb2N1bWVudDoKICAgICAgICAgICAgaW5jbHVkZXM6CiAgICAgICAgICAgICAgICBpbl9oZWFkZXI6IGhlYWRlci5odG1sCiAgICAgICAgICAgIHRoZW1lOiBwYXBlcgogICAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICAgICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgICAgIG1hcmtkb3duOiBHRk0KICAgICAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keXsgLyogTm9ybWFsICAqLwogICAgICBmb250LXNpemU6IDE0cHQ7CiAgfQpwcmUgewogIGZvbnQtc2l6ZTogMTJwdAp9Cjwvc3R5bGU+CgpJbiB0aGlzIG1vZHVsZSwgd2Ugd2lsbDoKCiogZGlzY3VzcyByZXByb2R1Y2libGUgY29tcHV0aW5nIGluIGdlbmVyYWwKKiBkaXNjdXNzIHN0b3JhZ2UgYmVzdCBwcmFjdGljZXMgZm9yIHJhdyBkYXRhLCBhbmxheXNpcyBmaWxlcywgc2NyaXB0cywgZXRjLgoqIGxlYXJuIGFib3V0IHNldmVyYWwgaW5zdGl0dXRpb25hbCBzdG9yYWdlIG9wdGlvbnMgKGFuZCBhc3NvY2lhdGVkIGNvbXB1dGUgcmVzb3VyY2VzKQoqIGxlYXJuIGFib3V0IHRoZSBVTVJDUCBhbmQgaG93IHRvIHJlcXVlc3QgaXQKKiBtYWtlIGEgcGxhbiBmb3IgZW5yb2xsaW5nIFBJcyBpbiBVTVJDUCBhbmQgZW5hYmxpbmcgYWNjZXNzIHRvIGFsbCByZXNlYXJjaGVycwoKPGJyPgoKIyMgUmVwcm9kdWNpYmxlIENvbXB1dGluZwoKUmVwcm9kdWNpYmxlIGNvbXB1dGluZyBoYXMgYmVjb21lIGluY3JlYXNpbmdseSBpbXBvcnRhbnQgaW4gcmVjZW50IHllYXJzLiBBcyBleHBlcmltZW50YWwgZGF0YSB2b2x1bWVzIGhhdmUgaW5jcmVhc2VkIGV4cG9uZW50aWFsbHksIGFuZCBhcyByZXNlYXJjaCBlbmRlYXZvcnMgaGF2ZSBlbXBsb3llZCBtb3JlIGNvbXBsaWNhdGVkIGFuYWx5c2VzIG92ZXIgdGltZSwgY29tcHV0YXRpb24gaGFzIGJlY29tZSBhIGZ1bmRhbWVudGFsIGFzcGVjdCBvZiB2aXJ0dWFsbHkgZXZlcnkgdHlwZSBvZiByZXNlYXJjaC4KClJlcHJvZHVjaWJpbGl0eSBpdHNlbGYgaXMgYW4gaW50ZWdyYWwgcGFydCBvZiB0aGUgc2NpZW50aWZpYyBwcm9jZXNzLiBXZSBkZXNjcmliZSBvdXIgZXhwZXJpbWVudHMgd2l0aCBzdWZmaWNpZW50IGRldGFpbCBzbyB0aGF0IHRoZXkgY2FuIGJlIHJlcGxpY2F0ZWQgYW5kIG91ciBmaW5kaW5ncyBjYW4gYmUgY29uZmlybWVkIGJ5IG90aGVycywgYW5kIHNvIHRoYXQgZXZlbnR1YWxseSBvdGhlcnMgbWF5IGJ1aWxkIHVwb24gdGhlbS4KClNvIHRha2luZyB0aGVzZSB0d28gdGhpbmdzIHRvZ2V0aGVyLCB0aGUgaW5jcmVhc2luZyB1c2Ugb2YgY29tcHV0aW5nIGluIHJlc2VhcmNoIGFuZCB0aGUgaW5oZXJlbnQgbmVlZCBmb3IgcmVwcm9kdWNpYmlsaXR5IGluIHRoZSBzY2llbnRpZmljIHByb2Nlc3MsIHdlIGNhbiBzdGFydCB0byB1bmRlcnN0YW5kIHRoZSBpbXBvcnRhbmNlIG9mIHJlcHJvZHVjaWJsZSBjb21wdXRpbmcuCgpUaGVyZSBhcmUgc29tZSBjaGFsbGVuZ2VzIHdlIG11c3Qgb3ZlcmNvbWUgaW4gdGhpcyByZWFsbS4gV2hlbiB3ZSB0cnkgdG8gZW1wbG95IG91ciB0eXBpY2FsIG1ldGhvZG9sb2dpZXMgZm9yIGdlbmVyYWwgc2NpZW50aWZpYyByZXByb2R1Y2liaWxpdHksIHRoZXkgbWF5IG5vdCBiZSBzdWZmaWNpZW50IHRvIHRydWx5IGVuYWJsZSBvdGhlcnMgdG8gcmVjcmVhdGUgb3VyIHdvcmsuIEluIG1hbnkgY2FzZXMsIGluIG9yZGVyIHRvIGNyZWRpYmx5IHZhbGlkYXRlIGFuIGFuYWx5c2lzLCB3ZSBtdXN0IGJlIGFibGUgdG8gbm90IG9ubHkgc2VlIGFuZCB1bmRlcnN0YW5kIHRoZSBzdGVwcyBvZiBhbiBhbmFseXNpcywgYnV0IGFsc28gdG8gdXNlIHRoZSBzYW1lIHNvZnR3YXJlIHdpdGggdGhlIHNhbWUgaW5wdXQgZGF0YSBhbmQgcGVyZm9ybSB0aGVzZSBzYW1lIGRhdGEgbWFuaXB1bGF0aW9ucyBvdXJzZWx2ZXMuIFRyeWluZyB0byBhY2hpZXZlIHRoaXMgdGFzayB3aXRoIG9ubHkgYSBkZXNjcmlwdGl2ZSBzdW1tYXJ5IG9mIG91ciBhbmFseXNpcyBtZXRob2RzLCBwYXJ0aWN1bGFybHkgd2hlbiB1c2luZyBjdXR0aW5nLWVkZ2UgYWNhZGVtaWMgc29mdHdhcmUsIG1heSBvZnRlbiBwcm9kdWNlIGxpdHRsZSBtb3JlIHRoYW4gZnJ1c3RyYXRpb24uCgpMZXQncyB0YWtlIGEgbW9tZW50IHRvIHRoaW5rIGFib3V0IG91ciBvd24gZXhwZXJpZW5jZXMgd2l0aCB0aGlzIHRvcGljLiBDYW4gd2UgdGhpbmsgb2YgZXhwZXJpZW5jZXMgd2hlcmUgd2UgZW5jb3VudGVyZWQgY2hhbGxlbmdlcyB3aGlsZSB0cnlpbmcgdG8gcmVwcm9kdWNlIHRoZSBhbmFseXNpcyBvZiBvdGhlcnM/IE9yIHdoaWxlIHRyeWluZyB0byBzaGFyZSBvdXIgb3duIGFuYWx5c2VzIHdpdGggY29sbGVhZ3Vlcz8KClRoZXJlIGFyZSBhIG51bWJlciBvZiB0b29scyBhbmQgdGVjaG5pcXVlcyB0aGF0IGhhdmUgZW1lcmdlZCB0byBhZGRyZXNzIHNvbWUgb2YgdGhlc2UgY2hhbGxlbmdlcywgYW5kIHRvIHJlYWxseSBsb3dlciB0aGUgYmFycmllciB0byBzaGFyaW5nIGFuZCByZXByb2R1Y2luZyBvdXIgcmVzdWx0cy4KCkluIHRoaXMgd29ya3Nob3Agd2UnbGwgZGlzY3VzcyB0aGVzZSB0b29scyBhbmQgdGVjaG5pcXVlcywgd2UnbGwgcHJvdmlkZSBzcGVjaWZpYyBndWlkYW5jZSBmb3IgVW5pdmVyc2l0eSBvZiBNaWNoaWdhbiByZXNlYXJjaGVycyB0byBhZGRyZXNzIHJlcHJvZHVjaWJpbGl0eSBjb25jZXJucywgYW5kIHdlJ2xsIHVzZSBwcmFjdGljYWwgZXhhbXBsZXMgYWxvbmcgdGhlIHdheSB0byBnYWluIGV4cGVyaWVuY2UgYW5kIGVtcGhhc2l6ZSB0aGUgY29uY2VwdHMgdGhhdCB3ZSBsZWFybi4KCjxicj4KCiMjIFN0b3JhZ2UgQmVzdCBQcmFjdGljZXMKCk9uZSBzaW1wbGUgd2F5IHRvIG9yZ2FuaXplIG91ciB0aGlua2luZyBhYm91dCBzdG9yYWdlIGJlc3QgcHJhY3RpY2VzIGlzIHRvIGRpdmlkZSB0aGUgdG9waWMgaW50byByYXcgZGF0YSBjb25zaWRlcmF0aW9ucywgYW5kIGNvbnNpZGVyYXRpb25zIGZvciBhbmFseXNpcyBwcm9qZWN0cy4gQnkgc2VwYXJhdGluZyBhbmQgZm9jdXNpbmcgb24gdGhvc2UgdHdvIGFzcGVjdHMsIHdlIGNhbiBlZmZlY3RpdmVseSBhZGRyZXNzIG1hbnkgb2YgdGhlIGNoYWxsZW5nZXMgYXNzb2NpYXRlZCB3aXRoIGVhY2guCgo+Tm90ZTogVGhlIGltcG9ydGFuY2Ugb2YgZG9jdW1lbnRhdGlvbiBpcyB1bml2ZXJzYWwgdG8gYWxsIGFzcGVjdHMgb2YgcmVwcm9kdWNpYmxlIHJlc2VhcmNoLiBJbiBjb25zaWRlcmluZyBiZXN0IHByYWN0aWNlcyBib3RoIGZvciBvdXIgcmF3IGRhdGEgYW5kIGZvciBvdXIgYW5hbHlzaXMgcHJvamVjdHMsIHdlIHdpbGwgZW1waGFzaXplIHRoZSBpbXBvcnRhbmNlIG9mIGRvY3VtZW50YXRpb24hCgojIyMgQSBHZW5lcmFsaXplZCBEYXRhIEZsb3cKCiFbXShpbWFnZXMvTW9kdWxlMDFfZ2VuZXJhbF9iZXN0X3ByYWN0aWNlX2RhdGFfZmxvdy5wbmcpCgojIyMgUmF3IERhdGEKCldoZW4gY29uc2lkZXJpbmcgYmVzdCBwcmFjdGljZXMgZm9yIHJhdyBkYXRhIHN0b3JhZ2UsIHdlIGNhbiBnZW5lcmFsbHkgb3JpZW50IG91cnNlbHZlcyBhcm91bmQgb25lIHRhc2sgLSBlbnN1cmUgdGhhdCB0aGUgZGF0YSBhcmUgc2FmZS4KClNhZmUgZnJvbToKCi0gQWNjaWRlbnRhbCBkZWxldGlvbgotIEhhcmR3YXJlIGZhaWx1cmUKLSBMb3NzIG9mIGFjY2VzcwoKV2l0aCB0aGlzIGluIG1pbmQsIHdlIHJlY29tbWVuZCBwbGFjaW5nIHlvdXIgcmF3IGV4cGVyaW1lbnRhbCBkYXRhIGludG8gYSBzcGVjaWZpYyBkZXNpZ25hdGVkIGxvY2F0aW9uIHdoaWNoIGlzICoqc29sZWx5KiogZGVkaWNhdGVkIHRvIHN0b3JpbmcgeW91ciByYXcgZGF0YS4KClNvb24gd2UnbGwgdGFsayBhYm91dCBzcGVjaWZpYyBvcHRpb25zIGZvciBVTWljaCByZXNlYXJjaGVycywgYnV0IGZvciBub3cgd2UnbGwganVzdCBzcGVhayBvZiB0aGUgZ2VuZXJhbCBwcm9jZXNzLiBEYXRhIHRoYXQgY2Fubm90IGVhc2lseSBiZSByZS1vYnRhaW5lZCBzaG91bGQgYmUgdHJlYXRlZCB3aXRoIGdyZWF0IGNhcmUuIEJ5IGZvbGxvd2luZyB0aGUgcmVjb21tZW5kYXRpb25zIGhlcmUsIHdlIGNhbiBhY2hpZXZlIHRoaXMgYW5kIGhhdmUgcGVhY2Ugb2YgbWluZCB0aGF0IHdlIGFyZSBwcmVzZXJ2aW5nIG91ciByYXcgZGF0YSBhbmQgb3VyIGNhcGFiaWxpdGllcyBmb3IgcmVwcm9kdWNpYmxlIHJlc2VhcmNoIHdlbGwgaW50byB0aGUgZnV0dXJlLgoKUmVjb21tZW5kZWQ6CgotIERlc2lnbmF0ZWQgbG9jYXRpb24gZm9yIHN0b3JpbmcgcmF3IGRhdGEKLSBMaW1pdCB3cml0ZSBhY2Nlc3Mgb2Ygc3RvcmVkIGRhdGEgZmlsZXMKLSBVc2UgaW5zdGl0dXRpb25hbCBzdG9yYWdlCiAgLSBMYXJnZSBmaWxlIHNpemVzIGFuZCBsYXJnZSB0b3RhbCBhbGxvY2F0aW9ucwogIC0gTG9uZy10ZXJtIHN1cHBvcnQKICAtIEhhcmR3YXJlIHJlZHVuZGFuY3kKICAtIExvY2F0aW9uIHJlZHVuZGFuY3kKCkFub3RoZXIgdGhpbmcgdG8gbWVudGlvbiBmb3IgcmF3IGRhdGEgYmVzdCBwcmFjdGljZXMgaXMgdGhlIHByb2NlZHVyZSBvZiBjaGVja2luZyBmaWxlIGludGVncml0eS4gV2hlbmV2ZXIgdHJhbnNmZXJyaW5nIGRhdGEgZnJvbSBvbmUgc3RvcmFnZSBsb2NhdGlvbiB0byBhbm90aGVyLCBhbmQgZXNwZWNpYWxseSB3aGlsZSBkb2luZyBzbyBvdmVyIGEgbmV0d29yayBjb25uZWN0aW9uLCBpdCBpcyBnb29kIHByYWN0aWNlIHRvIGZvbGxvdyB1cCB3aXRoIGEgZmlsZSBpbnRlZ3JpdHkgY2hlY2suIEJyaWVmbHksIHdlIHVzZSBzb2Z0d2FyZSB0byBpbnNwZWN0IG91ciBmaWxlcyBhbmQgZGV0ZXJtaW5lIGlmIGFueSBvZiB0aGUgY29udGVudHMgaGF2ZSBjaGFuZ2VkLiBJbiBhIGxhdGVyIG1vZHVsZSB3ZSdsbCBoYXZlIGEgY2hhbmNlIHRvIHRyeSB0aGlzIG91cnNlbHZlcywgdXNpbmcgdGhlIGBtZDVzdW1gIHV0aWxpdHkuIFRoaXMgaXMgYSByZWxhdGl2ZWx5IGVmZmljaWVudCB3YXkgb2YgdmVyaWZ5aW5nIGZpbGUgaW50ZWdyaXR5IGFmdGVyIGEgZmlsZSB0cmFuc2Zlci4KCgojIyMgQW5hbHlzaXMgUHJvamVjdHMKCldlIGNhbiBiZWdpbiB0aGlua2luZyBvZiBvdXIgbmV4dCB0YXNrIC0gaGFuZGxpbmcgZGF0YSBhbmQgb3JnYW5pemluZyBmaWxlcyBhbmQgYXJ0aWZhY3RzIGZvciBvdXIgYW5hbHlzaXMgLSBieSBzdGFydGluZyB3aXRoIHRoZSBpZGVhIG9mIHRoZSBkYXRhIGZsb3cgZGVzY3JpYmVkIGFib3ZlLiBPbmUgb2YgdGhlIGZpcnN0IHRhc2tzIGluIHRoaXMgYXJlYSBpcyB0byBzZXQgdXAgYSBuZXcgbG9jYXRpb24gZm9yIHlvdXIgYW5hbHlzaXMgYW5kIG1ha2UgYSBjb3B5IG9mIHlvdXIgcmF3IGRhdGEgdGhlcmUuCgpTb21lIGNvbnNpZGVyYXRpb25zOgoKIC0gRmFzdCBzdG9yYWdlLCB3ZWxsIHN1aXRlZCBmb3IgY29tcHV0YXRpb24KIC0gUHJvamVjdCBvcmdhbml6YXRpb24gdGhhdCBmYWNpbGl0YXRlcyByZXByb2R1Y2liaWxpdHkKIC0gSW4tcHJvZ3Jlc3MgYW5hbHlzZXMsIGNsZWFudXAgcHJvY2VkdXJlcywgYW5kIGVuZC10by1lbmQgcmVwZWF0YWJsZSBhbmFseXNlcwoKV2hlbiB3ZSB0aGluayBhYm91dCBmYXN0IHN0b3JhZ2UgdGhhdCBpcyB3ZWxsIHN1aXRlZCBmb3IgY29tcHV0YXRpb24sIHdlIG1vc3RseSBjb250cmFzdCB0aGF0IHdpdGggb3VyIGxvbmctdGVybSBhcmNoaXZhbCBzdG9yYWdlLiBBIHN0b3JhZ2Ugb3B0aW9uIGlzIHdlbGwgc3VpdGVkIGZvciBjb21wdXRhdGlvbiBpZiBpdCBpcyBhY2Nlc3NpYmxlIHZpYSBoaWdoLXRocm91Z2hwdXQgY29ubmVjdGlvbiB0byBzdWZmaWNpZW50bHkgcG93ZXJmdWwgcHJvY2Vzc2luZyBoYXJkd2FyZS4gVGhlIHNwZWVkIG9mIHJlYWRpbmcgYW5kIHdyaXRpbmcgZnJvbSB0aGlzIGxvY2F0aW9uIGNhbiBncmVhdGx5IGFmZmVjdCBwcm9jZXNzaW5nIHRpbWVzIG9mIHlvdXIgYW5hbHlzaXMsIGRlcGVuZGluZyBvbiB0aGUgc3RlcHMgaW52b2x2ZWQuCgpJbiB0ZXJtcyBvZiBwcm9qZWN0IG9yZ2FuaXphdGlvbiwgZ2VuZXJhbGx5IHdlIHdhbnQgdG8gaGF2ZSBkaXN0aW5jdCBsb2NhdGlvbnMgZm9yIHNwZWNpZmljIHB1cnBvc2VzLCBhbmQgcHJlZmVyYWJseSBvcmdhbml6aW5nIHRoaW5ncyBpbiBhIGNvbnNpc3RlbnQgbWFubmVyIGZvciBhbGwgb2Ygb3VyIHByb2plY3RzLgoKSW4gYSBwYXJ0aWN1bGFyIHByb2plY3QsIHlvdSBtYXkgd2FudDoKCi0gYGlucHV0X2RhdGFgIGRpcmVjdG9yeSBmb3IgY29weSBvZiByYXcgZGF0YQotIGBzY3JpcHRzYCBkaXJlY3RvcnkgZm9yIGFuYWx5c2lzIHNjcmlwdHMKLSBEaXJlY3RvcmllcyBmb3IgaW50ZXJtZWRpYXRlcywgbG9nIGZpbGVzLCBhbmQgZmluYWwgb3V0cHV0cwotIGBSRUFETUUudHh0YCBmb3IgdGhlIHByb2plY3QKICAtIE9wdGlvbmFsIGBkb2NzYCBkaXJlY3RvcnkgZm9yIGV4dGVuc2l2ZSBkb2N1bWVudGF0aW9uLCBzdXBwb3J0aW5nIHdvcmtzLCBldGMuCgpBIHVzZWZ1bCBpZGVhIGZvciBvdXIgcHJvamVjdCBkaXJlY3RvcnkgbGF5b3V0cyBpcyB0byB0aGluayBhYm91dCB0aGUgcHJvamVjdCBsaWZlIGN5Y2xlIGFuZCB3b3JrIHRvd2FyZHMgYW4gZW5kLWdvYWwgb2YgYSByZXByb2R1Y2libGUgYW5hbHlzaXMuIFdoaWxlIGF0IHRoZSBiZWdpbm5pbmcgb2YgYW4gYW5hbHlzaXMgbWFueSB0aGluZ3MgbWF5IGJlIGZsZXhpYmxlLCBhdCB0aGUgZW5kIHdlIHdpbGwgd2FudCB0byBiZSBhYmxlIHRvIHJlLWV4ZWN1dGUgdGhlIGFuYWx5c2lzIHN0YXJ0aW5nIGZyb20gdGhlIHJhdyBpbnB1dCBkYXRhIGFuZCBydW5uaW5nIGFsbCB0aGUgd2F5IHVudGlsIGl0IHByb2R1Y2VzIHRoZSBmaW5hbCBvdXRwdXRzLgoKVGFraW5nIHRpbWUgdG8gc2VncmVnYXRlIHNwZWNpZmljIGVmZm9ydHMgd2l0aGluIGEgcHJvamVjdCwgZG9jdW1lbnRpbmcgb3VyIHN0ZXBzIGFzIHdlIHBlcmZvcm0gaW4tcHJvZ3Jlc3MgYW5hbHlzZXMsIHBlcmZvcm1pbmcgY2xlYW51cHMgd2hlcmUgbmVlZGVkLCBhbmQgc2ltaWxhciBlZmZvcnRzIHdpbGwgYWlkIHVzIGFzIHdlIHdvcmsgdG93YXJkcyB0aGF0IGdvYWwuCgpUaGluayBhaGVhZCB3aGVuIGRlc2lnbmluZyB0aGUgbGF5b3V0IG9mIHlvdXIgcHJvamVjdHMuIElmIHlvdSB3aWxsIGJlIHRyeWluZyBzZXZlcmFsIHJlbGF0ZWQgYW5hbHlzaXMgYXBwcm9hY2hlcyB1c2luZyB0aGUgc2FtZSBpbnB1dCBkYXRhLCBidXQgaW50ZW5kIG9uIHVzaW5nIHJlc3VsdHMgZnJvbSBvbmx5IG9uZSBvZiB0aGUgZXZhbHVhdGVkIG1ldGhvZHMsIGl0IG1heSBtYWtlIHNlbnNlIHRvIGludGVudGlvbmFsbHkgc3ViZGl2aWRlIHRoZSBjb250ZW50cyBvZiB5b3VyIHByb2plY3QgZGlyZWN0b3J5IGFjY29yZGluZ2x5LiBJZiB5b3UgaGF2ZSBzZXZlcmFsIGRpc3RpbmN0IGFuYWx5c2VzIHRoYXQgbWF5IHVzZSB0aGUgc2FtZSBpbnB1dCBkYXRhLCB0aGVuIHBlcmhhcHMgY3JlYXRpbmcgc2VwYXJhdGUgcHJvamVjdHMgZm9yIGVhY2ggb2YgdGhlbSB3aWxsIG1ha2UgdGhlIG1vc3Qgc2Vuc2UuIEl0J3MgaGFyZCB0byBiZSB0b3RhbGx5IHByZXNjcmlwdGl2ZSB3aGVuIG1ha2luZyByZWNvbW1lbmRhdGlvbnMgaGVyZSwgYnV0IHRocm91Z2ggb3VyIGV4YW1wbGUgd2UgaG9wZSB0byBzcGFyayB0aGUga2luZHMgb2YgY29udmVyc2F0aW9ucyBhbmQgdGhlIHR5cGVzIG9mIHRoaW5raW5nIHRoYXQgYXJlIHJlcXVpcmVkIGhlcmUuCgohW10oaW1hZ2VzL01vZHVsZTAxX3Byb2plY3RzX2xheW91dC5wbmcpCgpPbmUgbGFzdCBub3RlIG9uIGhhbmRsaW5nIGFuZCBvcmdhbml6aW5nIGFuYWx5c2lzIHByb2plY3RzIC0gdXNlIHNvbWUgZm9ybSBvZiBpZGVudGlmaWNhdGlvbiBzeXN0ZW0gZm9yIHByb2plY3RzIGluIHlvdXIgbGFiLiBUaGlzIHNpbXBsaWZpZXMgY29tbXVuaWNhdGlvbiBhbmQgcmVjb3JkIGtlZXBpbmcsIGluIGFkZGl0aW9uIHRvIHRoZSBvcmdhbml6YXRpb25hbCBiZW5lZml0cy4KClNvbWUgaWRlYXMgZm9yIHByb2plY3QgaWRlbnRpZmljYXRpb24gc3lzdGVtczoKCi0gQ29kZW5hbWVzCi0gQWxwaGFudW1lcmljIElEcwoKPGJyPgoKIyMgU3RvcmFnZSBPcHRpb25zIGZvciBVTWljaCBSZXNlYXJjaGVycwoKV2UndmUgZGlzY3Vzc2VkIGJlc3QgcHJhY3RpY2VzIGZvciBkYXRhLCBhbmFseXNpcyBpbnRlcm1lZGlhdGVzIGFuZCBzY3JpcHRzLCBldGMuIGluIGdlbmVyYWwgdGVybXMsIGJ1dCBub3cgd2UnbGwgaGF2ZSB0aGUgb3Bwb3J0dW5pdHkgdG8gcmV2aXNpdCB0aGVzZSBpZGVhcyB3aGlsZSBoaWdobGlnaHRpbmcgc3BlY2lmaWMgb3B0aW9ucyBhbmQgcmVjb21tZW5kYXRpb25zIGZvciBVTWljaCByZXNlYXJjaGVycy4gQnkgdGhlIGVuZCBvZiB0aGlzIG1vZHVsZSwgd2Ugd2lsbCB1bmRlcnN0YW5kIG91ciBudW1lcm91cyBzdG9yYWdlIG9wdGlvbnMgYXZhaWxhYmxlIHRvIHVzLiBMb29raW5nIGZvcndhcmQgdG8gZnV0dXJlIG1vZHVsZXMsIHdlJ2xsIGFsc28gcnVuIGV4ZXJjaXNlcyB0aGF0IGludGVyYWN0IHdpdGggc29tZSBvZiB0aGVzZSBzdG9yYWdlIGFsbG9jYXRpb25zIGFzIHdlIHByb2NlZWQsIGluY2x1ZGluZyBEYXRhIERlbiBhbmQgaXRzIHVuaXF1ZSBjaGFyYWN0ZXJpc3RpY3MgYW5kIHVzYWdlIHBhdHRlcm5zLgoKCiMjIyBXaGF0IGlzIEFSQz8KClRoZSB2YXN0IG1ham9yaXR5IG9mIGNvbXB1dGluZyByZXNvdXJjZXMgd2UnbGwgYmUgZGlzY3Vzc2luZyBpbiB0aGUgd29ya3Nob3AgYXJlIHByb3ZpZGVkIGFuZCBtYW5hZ2VkIGJ5IEFSQyAtIEFkdmFuY2VkIFJlc2VhcmNoIENvbXB1dGluZyBhdCBVbml2ZXJzaXR5IG9mIE1pY2hpZ2FuLiBUaGUgc2hhcmVkIGNvbXB1dGluZyBjbHVzdGVyIHRoYXQgd2UnbGwgYmUgdXNpbmcgaW4gdGhlIHdvcmtzaG9wIGlzIHJ1biBieSBBUkMsIGFuZCB0aGUgc3RvcmFnZSBhbGxvY2F0aW9ucyBsaWtld2lzZSBhcmUgcHJvdmlkZWQgYnkgQVJDLiBUaGVpciBtaXNzaW9uIGlzIHRvIHByb3ZpZGUgdW5pdmVyc2l0eSByZXNlYXJjaGVycyB3aXRoIHRoZSBhZHZhbmNlZCBjb21wdXRpbmcgcmVzb3VyY2VzIHRoYXQgdGhleSBuZWVkLCBhbmQgdGhleSd2ZSBiZWVuIHdvcmtpbmcgd2l0aCByZXNlYXJjaCBncm91cHMgaW4gdmFyaW91cyBjb21wdXRlIGludGVuc2l2ZSBmaWVsZHMgdG8gYWNoaWV2ZSB0aGlzLiAKCkxhdGVyIGluIHRoaXMgbW9kdWxlIHdlJ2xsIGRpc2N1c3MgaW4gZGV0YWlsIGhvdyB0byByZXF1ZXN0IHJlc291cmNlcyB0aHJvdWdoIEFSQywgYnV0IGZvciBub3cgd2UnbGwgZm9jdXMgb24gdGhlIHN0b3JhZ2UgdG9waWMgYW5kIGNvdmVyIHNvbWUgaW1wb3J0YW50IHN0b3JhZ2Ugb3B0aW9ucyB0aGF0IEFSQyBwcm92aWRlcy4KCiMjIyBEYXRhIERlbgoKRGF0YSBEZW4gaXMgYSBsb3ctY29zdCwgaGlnaGx5IGR1cmFibGUgc3RvcmFnZSBzeXN0ZW0gb3BlcmF0ZWQgYnkgQVJDLgoKLSBUYXBlLWJhc2VkIGFyY2hpdmFsIHN0b3JhZ2UKLSBUaGUgbGFyZ2VzdCBhbmQgbW9zdCBhZmZvcmRhYmxlIHN0b3JhZ2UgYXZhaWxhYmxlIHRocm91Z2ggQVJDLgotIENhbiBvbmx5IGFjY2VzcyB0aGlzIGluZGlyZWN0bHkKICAtIGkuZS4gdXNlIEdsb2J1cyB0byBpbnRlcmZhY2Ugd2l0aCB0aGlzIHN0b3JhZ2UuIAogIAo8IS0tIER1ZSB0byBpdHMgYXJjaGl0ZWN0dXJlLCBzbG93IHNwZWVkcywgYW5kIG5lZWQgdG8gZWxpbWluYXRlIHVubmVjZXNzYXJ5IHJlYWQvd3JpdGUgb3BlcmF0aW9ucyAtLT4KCj4gTm90ZTogRGF0YSBEZW4gaGFzIGEgZmlsZSBzaXplIGxpbWl0YXRpb24gLSBpdCBkb2VzIG5vdCBoYW5kbGUgbGFyZ2UgYW1vdW50cyBvZiBzbWFsbCBmaWxlcy4gT3B0aW1hbCBmaWxlIHNpemUgaXMgaW4gdGhlIG11bHRpLWdpZ2FieXRlIHJhbmdlLgo+IFRoZSBsaW1pdGF0aW9uIDEwLDAwMCBmaWxlcyBwZXIgVEIgb2Ygc3RvcmFnZS4KCgojIyMgVHVyYm8KClR1cmJvIGlzIGEgaGlnaC1jYXBhY2l0eSwgcmVsaWFibGUsIGFuZCBmYXN0IHN0b3JhZ2Ugc3lzdGVtIG9wZXJhdGVkIGJ5IEFSQy4gSXQgaXMgbW9yZSBjb3N0bHkgdGhhbiBEYXRhIERlbi4KCi0gTW9yZSBjb3N0bHkgdGhhbiBEYXRhIERlbgotIFR1bmVkIGZvciBmaWxlcyBtb2RlcmF0ZSB0byBsYXJnZSBpbiBzaXplLCBidXQgY2FuIGFsc28gZWFzaWx5IGFjY29tb2RhdGUgc21hbGwgZmlsZXMKLSBDYW4gYmUgYWNjZXNzZWQgdGhyb3VnaCB0aGUgSGlnaC1QZXJmb3JtYW5jZSBDb21wdXRpbmcgKEhQQykgY2x1c3RlcgoKRmFzdCBzdG9yYWdlIGxpa2UgVHVyYm8gaXMgd2VsbC1lcXVpcHBlZCBmb3IgY29tcHV0aW5nIGRpcmVjbHkgZnJvbSBpdC4gVHVyYm8gc3VwcG9ydHMgZmFzdCByZWFkL3dyaXRlIHRpbWVzLCBhbmQgaXMgYW4gZXhjZWxsZW50IHBsYWNlIHRvIHBlcmZvcm0gYW5hbHlzZXMuCgoKIyMjIFR1cmJvIGFuZCBEYXRhIERlbiAtIENvc3QgRGlmZmVyZW5jZQoKV2UgZGlzY3Vzc2VkIGFib3ZlIHRoYXQgRGF0YSBEZW4gaXMgc2xvdywgdW5zdWl0ZWQgZm9yIGFuYWx5c2lzLCB5ZXQgY29zdC1lZmZlY3RpdmUsIHdoaWxlIFR1cmJvIGlzIGZhc3QsIHdlbGwtdHVuZWQgZm9yIGFuYWx5c2lzLCBhbmQgbW9yZSBjb3N0bHkuIFRvIHB1dCBzb21lIG51bWJlcnMgdG8gdGhpcyBwcmljZSBkaXNjdXNzaW9uLCBzZWUgdGhlIGZvbGxvd2luZyB0YWJsZSBvZiBjb3N0IHBlciBUQiBwZXIgeWVhcjoKCnwgICAgICAgICAgfCBVbnJlcGxpY2F0ZWQgfCBSZXBsaWNhdGVkIHwKfCAtLS0tLS0tLTp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwgLS0tLS0tLS0tLTp8CnwgVHVyYm8gICAgfCAkNzcuODggICAgICAgICAgICAgICAgICB8ICQxNTYuMjIgICAgfAp8IERhdGEgRGVuIHwgTkEgICAgICAgICAgICAgICAgICAgICAgfCAkMjAuMDQgICAgIHwKCk5vdGljZSB0aGF0IFR1cmJvIHN0b3JhZ2UgaXMgYWJvdXQgOHggbW9yZSBjb3N0bHkgdGhhbiBEYXRhIERlbiBmb3IgdGhlIHNhbWUgYW1vdW50IG9mIHJlcGxpY2F0ZWQgc3RvcmFnZS4KCj5Ob3RlOiBEYXRhIERlbiBpcyBvbmx5IGF2YWlsYWJsZSBpbiB0aGUgcmVwbGljYXRlZCBmb3JtYXQuCgoKIyMjIEhvbWUsIFNjcmF0Y2gsIHRtcCwgYW5kIG90aGVycwoKLSBIb21lIGRpcmVjdG9yeSAoODAgR0IgcXVvdGEpCiAgLSAvaG9tZS91bmlxbmFtZQotIFNjcmF0Y2ggZGlyZWN0b3J5ICgxMCBUQiBhbmQgMSwwMDAsMDAwIGZpbGUgcXVvdGEpCiAgLSAvc2NyYXRjaC9hY2NvdW50X3Jvb3QvYWNjb3VudC91bmlxbmFtZQogIC0gTm90IHBlcnNpc3RlbnQgb3ZlciB0aW1lCiAgICAtIEF1dG9tYXRpY2FsbHkgZGVsZXRlZCBpZiBub3QgYWNjZXNzZWQgaW4gNjAgZGF5cwotIExvY2FsIGRpc2sgKDQgVEIgc2hhcmVkKQogIC0gL3RtcAogIC0gTm90IHBlcnNpc3RlbnQgYWNyb3NzIG1hY2hpbmVzCgoKIyMjIEluc3RpdHV0aW9uYWwgU3RvcmFnZSB2cyBPdGhlciBTdG9yYWdlCgp8IEluc3RpdHV0aW9uYWwgfCBPdGhlciB8Cnw6LS0tLS0tLS0tLS0tLS0tIHw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwKfCBUdXJibyAgICAgICAgICAgfCBMYXB0b3AgU3RvcmFnZSAgICAgICAgICAgICAgICAgICAgfAp8IERhdGEgRGVuICAgICAgICB8IFN0b3JhZ2Ugb24gYSBTaGFyZWQgTGFiIENvbXB1dGVyICB8CnwgSG9tZSAvIFNjcmF0Y2gqIHwgUG9ydGFibGUgSGFyZCBEcml2ZSAvIEZsYXNoIERyaXZlIHwKfCBNaVN0b3JhZ2UgICAgICAgfCBDbG91ZCBTdG9yYWdlICAgICAgICAgICAgICAgICAgICAgfAoKPGJyPgoKIyMgVU1SQ1AKCiFbXShpbWFnZXMvTW9kdWxlMDFfVU1SQ1BfcHJvdmlkZXMucG5nKQoKVGhlIGZpZ3VyZSBhYm92ZSBoaWdobGlnaHRzIHRoZSBtb3N0IGltcG9ydGFudCBhbmQgaW1wcmVzc2l2ZSBkZXRhaWxzIG9mIHRoZSBVTVJDUCwgYnV0IHlvdSBjYW4gZmluZCBmdWxsIGRldGFpbHMgb2YgdGhlIHJlc291cmNlcyBvZmZlcmVkIHRocm91Z2ggdGhpcyBwcm9ncmFtIG9uIFt0aGUgVU1SQ1AgcGFnZSBvZiBBUkMncyB3ZWJzaXRlXShodHRwczovL2FyYy51bWljaC5lZHUvdW1yY3AvKS4KCiMjIyBTaWduaW5nIHVwIGZvciB0aGUgVU1SQ1AKCldpdGhpbiB0aGF0IHNpdGUsIHRoZXJlIGlzIGFub3RoZXIgcGFnZSB0aGF0IEkgaGlnaGx5IHJlY29tbWVuZCBhcyBhIGdyZWF0IHBsYWNlIHRvIHN0YXJ0IC0gdGhlIFtVTVJDUCBSZXF1ZXN0aW5nIFJlc291cmNlcyBHdWlkZV0oaHR0cHM6Ly9hcmMudW1pY2guZWR1L3VtcmNwLXJlcXVlc3RpbmctcmVzb3VyY2VzLWd1aWRlLykuIFRoZXJlIHlvdSdsbCBmaW5kIGRldGFpbHMgYWJvdXQgdGhlIHNpZ251cCBwcm9jZXNzLiBBZnRlciBzaWduaW5nIHVwLCB5b3UnbGwgYmUgYWJsZSB0byB1c2Ugc29tZSBvZiB0aGUgbnVtZXJvdXMgY29tcHV0ZSBub2RlcyBhdmFpbGFibGUgdGhyb3VnaCBBUkMsIGFzIHdlbGwgYXMgdGhlIHZhcmlvdXMgc3RvcmFnZSB0aWVycyBkZXNjcmliZWQgYWJvdmUuCgo8YnI+CgohW10oaW1hZ2VzL01vZHVsZTAxX3N0ZXBzX2dldHRpbmdfVU1SQ1AucG5nKQoKPGJyPgoKPGRldGFpbHM+CjxzdW1tYXJ5PkFkZGl0aW9uYWwgUmVzb3VyY2VzIEF2YWlsYWJsZSBUaHJvdWdoIEhJVFMgUkNJPC9zdW1tYXJ5PgoKIVtdKGltYWdlcy9Nb2R1bGUwMV91bXJjcF9wbHVzX3VtcmNpX3Byb3ZpZGVzLnBuZykKCkluIGFkZGl0aW9uIHRvIHRoZSByZXNvdXJjZXMgcHJvdmlkZWQgdGhyb3VnaCB0aGUgVU1SQ1AsIHNvbWUgcmVzZWFyY2hlcnMgd2l0aGluIHRoZSBtZWRpY2FsIHN5c3RlbSB3aWxsIGhhdmUgYWRkaXRvbmFsIHJlc291cmNlcyBhdmFpbGFibGUgdGhyb3VnaCBVTSBIZWFsdGggSW5mb3JtYXRpb24gVGVjaG5vbG9neSAmIFNlcnZpY2VzIChISVRTKS4gVGhyb3VnaCBzdHJhdGVnaWMgaW52ZXN0bWVudHMgaW4gSGlnaCBQZXJmb3JtYW5jZSBDb21wdXRpbmcgYnkgTWljaGlnYW4gTWVkaWNpbmUsIGVsaWdpYmxlIHJlc2VhcmNoZXJzIGNhbiBlbmpveSBhZGRpdGlvbmFsIGFsbG9jYXRpb25zIGZvciB0aGUgZGVzY3JpYmVkIHJlc291cmNlcyAtIG1vc3Qgbm90YWJseSB1bmxpbWl0ZWQgRGF0YSBEZW4gc3RvcmFnZS4KCkluIHRoZSBkb2N1bWVudGF0aW9uIGZvciB0aGUgVU1SQ1AgYW5kIHRoZSBVTVJDSSwgeW91J2xsIHNlZSB0aGF0IHRoZXkgcmVjb21tZW5kIGZpcnN0IHVzaW5nIHRoZSBVTVJDUCByZXNvdXJjZXMgKGF2YWlsYWJsZSB0byBhbGwgdW5pdmVyc2l0eSByZXNlYXJjaGVycykgYW5kIHRoZW4gdHJhbnNpdGlvbmluZyB0byB0aGVzZSBhZGRpdGlvbmFsIEhJVFMgVU1SQ0kgcmVzb3VyY2VzIChhdmFpbGFibGUgdG8gTWljaGlnYW4gTWVkaWNpbmUgcmVzZWFyY2hlcnMpIHdoZW4gcG9zc2libGUuIEluIGFueSBjYXNlLCBzaW5jZSB0aGVzZSBhbGxvY2F0aW9ucyBhcmUgbWFuYWdlZCBieSBBUkMgZm9yIGFsbCB1bml2ZXJpc2l0eSByZXNlYXJjaGVycyAtIE1pY2hpZ2FuIE1lZGljbmUgb3Igb3RoZXJ3aXNlIC0geW91J2xsIGJlIHVzaW5nIHRoZSBzYW1lIGZvcm1zIGFuZCBwcm9jZWR1cmVzIHRvIHJlcXVlc3QgcmVzb3VyY2VzIGFuZCB1c2UgdGhlbS4gSG93ZXZlciwgdGhlIGJpbGxpbmcgZGV0YWlscyBtYXkgY2hhbmdlIGRlcGVuZGluZyBvbiB0aGlzIGVsaWdpYmlsaXR5LgoKW0xpbmsgdG8gSElUUyBwYWdlIG9uIFVNUkNJXShodHRwczovL2hpdHMubWVkaWNpbmUudW1pY2guZWR1L3Jlc2VhcmNoLWVkdWNhdGlvbi9yZXNlYXJjaC1jb21wdXRpbmctZGF0YS1zdG9yYWdlL3Jlc2VhcmNoLWNvbXB1dGluZy1wYWNrYWdlKQoKPC9kZXRhaWxzPgoKPGJyPgoKIyMjIEdyZWF0IExha2VzLCBBcm1pczIsIGFuZCBMaWdodGhvdXNlIENsdXN0ZXJzCgpUaGlzIG1vZHVsZSBvdmVyYWxsIGlzIHByaW1hcmlseSBmb2N1c2VkIG9uIHN0b3JhZ2UtcmVsYXRlZCB0b3BpY3MuIFdlJ3ZlIGJyaWVmbHkgbWVudGlvbmVkIHRoYXQgaW4gYWRkaXRpb24gdG8gc3RvcmFnZSByZXNvdXJjZXMsIEFSQyBhbHNvIHByb3ZpZGVzIGFjY2VzcyB0byBoaWdoLXBlcmZvcm1hbmNlIGNvbXB1dGluZyAoSFBDKSBoYXJkd2FyZSBhcyB3ZWxsLiBXaGlsZSBpbiB0aGlzIHdvcmtzaG9wIHdlJ2xsIGp1c3QgYmUgZm9jdXNpbmcgb24gb25lIG9mIHRoZW0sIGluIGZhY3QgdGhlcmUgYXJlIHNldmVyYWwgSFBDIGNsdXN0ZXJzIHRoYXQgYXJlIGF2YWlsYWJsZSB0byBVTWljaCByZXNlYXJjaGVycywgaW4gb3JkZXIgdG8gbWVldCB2YXJpb3VzIG5lZWRzLgoKV2hlbiBkaXNjdXNzaW5nIHJlc2VhcmNoIG5lZWRzLCBlc3BlY2lhbGx5IGluIGFudGljaXBhdGlvbiBvZiByZXF1ZXN0aW5nIFVNUkNQIHJlc291cmNlcyBhbmQgZmlsbGluZyBvdXQgdGhlIHJlcXVpcmVkIGZvcm0sIHdlIHNob3VsZCBkaXNjdXNzIGEgbGl0dGxlIGJpdCBhYm91dCB0aHJlZSBIUEMgb3B0aW9ucyBwcm92aWRlZCB0aHJvdWdoIEFSQzoKCi0gR3JlYXQgTGFrZXMKLSBBcm1pczIgKEhJUEFBLWFsaWduZWQpCi0gTGlnaHRob3VzZSAoUmVzZWFyY2hlci1vd25lZCBoYXJkd2FyZSkKCldlJ2xsIGJlIGRpc2N1c3NpbmcgR3JlYXQgTGFrZXMgYXQgbGVuZ3RoIHRocm91Z2hvdXQgdGhpcyB3b3Jrc2hvcCBhbmQgdXNpbmcgaXQgZm9yIG91ciBleGFtcGxlIGFuYWx5c2VzLiBXZSBjYW4gdGhpbmsgb2YgaXQgYXMgYSBnZW5lcmFsLXB1cnBvc2UgSFBDIGNsdXN0ZXIsIHdoaWNoIGlzIHN1aXRhYmxlIGZvciBtYW55IGRpZmZlcmVudCBraW5kcyBvZiByZXNlYXJjaC4KCkFybWlzMiBpcyBzaW1pbGFyIGluIGZlZWwgdG8gdGhlIEdyZWF0IExha2VzIGNsdXN0ZXIsIGV4Y2VwdCBpdCBpcyBjb25maWd1cmVkIHdpdGggc3BlY2lmaWMgc2VjdXJpdHkgbWVhc3VyZXMgaW4gcGxhY2UgdG8gZW5hYmxlIGFuYWx5c2lzIG9mIHNlbnNpdGl2ZSBkYXRhLCBzdWNoIGFzIGV4cG9ydC1jb250cm9sbGVkIG9yIEhJUEFBIHByb3RlY3RlZCBkYXRhLiAgV2hlbiBmaWxsaW5nIG91dCB0aGUgVU1SQ1AgZm9ybSwgeW91IGNhbiBtYWtlIHNlbGVjdGlvbnMgZm9yIHNlbnNpdGl2ZSBkYXRhIG5lZWRzLCB3aGljaCB3aWxsIHByb3ZpZGUgQ1BVIGhvdXJzIG9uIEFybWlzMiBhbmQgYXNzb2NpYXRlZCBzdG9yYWdlLiBXZSdsbCBzZWUgbGF0ZXIsIHRoYXQgd2UgaGF2ZSBmbGV4aWJpbGl0eSBpbiBob3cgd2UgYWxsb2NhdGUgcmVzb3VyY2VzIGJldHdlZW4gZS5nLiBHcmVhdCBMYWtlcyBhbmQgQXJtaXMyLgoKPk5vdGU6IFRoZXJlIGlzIGEgc2VwYXJhdGUsIHNlY3VyaXR5LWVuaGFuY2VkIFR1cmJvIGFsbG9jYXRpb24gdGhhdCBpcyBhbHNvIEhJUEFBIGFsaWduZWQgdGhhdCBzaG91bGQgYmUgdXNlZCB3aXRoIEFybWlzMi4KCkxpZ2h0aG91c2UgaXMgYWxzbyBzaW1pbGFyIGluIGZlZWwgdG8gdGhlIEdyZWF0IExha2VzIGNsdXN0ZXIsIGV4Y2VwdCBpdCBpcyBhIGNsdXN0ZXIgY29tcHJpc2VkIGVudGlyZWx5IG9mIHJlc2VhcmNoZXItb3duZWQgaGFyZHdhcmUuIENvbnRyYXN0aW5nIHRoaXMgd2l0aCBHcmVhdCBMYWtlcyB3aGVyZSB3ZSBhcmUgb25seSByZXNwb25zaWJsZSBmb3IgdGhlIGNvc3Qgb2YgdGhlIHJlc291cmNlcyB3ZSB1c2UsIG9uIExpZ2h0aG91c2UsIGEgcmVzZWFyY2hlciB3aWxsIGZ1bmQgdGhlIGVudGlyZXR5IG9mIHRoZSBoYXJkd2FyZSBhbmQgcmVjZWl2ZSAxMDAlIG9mIGl0cyBhdmFpbGFiaWxpdHkuIFRoaXMgY2FuIGJlIGEgZ29vZCBjaG9pY2UgZm9yIHJlc2VhcmNoZXJzIHdobyBhcmUgZXhwZWN0ZWQgdG8gaGF2ZSBuZWFyLWNvbnN0YW50IGNvbXB1dGUgdXNhZ2UgbmVlZHMsIG9yIHdobyByZXF1aXJlIGluc3RhbnQgYXZhaWxhYmlsaXR5IG9mIEhQQyByZXNvdXJjZXMuCgo8YnI+CgpNYWluIGlkZWFzOgoKIC0gUEkgbXVzdCBiZSB0aGUgb25lIHRvIGZpbGwgb3V0IGZvcm0KIC0gUEkgd2lsbCBhdXRvbWF0aWNhbGx5IGJlY29tZSBhbiBhZG1pbmlzdHJhdG9yCiAtIE90aGVycyBjYW4gYmVjb21lIGFkbWluaXN0cmF0b3JzIChsYWIgbWFuYWdlcikgb3IgbWVtYmVycwoKPGJyPgoKIyMjIEFkbWluaXN0cmF0b3JzIHZzIFVzZXJzCgp8ICAgICAgICAgICAgICB8IENoYW5nZSBBbGxvY2F0aW9ucyB8IEFkZC9SZW1vdmUgVXNlcnMgfCBVc2UgR0wgY29tcHV0ZSB0aW1lIHwgUmVhZC9Xcml0ZSBhY2Nlc3MgdG8gVHVyYm8gfCBHbG9idXMgQWRtaW4gfAp8IC0tLS0tLS0tLS0tLSB8Oi0tLS0tLS0tLS0tLS0tLS0tLSB8Oi0tLS0tLS0tLS0tLS0tLS0gfDotLS0tLS0tLS0tLS0tLS0tLS0tIHw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfDotLS0tLS0tLS0tLS0tIHwKfCBQSSAgICAgICAgICAgfCDinIUgICAgICAgICAgICAgICAgICB8IOKchSAgICAgICAgICAgICAgICB8IOKPsyAgICAgICAgICAgICAgICAgICB8IOKPsyAgICAgICAgICAgICAgICAgICAgICAgICAgfCDinIUgICAgICAgICAgICAgfAp8IExhYiBNYW5hZ2VyICB8IOKchSAgICAgICAgICAgICAgICAgIHwg4pyFICAgICAgICAgICAgICAgIHwg4o+zICAgICAgICAgICAgICAgICAgIHwg4o+zICAgICAgICAgICAgICAgICAgICAgICAgICB8IOKchSAgICAgICAgICAgICB8CnwgR3JhZCBTdHVkZW50IHwgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICB8IOKchSAgICAgICAgICAgICAgICAgICB8IOKchSAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgIHwKCj4gTGVnZW5kOgo+Cj4g4pyFID0gRnJlcXVlbnQKPgo+IOKPsyA9IE9jY2FzaW9uYWwKCjxicj4KCiMjIyBSZXNvdXJjZSBNYW5hZ2VtZW50IFBvcnRhbAoKIVtdKGltYWdlcy9Nb2R1bGUwMV9yZXNvdXJjZV9tYW5hZ2VtZW50X3BvcnRhbC5wbmcpCgpBIGtleSBwYXJ0IG9mIGhvdyB3ZSB3aWxsIG1hbmFnZSBvdXIgQVJDIHJlc291cmNlcyBpcyB0aHJvdWdoIHRoZWlyIFJlc291cmNlIE1hbmFnZW1lbnQgUG9ydGFsLCBzaG93biBoZXJlLiAKClRoaXMgcG9ydGFsIGNhbiBiZSBmb3VuZCBhdCBbaHR0cHM6Ly9wb3J0YWwuYXJjLnVtaWNoLmVkdV0oaHR0cHM6Ly9wb3J0YWwuYXJjLnVtaWNoLmVkdSkuCgpMZXQncyBub3QgZ28gdGhlcmUganVzdCB5ZXQsIGJ1dCBkaXNjdXNzIHdoYXQgd2Ugc2VlIGluIHRoaXMgc2NyZWVuc2hvdCwgYW5kIHRoZW4gbW92ZSBvbiB0byB0aGUgZXhlcmNpc2UuIFdlJ2xsIGxlYXJuIGFib3V0IHNvbWUgb2YgdGhlIGRpZmZlcmVuY2VzIHRoYXQgd2UgbWF5IHNlZSBkZXBlbmRpbmcgb24gb3VyIGN1cnJlbnQgc3RhdHVzIGFuZCBleGlzdGluZyByZXNvdXJjZXMsIGFuZCB3ZSdsbCBsZWFybiB0aGF0IHRoZXJlIGFyZSBzb21lIGRpZmZlcmVuY2VzIGluIHRoZSBiZXN0IHdheSB0byByZXF1ZXN0IFVNUkNQIHJlc291cmNlcyBkZXBlbmRpbmcgb24gdGhlc2UgZGV0YWlscy4KCjxicj4KCgojIyBFeGVyY2lzZTogTWFrZSBhIEdhbWUgUGxhbiBmb3IgVU1SQ1AKCkluIHRoaXMgZXhlcmNpc2Ugd2Ugd2lsbCBkZXRlcm1pbmUgdGhlIG5lZWRzIGZvciBVTVJDUCBlbnJvbGxtZW50IGJ5IGF1ZGllbmNlICYgdGhlaXIgUElzLgoKVGhlcmUgYXJlIHR3byB2aWRlbyBsaW5rcyBiZWxvdy4gVGhlcmUncyBhIGRlY2VudCBhbW91bnQgb2Ygb3ZlcmxhcCBpbiB0aGUgY29udGVudCwgYW5kIHRoZSBtYWluIGlkZWFzIGFyZSBwcmV0dHkgc2ltaWxhci4gSW4gZWl0aGVyIGNhc2UsIHdlIHdpbGwgYmUgZmlsbGluZyBvdXQgdGhlIFVNUkNQIHdlYiBmb3JtcyBhcyBzaG93biBpbiB0aGUgdmlkZW9zLiBEZXBlbmRpbmcgb24gb3VyIGN1cnJlbnQgc3RhdHVzIHRob3VnaCwgd2UgbWF5IGhhdmUgZGlmZmVyZW50IG9wdGltYWwgc3RhcnRpbmcgcG9pbnRzIGFuZCBkaWZmZXJlbnQgdGhpbmdzIHRvIGNvbnNpZGVyLgoKPGJyPgoKW1VNUkNQIEhvdyB0byBFbnJvbGwgLSBOZXcgdG8gQVJDIFNlcnZpY2VzXShodHRwczovL3d3dy5taXZpZGVvLml0LnVtaWNoLmVkdS9tZWRpYS90LzFfaThqNXB1anovMTgxODYwNTYxKQoKPGJyPgoKW1VNUkNQIEhvdyB0byBFbnJvbGwgLSBFeGlzdGluZyBPd25lciBvZiBBUkMgU2VydmljZXNdKGh0dHBzOi8vd3d3Lm1pdmlkZW8uaXQudW1pY2guZWR1L21lZGlhL3QvMV96bmY2eWdrMC8xODE4NjA1NjEpCgo8YnI+Cjxicj4KCnwgW1ByZXZpb3VzIGxlc3Nvbl0oTW9kdWxlMDFfV2FybWluZ19VcC5odG1sKSB8IFtUb3Agb2YgdGhpcyBsZXNzb25dKCN0b3ApIHwgW05leHQgbGVzc29uXShNb2R1bGUwMl90cmFuc2ZlcnJpbmdfZGF0YV9nbG9idXMuaHRtbCkgfAp8IDotLS0gfCA6LS0tLTogfCAtLS06IHwK