Module 5: What is Git and why is it useful for reproducible research?

First off a digression (or an introduction, however you want to look at it), you may be thinking that your research is reproducible already and not really see any benefits to reading what this module is about and employing the suggested techniques. We can tell you from personal experience that unless you make a conscious effort to ensure that your research is reproducible without instruction from you (say in the unlikely event that you got hit by a bus and were never heard from again), it IS NOT reproducible (unpublished anecdotal results from years of research experience by the authors). Research is fully reproducible when you provide sufficient instructions along with data and code that will allow another researcher to reproduce your exact results to all decimal places. We repeat to all decimal places (close enough doesn’t cut it for the reproducible research club). There are many benefits to you besides the altruistic benefit of making science better. These include having a research record that you can go back to (without reinventing the wheel) when you forget what you did 6 months ago, the surprising sense of liberation that comes with transparency (let the world discover my errors!), and no need to explain things to co-workers, grad students, etc. (just send them the link with all the details!).

Now that the digression is over, let’s begin to answer the question for this module.

Git is a software document version control system. Git has been most commonly used in the field of computer science for version control of computer code and to allow for collaborative coding between people working on the same project. It has recently become recognized as an essential tool for helping ensure reproducible research. Typically, many people track file versions in a project directory or folder by adding numbers (e.g. docv1, docv2, docv3) or dates (doc02012018, doc02052018, doc02142018) and sometimes when we think something is done, it’s actually not done and we end up with filenames like final, final2, final3, and finalfinal. Do you have a directory that looks like the one below containing multiple versions of a file?


An actual messy directory:


The proliferation of dozens of file versions over the course of a project can affect research reproducibility when project staff become uncertain about the correct file version. This can happen for example when files have had changes to numbers due to error discovery and correction, which can increase the potential for an incorrect version to be used in the generation of results reported in a manuscript in the absence of a robust version control system. Git tracks file versions behind the scenes and can include messages about changes to each file version. Only the current file version is visible in your directory. Imagine how much work-related stress might be removed if your file directories for manuscripts looked instead like the one below.



How does Git work in a nutshell?

Git works by taking what can be thought of as ‘snapshots’ of a file in a directory that a user has put under version control. In the image below, files A, B, and C are being tracked by Git . In version 2 (i.e. at snapshot time 2), files A and C have changes but B does not. In version 3 (i.e. at snapshot time 3), only file C has changed.

What is GitHub and why is it useful?

GitHub is a free website that uses git and allows you to store version controlled files (among other features) on an accessible cloud-based server platform. Of note, you can use version control for any type of file (code, data, word, PowerPoint, PDFs, etc.) In this module, we will demonstrate how GitHub can be used to host your code, associated data sets, and file versions associated with a project or published manuscript. Making these files publicly accessible improves the quality of scientific research because others are can evaluate the accuracy of the work, add to the work, and learn (hopefully) robust analytic strategies that you have created and shared.

Working with Git

We will give instructions for two commonly used git software tools in this module: GitHub Desktop and Git Bash. GitHub desktop is a point-and-click graphical user interface (GUI) application. Git Bash is a popular command line interface (CLI) that uses Unix commands. Personally we prefer Git Bash not only because it is marginally faster once you learn to use it but because when you use command line, there is a certain cool factor as it is perceived by many as more hardcore than GUI applications (Whoa you know command line? You are so cool!). However, our testers for this module told us to put GitHub Desktop instructions first so we did. However, if you are feeling a bit like a renegade, skip the GitHub desktop instructions and proceed to Git Bash instructions below. Both are free and allow you to do local version control as well as remote version control on GitHub. Of note, you can also drag and drop files into a GitHub website repository that you create (see instructions below), and although it is super easy, it is super softcore and it doesn’t work when you have no internet or are just using Git for local version control.

Step-by-step instructions for GitHub desktop

1. Create a GitHub account

Go to: https://github.com to create an account. For more detailed instructions on using GitHub than are provided below, see: https://guides.github.com/activities/hello-world/.

2. Download and install GitHub desktop

For 64-bit Windows: https://central.github.com/deployments/desktop/desktop/latest/win32

For Mac OS: https://central.github.com/deployments/desktop/desktop/latest/darwin

Or go to https://desktop.github.com/ and find the version for your machine.

3. Open GitHub desktop, sign in and initialize a repository

When you first open GitHub desktop, you will be prompted to enter your user name and password from github.com. Enter these, and click File –> New repository.

Enter a name for your new repository. I called mine Project1, and in the description box, I typed This is my first GitHub repo. I then changed the local path from the default to a more convenient directory (I used the desktop). Finally, I clicked the box for “Initialize this repository with a readme” and then “Create repository”. The readme file is optional and it is a text file created with the repository name in it and nothing else. If you choose to create it here, you can open it on your machine and put more information about the repository in it for you and your team (e.g., a list of all the files you’ve added with more details about each, a brief project overview).

4. Save project file(s) in the repository folder

If you already have a project you’re working on and would like to store/share on GitHub, copy and paste, drag and drop, or otherwise move those files to the new project folder/repository you’ve created. For this tutorial, I created a text file with “hello world” in it, because I have no imagination, and saved it as helloWorld.txt in the Project1 folder. Feel free to do so if you don’t have other files handy or ready for prime time.

5. Commit changes to the repository

Once you’ve moved your files to your version of the Project1 folder, they should appear in GitHub desktop under the “Changes” tab. In the lower left corner there are two boxes, one for a summary and one for a description. Type something in the summary box (I used “This is a test”) and if you like, type a longer description in the description box (I used “My first GitHub commit!”). The summary box is required, and the description box is optional. You can always add more to these or change them later.

Click “Commit to master”. The large GitHub desktop panel will change to read “No local changes…”

6. Send your new repository to your GitHub account

When you’re ready to send your new repository to GitHub, click on “Publish repository” toward the top right of GitHub desktop. A popup will show you the details of the repository. Unless you have an upgraded (paid) GitHub account, you need to unclick the “Keep this code private” box. Review the other information and then click “Publish repository”.

Switch to your browser and go to github.com to verify that your repository is there. Each time you’re working on your project, open GitHub desktop and 1) commit changes, then 2) “Push” the repo to your online GitHub account to save changes in the cloud. You can use the Repository menu –> Push, or use the keyboard shortcut Ctrl P to push changes once committed.

7. Pull your repository down to a local machine after changes

If you’ve pushed your repository to GitHub, and then your colleague makes changes or updates, you’ll need to pull the repository back down to make and then commit new changes to the current version. To do this, first open the repository from your local copy in Git Desktop. Then from the Repository menu, click “Pull”. The current version will be downloaded to your local machine. Then you can make changes, commit, and push your new version to GitHub. Don’t forget to type a brief description of the changes you’ve made to this version. Your colleagues (and your future self) will thank you.

Clone a repository from GitHub to your local machine with Git Desktop

If another team member created a repository that you’re using, or if you find a repository you’d like to have, you can save a local copy to work on yourself and then commit changes and push them to GitHub online.

  • From GitHub desktop, simply click on File –> Clone Repository;
  • Choose one of your existing repositories or fill in the URL to the repository you’d like to save locally;
  • Ensure that the local path points where you would like and click “Clone”;
  • Now you can edit the repo like normal and commit, push, and share changes.

Step-by-step instructions for using Git Bash

Git Bash may be a little intimidating for some researchers without any computer science experience so we provide the following warning. It uses a command line interface, which can be fun to use because it is a very efficient way to use version control for your files (it may carve minutes maybe even hours off of your time spent putting stuff on GitHub over your lifetime). However, if this does not sound like an adventure that you would like to have (learning a command line program), you can stop here. GitHub Desktop is a perfectly fine application that will provide you with the same results as Git Bash.

1. Create a GitHub account.

Go to: https://github.com to create an account. For more additional instructions on using GitHub, see https://guides.github.com/activities/hello-world/.

2. Download and install Git Bash

For Mac users, download and install Git Bash from: https://git-scm.com/download/mac. Helpful tip: If you get an error message that your security preferences do not allow Git Bash to be opened, go into system preferences -> security & privacy -> general and select “open anyways”. If you can’t find git after downloading, go to finder -> go (drop down menu) -> go to the folder and then type folder path and it will probably be “usr/local/bin”. You can drag the folder labeled “git” to another, easier to find location of your choice. If you are not sure of the folder path, go to the git installer and open the readme.txt and it should tell you the path.

For Windows users, download and install Git Bash from: https://git-scm.com/download/win.

3. Open Git Bash and set up your username and email using the same email that you used for your GitHub account

To set up your username type: git config --global user.name "Your user name" at the command prompt (i.e. $)

To set up your user email type: git config --global user.email [enter your email address here without brackets] at the command prompt (i.e. $)

.

4. Create a directory for version control and change your directory in Git Bash to this directory

The first thing you need to do to start using git is create a project directory (a folder) on your computer (or skip this if already have one in mind). Change the directory to the one that you will put under version control by typing cd at the unix command prompt ($) followed by the path in quotation marks as shown below.

.

Note: On Mac, you will be doing all of this in the terminal. You can find the terminal by searching “Terminal” in the search bar.

You will now see that this directory is referred to as the ‘master’ directory. For more help with setting up git see: https://docs.gitlab.com/ce/gitlab-basics/start-using-git.html.

5. Initialize a git repository in the directory you created in step 4

At the command prompt ($), type git init to initialize a git repository in the directory you created in step 4. The folder labelled .git that is AUTOMATICALLY created with the git init command in the local master directory provides all the necessary metadata for using git (the magic). You can ignore this folder but know that it is essential for using git.

$ git init

6. Put a file under version control.

