What is a version?
- Contents of a file at a given point in time
- Metadata (information associated with the file):
- The author of the file
- Location
- Type
- Timestamp of the last save
What is version control?
- Version control is a group of systems and
processes
- To manage changes made to documents, programs, and directories
- Version control is useful for anything that:
- changes over time, or
- needs to be shared
Git is a popular
version control system for computer programming and
other projects
Open
source
Scalable (= in terms of projects, collaborators
or resources)
Benefits of Git:
- Git stores contents and metadata, so nothing is
lost
- Git notifies users when there is
conflicting content in files
- Git synchronizes across different people and
computers
Action
- Install Git or check whether you have it already for your respective
operation system: Linux,
MacOs
and Windows.
In case you are Windows users, consider
installing Unix shell along the way. Alternatively, look for
the equivalent
command in your respective shell.
Using Git
- Git commants are run on the shell, also known as
the terminal
- The shell (Zsh, PowerShell,…)
- is a program for executing commants (e.g., create a
folder)
- can be used to easily preview, modify, or inspect files and
directories (= folders)
Action
Useful shell commands
- Locate your current working directory -
pwd
- List all of the items in the current working directory -
ls
- Change a directory -
cd <directory_name>
- Checking Git version -
git --version
- Create or edit a file -
echo
For more commands, see (e.g.) the following article.
Please note that the default
command prompt on Windows uses different
syntax.
- Cloud-based hosting service
- Allows users to store and track their work (= version control)
- On-demand resources over the internet, such as
storage
There are plenty of sites on the Internet where you can upload git
repositories with code - e.g. GitLab or BitBucket.
- Use-cases
- Storing projects
- Keeping track of projects and files
- Collaborating with others
- Social network
- Open-source projects
GitHub enhances Git, but cannot be used without
it.
Action
- If you don’t already have a user account on github.com, go there and
create one.
Clone a repository (git clone
)
- To get started, let’s try working with a repository created for the
purposes of this workshop.
Action
- Type the following command in your command line:
git clone https://github.com/VGabrhel/git-scientific-communication.git
- A new repository will be created - a directory with the name
git-scientific-communication
that contains folders and
files.
Action
- You can look at the URL you used in this example in
your browser. There, you’ll see a list of
files and lots of links to information about
the repository (for example, under “commits” is the
history).
Action
Switch to the new directory
(cd git-scientific-communication
) and try looking at the
history (gitk
or git log
). It may be short,
but it’s important that there is some. You have a copy of a project on
your computer that someone else created!
Your contribution to this project will be a
write to the repository: specifically, adding a file
with your name on it.
- The name (or distinct identificator) is there
to avoid clashes: we need the contributions from all
the people going through this course to be different.
However, your post will be publicly displayed on the
internet. If you don’t want to expose your real name, feel free
to use a nickname, a favorite food, or a few random
letters instead (be original to avoid conflicts).
- Whatever you decide to use, it will be referred to as
<your_name>
further down the line.
Creating a branch
Action
Use git branch
to find out what branch you are
currently on. It should be the master
/ main
branch.
This master
/ main
branch is only good
to use for commits that the whole team has already
agreed on. So when you want to contribute to a project,
the first step is to make a new branch for your contribution and
switch to that branch. For example:
git branch <your_branch>
git checkout <your_branch>
Pushing changes (git push
)
Action
- In R, create a data file to be shared with others.
# Excplicitedly call the source package
library("datasets")
# Import the USArrests dataset from the package
data("USArrests", package = "datasets")
# Save the object as a data frame
USArrests <- as.data.frame(USArrests)
# Export the data frame as a .csv file with <your_name>
write.csv(USArrests, file = "data/USArrests_<your_name>.csv", row.names = FALSE)
Action
- Add a file named after your name (or nickname):
git add USArrests_<your_name>.csv
- Use the
git status
to observe the indicated
changes:
git status
- Commit the added file to git (
git commit
):
git commit -m "Add the USArrests data for the respective contributor"
- Again, use the
git status
and compare the outcome with
the previous status:
git status
- Now all that’s left to do is “just” merge the change into
the original shared repository. But that’s not easy: the
repository you cloned cannot
be changed by just anyone.
- A lot of places on the Internet (blogs, news sites,
e-shops) work in such a way that a select group of
people, “editors”, have the right to change the
content as they like.
- Such editors must be trusted by the project
administrator before they are allowed access.
- With Git, a slightly different
mechanism is used: you upload changes to your own
shared repository, which only you have the right to change. -
You then write a pull request to the owner of
the original project. This could be an email saying “Hey, I
have some changes at so-and-so address that you might find useful! Add
them to your project!”
- The advantage is that anyone can join the project -
if it’s public.
You don’t have to ask beforehand, you don’t have to
prove you’re a trustworthy person, just change something and send it.
- Whether the authors of the project like the change or not is
another matter - but they can judge the change itself, not the
credibility of the author.
- Services like github.com allow you to make your own
shared repository (which will be available on
the web) and make it easy to incorporate
changes (instead of sending an email, just press a button).
Let’s see how to do it.
Action
- Log in to GitHub and then go to the
address you used for
git clone
. Find the
“Fork” button on the top left and click it. This will
create your own copy of the repository on GitHub. The address should be
something like:
https://github.com/<your_github_name>/git-scientific-communication.git
.
Action
- Now, how do you upload changes from your computer to GitHub?
For each repository on your computer, Git remembers the addresses where
you can download and push changes. The
git remote -v command
will show you a list of those
addresses. For example:
git remote -v
origin https://github.com/VGabrhel/git-scientific-communication.git (fetch)
origin https://github.com/VGabrhel/git-scientific-communication.git (push)
- This output means that “origin” is the address from which you cloned
the repository.
Action
Add a similar shortcut for your own repository on GitHub. Don’t
forget to replace your name with the name of the account you have on
GitHub. (Note that your name appears twice in the command!)
git remote add <your_name> https://github.com/<your_github_name>/git-scientific-communication.git
and check that it worked:
git remote -v
origin git@github.com:kpsych-fss-mu/git-scientific-communication.git.git (fetch)
origin git@github.com:kpsych-fss-mu/git-scientific-communication.git.git (push)
<your_name> https://github.com/<your_name>/git-scientific-communication (fetch)
<your_name> https://github.com/<your_name>/git-scientific-communication (push)
Action
- So much for the setup - just do git remote add once for each
repository. Then you can upload changes using:
git push --set-upstream origin <your_branch>
- Which means: push the
<your_branch>
branch
to the address stored under <your_name>
.
Action
- Does it work? Look at
https://github.com/<your_github_name>/git-scientific-communication
in your browser and make sure your changes are there.
Pull request
- Now all you have to do is ask the authors of the original project
to add the changes from your shared repository to their copy. GitHub
has a mechanism for doing this called a pull
request.
Action
Go to the original project’s page (the address you used for
git clone
in the beginning). There you should see a
notification of your newly uploaded branch with a big green
Compare & pull request button.
Click on it. If you want, add/change the
description of what this change entails. Then hit the next
button.
If you don’t see the Compare & pull request button, go to the
address of your copy of the repository and hit the
New pull request button. Select what
you want to include, add/change the label, then press
Create pull request.
You’re done! Now it’s up to the project
authors to look at the changes and accept them
- or start a discussion about how to make them even
better. (You can discuss on the pull request page or via
email.)
This probably won’t happen for adding a name to the attendance
list, but if you needed to work on the change a bit more before
incorporating it (even after a few days of discussion), it wouldn’t be a
problem. Switch to the <your_branch>
branch on your machine, make further
commits, and use git push to update your
<your_branch>
pull request.
Update (git pull
)
- Once your changes - and those of others - have been
merged, you can update your local
repository.
- This is the one on your computer.
Action
First, switch back to the master
branch. Now you won’t be working on <your_branch>
;
that branch is already committed.
This is done with git pull origin master
(pull
changes from the “master” branch from the address under “origin”). You
can use gitk --all
or git log
to see how the
project has evolved in the meantime.
It’s always a good idea to do this git pull
before you start working on a new change/branch. This
will ensure that the project you are changing is
“fresh”.
- Congratulations! You just went through the “round” that most
programmers do every day: making a change, pushing it to colleagues for
review and incorporation, and pulling changes from others.
Bug reporting (issues)
- Occasionally, you find a bug in a GitHub project,
but you don’t have the time or knowledge to fix it.
- In this case, you’ll often find a list of reported issues
on the GitHub project page under the Issues tab.
- If you don’t find “your” bug among them, you can report it - just
click on New Issue and you can post when the bug
occurs, what the program is doing wrong, and what it should be doing
instead.
- Some projects don’t use Issues on GitHub. If you can’t find the
Issues tab, check the project documentation to see if there’s a link to
the bug list.
License
- To make sharing work for legal purposes, it is
not enough to upload a piece of code to the Internet.
You also have to officially announce that others can
play with it.
- This is because you have a copyright on your code
that says others cannot use your program, let alone
improve it, unless you give them permission.
- To formally grant this permission, they use licenses written by
lawyers.
- The issue of licenses can, unfortunately, be quite complex. But if
you simplify it to the minimum, you just want to ensure that everyone
can use your creation, learn from it, pass it on, and improve it. In
that case, choose, for example, the MIT
license.
- In addition, if you want to prevent someone from taking your code
and “improving” it and profiting from it without sharing the
improvements with others, try the AGPL.
- Code is most often licensed by putting the license text into a file
called
LICENSE
and adding it to Git. It is a good idea to
mention the license in the README
file as well.
- If you want to read more about licenses, I refer you to
choosealicense.com, or creativecommons.org and opensource.org.
Next: Hands-on!
Action
- Consider a project where you want tu use Git (and
GitHub; ~15 min)
- What is the nature of the collaboration in this
project?
- Who are the collaborators?
- Create the respective
repository
- Secure the main branch from pushing directly to it
- Set tokens and other security
elements
- Create the README and
licence files
- Push all of the related materials to the
repository and create a pull request
- Let the collaborator review the pushed code.
- After the changes are merged,
checkout to the local main branch and pull the updated remote main
branch.
Resources
- You may find multiple resources for learning git and/or services
like GitHub available for free (although sometimes you need to
register).
Cheat-sheets
Go back to Blog.
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIHZlcnNpb24gY29udHJvbCB3aXRoIEdpdCBmb3IgYSBtb3JlIGVmZmljaWVudCBjb2xsYWJvcmF0aW9uIgphdXRob3I6ICJWaXQgR2FicmhlbCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lCiAgICBjc3M6ICcvVXNlcnMvdml0Z2FicmhlbC9EZXNrdG9wL0dpdC9QZXJzb25hbC9kYXRhbXVzdGZsb3cvcHVibGljL2Nzcy9jb2Rlci5taW4uYTRmMzMyMjEzYTIxY2U4ZWI1MjE2NzBjNjE0NDcwYzU4OTIzYWFhZjM4NWUyYTczOTgyYzMxZGQ3NjQyZGVjYi5jc3MnCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiB5ZXMKLS0tCgojIyAqKldoYXQgaXMgYSB2ZXJzaW9uPyoqCi0gPHU+Q29udGVudHMgb2YgYSBmaWxlIGF0IGEgZ2l2ZW4gcG9pbnQgaW4gdGltZTwvdT4KLSAqKk1ldGFkYXRhKiogKGluZm9ybWF0aW9uIGFzc29jaWF0ZWQgd2l0aCB0aGUgZmlsZSk6CiAgLSAqVGhlIGF1dGhvciBvZiB0aGUgZmlsZSoKICAtICpMb2NhdGlvbioKICAtICpUeXBlKgogIC0gKlRpbWVzdGFtcCBvZiB0aGUgbGFzdCBzYXZlKgogIAojIyAqKldoYXQgaXMgdmVyc2lvbiBjb250cm9sPyoqCi0gKipWZXJzaW9uIGNvbnRyb2wqKiBpcyBhIDx1Pmdyb3VwIG9mIHN5c3RlbXMgYW5kIHByb2Nlc3NlczwvdT4KICAtIFRvIG1hbmFnZSBjaGFuZ2VzIG1hZGUgdG8gZG9jdW1lbnRzLCBwcm9ncmFtcywgYW5kIGRpcmVjdG9yaWVzCi0gVmVyc2lvbiBjb250cm9sIGlzICoqdXNlZnVsKiogZm9yIGFueXRoaW5nIHRoYXQ6CiAgLSAqKmNoYW5nZXMgb3ZlciB0aW1lKiosIG9yCiAgLSAqKm5lZWRzIHRvIGJlIHNoYXJlZCoqIAoKPGltZyBzcmM9InZpei9naXQtbG9nby5wbmciIHdpZHRoPSI0MDAiIGNsYXNzPSJjZW50ZXIiPgoKLSBbR2l0XShodHRwczovL2dpdC1zY20uY29tLykgaXMgYSBwb3B1bGFyICoqdmVyc2lvbiBjb250cm9sIHN5c3RlbSoqIGZvciBjb21wdXRlciBwcm9ncmFtbWluZyBhbmQgb3RoZXIgcHJvamVjdHMgCi0gWyoqT3BlbiBzb3VyY2UqKl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3Blbi1zb3VyY2Vfc29mdHdhcmUpCi0gKipTY2FsYWJsZSoqICg9IGluIHRlcm1zIG9mIHByb2plY3RzLCBjb2xsYWJvcmF0b3JzIG9yIHJlc291cmNlcykKCi0gKipCZW5lZml0cyoqIG9mIEdpdDoKICAtIEdpdCAqKnN0b3JlcyBjb250ZW50cyBhbmQgbWV0YWRhdGEqKiwgc28gbm90aGluZyBpcyBsb3N0CiAgLSBHaXQgKipub3RpZmllcyoqIHVzZXJzIHdoZW4gdGhlcmUgaXMgKipjb25mbGljdGluZyBjb250ZW50KiogaW4gZmlsZXMKICAtIEdpdCAqKnN5bmNocm9uaXplcyoqIGFjcm9zcyBkaWZmZXJlbnQgcGVvcGxlIGFuZCBjb21wdXRlcnMKCj4gKipBY3Rpb24qKgoKLSBJbnN0YWxsIEdpdCBvciBjaGVjayB3aGV0aGVyIHlvdSBoYXZlIGl0IGFscmVhZHkgZm9yIHlvdXIgcmVzcGVjdGl2ZSBvcGVyYXRpb24gc3lzdGVtOgpbTGludXhdKGh0dHBzOi8vZ2l0aHViLmNvbS9naXQtZ3VpZGVzL2luc3RhbGwtZ2l0P2ZiY2xpZD1Jd0FSMWtpaGhFanoyOTVMUTZzNjVCbEl6eGRUYW1UaFFCY1Z6Qm5CczFaRFEwcEtUNEhPSkxaRjlhV1Q4I2luc3RhbGwtZ2l0LW9uLWxpbnV4KSwgW01hY09zXShodHRwczovL2dpdGh1Yi5jb20vZ2l0LWd1aWRlcy9pbnN0YWxsLWdpdD9mYmNsaWQ9SXdBUjFraWhoRWp6Mjk1TFE2czY1QmxJenhkVGFtVGhRQmNWekJuQnMxWkRRMHBLVDRIT0pMWkY5YVdUOCNpbnN0YWxsLWdpdC1vbi13aW5kb3dzKSBhbmQgW1dpbmRvd3NdKGh0dHBzOi8vZ2l0aHViLmNvbS9naXQtZ3VpZGVzL2luc3RhbGwtZ2l0P2ZiY2xpZD1Jd0FSMWtpaGhFanoyOTVMUTZzNjVCbEl6eGRUYW1UaFFCY1Z6Qm5CczFaRFEwcEtUNEhPSkxaRjlhV1Q4I2luc3RhbGwtZ2l0LW9uLXdpbmRvd3MpLgoKSW4gY2FzZSB5b3UgYXJlICoqV2luZG93cyoqIHVzZXJzLCAqKmNvbnNpZGVyIGluc3RhbGxpbmcgVW5peCBzaGVsbCoqIGFsb25nIHRoZSB3YXkuIEFsdGVybmF0aXZlbHksIGxvb2sgZm9yIHRoZSBbZXF1aXZhbGVudCBjb21tYW5kXShodHRwczovL2dpc3QuZ2l0aHViLmNvbS9qb25sYWJlbGxlL2U4YmE5NGNkMjliOGY2M2ZkN2RkM2M0Zjk1YzFkMjEwKSBpbiB5b3VyIHJlc3BlY3RpdmUgc2hlbGwuCgojIyAqKlVzaW5nIEdpdCoqCi0gR2l0IGNvbW1hbnRzIGFyZSBydW4gb24gdGhlICoqc2hlbGwqKiwgYWxzbyBrbm93biBhcyB0aGUgKip0ZXJtaW5hbCoqCi0gVGhlICoqc2hlbGwqKiAoKlpzaCosICpQb3dlclNoZWxsKiwuLi4pCiAgLSBpcyBhICoqcHJvZ3JhbSBmb3IgZXhlY3V0aW5nIGNvbW1hbnRzKiogKGUuZy4sIGNyZWF0ZSBhIGZvbGRlcikKICAtIGNhbiBiZSB1c2VkIHRvIGVhc2lseSA8dT5wcmV2aWV3LCBtb2RpZnksIG9yIGluc3BlY3QgZmlsZXMgYW5kIGRpcmVjdG9yaWVzPC91PiAoPSBmb2xkZXJzKQogIAo+ICoqQWN0aW9uKioKCi0gT3BlbiB5b3VyIHRlcm1pbmFsIC0gZWl0aGVyIGluc2lkZSBhbm90aGVyIHRvb2wgbGlrZSBbUlN0dWRpb10oaHR0cHM6Ly9zdXBwb3J0LnBvc2l0LmNvL2hjL2VuLXVzL2FydGljbGVzLzExNTAxMDczNzE0OC1Vc2luZy10aGUtUlN0dWRpby1UZXJtaW5hbCkgb3IgYXMgYSBbc3RhbmRhbG9uZSBhcHBdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9hLXF1aWNrLWd1aWRlLXRvLXVzaW5nLWNvbW1hbmQtbGluZS10ZXJtaW5hbC05NjgxNWI5N2I5NTUpLgogIAojIyAqKlVzZWZ1bCBzaGVsbCBjb21tYW5kcyoqCgotICpMb2NhdGUgeW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5KiAtIGBwd2RgCi0gKkxpc3QgYWxsIG9mIHRoZSBpdGVtcyBpbiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSogLSBgbHNgCi0gKkNoYW5nZSBhIGRpcmVjdG9yeSogLSBgY2QgPGRpcmVjdG9yeV9uYW1lPmAKLSAqQ2hlY2tpbmcgR2l0IHZlcnNpb24qIC0gYGdpdCAtLXZlcnNpb25gCi0gKkNyZWF0ZSBvciBlZGl0IGEgZmlsZSogLSBgZWNob2AKCkZvciBtb3JlIGNvbW1hbmRzLCBzZWUgKGUuZy4pIHRoZSBmb2xsb3dpbmcgW2FydGljbGVdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9ob3ctdG8tYmVjb21lLWEtY29tbWFuZC1saW5lLXdpemFyZC01ZDc4ZDc1ZmJmMGMpLgoKUGxlYXNlIG5vdGUgdGhhdCB0aGUgWyoqZGVmYXVsdCBjb21tYW5kIHByb21wdCoqXShodHRwczovL3d3dy5tYWtldXNlb2YuY29tL3RhZy9hLWJlZ2lubmVycy1ndWlkZS10by10aGUtd2luZG93cy1jb21tYW5kLWxpbmUpIG9uICoqV2luZG93cyB1c2VzIGRpZmZlcmVudCBzeW50YXgqKi4gCgo8aW1nIHNyYz0idml6L2dpdGh1Yi5wbmciIGFsaWFzPSAiI2dpdGh1YiIgd2lkdGg9IjQwMCIgY2xhc3M9ImNlbnRlciI+CgotIENsb3VkLWJhc2VkIGhvc3RpbmcgKipzZXJ2aWNlKioKLSBBbGxvd3MgdXNlcnMgdG8gc3RvcmUgYW5kIHRyYWNrIHRoZWlyIHdvcmsgKD0gdmVyc2lvbiBjb250cm9sKQotICoqT24tZGVtYW5kIHJlc291cmNlcyoqIG92ZXIgdGhlIGludGVybmV0LCBzdWNoIGFzICoqc3RvcmFnZSoqCgpUaGVyZSBhcmUgcGxlbnR5IG9mIHNpdGVzIG9uIHRoZSBJbnRlcm5ldCB3aGVyZSB5b3UgY2FuIHVwbG9hZCBnaXQgcmVwb3NpdG9yaWVzIHdpdGggY29kZSAtIGUuZy4gW0dpdExhYl0oaHR0cHM6Ly9hYm91dC5naXRsYWIuY29tLykgb3IgW0JpdEJ1Y2tldF0oaHR0cHM6Ly9iaXRidWNrZXQub3JnL3Byb2R1Y3QpLgoKLSA8dT5Vc2UtY2FzZXM8L3U+CiAgLSAqU3RvcmluZyBwcm9qZWN0cyoKICAtICpLZWVwaW5nIHRyYWNrIG9mIHByb2plY3RzIGFuZCBmaWxlcyoKICAtICpDb2xsYWJvcmF0aW5nIHdpdGggb3RoZXJzKgogIC0gKlNvY2lhbCBuZXR3b3JrKgogIC0gKk9wZW4tc291cmNlIHByb2plY3RzKgoKKipHaXRIdWIgZW5oYW5jZXMgR2l0LCBidXQgY2Fubm90IGJlIHVzZWQgd2l0aG91dCBpdC4qKgoKPiAqKkFjdGlvbioqCgotIElmIHlvdSBkb24ndCBhbHJlYWR5IGhhdmUgYSB1c2VyIGFjY291bnQgb24gZ2l0aHViLmNvbSwgZ28gdGhlcmUgYW5kIGNyZWF0ZSBvbmUuCgojIyAqKkNsb25lIGEgcmVwb3NpdG9yeSoqIChgZ2l0IGNsb25lYCkKLSBUbyBnZXQgc3RhcnRlZCwgbGV0J3MgdHJ5IHdvcmtpbmcgd2l0aCBhIHJlcG9zaXRvcnkgY3JlYXRlZCBmb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgd29ya3Nob3AuIAoKPiAqKkFjdGlvbioqCgotIFR5cGUgdGhlIGZvbGxvd2luZyBjb21tYW5kIGluIHlvdXIgY29tbWFuZCBsaW5lOgpgYGAKZ2l0IGNsb25lIGh0dHBzOi8vZ2l0aHViLmNvbS9WR2FicmhlbC9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uLmdpdApgYGAKCi0gQSBuZXcgcmVwb3NpdG9yeSB3aWxsIGJlIGNyZWF0ZWQgLSBhIGRpcmVjdG9yeSB3aXRoIHRoZSBuYW1lIGBnaXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uYCB0aGF0IGNvbnRhaW5zIGZvbGRlcnMgYW5kIGZpbGVzLgoKPiAqKkFjdGlvbioqCgotIFlvdSBjYW4gbG9vayBhdCB0aGUgKipVUkwqKiB5b3UgdXNlZCBpbiB0aGlzIGV4YW1wbGUgaW4geW91ciAqKmJyb3dzZXIqKi4gVGhlcmUsIHlvdSdsbCBzZWUgYSAqKmxpc3Qgb2YgZmlsZXMqKiBhbmQgbG90cyBvZiAqKmxpbmtzKiogdG8gaW5mb3JtYXRpb24gYWJvdXQgdGhlIHJlcG9zaXRvcnkgKGZvciBleGFtcGxlLCB1bmRlciAqKiJjb21taXRzIioqIGlzIHRoZSBoaXN0b3J5KS4KCj4gKipBY3Rpb24qKgoKLSBTd2l0Y2ggdG8gdGhlIG5ldyBkaXJlY3RvcnkgKGBjZCBnaXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uYCkgYW5kIHRyeSBsb29raW5nIGF0IHRoZSBoaXN0b3J5IChgZ2l0a2Agb3IgYGdpdCBsb2dgKS4gSXQgbWF5IGJlIHNob3J0LCBidXQgaXQncyBpbXBvcnRhbnQgdGhhdCB0aGVyZSBpcyBzb21lLiBZb3UgaGF2ZSBhIGNvcHkgb2YgYSBwcm9qZWN0IG9uIHlvdXIgY29tcHV0ZXIgdGhhdCBzb21lb25lIGVsc2UgY3JlYXRlZCEKCi0gKipZb3VyIGNvbnRyaWJ1dGlvbiB0byB0aGlzIHByb2plY3QqKiB3aWxsIGJlIGEgKip3cml0ZSB0byB0aGUgcmVwb3NpdG9yeSoqOiBzcGVjaWZpY2FsbHksIDx1PmFkZGluZyBhIGZpbGUgd2l0aCB5b3VyIG5hbWUgb24gaXQ8L3U+LiAKICAtIFRoZSAqKm5hbWUqKiAob3IgZGlzdGluY3QgaWRlbnRpZmljYXRvcikgaXMgdGhlcmUgKip0byBhdm9pZCBjbGFzaGVzKio6IHdlIG5lZWQgdGhlIGNvbnRyaWJ1dGlvbnMgZnJvbSBhbGwgdGhlIHBlb3BsZSBnb2luZyB0aHJvdWdoIHRoaXMgY291cnNlIHRvIGJlIGRpZmZlcmVudC4KCi0gSG93ZXZlciwgeW91ciBwb3N0IHdpbGwgYmUgKipwdWJsaWNseSBkaXNwbGF5ZWQgb24gdGhlIGludGVybmV0KiouIElmIHlvdSBkb24ndCB3YW50IHRvIGV4cG9zZSB5b3VyIHJlYWwgbmFtZSwgZmVlbCBmcmVlIHRvIHVzZSBhICoqbmlja25hbWUqKiwgYSBmYXZvcml0ZSBmb29kLCBvciBhIGZldyByYW5kb20gbGV0dGVycyBpbnN0ZWFkIChiZSBvcmlnaW5hbCB0byBhdm9pZCBjb25mbGljdHMpLiAKICAtIFdoYXRldmVyIHlvdSBkZWNpZGUgdG8gdXNlLCBpdCB3aWxsIGJlIHJlZmVycmVkIHRvIGFzIGA8eW91cl9uYW1lPmAgZnVydGhlciBkb3duIHRoZSBsaW5lLgoKIyMgKipDcmVhdGluZyBhIGJyYW5jaCoqCgo8aW1nIHNyYz0idml6L29jdG9wdXMuanBlZyIgd2lkdGg9IjYwMCIgY2xhc3M9ImNlbnRlciI+Cgo+ICoqQWN0aW9uKiogCgotIFVzZSBgZ2l0IGJyYW5jaGAgdG8gZmluZCBvdXQgd2hhdCBicmFuY2ggeW91IGFyZSBjdXJyZW50bHkgb24uIEl0IHNob3VsZCBiZSB0aGUgYG1hc3RlcmAgLyBgbWFpbmAgW2JyYW5jaF0oaHR0cHM6Ly93d3cudGhlc2VydmVyc2lkZS5jb20vZmVhdHVyZS9XaHktR2l0SHViLXJlbmFtZWQtaXRzLW1hc3Rlci1icmFuY2gtdG8tbWFpbikuCgotIFRoaXMgYG1hc3RlcmAgLyBgbWFpbmAgYnJhbmNoIGlzIG9ubHkgZ29vZCB0byB1c2UgZm9yIGNvbW1pdHMgdGhhdCB0aGUgd2hvbGUgdGVhbSBoYXMgYWxyZWFkeSAqKmFncmVlZCoqIG9uLiBTbyB3aGVuIHlvdSB3YW50IHRvIGNvbnRyaWJ1dGUgdG8gYSBwcm9qZWN0LCB0aGUgPHU+Zmlyc3Qgc3RlcCBpcyB0byBtYWtlIGEgbmV3IGJyYW5jaCBmb3IgeW91ciBjb250cmlidXRpb24gYW5kIHN3aXRjaCB0byB0aGF0IGJyYW5jaDwvdT4uIEZvciBleGFtcGxlOgpgYGAKZ2l0IGJyYW5jaCA8eW91cl9icmFuY2g+CmdpdCBjaGVja291dCA8eW91cl9icmFuY2g+CmBgYAoKIyMgKipQdXNoaW5nIGNoYW5nZXMqKiAoYGdpdCBwdXNoYCkKPiAqKkFjdGlvbioqCgotIEluIFIsIGNyZWF0ZSBhIGRhdGEgZmlsZSB0byBiZSBzaGFyZWQgd2l0aCBvdGhlcnMuCgpgYGAKIyBFeGNwbGljaXRlZGx5IGNhbGwgdGhlIHNvdXJjZSBwYWNrYWdlCmxpYnJhcnkoImRhdGFzZXRzIikKCiMgSW1wb3J0IHRoZSBVU0FycmVzdHMgZGF0YXNldCBmcm9tIHRoZSBwYWNrYWdlCmRhdGEoIlVTQXJyZXN0cyIsIHBhY2thZ2UgPSAiZGF0YXNldHMiKQoKIyBTYXZlIHRoZSBvYmplY3QgYXMgYSBkYXRhIGZyYW1lClVTQXJyZXN0cyA8LSBhcy5kYXRhLmZyYW1lKFVTQXJyZXN0cykKCiMgRXhwb3J0IHRoZSBkYXRhIGZyYW1lIGFzIGEgLmNzdiBmaWxlIHdpdGggPHlvdXJfbmFtZT4Kd3JpdGUuY3N2KFVTQXJyZXN0cywgZmlsZSA9ICJkYXRhL1VTQXJyZXN0c188eW91cl9uYW1lPi5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgo+ICoqQWN0aW9uKioKCi0gQWRkIGEgZmlsZSBuYW1lZCBhZnRlciB5b3VyIG5hbWUgKG9yIG5pY2tuYW1lKToKYGBgCmdpdCBhZGQgVVNBcnJlc3RzXzx5b3VyX25hbWU+LmNzdgpgYGAKCi0gVXNlIHRoZSBgZ2l0IHN0YXR1c2AgdG8gb2JzZXJ2ZSB0aGUgaW5kaWNhdGVkIGNoYW5nZXM6CmBgYApnaXQgc3RhdHVzCmBgYAoKLSBDb21taXQgdGhlIGFkZGVkIGZpbGUgdG8gZ2l0IChgZ2l0IGNvbW1pdGApOgpgYGAKZ2l0IGNvbW1pdCAtbSAiQWRkIHRoZSBVU0FycmVzdHMgZGF0YSBmb3IgdGhlIHJlc3BlY3RpdmUgY29udHJpYnV0b3IiCmBgYAoKLSBBZ2FpbiwgdXNlIHRoZSBgZ2l0IHN0YXR1c2AgYW5kIGNvbXBhcmUgdGhlIG91dGNvbWUgd2l0aCB0aGUgcHJldmlvdXMgc3RhdHVzOgpgYGAKZ2l0IHN0YXR1cwpgYGAKCi0gTm93IGFsbCB0aGF0J3MgbGVmdCB0byBkbyBpcyAianVzdCIgKiptZXJnZSB0aGUgY2hhbmdlIGludG8gdGhlIG9yaWdpbmFsKiogc2hhcmVkIHJlcG9zaXRvcnkuIEJ1dCB0aGF0J3Mgbm90IGVhc3k6IHRoZSByZXBvc2l0b3J5IHlvdSBjbG9uZWQgW2Nhbm5vdCBiZSBjaGFuZ2VkXShodHRwczovL2RvY3MuZ2l0aHViLmNvbS9lbi9yZXBvc2l0b3JpZXMvY29uZmlndXJpbmctYnJhbmNoZXMtYW5kLW1lcmdlcy1pbi15b3VyLXJlcG9zaXRvcnkvZGVmaW5pbmctdGhlLW1lcmdlYWJpbGl0eS1vZi1wdWxsLXJlcXVlc3RzL21hbmFnaW5nLWEtYnJhbmNoLXByb3RlY3Rpb24tcnVsZSkgYnkganVzdCBhbnlvbmUuCi0gQSBsb3Qgb2YgcGxhY2VzIG9uIHRoZSBJbnRlcm5ldCAoKipibG9ncywgbmV3cyBzaXRlcywgZS1zaG9wcyoqKSB3b3JrIGluIHN1Y2ggYSB3YXkgdGhhdCBhICoqc2VsZWN0IGdyb3VwIG9mIHBlb3BsKiplLCAiZWRpdG9ycyIsIGhhdmUgdGhlICoqcmlnaHQgdG8gY2hhbmdlIHRoZSBjb250ZW50KiogYXMgdGhleSBsaWtlLiAKICAtIFN1Y2ggZWRpdG9ycyBtdXN0IGJlICoqdHJ1c3RlZCBieSB0aGUgcHJvamVjdCBhZG1pbmlzdHJhdG9yKiogYmVmb3JlIHRoZXkgYXJlIGFsbG93ZWQgYWNjZXNzLgotIFdpdGggKipHaXQqKiwgYSBzbGlnaHRseSAqKmRpZmZlcmVudCBtZWNoYW5pc20qKiBpcyB1c2VkOiB5b3UgKip1cGxvYWQgY2hhbmdlcyB0byB5b3VyIG93biBzaGFyZWQgcmVwb3NpdG9yeSoqLCB3aGljaCBvbmx5IHlvdSBoYXZlIHRoZSByaWdodCB0byBjaGFuZ2UuICAgLSBZb3UgdGhlbiAqKndyaXRlIGEgcHVsbCByZXF1ZXN0KiogdG8gdGhlICoqb3duZXIgb2YgdGhlIG9yaWdpbmFsIHByb2plY3QqKi4gVGhpcyBjb3VsZCBiZSBhbiBlbWFpbCBzYXlpbmcgKiJIZXksIEkgaGF2ZSBzb21lIGNoYW5nZXMgYXQgc28tYW5kLXNvIGFkZHJlc3MgdGhhdCB5b3UgbWlnaHQgZmluZCB1c2VmdWwhIEFkZCB0aGVtIHRvIHlvdXIgcHJvamVjdCEiKgotIFRoZSBhZHZhbnRhZ2UgaXMgdGhhdCAqKmFueW9uZSBjYW4qKiBqb2luIHRoZSBwcm9qZWN0IC0gaWYgaXQncyBbKipwdWJsaWMqKl0oaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vcmVwb3NpdG9yaWVzL2NyZWF0aW5nLWFuZC1tYW5hZ2luZy1yZXBvc2l0b3JpZXMvYWJvdXQtcmVwb3NpdG9yaWVzKS4gKipZb3UgZG9uJ3QgaGF2ZSB0byBhc2sgYmVmb3JlaGFuZCoqLCB5b3UgZG9uJ3QgaGF2ZSB0byBwcm92ZSB5b3UncmUgYSB0cnVzdHdvcnRoeSBwZXJzb24sIGp1c3QgY2hhbmdlIHNvbWV0aGluZyBhbmQgc2VuZCBpdC4gCiAgLSA8dT5XaGV0aGVyIHRoZSBhdXRob3JzIG9mIHRoZSBwcm9qZWN0IGxpa2UgdGhlIGNoYW5nZSBvciBub3QgaXMgYW5vdGhlciBtYXR0ZXI8L3U+IC0gYnV0IHRoZXkgY2FuIGp1ZGdlIHRoZSBjaGFuZ2UgaXRzZWxmLCBub3QgdGhlIGNyZWRpYmlsaXR5IG9mIHRoZSBhdXRob3IuCi0gKipTZXJ2aWNlcyoqIGxpa2UgZ2l0aHViLmNvbSBhbGxvdyB5b3UgdG8gbWFrZSB5b3VyIG93biAqKnNoYXJlZCByZXBvc2l0b3J5KiogKHdoaWNoIHdpbGwgYmUgKiphdmFpbGFibGUgb24gdGhlIHdlYioqKSBhbmQgbWFrZSBpdCBlYXN5IHRvICoqaW5jb3Jwb3JhdGUgY2hhbmdlcyoqIChpbnN0ZWFkIG9mIHNlbmRpbmcgYW4gZW1haWwsIGp1c3QgcHJlc3MgYSBidXR0b24pLiBMZXQncyBzZWUgaG93IHRvIGRvIGl0LgoKPiAqKkFjdGlvbioqCgotICoqTG9nIGluIHRvIEdpdEh1YioqIGFuZCB0aGVuIGdvIHRvIHRoZSAqKmFkZHJlc3MqKiB5b3UgdXNlZCBmb3IgYGdpdCBjbG9uZWAuIEZpbmQgdGhlICoqIkZvcmsiKiogYnV0dG9uIG9uIHRoZSB0b3AgbGVmdCBhbmQgY2xpY2sgaXQuIFRoaXMgd2lsbCBjcmVhdGUgeW91ciBvd24gY29weSBvZiB0aGUgcmVwb3NpdG9yeSBvbiBHaXRIdWIuIFRoZSBhZGRyZXNzIHNob3VsZCBiZSBzb21ldGhpbmcgbGlrZTogYGh0dHBzOi8vZ2l0aHViLmNvbS88eW91cl9naXRodWJfbmFtZT4vZ2l0LXNjaWVudGlmaWMtY29tbXVuaWNhdGlvbi5naXRgLgoKPiAqKkFjdGlvbioqCgotIE5vdywgaG93IGRvIHlvdSA8dT51cGxvYWQgY2hhbmdlcyBmcm9tIHlvdXIgY29tcHV0ZXIgdG8gR2l0SHViPC91Pj8gRm9yIGVhY2ggcmVwb3NpdG9yeSBvbiB5b3VyIGNvbXB1dGVyLCBHaXQgcmVtZW1iZXJzIHRoZSBhZGRyZXNzZXMgd2hlcmUgeW91IGNhbiBkb3dubG9hZCBhbmQgcHVzaCBjaGFuZ2VzLiBUaGUgYGdpdCByZW1vdGUgLXYgY29tbWFuZGAgd2lsbCBzaG93IHlvdSBhIGxpc3Qgb2YgdGhvc2UgYWRkcmVzc2VzLiBGb3IgZXhhbXBsZToKYGBgCmdpdCByZW1vdGUgLXYKb3JpZ2luIGh0dHBzOi8vZ2l0aHViLmNvbS9WR2FicmhlbC9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uLmdpdCAoZmV0Y2gpCm9yaWdpbiBodHRwczovL2dpdGh1Yi5jb20vVkdhYnJoZWwvZ2l0LXNjaWVudGlmaWMtY29tbXVuaWNhdGlvbi5naXQgKHB1c2gpCmBgYAotIFRoaXMgb3V0cHV0IG1lYW5zIHRoYXQgIm9yaWdpbiIgaXMgdGhlIGFkZHJlc3MgZnJvbSB3aGljaCB5b3UgY2xvbmVkIHRoZSByZXBvc2l0b3J5LgoKPiAqKkFjdGlvbioqCgotIEFkZCBhIHNpbWlsYXIgc2hvcnRjdXQgZm9yIHlvdXIgb3duIHJlcG9zaXRvcnkgb24gR2l0SHViLiBEb24ndCBmb3JnZXQgdG8gcmVwbGFjZSB5b3VyIG5hbWUgd2l0aCB0aGUgbmFtZSBvZiB0aGUgYWNjb3VudCB5b3UgaGF2ZSBvbiBHaXRIdWIuIChOb3RlIHRoYXQgeW91ciBuYW1lIGFwcGVhcnMgdHdpY2UgaW4gdGhlIGNvbW1hbmQhKQoKLSBgZ2l0IHJlbW90ZSBhZGQgPHlvdXJfbmFtZT4gaHR0cHM6Ly9naXRodWIuY29tLzx5b3VyX2dpdGh1Yl9uYW1lPi9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uLmdpdGAgYW5kIGNoZWNrIHRoYXQgaXQgd29ya2VkOgpgYGAKZ2l0IHJlbW90ZSAtdgpvcmlnaW4gZ2l0QGdpdGh1Yi5jb206a3BzeWNoLWZzcy1tdS9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uLmdpdC5naXQgKGZldGNoKQpvcmlnaW4gZ2l0QGdpdGh1Yi5jb206a3BzeWNoLWZzcy1tdS9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uLmdpdC5naXQgKHB1c2gpCjx5b3VyX25hbWU+IGh0dHBzOi8vZ2l0aHViLmNvbS88eW91cl9uYW1lPi9naXQtc2NpZW50aWZpYy1jb21tdW5pY2F0aW9uIChmZXRjaCkKPHlvdXJfbmFtZT4gaHR0cHM6Ly9naXRodWIuY29tLzx5b3VyX25hbWU+L2dpdC1zY2llbnRpZmljLWNvbW11bmljYXRpb24gKHB1c2gpCmBgYAoKPiAqKkFjdGlvbioqCgotIFNvIG11Y2ggZm9yIHRoZSBzZXR1cCAtIGp1c3QgZG8gZ2l0IHJlbW90ZSBhZGQgb25jZSBmb3IgZWFjaCByZXBvc2l0b3J5LiBUaGVuIHlvdSBjYW4gdXBsb2FkIGNoYW5nZXMgdXNpbmc6CmBgYApnaXQgcHVzaCAtLXNldC11cHN0cmVhbSBvcmlnaW4gPHlvdXJfYnJhbmNoPgpgYGAKCi0gV2hpY2ggbWVhbnM6IHB1c2ggdGhlPC91PiBgPHlvdXJfYnJhbmNoPmAgPHU+YnJhbmNoIHRvIHRoZSBhZGRyZXNzIHN0b3JlZCB1bmRlcjwvdT4gYDx5b3VyX25hbWU+YC4KCj4gKipBY3Rpb24qKgoKLSBEb2VzIGl0IHdvcms/IExvb2sgYXQgYGh0dHBzOi8vZ2l0aHViLmNvbS88eW91cl9naXRodWJfbmFtZT4vZ2l0LXNjaWVudGlmaWMtY29tbXVuaWNhdGlvbmAgaW4geW91ciBicm93c2VyIGFuZCBtYWtlIHN1cmUgeW91ciBjaGFuZ2VzIGFyZSB0aGVyZS4KCiMjICoqUHVsbCByZXF1ZXN0KioKCi0gTm93IGFsbCB5b3UgaGF2ZSB0byBkbyBpcyA8dT5hc2sgdGhlIGF1dGhvcnMgb2YgdGhlIG9yaWdpbmFsIHByb2plY3QgdG8gYWRkIHRoZSBjaGFuZ2VzIGZyb20geW91ciBzaGFyZWQgcmVwb3NpdG9yeSB0byB0aGVpciBjb3B5PC91Pi4gR2l0SHViIGhhcyBhIG1lY2hhbmlzbSBmb3IgZG9pbmcgdGhpcyBjYWxsZWQgYSBbKipwdWxsIHJlcXVlc3QqKl0oaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vcHVsbC1yZXF1ZXN0cy9jb2xsYWJvcmF0aW5nLXdpdGgtcHVsbC1yZXF1ZXN0cy9wcm9wb3NpbmctY2hhbmdlcy10by15b3VyLXdvcmstd2l0aC1wdWxsLXJlcXVlc3RzL2Fib3V0LXB1bGwtcmVxdWVzdHMpLgoKPiAqKkFjdGlvbioqCgotIEdvIHRvIHRoZSBvcmlnaW5hbCBwcm9qZWN0J3MgcGFnZSAodGhlIGFkZHJlc3MgeW91IHVzZWQgZm9yIGBnaXQgY2xvbmVgIGluIHRoZSBiZWdpbm5pbmcpLiBUaGVyZSB5b3Ugc2hvdWxkIHNlZSBhIG5vdGlmaWNhdGlvbiBvZiB5b3VyIG5ld2x5IHVwbG9hZGVkIGJyYW5jaCB3aXRoIGEgYmlnIGdyZWVuICoqQ29tcGFyZSAmIHB1bGwgcmVxdWVzdCBidXR0b24qKi4gKipDbGljayoqIG9uIGl0LiBJZiB5b3Ugd2FudCwgKiphZGQvY2hhbmdlIHRoZSBkZXNjcmlwdGlvbioqIG9mIHdoYXQgdGhpcyBjaGFuZ2UgZW50YWlscy4gVGhlbiBoaXQgdGhlIG5leHQgYnV0dG9uLgoKLSBJZiB5b3UgZG9uJ3Qgc2VlIHRoZSBDb21wYXJlICYgcHVsbCByZXF1ZXN0IGJ1dHRvbiwgZ28gdG8gdGhlICoqYWRkcmVzcyBvZiB5b3VyIGNvcHkgb2YgdGhlIHJlcG9zaXRvcnkqKiBhbmQgaGl0IHRoZSAqKk5ldyBwdWxsIHJlcXVlc3QqKiBidXR0b24uICoqU2VsZWN0Kiogd2hhdCB5b3Ugd2FudCB0byBpbmNsdWRlLCAqKmFkZC9jaGFuZ2UqKiB0aGUgbGFiZWwsIHRoZW4gcHJlc3MgKipDcmVhdGUgcHVsbCByZXF1ZXN0KiouCi0gKipZb3UncmUgZG9uZSoqISBOb3cgaXQncyB1cCB0byB0aGUgKipwcm9qZWN0IGF1dGhvcnMqKiB0byBsb29rIGF0IHRoZSBjaGFuZ2VzIGFuZCAqKmFjY2VwdCoqIHRoZW0gLSBvciBzdGFydCBhICoqZGlzY3Vzc2lvbioqIGFib3V0IGhvdyB0byBtYWtlIHRoZW0gZXZlbiBiZXR0ZXIuIChZb3UgY2FuIGRpc2N1c3Mgb24gdGhlIHB1bGwgcmVxdWVzdCBwYWdlIG9yIHZpYSBlbWFpbC4pCi0gVGhpcyBwcm9iYWJseSB3b24ndCBoYXBwZW4gZm9yIGFkZGluZyBhIG5hbWUgdG8gdGhlIGF0dGVuZGFuY2UgbGlzdCwgYnV0IGlmIHlvdSBuZWVkZWQgdG8gd29yayBvbiB0aGUgY2hhbmdlIGEgYml0IG1vcmUgYmVmb3JlIGluY29ycG9yYXRpbmcgaXQgKGV2ZW4gYWZ0ZXIgYSBmZXcgZGF5cyBvZiBkaXNjdXNzaW9uKSwgaXQgd291bGRuJ3QgYmUgYSBwcm9ibGVtLiAqKlN3aXRjaCB0byB0aGUqKiBgPHlvdXJfYnJhbmNoPmAgKipicmFuY2ggb24geW91ciBtYWNoaW5lKiosIG1ha2UgKipmdXJ0aGVyIGNvbW1pdHMqKiwgYW5kIHVzZSAqKmdpdCBwdXNoIHRvIHVwZGF0ZSoqIHlvdXIgYDx5b3VyX2JyYW5jaD5gICoqcHVsbCByZXF1ZXN0KiouCgojIyAqKlVwZGF0ZSoqIChgZ2l0IHB1bGxgKQotIE9uY2UgeW91ciAqKmNoYW5nZXMqKiAtIGFuZCB0aG9zZSBvZiBvdGhlcnMgLSBoYXZlIGJlZW4gKiptZXJnZWQqKiwgeW91IGNhbiAqKnVwZGF0ZSB5b3VyIGxvY2FsIHJlcG9zaXRvcnkqKi4KICAtIFRoaXMgaXMgdGhlICoqb25lIG9uIHlvdXIgY29tcHV0ZXIqKi4KCj4gKipBY3Rpb24qKiAKCi0gRmlyc3QsICoqc3dpdGNoIGJhY2sqKiB0byB0aGUgYG1hc3RlcmAgYnJhbmNoLiBOb3cgeW91IHdvbid0IGJlIHdvcmtpbmcgb24gYDx5b3VyX2JyYW5jaD5gOyB0aGF0IGJyYW5jaCBpcyBhbHJlYWR5IGNvbW1pdHRlZC4KLSBUaGlzIGlzIGRvbmUgd2l0aCBgZ2l0IHB1bGwgb3JpZ2luIG1hc3RlcmAgKHB1bGwgY2hhbmdlcyBmcm9tIHRoZSAibWFzdGVyIiBicmFuY2ggZnJvbSB0aGUgYWRkcmVzcyB1bmRlciAib3JpZ2luIikuIFlvdSBjYW4gdXNlIGBnaXRrIC0tYWxsYCBvciBgZ2l0IGxvZ2AgdG8gc2VlIGhvdyB0aGUgcHJvamVjdCBoYXMgZXZvbHZlZCBpbiB0aGUgbWVhbnRpbWUuCgotIEl0J3MgYWx3YXlzIGEgZ29vZCBpZGVhIHRvIGRvIHRoaXMgYGdpdCBwdWxsYCAqKmJlZm9yZSB5b3Ugc3RhcnQgd29ya2luZyBvbiBhIG5ldyBjaGFuZ2UvYnJhbmNoKiouIFRoaXMgd2lsbCBlbnN1cmUgdGhhdCB0aGUgcHJvamVjdCB5b3UgYXJlIGNoYW5naW5nIGlzICoqImZyZXNoIioqLgogIC0gQ29uZ3JhdHVsYXRpb25zISBZb3UganVzdCB3ZW50IHRocm91Z2ggdGhlICJyb3VuZCIgdGhhdCBtb3N0IHByb2dyYW1tZXJzIGRvIGV2ZXJ5IGRheTogbWFraW5nIGEgY2hhbmdlLCBwdXNoaW5nIGl0IHRvIGNvbGxlYWd1ZXMgZm9yIHJldmlldyBhbmQgaW5jb3Jwb3JhdGlvbiwgYW5kIHB1bGxpbmcgY2hhbmdlcyBmcm9tIG90aGVycy4KICAKPGltZyBzcmM9InZpei9naXQtd29ya2Zsb3cucG5nIiB3aWR0aD0iNjAwIiBjbGFzcz0iY2VudGVyIj4KCiMjICoqQnVnIHJlcG9ydGluZyoqIChpc3N1ZXMpCgotIE9jY2FzaW9uYWxseSwgeW91ICoqZmluZCBhIGJ1ZyoqIGluIGEgR2l0SHViIHByb2plY3QsIGJ1dCB5b3UgKipkb24ndCBoYXZlIHRoZSB0aW1lIG9yIGtub3dsZWRnZSB0byBmaXggaXQqKi4gCiAgLSBJbiB0aGlzIGNhc2UsIHlvdSdsbCBvZnRlbiBmaW5kIGEgbGlzdCBvZiByZXBvcnRlZCBbKippc3N1ZXMqKl0oaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vaXNzdWVzL3RyYWNraW5nLXlvdXItd29yay13aXRoLWlzc3Vlcy9hYm91dC1pc3N1ZXMpIG9uIHRoZSBHaXRIdWIgcHJvamVjdCBwYWdlIHVuZGVyIHRoZSAqKklzc3VlcyB0YWIqKi4gCiAgLSBJZiB5b3UgZG9uJ3QgZmluZCAieW91ciIgYnVnIGFtb25nIHRoZW0sIHlvdSBjYW4gcmVwb3J0IGl0IC0ganVzdCBjbGljayBvbiAqKk5ldyBJc3N1ZSoqIGFuZCB5b3UgY2FuIDx1PnBvc3Qgd2hlbiB0aGUgYnVnIG9jY3Vycywgd2hhdCB0aGUgcHJvZ3JhbSBpcyBkb2luZyB3cm9uZywgYW5kIHdoYXQgaXQgc2hvdWxkIGJlIGRvaW5nIGluc3RlYWQ8L3U+LgotIFNvbWUgcHJvamVjdHMgZG9uJ3QgdXNlIElzc3VlcyBvbiBHaXRIdWIuIElmIHlvdSBjYW4ndCBmaW5kIHRoZSBJc3N1ZXMgdGFiLCBjaGVjayB0aGUgcHJvamVjdCBkb2N1bWVudGF0aW9uIHRvIHNlZSBpZiB0aGVyZSdzIGEgbGluayB0byB0aGUgYnVnIGxpc3QuCgojIyAqKlJFQURNRSoqOiBJbmZvcm1hdGlvbiBmb3Igb3RoZXJzCi0gPHU+SWYgeW91J3JlIGNyZWF0aW5nIGEgcHJvamVjdCBhbmQgd2FudCBvdGhlcnMgdG8gY29udHJpYnV0ZSB0byBpdCwgeW91IG5lZWQgdGhlbSB0byBrbm93IHdoYXQgeW91ciBwcm9qZWN0IGRvZXMsIHdoYXQgaXQncyBnb29kIGZvciwgaG93IGl0J3MgdXNlZDwvdT4sIGV0Yy4KCi0gVGhlIFsqKlJFQURNRSoqXShodHRwczovL2RvY3MuZ2l0aHViLmNvbS9lbi9yZXBvc2l0b3JpZXMvbWFuYWdpbmcteW91ci1yZXBvc2l0b3J5cy1zZXR0aW5ncy1hbmQtZmVhdHVyZXMvY3VzdG9taXppbmcteW91ci1yZXBvc2l0b3J5L2Fib3V0LXJlYWRtZXMpIGZpbGUgaXMgdXNlZCBmb3IgKipiYXNpYyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgcHJvamVjdC9yZXBvc2l0b3J5KiouIFRoaXMgZmlsZSBjYW4gaW5jbHVkZToKICAtICpwcm9qZWN0IG5hbWUqLAogIC0gKmEgYnJpZWYgZGVzY3JpcHRpb24gb2YgdGhlIHByb2plY3QgKG9uZSBvciB0d28gc2VudGVuY2VzKSosCiAgLSAqYSBzaG9ydCBpbnN0cnVjdGlvbiBvbiBob3cgdG8gaW5zdGFsbCB0aGUgcHJvamVjdCosCiAgLSAqc2hvcnQgaW5zdHJ1Y3Rpb25zIG9uIGhvdyB0byBydW4gdGhlIHByb2plY3QqLAogIC0gKnNob3J0IGluc3RydWN0aW9ucyBvbiBob3cgdG8gdXNlIHRoZSBwcm9qZWN0LCBvciBhIGxpbmsgdG8gbW9yZSBleHRlbnNpdmUgZG9jdW1lbnRhdGlvbiosCiAgLSAqaWYgdGhlIHByb2plY3QgaGFzIHRlc3RzLCBpbmZvcm1hdGlvbiBvbiBob3cgdG8gcnVuIHRoZW0qLAogIC0gKmluZm9ybWF0aW9uIG9uIGhvdyB0byBnZXQgaW52b2x2ZWQgaW4gdGhlIGRldmVsb3BtZW50IG9mIHRoZSBwcm9qZWN0KiwKICAtICppbmZvcm1hdGlvbiBhYm91dCB0aGUgYXV0aG9ycyBvZiB0aGUgcHJvamVjdCosCiAgLSAqbGljZW5zaW5nIGluZm9ybWF0aW9uIChtb3JlIG9uIGxpY2Vuc2luZyBsYXRlcikqLgoKLSBUaGUgUkVBRE1FIHNob3VsZCBiZSAqKnN0cnVjdHVyZWQqKiBhbmQgc2hvdWxkbid0IHRha2UgdGhlIHVzZXIgYW4gaG91ciB0byByZWFkLCAqKnVzdWFsbHkgc2hvcnQgcHVuY2h5IGluZm9ybWF0aW9uIHdpdGggYSBwb3NzaWJsZSBsaW5rIHNvbWV3aGVyZSBlbHNlIGlzIGVub3VnaCoqLiAKICAtIEZvciBleGFtcGxlLCB5b3UgZG9uJ3QgbmVlZCB0byBleHBsYWluIGluIGVhY2ggcHJvamVjdCBob3cgdG8gaW5zdGFsbCBQeXRob24uIEp1c3Qgc2F5IHRoYXQgUHl0aG9uIGlzIG5lZWRlZCAoYW5kIGluIHdoaWNoIHZlcnNpb24pIGFuZCByZWZlciB0aGUgdXNlciB0byB0aGUgYXBwcm9wcmlhdGUgaW5zdHJ1Y3Rpb25zLiAKICAgIC0gWW91IGFsc28gbmVlZCB0byB0YWtlIGludG8gYWNjb3VudCB0aGUgKippbnRlZGVkIGF1ZGllbmNlKHMpKiogb3IgKip3aG8gd2lsbCBiZSByZWFkaW5nKiogdGhlIFJFQURNRS4KLSBHaXRIdWIgKGFuZCBsb3RzIG9mIG90aGVyIHNpbWlsYXIgc2VydmljZXMpIGFsbG93cyB5b3UgdG8gKip1c2UgYSBtYXJrdXAgbGFuZ3VhZ2UqKiBzdWNoIGFzICoqTWFya2Rvd24qKiBmb3IgdGhlIFJFQURNRS4gSXQncyB0aGVuIHBvc3NpYmxlIHRvIHVzZSBoZWFkaW5ncywgaW1hZ2VzLCBldGMuCi0gQW5kIGxhc3QgYnV0IG5vdCBsZWFzdDogKipvcGVuLXNvdXJjZSBwcm9qZWN0cyB0ZW5kIHRvIGJlIGluIEVuZ2xpc2gqKiBzbyB0aGF0IGFueW9uZSBmcm9tIGFyb3VuZCB0aGUgd29ybGQgY2FuIHBhcnRpY2lwYXRlLiAqKlZhcmlhYmxlIG5hbWVzLCBjb21tZW50cywgZG9jdW1lbnRhdGlvbioqIC0gZXZlcnl0aGluZyBpcyAqKnByaW1hcmlseSBpbiBFbmdsaXNoKiouCgojIyAqKkxpY2Vuc2UqKgotIFRvIG1ha2UgKipzaGFyaW5nIHdvcmsgZm9yIGxlZ2FsIHB1cnBvc2VzKiosIGl0IGlzICoqbm90IGVub3VnaCB0byB1cGxvYWQgYSBwaWVjZSBvZiBjb2RlIHRvIHRoZSBJbnRlcm5ldCoqLiBZb3UgYWxzbyBoYXZlIHRvICoqb2ZmaWNpYWxseSBhbm5vdW5jZSoqIHRoYXQgb3RoZXJzIGNhbiBwbGF5IHdpdGggaXQuIAogIC0gVGhpcyBpcyBiZWNhdXNlICoqeW91IGhhdmUgYSBjb3B5cmlnaHQqKiBvbiB5b3VyIGNvZGUgdGhhdCBzYXlzICoqb3RoZXJzIGNhbm5vdCB1c2UgeW91ciBwcm9ncmFtKiosIGxldCBhbG9uZSBpbXByb3ZlIGl0LCAqKnVubGVzcyB5b3UgZ2l2ZSB0aGVtIHBlcm1pc3Npb24uKiogCiAgICAtIDx1PlRvIGZvcm1hbGx5IGdyYW50IHRoaXMgcGVybWlzc2lvbiwgdGhleSB1c2UgbGljZW5zZXMgd3JpdHRlbiBieSBsYXd5ZXJzPC91Pi4KLSBUaGUgaXNzdWUgb2YgbGljZW5zZXMgY2FuLCB1bmZvcnR1bmF0ZWx5LCBiZSBxdWl0ZSBjb21wbGV4LiBCdXQgaWYgeW91IHNpbXBsaWZ5IGl0IHRvIHRoZSBtaW5pbXVtLCB5b3UganVzdCB3YW50IHRvIGVuc3VyZSB0aGF0IGV2ZXJ5b25lIGNhbiB1c2UgeW91ciBjcmVhdGlvbiwgbGVhcm4gZnJvbSBpdCwgcGFzcyBpdCBvbiwgYW5kIGltcHJvdmUgaXQuIEluIHRoYXQgY2FzZSwgY2hvb3NlLCBmb3IgZXhhbXBsZSwgdGhlIFsqTUlUIGxpY2Vuc2UqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NSVRfTGljZW5zZSkuCi0gSW4gYWRkaXRpb24sIGlmIHlvdSB3YW50IHRvIHByZXZlbnQgc29tZW9uZSBmcm9tIHRha2luZyB5b3VyIGNvZGUgYW5kICJpbXByb3ZpbmciIGl0IGFuZCBwcm9maXRpbmcgZnJvbSBpdCB3aXRob3V0IHNoYXJpbmcgdGhlIGltcHJvdmVtZW50cyB3aXRoIG90aGVycywgdHJ5IHRoZSBbKkFHUEwqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BZmZlcm9fR2VuZXJhbF9QdWJsaWNfTGljZW5zZSkuCi0gQ29kZSBpcyBtb3N0IG9mdGVuIGxpY2Vuc2VkIGJ5IHB1dHRpbmcgdGhlIGxpY2Vuc2UgdGV4dCBpbnRvIGEgZmlsZSBjYWxsZWQgYExJQ0VOU0VgIGFuZCBhZGRpbmcgaXQgdG8gR2l0LiBJdCBpcyBhIGdvb2QgaWRlYSB0byBtZW50aW9uIHRoZSBsaWNlbnNlIGluIHRoZSBgUkVBRE1FYCBmaWxlIGFzIHdlbGwuCi0gSWYgeW91IHdhbnQgdG8gcmVhZCBtb3JlIGFib3V0IGxpY2Vuc2VzLCBJIHJlZmVyIHlvdSB0byBjaG9vc2VhbGljZW5zZS5jb20sIG9yIGNyZWF0aXZlY29tbW9ucy5vcmcgYW5kIG9wZW5zb3VyY2Uub3JnLgoKIyMgKipOZXh0OiBIYW5kcy1vbiEqKgoKPiAqKkFjdGlvbioqCgotICoqQ29uc2lkZXIgYSBwcm9qZWN0Kiogd2hlcmUgeW91IHdhbnQgdHUgdXNlIEdpdCAoYW5kIEdpdEh1YjsgKn4xNSBtaW4qKQogIC0gV2hhdCBpcyB0aGUgKipuYXR1cmUgb2YgdGhlIGNvbGxhYm9yYXRpb24qKiBpbiB0aGlzIHByb2plY3Q/IAogIC0gV2hvIGFyZSB0aGUgKipjb2xsYWJvcmF0b3JzKio/CiAgCi0gKipDcmVhdGUqKiB0aGUgcmVzcGVjdGl2ZSAqKnJlcG9zaXRvcnkqKgogLSBTZWN1cmUgdGhlIG1haW4gYnJhbmNoIGZyb20gcHVzaGluZyBkaXJlY3RseSB0byBpdAogLSBTZXQgKip0b2tlbnMqKiBhbmQgb3RoZXIgKipzZWN1cml0eSoqIGVsZW1lbnRzCiAtICoqQ3JlYXRlKiogdGhlICoqUkVBRE1FKiogYW5kICoqbGljZW5jZSoqIGZpbGVzCiAtICoqUHVzaCoqIGFsbCBvZiB0aGUgcmVsYXRlZCAqKm1hdGVyaWFscyB0byB0aGUgcmVwb3NpdG9yeSoqIGFuZCAqKmNyZWF0ZSBhIHB1bGwgcmVxdWVzdCoqCiAtIExldCB0aGUgKipjb2xsYWJvcmF0b3IgcmV2aWV3KiogdGhlIHB1c2hlZCBjb2RlLgogLSAqKkFmdGVyKiogdGhlIGNoYW5nZXMgYXJlICoqbWVyZ2VkKiosIDx1PmNoZWNrb3V0IHRvIHRoZSBsb2NhbCBtYWluIGJyYW5jaCBhbmQgcHVsbCB0aGUgdXBkYXRlZCByZW1vdGUgbWFpbiBicmFuY2g8L3U+LgoKCiMjICoqUmVzb3VyY2VzKioKCi0gWW91IG1heSBmaW5kIG11bHRpcGxlIHJlc291cmNlcyBmb3IgbGVhcm5pbmcgZ2l0IGFuZC9vciBzZXJ2aWNlcyBsaWtlIEdpdEh1YiBhdmFpbGFibGUgZm9yIGZyZWUgKGFsdGhvdWdoIHNvbWV0aW1lcyB5b3UgbmVlZCB0byByZWdpc3RlcikuCgojIyMgKipDb3Vyc2VzKioKCi0gW0ludHJvZHVjdGlvbiB0byBWZXJzaW9uIENvbnRyb2wgd2l0aCBHaXRdKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS9sZWFybi9jb3Vyc2VzL2ludHJvZHVjdGlvbi10by12ZXJzaW9uLWNvbnRyb2wtd2l0aC1naXQpCi0gW0ludHJvZHVjdGlvbiB0byBHaXRdKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS9sZWFybi9jb3Vyc2VzL2ludHJvZHVjdGlvbi10by1naXQpCi0gW0dpdEh1YiBDb25jZXB0c10oaHR0cHM6Ly9hcHAuZGF0YWNhbXAuY29tL2xlYXJuL2NvdXJzZXMvZ2l0aHViLWNvbmNlcHRzKQotIFtHaXQ6IEJlY29tZSBhbiBFeHBlcnQgaW4gR2l0ICYgR2l0SHViIGluIDQgSG91cnNdKGh0dHBzOi8vd3d3LnVkZW15LmNvbS9jb3Vyc2UvZ2l0LWV4cGVydC00LWhvdXJzKQotIFtJbnRyb2R1Y3Rpb24gdG8gR2l0IGFuZCBHaXRIdWJdKGh0dHBzOi8vd3d3LmNvdXJzZXJhLm9yZy9sZWFybi9pbnRyb2R1Y3Rpb24tZ2l0LWdpdGh1YikKLSBbU3BvbHVwcsOhY2UgYSBPcGVuLVNvdXJjZV0oaHR0cHM6Ly9uYXVjc2UucHl0aG9uLmN6L2NvdXJzZS9weWxhZGllcy9zZXNzaW9ucy9mb3NzLykgKEN6ZWNoKQoKCiMjIyAqKkRvY3VtZW50YXRpb24qKgoKLSBbR2l0IC0gRG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9naXQtc2NtLmNvbS9kb2MpCi0gW0dpdEh1YiBEb2NzXShodHRwczovL2RvY3MuZ2l0aHViLmNvbS9lbikKCiMjIyAqKkNoZWF0LXNoZWV0cyoqCgotIFtnaXRdKGh0dHBzOi8vcHl2ZWMuZ2l0aHViLmlvL2NoZWF0c2hlZXRzL2Jhc2ljLWdpdC9iYXNpYy1naXQtY3MucGRmKSAoQ3plY2gpCi0gW01hcmtkb3duXShodHRwczovL3d3dy5tYXJrZG93bmd1aWRlLm9yZy9jaGVhdC1zaGVldC8pCgombmJzcDsKJm5ic3A7Cgo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGI+R28gYmFjayB0byA8YSBocmVmPSIvcG9zdCI+QmxvZzwvYj48L2E+LjwvcD4=