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.

1 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.

1.1

πŸ’» 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.

1.2

πŸ’» 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.

1.3

πŸ’» 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)

2 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.

2.1

πŸ’» 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.

2.2

πŸ’» 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.

2.3 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.

2.3.1 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") 

2.3.2 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 (/).

2.3.3 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.

2.4

πŸ’» Now it’s time to make your own meme in RStudio. Follow the steps below:

  1. Find an appropriate image of your choice online (please ensure you pick content suitable for university and work).

  2. Copy the url.

  3. Assign this url to an object in RStudio.

  4. Use the meme function to add words to your image.

  5. Save your meme using either the savePlotfunction, 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


3 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.

3.1

πŸ’» Run the following code to download, install and load the magick package in your current RStudio session.

install.packages("magick")
library(magick)

3.2

πŸ’» 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.

3.3

πŸ’» 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.

4 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.

4.1

πŸ’» 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

4.2

πŸ’» 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.

4.3

πŸ’» 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.

4.4

πŸ’» 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.

4.5

πŸ’» 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.

4.6

πŸ’» 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=