If you do not have an existing file you want to put under version control for the purposes of this tutorial, you can make an empty text file using notepad or some other text editor. I made a file containing the text “hello world” and saved it as helloworld.txt in my master directory. Once I have the file, I can now add it for version tracking by git using the git add command.

$ git add 'C:.txt' or git add helloworld.txt

The helloworld.txt file has now been added to what is colloquially referred to as the “staging” environment and is ready to be committed as a snapshot (i.e. a version).

7. Record changes in your file to your local repository

You can include a message with git commit to provide information about the changes made to the file or if it is your first file you can include any message you want associated with the file. This is helpful so that you (or your collaborators) know what changes occurred in each version.

$ git commit -m 'This is my first commit!'

This is all you have to do if you only want to control file versions locally. If you want to add version controlled files to a remote repository (such as one on GitHub), proceed to step 8.

8. Create a project repository on GitHub

Go to your GitHub site and log into your account (if you are not already logged in). To create a new GitHub project repository, click the “+” sign next to your icon (in the upper right hand corner of the screen) and select “New repository”. Provide it with a project associated name. You can also click on the green “New repository button” on the right hand side of the screen. I am going to call my GitHub repository Git_demo_files. Click the green ‘Create repository’ button.

10. Add committed version controlled files in your local repository (master) to your GitHub project repository

To do this, you use the git push command shown below. Files must be added and committed before they can be pushed to the remote repository.

$ git push -u origin master

You should see the helloworld.txt file now in your GitHub repository.

Note: You might be prompted for your username and password, just type each and press enter. Your password may not appear, but just trust that you typed it correctly, if you typed it incorrectly then just restart this step

Clone a repository from GitHub to your local machine with Git Bash.

You can also clone a GitHub repository to your local machine to start version control instead of creating a directory as in step 4. To clone a GitHub repository, go to the GitHub repository you want to clone (you may need to create it first as mentioned in step 10) and click the green Clone or download button and then Download to zip.

In the zipped folder, there will be a copy of the repository that you can transfer to a location on your computer that will contain all of your files (if it isn’t empty).

Then follow steps 4-7 (for step 4 start with cd) and step 10 (omit steps 8 and 9) to push versions of files to the GitHub repository. You can also pull versions from the GitHub repository (in the case that you are working with a collaborator) so that you have the most recent version using the command git pull origin master. You can then repeat the cycle (work on the new file version, add and commit it as a new version, and then push it back to the GitHub repository).

Final words on Git Bash

It gets more complicated but this should be enough to get you started with using git for version control to enhance the reproducibility of your research. To learn more about working with the git version control system (including branching and merging that are important concepts for working collaboratively), see this excellent resource: https://git-scm.com/book/en/v2

Other useful commands (from various sources):

To change GitHub repositories:

$ git remote rm origin

Following this command, add a new origin as described in step 9.

To remove all files from the staging area:

$ git reset HEAD -- .

To remove a single file from staging area:

$ git reset HEAD -- "path/to/file"

To see files that are to be committed (those in your staging area):

$ git diff --cached

To see files in staging area:

$ git status

To revert to an earlier version of a file:

$ git reset - -hard 'commit hash

