Data Science Stream
Topic 1B: Using RStudio
Welcome to the first Data Science computer lab for STM1001!
Throughout the semester, we will use the R software environment in our computer labs and assessments.
R is free, flexible, and used by millions of people for statistical computing and data visualisation.
Learning R can be challenging at first. To make our learning experience more enjoyable, we will be using RStudio rather than base R for all our R coding. RStudio is an integrated development environment (IDE) for R, and offers several helpful features and user-interface options missing from base R.
In this first Data Science computer lab we will take things slowly, and focus on practicing and reinforcing key R coding skills you began developing in the first core Computer Lab, via some light-hearted examples. A solid R foundation will ensure that in subsequent computer labs, you will be able to pick up and apply new R coding skills more easily.
By the end of this lab, you should feel comfortable using simple R commands, creating and naming new objects, installing, loading and using R packages, and saving images generated in RStudio.
π§ Reminder: Online students
Throughout the computer lab question sheets, you will see emojis and/or collapsible sections like this one. Each emoji has a particular meaning and will sometimes be associated with additional instructions:
Prompts for you
π¬ Write your answer in the chat.
Modes at different times during the lab
π‘ Main room. All together in the main room β your computer lab demonstrator will be presenting information or facilitating class discussion
π‘ Breakout rooms. Person with birthday closest to (your computer lab demonstrator will pick a random date) shares their screen or whiteboard. Here you will discuss a question together and bring your groupβs answer back to the main room.
π» Focus mode. You will still be in the main room, but working independently. All students will be sharing screen during this time so that your computer lab demonstrator (but not other students) can see your screen.
π« Reminder: Face-to-face (blended) students
Throughout the computer lab question sheets, you will see emojis and/or collapsible sections like this one. You can ignore the emojis and collapsible sections, as they contain information relevant to students who are studying online.
Checklist
π‘ Before we continue, make sure that you have done the following:
- Installed R and RStudio on your personal device (this will be helpful for assignment work, even if you intend to complete the computer labs on university computers)
- Completed the first core Computer Lab
- Looked over the different books in the Introduction to R content on LMS
- Confirmed that you are in the correct stream
If you have any questions about any of these items, please ask your computer lab demonstrator for assistance.
Installing new R packages
π» R contains many in-built functions, and by itself is perfectly sufficient for a number of data analysis methods.
However, one of the great benefits of R is that anyone can create packages (bundles of code, data and functions) which can be uploaded to global repositories (such as CRAN), and made available for anyone around the world to download and use in their version of R.
These packages are often extremely helpful. They may contain useful data sets for a specific field of research, address a shortcoming with the base R suite of functions, allow users to perform specialised analyses, and/or offer users some additional functionalities missing from base R.
On the other hand, sometimes user-created packages are more light-hearted, or are pet projects not necessarily intended for serious data analysis. One such example is the meme
package (Yu 2021), which allows users to create simple memes using R code.
Letβs install and load the meme
package in RStudio now.
π» Because the meme
package is not installed in base R, we need to download it before we can use it.
Recall that we can use the install.packages()
R function to do this. Run the code below to do this now:
install.packages("meme")
# Note that the package name must be surrounded by quotation marks when using the install.packages function.
π» When you install an R package, you will see some text appear in the RStudio Console
window. Often, some of this text is red, which at first can be unnerving - you may think that an error has occurred. Donβt worry! While it is always a good idea to check these red text messages, they are not necessarily errors, and often can be safely ignored.
If you check the final part of the text output, which is in black not red, you should see something like package βmemeβ successfully unpacked and MD5 sums checked
. This is reassuring - the package has installed correctly, and the red text above is just telling us how R went about installing it.
Note: If you see a message about installing Rtools
, ignore it, we donβt need it for the purposes of this lab.
π» Once the meme
package is downloaded and installed, we need to load it in our current RStudio session.
Run the following code to load the meme
package.
library(meme)
Making memes in RStudio
π» With the meme
package installed and loaded in RStudio, we can now start to make some simple memes!
We really only need two lines of code for this, as we will demonstrate with the following example.
π» Firstly, we need to find an appropriate image. For this example, we will use an image of Hagrid, from the Harry Potter series. We have located this image online, and copied the url. In RStudio, we assign this url to the object hagrid
, as shown below:
hagrid <- "https://i.imgflip.com/13wb2t.jpg"
# Note that the url needs to be contained within quotation marks
Make sure to run this code before moving on to the next step.
Note: For a refresher on objects, check the R Coding Fundamentals book in the Introduction to R content on LMS.
π» Next, we use the meme
function (which is only available because we installed and loaded the meme
package) to add some words to this image. Try running the code below, and see what happens.
meme(hagrid, "Yer a wizard", "with coding", font = "sans")
Note: Some warnings may appear in the Console
section of RStudio as this code is executing. Donβt worry about them, it is safe to ignore these warnings.
π§ Online students
π¬ After running the code, a meme should have appeared in RStudio. Take a snippet/screenshot of the meme and copy-paste it into the chat.
How to save RStudio images
π» If you would like to save the meme you have made, we have several options, which we will demonstrate now, via another example.
In the code below, we make a new meme, and assign it to the object success
, using the assignment operator <-
. Try running this code now.
success_kid <- "http://i0.kym-cdn.com/entries/icons/mobile/000/000/745/success.jpg"
success <- meme(success_kid, "Using R", "to make memes", font = "sans")
success
Hint: Notice that we need to include the final line of code, calling the object success
, in order for the image to be shown.
Option A: Base R function
π» We can use the base R function savePlot
to save an image created in RStudio.
To do so, the image needs to have been produced in a separate graphics device.
- If you are using a Windows OS, you can run the code
windows()
to open a separate graphics device in RStudio.
- If you are using a Mac OS, the equivalent function is
quartz()
.
Note: Separate graphics devices for each image created in RStudio can be helpful if you want to see several images at once. Technically you can also save the image via the graphics deviceβs menu bar.
Take a look at the code below, and then run it, to save your success kid meme to your current working directory.
windows() # or quartz(), if you are a Mac user
success # render the image in the graphics device
savePlot(filename = "successkid", type = "png")
Option B: A function from a specific package
π» Sometimes packages will include a custom function for some operation, such as the saving of a file. These can often offer additional utility to the default alternative.
The meme
package has a specific function, meme_save
, for saving memes. Take a look at the code below.
meme_save(success, file="c:/STM1001/Data Science/success_kid_R_meme.png")
Here, the function allows us to specify the save location of our file. We are saving our success
meme to the example file location c:\STM1001\Data Science\
, with the name success_kid_R_meme.png
.
Note: Although the file path on our computer includes backslashes (\
), in R code these need to be changed to forward slashes (/
).
Option C: Via the RStudio Plots window
π» Instead of using R code, we can save our image manually, by navigating to the Plots
window in RStudio, clicking Export
, and selecting either Save as Image...
or Save as PDF...
, as shown below:
Try this now, and save your success
meme as a pdf.
π» Now itβs time to make your own meme in RStudio. Follow the steps below:
Find an appropriate image of your choice online (please ensure you pick content suitable for university and work).
Copy the url.
Assign this url to an object in RStudio.
Use the meme
function to add words to your image.
Save your meme using either the savePlot
function, meme_save
function or the manual approach.
βHint
Hint: If you are not quite sure how to begin, click the Show
button to the right below.
# First, we need to find an image, and assign it to an object
# (here we use the generic object name 'image_name')
# Just replace the ...s with the url of your image
image_name <- "..."
# Next, we need to use the meme function, to add some words (just replace the ...s)
my_meme <- meme(image_name, "...", "...", font = "sans")
# Note that you need to include the `, font = "sans"` part to ensure R know which font to use.
# Now all that's left is to save your meme - just refer to the code above.
π§ Online students
π¬ Once you have created your meme in RStudio, take a snippet/screenshot of it and copy-paste it into the chat.
Congratulations! You were probably not expecting to make a meme in your first data science computer lab. While this wonβt be on the final exam, the R skills you are developing here are important, and hopefully you are starting to realise that R is very versatile.
π‘ Reconvene in main room to discuss results
Customizing GIFs in RStudio
π» R is not limited to working with static images - we can modify and create GIFs and animations (and in future weeks we will make animated, interactive graphs using real data).
In this section, we will use another fun package, the magick
package (Ooms 2021), to customize a GIF.
π» Run the following code to download, install and load the magick
package in your current RStudio session.
install.packages("magick")
library(magick)
π» Just as we obtained online images of hagrid
and success kid
, so too can we use urls to GIFs and animations.
For this example, we have used the url to a GIF of a rotating Earth.
We can use the image_read
function to read this GIF into RStudio. Run the code below to assign it to the object Earth
.
Earth <- image_read("https://i.giphy.com/media/mf8UbIDew7e8g/giphy.gif")
Earth
Make sure to run this code before moving on to the next step (donβt worry if it takes a few seconds). The GIF should appear in the Viewer
section of RStudio.
π» Using the magick
package, we can easily make some changes to this Earth
GIF.
Run the following code, and inspect the output.
rev(Earth) %>%
image_flip() %>%
image_annotate(" Meanwhile, in Australia", size = 40, color = "white")
You will notice here that:
- We have reversed the GIF, using the
rev
function
- We have flipped the GIF, using the
image_flip
function, and
- We have added text to this GIF using the
image_annotate
function
π§ Online students
π¬ Once you have created your GIF, take a snippet/screenshot of it and copy-paste it into the chat.
This is really just scratching the surface of the magick
package. For the moment though, letβs move on.
Palmer Penguins Data Set
π» Now that we have had a taste of some of the more light-hearted R packages out there, letβs consider a package which contains some useful data.
The palmerpenguins
R package (Horst, Hill, and Gorman 2020) contains data, collected over the course of several years, on 3 species of penguin living on different islands in the Palmer archipelago, off the coast of Antarctica. Over the course of the next few data science computer labs, we will create various interactive data visualisations using the penguins
data from this package.
For more details on the penguins
data set, and a taste of whatβs ahead in future labs, you can refer to Section 2 of the Data Visualisation in R supplement.
For this lab, letβs use some R functions to inspect the penguins
data set.
π» Just like the previous packages, to begin we will need to download and load the palmerpenguins
package.
Using what you have practiced earlier in this computer lab, install and load the palmerpenguins
package in RStudio.
##
## Attaching package: 'palmerpenguins'
## The following objects are masked from 'package:datasets':
##
## penguins, penguins_raw
π» Recall from the first core Computer Lab that you can easily check the dimensions of your data using the dim
, nrow
and ncol
functions. Use these now to assess the penguins
data set.
Note: Check the Code
button below if you would like a refresher.
# This code checks the dimensions of the penguins data set
dim(penguins)
π§ Online students
π¬ Copy your result from the RStudio console and paste it into the chat.
π» Use the summary
function to obtain a quick overview of the penguins
data set.
Donβt worry too much about the values shown in the summary table - the main things to note at this stage are the different variables.
π» Often, when we begin working with a new data set, it is helpful to take a quick look at some of the recorded values. We can use the head
function to look at the recorded values for the first 6 observations in a data set.
Try using the head
function now, with the penguins
data set. What do you observe?
π§ Online students
π¬ Copy your result from the RStudio console and paste it into the chat.
π» When a data set has multiple columns of information, we can assess the information in specific column by writing the name of the object, adding a $
at the end, and then writing the name of the specific column we would like to inspect.
For example, we could use the following code to check the recorded bill length measurements of the penguins:
penguins$bill_length_mm
Run this code now.
βNote
When we have a large data set, output may appear over several lines in the Console
. The numbers that appear in brackets to the left of each line of output are not observations. Rather, these denote the position number for the first observation on that line of output. E.g. a [17]
would denote that the observation directly to the right of the [17]
is the 17th recorded observation in the data set, for the variable being considered.
π» Try using this $
approach to check the recorded bill depths and body masses of the penguins.
Note: Notice that once you type the $
, RStudio will helpfully prompt you with possible selections.
π‘ Reconvene in main room to discuss results
Thatβs the end of the first data science computer lab!
Hopefully you have enjoyed this first computer lab, and now have a better idea of just how versatile R can be (particularly when using the helpful RStudio GUI). Donβt worry if some of the code seems difficult at the moment - this is only the first lab after all!
In the next data science computer lab we will continue working with the palmerpenguins
data set, and cover how to create interactive plots using a new package.
Important Notes
If you have any questions about the content in this lab, or are stuck on some R code used in the lab, please ask your lab demonstrator for assistance.
Make sure to save your R script file somewhere safe - it may be a helpful reference source for later work.
Make sure that you finish off your readings of the Introduction to R content on LMS prior to the second data science computer lab.
References
Horst, Allison Marie, Alison Presmanes Hill, and Kristen B Gorman. 2020.
Palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data.
https://doi.org/10.5281/zenodo.3960218.
Ooms, Jeroen. 2021.
magick: advanced graphics and image-processing in R.
https://docs.ropensci.org/magick/.
Yu, Guangchuang. 2021.
meme: create memes in R.
https://github.com/GuangchuangYu/meme/.
These notes have been prepared by Rupert Kuveke. The copyright for the material in these notes resides with the author named above, with the Department of Mathematical and Physical Sciences and with La Trobe University. Copyright in this work is vested in La Trobe University including all La Trobe University branding and naming. Unless otherwise stated, material within this work is licensed under a Creative Commons Attribution-Non Commercial-Non Derivatives License
BY-NC-ND.
LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiAxQiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBTdHJlYW0gey19DQoNCiMjIyBUb3BpYyAxQjogVXNpbmcgUlN0dWRpbyB7LX0NCg0KPGJyPg0KDQpXZWxjb21lIHRvIHRoZSBmaXJzdCBEYXRhIFNjaWVuY2UgY29tcHV0ZXIgbGFiIGZvciBTVE0xMDAxIQ0KDQpUaHJvdWdob3V0IHRoZSBzZW1lc3Rlciwgd2Ugd2lsbCB1c2UgdGhlICoqUiBzb2Z0d2FyZSBlbnZpcm9ubWVudCoqIGluIG91ciBjb21wdXRlciBsYWJzIGFuZCBhc3Nlc3NtZW50cy4NClIgaXMgZnJlZSwgZmxleGlibGUsIGFuZCB1c2VkIGJ5IG1pbGxpb25zIG9mIHBlb3BsZSBmb3Igc3RhdGlzdGljYWwgY29tcHV0aW5nIGFuZCBkYXRhIHZpc3VhbGlzYXRpb24uDQoNCkxlYXJuaW5nIFIgY2FuIGJlIGNoYWxsZW5naW5nIGF0IGZpcnN0LiBUbyBtYWtlIG91ciBsZWFybmluZyBleHBlcmllbmNlIG1vcmUgZW5qb3lhYmxlLCB3ZSB3aWxsIGJlIHVzaW5nICoqUlN0dWRpbyoqIHJhdGhlciB0aGFuIGJhc2UgUiBmb3IgYWxsIG91ciBSIGNvZGluZy4gUlN0dWRpbyBpcyBhbiBpbnRlZ3JhdGVkIGRldmVsb3BtZW50IGVudmlyb25tZW50IChJREUpIGZvciBSLCBhbmQgb2ZmZXJzIHNldmVyYWwgaGVscGZ1bCBmZWF0dXJlcyBhbmQgdXNlci1pbnRlcmZhY2Ugb3B0aW9ucyBtaXNzaW5nIGZyb20gYmFzZSBSLg0KDQpJbiB0aGlzIGZpcnN0IERhdGEgU2NpZW5jZSBjb21wdXRlciBsYWIgd2Ugd2lsbCB0YWtlIHRoaW5ncyBzbG93bHksIGFuZCBmb2N1cyBvbiBwcmFjdGljaW5nIGFuZCByZWluZm9yY2luZyBrZXkgUiBjb2Rpbmcgc2tpbGxzIHlvdSBiZWdhbiBkZXZlbG9waW5nIGluIFt0aGUgZmlyc3QgY29yZSBDb21wdXRlciBMYWJdKGh0dHBzOi8vcnB1YnMuY29tL0xUVV9TVE0xMDAxL0NMMSksIHZpYSBzb21lIGxpZ2h0LWhlYXJ0ZWQgZXhhbXBsZXMuIEEgc29saWQgUiBmb3VuZGF0aW9uIHdpbGwgZW5zdXJlIHRoYXQgaW4gc3Vic2VxdWVudCBjb21wdXRlciBsYWJzLCB5b3Ugd2lsbCBiZSBhYmxlIHRvIHBpY2sgdXAgYW5kIGFwcGx5IG5ldyBSIGNvZGluZyBza2lsbHMgbW9yZSBlYXNpbHkuDQoNCg0KQnkgdGhlIGVuZCBvZiB0aGlzIGxhYiwgeW91IHNob3VsZCBmZWVsIGNvbWZvcnRhYmxlIHVzaW5nIHNpbXBsZSBSIGNvbW1hbmRzLCBjcmVhdGluZyBhbmQgbmFtaW5nIG5ldyBvYmplY3RzLCBpbnN0YWxsaW5nLCBsb2FkaW5nIGFuZCB1c2luZyBSIHBhY2thZ2VzLCBhbmQgc2F2aW5nIGltYWdlcyBnZW5lcmF0ZWQgaW4gUlN0dWRpby4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipSZW1pbmRlcjogT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpUaHJvdWdob3V0IHRoZSBjb21wdXRlciBsYWIgcXVlc3Rpb24gc2hlZXRzLCB5b3Ugd2lsbCBzZWUgZW1vamlzIGFuZC9vciBjb2xsYXBzaWJsZSBzZWN0aW9ucyBsaWtlIHRoaXMgb25lLiBFYWNoIGVtb2ppIGhhcyBhIHBhcnRpY3VsYXIgbWVhbmluZyBhbmQgd2lsbCBzb21ldGltZXMgYmUgYXNzb2NpYXRlZCB3aXRoIGFkZGl0aW9uYWwgaW5zdHJ1Y3Rpb25zOg0KDQoqKlByb21wdHMgZm9yIHlvdSoqDQoNCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIFdyaXRlIHlvdXIgYW5zd2VyIGluIHRoZSBjaGF0Lg0KDQoqKk1vZGVzIGF0IGRpZmZlcmVudCB0aW1lcyBkdXJpbmcgdGhlIGxhYioqDQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgICoqTWFpbiByb29tKiouIEFsbCB0b2dldGhlciBpbiB0aGUgbWFpbiByb29tIOKAkyB5b3VyIGNvbXB1dGVyIGxhYiBkZW1vbnN0cmF0b3Igd2lsbCBiZSBwcmVzZW50aW5nIGluZm9ybWF0aW9uIG9yIGZhY2lsaXRhdGluZyBjbGFzcyBkaXNjdXNzaW9uDQoNCmByIGVtbzo6amkoImJ1bGIiKWAgKipCcmVha291dCByb29tcyoqLiBQZXJzb24gd2l0aCBiaXJ0aGRheSBjbG9zZXN0IHRvICh5b3VyIGNvbXB1dGVyIGxhYiBkZW1vbnN0cmF0b3Igd2lsbCBwaWNrIGEgcmFuZG9tIGRhdGUpIHNoYXJlcyB0aGVpciBzY3JlZW4gb3Igd2hpdGVib2FyZC4gSGVyZSB5b3Ugd2lsbCBkaXNjdXNzIGEgcXVlc3Rpb24gdG9nZXRoZXIgYW5kIGJyaW5nIHlvdXIgZ3JvdXAncyBhbnN3ZXIgYmFjayB0byB0aGUgbWFpbiByb29tLg0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCAqKkZvY3VzIG1vZGUqKi4gWW91IHdpbGwgc3RpbGwgYmUgaW4gdGhlIG1haW4gcm9vbSwgYnV0IHdvcmtpbmcgaW5kZXBlbmRlbnRseS4gQWxsIHN0dWRlbnRzIHdpbGwgYmUgc2hhcmluZyBzY3JlZW4gZHVyaW5nIHRoaXMgdGltZSBzbyB0aGF0IHlvdXIgY29tcHV0ZXIgbGFiIGRlbW9uc3RyYXRvciAoYnV0IG5vdCBvdGhlciBzdHVkZW50cykgY2FuIHNlZSB5b3VyIHNjcmVlbi4gDQoNCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoInNjaG9vbCIpYCAqKlJlbWluZGVyOiBGYWNlLXRvLWZhY2UgKGJsZW5kZWQpIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpUaHJvdWdob3V0IHRoZSBjb21wdXRlciBsYWIgcXVlc3Rpb24gc2hlZXRzLCB5b3Ugd2lsbCBzZWUgZW1vamlzIGFuZC9vciBjb2xsYXBzaWJsZSBzZWN0aW9ucyBsaWtlIHRoaXMgb25lLiBZb3UgY2FuIGlnbm9yZSB0aGUgZW1vamlzIGFuZCBjb2xsYXBzaWJsZSBzZWN0aW9ucywgYXMgdGhleSBjb250YWluIGluZm9ybWF0aW9uIHJlbGV2YW50IHRvIHN0dWRlbnRzIHdobyBhcmUgc3R1ZHlpbmcgb25saW5lLg0KDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMgQ2hlY2tsaXN0IHstfQ0KDQpgciBlbW86OmppKCJob3VzZV93aXRoX2dhcmRlbiIpYCBCZWZvcmUgd2UgY29udGludWUsIG1ha2Ugc3VyZSB0aGF0IHlvdSBoYXZlIGRvbmUgdGhlIGZvbGxvd2luZzoNCg0KKiBJbnN0YWxsZWQgUiBhbmQgUlN0dWRpbyBvbiB5b3VyIHBlcnNvbmFsIGRldmljZSAodGhpcyB3aWxsIGJlIGhlbHBmdWwgZm9yIGFzc2lnbm1lbnQgd29yaywgZXZlbiBpZiB5b3UgaW50ZW5kIHRvIGNvbXBsZXRlIHRoZSBjb21wdXRlciBsYWJzIG9uIHVuaXZlcnNpdHkgY29tcHV0ZXJzKQ0KKiBDb21wbGV0ZWQgW3RoZSBmaXJzdCBjb3JlIENvbXB1dGVyIExhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvQ0wxKQ0KKiBMb29rZWQgb3ZlciB0aGUgZGlmZmVyZW50IGJvb2tzIGluIHRoZSAqSW50cm9kdWN0aW9uIHRvIFIqIGNvbnRlbnQgb24gTE1TDQoqIENvbmZpcm1lZCB0aGF0IHlvdSBhcmUgaW4gdGhlIGNvcnJlY3Qgc3RyZWFtDQoNCklmIHlvdSBoYXZlIGFueSBxdWVzdGlvbnMgYWJvdXQgYW55IG9mIHRoZXNlIGl0ZW1zLCBwbGVhc2UgYXNrIHlvdXIgY29tcHV0ZXIgbGFiIGRlbW9uc3RyYXRvciBmb3IgYXNzaXN0YW5jZS4NCg0KIyBJbnN0YWxsaW5nIG5ldyBSIHBhY2thZ2VzDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFIgY29udGFpbnMgbWFueSBpbi1idWlsdCBmdW5jdGlvbnMsIGFuZCBieSBpdHNlbGYgaXMgcGVyZmVjdGx5IHN1ZmZpY2llbnQgZm9yIGEgbnVtYmVyIG9mIGRhdGEgYW5hbHlzaXMgbWV0aG9kcy4NCkhvd2V2ZXIsIG9uZSBvZiB0aGUgZ3JlYXQgYmVuZWZpdHMgb2YgUiBpcyB0aGF0IGFueW9uZSBjYW4gY3JlYXRlICoqcGFja2FnZXMqKiAoYnVuZGxlcyBvZiBjb2RlLCBkYXRhIGFuZCBmdW5jdGlvbnMpIHdoaWNoIGNhbiBiZSB1cGxvYWRlZCB0byBnbG9iYWwgcmVwb3NpdG9yaWVzIChzdWNoIGFzIENSQU4pLCBhbmQgbWFkZSBhdmFpbGFibGUgZm9yIGFueW9uZSBhcm91bmQgdGhlIHdvcmxkIHRvIGRvd25sb2FkIGFuZCB1c2UgaW4gdGhlaXIgdmVyc2lvbiBvZiBSLiANCg0KVGhlc2UgcGFja2FnZXMgYXJlIG9mdGVuIGV4dHJlbWVseSBoZWxwZnVsLiBUaGV5IG1heSBjb250YWluIHVzZWZ1bCBkYXRhIHNldHMgZm9yIGEgc3BlY2lmaWMgZmllbGQgb2YgcmVzZWFyY2gsIGFkZHJlc3MgYSBzaG9ydGNvbWluZyB3aXRoIHRoZSBiYXNlIFIgc3VpdGUgb2YgZnVuY3Rpb25zLCBhbGxvdyB1c2VycyB0byBwZXJmb3JtIHNwZWNpYWxpc2VkIGFuYWx5c2VzLCBhbmQvb3Igb2ZmZXIgdXNlcnMgc29tZSBhZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdGllcyBtaXNzaW5nIGZyb20gYmFzZSBSLiAgDQoNCk9uIHRoZSBvdGhlciBoYW5kLCBzb21ldGltZXMgdXNlci1jcmVhdGVkIHBhY2thZ2VzIGFyZSBtb3JlIGxpZ2h0LWhlYXJ0ZWQsIG9yIGFyZSBwZXQgcHJvamVjdHMgbm90IG5lY2Vzc2FyaWx5IGludGVuZGVkIGZvciBzZXJpb3VzIGRhdGEgYW5hbHlzaXMuIE9uZSBzdWNoIGV4YW1wbGUgaXMgdGhlIGBtZW1lYCBwYWNrYWdlIFtAbWVtZXNdLCB3aGljaCBhbGxvd3MgdXNlcnMgdG8gY3JlYXRlIHNpbXBsZSBtZW1lcyB1c2luZyBSIGNvZGUuDQoNCkxldCdzIGluc3RhbGwgYW5kIGxvYWQgdGhlIGBtZW1lYCBwYWNrYWdlIGluIFJTdHVkaW8gbm93Lg0KDQojIyANCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgQmVjYXVzZSB0aGUgYG1lbWVgIHBhY2thZ2UgaXMgbm90IGluc3RhbGxlZCBpbiBiYXNlIFIsIHdlIG5lZWQgdG8gZG93bmxvYWQgaXQgYmVmb3JlIHdlIGNhbiB1c2UgaXQuDQpSZWNhbGwgdGhhdCB3ZSBjYW4gdXNlIHRoZSBgaW5zdGFsbC5wYWNrYWdlcygpYCBSIGZ1bmN0aW9uIHRvIGRvIHRoaXMuIFJ1biB0aGUgY29kZSBiZWxvdyB0byBkbyB0aGlzIG5vdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVCwgaW5jbHVkZSA9IEZ9DQppbnN0YWxsLnBhY2thZ2VzKCJtZW1lIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoIm1lbWUiKQ0KIyBOb3RlIHRoYXQgdGhlIHBhY2thZ2UgbmFtZSBtdXN0IGJlIHN1cnJvdW5kZWQgYnkgcXVvdGF0aW9uIG1hcmtzIHdoZW4gdXNpbmcgdGhlIGluc3RhbGwucGFja2FnZXMgZnVuY3Rpb24uDQpgYGANCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgV2hlbiB5b3UgaW5zdGFsbCBhbiBSIHBhY2thZ2UsIHlvdSB3aWxsIHNlZSBzb21lIHRleHQgYXBwZWFyIGluIHRoZSBSU3R1ZGlvIGBDb25zb2xlYCB3aW5kb3cuIE9mdGVuLCBzb21lIG9mIHRoaXMgdGV4dCBpcyA8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj5yZWQ8L3NwYW4+LCB3aGljaCBhdCBmaXJzdCBjYW4gYmUgdW5uZXJ2aW5nIC0geW91IG1heSB0aGluayB0aGF0IGFuIGVycm9yIGhhcyBvY2N1cnJlZC4gKipEb24ndCB3b3JyeSEqKiBXaGlsZSBpdCBpcyBhbHdheXMgYSBnb29kIGlkZWEgdG8gY2hlY2sgdGhlc2UgcmVkIHRleHQgbWVzc2FnZXMsIHRoZXkgYXJlIG5vdCBuZWNlc3NhcmlseSBlcnJvcnMsIGFuZCBvZnRlbiBjYW4gYmUgc2FmZWx5IGlnbm9yZWQuIA0KDQpJZiB5b3UgY2hlY2sgdGhlIGZpbmFsIHBhcnQgb2YgdGhlIHRleHQgb3V0cHV0LCB3aGljaCBpcyBpbiBibGFjayBub3QgcmVkLCB5b3Ugc2hvdWxkIHNlZSBzb21ldGhpbmcgbGlrZSBgcGFja2FnZSDigJhtZW1l4oCZIHN1Y2Nlc3NmdWxseSB1bnBhY2tlZCBhbmQgTUQ1IHN1bXMgY2hlY2tlZGAuIFRoaXMgaXMgcmVhc3N1cmluZyAtIHRoZSBwYWNrYWdlIGhhcyBpbnN0YWxsZWQgY29ycmVjdGx5LCBhbmQgdGhlIHJlZCB0ZXh0IGFib3ZlIGlzIGp1c3QgdGVsbGluZyB1cyBob3cgUiB3ZW50IGFib3V0IGluc3RhbGxpbmcgaXQuDQoNCipOb3RlOiBJZiB5b3Ugc2VlIGEgbWVzc2FnZSBhYm91dCBpbnN0YWxsaW5nIGBSdG9vbHNgLCBpZ25vcmUgaXQsIHdlIGRvbid0IG5lZWQgaXQgZm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGxhYi4qDQoNCiMjIA0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBPbmNlIHRoZSBgbWVtZWAgcGFja2FnZSBpcyBkb3dubG9hZGVkIGFuZCBpbnN0YWxsZWQsIHdlIG5lZWQgdG8gbG9hZCBpdCBpbiBvdXIgY3VycmVudCBSU3R1ZGlvIHNlc3Npb24uDQpSdW4gdGhlIGZvbGxvd2luZyBjb2RlIHRvIGxvYWQgdGhlIGBtZW1lYCBwYWNrYWdlLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCBpbmNsdWRlID0gRn0NCmxpYnJhcnkobWVtZSkNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KbGlicmFyeShtZW1lKQ0KYGBgDQoNCiMgTWFraW5nIG1lbWVzIGluIFJTdHVkaW8NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgV2l0aCB0aGUgYG1lbWVgIHBhY2thZ2UgaW5zdGFsbGVkIGFuZCBsb2FkZWQgaW4gUlN0dWRpbywgd2UgY2FuIG5vdyBzdGFydCB0byBtYWtlIHNvbWUgc2ltcGxlIG1lbWVzIQ0KV2UgcmVhbGx5IG9ubHkgbmVlZCB0d28gbGluZXMgb2YgY29kZSBmb3IgdGhpcywgYXMgd2Ugd2lsbCBkZW1vbnN0cmF0ZSB3aXRoIHRoZSBmb2xsb3dpbmcgZXhhbXBsZS4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgRmlyc3RseSwgd2UgbmVlZCB0byBmaW5kIGFuIGFwcHJvcHJpYXRlIGltYWdlLiBGb3IgdGhpcyBleGFtcGxlLCB3ZSB3aWxsIHVzZSBhbiBpbWFnZSBvZiBIYWdyaWQsIGZyb20gdGhlIEhhcnJ5IFBvdHRlciBzZXJpZXMuIFdlIGhhdmUgbG9jYXRlZCB0aGlzIGltYWdlIG9ubGluZSwgYW5kIGNvcGllZCB0aGUgdXJsLiBJbiBSU3R1ZGlvLCB3ZSBhc3NpZ24gdGhpcyB1cmwgdG8gdGhlIG9iamVjdCBgaGFncmlkYCwgYXMgc2hvd24gYmVsb3c6IA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KaGFncmlkIDwtICJodHRwczovL2kuaW1nZmxpcC5jb20vMTN3YjJ0LmpwZyINCiMgTm90ZSB0aGF0IHRoZSB1cmwgbmVlZHMgdG8gYmUgY29udGFpbmVkIHdpdGhpbiBxdW90YXRpb24gbWFya3MNCmBgYA0KDQpNYWtlIHN1cmUgdG8gcnVuIHRoaXMgY29kZSBiZWZvcmUgbW92aW5nIG9uIHRvIHRoZSBuZXh0IHN0ZXAuDQoNCipOb3RlOiBGb3IgYSByZWZyZXNoZXIgb24gb2JqZWN0cywgY2hlY2sgdGhlIFIgQ29kaW5nIEZ1bmRhbWVudGFscyBib29rIGluIHRoZSBJbnRyb2R1Y3Rpb24gdG8gUiBjb250ZW50IG9uIExNUy4qDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE5leHQsIHdlIHVzZSB0aGUgYG1lbWVgIGZ1bmN0aW9uICh3aGljaCBpcyBvbmx5IGF2YWlsYWJsZSBiZWNhdXNlIHdlIGluc3RhbGxlZCBhbmQgbG9hZGVkIHRoZSBgbWVtZWAgcGFja2FnZSkgdG8gYWRkIHNvbWUgd29yZHMgdG8gdGhpcyBpbWFnZS4gVHJ5IHJ1bm5pbmcgdGhlIGNvZGUgYmVsb3csIGFuZCBzZWUgd2hhdCBoYXBwZW5zLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KbWVtZShoYWdyaWQsICJZZXIgYSB3aXphcmQiLCAid2l0aCBjb2RpbmciLCBmb250ID0gInNhbnMiKQ0KYGBgDQoNCipOb3RlOiBTb21lIHdhcm5pbmdzIG1heSBhcHBlYXIgaW4gdGhlIGBDb25zb2xlYCBzZWN0aW9uIG9mIFJTdHVkaW8gYXMgdGhpcyBjb2RlIGlzIGV4ZWN1dGluZy4gRG9uJ3Qgd29ycnkgYWJvdXQgdGhlbSwgaXQgaXMgc2FmZSB0byBpZ25vcmUgdGhlc2Ugd2FybmluZ3MuKiANCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4NCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIEFmdGVyIHJ1bm5pbmcgdGhlIGNvZGUsIGEgbWVtZSBzaG91bGQgaGF2ZSBhcHBlYXJlZCBpbiBSU3R1ZGlvLiBUYWtlIGEgc25pcHBldC9zY3JlZW5zaG90IG9mIHRoZSBtZW1lIGFuZCBjb3B5LXBhc3RlIGl0IGludG8gdGhlIGNoYXQuDQo8L2RldGFpbHM+IA0KDQojIyBIb3cgdG8gc2F2ZSBSU3R1ZGlvIGltYWdlcw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBJZiB5b3Ugd291bGQgbGlrZSB0byBzYXZlIHRoZSBtZW1lIHlvdSBoYXZlIG1hZGUsIHdlIGhhdmUgc2V2ZXJhbCBvcHRpb25zLCB3aGljaCB3ZSB3aWxsIGRlbW9uc3RyYXRlIG5vdywgdmlhIGFub3RoZXIgZXhhbXBsZS4NCg0KSW4gdGhlIGNvZGUgYmVsb3csIHdlIG1ha2UgYSBuZXcgbWVtZSwgYW5kIGFzc2lnbiBpdCB0byB0aGUgb2JqZWN0IGBzdWNjZXNzYCwgdXNpbmcgdGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IgYDwtYC4gVHJ5IHJ1bm5pbmcgdGhpcyBjb2RlIG5vdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnN1Y2Nlc3Nfa2lkIDwtICJodHRwOi8vaTAua3ltLWNkbi5jb20vZW50cmllcy9pY29ucy9tb2JpbGUvMDAwLzAwMC83NDUvc3VjY2Vzcy5qcGciDQpzdWNjZXNzIDwtIG1lbWUoc3VjY2Vzc19raWQsICJVc2luZyBSIiwgInRvIG1ha2UgbWVtZXMiLCBmb250ID0gInNhbnMiKQ0Kc3VjY2Vzcw0KYGBgDQoNCipIaW50OiBOb3RpY2UgdGhhdCB3ZSBuZWVkIHRvIGluY2x1ZGUgdGhlIGZpbmFsIGxpbmUgb2YgY29kZSwgY2FsbGluZyB0aGUgb2JqZWN0IGBzdWNjZXNzYCwgaW4gb3JkZXIgZm9yIHRoZSBpbWFnZSB0byBiZSBzaG93bi4qDQoNCiMjIyBPcHRpb24gQTogQmFzZSBSIGZ1bmN0aW9uDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFdlIGNhbiB1c2UgdGhlIGJhc2UgUiBmdW5jdGlvbiBgc2F2ZVBsb3RgIHRvIHNhdmUgYW4gaW1hZ2UgY3JlYXRlZCBpbiBSU3R1ZGlvLg0KVG8gZG8gc28sIHRoZSBpbWFnZSBuZWVkcyB0byBoYXZlIGJlZW4gcHJvZHVjZWQgaW4gYSBzZXBhcmF0ZSBncmFwaGljcyBkZXZpY2UuIA0KICANCiAgKiBJZiB5b3UgYXJlIHVzaW5nIGEgV2luZG93cyBPUywgeW91IGNhbiBydW4gdGhlIGNvZGUgYHdpbmRvd3MoKWAgdG8gb3BlbiBhIHNlcGFyYXRlIGdyYXBoaWNzIGRldmljZSBpbiBSU3R1ZGlvLiANCiAgKiBJZiB5b3UgYXJlIHVzaW5nIGEgTWFjIE9TLCB0aGUgZXF1aXZhbGVudCBmdW5jdGlvbiBpcyBgcXVhcnR6KClgLg0KDQoqTm90ZTogU2VwYXJhdGUgZ3JhcGhpY3MgZGV2aWNlcyBmb3IgZWFjaCBpbWFnZSBjcmVhdGVkIGluIFJTdHVkaW8gY2FuIGJlIGhlbHBmdWwgaWYgeW91IHdhbnQgdG8gc2VlIHNldmVyYWwgaW1hZ2VzIGF0IG9uY2UuIFRlY2huaWNhbGx5IHlvdSBjYW4gYWxzbyBzYXZlIHRoZSBpbWFnZSB2aWEgdGhlIGdyYXBoaWNzIGRldmljZSdzIG1lbnUgYmFyLioNCg0KVGFrZSBhIGxvb2sgYXQgdGhlIGNvZGUgYmVsb3csIGFuZCB0aGVuIHJ1biBpdCwgdG8gc2F2ZSB5b3VyIHN1Y2Nlc3Mga2lkIG1lbWUgdG8geW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5Lg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0Kd2luZG93cygpICMgb3IgcXVhcnR6KCksIGlmIHlvdSBhcmUgYSBNYWMgdXNlcg0Kc3VjY2VzcyAjIHJlbmRlciB0aGUgaW1hZ2UgaW4gdGhlIGdyYXBoaWNzIGRldmljZQ0Kc2F2ZVBsb3QoZmlsZW5hbWUgPSAic3VjY2Vzc2tpZCIsIHR5cGUgPSAicG5nIikgDQpgYGANCg0KIyMjIE9wdGlvbiBCOiBBIGZ1bmN0aW9uIGZyb20gYSBzcGVjaWZpYyBwYWNrYWdlDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFNvbWV0aW1lcyBwYWNrYWdlcyB3aWxsIGluY2x1ZGUgYSBjdXN0b20gZnVuY3Rpb24gZm9yIHNvbWUgb3BlcmF0aW9uLCBzdWNoIGFzIHRoZSBzYXZpbmcgb2YgYSBmaWxlLiBUaGVzZSBjYW4gb2Z0ZW4gb2ZmZXIgYWRkaXRpb25hbCB1dGlsaXR5IHRvIHRoZSBkZWZhdWx0IGFsdGVybmF0aXZlLg0KDQpUaGUgYG1lbWVgIHBhY2thZ2UgaGFzIGEgc3BlY2lmaWMgZnVuY3Rpb24sIGBtZW1lX3NhdmVgLCBmb3Igc2F2aW5nIG1lbWVzLiBUYWtlIGEgbG9vayBhdCB0aGUgY29kZSBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCm1lbWVfc2F2ZShzdWNjZXNzLCBmaWxlPSJjOi9TVE0xMDAxL0RhdGEgU2NpZW5jZS9zdWNjZXNzX2tpZF9SX21lbWUucG5nIikgDQpgYGANCg0KSGVyZSwgdGhlIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBzcGVjaWZ5IHRoZSBzYXZlIGxvY2F0aW9uIG9mIG91ciBmaWxlLiBXZSBhcmUgc2F2aW5nIG91ciBgc3VjY2Vzc2AgbWVtZSB0byB0aGUgZXhhbXBsZSBmaWxlIGxvY2F0aW9uIGBjOlxTVE0xMDAxXERhdGEgU2NpZW5jZVxgLCB3aXRoIHRoZSBuYW1lIGBzdWNjZXNzX2tpZF9SX21lbWUucG5nYC4gDQoNCipOb3RlOiBBbHRob3VnaCB0aGUgZmlsZSBwYXRoIG9uIG91ciBjb21wdXRlciBpbmNsdWRlcyBiYWNrc2xhc2hlcyAoYFxgKSwgaW4gUiBjb2RlIHRoZXNlIG5lZWQgdG8gYmUgY2hhbmdlZCB0byBmb3J3YXJkIHNsYXNoZXMgKGAvYCkuKg0KDQojIyMgT3B0aW9uIEM6IFZpYSB0aGUgUlN0dWRpbyBQbG90cyB3aW5kb3cNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgSW5zdGVhZCBvZiB1c2luZyBSIGNvZGUsIHdlIGNhbiBzYXZlIG91ciBpbWFnZSBtYW51YWxseSwgYnkgbmF2aWdhdGluZyB0byB0aGUgYFBsb3RzYCB3aW5kb3cgaW4gUlN0dWRpbywgY2xpY2tpbmcgYEV4cG9ydGAsIGFuZCBzZWxlY3RpbmcgZWl0aGVyIGBTYXZlIGFzIEltYWdlLi4uYCBvciBgU2F2ZSBhcyBQREYuLi5gLCBhcyBzaG93biBiZWxvdzogDQoNCjxjZW50ZXI+PGltZyBzcmM9InNhdmVfaW1hZ2UuanBnIiB3aWR0aCA9IDMwMD48L2NlbnRlcj4NCg0KVHJ5IHRoaXMgbm93LCBhbmQgc2F2ZSB5b3VyIGBzdWNjZXNzYCBtZW1lIGFzIGEgcGRmLg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBOb3cgaXQncyB0aW1lIHRvIG1ha2UgeW91ciBvd24gbWVtZSBpbiBSU3R1ZGlvLiBGb2xsb3cgdGhlIHN0ZXBzIGJlbG93Og0KDQphLiBGaW5kIGFuIGFwcHJvcHJpYXRlIGltYWdlIG9mIHlvdXIgY2hvaWNlIG9ubGluZSAocGxlYXNlIGVuc3VyZSB5b3UgcGljayBjb250ZW50IHN1aXRhYmxlIGZvciB1bml2ZXJzaXR5IGFuZCB3b3JrKS4gDQoNCmIuIENvcHkgdGhlIHVybC4gDQoNCmMuIEFzc2lnbiB0aGlzIHVybCB0byBhbiBvYmplY3QgaW4gUlN0dWRpby4NCg0KZC4gVXNlIHRoZSBgbWVtZWAgZnVuY3Rpb24gdG8gYWRkIHdvcmRzIHRvIHlvdXIgaW1hZ2UuDQoNCmUuIFNhdmUgeW91ciBtZW1lIHVzaW5nIGVpdGhlciB0aGUgYHNhdmVQbG90YGZ1bmN0aW9uLCBgbWVtZV9zYXZlYCBmdW5jdGlvbiBvciB0aGUgbWFudWFsIGFwcHJvYWNoLg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqSGludCogIDwvc3VtbWFyeT4NCipIaW50OiBJZiB5b3UgYXJlIG5vdCBxdWl0ZSBzdXJlIGhvdyB0byBiZWdpbiwgY2xpY2sgdGhlIGBTaG93YCBidXR0b24gdG8gdGhlIHJpZ2h0IGJlbG93LioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgRmlyc3QsIHdlIG5lZWQgdG8gZmluZCBhbiBpbWFnZSwgYW5kIGFzc2lnbiBpdCB0byBhbiBvYmplY3QgDQojIChoZXJlIHdlIHVzZSB0aGUgZ2VuZXJpYyBvYmplY3QgbmFtZSAnaW1hZ2VfbmFtZScpDQojIEp1c3QgcmVwbGFjZSB0aGUgLi4ucyB3aXRoIHRoZSB1cmwgb2YgeW91ciBpbWFnZQ0KaW1hZ2VfbmFtZSA8LSAiLi4uIg0KIyBOZXh0LCB3ZSBuZWVkIHRvIHVzZSB0aGUgbWVtZSBmdW5jdGlvbiwgdG8gYWRkIHNvbWUgd29yZHMgKGp1c3QgcmVwbGFjZSB0aGUgLi4ucykNCm15X21lbWUgPC0gbWVtZShpbWFnZV9uYW1lLCAiLi4uIiwgIi4uLiIsIGZvbnQgPSAic2FucyIpDQojIE5vdGUgdGhhdCB5b3UgbmVlZCB0byBpbmNsdWRlIHRoZSBgLCBmb250ID0gInNhbnMiYCBwYXJ0IHRvIGVuc3VyZSBSIGtub3cgd2hpY2ggZm9udCB0byB1c2UuDQojIE5vdyBhbGwgdGhhdCdzIGxlZnQgaXMgdG8gc2F2ZSB5b3VyIG1lbWUgLSBqdXN0IHJlZmVyIHRvIHRoZSBjb2RlIGFib3ZlLg0KYGBgDQo8L2RldGFpbHM+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCBPbmNlIHlvdSBoYXZlIGNyZWF0ZWQgeW91ciBtZW1lIGluIFJTdHVkaW8sIHRha2UgYSBzbmlwcGV0L3NjcmVlbnNob3Qgb2YgaXQgYW5kIGNvcHktcGFzdGUgaXQgaW50byB0aGUgY2hhdC4NCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KQ29uZ3JhdHVsYXRpb25zISBZb3Ugd2VyZSBwcm9iYWJseSBub3QgZXhwZWN0aW5nIHRvIG1ha2UgYSBtZW1lIGluIHlvdXIgZmlyc3QgZGF0YSBzY2llbmNlIGNvbXB1dGVyIGxhYi4gV2hpbGUgdGhpcyB3b24ndCBiZSBvbiB0aGUgZmluYWwgZXhhbSwgdGhlIFIgc2tpbGxzIHlvdSBhcmUgZGV2ZWxvcGluZyBoZXJlIGFyZSBpbXBvcnRhbnQsIGFuZCBob3BlZnVsbHkgeW91IGFyZSBzdGFydGluZyB0byByZWFsaXNlIHRoYXQgUiBpcyB2ZXJ5IHZlcnNhdGlsZS4NCg0KPGJyPg0KDQojIyMjIGByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIFJlY29udmVuZSBpbiBtYWluIHJvb20gdG8gZGlzY3VzcyByZXN1bHRzIHstfQ0KDQo8YnI+DQoNCiMgQ3VzdG9taXppbmcgR0lGcyBpbiBSU3R1ZGlvDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgICBSIGlzIG5vdCBsaW1pdGVkIHRvIHdvcmtpbmcgd2l0aCBzdGF0aWMgaW1hZ2VzIC0gd2UgY2FuIG1vZGlmeSBhbmQgY3JlYXRlIEdJRnMgYW5kIGFuaW1hdGlvbnMgKGFuZCBpbiBmdXR1cmUgd2Vla3Mgd2Ugd2lsbCBtYWtlIGFuaW1hdGVkLCBpbnRlcmFjdGl2ZSBncmFwaHMgdXNpbmcgcmVhbCBkYXRhKS4NCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCB1c2UgYW5vdGhlciBmdW4gcGFja2FnZSwgdGhlIGBtYWdpY2tgIHBhY2thZ2UgW0BtYWdpY2tdLCB0byBjdXN0b21pemUgYSBHSUYuDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgICBSdW4gdGhlIGZvbGxvd2luZyBjb2RlIHRvIGRvd25sb2FkLCBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgbWFnaWNrYCBwYWNrYWdlIGluIHlvdXIgY3VycmVudCBSU3R1ZGlvIHNlc3Npb24uDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFQsIGluY2x1ZGUgPSBGfQ0KaW5zdGFsbC5wYWNrYWdlcygibWFnaWNrIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KG1hZ2ljaykNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KbGlicmFyeShtYWdpY2spDQpgYGANCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgIEp1c3QgYXMgd2Ugb2J0YWluZWQgb25saW5lIGltYWdlcyBvZiBgaGFncmlkYCBhbmQgYHN1Y2Nlc3Mga2lkYCwgc28gdG9vIGNhbiB3ZSB1c2UgdXJscyB0byBHSUZzIGFuZCBhbmltYXRpb25zLg0KRm9yIHRoaXMgZXhhbXBsZSwgd2UgaGF2ZSB1c2VkIHRoZSB1cmwgdG8gYSBHSUYgb2YgYSByb3RhdGluZyBFYXJ0aC4NCg0KV2UgY2FuIHVzZSB0aGUgYGltYWdlX3JlYWRgIGZ1bmN0aW9uIHRvIHJlYWQgdGhpcyBHSUYgaW50byBSU3R1ZGlvLiBSdW4gdGhlIGNvZGUgYmVsb3cgdG8gYXNzaWduIGl0IHRvIHRoZSBvYmplY3QgYEVhcnRoYC4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVCwgLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCkVhcnRoIDwtIGltYWdlX3JlYWQoImh0dHBzOi8vaS5naXBoeS5jb20vbWVkaWEvbWY4VWJJRGV3N2U4Zy9naXBoeS5naWYiKQ0KRWFydGgNCmBgYA0KDQpNYWtlIHN1cmUgdG8gcnVuIHRoaXMgY29kZSBiZWZvcmUgbW92aW5nIG9uIHRvIHRoZSBuZXh0IHN0ZXAgKGRvbid0IHdvcnJ5IGlmIGl0IHRha2VzIGEgZmV3IHNlY29uZHMpLiBUaGUgR0lGIHNob3VsZCBhcHBlYXIgaW4gdGhlIGBWaWV3ZXJgIHNlY3Rpb24gb2YgUlN0dWRpby4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgIFVzaW5nIHRoZSBgbWFnaWNrYCBwYWNrYWdlLCB3ZSBjYW4gZWFzaWx5IG1ha2Ugc29tZSBjaGFuZ2VzIHRvIHRoaXMgYEVhcnRoYCBHSUYuDQoNClJ1biB0aGUgZm9sbG93aW5nIGNvZGUsIGFuZCBpbnNwZWN0IHRoZSBvdXRwdXQuDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFQsICwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpyZXYoRWFydGgpICU+JSANCiAgICAgICAgICAgaW1hZ2VfZmxpcCgpICU+JSANCiAgICAgICAgICAgaW1hZ2VfYW5ub3RhdGUoIiAgICAgICAgTWVhbndoaWxlLCBpbiBBdXN0cmFsaWEiLCBzaXplID0gNDAsIGNvbG9yID0gIndoaXRlIikNCmBgYA0KDQpZb3Ugd2lsbCBub3RpY2UgaGVyZSB0aGF0OiANCg0KKiBXZSBoYXZlIHJldmVyc2VkIHRoZSBHSUYsIHVzaW5nIHRoZSBgcmV2YCBmdW5jdGlvbg0KKiBXZSBoYXZlIGZsaXBwZWQgdGhlIEdJRiwgdXNpbmcgdGhlIGBpbWFnZV9mbGlwYCBmdW5jdGlvbiwgYW5kDQoqIFdlIGhhdmUgYWRkZWQgdGV4dCB0byB0aGlzIEdJRiB1c2luZyB0aGUgYGltYWdlX2Fubm90YXRlYCBmdW5jdGlvbg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgT25jZSB5b3UgaGF2ZSBjcmVhdGVkIHlvdXIgR0lGLCB0YWtlIGEgc25pcHBldC9zY3JlZW5zaG90IG9mIGl0IGFuZCBjb3B5LXBhc3RlIGl0IGludG8gdGhlIGNoYXQuDQo8L2RldGFpbHM+IA0KDQpUaGlzIGlzIHJlYWxseSBqdXN0IHNjcmF0Y2hpbmcgdGhlIHN1cmZhY2Ugb2YgdGhlIGBtYWdpY2tgIHBhY2thZ2UuIEZvciB0aGUgbW9tZW50IHRob3VnaCwgbGV0J3MgbW92ZSBvbi4NCg0KPCEtLSAjIERyYXdpbmcgYSBmaXNoIGluIFJTdHVkaW8gLS0+DQoNCjwhLS0gYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgIEluc3RlYWQgb2YgdXNpbmcgYSBwcmUtZXhpc3RpbmcgaW1hZ2Ugb3IgR0lGLCBsZXQncyBub3cgdHJ5IHRvIGNyZWF0ZSBvbmUgZnJvbSBzY3JhdGNoLiBTcGVjaWZpY2FsbHksIGxldCdzIGRyYXcgYSBmaXNoLiBUbyBkbyB0aGlzLCB3ZSBjYW4gdXNlIHRoZSBhcHByb3ByaWF0ZWx5IG5hbWVkIGByZmlzaGRyYXdgIHBhY2thZ2UgW0ByZmlzaGRyYXddLiAgLS0+DQo8IS0tIDxicj4gLS0+DQo8IS0tICpOb3RlIHRoYXQgdGhpcyBwYWNrYWdlIHdvcmtzIG9uIFIgV2luZG93cyBWLjQuNS4wIGFzIGF0IDMwLzA3LzIwMjUsIGJ1dCBtYXkgcmVxdWlyZSBzZXZlcmFsIGRlcGVuZGVuY3kgcGFja2FnZXMgdG8gYmUgdXBkYXRlZC4qIC0tPg0KDQo8IS0tICMjIC0tPg0KDQo8IS0tIGByIGVtbzo6amkoImNvbXB1dGVyIilgICBMZXQncyBkb3dubG9hZCBhbmQgaW5zdGFsbCB0aGUgYHJmaXNoZHJhd2AgcGFja2FnZSBub3cuIEluIG9yZGVyIHRvIHVzZSB0aGlzIHBhY2thZ2UsIHdlIHdpbGwgYWxzbyBuZWVkIHRvIGRvd25sb2FkIGFuZCBpbnN0YWxsIHNvbWUgYWRkaXRpb25hbCBwYWNrYWdlcywgdXBvbiB3aGljaCB0aGUgYHJmaXNoZHJhd2AgcGFja2FnZSBkZXBlbmRzLiBTdWNoIHBhY2thZ2VzIGFyZSBrbm93biBhcyAqKmRlcGVuZGVuY2llcyoqLCBhbmQgaXQgaXMgY29tbW9uIGZvciBtb3JlIHNvcGhpc3RpY2F0ZWQgUiBwYWNrYWdlcyB0byBoYXZlIG11bHRpcGxlIGRlcGVuZGVuY2llcy4gLS0+DQoNCjwhLS0gKk5vdGU6IFRoZXNlIGRlcGVuZGVuY2llcyBhcmUgcGFja2FnZXMgaW4gdGhlaXIgb3duIHJpZ2h0LiogLS0+DQoNCjwhLS0gUnVuIHRoZSBjb2RlIGJlbG93IGluIFJTdHVkaW86IC0tPg0KDQo8IS0tIGBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFQsIGluY2x1ZGUgPSBGfSAtLT4NCjwhLS0gaW5zdGFsbC5wYWNrYWdlcygicmZpc2hkcmF3IiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpIC0tPg0KPCEtLSBpbnN0YWxsLnBhY2thZ2VzKCJwYXRjaHdvcmsiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikgLS0+DQo8IS0tIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSBgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfSAtLT4NCjwhLS0gIyBNYWluIHBhY2thZ2UgLS0+DQo8IS0tIGluc3RhbGwucGFja2FnZXMoInJmaXNoZHJhdyIpIC0tPg0KPCEtLSAjIERlcGVuZGVuY2llcyAtLT4NCjwhLS0gaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIik7IGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAtLT4NCjwhLS0gYGBgIC0tPg0KDQo8IS0tIGBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIGluY2x1ZGUgPSBGfSAtLT4NCjwhLS0gbGlicmFyeSgicmZpc2hkcmF3IikgLS0+DQo8IS0tIGxpYnJhcnkoInBhdGNod29yayIpIC0tPg0KPCEtLSBsaWJyYXJ5KCJnZ3Bsb3QyIikgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSBgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfSAtLT4NCjwhLS0gbGlicmFyeSgicmZpc2hkcmF3Iik7IGxpYnJhcnkoInBhdGNod29yayIpOyBsaWJyYXJ5KCJnZ3Bsb3QyIikgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSAjIyAtLT4NCg0KPCEtLSBgciBlbW86OmppKCJjb21wdXRlciIpYCBSdW4gdGhlIGNvZGUgYmVsb3cgdG8gcmVuZGVyIGEgZGV0YWlsZWQgZHJhd2luZyBvZiBhIGZpc2ggaW4gUlN0dWRpbyAocmVjYWxsIHRoZSBgd2luZG93cygpYCBhbmQgYHF1YXJ0eigpYCBncmFwaGljcyB3aW5kb3dzIGNvZGUpOiAtLT4NCg0KPCEtLSBgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfSAtLT4NCjwhLS0gZ2V0X3BvbHlsaW5lcyhwYXRoID0gImluc3QvZmlzaGRyYXcuanMiLCBmb3JtYXQgPSAic21pbCIsIC0tPg0KPCEtLSAgICAgICAgICAgICAgIG91dHB1dCA9ICJhbmltYXRlZC5zdmciLCBkcmF3X3R5cGUgPSAicmFuZG9tIikgLS0+DQoNCjwhLS0gIyBGb3IgV2luZG93cyB1c2VycywgdXNlIC0tPg0KPCEtLSB3aW5kb3dzKCkgIC0tPg0KPCEtLSBmaXNoX2RyYXcoKSAtLT4NCg0KPCEtLSAjIEZvciBNYWMgdXNlcnMsIGluc3RlYWQgdXNlIC0tPg0KPCEtLSBxdWFydHooKSAtLT4NCjwhLS0gZmlzaF9kcmF3KCkgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSA8ZGV0YWlscz4gLS0+DQo8IS0tICAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5PiAtLT4NCjwhLS0gYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgT25jZSB5b3UgaGF2ZSBjcmVhdGVkIHlvdXIgZmlzaCBpbWFnZSBpbiBSU3R1ZGlvLCB0YWtlIGEgc25pcHBldC9zY3JlZW5zaG90IG9mIGl0IGFuZCBjb3B5LXBhc3RlIGl0IGludG8gdGhlIGNoYXQuIC0tPg0KPCEtLSA8L2RldGFpbHM+ICAtLT4NCg0KPCEtLSAjIyAtLT4NCg0KPCEtLSBgciBlbW86OmppKCJjb21wdXRlciIpYCAgU3VwcG9zZSB3ZSB3b3VsZCBsaWtlIHRvIGNoYW5nZSB0aGUgY29sb3VyIG9mIG91ciBmaXNoLiBXZSBjYW4gZG8gdGhpcywgYnkgaW5jbHVkaW5nIHRoZSBhcmd1bWVudCBgY29sID0gIi4uLiJgIHdpdGhpbiB0aGUgZnVuY3Rpb24gYGZpc2hfZHJhd2AuIEZvciBleGFtcGxlLCBpZiB3ZSB3b3VsZCBsaWtlIG91ciBmaXNoIHRvIGJlIGJsdWUsIHdlIGNhbiB3cml0ZSAtLT4NCg0KPCEtLSBgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfSAtLT4NCjwhLS0gZmlzaF9kcmF3KGNvbCA9ICJibHVlIikgLS0+DQo8IS0tIGBgYCAtLT4NCg0KPCEtLSBUcnkgY2hhbmdpbmcgdGhpcyBjb2xvdXIgdG8gYSBkaWZmZXJlbnQgY29sb3VyLCBhbmQgdGhlbiBydW4gdGhlIGNvZGUuIC0tPg0KDQo8IS0tICpOb3RlOiBBcyB3ZSB3aWxsIHNlZSBpbiBmdXR1cmUgbGFicywgbWFueSBSIGZ1bmN0aW9ucyBmb3IgcHJvZHVjaW5nIHZpc3VhbGlzYXRpb25zIGluY29ycG9yYXRlIGFuIGFyZ3VtZW50IGxpa2UgYGNvbCA9IGAgdG8gYWxsb3cgZm9yIGNvbG91ciBzcGVjaWZpY2F0aW9uLiogLS0+DQoNCjwhLS0gPGRldGFpbHM+IC0tPg0KPCEtLSAgIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4gLS0+DQo8IS0tIGByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIE9uY2UgeW91IGhhdmUgY3JlYXRlZCB5b3VyIGNvbG91cmVkIGZpc2ggaW1hZ2UgaW4gUlN0dWRpbywgdGFrZSBhIHNuaXBwZXQvc2NyZWVuc2hvdCBvZiBpdCBhbmQgY29weS1wYXN0ZSBpdCBpbnRvIHRoZSBjaGF0LiAtLT4NCjwhLS0gPC9kZXRhaWxzPiAgLS0+DQoNCiMgUGFsbWVyIFBlbmd1aW5zIERhdGEgU2V0IHsjcGVuZ3VpbnN9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgICBOb3cgdGhhdCB3ZSBoYXZlIGhhZCBhIHRhc3RlIG9mIHNvbWUgb2YgdGhlIG1vcmUgbGlnaHQtaGVhcnRlZCBSIHBhY2thZ2VzIG91dCB0aGVyZSwgbGV0J3MgY29uc2lkZXIgYSBwYWNrYWdlIHdoaWNoIGNvbnRhaW5zIHNvbWUgdXNlZnVsIGRhdGEuDQoNClRoZSBgcGFsbWVycGVuZ3VpbnNgIFIgcGFja2FnZSBbQHBlbmd1aW5zXSBjb250YWlucyBkYXRhLCBjb2xsZWN0ZWQgb3ZlciB0aGUgY291cnNlIG9mIHNldmVyYWwgeWVhcnMsIG9uIDMgc3BlY2llcyBvZiBwZW5ndWluIGxpdmluZyBvbiBkaWZmZXJlbnQgaXNsYW5kcyBpbiB0aGUgUGFsbWVyIGFyY2hpcGVsYWdvLCBvZmYgdGhlIGNvYXN0IG9mIEFudGFyY3RpY2EuIE92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgbmV4dCBmZXcgZGF0YSBzY2llbmNlIGNvbXB1dGVyIGxhYnMsIHdlIHdpbGwgY3JlYXRlIHZhcmlvdXMgaW50ZXJhY3RpdmUgZGF0YSB2aXN1YWxpc2F0aW9ucyB1c2luZyB0aGUgYHBlbmd1aW5zYCBkYXRhIGZyb20gdGhpcyBwYWNrYWdlLg0KDQpGb3IgbW9yZSBkZXRhaWxzIG9uIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0LCBhbmQgYSB0YXN0ZSBvZiB3aGF0J3MgYWhlYWQgaW4gZnV0dXJlIGxhYnMsIHlvdSBjYW4gcmVmZXIgdG8gW1NlY3Rpb24gMiBvZiB0aGUgRGF0YSBWaXN1YWxpc2F0aW9uIGluIFIgc3VwcGxlbWVudF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvcmVoay9zdG0xMDAxX2RzbV9kYXRhX3Zpc3VhbGlzYXRpb25faW5fci9wZW5ndWlucy5odG1sKS4NCg0KRm9yIHRoaXMgbGFiLCBsZXQncyB1c2Ugc29tZSBSIGZ1bmN0aW9ucyB0byBpbnNwZWN0IHRoZSAgYHBlbmd1aW5zYCBkYXRhIHNldC4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgIEp1c3QgbGlrZSB0aGUgcHJldmlvdXMgcGFja2FnZXMsIHRvIGJlZ2luIHdlIHdpbGwgbmVlZCB0byBkb3dubG9hZCBhbmQgbG9hZCB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlLg0KDQpVc2luZyB3aGF0IHlvdSBoYXZlIHByYWN0aWNlZCBlYXJsaWVyIGluIHRoaXMgY29tcHV0ZXIgbGFiLCBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2UgaW4gUlN0dWRpby4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gRiwgaW5jbHVkZSA9IEZ9DQppbnN0YWxsLnBhY2thZ2VzKHNldGRpZmYoInBhbG1lcnBlbmd1aW5zIiwgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZz1GfQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCmBgYA0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCAgUmVjYWxsIGZyb20gW3RoZSBmaXJzdCBjb3JlIENvbXB1dGVyIExhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvQ0wxKSB0aGF0IHlvdSBjYW4gZWFzaWx5IGNoZWNrIHRoZSBkaW1lbnNpb25zIG9mIHlvdXIgZGF0YSB1c2luZyB0aGUgYGRpbWAsIGBucm93YCBhbmQgYG5jb2xgIGZ1bmN0aW9ucy4gVXNlIHRoZXNlIG5vdyB0byBhc3Nlc3MgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQuDQoNCipOb3RlOiBDaGVjayB0aGUgYENvZGVgIGJ1dHRvbiBiZWxvdyBpZiB5b3Ugd291bGQgbGlrZSBhIHJlZnJlc2hlci4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFR9DQojIFRoaXMgY29kZSBjaGVja3MgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHBlbmd1aW5zIGRhdGEgc2V0DQpkaW0ocGVuZ3VpbnMpDQpgYGANCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4NCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIENvcHkgeW91ciByZXN1bHQgZnJvbSB0aGUgUlN0dWRpbyBjb25zb2xlIGFuZCBwYXN0ZSBpdCBpbnRvIHRoZSBjaGF0Lg0KPC9kZXRhaWxzPiANCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgVXNlIHRoZSBgc3VtbWFyeWAgZnVuY3Rpb24gdG8gb2J0YWluIGEgcXVpY2sgb3ZlcnZpZXcgb2YgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQuDQoNCkRvbid0IHdvcnJ5IHRvbyBtdWNoIGFib3V0IHRoZSB2YWx1ZXMgc2hvd24gaW4gdGhlIHN1bW1hcnkgdGFibGUgLSB0aGUgbWFpbiB0aGluZ3MgdG8gbm90ZSBhdCB0aGlzIHN0YWdlIGFyZSB0aGUgZGlmZmVyZW50IHZhcmlhYmxlcy4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgIE9mdGVuLCB3aGVuIHdlIGJlZ2luIHdvcmtpbmcgd2l0aCBhIG5ldyBkYXRhIHNldCwgaXQgaXMgaGVscGZ1bCB0byB0YWtlIGEgcXVpY2sgbG9vayBhdCBzb21lIG9mIHRoZSByZWNvcmRlZCB2YWx1ZXMuIFdlIGNhbiB1c2UgdGhlIGBoZWFkYCBmdW5jdGlvbiB0byBsb29rIGF0IHRoZSByZWNvcmRlZCB2YWx1ZXMgZm9yIHRoZSBmaXJzdCA2IG9ic2VydmF0aW9ucyBpbiBhIGRhdGEgc2V0LiANCg0KVHJ5IHVzaW5nIHRoZSBgaGVhZGAgZnVuY3Rpb24gbm93LCB3aXRoIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0LiBXaGF0IGRvIHlvdSBvYnNlcnZlPw0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgQ29weSB5b3VyIHJlc3VsdCBmcm9tIHRoZSBSU3R1ZGlvIGNvbnNvbGUgYW5kIHBhc3RlIGl0IGludG8gdGhlIGNoYXQuDQo8L2RldGFpbHM+IA0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCAgV2hlbiBhIGRhdGEgc2V0IGhhcyBtdWx0aXBsZSBjb2x1bW5zIG9mIGluZm9ybWF0aW9uLCB3ZSBjYW4gYXNzZXNzIHRoZSBpbmZvcm1hdGlvbiBpbiBzcGVjaWZpYyBjb2x1bW4gYnkgd3JpdGluZyB0aGUgbmFtZSBvZiB0aGUgb2JqZWN0LCBhZGRpbmcgYSBgJGAgYXQgdGhlIGVuZCwgYW5kIHRoZW4gd3JpdGluZyB0aGUgbmFtZSBvZiB0aGUgc3BlY2lmaWMgY29sdW1uIHdlIHdvdWxkIGxpa2UgdG8gaW5zcGVjdC4NCg0KRm9yIGV4YW1wbGUsIHdlIGNvdWxkIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUgdG8gY2hlY2sgdGhlIHJlY29yZGVkIGJpbGwgbGVuZ3RoIG1lYXN1cmVtZW50cyBvZiB0aGUgcGVuZ3VpbnM6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWlucyRiaWxsX2xlbmd0aF9tbQ0KYGBgDQoNClJ1biB0aGlzIGNvZGUgbm93Lg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqTm90ZSogIDwvc3VtbWFyeT4NCipXaGVuIHdlIGhhdmUgYSBsYXJnZSBkYXRhIHNldCwgb3V0cHV0IG1heSBhcHBlYXIgb3ZlciBzZXZlcmFsIGxpbmVzIGluIHRoZSBgQ29uc29sZWAuIFRoZSBudW1iZXJzIHRoYXQgYXBwZWFyIGluIGJyYWNrZXRzIHRvIHRoZSBsZWZ0IG9mIGVhY2ggbGluZSBvZiBvdXRwdXQgYXJlIG5vdCBvYnNlcnZhdGlvbnMuIFJhdGhlciwgdGhlc2UgZGVub3RlIHRoZSBwb3NpdGlvbiBudW1iZXIgZm9yIHRoZSBmaXJzdCBvYnNlcnZhdGlvbiBvbiB0aGF0IGxpbmUgb2Ygb3V0cHV0LiBFLmcuIGEgYFsxN11gIHdvdWxkIGRlbm90ZSB0aGF0IHRoZSBvYnNlcnZhdGlvbiBkaXJlY3RseSB0byB0aGUgcmlnaHQgb2YgdGhlIGBbMTddYCBpcyB0aGUgMTd0aCByZWNvcmRlZCBvYnNlcnZhdGlvbiBpbiB0aGUgZGF0YSBzZXQsIGZvciB0aGUgdmFyaWFibGUgYmVpbmcgY29uc2lkZXJlZC4qDQo8L2RldGFpbHM+DQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgICBUcnkgdXNpbmcgdGhpcyBgJGAgYXBwcm9hY2ggdG8gY2hlY2sgdGhlIHJlY29yZGVkIGJpbGwgZGVwdGhzIGFuZCBib2R5IG1hc3NlcyBvZiB0aGUgcGVuZ3VpbnMuDQoNCipOb3RlOiBOb3RpY2UgdGhhdCBvbmNlIHlvdSB0eXBlIHRoZSBgJGAsIFJTdHVkaW8gd2lsbCBoZWxwZnVsbHkgcHJvbXB0IHlvdSB3aXRoIHBvc3NpYmxlIHNlbGVjdGlvbnMuKg0KDQo8YnI+DQoNCiMjIyMgYHIgZW1vOjpqaSgiaG91c2Vfd2l0aF9nYXJkZW4iKWAgUmVjb252ZW5lIGluIG1haW4gcm9vbSB0byBkaXNjdXNzIHJlc3VsdHMgey19DQoNCjxicj4NCg0KIyMjIyBUaGF0J3MgdGhlIGVuZCBvZiB0aGUgZmlyc3QgZGF0YSBzY2llbmNlIGNvbXB1dGVyIGxhYiEgIyMjIyB7LX0NCg0KSG9wZWZ1bGx5IHlvdSBoYXZlIGVuam95ZWQgdGhpcyBmaXJzdCBjb21wdXRlciBsYWIsIGFuZCBub3cgaGF2ZSBhIGJldHRlciBpZGVhIG9mIGp1c3QgaG93IHZlcnNhdGlsZSBSIGNhbiBiZSAocGFydGljdWxhcmx5IHdoZW4gdXNpbmcgdGhlIGhlbHBmdWwgUlN0dWRpbyBHVUkpLiBEb24ndCB3b3JyeSBpZiBzb21lIG9mIHRoZSBjb2RlIHNlZW1zIGRpZmZpY3VsdCBhdCB0aGUgbW9tZW50IC0gdGhpcyBpcyBvbmx5IHRoZSBmaXJzdCBsYWIgYWZ0ZXIgYWxsISANCg0KSW4gdGhlIG5leHQgZGF0YSBzY2llbmNlIGNvbXB1dGVyIGxhYiB3ZSB3aWxsIGNvbnRpbnVlIHdvcmtpbmcgd2l0aCB0aGUgYHBhbG1lcnBlbmd1aW5zYCBkYXRhIHNldCwgYW5kIGNvdmVyIGhvdyB0byBjcmVhdGUgaW50ZXJhY3RpdmUgcGxvdHMgdXNpbmcgYSBuZXcgcGFja2FnZS4NCg0KIyMjIyBJbXBvcnRhbnQgTm90ZXMgIyMjIyB7LX0NCg0KDQoqICoqSWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucyBhYm91dCB0aGUgY29udGVudCBpbiB0aGlzIGxhYiwgb3IgYXJlIHN0dWNrIG9uIHNvbWUgUiBjb2RlIHVzZWQgaW4gdGhlIGxhYiwgcGxlYXNlIGFzayB5b3VyIGxhYiBkZW1vbnN0cmF0b3IgZm9yIGFzc2lzdGFuY2UuKioNCg0KKiAqKk1ha2Ugc3VyZSB0byBzYXZlIHlvdXIgUiBzY3JpcHQgZmlsZSBzb21ld2hlcmUgc2FmZSAtIGl0IG1heSBiZSBhIGhlbHBmdWwgcmVmZXJlbmNlIHNvdXJjZSBmb3IgbGF0ZXIgd29yay4qKg0KDQoqICoqTWFrZSBzdXJlIHRoYXQgeW91IGZpbmlzaCBvZmYgeW91ciByZWFkaW5ncyBvZiB0aGUgSW50cm9kdWN0aW9uIHRvIFIgY29udGVudCBvbiBMTVMgcHJpb3IgdG8gdGhlIHNlY29uZCBkYXRhIHNjaWVuY2UgY29tcHV0ZXIgbGFiLioqDQoNCjxicj4NCg0KIyBSZWZlcmVuY2VzIHstICNSZWZ9DQo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4NCg0KPGJyPg0KDQo8Zm9udCBjb2xvciA9ICJncmV5Ij4NClRoZXNlIG5vdGVzIGhhdmUgYmVlbiBwcmVwYXJlZCBieSBSdXBlcnQgS3V2ZWtlLiBUaGUgY29weXJpZ2h0IGZvciB0aGUgbWF0ZXJpYWwgaW4gdGhlc2Ugbm90ZXMgcmVzaWRlcyB3aXRoIHRoZSBhdXRob3IgbmFtZWQgYWJvdmUsIHdpdGggdGhlIERlcGFydG1lbnQgb2YgTWF0aGVtYXRpY2FsIGFuZCBQaHlzaWNhbCBTY2llbmNlcyBhbmQgd2l0aCBMYSBUcm9iZSBVbml2ZXJzaXR5LiBDb3B5cmlnaHQgaW4gdGhpcyB3b3JrIGlzIHZlc3RlZCBpbiBMYSBUcm9iZSBVbml2ZXJzaXR5IGluY2x1ZGluZyBhbGwgTGEgVHJvYmUgVW5pdmVyc2l0eSBicmFuZGluZyBhbmQgbmFtaW5nLiBVbmxlc3Mgb3RoZXJ3aXNlIHN0YXRlZCwgbWF0ZXJpYWwgd2l0aGluIHRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uIENvbW1lcmNpYWwtTm9uIERlcml2YXRpdmVzIExpY2Vuc2UgDQo8YSBocmVmID0gImh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1uZC80LjAvQ0MiIHRhcmdldD0iX2JsYW5rIj4gQlktTkMtTkQuIDwvYT4NCjwvZm9udD4=