For code below, Open Git
(or Powershell, Terminal,
Command Prompt, etc.) in directory of repository and use the relevant
code.
Why It is Important to
Use Git
/Version Control
There are many reasons why it is important to use git/version
control:
It (GitHub
/GitLab
) provides backups of all
files in the cloud
It (GitHub
/GitLab
) allows you to access
the files in the cloud from any computer with access to the internet,
even if you are away from your local computer
Version control provides history of all (committed) changes made to
all files
If you make a mistake in your code, you can easily revert to a prior
version because you took snapshots (commits) of your files!
You don’t need to keep all the “commented out” lines of code
This allows you to write cleaner code, because you can remove
commented out lines of code, knowing that you can easily recover them in
your commit history
You don’t have to keep files or folders named “project_old” or
whatever
This allows you to keep cleaner file/folder directories for your
projects
Git
keeps all files for the project self-contained,
which helps increase reproducibility
It (GitHub
/GitLab
) allows easier
collaboration with others on the project
It (GitHub
/GitLab
) allows easier sharing
with outside researchers
How to Use
Best practices
working with version control
Create a new repository (repo) whenever you start a new project
Follow the Petersen Lab template for how to structure your repo
(folder structure, .gitignore
file, etc.):
To collaborate with others:
Navigate to the repo on the UI GitLab
website
When in the repo, click “Members”
Add the Collaborator
Each time you want to work on the files in the repo, follow this
cycle:
Using the GitHub Desktop
app, sync the repo files from
the cloud to the repo on your local computer (i.e., fetch any repo
updates to your local machine from the cloud)
Make sure to do this before many code changes so you are working
with the latest version of files
Do your work on the repo: make any code/file/folder additions,
changes, or deletions
Using the GitHub Desktop
app, commit the changes
Commit changes to the cloud early and often; when deciding what to
commit and when, try to group “similar changes” into the same commit
(“like goes with like”)
Use a separate “commit” for each separable “functional unit”
changed
Using the GitHub Desktop
app, sync the repo files from
your local computer to the repo on the cloud (i.e., push all of your
committed changes to the cloud)
Never leave file changes uncommitted or unsynced when you stop
working on the repo for the day!
Instructions for
using GitHub Desktop
app with GitLab
How to add a
pre-existing repo from the lab drive (RDSS
/network share)
to your computer
For example, the SRS-DataProcessing
repo lives on the
lab drive.
Make sure Dr. Petersen has given you collaborator access to the
repo
Open GitHub Desktop
app
Navigate to the folder location of the repo on the lab drive
Drag the .git
folder within the repo to the
GitHub Desktop
app
How to clone a repo
from GitLab
to local
Navigate to relevant repo on GitLab
(https://research-git.uiowa.edu )
Click Clone
in right-hand corner, select
Clone with HTTPS
Open GitHub Desktop
App and click File
,
Clone Repository
Click the URL
tab
Paste in the URL
Navigate to where you want to save it
The recommended location for your repos is to create a folder titled
GitHub
in your Documents
folder, and to put
repos in the GitHub
folder (by default: PC:
C:/Users/[USERNAME]/Documents/GitHub/
; Mac:
/Users/[user]/Documents/GitHub/
) because various lab
scripts try to read the lab functions from this location; it is
NOT recommended to put git
repos in a OneDrive
folder because git
files tend not to play nice with syncing services (e.g., OneDrive,
Dropbox)
Click Clone
Enter your GitLab
username as your username and your
Personal Access Token as your password
How to add, modify,
or delete files in a repo
Open relevant repo in GitHub Desktop
app
Pull any repo updates from the server to the local files (“Fetch
origin”, “Pull origin”)
Make necessary additions, modifications, and deletions to the
files
Create commits for all changes in GitHub Desktop
app
(one commit per substantive change): Enter “Summary” and “Commit to
master”
After making all changes and commits, push local file changes to the
server using GitHub Desktop
(“Fetch origin”, “Push
origin”)
How to collaborate
with others
Navigate to the repo on the UI GitLab
website
When in the repo, click “Settings”
Click “Members”
Add the Collaborator
How to clone a repo
into local directory with a different folder name (directory must be
empty)
Git
Bash into directory
git clone https://research-git.uiowa.edu/petersenlab/srs/SRS-DataProcessing.git .
git remote set-url --add origin https://research-git.uiowa.edu/petersenlab/srs/SRS-DataProcessing.git
git remote -v
How to transfer a
repo to a new location/group/subgroup
Create location/group/subgroup (e.g.,
PetersenLab/School Readiness Study
)
When in the repo, click “Settings”
Go to “Advanced”, and click “Expand”
Go to “Transfer project”, and select the location/group/subgroup you
want to transfer the repo to under “Select a new namespace”
In the local repo, edit the repo URL in the .git/config
file
When asked for your password, enter your username (HawkID) and
GitLab
Personal Access Token
How to use large
file storage (LFS)
Make sure the large files are not in the repo yet.
In GitHub Desktop
, open the repo you want to use LFS
for
In GitHub Desktop
, select the Repository
tab, then select Command Prompt
or similar
In the command prompt, type (based on instructions from: https://docs.gitlab.com/ee/topics/git/lfs/ ; archived at
https://perma.cc/6WMC-GTKN ):
git lfs install # initialize the Git LFS project
git lfs track "*.Rdata" # select the file extensions that you want to treat as large files
This should have created a .gitattributes
file in the
repo. In GitHub Desktop
, commit and push the
.gitattributes
file to the cloud version of the repo.
Copy the large files into the repo.
In GitHub Desktop
, commit and push the large file to
the cloud version of the repo.
(Or, if not using GitHub Desktop
, can commit in the
command prompt (https://docs.gitlab.com/ee/topics/git/lfs/ )):
git add . # add the large file to the project
git commit -am "insert name of commit message here" # commit the file meta data
git push origin master # sync the git repo and large file to the GitLab server
When asked for credentials, use your HawkID as your username and
your personal access token as your password
How to create a new
repository on a shared network drive
Create a repo on GitHub
or GitLab
online
Open Git
Bash on the desktop
Using Git
Bash, set the current directory to the path
where the new repo will be. For example, use the following command to
clone to the School Readiness Study
cd "R:\Lab\Studies\School Readiness Study"
Next, go to GitLab
or GitHub
online and
obtain the HTTPS URL to the new repository that was created. Clone the
repository with the HTTPS link using Git
Bash with the
following command
git clone (HTTPS Link)
How to revert
changes to a previous commit
Open the Github Desktop
and navigate to the repository
you would like to revert changes for
Next, click the history
tab
Right click the commit you would like to revert back to, and select
revert changes
Push the changes to the repo to complete the revision
revert changes
Troubleshooting
Error creating
commit
git add -A
git status
git commit -m "Message"` (where "Message" is the summary message of the commit)
git push
git status
Undo commit (but
retain file changes)
git reset --soft HEAD^
Error:
Sync failed
git status
git push
OLD
Creating Repo on
Local Directory (if Directory is empty)
Create Repo on GitHub
Don’t add README yet
Open Git
Shell, navigate to directory, and type:
git init
git remote add origin https://github.com/DevPsyLab/petersenlab.git
git remote -v
Drag and drop the folder with the repository into the GUI app
Add .gitignore file with .Rhistory
Creating Repo on
Local Directory (if Directory is not empty)
Create Repo on GitHub
Don’t add README yet
Open Git
Shell, navigate to directory, and type:
git init
git add .
git commit -m 'First commit'
git remote add origin https://research-git.uiowa.edu/itpetersen/PetersenLab.git
git remote -v
git push -u origin master
Drag and drop the folder with the repository into the GUI app
Add .gitignore file with .Rhistory
Creating
R
Scripts Repo on Lab Server
Create R
Scripts Repo
Open R
Scripts folder and delete .git
folder
Open Git
Shell and type:
git init
git add .
git commit -m 'First commit'
git remote add origin https://research-git.uiowa.edu/PetersenLab/R-Scripts.git
git remote -v
git push -u origin master
Move R
Scripts folder to another location
Clone repo into folder:
open Git
Shell
navigate to Z:\TDS II\Data\R Scripts\
git clone https://research-git.uiowa.edu/PetersenLab/R-Scripts.git .
The dot on the end of the git clone
command means “the
current directory”
Drag and drop the folder with the repository into the GUI app
Add .gitignore
file with .Rhistory
LS0tCnRpdGxlOiAiR2l0LCBHaXRMYWIsIGFuZCBHaXRIdWIiCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIGVycm9yID0gVFJVRSwKICBjb21tZW50ID0gIiIpCmBgYAoKRm9yIGNvZGUgYmVsb3csIE9wZW4gYEdpdGAgKG9yIFBvd2Vyc2hlbGwsIFRlcm1pbmFsLCBDb21tYW5kIFByb21wdCwgZXRjLikgaW4gZGlyZWN0b3J5IG9mIHJlcG9zaXRvcnkgYW5kIHVzZSB0aGUgcmVsZXZhbnQgY29kZS4KCiMgV2h5IEl0IGlzIEltcG9ydGFudCB0byBVc2UgYEdpdGAvVmVyc2lvbiBDb250cm9sCgpUaGVyZSBhcmUgbWFueSByZWFzb25zIHdoeSBpdCBpcyBpbXBvcnRhbnQgdG8gdXNlIGdpdC92ZXJzaW9uIGNvbnRyb2w6CgotIEl0IChgR2l0SHViYC9gR2l0TGFiYCkgcHJvdmlkZXMgYmFja3VwcyBvZiBhbGwgZmlsZXMgaW4gdGhlIGNsb3VkCi0gSXQgKGBHaXRIdWJgL2BHaXRMYWJgKSBhbGxvd3MgeW91IHRvIGFjY2VzcyB0aGUgZmlsZXMgaW4gdGhlIGNsb3VkIGZyb20gYW55IGNvbXB1dGVyIHdpdGggYWNjZXNzIHRvIHRoZSBpbnRlcm5ldCwgZXZlbiBpZiB5b3UgYXJlIGF3YXkgZnJvbSB5b3VyIGxvY2FsIGNvbXB1dGVyCi0gVmVyc2lvbiBjb250cm9sIHByb3ZpZGVzIGhpc3Rvcnkgb2YgYWxsIChjb21taXR0ZWQpIGNoYW5nZXMgbWFkZSB0byBhbGwgZmlsZXMKLSBJZiB5b3UgbWFrZSBhIG1pc3Rha2UgaW4geW91ciBjb2RlLCB5b3UgY2FuIGVhc2lseSByZXZlcnQgdG8gYSBwcmlvciB2ZXJzaW9uIGJlY2F1c2UgeW91IHRvb2sgc25hcHNob3RzIChjb21taXRzKSBvZiB5b3VyIGZpbGVzIQogICAgLSBZb3UgZG9uJ3QgbmVlZCB0byBrZWVwIGFsbCB0aGUgImNvbW1lbnRlZCBvdXQiIGxpbmVzIG9mIGNvZGUKICAgICAgICAtIFRoaXMgYWxsb3dzIHlvdSB0byB3cml0ZSBjbGVhbmVyIGNvZGUsIGJlY2F1c2UgeW91IGNhbiByZW1vdmUgY29tbWVudGVkIG91dCBsaW5lcyBvZiBjb2RlLCBrbm93aW5nIHRoYXQgeW91IGNhbiBlYXNpbHkgcmVjb3ZlciB0aGVtIGluIHlvdXIgY29tbWl0IGhpc3RvcnkKICAgIC0gWW91IGRvbid0IGhhdmUgdG8ga2VlcCBmaWxlcyBvciBmb2xkZXJzIG5hbWVkICJwcm9qZWN0X29sZCIgb3Igd2hhdGV2ZXIKICAgICAgICAtIFRoaXMgYWxsb3dzIHlvdSB0byBrZWVwIGNsZWFuZXIgZmlsZS9mb2xkZXIgZGlyZWN0b3JpZXMgZm9yIHlvdXIgcHJvamVjdHMKLSBgR2l0YCBrZWVwcyBhbGwgZmlsZXMgZm9yIHRoZSBwcm9qZWN0IHNlbGYtY29udGFpbmVkLCB3aGljaCBoZWxwcyBpbmNyZWFzZSByZXByb2R1Y2liaWxpdHkKLSBJdCAoYEdpdEh1YmAvYEdpdExhYmApIGFsbG93cyBlYXNpZXIgY29sbGFib3JhdGlvbiB3aXRoIG90aGVycyBvbiB0aGUgcHJvamVjdAotIEl0IChgR2l0SHViYC9gR2l0TGFiYCkgYWxsb3dzIGVhc2llciBzaGFyaW5nIHdpdGggb3V0c2lkZSByZXNlYXJjaGVycwoKIyBIb3cgdG8gVXNlCgojIyBUbyBiZWdpbiB7I3RvQmVnaW59CgoxLiBJbnN0YWxsIGBnaXRgIChodHRwczovL2dpdC1zY20uY29tL2Rvd25sb2FkcykKMS4gSW5zdGFsbCBgR2l0SHViIERlc2t0b3BgIGFwcCAoaHR0cHM6Ly9kZXNrdG9wLmdpdGh1Yi5jb20pCjEuIENyZWF0ZSBhIFBlcnNvbmFsIEFjY2VzcyBUb2tlbiAoaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvdXNlci9wcm9maWxlL3BlcnNvbmFsX2FjY2Vzc190b2tlbnMuaHRtbCwgYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy82Wkg4LUpOWkM7IG9yIGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS8tL3Byb2ZpbGUvcGVyc29uYWxfYWNjZXNzX3Rva2VucywgYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy83SlBVLVdEQlMpIG9uIHRoZSBVSSBgR2l0TGFiYCBpbnN0YW5jZSAoaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1KSB0byBhY2Nlc3MgVUkgYEdpdExhYmAgcmVwb3NpdG9yaWVzIGZyb20gYEdpdEh1YiBEZXNrdG9wYC4KICAgIC0gIEZvciBhcHBsaWNhdGlvbiBuYW1lLCBwdXQgIkdpdEh1YiIKICAgIC0gIEZvciBleHBpcmF0aW9uIGRhdGUsIGxlYXZlIGl0IGJsYW5rIChvciBzZXQgaXQgZm9yIGFzIGxhdGUgYW4gZXhwaXJhdGlvbiBkYXRlIGFzIHBvc3NpYmxlKQogICAgLSAgRm9yIHNjb3Blcywgc2VsZWN0IGV2ZXJ5dGhpbmcKMS4gV2hlbiBjbG9uaW5nIGEgcmVwb3NpdG9yeSBmcm9tIFVJJ3MgYEdpdExhYmAgaW5zdGFuY2UgdXNpbmcgYEdpdEh1YiBEZXNrdG9wYCwgYEdpdEh1YiBEZXNrdG9wYCB3aWxsIGFzayBmb3IgeW91ciB1c2VybmFtZSBhbmQgcGFzc3dvcmQuCkVudGVyIHlvdXIgSGF3a0lEIGFzIHlvdXIgdXNlcm5hbWUgYW5kIHlvdXIgVUkgYEdpdExhYmAgUGVyc29uYWwgQWNjZXNzIFRva2VuIGFzIHlvdXIgcGFzc3dvcmQuCgojIyBCZXN0IHByYWN0aWNlcyB3b3JraW5nIHdpdGggdmVyc2lvbiBjb250cm9sIHsjYmVzdFByYWN0aWNlc30KCi0gQ3JlYXRlIGEgbmV3IHJlcG9zaXRvcnkgKHJlcG8pIHdoZW5ldmVyIHlvdSBzdGFydCBhIG5ldyBwcm9qZWN0Ci0gRm9sbG93IHRoZSBQZXRlcnNlbiBMYWIgdGVtcGxhdGUgZm9yIGhvdyB0byBzdHJ1Y3R1cmUgeW91ciByZXBvIChmb2xkZXIgc3RydWN0dXJlLCBgLmdpdGlnbm9yZWAgZmlsZSwgZXRjLik6CiAgICAtIGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9QZXRlcnNlbkxhYi9UZW1wbGF0ZQotIFRvIGNvbGxhYm9yYXRlIHdpdGggb3RoZXJzOgogICAgLSBOYXZpZ2F0ZSB0byB0aGUgcmVwbyBvbiB0aGUgVUkgYEdpdExhYmAgd2Vic2l0ZQogICAgLSBXaGVuIGluIHRoZSByZXBvLCBjbGljayAiTWVtYmVycyIKICAgIC0gQWRkIHRoZSBDb2xsYWJvcmF0b3IKLSBFYWNoIHRpbWUgeW91IHdhbnQgdG8gd29yayBvbiB0aGUgZmlsZXMgaW4gdGhlIHJlcG8sIGZvbGxvdyB0aGlzIGN5Y2xlOgogICAgMS4gVXNpbmcgdGhlIGBHaXRIdWIgRGVza3RvcGAgYXBwLCBzeW5jIHRoZSByZXBvIGZpbGVzIGZyb20gdGhlIGNsb3VkIHRvIHRoZSByZXBvIG9uIHlvdXIgbG9jYWwgY29tcHV0ZXIgKGkuZS4sIGZldGNoIGFueSByZXBvIHVwZGF0ZXMgdG8geW91ciBsb2NhbCBtYWNoaW5lIGZyb20gdGhlIGNsb3VkKQogICAgICAgIC0gTWFrZSBzdXJlIHRvIGRvIHRoaXMgYmVmb3JlIG1hbnkgY29kZSBjaGFuZ2VzIHNvIHlvdSBhcmUgd29ya2luZyB3aXRoIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBmaWxlcwogICAgMS4gRG8geW91ciB3b3JrIG9uIHRoZSByZXBvOiBtYWtlIGFueSBjb2RlL2ZpbGUvZm9sZGVyIGFkZGl0aW9ucywgY2hhbmdlcywgb3IgZGVsZXRpb25zCiAgICAxLiBVc2luZyB0aGUgYEdpdEh1YiBEZXNrdG9wYCBhcHAsIGNvbW1pdCB0aGUgY2hhbmdlcwogICAgICAgIC0gQ29tbWl0IGNoYW5nZXMgdG8gdGhlIGNsb3VkIGVhcmx5IGFuZCBvZnRlbjsgd2hlbiBkZWNpZGluZyB3aGF0IHRvIGNvbW1pdCBhbmQgd2hlbiwgdHJ5IHRvIGdyb3VwICJzaW1pbGFyIGNoYW5nZXMiIGludG8gdGhlIHNhbWUgY29tbWl0ICgibGlrZSBnb2VzIHdpdGggbGlrZSIpCiAgICAgICAgLSBVc2UgYSBzZXBhcmF0ZSAiY29tbWl0IiBmb3IgZWFjaCBzZXBhcmFibGUgImZ1bmN0aW9uYWwgdW5pdCIgY2hhbmdlZAogICAgMS4gVXNpbmcgdGhlIGBHaXRIdWIgRGVza3RvcGAgYXBwLCBzeW5jIHRoZSByZXBvIGZpbGVzIGZyb20geW91ciBsb2NhbCBjb21wdXRlciB0byB0aGUgcmVwbyBvbiB0aGUgY2xvdWQgKGkuZS4sIHB1c2ggYWxsIG9mIHlvdXIgY29tbWl0dGVkIGNoYW5nZXMgdG8gdGhlIGNsb3VkKQogICAgICAgIC0gTmV2ZXIgbGVhdmUgZmlsZSBjaGFuZ2VzIHVuY29tbWl0dGVkIG9yIHVuc3luY2VkIHdoZW4geW91IHN0b3Agd29ya2luZyBvbiB0aGUgcmVwbyBmb3IgdGhlIGRheSEKCiMjIEluc3RydWN0aW9ucyBmb3IgdXNpbmcgYEdpdEh1YiBEZXNrdG9wYCBhcHAgd2l0aCBgR2l0TGFiYAoKLSBodHRwczovL2l0bmV4dC5pby9ob3ctdG8tdXNlLWdpdGh1Yi1kZXNrdG9wLXdpdGgtZ2l0bGFiLWNkNGQyZGUzZDEwNCAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9TNTlSLTNZVDcpCi0gaHR0cHM6Ly9jb21tdW5pdHkucmVjbGFpbWhvc3RpbmcuY29tL3QvdXNpbmctZ2l0aHViLWRlc2t0b3Atd2l0aC1naXRsYWIvODc2IChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1pQVDktS0VRTCkKLSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8yMjYzOTgxNS9kb2VzLWdpdGh1Yi1mb3Itd2luZG93cy13b3JrLXdpdGgtZ2l0bGFiIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzk5UlItNktMRSkKLSBodHRwczovL2dpdGh1Yi5jb20vZGVza3RvcC9kZXNrdG9wL2lzc3Vlcy84NTIjaXNzdWVjb21tZW50LTQwMjU0Njg0OCAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy8zR0NVLUdUUFUpCi0gaHR0cHM6Ly9naXRodWIuY29tL2Rlc2t0b3AvZGVza3RvcC9pc3N1ZXMvMzgxNiNpc3N1ZWNvbW1lbnQtNDIxMDYwOTc0IChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL044UlMtQkZXUikKCiMjIEhvdyB0byBjcmVhdGUgYSByZXBvIG9uIGxvY2FsIGNvbXB1dGVyCgoxLiBDcmVhdGUgcmVwb3NpdG9yeSBvbiBVSSBgR2l0TGFiYCB3ZWJzaXRlIChodHRwczovL3Jlc2VhcmNoLWdpdC51aW93YS5lZHUpCjEuIE9wZW4gYEdpdEh1YiBEZXNrdG9wYCBhcHAKMS4gQ2xvbmUgcmVwb3NpdG9yeQoxLiBBZGQgYC5naXRpZ25vcmVgIGZpbGUgKGZyb20gVGVtcGxhdGUgcHJvamVjdDogaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L3BldGVyc2VubGFiL1RlbXBsYXRlL2Jsb2IvbWFzdGVyLy5naXRpZ25vcmUpIHRvIHRoZSByb290IG9mIHRoZSBjbG9uZWQgcHJvamVjdCBmb2xkZXIKMS4gRm9sbG93IHRoZSBQZXRlcnNlbiBMYWIgdGVtcGxhdGUgZm9yIGhvdyB0byBzdHJ1Y3R1cmUgeW91ciByZXBvIChmb2xkZXIgc3RydWN0dXJlLCBgLmdpdGlnbm9yZWAgZmlsZSwgZXRjLik6IGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9QZXRlcnNlbkxhYi9UZW1wbGF0ZQogICAgLSAgTm90ZSB0aGF0IGEgZm9sZGVyIHdpbGwgbm90IGJlIHN5bmNlZCBpZiB0aGVyZSBhcmUgbm8gZmlsZXMgaW4gdGhlbSAoaS5lLiwgaWYgdGhlIGZvbGRlciBpcyBlbXB0eSkKMS4gU3luYyBmaWxlIGNoYW5nZXMgdXNpbmcgYEdpdEh1YiBEZXNrdG9wYCAoIkZldGNoIG9yaWdpbiIsICJQdXNoIG9yaWdpbiIpCgojIyBIb3cgdG8gYWRkIGEgcHJlLWV4aXN0aW5nIHJlcG8gZnJvbSB0aGUgbGFiIGRyaXZlIChgUkRTU2AvbmV0d29yayBzaGFyZSkgdG8geW91ciBjb21wdXRlcgoKRm9yIGV4YW1wbGUsIHRoZSBgU1JTLURhdGFQcm9jZXNzaW5nYCByZXBvIGxpdmVzIG9uIHRoZSBsYWIgZHJpdmUuCgoxLiBNYWtlIHN1cmUgRHIuIFBldGVyc2VuIGhhcyBnaXZlbiB5b3UgY29sbGFib3JhdG9yIGFjY2VzcyB0byB0aGUgcmVwbwoxLiBPcGVuIGBHaXRIdWIgRGVza3RvcGAgYXBwCjEuIE5hdmlnYXRlIHRvIHRoZSBmb2xkZXIgbG9jYXRpb24gb2YgdGhlIHJlcG8gb24gdGhlIGxhYiBkcml2ZQoxLiBEcmFnIHRoZSBgLmdpdGAgZm9sZGVyIHdpdGhpbiB0aGUgcmVwbyB0byB0aGUgYEdpdEh1YiBEZXNrdG9wYCBhcHAKCiMjIEhvdyB0byBjbG9uZSBhIHJlcG8gZnJvbSBgR2l0TGFiYCB0byBsb2NhbAoKMS4gTmF2aWdhdGUgdG8gcmVsZXZhbnQgcmVwbyBvbiBgR2l0TGFiYCAoaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1KQoxLiBDbGljayBgQ2xvbmVgIGluIHJpZ2h0LWhhbmQgY29ybmVyLCBzZWxlY3QgYENsb25lIHdpdGggSFRUUFNgCjEuIE9wZW4gYEdpdEh1YiBEZXNrdG9wYCBBcHAgYW5kIGNsaWNrIGBGaWxlYCwgYENsb25lIFJlcG9zaXRvcnlgCjEuIENsaWNrIHRoZSBgVVJMYCB0YWIKMS4gUGFzdGUgaW4gdGhlIFVSTAoxLiBOYXZpZ2F0ZSB0byB3aGVyZSB5b3Ugd2FudCB0byBzYXZlIGl0CiAgICAtICBUaGUgcmVjb21tZW5kZWQgbG9jYXRpb24gZm9yIHlvdXIgcmVwb3MgaXMgdG8gY3JlYXRlIGEgZm9sZGVyIHRpdGxlZCBgR2l0SHViYCBpbiB5b3VyIGBEb2N1bWVudHNgIGZvbGRlciwgYW5kIHRvIHB1dCByZXBvcyBpbiB0aGUgYEdpdEh1YmAgZm9sZGVyIChieSBkZWZhdWx0OiBQQzogYEM6L1VzZXJzL1tVU0VSTkFNRV0vRG9jdW1lbnRzL0dpdEh1Yi9gOyBNYWM6IGAvVXNlcnMvW3VzZXJdL0RvY3VtZW50cy9HaXRIdWIvYCkgYmVjYXVzZSB2YXJpb3VzIGxhYiBzY3JpcHRzIHRyeSB0byByZWFkIHRoZSBsYWIgZnVuY3Rpb25zIGZyb20gdGhpcyBsb2NhdGlvbjsgaXQgaXMgKk5PVCogcmVjb21tZW5kZWQgdG8gcHV0IGBnaXRgIHJlcG9zIGluIGEgT25lRHJpdmUgZm9sZGVyIGJlY2F1c2UgW2BnaXRgIGZpbGVzIHRlbmQgbm90IHRvIHBsYXkgbmljZSB3aXRoIHN5bmNpbmcgc2VydmljZXNdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE5MzA1MDMzL3doeS1pcy1wdXR0aW5nLWdpdC1yZXBvc2l0b3JpZXMtaW5zaWRlLW9mLWEtZHJvcGJveC1mb2xkZXItbm90LXJlY29tbWVuZGVkOyBhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1VUWDgtS1ZMOSkgKGUuZy4sIE9uZURyaXZlLCBEcm9wYm94KQoxLiBDbGljayBgQ2xvbmVgCjEuIEVudGVyIHlvdXIgYEdpdExhYmAgdXNlcm5hbWUgYXMgeW91ciB1c2VybmFtZSBhbmQgeW91ciBQZXJzb25hbCBBY2Nlc3MgVG9rZW4gYXMgeW91ciBwYXNzd29yZAoKIyMgSG93IHRvIGFkZCwgbW9kaWZ5LCBvciBkZWxldGUgZmlsZXMgaW4gYSByZXBvCgoxLiBPcGVuIHJlbGV2YW50IHJlcG8gaW4gYEdpdEh1YiBEZXNrdG9wYCBhcHAKMS4gUHVsbCBhbnkgcmVwbyB1cGRhdGVzIGZyb20gdGhlIHNlcnZlciB0byB0aGUgbG9jYWwgZmlsZXMgKCJGZXRjaCBvcmlnaW4iLCAiUHVsbCBvcmlnaW4iKQoxLiBNYWtlIG5lY2Vzc2FyeSBhZGRpdGlvbnMsIG1vZGlmaWNhdGlvbnMsIGFuZCBkZWxldGlvbnMgdG8gdGhlIGZpbGVzCjEuIENyZWF0ZSBjb21taXRzIGZvciBhbGwgY2hhbmdlcyBpbiBgR2l0SHViIERlc2t0b3BgIGFwcCAob25lIGNvbW1pdCBwZXIgc3Vic3RhbnRpdmUgY2hhbmdlKTogRW50ZXIgIlN1bW1hcnkiIGFuZCAiQ29tbWl0IHRvIG1hc3RlciIKMS4gQWZ0ZXIgbWFraW5nIGFsbCBjaGFuZ2VzIGFuZCBjb21taXRzLCBwdXNoIGxvY2FsIGZpbGUgY2hhbmdlcyB0byB0aGUgc2VydmVyIHVzaW5nIGBHaXRIdWIgRGVza3RvcGAgKCJGZXRjaCBvcmlnaW4iLCAiUHVzaCBvcmlnaW4iKQoKIyMgSG93IHRvIGNvbGxhYm9yYXRlIHdpdGggb3RoZXJzCgoxLiBOYXZpZ2F0ZSB0byB0aGUgcmVwbyBvbiB0aGUgVUkgYEdpdExhYmAgd2Vic2l0ZQoxLiBXaGVuIGluIHRoZSByZXBvLCBjbGljayAiU2V0dGluZ3MiCjEuIENsaWNrICJNZW1iZXJzIgoxLiBBZGQgdGhlIENvbGxhYm9yYXRvcgoKIyMgSG93IHRvIGNyZWF0ZSBhIHB1bGwgcmVxdWVzdCB7I3B1bGwtcmVxdWVzdH0KCjEuIFRvIGNyZWF0ZSBhIHB1bGwgcmVxdWVzdCwgeW91IGVpdGhlciBuZWVkIHRvIGhhdmUgd3JpdGUgcGVybWlzc2lvbnMgZm9yIHRoZSByZXBvLCBvciB5b3UgbmVlZCB0byBjcmVhdGUgYSBmb3JrIG9mIHRoZSByZXBvLgpUbyBmb3JrIHRoZSByZXBvLCBzZWUgaGVyZTogaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vcHVsbC1yZXF1ZXN0cy9jb2xsYWJvcmF0aW5nLXdpdGgtcHVsbC1yZXF1ZXN0cy93b3JraW5nLXdpdGgtZm9ya3MvZm9yay1hLXJlcG8jZm9ya2luZy1hLXJlcG9zaXRvcnkgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvMzNQNi1ZNEJSKQoxLiBBZnRlciBmb3JraW5nIHRoZSByZXBvIChpZiBuZWNlc3NhcnkpLCBzeW5jIHRoZSByZXBvIHdpdGggdGhlIGxhdGVzdCB2ZXJzaW9uIGZyb20gdGhlIGNsb3VkIHNvIHlvdSBrbm93IHlvdSBhcmUgZWRpdGluZyB0aGUgbGF0ZXN0IHZlcnNpb24gb2YgdGhlIGZpbGVzLgoxLiBNYWtlIGFueSBjaGFuZ2VzIHRvIHRoZSBmaWxlcyBpbiB0aGUgcmVwbyB0aGF0IHlvdSdkIGxpa2UgdG8gaW5jb3Jwb3JhdGUgaW50byB0aGUgcmVwbwoxLiBPcGVuIGEgcHVsbCByZXF1ZXN0IHdpdGggeW91ciBjaGFuZ2VzOiBodHRwczovL2RvY3MuZ2l0aHViLmNvbS9lbi9wdWxsLXJlcXVlc3RzL2NvbGxhYm9yYXRpbmctd2l0aC1wdWxsLXJlcXVlc3RzL3Byb3Bvc2luZy1jaGFuZ2VzLXRvLXlvdXItd29yay13aXRoLXB1bGwtcmVxdWVzdHMvY3JlYXRpbmctYS1wdWxsLXJlcXVlc3QtZnJvbS1hLWZvcmsgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvS0FQMy1MNUw3KQoKIyMgSG93IHRvIGNsb25lIGEgcmVwbyBpbnRvIGxvY2FsIGRpcmVjdG9yeSB3aXRoIGEgZGlmZmVyZW50IGZvbGRlciBuYW1lIChkaXJlY3RvcnkgbXVzdCBiZSBlbXB0eSkKCjEuIGBHaXRgIEJhc2ggaW50byBkaXJlY3RvcnkKYGBgCmdpdCBjbG9uZSBodHRwczovL3Jlc2VhcmNoLWdpdC51aW93YS5lZHUvcGV0ZXJzZW5sYWIvc3JzL1NSUy1EYXRhUHJvY2Vzc2luZy5naXQgLgpnaXQgcmVtb3RlIHNldC11cmwgLS1hZGQgb3JpZ2luIGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9wZXRlcnNlbmxhYi9zcnMvU1JTLURhdGFQcm9jZXNzaW5nLmdpdApnaXQgcmVtb3RlIC12CmBgYAoKIyMgSG93IHRvIHRyYW5zZmVyIGEgcmVwbyB0byBhIG5ldyBsb2NhdGlvbi9ncm91cC9zdWJncm91cAoKMS4gQ3JlYXRlIGxvY2F0aW9uL2dyb3VwL3N1Ymdyb3VwIChlLmcuLCBgUGV0ZXJzZW5MYWIvU2Nob29sIFJlYWRpbmVzcyBTdHVkeWApCjEuIFdoZW4gaW4gdGhlIHJlcG8sIGNsaWNrICJTZXR0aW5ncyIKMS4gR28gdG8gIkFkdmFuY2VkIiwgYW5kIGNsaWNrICJFeHBhbmQiCjEuIEdvIHRvICJUcmFuc2ZlciBwcm9qZWN0IiwgYW5kIHNlbGVjdCB0aGUgbG9jYXRpb24vZ3JvdXAvc3ViZ3JvdXAgeW91IHdhbnQgdG8gdHJhbnNmZXIgdGhlIHJlcG8gdG8gdW5kZXIgIlNlbGVjdCBhIG5ldyBuYW1lc3BhY2UiCjEuIEluIHRoZSBsb2NhbCByZXBvLCBlZGl0IHRoZSByZXBvIFVSTCBpbiB0aGUgYC5naXQvY29uZmlnYCBmaWxlCjEuIFdoZW4gYXNrZWQgZm9yIHlvdXIgcGFzc3dvcmQsIGVudGVyIHlvdXIgdXNlcm5hbWUgKEhhd2tJRCkgYW5kIGBHaXRMYWJgIFBlcnNvbmFsIEFjY2VzcyBUb2tlbgoKIyMgSG93IHRvIHVzZSBsYXJnZSBmaWxlIHN0b3JhZ2UgKExGUykgeyNnaXRMZnN9CgoxLiBNYWtlIHN1cmUgdGhlIGxhcmdlIGZpbGVzIGFyZSBub3QgaW4gdGhlIHJlcG8geWV0LgoxLiBJbiBgR2l0SHViIERlc2t0b3BgLCBvcGVuIHRoZSByZXBvIHlvdSB3YW50IHRvIHVzZSBMRlMgZm9yCjEuIEluIGBHaXRIdWIgRGVza3RvcGAsIHNlbGVjdCB0aGUgYFJlcG9zaXRvcnlgIHRhYiwgdGhlbiBzZWxlY3QgYENvbW1hbmQgUHJvbXB0YCBvciBzaW1pbGFyCjEuIEluIHRoZSBjb21tYW5kIHByb21wdCwgdHlwZSAoYmFzZWQgb24gaW5zdHJ1Y3Rpb25zIGZyb206IGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL3RvcGljcy9naXQvbGZzLzsgYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy82V01DLUdUS04pOgpgYGAKZ2l0IGxmcyBpbnN0YWxsICAgICAgICAgICMgaW5pdGlhbGl6ZSB0aGUgR2l0IExGUyBwcm9qZWN0CmdpdCBsZnMgdHJhY2sgIiouUmRhdGEiICAjIHNlbGVjdCB0aGUgZmlsZSBleHRlbnNpb25zIHRoYXQgeW91IHdhbnQgdG8gdHJlYXQgYXMgbGFyZ2UgZmlsZXMKYGBgCjUuIFRoaXMgc2hvdWxkIGhhdmUgY3JlYXRlZCBhIGAuZ2l0YXR0cmlidXRlc2AgZmlsZSBpbiB0aGUgcmVwby4gSW4gYEdpdEh1YiBEZXNrdG9wYCwgY29tbWl0IGFuZCBwdXNoIHRoZSBgLmdpdGF0dHJpYnV0ZXNgIGZpbGUgdG8gdGhlIGNsb3VkIHZlcnNpb24gb2YgdGhlIHJlcG8uCjYuIENvcHkgdGhlIGxhcmdlIGZpbGVzIGludG8gdGhlIHJlcG8uCjcuIEluIGBHaXRIdWIgRGVza3RvcGAsIGNvbW1pdCBhbmQgcHVzaCB0aGUgbGFyZ2UgZmlsZSB0byB0aGUgY2xvdWQgdmVyc2lvbiBvZiB0aGUgcmVwby4KOC4gKE9yLCBpZiBub3QgdXNpbmcgYEdpdEh1YiBEZXNrdG9wYCwgY2FuIGNvbW1pdCBpbiB0aGUgY29tbWFuZCBwcm9tcHQgKGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL3RvcGljcy9naXQvbGZzLykpOgpgYGAKZ2l0IGFkZCAuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFkZCB0aGUgbGFyZ2UgZmlsZSB0byB0aGUgcHJvamVjdApnaXQgY29tbWl0IC1hbSAiaW5zZXJ0IG5hbWUgb2YgY29tbWl0IG1lc3NhZ2UgaGVyZSIgICMgY29tbWl0IHRoZSBmaWxlIG1ldGEgZGF0YQpnaXQgcHVzaCBvcmlnaW4gbWFzdGVyICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc3luYyB0aGUgZ2l0IHJlcG8gYW5kIGxhcmdlIGZpbGUgdG8gdGhlIEdpdExhYiBzZXJ2ZXIKYGBgCjkuIFdoZW4gYXNrZWQgZm9yIGNyZWRlbnRpYWxzLCB1c2UgeW91ciBIYXdrSUQgYXMgeW91ciB1c2VybmFtZSBhbmQgeW91ciBwZXJzb25hbCBhY2Nlc3MgdG9rZW4gYXMgeW91ciBwYXNzd29yZAoKIyMgSG93IHRvIGNyZWF0ZSBhIG5ldyByZXBvc2l0b3J5IG9uIGEgc2hhcmVkIG5ldHdvcmsgZHJpdmUKCjEuIENyZWF0ZSBhIHJlcG8gb24gYEdpdEh1YmAgb3IgYEdpdExhYmAgb25saW5lCjEuIE9wZW4gYEdpdGAgQmFzaCBvbiB0aGUgZGVza3RvcAoxLiBVc2luZyBgR2l0YCBCYXNoLCBzZXQgdGhlIGN1cnJlbnQgZGlyZWN0b3J5IHRvIHRoZSBwYXRoIHdoZXJlIHRoZSBuZXcgcmVwbyB3aWxsIGJlLgpGb3IgZXhhbXBsZSwgdXNlIHRoZSBmb2xsb3dpbmcgY29tbWFuZCB0byBjbG9uZSB0byB0aGUgU2Nob29sIFJlYWRpbmVzcyBTdHVkeQoKYGBgCmNkICJSOlxMYWJcU3R1ZGllc1xTY2hvb2wgUmVhZGluZXNzIFN0dWR5IgpgYGAKCjEuIE5leHQsIGdvIHRvIGBHaXRMYWJgIG9yIGBHaXRIdWJgIG9ubGluZSBhbmQgb2J0YWluIHRoZSBIVFRQUyBVUkwgdG8gdGhlIG5ldyByZXBvc2l0b3J5IHRoYXQgd2FzIGNyZWF0ZWQuCkNsb25lIHRoZSByZXBvc2l0b3J5IHdpdGggdGhlIEhUVFBTIGxpbmsgdXNpbmcgYEdpdGAgQmFzaCB3aXRoIHRoZSBmb2xsb3dpbmcgY29tbWFuZAoKYGBgCmdpdCBjbG9uZSAoSFRUUFMgTGluaykKYGBgCgojIyBIb3cgdG8gcmV2ZXJ0IGNoYW5nZXMgdG8gYSBwcmV2aW91cyBjb21taXQgeyNyZXZlcnRDb21taXR9CgoxLiBPcGVuIHRoZSBgR2l0aHViIERlc2t0b3BgIGFuZCBuYXZpZ2F0ZSB0byB0aGUgcmVwb3NpdG9yeSB5b3Ugd291bGQgbGlrZSB0byByZXZlcnQgY2hhbmdlcyBmb3IKMS4gTmV4dCwgY2xpY2sgdGhlIGBoaXN0b3J5YCB0YWIKMS4gUmlnaHQgY2xpY2sgdGhlIGNvbW1pdCB5b3Ugd291bGQgbGlrZSB0byByZXZlcnQgYmFjayB0bywgYW5kIHNlbGVjdCByZXZlcnQgY2hhbmdlcwoxLiBQdXNoIHRoZSBjaGFuZ2VzIHRvIHRoZSByZXBvIHRvIGNvbXBsZXRlIHRoZSByZXZpc2lvbgoKIVtyZXZlcnQgY2hhbmdlc10oaW1hZ2VzL3JldmVydENoYW5nZXMucG5nKQoKIyMgSG93IHRvIHBlcmZvcm0gYSBwYXJ0aWFsIGNvbW1pdCB7I3BhcnRpYWxDb21taXR9CgoxLiBJbiBgR2l0SHViIERlc2t0b3BgLCBjbGljayB0aGUgZGVzaXJlZCBsaW5lcyBpbiB0aGUgZ3V0dGVyCjIuIENyZWF0ZSB0aGUgY29tbWl0LCBhbmQgbGVhdmUgdGhlIG90aGVyIGNoYW5nZXMgZm9yIHlvdSB0byBjb250aW51ZSB3b3JraW5nIG9uLgoKaHR0cHM6Ly9naXRodWIuYmxvZy8yMDE1LTAxLTE0LXBhcnRpYWwtY29tbWl0cy1pbi1naXRodWItZm9yLXdpbmRvd3MgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNVUzVi1ZV1JGKQoKIyMgSG93IHRvIGNvcHkgYSByZXBvIHRvIGEgbmV3IHJlcG8geyNjb3B5UmVwb30KCmh0dHBzOi8vZ2l0aHViLmNvbS9uZXcvaW1wb3J0CgojIyBIb3cgdG8gbWFrZSBhIHJlcG9zaXRvcnkgYSB0ZW1wbGF0ZSByZXBvc2l0b3J5IHsjdGVtcGxhdGVSZXBvfQoKaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vcmVwb3NpdG9yaWVzL2NyZWF0aW5nLWFuZC1tYW5hZ2luZy1yZXBvc2l0b3JpZXMvY3JlYXRpbmctYS10ZW1wbGF0ZS1yZXBvc2l0b3J5IChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1BZVzUtS0FQNSkKCiMjIEhvdyB0byBjcmVhdGUgYSByZXNwb3NpdG9yeSBmcm9tIGEgdGVtcGxhdGUgeyNyZXBvRnJvbVRlbXBsYXRlfQoKaHR0cHM6Ly9kb2NzLmdpdGh1Yi5jb20vZW4vcmVwb3NpdG9yaWVzL2NyZWF0aW5nLWFuZC1tYW5hZ2luZy1yZXBvc2l0b3JpZXMvY3JlYXRpbmctYS1yZXBvc2l0b3J5LWZyb20tYS10ZW1wbGF0ZSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85RTJDLU1VQ0spCgojIFRyb3VibGVzaG9vdGluZyB7I3Ryb3VibGVzaG9vdGluZ30KCiMjIEVycm9yOiBBdXRoZW50aWNhdGlvbiBGYWlsZWQgeyNhdXRoZW50aWNhdGlvbkZhaWxlZH0KCiFbYXV0aGVudGljYXRpb24gZmFpbGVkXShpbWFnZXMvZ2l0aHViRGVza3RvcEF1dGhlbnRpY2F0aW9uRXJyb3IucG5nKQoKVGhpcyBlcnJvciBjYW4gb2NjdXIgZm9yIGEgdmFyaWV0eSBvZiByZWFzb25zLgpPbmUgcG9zc2liaWxpdHkgaXMgdGhhdCB5b3VyIEdpdExhYiBQZXJzb25hbCBBY2Nlc3MgVG9rZW4gKFBBVCkgaGFzIGV4cGlyZWQuClRvIGZpeCB0aGlzOgoKMS4gQ3JlYXRlIGEgUGVyc29uYWwgQWNjZXNzIFRva2VuIChodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9lZS91c2VyL3Byb2ZpbGUvcGVyc29uYWxfYWNjZXNzX3Rva2Vucy5odG1sLCBhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzZaSDgtSk5aQzsgb3IgaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1Ly0vcHJvZmlsZS9wZXJzb25hbF9hY2Nlc3NfdG9rZW5zLCBhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzdKUFUtV0RCUykgb24gdGhlIFVJIGBHaXRMYWJgIGluc3RhbmNlIChodHRwczovL3Jlc2VhcmNoLWdpdC51aW93YS5lZHUpIHRvIGFjY2VzcyBVSSBgR2l0TGFiYCByZXBvc2l0b3JpZXMgZnJvbSBgR2l0SHViIERlc2t0b3BgLgogICAgLSAgRm9yIGFwcGxpY2F0aW9uIG5hbWUsIHB1dCAiR2l0SHViIgogICAgLSAgRm9yIGV4cGlyYXRpb24gZGF0ZSwgbGVhdmUgaXQgYmxhbmsgKG9yIHNldCBpdCBmb3IgYXMgbGF0ZSBhbiBleHBpcmF0aW9uIGRhdGUgYXMgcG9zc2libGUpCiAgICAtICBGb3Igc2NvcGVzLCBzZWxlY3QgZXZlcnl0aGluZwoxLiBXaGVuIGNsb25pbmcgYSByZXBvc2l0b3J5IGZyb20gVUkncyBgR2l0TGFiYCBpbnN0YW5jZSB1c2luZyBgR2l0SHViIERlc2t0b3BgLCBgR2l0SHViIERlc2t0b3BgIHdpbGwgYXNrIGZvciB5b3VyIHVzZXJuYW1lIGFuZCBwYXNzd29yZC4KRW50ZXIgeW91ciBIYXdrSUQgYXMgeW91ciB1c2VybmFtZSBhbmQgeW91ciBVSSBgR2l0TGFiYCBQZXJzb25hbCBBY2Nlc3MgVG9rZW4gYXMgeW91ciBwYXNzd29yZC4KCklmIHlvdSBkbyBub3QgcmVjZWl2ZSBhIHByb21wdCB0byBlbnRlciB5b3VyIHVzZXJuYW1lIGFuZCBwYXNzd29yZCwgdHJ5IHJlbW92aW5nIHRoZSBzYXZlZCBHaXRIdWJjcmVkZW50aWFscyBmcm9tIFdpbmRvd3MgQ3JlZGVudGlhbCBNYW5hZ2VyOgpodHRwczovL2dpdGh1Yi5jb20vZGVza3RvcC9kZXNrdG9wL2lzc3Vlcy84ODYwI2lzc3VlY29tbWVudC0yMjExODEyNjQ2CgojIyBgR2l0SHViYCBzaG93cyBhbGwgZmlsZXMgYXMgYmVpbmcgY2hhbmdlZCBldmVuIHRob3VnaCB0aGUgZmlsZXMgaGF2ZW4ndCBjaGFuZ2VkCgpXaW5kb3dzIGFuZCBNYWMgdXNlIGRpZmZlcmVudCBsaW5lIGVuZGluZ3MgKGh0dHBzOi8vZ2l0aHViLmNvbS9NaWNyb3NvZnQvV1NML2lzc3Vlcy8xODQ7IGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvRjhVWC1ZSlAzKToKCmBgYApnaXQgY29uZmlnIC0tZ2xvYmFsIGNvcmUuYXV0b2NybGYgdHJ1ZQpgYGAKICAKIyMgRXJyb3I6IGBZb3UgYXJlIG5vdCBhbGxvd2VkIHRvIHB1c2ggY29kZSB0byBwcm90ZWN0ZWQgYnJhbmNoZXMgb24gdGhpcyBwcm9qZWN0YAoKMS4gTWFrZSBzdXJlIHRoZSBvd25lciBvZiB0aGUgcmVwbyB1bnByb3RlY3RzIHRoZSBicmFuY2ggKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMyMjQ2NTAzL2ZpeC1naXRsYWItZXJyb3IteW91LWFyZS1ub3QtYWxsb3dlZC10by1wdXNoLWNvZGUtdG8tcHJvdGVjdGVkLWJyYW5jaGVzLW9uLXRoaTsgYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85OEFGLU42QlkpCjEuIE9wZW4gdGhlIHJlcG8sIGNsaWNrICJTZXR0aW5ncyIsICJSZXBvc2l0b3J5IiwgIlByb3RlY3RlZCBCcmFuY2hlcyIKMS4gQ2hhbmdlICJBbGxvd2VkIHRvIG1lcmdlIiBhbmQgIkFsbG93ZWQgdG8gcHVzaCIgdG8gIkRldmVsb3BlcnMgYW5kIE1haW50YWluZXJzIiwgYW5kIGNsaWNrICJVbnByb3RlY3QiCgojIyBFcnJvciBjcmVhdGluZyBjb21taXQKCmBgYApnaXQgYWRkIC1BCmdpdCBzdGF0dXMKZ2l0IGNvbW1pdCAtbSAiTWVzc2FnZSJgICh3aGVyZSAiTWVzc2FnZSIgaXMgdGhlIHN1bW1hcnkgbWVzc2FnZSBvZiB0aGUgY29tbWl0KQpnaXQgcHVzaApnaXQgc3RhdHVzCmBgYAoKIyMgVW5kbyBjb21taXQgKGJ1dCByZXRhaW4gZmlsZSBjaGFuZ2VzKQoKYGBgCmdpdCByZXNldCAtLXNvZnQgSEVBRF4KYGBgCgojIyBFcnJvcjogYFN5bmMgZmFpbGVkYAoKYGBgCmdpdCBzdGF0dXMKZ2l0IHB1c2gKYGBgCgojIyBFcnJvcjogYFN5bmMgZmFpbGVkIC0tIFN5bmNpbmcgd291bGQgb3ZlcndyaXRlIHlvdXIgdW5jb21taXR0ZWQgY2hhbmdlc2AKCmh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzIzMDg0ODIyL2dpdGh1Yi1zb21lLXVuY29tbWl0ZWQtY2hhbmdlcy13b3VsZC1iZS1vdmVyLXdyaXR0ZW4tYnktc3luY2luZyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9BUDVTLUczOEIpOgoKMS4gYGdpdCBzdGFzaCAtdWAKMS4gKHBlcmZvcm0gbWFudWFsIHN5bmMgaW4gYEdpdEh1YiBEZXNrdG9wYCkKMS4gYGdpdCBzdGFzaCBwb3BgCiAgCiMjIEVycm9yOiBgUGlwZWxpbmUgaGFzIGZhaWxlZCBmb3IgbWFzdGVyYAoKaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvdG9waWNzL2F1dG9kZXZvcHMvI2F0LXRoZS1wcm9qZWN0LWxldmVsIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzNNQVEtWkJGRikKCjEuIE9wZW4gdGhlIHJlcG8gaW4gYEdpdExhYmAKMS4gR28gdG8geW91ciBwcm9qZWN0J3MgIlNldHRpbmdzIiA+ICJDSS9DRCIgPiAiQXV0byBEZXZPcHMiCjEuIERpc2FibGUgKHVuY2hlY2spIHRoZSAiRGVmYXVsdCB0byBBdXRvIERldk9wcyBwaXBlbGluZSIKMS4gQ2xpY2sgIlNhdmUgY2hhbmdlcyIKCiMgT0xECgojIyBDcmVhdGluZyBSZXBvIG9uIExvY2FsIERpcmVjdG9yeSAoaWYgRGlyZWN0b3J5IGlzIGVtcHR5KQoKMS4gQ3JlYXRlIFJlcG8gb24gR2l0SHViCjEuIERvbid0IGFkZCBSRUFETUUgeWV0CjEuIE9wZW4gYEdpdGAgU2hlbGwsIG5hdmlnYXRlIHRvIGRpcmVjdG9yeSwgYW5kIHR5cGU6CmBgYApnaXQgaW5pdApnaXQgcmVtb3RlIGFkZCBvcmlnaW4gaHR0cHM6Ly9naXRodWIuY29tL0RldlBzeUxhYi9wZXRlcnNlbmxhYi5naXQKZ2l0IHJlbW90ZSAtdgpgYGAKNC4gRHJhZyBhbmQgZHJvcCB0aGUgZm9sZGVyIHdpdGggdGhlIHJlcG9zaXRvcnkgaW50byB0aGUgR1VJIGFwcAo1LiBBZGQgLmdpdGlnbm9yZSBmaWxlIHdpdGggLlJoaXN0b3J5CgojIyBDcmVhdGluZyBSZXBvIG9uIExvY2FsIERpcmVjdG9yeSAoaWYgRGlyZWN0b3J5IGlzICpub3QqIGVtcHR5KQoKMS4gQ3JlYXRlIFJlcG8gb24gR2l0SHViCjEuIERvbid0IGFkZCBSRUFETUUgeWV0CjEuIE9wZW4gYEdpdGAgU2hlbGwsIG5hdmlnYXRlIHRvIGRpcmVjdG9yeSwgYW5kIHR5cGU6CmBgYApnaXQgaW5pdApnaXQgYWRkIC4KZ2l0IGNvbW1pdCAtbSAnRmlyc3QgY29tbWl0JwpnaXQgcmVtb3RlIGFkZCBvcmlnaW4gaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L2l0cGV0ZXJzZW4vUGV0ZXJzZW5MYWIuZ2l0CmdpdCByZW1vdGUgLXYKZ2l0IHB1c2ggLXUgb3JpZ2luIG1hc3RlcgpgYGAKNC4gRHJhZyBhbmQgZHJvcCB0aGUgZm9sZGVyIHdpdGggdGhlIHJlcG9zaXRvcnkgaW50byB0aGUgR1VJIGFwcAo1LiBBZGQgLmdpdGlnbm9yZSBmaWxlIHdpdGggLlJoaXN0b3J5CgojIyBDcmVhdGluZyBgUmAgU2NyaXB0cyBSZXBvIG9uIExhYiBTZXJ2ZXIKCjEuIENyZWF0ZSBgUmAgU2NyaXB0cyBSZXBvCjEuIE9wZW4gYFJgIFNjcmlwdHMgZm9sZGVyIGFuZCBkZWxldGUgYC5naXRgIGZvbGRlcgoxLiBPcGVuIGBHaXRgIFNoZWxsIGFuZCB0eXBlOgpgYGAKZ2l0IGluaXQKZ2l0IGFkZCAuCmdpdCBjb21taXQgLW0gJ0ZpcnN0IGNvbW1pdCcKZ2l0IHJlbW90ZSBhZGQgb3JpZ2luIGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9QZXRlcnNlbkxhYi9SLVNjcmlwdHMuZ2l0CmdpdCByZW1vdGUgLXYKZ2l0IHB1c2ggLXUgb3JpZ2luIG1hc3RlcgpgYGAKNC4gTW92ZSBgUmAgU2NyaXB0cyBmb2xkZXIgdG8gYW5vdGhlciBsb2NhdGlvbgo1LiBDbG9uZSByZXBvIGludG8gZm9sZGVyOgogICAgLSBvcGVuIGBHaXRgIFNoZWxsCiAgICAtIG5hdmlnYXRlIHRvIGBaOlxURFMgSUlcRGF0YVxSIFNjcmlwdHNcYAogICAgYGBgCiAgICBnaXQgY2xvbmUgaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L1BldGVyc2VuTGFiL1ItU2NyaXB0cy5naXQgLgogICAgYGBgCiAgICBUaGUgZG90IG9uIHRoZSBlbmQgb2YgdGhlIGBnaXQgY2xvbmVgIGNvbW1hbmQgbWVhbnMgInRoZSBjdXJyZW50IGRpcmVjdG9yeSIKNi4gRHJhZyBhbmQgZHJvcCB0aGUgZm9sZGVyIHdpdGggdGhlIHJlcG9zaXRvcnkgaW50byB0aGUgR1VJIGFwcAo3LiBBZGQgYC5naXRpZ25vcmVgIGZpbGUgd2l0aCBgLlJoaXN0b3J5YAo=