Note for ‘commit hash’, you need to insert the long or abbreviated alphanumeric hash number for the commit. You can get with abbreviated hash numbers for each commit with the below command. (For output options, see: https://gitscm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History):

$ git log --pretty=format:"%h %s"--graph

LS0tCnRpdGxlOiAiTW9kdWxlIDUiCm91dHB1dDoKICAgCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGRmX3ByaW50OiB0aWJibGUKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgaW5jbHVkZXM6CiAgICAgICBhZnRlcl9ib2R5OiBHOlxcQ1BIU1NcXE9wZW5TY2llbmNlXFxNb2R1bGVzXFxTdHlsZXNoZWV0c1xcRm9vdC5odG1sCi0tLQo8aGVhZHsjdG9wfT4KCjxzY3JpcHQgc3JjID0gIkc6XFxDUEhTU1xcT3BlblNjaWVuY2VcXE1vZHVsZXNcXFN0eWxlc2hlZXRzXFxNYWluLmpzIj48L3NjcmlwdD4KPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiB0eXBlPSJ0ZXh0L2NzcyIgaHJlZj0iRzpcXENQSFNTXFxPcGVuU2NpZW5jZVxcTW9kdWxlc1xcU3R5bGVzaGVldHNcXE1haW5TdHlsZS5jc3MiPgpgYGB7ciwgZWNobz1GQUxTRX0KaHRtbHRvb2xzOjppbmNsdWRlSFRNTCgiRzpcXENQSFNTXFxPcGVuU2NpZW5jZVxcTW9kdWxlc1xcU3R5bGVzaGVldHNcXE5hdmJhci5odG1sIikKYGBgCjxpbWcgY2xhc3M9ImxvZ28iIHNyYyA9ICJHOlxcQ1BIU1NcXE9wZW5TY2llbmNlXFxNb2R1bGVzXFxjMnMtbG9nby1mb3ItbW9kdWxlcy5qcGciPgogICAKPC9oZWFkPgoKYGBge3Igc2V0dXBPcHRzLCBlY2hvPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1GQUxTRSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTgsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UpCgpgYGAKCiMgTW9kdWxlIDU6IFdoYXQgaXMgR2l0IGFuZCB3aHkgaXMgaXQgdXNlZnVsIGZvciByZXByb2R1Y2libGUgcmVzZWFyY2g/CkZpcnN0IG9mZiBhIGRpZ3Jlc3Npb24gKG9yIGFuIGludHJvZHVjdGlvbiwgaG93ZXZlciB5b3Ugd2FudCB0byBsb29rIGF0IGl0KSwgeW91IG1heSBiZSB0aGlua2luZyB0aGF0IHlvdXIgcmVzZWFyY2ggaXMgcmVwcm9kdWNpYmxlIGFscmVhZHkgYW5kIG5vdCByZWFsbHkgc2VlIGFueSBiZW5lZml0cyB0byByZWFkaW5nIHdoYXQgdGhpcyBtb2R1bGUgaXMgYWJvdXQgYW5kIGVtcGxveWluZyB0aGUgc3VnZ2VzdGVkIHRlY2huaXF1ZXMuIFdlIGNhbiB0ZWxsIHlvdSBmcm9tIHBlcnNvbmFsIGV4cGVyaWVuY2UgdGhhdCB1bmxlc3MgeW91IG1ha2UgYSBjb25zY2lvdXMgZWZmb3J0IHRvIGVuc3VyZSB0aGF0IHlvdXIgcmVzZWFyY2ggaXMgcmVwcm9kdWNpYmxlIHdpdGhvdXQgaW5zdHJ1Y3Rpb24gZnJvbSB5b3UgKHNheSBpbiB0aGUgdW5saWtlbHkgZXZlbnQgdGhhdCB5b3UgZ290IGhpdCBieSBhIGJ1cyBhbmQgd2VyZSBuZXZlciBoZWFyZCBmcm9tIGFnYWluKSwgaXQgSVMgTk9UIHJlcHJvZHVjaWJsZSAodW5wdWJsaXNoZWQgYW5lY2RvdGFsIHJlc3VsdHMgZnJvbSB5ZWFycyBvZiByZXNlYXJjaCBleHBlcmllbmNlIGJ5IHRoZSBhdXRob3JzKS4gUmVzZWFyY2ggaXMgZnVsbHkgcmVwcm9kdWNpYmxlIHdoZW4geW91IHByb3ZpZGUgc3VmZmljaWVudCBpbnN0cnVjdGlvbnMgYWxvbmcgd2l0aCBkYXRhIGFuZCBjb2RlIHRoYXQgd2lsbCBhbGxvdyBhbm90aGVyIHJlc2VhcmNoZXIgdG8gcmVwcm9kdWNlIHlvdXIgZXhhY3QgcmVzdWx0cyB0byBhbGwgZGVjaW1hbCBwbGFjZXMuIFdlIHJlcGVhdCB0byBhbGwgZGVjaW1hbCBwbGFjZXMgKGNsb3NlIGVub3VnaCBkb2Vzbid0IGN1dCBpdCBmb3IgdGhlIHJlcHJvZHVjaWJsZSByZXNlYXJjaCBjbHViKS4gVGhlcmUgYXJlIG1hbnkgYmVuZWZpdHMgdG8geW91IGJlc2lkZXMgdGhlIGFsdHJ1aXN0aWMgYmVuZWZpdCBvZiBtYWtpbmcgc2NpZW5jZSBiZXR0ZXIuIFRoZXNlIGluY2x1ZGUgaGF2aW5nIGEgcmVzZWFyY2ggcmVjb3JkIHRoYXQgeW91IGNhbiBnbyBiYWNrIHRvICh3aXRob3V0IHJlaW52ZW50aW5nIHRoZSB3aGVlbCkgd2hlbiB5b3UgZm9yZ2V0IHdoYXQgeW91IGRpZCA2IG1vbnRocyBhZ28sIHRoZSBzdXJwcmlzaW5nIHNlbnNlIG9mIGxpYmVyYXRpb24gdGhhdCBjb21lcyB3aXRoIHRyYW5zcGFyZW5jeSAobGV0IHRoZSB3b3JsZCBkaXNjb3ZlciBteSBlcnJvcnMhKSwgYW5kIG5vIG5lZWQgdG8gZXhwbGFpbiB0aGluZ3MgdG8gY28td29ya2VycywgZ3JhZCBzdHVkZW50cywgZXRjLiAoanVzdCBzZW5kIHRoZW0gdGhlIGxpbmsgd2l0aCBhbGwgdGhlIGRldGFpbHMhKS4gCgpOb3cgdGhhdCB0aGUgZGlncmVzc2lvbiBpcyBvdmVyLCBsZXQncyBiZWdpbiB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uIGZvciB0aGlzIG1vZHVsZS4KCltHaXRdKGh0dHBzOi8vZ2l0LXNjbS5jb20vYm9vay9lbi92MS9HZXR0aW5nLVN0YXJ0ZWQtR2l0LUJhc2ljcykgaXMgYSBzb2Z0d2FyZSBkb2N1bWVudCB2ZXJzaW9uIGNvbnRyb2wgc3lzdGVtLiBHaXQgaGFzIGJlZW4gbW9zdCBjb21tb25seSB1c2VkIGluIHRoZSBmaWVsZCBvZiBjb21wdXRlciBzY2llbmNlIGZvciB2ZXJzaW9uIGNvbnRyb2wgb2YgY29tcHV0ZXIgY29kZSBhbmQgdG8gYWxsb3cgZm9yIGNvbGxhYm9yYXRpdmUgY29kaW5nIGJldHdlZW4gcGVvcGxlIHdvcmtpbmcgb24gdGhlIHNhbWUgcHJvamVjdC4gSXQgaGFzIHJlY2VudGx5IGJlY29tZSByZWNvZ25pemVkIGFzIGFuIGVzc2VudGlhbCB0b29sIGZvciBoZWxwaW5nIGVuc3VyZSByZXByb2R1Y2libGUgcmVzZWFyY2guIFR5cGljYWxseSwgbWFueSBwZW9wbGUgdHJhY2sgZmlsZSB2ZXJzaW9ucyBpbiBhIHByb2plY3QgZGlyZWN0b3J5IG9yIGZvbGRlciBieSBhZGRpbmcgbnVtYmVycyAoZS5nLiBkb2N2MSwgZG9jdjIsIGRvY3YzKSBvciBkYXRlcyAoZG9jMDIwMTIwMTgsIGRvYzAyMDUyMDE4LCBkb2MwMjE0MjAxOCkgYW5kIHNvbWV0aW1lcyB3aGVuIHdlIHRoaW5rIHNvbWV0aGluZyBpcyBkb25lLCBpdCdzIGFjdHVhbGx5IG5vdCBkb25lIGFuZCB3ZSBlbmQgdXAgd2l0aCBmaWxlbmFtZXMgbGlrZSBmaW5hbCwgZmluYWwyLCBmaW5hbDMsIGFuZCBmaW5hbGZpbmFsLiBEbyB5b3UgaGF2ZSBhIGRpcmVjdG9yeSB0aGF0IGxvb2tzIGxpa2UgdGhlIG9uZSBiZWxvdyBjb250YWluaW5nIG11bHRpcGxlIHZlcnNpb25zIG9mIGEgZmlsZT8gCgo8YnI+CkFuIGFjdHVhbCBtZXNzeSBkaXJlY3Rvcnk6IAo8YnI+PGJyPgohW10obWVzc3lmaWxlZGlyLlBORykKCjxicj4KClRoZSBwcm9saWZlcmF0aW9uIG9mIGRvemVucyBvZiBmaWxlIHZlcnNpb25zIG92ZXIgdGhlIGNvdXJzZSBvZiBhIHByb2plY3QgY2FuIGFmZmVjdCByZXNlYXJjaCByZXByb2R1Y2liaWxpdHkgd2hlbiBwcm9qZWN0IHN0YWZmIGJlY29tZSB1bmNlcnRhaW4gYWJvdXQgdGhlIGNvcnJlY3QgZmlsZSB2ZXJzaW9uLiBUaGlzIGNhbiBoYXBwZW4gZm9yIGV4YW1wbGUgd2hlbiBmaWxlcyBoYXZlIGhhZCBjaGFuZ2VzIHRvIG51bWJlcnMgZHVlIHRvIGVycm9yIGRpc2NvdmVyeSBhbmQgY29ycmVjdGlvbiwgd2hpY2ggY2FuIGluY3JlYXNlIHRoZSBwb3RlbnRpYWwgZm9yIGFuIGluY29ycmVjdCB2ZXJzaW9uIHRvIGJlIHVzZWQgaW4gdGhlIGdlbmVyYXRpb24gb2YgcmVzdWx0cyByZXBvcnRlZCBpbiBhIG1hbnVzY3JpcHQgaW4gdGhlIGFic2VuY2Ugb2YgYSByb2J1c3QgdmVyc2lvbiBjb250cm9sIHN5c3RlbS4gICBHaXQgdHJhY2tzIGZpbGUgdmVyc2lvbnMgYmVoaW5kIHRoZSBzY2VuZXMgYW5kIGNhbiBpbmNsdWRlIG1lc3NhZ2VzIGFib3V0IGNoYW5nZXMgdG8gZWFjaCBmaWxlIHZlcnNpb24uIE9ubHkgdGhlIGN1cnJlbnQgZmlsZSB2ZXJzaW9uIGlzIHZpc2libGUgaW4geW91ciBkaXJlY3RvcnkuIEltYWdpbmUgaG93IG11Y2ggd29yay1yZWxhdGVkIHN0cmVzcyBtaWdodCBiZSByZW1vdmVkIGlmIHlvdXIgZmlsZSBkaXJlY3RvcmllcyBmb3IgbWFudXNjcmlwdHMgbG9va2VkIGluc3RlYWQgbGlrZSB0aGUgb25lIGJlbG93LiAgCgo8YnI+CgohW10oY2xlYW5maWxlZGlyLlBORykKCjxicj4KCiMjSG93IGRvZXMgR2l0IHdvcmsgaW4gYSBudXRzaGVsbD8KR2l0IHdvcmtzIGJ5IHRha2luZyB3aGF0IGNhbiBiZSB0aG91Z2h0IG9mIGFzICdzbmFwc2hvdHMnIG9mIGEgZmlsZSBpbiBhIGRpcmVjdG9yeSB0aGF0IGEgdXNlciBoYXMgcHV0IHVuZGVyIHZlcnNpb24gY29udHJvbC4gIEluIHRoZSBpbWFnZSBiZWxvdywgZmlsZXMgQSwgQiwgYW5kIEMgYXJlIGJlaW5nIHRyYWNrZWQgYnkgR2l0IC4gSW4gdmVyc2lvbiAyIChpLmUuIGF0IHNuYXBzaG90IHRpbWUgMiksIGZpbGVzIEEgYW5kIEMgaGF2ZSBjaGFuZ2VzIGJ1dCBCIGRvZXMgbm90LiBJbiB2ZXJzaW9uIDMgKGkuZS4gYXQgc25hcHNob3QgdGltZSAzKSwgb25seSBmaWxlIEMgaGFzIGNoYW5nZWQuCgoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvcmF3L21hc3Rlci92ZXJzaW9uc092ZXJUaW1lLmpwZykKCgojI1doYXQgaXMgR2l0SHViIGFuZCB3aHkgaXMgaXQgdXNlZnVsPwpHaXRIdWIgaXMgYSBmcmVlIHdlYnNpdGUgdGhhdCB1c2VzIGdpdCBhbmQgYWxsb3dzIHlvdSB0byBzdG9yZSB2ZXJzaW9uIGNvbnRyb2xsZWQgZmlsZXMgKGFtb25nIG90aGVyIGZlYXR1cmVzKSBvbiBhbiBhY2Nlc3NpYmxlIGNsb3VkLWJhc2VkIHNlcnZlciBwbGF0Zm9ybS4gT2Ygbm90ZSwgeW91IGNhbiB1c2UgdmVyc2lvbiBjb250cm9sIGZvciBhbnkgdHlwZSBvZiBmaWxlIChjb2RlLCBkYXRhLCB3b3JkLCBQb3dlclBvaW50LCBQREZzLCBldGMuKSBJbiB0aGlzIG1vZHVsZSwgd2Ugd2lsbCBkZW1vbnN0cmF0ZSBob3cgR2l0SHViIGNhbiBiZSB1c2VkIHRvIGhvc3QgeW91ciBjb2RlLCBhc3NvY2lhdGVkIGRhdGEgc2V0cywgYW5kIGZpbGUgdmVyc2lvbnMgYXNzb2NpYXRlZCB3aXRoIGEgcHJvamVjdCBvciBwdWJsaXNoZWQgbWFudXNjcmlwdC4gTWFraW5nIHRoZXNlIGZpbGVzIHB1YmxpY2x5IGFjY2Vzc2libGUgaW1wcm92ZXMgdGhlIHF1YWxpdHkgb2Ygc2NpZW50aWZpYyByZXNlYXJjaCBiZWNhdXNlIG90aGVycyBhcmUgY2FuIGV2YWx1YXRlIHRoZSBhY2N1cmFjeSBvZiB0aGUgd29yaywgYWRkIHRvIHRoZSB3b3JrLCBhbmQgbGVhcm4gKGhvcGVmdWxseSkgcm9idXN0IGFuYWx5dGljIHN0cmF0ZWdpZXMgdGhhdCB5b3UgaGF2ZSBjcmVhdGVkIGFuZCBzaGFyZWQuCgojI1dvcmtpbmcgd2l0aCBHaXQgCldlIHdpbGwgZ2l2ZSBpbnN0cnVjdGlvbnMgZm9yIHR3byBjb21tb25seSB1c2VkIGdpdCBzb2Z0d2FyZSB0b29scyBpbiB0aGlzIG1vZHVsZTogKkdpdEh1YiBEZXNrdG9wKiBhbmQgKkdpdCBCYXNoKi4gIEdpdEh1YiBkZXNrdG9wIGlzIGEgcG9pbnQtYW5kLWNsaWNrIGdyYXBoaWNhbCB1c2VyIGludGVyZmFjZSAoR1VJKSBhcHBsaWNhdGlvbi4gR2l0IEJhc2ggaXMgYSBwb3B1bGFyIGNvbW1hbmQgbGluZSBpbnRlcmZhY2UgKENMSSkgdGhhdCB1c2VzIFVuaXggY29tbWFuZHMuIFBlcnNvbmFsbHkgd2UgcHJlZmVyIEdpdCBCYXNoIG5vdCBvbmx5IGJlY2F1c2UgaXQgaXMgbWFyZ2luYWxseSBmYXN0ZXIgb25jZSB5b3UgbGVhcm4gdG8gdXNlIGl0IGJ1dCBiZWNhdXNlIHdoZW4geW91IHVzZSBjb21tYW5kIGxpbmUsIHRoZXJlIGlzIGEgY2VydGFpbiBjb29sIGZhY3RvciBhcyBpdCBpcyBwZXJjZWl2ZWQgYnkgbWFueSBhcyBtb3JlIGhhcmRjb3JlIHRoYW4gR1VJIGFwcGxpY2F0aW9ucyAoV2hvYSB5b3Uga25vdyBjb21tYW5kIGxpbmU/IFlvdSBhcmUgc28gY29vbCEpLiBIb3dldmVyLCBvdXIgdGVzdGVycyBmb3IgdGhpcyBtb2R1bGUgdG9sZCB1cyB0byBwdXQgR2l0SHViIERlc2t0b3AgaW5zdHJ1Y3Rpb25zIGZpcnN0IHNvIHdlIGRpZC4gSG93ZXZlciwgaWYgeW91IGFyZSBmZWVsaW5nIGEgYml0IGxpa2UgYSByZW5lZ2FkZSwgc2tpcCB0aGUgR2l0SHViIGRlc2t0b3AgaW5zdHJ1Y3Rpb25zIGFuZCBwcm9jZWVkIHRvIEdpdCBCYXNoIGluc3RydWN0aW9ucyBiZWxvdy4gQm90aCBhcmUgZnJlZSBhbmQgYWxsb3cgeW91IHRvIGRvIGxvY2FsIHZlcnNpb24gY29udHJvbCBhcyB3ZWxsIGFzIHJlbW90ZSB2ZXJzaW9uIGNvbnRyb2wgb24gR2l0SHViLiBPZiBub3RlLCB5b3UgY2FuIGFsc28gZHJhZyBhbmQgZHJvcCBmaWxlcyBpbnRvIGEgR2l0SHViIHdlYnNpdGUgcmVwb3NpdG9yeSB0aGF0IHlvdSBjcmVhdGUgKHNlZSBpbnN0cnVjdGlvbnMgYmVsb3cpLCBhbmQgYWx0aG91Z2ggaXQgaXMgc3VwZXIgZWFzeSwgaXQgaXMgc3VwZXIgc29mdGNvcmUgYW5kIGl0IGRvZXNuJ3Qgd29yayB3aGVuIHlvdSBoYXZlIG5vIGludGVybmV0IG9yIGFyZSBqdXN0IHVzaW5nIEdpdCBmb3IgbG9jYWwgdmVyc2lvbiBjb250cm9sLiAKCgojIyNTdGVwLWJ5LXN0ZXAgaW5zdHJ1Y3Rpb25zIGZvciBHaXRIdWIgZGVza3RvcAoKCiMjIyMxLiBDcmVhdGUgYSBHaXRIdWIgYWNjb3VudApHbyB0bzogaHR0cHM6Ly9naXRodWIuY29tIHRvIGNyZWF0ZSBhbiBhY2NvdW50LiBGb3IgbW9yZSBkZXRhaWxlZCBpbnN0cnVjdGlvbnMgb24gdXNpbmcgR2l0SHViIHRoYW4gYXJlIHByb3ZpZGVkIGJlbG93LCBzZWU6IGh0dHBzOi8vZ3VpZGVzLmdpdGh1Yi5jb20vYWN0aXZpdGllcy9oZWxsby13b3JsZC8uCgojIyMjMi4gRG93bmxvYWQgYW5kIGluc3RhbGwgR2l0SHViIGRlc2t0b3AKCkZvciA2NC1iaXQgV2luZG93czogaHR0cHM6Ly9jZW50cmFsLmdpdGh1Yi5jb20vZGVwbG95bWVudHMvZGVza3RvcC9kZXNrdG9wL2xhdGVzdC93aW4zMiAKCkZvciBNYWMgT1M6IGh0dHBzOi8vY2VudHJhbC5naXRodWIuY29tL2RlcGxveW1lbnRzL2Rlc2t0b3AvZGVza3RvcC9sYXRlc3QvZGFyd2luIAoKT3IgZ28gdG8gaHR0cHM6Ly9kZXNrdG9wLmdpdGh1Yi5jb20vIGFuZCBmaW5kIHRoZSB2ZXJzaW9uIGZvciB5b3VyIG1hY2hpbmUuCgoKIyMjIzMuIE9wZW4gR2l0SHViIGRlc2t0b3AsIHNpZ24gaW4gYW5kIGluaXRpYWxpemUgYSByZXBvc2l0b3J5CgpXaGVuIHlvdSBmaXJzdCBvcGVuIEdpdEh1YiBkZXNrdG9wLCB5b3Ugd2lsbCBiZSBwcm9tcHRlZCB0byBlbnRlciB5b3VyIHVzZXIgbmFtZSBhbmQgcGFzc3dvcmQgZnJvbSBnaXRodWIuY29tLiBFbnRlciB0aGVzZSwgYW5kIGNsaWNrIEZpbGUgLS0+IE5ldyByZXBvc2l0b3J5LiAKCkVudGVyIGEgbmFtZSBmb3IgeW91ciBuZXcgcmVwb3NpdG9yeS4gSSBjYWxsZWQgbWluZSAqUHJvamVjdDEqLCBhbmQgaW4gdGhlIGRlc2NyaXB0aW9uIGJveCwgSSB0eXBlZCAqVGhpcyBpcyBteSBmaXJzdCBHaXRIdWIgcmVwbyouIEkgdGhlbiBjaGFuZ2VkIHRoZSBsb2NhbCBwYXRoIGZyb20gdGhlIGRlZmF1bHQgdG8gYSBtb3JlIGNvbnZlbmllbnQgZGlyZWN0b3J5IChJIHVzZWQgdGhlIGRlc2t0b3ApLiBGaW5hbGx5LCBJIGNsaWNrZWQgdGhlIGJveCBmb3IgIkluaXRpYWxpemUgdGhpcyByZXBvc2l0b3J5IHdpdGggYSByZWFkbWUiIGFuZCB0aGVuICJDcmVhdGUgcmVwb3NpdG9yeSIuIFRoZSByZWFkbWUgZmlsZSBpcyBvcHRpb25hbCBhbmQgaXQgaXMgYSB0ZXh0IGZpbGUgY3JlYXRlZCB3aXRoIHRoZSByZXBvc2l0b3J5IG5hbWUgaW4gaXQgYW5kIG5vdGhpbmcgZWxzZS4gSWYgeW91IGNob29zZSB0byBjcmVhdGUgaXQgaGVyZSwgeW91IGNhbiBvcGVuIGl0IG9uIHlvdXIgbWFjaGluZSBhbmQgcHV0IG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHJlcG9zaXRvcnkgaW4gaXQgZm9yIHlvdSBhbmQgeW91ciB0ZWFtICgqZS5nLiosIGEgbGlzdCBvZiBhbGwgdGhlIGZpbGVzIHlvdSd2ZSBhZGRlZCB3aXRoIG1vcmUgZGV0YWlscyBhYm91dCBlYWNoLCBhIGJyaWVmIHByb2plY3Qgb3ZlcnZpZXcpLgoKPGltZyBzcmM9Imh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvcmF3L21hc3Rlci9kZXNrdG9wSU1HMS5QTkciPgoKIyMjIzQuIFNhdmUgcHJvamVjdCBmaWxlKHMpIGluIHRoZSByZXBvc2l0b3J5IGZvbGRlcgoKSWYgeW91IGFscmVhZHkgaGF2ZSBhIHByb2plY3QgeW91J3JlIHdvcmtpbmcgb24gYW5kIHdvdWxkIGxpa2UgdG8gc3RvcmUvc2hhcmUgb24gR2l0SHViLCBjb3B5IGFuZCBwYXN0ZSwgZHJhZyBhbmQgZHJvcCwgb3Igb3RoZXJ3aXNlIG1vdmUgdGhvc2UgZmlsZXMgdG8gdGhlIG5ldyBwcm9qZWN0IGZvbGRlci9yZXBvc2l0b3J5IHlvdSd2ZSBjcmVhdGVkLiBGb3IgdGhpcyB0dXRvcmlhbCwgSSBjcmVhdGVkIGEgdGV4dCBmaWxlIHdpdGggImhlbGxvIHdvcmxkIiBpbiBpdCwgYmVjYXVzZSBJIGhhdmUgbm8gaW1hZ2luYXRpb24sIGFuZCBzYXZlZCBpdCBhcyBoZWxsb1dvcmxkLnR4dCBpbiB0aGUgKlByb2plY3QxKiBmb2xkZXIuIEZlZWwgZnJlZSB0byBkbyBzbyBpZiB5b3UgZG9uJ3QgaGF2ZSBvdGhlciBmaWxlcyBoYW5keSBvciByZWFkeSBmb3IgcHJpbWUgdGltZS4KCiMjIyM1LiBDb21taXQgY2hhbmdlcyB0byB0aGUgcmVwb3NpdG9yeQoKT25jZSB5b3UndmUgbW92ZWQgeW91ciBmaWxlcyB0byB5b3VyIHZlcnNpb24gb2YgdGhlICpQcm9qZWN0MSogZm9sZGVyLCB0aGV5IHNob3VsZCBhcHBlYXIgaW4gR2l0SHViIGRlc2t0b3AgdW5kZXIgdGhlICJDaGFuZ2VzIiB0YWIuIEluIHRoZSBsb3dlciBsZWZ0IGNvcm5lciB0aGVyZSBhcmUgdHdvIGJveGVzLCBvbmUgZm9yIGEgc3VtbWFyeSBhbmQgb25lIGZvciBhIGRlc2NyaXB0aW9uLiBUeXBlIHNvbWV0aGluZyBpbiB0aGUgc3VtbWFyeSBib3ggKEkgdXNlZCAiVGhpcyBpcyBhIHRlc3QiKSBhbmQgaWYgeW91IGxpa2UsIHR5cGUgYSBsb25nZXIgZGVzY3JpcHRpb24gaW4gdGhlIGRlc2NyaXB0aW9uIGJveCAoSSB1c2VkICJNeSBmaXJzdCBHaXRIdWIgY29tbWl0ISIpLiBUaGUgc3VtbWFyeSBib3ggaXMgcmVxdWlyZWQsIGFuZCB0aGUgZGVzY3JpcHRpb24gYm94IGlzIG9wdGlvbmFsLiBZb3UgY2FuIGFsd2F5cyBhZGQgbW9yZSB0byB0aGVzZSBvciBjaGFuZ2UgdGhlbSBsYXRlci4KCjxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20va2lqb2huc29uL0dpdGh1Yi1HaXQtTW9kdWxlL2NhZjgzNTgzMjk1N2ZlYzBhYzNhNzdmZDIxMmY2MTVmMmQyOTI2NWUvZGVza3RvcElNRzIuUE5HIj4KCkNsaWNrICJDb21taXQgdG8gbWFzdGVyIi4gVGhlIGxhcmdlIEdpdEh1YiBkZXNrdG9wIHBhbmVsIHdpbGwgY2hhbmdlIHRvIHJlYWQgIk5vIGxvY2FsIGNoYW5nZXMuLi4iIAoKPGltZyBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvY2FmODM1ODMyOTU3ZmVjMGFjM2E3N2ZkMjEyZjYxNWYyZDI5MjY1ZS9kZXNrdG9wSU1HMy5QTkciPgoKIyMjIzYuIFNlbmQgeW91ciBuZXcgcmVwb3NpdG9yeSB0byB5b3VyIEdpdEh1YiBhY2NvdW50CgpXaGVuIHlvdSdyZSByZWFkeSB0byBzZW5kIHlvdXIgbmV3IHJlcG9zaXRvcnkgdG8gR2l0SHViLCBjbGljayBvbiAiUHVibGlzaCByZXBvc2l0b3J5IiB0b3dhcmQgdGhlIHRvcCByaWdodCBvZiBHaXRIdWIgZGVza3RvcC4gQSBwb3B1cCB3aWxsIHNob3cgeW91IHRoZSBkZXRhaWxzIG9mIHRoZSByZXBvc2l0b3J5LiBVbmxlc3MgeW91IGhhdmUgYW4gdXBncmFkZWQgKHBhaWQpIEdpdEh1YiBhY2NvdW50LCB5b3UgbmVlZCB0byB1bmNsaWNrIHRoZSAiS2VlcCB0aGlzIGNvZGUgcHJpdmF0ZSIgYm94LiBSZXZpZXcgdGhlIG90aGVyIGluZm9ybWF0aW9uIGFuZCB0aGVuIGNsaWNrICJQdWJsaXNoIHJlcG9zaXRvcnkiLiAKClN3aXRjaCB0byB5b3VyIGJyb3dzZXIgYW5kIGdvIHRvIGdpdGh1Yi5jb20gdG8gdmVyaWZ5IHRoYXQgeW91ciByZXBvc2l0b3J5IGlzIHRoZXJlLiBFYWNoIHRpbWUgeW91J3JlIHdvcmtpbmcgb24geW91ciBwcm9qZWN0LCBvcGVuIEdpdEh1YiBkZXNrdG9wIGFuZCAxKSBjb21taXQgY2hhbmdlcywgdGhlbiAyKSAiUHVzaCIgdGhlIHJlcG8gdG8geW91ciBvbmxpbmUgR2l0SHViIGFjY291bnQgdG8gc2F2ZSBjaGFuZ2VzIGluIHRoZSBjbG91ZC4gWW91IGNhbiB1c2UgdGhlIFJlcG9zaXRvcnkgbWVudSAtLT4gUHVzaCwgb3IgdXNlIHRoZSBrZXlib2FyZCBzaG9ydGN1dCAqQ3RybCBQKiB0byBwdXNoIGNoYW5nZXMgb25jZSBjb21taXR0ZWQuCgojIyMjNy4gUHVsbCB5b3VyIHJlcG9zaXRvcnkgZG93biB0byBhIGxvY2FsIG1hY2hpbmUgYWZ0ZXIgY2hhbmdlcwoKSWYgeW91J3ZlIHB1c2hlZCB5b3VyIHJlcG9zaXRvcnkgdG8gR2l0SHViLCBhbmQgdGhlbiB5b3VyIGNvbGxlYWd1ZSBtYWtlcyBjaGFuZ2VzIG9yIHVwZGF0ZXMsIHlvdSdsbCBuZWVkIHRvICpwdWxsKiB0aGUgcmVwb3NpdG9yeSBiYWNrIGRvd24gdG8gbWFrZSBhbmQgdGhlbiBjb21taXQgbmV3IGNoYW5nZXMgdG8gdGhlIGN1cnJlbnQgdmVyc2lvbi4gVG8gZG8gdGhpcywgZmlyc3Qgb3BlbiB0aGUgcmVwb3NpdG9yeSBmcm9tIHlvdXIgbG9jYWwgY29weSBpbiBHaXQgRGVza3RvcC4gVGhlbiBmcm9tIHRoZSBSZXBvc2l0b3J5IG1lbnUsIGNsaWNrICJQdWxsIi4gVGhlIGN1cnJlbnQgdmVyc2lvbiB3aWxsIGJlIGRvd25sb2FkZWQgdG8geW91ciBsb2NhbCBtYWNoaW5lLiBUaGVuIHlvdSBjYW4gbWFrZSBjaGFuZ2VzLCBjb21taXQsIGFuZCAqcHVzaCogeW91ciBuZXcgdmVyc2lvbiB0byBHaXRIdWIuICpEb24ndCBmb3JnZXQgdG8gdHlwZSBhIGJyaWVmIGRlc2NyaXB0aW9uIG9mIHRoZSBjaGFuZ2VzIHlvdSd2ZSBtYWRlIHRvIHRoaXMgdmVyc2lvbi4gWW91ciBjb2xsZWFndWVzIChhbmQgeW91ciBmdXR1cmUgc2VsZikgd2lsbCB0aGFuayB5b3UuKgoKPGltZyBzcmM9Imh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvcmF3L21hc3Rlci9kZXNrdG9wSU1HNC5wbmciPgoKIyMjI0Nsb25lIGEgcmVwb3NpdG9yeSBmcm9tIEdpdEh1YiB0byB5b3VyIGxvY2FsIG1hY2hpbmUgd2l0aCBHaXQgRGVza3RvcAoKSWYgYW5vdGhlciB0ZWFtIG1lbWJlciBjcmVhdGVkIGEgcmVwb3NpdG9yeSB0aGF0IHlvdSdyZSB1c2luZywgb3IgaWYgeW91IGZpbmQgYSByZXBvc2l0b3J5IHlvdSdkIGxpa2UgdG8gaGF2ZSwgeW91IGNhbiBzYXZlIGEgbG9jYWwgY29weSB0byB3b3JrIG9uIHlvdXJzZWxmIGFuZCB0aGVuIGNvbW1pdCBjaGFuZ2VzIGFuZCBwdXNoIHRoZW0gdG8gR2l0SHViIG9ubGluZS4gCgotIEZyb20gR2l0SHViIGRlc2t0b3AsIHNpbXBseSBjbGljayBvbiBGaWxlIC0tPiBDbG9uZSBSZXBvc2l0b3J5OwotIENob29zZSBvbmUgb2YgeW91ciBleGlzdGluZyByZXBvc2l0b3JpZXMgb3IgZmlsbCBpbiB0aGUgVVJMIHRvIHRoZSByZXBvc2l0b3J5IHlvdSdkIGxpa2UgdG8gc2F2ZSBsb2NhbGx5OwotIEVuc3VyZSB0aGF0IHRoZSBsb2NhbCBwYXRoIHBvaW50cyB3aGVyZSB5b3Ugd291bGQgbGlrZSBhbmQgY2xpY2sgIkNsb25lIjsKLSBOb3cgeW91IGNhbiBlZGl0IHRoZSByZXBvIGxpa2Ugbm9ybWFsIGFuZCBjb21taXQsIHB1c2gsIGFuZCBzaGFyZSBjaGFuZ2VzLgoKCiMjI1N0ZXAtYnktc3RlcCBpbnN0cnVjdGlvbnMgZm9yIHVzaW5nIEdpdCBCYXNoIApHaXQgQmFzaCBtYXkgYmUgYSBsaXR0bGUgaW50aW1pZGF0aW5nIGZvciBzb21lIHJlc2VhcmNoZXJzIHdpdGhvdXQgYW55IGNvbXB1dGVyIHNjaWVuY2UgZXhwZXJpZW5jZSBzbyB3ZSBwcm92aWRlIHRoZSBmb2xsb3dpbmcgd2FybmluZy4gSXQgdXNlcyBhIGNvbW1hbmQgbGluZSBpbnRlcmZhY2UsIHdoaWNoIGNhbiBiZSBmdW4gdG8gdXNlIGJlY2F1c2UgaXQgaXMgYSB2ZXJ5IGVmZmljaWVudCB3YXkgdG8gdXNlIHZlcnNpb24gY29udHJvbCBmb3IgeW91ciBmaWxlcyAoaXQgbWF5IGNhcnZlIG1pbnV0ZXMgbWF5YmUgZXZlbiBob3VycyBvZmYgb2YgeW91ciB0aW1lIHNwZW50IHB1dHRpbmcgc3R1ZmYgb24gR2l0SHViIG92ZXIgeW91ciBsaWZldGltZSkuIEhvd2V2ZXIsIGlmIHRoaXMgZG9lcyBub3Qgc291bmQgbGlrZSBhbiBhZHZlbnR1cmUgdGhhdCB5b3Ugd291bGQgbGlrZSB0byBoYXZlIChsZWFybmluZyBhIGNvbW1hbmQgbGluZSBwcm9ncmFtKSwgeW91IGNhbiBzdG9wIGhlcmUuIEdpdEh1YiBEZXNrdG9wIGlzIGEgcGVyZmVjdGx5IGZpbmUgYXBwbGljYXRpb24gdGhhdCB3aWxsIHByb3ZpZGUgeW91IHdpdGggdGhlIHNhbWUgcmVzdWx0cyBhcyBHaXQgQmFzaC4gCgojIyMjMS4gQ3JlYXRlIGEgR2l0SHViIGFjY291bnQuCkdvIHRvOiBodHRwczovL2dpdGh1Yi5jb20gdG8gY3JlYXRlIGFuIGFjY291bnQuIEZvciBtb3JlIGFkZGl0aW9uYWwgaW5zdHJ1Y3Rpb25zIG9uIHVzaW5nIEdpdEh1Yiwgc2VlIGh0dHBzOi8vZ3VpZGVzLmdpdGh1Yi5jb20vYWN0aXZpdGllcy9oZWxsby13b3JsZC8uCgojIyMjMi4gRG93bmxvYWQgYW5kIGluc3RhbGwgR2l0IEJhc2gKCioqRm9yIE1hYyB1c2VycyoqLCBkb3dubG9hZCBhbmQgaW5zdGFsbCBHaXQgQmFzaCBmcm9tOiBodHRwczovL2dpdC1zY20uY29tL2Rvd25sb2FkL21hYy4gKipIZWxwZnVsIHRpcCoqOiBJZiB5b3UgZ2V0IGFuIGVycm9yIG1lc3NhZ2UgdGhhdCB5b3VyIHNlY3VyaXR5IHByZWZlcmVuY2VzIGRvIG5vdCBhbGxvdyBHaXQgQmFzaCB0byBiZSBvcGVuZWQsIGdvIGludG8gc3lzdGVtIHByZWZlcmVuY2VzIC0+IHNlY3VyaXR5ICYgcHJpdmFjeSAtPiBnZW5lcmFsIGFuZCBzZWxlY3QgIm9wZW4gYW55d2F5cyIuIElmIHlvdSBjYW4ndCBmaW5kIGdpdCBhZnRlciBkb3dubG9hZGluZywgZ28gdG8gZmluZGVyIC0+IGdvIChkcm9wIGRvd24gbWVudSkgLT4gZ28gdG8gdGhlIGZvbGRlciBhbmQgdGhlbiB0eXBlIGZvbGRlciBwYXRoIGFuZCBpdCB3aWxsIHByb2JhYmx5IGJlICJ1c3IvbG9jYWwvYmluIi4gWW91IGNhbiBkcmFnIHRoZSBmb2xkZXIgbGFiZWxlZCAiZ2l0IiB0byBhbm90aGVyLCBlYXNpZXIgdG8gZmluZCBsb2NhdGlvbiBvZiB5b3VyIGNob2ljZS4gSWYgeW91IGFyZSBub3Qgc3VyZSBvZiB0aGUgZm9sZGVyIHBhdGgsIGdvIHRvIHRoZSBnaXQgaW5zdGFsbGVyIGFuZCBvcGVuIHRoZSByZWFkbWUudHh0IGFuZCBpdCBzaG91bGQgdGVsbCB5b3UgdGhlIHBhdGguCgoqKkZvciBXaW5kb3dzIHVzZXJzKiosIGRvd25sb2FkIGFuZCBpbnN0YWxsIEdpdCBCYXNoIGZyb206IGh0dHBzOi8vZ2l0LXNjbS5jb20vZG93bmxvYWQvd2luLgoKIyMjIzMuIE9wZW4gR2l0IEJhc2ggYW5kIHNldCB1cCB5b3VyIHVzZXJuYW1lIGFuZCBlbWFpbCB1c2luZyB0aGUgc2FtZSBlbWFpbCB0aGF0IHlvdSB1c2VkIGZvciB5b3VyIEdpdEh1YiBhY2NvdW50CgpUbyBzZXQgdXAgeW91ciB1c2VybmFtZSB0eXBlOiBgZ2l0IGNvbmZpZyAtLWdsb2JhbCB1c2VyLm5hbWUgIllvdXIgdXNlciBuYW1lImAgYXQgdGhlIGNvbW1hbmQgcHJvbXB0IChpLmUuIGAkYCkKClRvIHNldCB1cCB5b3VyIHVzZXIgZW1haWwgdHlwZTogYGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5lbWFpbCBbZW50ZXIgeW91ciBlbWFpbCBhZGRyZXNzIGhlcmUgd2l0aG91dCBicmFja2V0c11gIGF0IHRoZSBjb21tYW5kIHByb21wdCAoaS5lLiBgJGApCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2tpam9obnNvbi9HaXRodWItR2l0LU1vZHVsZS9ibG9iL21hc3Rlci9naXRfY29uZmlnLlBORz9yYXc9dHJ1ZSkuCgojIyMjNC4gQ3JlYXRlIGEgZGlyZWN0b3J5IGZvciB2ZXJzaW9uIGNvbnRyb2wgYW5kIGNoYW5nZSB5b3VyIGRpcmVjdG9yeSBpbiBHaXQgQmFzaCB0byB0aGlzIGRpcmVjdG9yeQoKVGhlIGZpcnN0IHRoaW5nIHlvdSBuZWVkIHRvIGRvIHRvIHN0YXJ0IHVzaW5nIGdpdCBpcyBjcmVhdGUgYSBwcm9qZWN0IGRpcmVjdG9yeSAoYSBmb2xkZXIpIG9uIHlvdXIgY29tcHV0ZXIgKG9yIHNraXAgdGhpcyBpZiBhbHJlYWR5IGhhdmUgb25lIGluIG1pbmQpLiBDaGFuZ2UgdGhlIGRpcmVjdG9yeSB0byB0aGUgb25lIHRoYXQgeW91IHdpbGwgcHV0IHVuZGVyIHZlcnNpb24gY29udHJvbCBieSB0eXBpbmcgYGNkYCBhdCB0aGUgdW5peCBjb21tYW5kIHByb21wdCAoYCRgKSBmb2xsb3dlZCBieSB0aGUgcGF0aCBpbiBxdW90YXRpb24gbWFya3MgYXMgc2hvd24gYmVsb3cuIAoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvYmxvYi9tYXN0ZXIvU3RlcDMuUE5HP3Jhdz10cnVlKS4KCipOb3RlOiBPbiBNYWMsIHlvdSB3aWxsIGJlIGRvaW5nIGFsbCBvZiB0aGlzIGluIHRoZSB0ZXJtaW5hbC4gWW91IGNhbiBmaW5kIHRoZSB0ZXJtaW5hbCBieSBzZWFyY2hpbmcgIlRlcm1pbmFsIiBpbiB0aGUgc2VhcmNoIGJhci4qIAoKWW91IHdpbGwgbm93IHNlZSB0aGF0IHRoaXMgZGlyZWN0b3J5IGlzIHJlZmVycmVkIHRvIGFzIHRoZSAnbWFzdGVyJyBkaXJlY3RvcnkuIEZvciBtb3JlIGhlbHAgd2l0aCBzZXR0aW5nIHVwIGdpdCBzZWU6IGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2NlL2dpdGxhYi1iYXNpY3Mvc3RhcnQtdXNpbmctZ2l0Lmh0bWwuCgojIyMjNS4gSW5pdGlhbGl6ZSBhIGdpdCByZXBvc2l0b3J5IGluIHRoZSBkaXJlY3RvcnkgeW91IGNyZWF0ZWQgaW4gc3RlcCA0CgpBdCB0aGUgY29tbWFuZCBwcm9tcHQgKGAkYCksIHR5cGUgYGdpdCBpbml0YCB0byBpbml0aWFsaXplIGEgZ2l0IHJlcG9zaXRvcnkgaW4gdGhlIGRpcmVjdG9yeSB5b3UgY3JlYXRlZCBpbiBzdGVwIDQuIFRoZSBmb2xkZXIgbGFiZWxsZWQgKi5naXQqIHRoYXQgaXMgQVVUT01BVElDQUxMWSBjcmVhdGVkIHdpdGggdGhlIGBnaXQgaW5pdGAgY29tbWFuZCBpbiB0aGUgbG9jYWwgbWFzdGVyIGRpcmVjdG9yeSBwcm92aWRlcyBhbGwgdGhlIG5lY2Vzc2FyeSBtZXRhZGF0YSBmb3IgdXNpbmcgZ2l0ICh0aGUgbWFnaWMpLiBZb3UgY2FuIGlnbm9yZSB0aGlzIGZvbGRlciBidXQga25vdyB0aGF0IGl0IGlzIGVzc2VudGlhbCBmb3IgdXNpbmcgZ2l0LgoKYCQgZ2l0IGluaXRgCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2tpam9obnNvbi9HaXRodWItR2l0LU1vZHVsZS9ibG9iL21hc3Rlci9TdGVwNC5QTkc/cmF3PXRydWUpCgojIyMjNi4gUHV0IGEgZmlsZSB1bmRlciB2ZXJzaW9uIGNvbnRyb2wuCgpJZiB5b3UgZG8gbm90IGhhdmUgYW4gZXhpc3RpbmcgZmlsZSB5b3Ugd2FudCB0byBwdXQgdW5kZXIgdmVyc2lvbiBjb250cm9sIGZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyB0dXRvcmlhbCwgeW91IGNhbiBtYWtlIGFuIGVtcHR5IHRleHQgZmlsZSB1c2luZyBub3RlcGFkIG9yIHNvbWUgb3RoZXIgdGV4dCBlZGl0b3IuIEkgbWFkZSBhIGZpbGUgY29udGFpbmluZyB0aGUgdGV4dCAiaGVsbG8gd29ybGQiIGFuZCBzYXZlZCBpdCBhcyBoZWxsb3dvcmxkLnR4dCBpbiBteSBtYXN0ZXIgZGlyZWN0b3J5LiBPbmNlIEkgaGF2ZSB0aGUgZmlsZSwgSSBjYW4gbm93IGFkZCBpdCBmb3IgdmVyc2lvbiB0cmFja2luZyBieSBnaXQgdXNpbmcgdGhlIGBnaXQgYWRkYCBjb21tYW5kLgoKYCQgZ2l0IGFkZCAnQzoudHh0J2Agb3IgYGdpdCBhZGQgaGVsbG93b3JsZC50eHRgCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2tpam9obnNvbi9HaXRodWItR2l0LU1vZHVsZS9ibG9iL21hc3Rlci9TdGVwNS5QTkc/cmF3PXRydWUpCgoKVGhlIGhlbGxvd29ybGQudHh0IGZpbGUgaGFzIG5vdyBiZWVuIGFkZGVkIHRvIHdoYXQgaXMgY29sbG9xdWlhbGx5IHJlZmVycmVkIHRvIGFzIHRoZSAic3RhZ2luZyIgZW52aXJvbm1lbnQgYW5kIGlzIHJlYWR5IHRvIGJlIGBjb21taXRgdGVkIGFzIGEgc25hcHNob3QgKGkuZS4gYSB2ZXJzaW9uKS4KCiMjIyM3LiBSZWNvcmQgY2hhbmdlcyBpbiB5b3VyIGZpbGUgdG8geW91ciBsb2NhbCByZXBvc2l0b3J5IAoKWW91IGNhbiBpbmNsdWRlIGEgbWVzc2FnZSB3aXRoIGBnaXQgY29tbWl0YCB0byBwcm92aWRlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjaGFuZ2VzIG1hZGUgdG8gdGhlIGZpbGUgb3IgaWYgaXQgaXMgeW91ciBmaXJzdCBmaWxlIHlvdSBjYW4gaW5jbHVkZSBhbnkgbWVzc2FnZSB5b3Ugd2FudCBhc3NvY2lhdGVkIHdpdGggdGhlIGZpbGUuIFRoaXMgaXMgaGVscGZ1bCBzbyB0aGF0IHlvdSAob3IgeW91ciBjb2xsYWJvcmF0b3JzKSBrbm93IHdoYXQgY2hhbmdlcyBvY2N1cnJlZCBpbiBlYWNoIHZlcnNpb24uIAoKYCQgZ2l0IGNvbW1pdCAtbSAnVGhpcyBpcyBteSBmaXJzdCBjb21taXQhJ2AKCiFbXShodHRwczovL2dpdGh1Yi5jb20va2lqb2huc29uL0dpdGh1Yi1HaXQtTW9kdWxlL2Jsb2IvbWFzdGVyL1N0ZXA2LlBORz9yYXc9dHJ1ZSkKClRoaXMgaXMgYWxsIHlvdSBoYXZlIHRvIGRvIGlmIHlvdSBvbmx5IHdhbnQgdG8gY29udHJvbCBmaWxlIHZlcnNpb25zIGxvY2FsbHkuIElmIHlvdSB3YW50IHRvIGFkZCB2ZXJzaW9uIGNvbnRyb2xsZWQgZmlsZXMgdG8gYSByZW1vdGUgcmVwb3NpdG9yeSAoc3VjaCBhcyBvbmUgb24gR2l0SHViKSwgcHJvY2VlZCB0byBzdGVwIDguCgojIyMjOC4gQ3JlYXRlIGEgcHJvamVjdCByZXBvc2l0b3J5IG9uIEdpdEh1YgoKR28gdG8geW91ciBHaXRIdWIgc2l0ZSBhbmQgbG9nIGludG8geW91ciBhY2NvdW50IChpZiB5b3UgYXJlIG5vdCBhbHJlYWR5IGxvZ2dlZCBpbikuIFRvIGNyZWF0ZSBhIG5ldyBHaXRIdWIgcHJvamVjdCByZXBvc2l0b3J5LCBjbGljayB0aGUgIisiIHNpZ24gbmV4dCB0byB5b3VyIGljb24gKGluIHRoZSB1cHBlciByaWdodCBoYW5kIGNvcm5lciBvZiB0aGUgc2NyZWVuKSBhbmQgc2VsZWN0ICJOZXcgcmVwb3NpdG9yeSIuIFByb3ZpZGUgaXQgd2l0aCBhIHByb2plY3QgYXNzb2NpYXRlZCBuYW1lLiBZb3UgY2FuIGFsc28gY2xpY2sgb24gdGhlIGdyZWVuICJOZXcgcmVwb3NpdG9yeSBidXR0b24iIG9uIHRoZSByaWdodCBoYW5kIHNpZGUgb2YgdGhlIHNjcmVlbi4gIEkgYW0gZ29pbmcgdG8gY2FsbCBteSBHaXRIdWIgcmVwb3NpdG9yeSAqR2l0X2RlbW9fZmlsZXMqLiBDbGljayB0aGUgZ3JlZW4gJ0NyZWF0ZSByZXBvc2l0b3J5JyBidXR0b24uCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2tpam9obnNvbi9HaXRodWItR2l0LU1vZHVsZS9ibG9iL21hc3Rlci9jcmVhdGVfcmVwby5wbmc/cmF3PXRydWUpCgojIyMjOS4gTGluayB5b3VyIGxvY2FsIHJlcG9zaXRvcnkgdG8gdGhlIHlvdXIgR2l0SHViIHJlcG9zaXRvcnkgCgpBIHdlYiBhZGRyZXNzIG9mIHlvdXIgcmVtb3RlIHJlcG9zaXRvcnkgY29tbW9ubHkgcmVmZXJyZWQgdG8gYXMgdGhlICpvcmlnaW4qIGlzIG5lZWRlZCB0byBsaW5rIHlvdXIgbG9jYWwgcmVwb3NpdG9yeSB0byB5b3VyIEdpdEh1YiByZXBvc2l0b3J5LiBUaGUgb3JpZ2luIGNhbiBiZSBmb3VuZCBpbiB0aGUgc2NyZWVuIGJlbG93IHRoYXQgY29tZXMgdXAgYWZ0ZXIgeW91ciBjcmVhdGUgeW91ciByZXBvc2l0b3J5LiBJdCBpcyB0aGUgbGluayBpbiB0aGUgdG9wIGJsdWUgYm94IHRvIHRoZSByaWdodCBvZiB0aGUgU1NIIGJveC4gSSBjYW4gYWRkIHRoZSBvcmlnaW4gdG8gdGhlIG1hZ2ljIGdpdCBmb2xkZXIgdXNpbmcgdGhlIGNvbW1hbmQgYmVsb3cuCgpgJCBnaXQgcmVtb3RlIGFkZCBvcmlnaW4gImh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0X2RlbW9fZmlsZXMuZ2l0ImAKCiFbXShodHRwczovL2dpdGh1Yi5jb20va2lqb2huc29uL0dpdGh1Yi1HaXQtTW9kdWxlL2Jsb2IvbWFzdGVyL0Nsb25lLnBuZz9yYXc9dHJ1ZSkKCiMjIyMxMC4gQWRkIGNvbW1pdHRlZCB2ZXJzaW9uIGNvbnRyb2xsZWQgZmlsZXMgaW4geW91ciBsb2NhbCByZXBvc2l0b3J5IChtYXN0ZXIpIHRvIHlvdXIgR2l0SHViIHByb2plY3QgcmVwb3NpdG9yeSAKClRvIGRvIHRoaXMsIHlvdSB1c2UgdGhlIGdpdCBwdXNoIGNvbW1hbmQgc2hvd24gYmVsb3cuIEZpbGVzIG11c3QgYmUgYWRkZWQgYW5kIGNvbW1pdHRlZCBiZWZvcmUgdGhleSBjYW4gYmUgcHVzaGVkIHRvIHRoZSByZW1vdGUgcmVwb3NpdG9yeS4gCgpgJCBnaXQgcHVzaCAtdSBvcmlnaW4gbWFzdGVyYAoKWW91IHNob3VsZCBzZWUgdGhlIGhlbGxvd29ybGQudHh0IGZpbGUgbm93IGluIHlvdXIgR2l0SHViIHJlcG9zaXRvcnkuCgoqTm90ZTogWW91IG1pZ2h0IGJlIHByb21wdGVkIGZvciB5b3VyIHVzZXJuYW1lIGFuZCBwYXNzd29yZCwganVzdCB0eXBlIGVhY2ggYW5kIHByZXNzIGVudGVyLiBZb3VyIHBhc3N3b3JkIG1heSBub3QgYXBwZWFyLCBidXQganVzdCB0cnVzdCB0aGF0IHlvdSB0eXBlZCBpdCBjb3JyZWN0bHksIGlmIHlvdSB0eXBlZCBpdCBpbmNvcnJlY3RseSB0aGVuIGp1c3QgcmVzdGFydCB0aGlzIHN0ZXAqIAoKIyMjI0Nsb25lIGEgcmVwb3NpdG9yeSBmcm9tIEdpdEh1YiB0byB5b3VyIGxvY2FsIG1hY2hpbmUgd2l0aCBHaXQgQmFzaC4KCllvdSBjYW4gYWxzbyBjbG9uZSBhIEdpdEh1YiByZXBvc2l0b3J5IHRvIHlvdXIgbG9jYWwgbWFjaGluZSB0byBzdGFydCB2ZXJzaW9uIGNvbnRyb2wgaW5zdGVhZCBvZiBjcmVhdGluZyBhIGRpcmVjdG9yeSBhcyBpbiBzdGVwIDQuIFRvIGNsb25lIGEgR2l0SHViIHJlcG9zaXRvcnksIGdvIHRvIHRoZSBHaXRIdWIgcmVwb3NpdG9yeSB5b3Ugd2FudCB0byBjbG9uZSAoeW91IG1heSBuZWVkIHRvIGNyZWF0ZSBpdCBmaXJzdCBhcyBtZW50aW9uZWQgaW4gc3RlcCAxMCkgYW5kIGNsaWNrIHRoZSBncmVlbiAqKkNsb25lIG9yIGRvd25sb2FkKiogYnV0dG9uIGFuZCB0aGVuICoqRG93bmxvYWQgdG8gemlwKiouIAoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9raWpvaG5zb24vR2l0aHViLUdpdC1Nb2R1bGUvYmxvYi9tYXN0ZXIvU3RlcDkucG5nP3Jhdz10cnVlKQoKSW4gdGhlIHppcHBlZCBmb2xkZXIsIHRoZXJlIHdpbGwgYmUgYSBjb3B5IG9mIHRoZSByZXBvc2l0b3J5IHRoYXQgeW91IGNhbiB0cmFuc2ZlciB0byBhIGxvY2F0aW9uIG9uIHlvdXIgY29tcHV0ZXIgdGhhdCB3aWxsIGNvbnRhaW4gYWxsIG9mIHlvdXIgZmlsZXMgKGlmIGl0IGlzbid0IGVtcHR5KS4gCgohW10oaHR0cHM6Ly9naXRodWIuY29tL2tpam9obnNvbi9HaXRodWItR2l0LU1vZHVsZS9ibG9iL21hc3Rlci96aXBwZWQuUE5HP3Jhdz10cnVlKQoKVGhlbiBmb2xsb3cgc3RlcHMgNC03IChmb3Igc3RlcCA0IHN0YXJ0IHdpdGggYGNkYCkgYW5kIHN0ZXAgMTAgKG9taXQgc3RlcHMgOCBhbmQgOSkgdG8gcHVzaCB2ZXJzaW9ucyBvZiBmaWxlcyB0byB0aGUgR2l0SHViIHJlcG9zaXRvcnkuIFlvdSBjYW4gYWxzbyBgcHVsbGAgdmVyc2lvbnMgZnJvbSB0aGUgR2l0SHViIHJlcG9zaXRvcnkgKGluIHRoZSBjYXNlIHRoYXQgeW91IGFyZSB3b3JraW5nIHdpdGggYSBjb2xsYWJvcmF0b3IpIHNvIHRoYXQgeW91IGhhdmUgdGhlIG1vc3QgcmVjZW50IHZlcnNpb24gdXNpbmcgdGhlIGNvbW1hbmQgYGdpdCBwdWxsIG9yaWdpbiBtYXN0ZXJgLiBZb3UgY2FuIHRoZW4gcmVwZWF0IHRoZSBjeWNsZSAod29yayBvbiB0aGUgbmV3IGZpbGUgdmVyc2lvbiwgYGFkZGAgYW5kIGBjb21taXRgIGl0IGFzIGEgbmV3IHZlcnNpb24sIGFuZCB0aGVuIGBwdXNoYCBpdCBiYWNrIHRvIHRoZSBHaXRIdWIgcmVwb3NpdG9yeSkuCgojIyMjRmluYWwgd29yZHMgb24gR2l0IEJhc2gKCkl0IGdldHMgbW9yZSBjb21wbGljYXRlZCBidXQgdGhpcyBzaG91bGQgYmUgZW5vdWdoIHRvIGdldCB5b3Ugc3RhcnRlZCB3aXRoIHVzaW5nIGdpdCBmb3IgdmVyc2lvbiBjb250cm9sIHRvIGVuaGFuY2UgdGhlIHJlcHJvZHVjaWJpbGl0eSBvZiB5b3VyIHJlc2VhcmNoLiBUbyBsZWFybiBtb3JlIGFib3V0IHdvcmtpbmcgd2l0aCB0aGUgZ2l0IHZlcnNpb24gY29udHJvbCBzeXN0ZW0gKGluY2x1ZGluZyBicmFuY2hpbmcgYW5kIG1lcmdpbmcgdGhhdCBhcmUgaW1wb3J0YW50IGNvbmNlcHRzIGZvciB3b3JraW5nIGNvbGxhYm9yYXRpdmVseSksIHNlZSB0aGlzIGV4Y2VsbGVudCByZXNvdXJjZTogaHR0cHM6Ly9naXQtc2NtLmNvbS9ib29rL2VuL3YyIAoKCgojIyMjT3RoZXIgdXNlZnVsIGNvbW1hbmRzIChmcm9tIHZhcmlvdXMgc291cmNlcyk6CgpUbyBjaGFuZ2UgR2l0SHViIHJlcG9zaXRvcmllczoKCmAkIGdpdCByZW1vdGUgcm0gb3JpZ2luYAoKRm9sbG93aW5nIHRoaXMgY29tbWFuZCwgYWRkIGEgbmV3IG9yaWdpbiBhcyBkZXNjcmliZWQgaW4gc3RlcCA5LgoKVG8gcmVtb3ZlIGFsbCBmaWxlcyBmcm9tIHRoZSBzdGFnaW5nIGFyZWE6CgpgJCBnaXQgcmVzZXQgSEVBRCAtLSAuYAoKVG8gcmVtb3ZlIGEgc2luZ2xlIGZpbGUgZnJvbSBzdGFnaW5nIGFyZWE6CgpgJCBnaXQgcmVzZXQgSEVBRCAtLSAicGF0aC90by9maWxlImAKClRvIHNlZSBmaWxlcyB0aGF0IGFyZSB0byBiZSBjb21taXR0ZWQgKHRob3NlIGluIHlvdXIgc3RhZ2luZyBhcmVhKToKCmAkIGdpdCBkaWZmIC0tY2FjaGVkYAoKVG8gc2VlIGZpbGVzIGluIHN0YWdpbmcgYXJlYToKCmAkIGdpdCBzdGF0dXNgCgpUbyByZXZlcnQgdG8gYW4gZWFybGllciB2ZXJzaW9uIG9mIGEgZmlsZToKCmAkIGdpdCByZXNldCAtIC1oYXJkICdjb21taXQgaGFzaGAKCk5vdGUgZm9yICdjb21taXQgaGFzaCcsIHlvdSBuZWVkIHRvIGluc2VydCB0aGUgbG9uZyBvciBhYmJyZXZpYXRlZCBhbHBoYW51bWVyaWMgKmhhc2gqIG51bWJlciBmb3IgdGhlIGNvbW1pdC4gIFlvdSBjYW4gZ2V0IHdpdGggYWJicmV2aWF0ZWQgaGFzaCBudW1iZXJzIGZvciBlYWNoIGNvbW1pdCB3aXRoIHRoZSBiZWxvdyBjb21tYW5kLiAoRm9yIG91dHB1dCBvcHRpb25zLCBzZWU6IGh0dHBzOi8vZ2l0c2NtLmNvbS9ib29rL2VuL3YyL0dpdC1CYXNpY3MtVmlld2luZy10aGUtQ29tbWl0LUhpc3RvcnkpOgoKYCQgZ2l0IGxvZyAtLXByZXR0eT1mb3JtYXQ6IiVoICVzIi0tZ3JhcGhgIAoKCgojI1Jlc291cmNlcwotIFtHaXQgdHV0b3JpYWxdKGh0dHBzOi8vd3d3Lmtlcm5lbC5vcmcvcHViL3NvZnR3YXJlL3NjbS9naXQvZG9jcy9naXR0dXRvcmlhbC5odG1sKQotIFtHaXRsYWIgZG9jdW1lbnRhdGlvbiBmb3IgY29tbWFuZCBsaW5lXShodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9jZS9naXRsYWItYmFzaWNzL3N0YXJ0LXVzaW5nLWdpdC5odG1sKQotIFtVc2luZyBHaXQvU1ZOIGZyb20gUlN0dWRpb10oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vcnN0dWRpby1hbmQtZ2l0aHViLykKLSBbR2l0IGJyYW5jaGluZ10oaHR0cHM6Ly9naXQtc2NtLmNvbS9ib29rL2VuL3YyL0dpdC1CcmFuY2hpbmctQnJhbmNoZXMtaW4tYS1OdXRzaGVsbCkK


Reproducibility Toolkit on GitHub

Top