Today we are going to learn how to plot data in R! While there are some simple plotting functions built into base R (you will often see tutorials that use the plot() command), I encourage you to produce your plots and data visualizations uisng the ggplot2 package in R. This package takes a little getting used to, but once you understand the syntax you will be making effective graphs and visualizations in no time! Visualizing data is such an important part of the data analysis process: it helps us to better understand the data and its distribution, it allows us to identify and communicate patterns in simple and visually appealing ways, and it enables us to condense a large amount of technical information into a diagram or visual.


#Make sure you download ggplot2 first! Let's load in package and set the working directory.
setwd("~/Binghamton/harp130")
library(dplyr)
library(tidyr)
library(ggplot2)

#we'll start by loading in some data to play with! We'll use NYC temperature data for this tutorial. 

temps <- read.csv("temps_nyc.csv")

#Take a look at this dataset! It contains mean, min, and max temperatures in NYC for an entire year (2014).
#What if we wanted to plot the temperatures over time? We could plot it using base R like so:

plot(temps$day, temps$actual_mean_temp)


#for all plots, the syntax is usually (x = , y = ) - we'll put time (days) on the horizontal axis, and temperatures on the vertical axis. Putting the time variable on the x-axis is pretty standard. 

This plot isn’t bad, but it isn’t very nice looking either. The ggplot2 package gives us so much flexibility to customize our plots - we’ll make a much nicer version of this soon. Before we get to that, we first need to learn a bit about the syntax of ggplot2.

#Let's look at the first line of a basic ggplot graph:

ggplot(temps, aes(x = day, y = actual_mean_temp))


#When you use the ggplot() command, you need to supply a few key arguments. The first is the dataset - in this case, we will be using the temps data (as shown). The next part, called the aesthetic mapping or aes of the plot, tells us what we will be plotting from the dataset. Later, we will also include some characteristics of the plot in the aes() section. Can we plot the graph now? Not just yet! We need to add a geom layer - the geom layer tells ggplot2 what kind of visualization to produce with the data. We use a + sign to indicate a new layer in the plot like this (here I'm using geom_point to tell ggplot2 to draw a scatter plot):

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point()

#One of the nice things about ggplot2 is its flexibility. We can easily customize the plot. Once you get used to the syntax of ggplot2, customization is very simple. For example, let's start by changing the color of the points:

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point(color = "mediumpurple")

There’s a few important things to point out about the code above. I have put the color = argument in the geom_point layer. This tells R to use the color blue for the points - when we create more complex graphs, being able to customize each geom layer individually becomes really important. Second, the color that I choose comes next in quotation marks. What happens if we leave them out?

blue <- "blue"

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point(color = blue)

As you can see, without the quotes, R thinks that we are using an object call blue to set the color of the graph! You could actually do that, like this:

blue <- "blue"

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point(color = blue)

Being able to set the color scheme of a graph using an object is much more useful when you are working with a color palette (that is, when you need to use multiple colors to symbolize a graph). We will see an example like that soon. Let’s look at some other customization features!

#What if we want to add labels to our plot? This is very easy to do with the labs argument, like so (remember that the x-axis is the horizontal axis, while the y-axis is the verticle axis):

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point(color = "blue") +
  labs(y = "Mean Temperature", x = "Day")

#This is starting to look pretty nice! What if we wanted to add a title too?

ggplot(temps, aes(x = day, y = actual_mean_temp)) +
  geom_point(color = "blue") +
  labs(y = "Mean Temperature", x = "Day", 
       title = "Mean Daily Temperature in New York City, 2014")


#You'll notice that I like to put each new argument after a "+" on a new line - you don't have to do this, but I prefer to because it makes my code much easier to follow. I also like to put longer label names on a new line - again, this won't affect how the code runs, it just makes it more readable. 
#But what if we wanted to also graph the minimum and maximum temperatures on the same plot? this is also very easy to do! We just need to use a geom_point layer for each variable we want to plot. 

#here we start by telling R that we want to use the temps data for our plot
ggplot(temps) +
  #for each new geom_point layer, I need to include a new aesthetic mapping
  #this tells R which variable to use in the plot
  geom_point(aes(x = day, y = actual_mean_temp), color = "gray") +
  geom_point(aes(x = day, y = actual_min_temp), color = "blue") +
  geom_point(aes(x = day, y = actual_max_temp), color = "red") +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014")


#Notice here that the color arguments are outside of the aes() argument. This is intentional - only arguments that depend on variables in the dataset should be in the aes() argument. What does that mean? In this case, the color "gray" doesn't depend on anything in the data - for example, the color doesn't change for lower or higher values. The entire geom_point layer is just gray. If we had a variable called "color" in the dataset, or if we wanted the colors to change based on temperature values, we could put color inside the aes(). I'll show an example next.
ggplot(temps) +
  geom_point(aes(x = day, y = actual_mean_temp, color = actual_mean_temp)) +
  labs(y = "Mean Temperature", x = "Day", 
       title = "Mean Daily Temperature in New York City, 2014",
       color = "Mean Temperature (F)")

Hopefully that makes sense now! So, the graph of multiple variables looks pretty nice! But, there no legend on our graph! How will people know what each color represents? This is a somewhat annoying limitation of ggplot2, and it’s a problem that you’ll come across somewhat frequently. There are two ways to fix it: first, we can add a legend manually. I’ll show you how to do that first. Second, we can reshape the data - this is a somewhat more complicated method, but it ends up being extremely useful when you have more than a few variables to graph. I’ll explain that method second.


#We'll first manually set the colors in the legend using scale_color_manual.For some reason, if you set the colors all at once, R will generate a legend; if you set each color individually in the geom_point layer, it won't. I don't make the rules, I just follow them! When you set the colors manually, you have to tell R what label you'd like to use for each geom layer. Here, I've set the label names using color = "" inside the aesthetic mapping in the geom layer. 

ggplot(temps) +
  geom_point(aes(x = day, y = actual_mean_temp, color = "Mean")) +
  geom_point(aes(x = day, y = actual_min_temp, color = "Min")) +
  geom_point(aes(x = day, y = actual_max_temp, color = "Max")) +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       #since the legend is based on the color mapping, use color = to set the legend title
       color = "Temperature Values")+
  scale_color_manual(labels = c("Mean", "Min", "Max"), values = c("gray", "blue", "red"))


#In scale_color_manual, we start by telling R which labels to use to generate the color scheme; in this case, it's the same labels we just set above. Then, we have to tell R which colors to use for each label. Because there are three color values to set, note that we have to use c() around the list of variable names and colors. 

#Scale_color_manual often involves some guessing and checking with the order of the colors - for some reason, R wanted to use the first color for the max temperature, the second for the mean, and the third for the min. This order makes no sense, but it is also not easy to change. If you notice that the colors in your graph don't match up, the easiest fix is to just change the order that you listed the colors and variable names so that it matches R's default ordering. That's what I did below. 
#Here's the correct plot!
ggplot(temps) +
  geom_point(aes(x = day, y = actual_mean_temp, color = "Mean")) +
  geom_point(aes(x = day, y = actual_min_temp, color = "Min")) +
  geom_point(aes(x = day, y = actual_max_temp, color = "Max")) +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature Values")+
  scale_color_manual(labels = c("Max", "Mean", "Min"), values = c("red", "gray", "blue"))

Doesn’t that look nice? Let’s talk about reshaping your data now. This is a very helpful skill to have, and you will find yourself having to reshape data frequently.So right now, each variable has its own column in the dataframe in our case, we’re working with four columns of data. Since three of the variables are temperature data, wouldn’t it make sense to put them all in one column instead? This is what we call transforming data from wide to long format - wide data has more columns, while long data will usually have more rows instead. Here’s a diagram of what it looks like to transform from long to wide: https://i.stack.imgur.com/i1Dne.jpg. You can look at this diagram later if you’re confused about what wide and long format look like. For whatever reason, the ggplot2 package tends to work better with long data. We’ll reshape the data using a command from the tidyr package, pivot_longer.

wide_data <- temps %>% 
  #we'll only select the variables of interest to do this
  select(c(day, actual_mean_temp, actual_min_temp, actual_max_temp))

#let's change the column names to make them a bit nicer:
#I'll show you why this matters soon. 
colnames(wide_data) <- c("Day", "Mean", "Min", "Max")

head(wide_data)
#Now we'll reshape it!

long_data <- wide_data %>% 
  #The column titles become the categories in a new column after the reshaping
  #I'm naming this new column temp_type
  #The temperature values are put in a new values column, which I'm calling temp
  pivot_longer(!Day, names_to = "temp_type", values_to = "temp")

head(long_data)
#What if I wanted to go from long to wide data? Here's what that looks like, for your reference:

wide_data1 <- long_data %>% 
  pivot_wider(names_from = temp_type, values_from = temp)

#Run this code to verify that the original wide_data and our new wide_data1 dataframe are the same. Logical data is helpful in this case!
#I'm setting the number of values that R prints out to 20 - otherwise, R would print the whole dataset on the screen, and it would take up a lot of space!
options(max.print = 20)
wide_data1 == wide_data
        Day Mean  Min  Max
  [1,] TRUE TRUE TRUE TRUE
  [2,] TRUE TRUE TRUE TRUE
  [3,] TRUE TRUE TRUE TRUE
  [4,] TRUE TRUE TRUE TRUE
  [5,] TRUE TRUE TRUE TRUE
 [ reached getOption("max.print") -- omitted 360 rows ]

Do you see the difference? Now, the category (temp_type, or mean, min, and max) is in one column, while each temperature that corresponds to the temp_type and day is in the temp column. The wide and long data sets are just different ways of storing the same data! Now let’s see how this works in ggplot2.


#Now, instead of three geom layers, we will need to plot the data by three groups: mean, min, and max. Because we are grouping the data in the dataframe by the type of temperature recorded, we need to assign the temp_type column to the group argument. Because each type of temperature will also have a different color, we will assign temp_type to the color argument as well. Let's see what this looks like!

ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_point() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")

Do you see why I changed the column names? R uses the categories in the temp_type column to add names to the legend. Keeping the “actual_mean_temp” (and so on) labels would not have been nearly as clear in a legend. In our graphs, we should aim to show complex information in the simplest way possible - having clear legend and axis titles is key to that. Now, in this case, the colors aren’t quite right! Let’s set them manually.

#create the color palette for the data
#Remember, order matters! Based on the order of the legend in the last graph, I will include the color for the max temp, then the mean, then the min. 

colors <- c("red", "gray", "blue")

ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_point() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = colors)

Do you see how much simpler and shorter the ggplot2 code is now? Reshaping data definitely takes some getting used to, but it’ll save you time in the future. Before we move on, I’ll show you one more way to set the colors, now that we have the data in long format. This third version will introduce you to a function that is helpful within dplyr functions, ifelse.

#This version involves creating a new column in the long dataframe with the color values in it. Each color will correspond to the correct temp_type. 
library(dplyr)
library(tidyr)
long_data <- long_data %>% 
  mutate(colors = ifelse(temp_type == "Max", "red",
                         ifelse(temp_type == "Mean", "gray", "blue")))

#Let's walk through the syntax of the ifelse function (note that it stand for "if else")
#You can read the code like this: if temp_type is equal to Max, set the value to red
#if temp type is equal to Mean, set the color to gray. 
#For all others, set the color to blue. 
#If you look up the documentation to ifelse, you'll see just how simple it is:
#ifelse(test, yes, no)
#you give the function the test, and set a value to correspond to yes (True) and no (False) answers. In this code, I have nested an ifelse function inside of another one, basically telling R that no or false values based on the first call to ifelse are subject to another ifelse statement. Values that are no or false in both calls ot ifelse will be blue (note that these are the minimum values).
#Let's graph this!

ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = colors)) +
  geom_point() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_identity(guide = "legend", labels = c("Min", "Mean", "Max"))


#If you want to use this method, you need to also include the scale_color_identity argument - this tells R to use colors from the data. I also had to specify the legend label names using the labels = argument - again, R is weird about variable order, and I had to include the label names in the same order that R uses in the legend. For whatever reason, this order is a bit random.

Overall, the second method of adding color for multiple variables (reshaping the data and using a color palette object to set colors) is probably the most flexible method. Often, you’ll be able to set palettes using functions, which makes the process even faster; it’s unlikely that you’ll need to manually specify colors. In the next chunk of code, I’ll give an example using a package that contains some really nice color palettes inspired by US national parks. More info on the palettes are here: https://github.com/katiejolly/nationalparkcolors. You can use the code from the github link to install the package, too. Other packages, like RColorBrewer, also provide a range of palettes to choose from.

#I already have this installed - I like using these colors for presentations. 
install.packages("devtools")
Error in install.packages : Updating loaded packages
devtools::install_github("katiejolly/nationalparkcolors")
Downloading GitHub repo katiejolly/nationalparkcolors@HEAD
  
  
  
✔  checking for file 'C:\Users\mhaller\AppData\Local\Temp\Rtmp2zRIXl\remotes32501e6e783c\katiejolly-nationalparkcolors-df8cd15/DESCRIPTION'

  
  
  
─  preparing 'nationalparkcolors':
✔  checking DESCRIPTION meta-information

  
  
  
─  checking for LF line-endings in source and make files and shell scripts
─  checking for empty or unneeded directories
   Omitted 'LazyData' from DESCRIPTION

  
─  building 'nationalparkcolors_0.1.0.tar.gz'

  
   
Installing package into ‘C:/Users/mhaller/AppData/Local/R/win-library/4.2’
(as ‘lib’ is unspecified)
* installing *source* package 'nationalparkcolors' ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
*** copying figures
** building package indices
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (nationalparkcolors)
install.packages("devtools")
Installing package into ‘C:/Users/mhaller/AppData/Local/R/win-library/4.2’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.2/devtools_2.4.4.zip'
Content type 'application/zip' length 429292 bytes (419 KB)
downloaded 419 KB
package ‘devtools’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\mhaller\AppData\Local\Temp\Rtmp2zRIXl\downloaded_packages
library(nationalparkcolors)

#I've just picked a random palette, these colors aren't meaningful. 
palette <- park_palette("SmokyMountains", n = 3)

library(ggplot2)
#Now graph it with the palette!
ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_point() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette)

So now you know the basics of graphing with ggplot2! There are just a few more topics to cover that you will find helpful. First, what if I don’t want to use a scatter plot? Ggplot2 comes with a wide range of geom possibilities! It’s so easy to produce different kinds of plots of your data. Let’s make a line plot with the data we already have.


ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_line() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette)

The line plot doesn’t look nice and smooth because we’re working with daily data - there are a lot of data points, and the temperatures move around a lot! But as you can see, switching to a line plot was so easy. Next, we can look at a bar plot. Line plots, scatter plots, and bar plots will be the most common plots you’ll use.

#Remember that bar plots don't require x and y variables - we just need one y variable (in this case, temperature) and categories for the x-axis (in this case, temp_type). Let's make a simple bar plot for one day:

day1 <- long_data %>% filter(Day == 1)

ggplot(day1, aes(y = temp, x = temp_type, group = temp_type, fill = temp_type))+
  geom_bar(stat = "Identity")+
  labs(x = "Temperature Type", y = "Temperature",
       title = "Temperatures in One Day in NYC") +
  theme(legend.position="none")+
  scale_fill_manual(values = palette)


#Some things to note about this code: because I have included the categories as x-values, I need to include the argument stat = "Identity" in the geom_bar layer. Without going into too much detail, this argument tells R that the height of the columns should be equal to the temp values. Note also that instead of color, we use the fill= argument here - the color argument is for lines and points, while solid polygons need to be assigned colors using the fill argument. As an exercise, try seeing what happens when you use color = instead! When you use fill, the scale_color_manual argument also changes to scale_fill_manual to set the color palette. Finally, R will automatically generate a legend when you assign colors using the group aesthetic - I didn't need a legend in this graph, so I used the theme() argument to set the legend position to "none". This deletes the legend from the plot, and is worth remembering. 

Let’s think about some other ways you can customize your plots. One way that we can make our plot look nice is by adding a visual theme. There are a number of themes you can add to your plot - we’ll download a new package now that contains some additional themes as well.

library(ggthemes)

#I prefer the minimal theme that comes loaded with ggplot2 - it makes plots look very sleek 
ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_line() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette) +
  theme_minimal()

#The ggthemes package comes with some other useful themes. Let's try a few more:
#If you want your plot to look like the plots in the Economist magazine, you might use this theme:

ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_line() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette)+
  theme_economist()


#This theme mimics plots drawn by the Wall Street Journal:
ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_line() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette)+
  theme_wsj()

If you type theme_ you should get a drop down menu of all of the possible themes to choose from - I would encourage you to play around with them, and see which one you like best!

#Finally, you can use the theme function to change the centering of the title and other text. By the default, everything is left-aligned. 

ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_line() +
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette) +
  theme_minimal()+
  theme(plot.title = element_text(hjust = 0.5))


#Note that the element_text(hjust = 0.5) argument is telling R to center-align the title text
#You can play around with the hjust argument to manually change the title position (although I don't really see any reason to do this)

Finally, can you use more than one plot type in the same plot? You sure can! The code below shows what this looks like by adding a trend line to the data using a smoothing method (don’t worry about how it works, this is just an example). In this example, because we are using the smoothing function to find the average values of each temperature type, we don’t need to change the aesthetics. If, for example, you wanted to make a line graph with one variable over time and a point graph with a different variable over time, you would need to manually include the aesthetics in each geom layer (like we did the first time we added color - in that example, each variable had its own geom layer, and we had to map the aesthetics for each one).


ggplot(long_data, aes(x = Day, y = temp, group = temp_type, color = temp_type)) +
  geom_point() +
  geom_smooth(color = "black")+
  labs(y = "Temperature", x = "Day", 
       title = "Daily Temperature in New York City, 2014",
       color = "Temperature (F)")+
  scale_color_manual(values = palette) +
  theme_minimal()+
  theme(plot.title = element_text(hjust = 0.5))

And there you have it! You are now a pro at using ggplot2. You should have all the tools you need to make beautiful and effective visualization in R. If you want more information on different types of graphs, or you just want a helpful reference to refer to as you progress through the course, you can find an excellent ggplot2 cheat sheet here: https://www.maths.usyd.edu.au/u/UG/SM/STAT3022/r/current/Misc/data-visualization-2.1.pdf.

Resources

FiveThirtyEight (2014). US. Weather History. [Data Set]. Retrieved from: https://github.com/fivethirtyeight/data/tree/master/us-weather-history.

Prabhakaran, S. (2017). The Complete ggplot2 Tutorial - Part1 | Introduction To ggplot2. Retrieved from: http://r-statistics.co/Complete-Ggplot2-Tutorial-Part1-With-R-Code.html.

LS0tDQp0aXRsZTogIldlZWsgMyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KDQotLS0NClRvZGF5IHdlIGFyZSBnb2luZyB0byBsZWFybiBob3cgdG8gcGxvdCBkYXRhIGluIFIhIFdoaWxlIHRoZXJlIGFyZSBzb21lIHNpbXBsZSBwbG90dGluZyBmdW5jdGlvbnMgYnVpbHQgaW50byBiYXNlIFIgKHlvdSB3aWxsIG9mdGVuIHNlZSB0dXRvcmlhbHMgdGhhdCB1c2UgdGhlIHBsb3QoKSBjb21tYW5kKSwgSSBlbmNvdXJhZ2UgeW91IHRvIHByb2R1Y2UgeW91ciBwbG90cyBhbmQgZGF0YSB2aXN1YWxpemF0aW9ucyB1aXNuZyB0aGUgZ2dwbG90MiBwYWNrYWdlIGluIFIuIFRoaXMgcGFja2FnZSB0YWtlcyBhIGxpdHRsZSBnZXR0aW5nIHVzZWQgdG8sIGJ1dCBvbmNlIHlvdSB1bmRlcnN0YW5kIHRoZSBzeW50YXggeW91IHdpbGwgYmUgbWFraW5nIGVmZmVjdGl2ZSBncmFwaHMgYW5kIHZpc3VhbGl6YXRpb25zIGluIG5vIHRpbWUhIFZpc3VhbGl6aW5nIGRhdGEgaXMgc3VjaCBhbiBpbXBvcnRhbnQgcGFydCBvZiB0aGUgZGF0YSBhbmFseXNpcyBwcm9jZXNzOiBpdCBoZWxwcyB1cyB0byBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgZGF0YSBhbmQgaXRzIGRpc3RyaWJ1dGlvbiwgaXQgYWxsb3dzIHVzIHRvIGlkZW50aWZ5IGFuZCBjb21tdW5pY2F0ZSBwYXR0ZXJucyBpbiBzaW1wbGUgYW5kIHZpc3VhbGx5IGFwcGVhbGluZyB3YXlzLCBhbmQgaXQgZW5hYmxlcyB1cyB0byBjb25kZW5zZSBhIGxhcmdlIGFtb3VudCBvZiB0ZWNobmljYWwgaW5mb3JtYXRpb24gaW50byBhIGRpYWdyYW0gb3IgdmlzdWFsLiANCg0KDQpgYGB7cn0NCg0KI01ha2Ugc3VyZSB5b3UgZG93bmxvYWQgZ2dwbG90MiBmaXJzdCEgTGV0J3MgbG9hZCBpbiBwYWNrYWdlIGFuZCBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5Lg0Kc2V0d2QoIn4vQmluZ2hhbXRvbi9oYXJwMTMwIikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojd2UnbGwgc3RhcnQgYnkgbG9hZGluZyBpbiBzb21lIGRhdGEgdG8gcGxheSB3aXRoISBXZSdsbCB1c2UgTllDIHRlbXBlcmF0dXJlIGRhdGEgZm9yIHRoaXMgdHV0b3JpYWwuIA0KDQp0ZW1wcyA8LSByZWFkLmNzdigidGVtcHNfbnljLmNzdiIpDQoNCiNUYWtlIGEgbG9vayBhdCB0aGlzIGRhdGFzZXQhIEl0IGNvbnRhaW5zIG1lYW4sIG1pbiwgYW5kIG1heCB0ZW1wZXJhdHVyZXMgaW4gTllDIGZvciBhbiBlbnRpcmUgeWVhciAoMjAxNCkuDQojV2hhdCBpZiB3ZSB3YW50ZWQgdG8gcGxvdCB0aGUgdGVtcGVyYXR1cmVzIG92ZXIgdGltZT8gV2UgY291bGQgcGxvdCBpdCB1c2luZyBiYXNlIFIgbGlrZSBzbzoNCg0KcGxvdCh0ZW1wcyRkYXksIHRlbXBzJGFjdHVhbF9tZWFuX3RlbXApDQoNCiNmb3IgYWxsIHBsb3RzLCB0aGUgc3ludGF4IGlzIHVzdWFsbHkgKHggPSAsIHkgPSApIC0gd2UnbGwgcHV0IHRpbWUgKGRheXMpIG9uIHRoZSBob3Jpem9udGFsIGF4aXMsIGFuZCB0ZW1wZXJhdHVyZXMgb24gdGhlIHZlcnRpY2FsIGF4aXMuIFB1dHRpbmcgdGhlIHRpbWUgdmFyaWFibGUgb24gdGhlIHgtYXhpcyBpcyBwcmV0dHkgc3RhbmRhcmQuIA0KYGBgDQpUaGlzIHBsb3QgaXNuJ3QgYmFkLCBidXQgaXQgaXNuJ3QgdmVyeSBuaWNlIGxvb2tpbmcgZWl0aGVyLiBUaGUgZ2dwbG90MiBwYWNrYWdlIGdpdmVzIHVzIHNvIG11Y2ggZmxleGliaWxpdHkgdG8gY3VzdG9taXplIG91ciBwbG90cyAtIHdlJ2xsIG1ha2UgYSBtdWNoIG5pY2VyIHZlcnNpb24gb2YgdGhpcyBzb29uLiBCZWZvcmUgd2UgZ2V0IHRvIHRoYXQsIHdlIGZpcnN0IG5lZWQgdG8gbGVhcm4gYSBiaXQgYWJvdXQgdGhlIHN5bnRheCBvZiBnZ3Bsb3QyLiANCg0KYGBge3J9DQojTGV0J3MgbG9vayBhdCB0aGUgZmlyc3QgbGluZSBvZiBhIGJhc2ljIGdncGxvdCBncmFwaDoNCg0KZ2dwbG90KHRlbXBzLCBhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9tZWFuX3RlbXApKQ0KDQojV2hlbiB5b3UgdXNlIHRoZSBnZ3Bsb3QoKSBjb21tYW5kLCB5b3UgbmVlZCB0byBzdXBwbHkgYSBmZXcga2V5IGFyZ3VtZW50cy4gVGhlIGZpcnN0IGlzIHRoZSBkYXRhc2V0IC0gaW4gdGhpcyBjYXNlLCB3ZSB3aWxsIGJlIHVzaW5nIHRoZSB0ZW1wcyBkYXRhIChhcyBzaG93bikuIFRoZSBuZXh0IHBhcnQsIGNhbGxlZCB0aGUgYWVzdGhldGljIG1hcHBpbmcgb3IgYWVzIG9mIHRoZSBwbG90LCB0ZWxscyB1cyB3aGF0IHdlIHdpbGwgYmUgcGxvdHRpbmcgZnJvbSB0aGUgZGF0YXNldC4gTGF0ZXIsIHdlIHdpbGwgYWxzbyBpbmNsdWRlIHNvbWUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBwbG90IGluIHRoZSBhZXMoKSBzZWN0aW9uLiBDYW4gd2UgcGxvdCB0aGUgZ3JhcGggbm93PyBOb3QganVzdCB5ZXQhIFdlIG5lZWQgdG8gYWRkIGEgZ2VvbSBsYXllciAtIHRoZSBnZW9tIGxheWVyIHRlbGxzIGdncGxvdDIgd2hhdCBraW5kIG9mIHZpc3VhbGl6YXRpb24gdG8gcHJvZHVjZSB3aXRoIHRoZSBkYXRhLiBXZSB1c2UgYSArIHNpZ24gdG8gaW5kaWNhdGUgYSBuZXcgbGF5ZXIgaW4gdGhlIHBsb3QgbGlrZSB0aGlzIChoZXJlIEknbSB1c2luZyBnZW9tX3BvaW50IHRvIHRlbGwgZ2dwbG90MiB0byBkcmF3IGEgc2NhdHRlciBwbG90KToNCg0KZ2dwbG90KHRlbXBzLCBhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9tZWFuX3RlbXApKSArDQogIGdlb21fcG9pbnQoKQ0KYGBgDQpgYGB7cn0NCiNPbmUgb2YgdGhlIG5pY2UgdGhpbmdzIGFib3V0IGdncGxvdDIgaXMgaXRzIGZsZXhpYmlsaXR5LiBXZSBjYW4gZWFzaWx5IGN1c3RvbWl6ZSB0aGUgcGxvdC4gT25jZSB5b3UgZ2V0IHVzZWQgdG8gdGhlIHN5bnRheCBvZiBnZ3Bsb3QyLCBjdXN0b21pemF0aW9uIGlzIHZlcnkgc2ltcGxlLiBGb3IgZXhhbXBsZSwgbGV0J3Mgc3RhcnQgYnkgY2hhbmdpbmcgdGhlIGNvbG9yIG9mIHRoZSBwb2ludHM6DQoNCmdncGxvdCh0ZW1wcywgYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWVhbl90ZW1wKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gIm1lZGl1bXB1cnBsZSIpDQpgYGANClRoZXJlJ3MgYSBmZXcgaW1wb3J0YW50IHRoaW5ncyB0byBwb2ludCBvdXQgYWJvdXQgdGhlIGNvZGUgYWJvdmUuIEkgaGF2ZSBwdXQgdGhlIGNvbG9yID0gYXJndW1lbnQgaW4gdGhlIGdlb21fcG9pbnQgbGF5ZXIuIFRoaXMgdGVsbHMgUiB0byB1c2UgdGhlIGNvbG9yIGJsdWUgZm9yIHRoZSBwb2ludHMgLSB3aGVuIHdlIGNyZWF0ZSBtb3JlIGNvbXBsZXggZ3JhcGhzLCBiZWluZyBhYmxlIHRvIGN1c3RvbWl6ZSBlYWNoIGdlb20gbGF5ZXIgaW5kaXZpZHVhbGx5IGJlY29tZXMgcmVhbGx5IGltcG9ydGFudC4gU2Vjb25kLCB0aGUgY29sb3IgdGhhdCBJIGNob29zZSBjb21lcyBuZXh0IGluIHF1b3RhdGlvbiBtYXJrcy4gV2hhdCBoYXBwZW5zIGlmIHdlIGxlYXZlIHRoZW0gb3V0Pw0KDQpgYGB7cn0NCmJsdWUgPC0gImJsdWUiDQoNCmdncGxvdCh0ZW1wcywgYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWVhbl90ZW1wKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gYmx1ZSkNCg0KYGBgDQpBcyB5b3UgY2FuIHNlZSwgd2l0aG91dCB0aGUgcXVvdGVzLCBSIHRoaW5rcyB0aGF0IHdlIGFyZSB1c2luZyBhbiBvYmplY3QgY2FsbCBibHVlIHRvIHNldCB0aGUgY29sb3Igb2YgdGhlIGdyYXBoISBZb3UgY291bGQgYWN0dWFsbHkgZG8gdGhhdCwgbGlrZSB0aGlzOg0KDQpgYGB7cn0NCmJsdWUgPC0gImJsdWUiDQoNCmdncGxvdCh0ZW1wcywgYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWVhbl90ZW1wKSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gYmx1ZSkNCmBgYA0KQmVpbmcgYWJsZSB0byBzZXQgdGhlIGNvbG9yIHNjaGVtZSBvZiBhIGdyYXBoIHVzaW5nIGFuIG9iamVjdCBpcyBtdWNoIG1vcmUgdXNlZnVsIHdoZW4geW91IGFyZSB3b3JraW5nIHdpdGggYSBjb2xvciBwYWxldHRlICh0aGF0IGlzLCB3aGVuIHlvdSBuZWVkIHRvIHVzZSBtdWx0aXBsZSBjb2xvcnMgdG8gc3ltYm9saXplIGEgZ3JhcGgpLiBXZSB3aWxsIHNlZSBhbiBleGFtcGxlIGxpa2UgdGhhdCBzb29uLiBMZXQncyBsb29rIGF0IHNvbWUgb3RoZXIgY3VzdG9taXphdGlvbiBmZWF0dXJlcyENCg0KYGBge3J9DQojV2hhdCBpZiB3ZSB3YW50IHRvIGFkZCBsYWJlbHMgdG8gb3VyIHBsb3Q/IFRoaXMgaXMgdmVyeSBlYXN5IHRvIGRvIHdpdGggdGhlIGxhYnMgYXJndW1lbnQsIGxpa2Ugc28gKHJlbWVtYmVyIHRoYXQgdGhlIHgtYXhpcyBpcyB0aGUgaG9yaXpvbnRhbCBheGlzLCB3aGlsZSB0aGUgeS1heGlzIGlzIHRoZSB2ZXJ0aWNsZSBheGlzKToNCg0KZ2dwbG90KHRlbXBzLCBhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9tZWFuX3RlbXApKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiYmx1ZSIpICsNCiAgbGFicyh5ID0gIk1lYW4gVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIpDQpgYGANCmBgYHtyfQ0KI1RoaXMgaXMgc3RhcnRpbmcgdG8gbG9vayBwcmV0dHkgbmljZSEgV2hhdCBpZiB3ZSB3YW50ZWQgdG8gYWRkIGEgdGl0bGUgdG9vPw0KDQpnZ3Bsb3QodGVtcHMsIGFlcyh4ID0gZGF5LCB5ID0gYWN0dWFsX21lYW5fdGVtcCkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIikgKw0KICBsYWJzKHkgPSAiTWVhbiBUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiTWVhbiBEYWlseSBUZW1wZXJhdHVyZSBpbiBOZXcgWW9yayBDaXR5LCAyMDE0IikNCg0KI1lvdSdsbCBub3RpY2UgdGhhdCBJIGxpa2UgdG8gcHV0IGVhY2ggbmV3IGFyZ3VtZW50IGFmdGVyIGEgIisiIG9uIGEgbmV3IGxpbmUgLSB5b3UgZG9uJ3QgaGF2ZSB0byBkbyB0aGlzLCBidXQgSSBwcmVmZXIgdG8gYmVjYXVzZSBpdCBtYWtlcyBteSBjb2RlIG11Y2ggZWFzaWVyIHRvIGZvbGxvdy4gSSBhbHNvIGxpa2UgdG8gcHV0IGxvbmdlciBsYWJlbCBuYW1lcyBvbiBhIG5ldyBsaW5lIC0gYWdhaW4sIHRoaXMgd29uJ3QgYWZmZWN0IGhvdyB0aGUgY29kZSBydW5zLCBpdCBqdXN0IG1ha2VzIGl0IG1vcmUgcmVhZGFibGUuIA0KDQpgYGANCmBgYHtyfQ0KI0J1dCB3aGF0IGlmIHdlIHdhbnRlZCB0byBhbHNvIGdyYXBoIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHRlbXBlcmF0dXJlcyBvbiB0aGUgc2FtZSBwbG90PyB0aGlzIGlzIGFsc28gdmVyeSBlYXN5IHRvIGRvISBXZSBqdXN0IG5lZWQgdG8gdXNlIGEgZ2VvbV9wb2ludCBsYXllciBmb3IgZWFjaCB2YXJpYWJsZSB3ZSB3YW50IHRvIHBsb3QuIA0KDQojaGVyZSB3ZSBzdGFydCBieSB0ZWxsaW5nIFIgdGhhdCB3ZSB3YW50IHRvIHVzZSB0aGUgdGVtcHMgZGF0YSBmb3Igb3VyIHBsb3QNCmdncGxvdCh0ZW1wcykgKw0KICAjZm9yIGVhY2ggbmV3IGdlb21fcG9pbnQgbGF5ZXIsIEkgbmVlZCB0byBpbmNsdWRlIGEgbmV3IGFlc3RoZXRpYyBtYXBwaW5nDQogICN0aGlzIHRlbGxzIFIgd2hpY2ggdmFyaWFibGUgdG8gdXNlIGluIHRoZSBwbG90DQogIGdlb21fcG9pbnQoYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWVhbl90ZW1wKSwgY29sb3IgPSAiZ3JheSIpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9taW5fdGVtcCksIGNvbG9yID0gImJsdWUiKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWF4X3RlbXApLCBjb2xvciA9ICJyZWQiKSArDQogIGxhYnMoeSA9ICJUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiRGFpbHkgVGVtcGVyYXR1cmUgaW4gTmV3IFlvcmsgQ2l0eSwgMjAxNCIpDQoNCiNOb3RpY2UgaGVyZSB0aGF0IHRoZSBjb2xvciBhcmd1bWVudHMgYXJlIG91dHNpZGUgb2YgdGhlIGFlcygpIGFyZ3VtZW50LiBUaGlzIGlzIGludGVudGlvbmFsIC0gb25seSBhcmd1bWVudHMgdGhhdCBkZXBlbmQgb24gdmFyaWFibGVzIGluIHRoZSBkYXRhc2V0IHNob3VsZCBiZSBpbiB0aGUgYWVzKCkgYXJndW1lbnQuIFdoYXQgZG9lcyB0aGF0IG1lYW4/IEluIHRoaXMgY2FzZSwgdGhlIGNvbG9yICJncmF5IiBkb2Vzbid0IGRlcGVuZCBvbiBhbnl0aGluZyBpbiB0aGUgZGF0YSAtIGZvciBleGFtcGxlLCB0aGUgY29sb3IgZG9lc24ndCBjaGFuZ2UgZm9yIGxvd2VyIG9yIGhpZ2hlciB2YWx1ZXMuIFRoZSBlbnRpcmUgZ2VvbV9wb2ludCBsYXllciBpcyBqdXN0IGdyYXkuIElmIHdlIGhhZCBhIHZhcmlhYmxlIGNhbGxlZCAiY29sb3IiIGluIHRoZSBkYXRhc2V0LCBvciBpZiB3ZSB3YW50ZWQgdGhlIGNvbG9ycyB0byBjaGFuZ2UgYmFzZWQgb24gdGVtcGVyYXR1cmUgdmFsdWVzLCB3ZSBjb3VsZCBwdXQgY29sb3IgaW5zaWRlIHRoZSBhZXMoKS4gSSdsbCBzaG93IGFuIGV4YW1wbGUgbmV4dC4NCg0KYGBgDQpgYGB7cn0NCmdncGxvdCh0ZW1wcykgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gZGF5LCB5ID0gYWN0dWFsX21lYW5fdGVtcCwgY29sb3IgPSBhY3R1YWxfbWVhbl90ZW1wKSkgKw0KICBsYWJzKHkgPSAiTWVhbiBUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiTWVhbiBEYWlseSBUZW1wZXJhdHVyZSBpbiBOZXcgWW9yayBDaXR5LCAyMDE0IiwNCiAgICAgICBjb2xvciA9ICJNZWFuIFRlbXBlcmF0dXJlIChGKSIpDQpgYGANCg0KSG9wZWZ1bGx5IHRoYXQgbWFrZXMgc2Vuc2Ugbm93ISBTbywgdGhlIGdyYXBoIG9mIG11bHRpcGxlIHZhcmlhYmxlcyBsb29rcyBwcmV0dHkgbmljZSEgQnV0LCB0aGVyZSBubyBsZWdlbmQgb24gb3VyIGdyYXBoISBIb3cgd2lsbCBwZW9wbGUga25vdyB3aGF0IGVhY2ggY29sb3IgcmVwcmVzZW50cz8gVGhpcyBpcyBhIHNvbWV3aGF0IGFubm95aW5nIGxpbWl0YXRpb24gb2YgZ2dwbG90MiwgYW5kIGl0J3MgYSBwcm9ibGVtIHRoYXQgeW91J2xsIGNvbWUgYWNyb3NzIHNvbWV3aGF0IGZyZXF1ZW50bHkuIFRoZXJlIGFyZSB0d28gd2F5cyB0byBmaXggaXQ6IGZpcnN0LCB3ZSBjYW4gYWRkIGEgbGVnZW5kIG1hbnVhbGx5LiBJJ2xsIHNob3cgeW91IGhvdyB0byBkbyB0aGF0IGZpcnN0LiBTZWNvbmQsIHdlIGNhbiByZXNoYXBlIHRoZSBkYXRhIC0gdGhpcyBpcyBhIHNvbWV3aGF0IG1vcmUgY29tcGxpY2F0ZWQgbWV0aG9kLCBidXQgaXQgZW5kcyB1cCBiZWluZyBleHRyZW1lbHkgdXNlZnVsIHdoZW4geW91IGhhdmUgbW9yZSB0aGFuIGEgZmV3IHZhcmlhYmxlcyB0byBncmFwaC4gSSdsbCBleHBsYWluIHRoYXQgbWV0aG9kIHNlY29uZC4gDQoNCmBgYHtyfQ0KDQojV2UnbGwgZmlyc3QgbWFudWFsbHkgc2V0IHRoZSBjb2xvcnMgaW4gdGhlIGxlZ2VuZCB1c2luZyBzY2FsZV9jb2xvcl9tYW51YWwuRm9yIHNvbWUgcmVhc29uLCBpZiB5b3Ugc2V0IHRoZSBjb2xvcnMgYWxsIGF0IG9uY2UsIFIgd2lsbCBnZW5lcmF0ZSBhIGxlZ2VuZDsgaWYgeW91IHNldCBlYWNoIGNvbG9yIGluZGl2aWR1YWxseSBpbiB0aGUgZ2VvbV9wb2ludCBsYXllciwgaXQgd29uJ3QuIEkgZG9uJ3QgbWFrZSB0aGUgcnVsZXMsIEkganVzdCBmb2xsb3cgdGhlbSEgV2hlbiB5b3Ugc2V0IHRoZSBjb2xvcnMgbWFudWFsbHksIHlvdSBoYXZlIHRvIHRlbGwgUiB3aGF0IGxhYmVsIHlvdSdkIGxpa2UgdG8gdXNlIGZvciBlYWNoIGdlb20gbGF5ZXIuIEhlcmUsIEkndmUgc2V0IHRoZSBsYWJlbCBuYW1lcyB1c2luZyBjb2xvciA9ICIiIGluc2lkZSB0aGUgYWVzdGhldGljIG1hcHBpbmcgaW4gdGhlIGdlb20gbGF5ZXIuIA0KDQpnZ3Bsb3QodGVtcHMpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9tZWFuX3RlbXAsIGNvbG9yID0gIk1lYW4iKSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gZGF5LCB5ID0gYWN0dWFsX21pbl90ZW1wLCBjb2xvciA9ICJNaW4iKSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gZGF5LCB5ID0gYWN0dWFsX21heF90ZW1wLCBjb2xvciA9ICJNYXgiKSkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgICNzaW5jZSB0aGUgbGVnZW5kIGlzIGJhc2VkIG9uIHRoZSBjb2xvciBtYXBwaW5nLCB1c2UgY29sb3IgPSB0byBzZXQgdGhlIGxlZ2VuZCB0aXRsZQ0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIFZhbHVlcyIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobGFiZWxzID0gYygiTWVhbiIsICJNaW4iLCAiTWF4IiksIHZhbHVlcyA9IGMoImdyYXkiLCAiYmx1ZSIsICJyZWQiKSkNCg0KI0luIHNjYWxlX2NvbG9yX21hbnVhbCwgd2Ugc3RhcnQgYnkgdGVsbGluZyBSIHdoaWNoIGxhYmVscyB0byB1c2UgdG8gZ2VuZXJhdGUgdGhlIGNvbG9yIHNjaGVtZTsgaW4gdGhpcyBjYXNlLCBpdCdzIHRoZSBzYW1lIGxhYmVscyB3ZSBqdXN0IHNldCBhYm92ZS4gVGhlbiwgd2UgaGF2ZSB0byB0ZWxsIFIgd2hpY2ggY29sb3JzIHRvIHVzZSBmb3IgZWFjaCBsYWJlbC4gQmVjYXVzZSB0aGVyZSBhcmUgdGhyZWUgY29sb3IgdmFsdWVzIHRvIHNldCwgbm90ZSB0aGF0IHdlIGhhdmUgdG8gdXNlIGMoKSBhcm91bmQgdGhlIGxpc3Qgb2YgdmFyaWFibGUgbmFtZXMgYW5kIGNvbG9ycy4gDQoNCiNTY2FsZV9jb2xvcl9tYW51YWwgb2Z0ZW4gaW52b2x2ZXMgc29tZSBndWVzc2luZyBhbmQgY2hlY2tpbmcgd2l0aCB0aGUgb3JkZXIgb2YgdGhlIGNvbG9ycyAtIGZvciBzb21lIHJlYXNvbiwgUiB3YW50ZWQgdG8gdXNlIHRoZSBmaXJzdCBjb2xvciBmb3IgdGhlIG1heCB0ZW1wZXJhdHVyZSwgdGhlIHNlY29uZCBmb3IgdGhlIG1lYW4sIGFuZCB0aGUgdGhpcmQgZm9yIHRoZSBtaW4uIFRoaXMgb3JkZXIgbWFrZXMgbm8gc2Vuc2UsIGJ1dCBpdCBpcyBhbHNvIG5vdCBlYXN5IHRvIGNoYW5nZS4gSWYgeW91IG5vdGljZSB0aGF0IHRoZSBjb2xvcnMgaW4geW91ciBncmFwaCBkb24ndCBtYXRjaCB1cCwgdGhlIGVhc2llc3QgZml4IGlzIHRvIGp1c3QgY2hhbmdlIHRoZSBvcmRlciB0aGF0IHlvdSBsaXN0ZWQgdGhlIGNvbG9ycyBhbmQgdmFyaWFibGUgbmFtZXMgc28gdGhhdCBpdCBtYXRjaGVzIFIncyBkZWZhdWx0IG9yZGVyaW5nLiBUaGF0J3Mgd2hhdCBJIGRpZCBiZWxvdy4gDQpgYGANCmBgYHtyfQ0KI0hlcmUncyB0aGUgY29ycmVjdCBwbG90IQ0KZ2dwbG90KHRlbXBzKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSBkYXksIHkgPSBhY3R1YWxfbWVhbl90ZW1wLCBjb2xvciA9ICJNZWFuIikpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9taW5fdGVtcCwgY29sb3IgPSAiTWluIikpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGRheSwgeSA9IGFjdHVhbF9tYXhfdGVtcCwgY29sb3IgPSAiTWF4IikpICsNCiAgbGFicyh5ID0gIlRlbXBlcmF0dXJlIiwgeCA9ICJEYXkiLCANCiAgICAgICB0aXRsZSA9ICJEYWlseSBUZW1wZXJhdHVyZSBpbiBOZXcgWW9yayBDaXR5LCAyMDE0IiwNCiAgICAgICBjb2xvciA9ICJUZW1wZXJhdHVyZSBWYWx1ZXMiKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKGxhYmVscyA9IGMoIk1heCIsICJNZWFuIiwgIk1pbiIpLCB2YWx1ZXMgPSBjKCJyZWQiLCAiZ3JheSIsICJibHVlIikpDQpgYGANCkRvZXNuJ3QgdGhhdCBsb29rIG5pY2U/IExldCdzIHRhbGsgYWJvdXQgcmVzaGFwaW5nIHlvdXIgZGF0YSBub3cuIFRoaXMgaXMgYSB2ZXJ5IGhlbHBmdWwgc2tpbGwgdG8gaGF2ZSwgYW5kIHlvdSB3aWxsIGZpbmQgeW91cnNlbGYgaGF2aW5nIHRvIHJlc2hhcGUgZGF0YSBmcmVxdWVudGx5LlNvIHJpZ2h0IG5vdywgZWFjaCB2YXJpYWJsZSBoYXMgaXRzIG93biBjb2x1bW4gaW4gdGhlIGRhdGFmcmFtZSBpbiBvdXIgY2FzZSwgd2UncmUgd29ya2luZyB3aXRoIGZvdXIgY29sdW1ucyBvZiBkYXRhLiBTaW5jZSB0aHJlZSBvZiB0aGUgdmFyaWFibGVzIGFyZSB0ZW1wZXJhdHVyZSBkYXRhLCB3b3VsZG4ndCBpdCBtYWtlIHNlbnNlIHRvIHB1dCB0aGVtIGFsbCBpbiBvbmUgY29sdW1uIGluc3RlYWQ/IFRoaXMgaXMgd2hhdCB3ZSBjYWxsIHRyYW5zZm9ybWluZyBkYXRhIGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCAtIHdpZGUgZGF0YSBoYXMgbW9yZSBjb2x1bW5zLCB3aGlsZSBsb25nIGRhdGEgd2lsbCB1c3VhbGx5IGhhdmUgbW9yZSByb3dzIGluc3RlYWQuIEhlcmUncyBhIGRpYWdyYW0gb2Ygd2hhdCBpdCBsb29rcyBsaWtlIHRvIHRyYW5zZm9ybSBmcm9tIGxvbmcgdG8gd2lkZTogaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9pMURuZS5qcGcuIFlvdSBjYW4gbG9vayBhdCB0aGlzIGRpYWdyYW0gbGF0ZXIgaWYgeW91J3JlIGNvbmZ1c2VkIGFib3V0IHdoYXQgd2lkZSBhbmQgbG9uZyBmb3JtYXQgbG9vayBsaWtlLiBGb3Igd2hhdGV2ZXIgcmVhc29uLCB0aGUgZ2dwbG90MiBwYWNrYWdlIHRlbmRzIHRvIHdvcmsgYmV0dGVyIHdpdGggbG9uZyBkYXRhLiBXZSdsbCByZXNoYXBlIHRoZSBkYXRhIHVzaW5nIGEgY29tbWFuZCBmcm9tIHRoZSB0aWR5ciBwYWNrYWdlLCBwaXZvdF9sb25nZXIuIA0KDQpgYGB7cn0NCndpZGVfZGF0YSA8LSB0ZW1wcyAlPiUgDQogICN3ZSdsbCBvbmx5IHNlbGVjdCB0aGUgdmFyaWFibGVzIG9mIGludGVyZXN0IHRvIGRvIHRoaXMNCiAgc2VsZWN0KGMoZGF5LCBhY3R1YWxfbWVhbl90ZW1wLCBhY3R1YWxfbWluX3RlbXAsIGFjdHVhbF9tYXhfdGVtcCkpDQoNCiNsZXQncyBjaGFuZ2UgdGhlIGNvbHVtbiBuYW1lcyB0byBtYWtlIHRoZW0gYSBiaXQgbmljZXI6DQojSSdsbCBzaG93IHlvdSB3aHkgdGhpcyBtYXR0ZXJzIHNvb24uIA0KY29sbmFtZXMod2lkZV9kYXRhKSA8LSBjKCJEYXkiLCAiTWVhbiIsICJNaW4iLCAiTWF4IikNCg0KaGVhZCh3aWRlX2RhdGEpDQpgYGANCmBgYHtyfQ0KI05vdyB3ZSdsbCByZXNoYXBlIGl0IQ0KDQpsb25nX2RhdGEgPC0gd2lkZV9kYXRhICU+JSANCiAgI1RoZSBjb2x1bW4gdGl0bGVzIGJlY29tZSB0aGUgY2F0ZWdvcmllcyBpbiBhIG5ldyBjb2x1bW4gYWZ0ZXIgdGhlIHJlc2hhcGluZw0KICAjSSdtIG5hbWluZyB0aGlzIG5ldyBjb2x1bW4gdGVtcF90eXBlDQogICNUaGUgdGVtcGVyYXR1cmUgdmFsdWVzIGFyZSBwdXQgaW4gYSBuZXcgdmFsdWVzIGNvbHVtbiwgd2hpY2ggSSdtIGNhbGxpbmcgdGVtcA0KICBwaXZvdF9sb25nZXIoIURheSwgbmFtZXNfdG8gPSAidGVtcF90eXBlIiwgdmFsdWVzX3RvID0gInRlbXAiKQ0KDQpoZWFkKGxvbmdfZGF0YSkNCmBgYA0KYGBge3J9DQojV2hhdCBpZiBJIHdhbnRlZCB0byBnbyBmcm9tIGxvbmcgdG8gd2lkZSBkYXRhPyBIZXJlJ3Mgd2hhdCB0aGF0IGxvb2tzIGxpa2UsIGZvciB5b3VyIHJlZmVyZW5jZToNCg0Kd2lkZV9kYXRhMSA8LSBsb25nX2RhdGEgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdGVtcF90eXBlLCB2YWx1ZXNfZnJvbSA9IHRlbXApDQoNCiNSdW4gdGhpcyBjb2RlIHRvIHZlcmlmeSB0aGF0IHRoZSBvcmlnaW5hbCB3aWRlX2RhdGEgYW5kIG91ciBuZXcgd2lkZV9kYXRhMSBkYXRhZnJhbWUgYXJlIHRoZSBzYW1lLiBMb2dpY2FsIGRhdGEgaXMgaGVscGZ1bCBpbiB0aGlzIGNhc2UhDQojSSdtIHNldHRpbmcgdGhlIG51bWJlciBvZiB2YWx1ZXMgdGhhdCBSIHByaW50cyBvdXQgdG8gMjAgLSBvdGhlcndpc2UsIFIgd291bGQgcHJpbnQgdGhlIHdob2xlIGRhdGFzZXQgb24gdGhlIHNjcmVlbiwgYW5kIGl0IHdvdWxkIHRha2UgdXAgYSBsb3Qgb2Ygc3BhY2UhDQpvcHRpb25zKG1heC5wcmludCA9IDIwKQ0Kd2lkZV9kYXRhMSA9PSB3aWRlX2RhdGENCmBgYA0KDQoNCkRvIHlvdSBzZWUgdGhlIGRpZmZlcmVuY2U/IE5vdywgdGhlIGNhdGVnb3J5ICh0ZW1wX3R5cGUsIG9yIG1lYW4sIG1pbiwgYW5kIG1heCkgaXMgaW4gb25lIGNvbHVtbiwgd2hpbGUgZWFjaCB0ZW1wZXJhdHVyZSB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSB0ZW1wX3R5cGUgYW5kIGRheSBpcyBpbiB0aGUgdGVtcCBjb2x1bW4uIFRoZSB3aWRlIGFuZCBsb25nIGRhdGEgc2V0cyBhcmUganVzdCBkaWZmZXJlbnQgd2F5cyBvZiBzdG9yaW5nIHRoZSBzYW1lIGRhdGEhIE5vdyBsZXQncyBzZWUgaG93IHRoaXMgd29ya3MgaW4gZ2dwbG90Mi4gDQoNCmBgYHtyfQ0KDQojTm93LCBpbnN0ZWFkIG9mIHRocmVlIGdlb20gbGF5ZXJzLCB3ZSB3aWxsIG5lZWQgdG8gcGxvdCB0aGUgZGF0YSBieSB0aHJlZSBncm91cHM6IG1lYW4sIG1pbiwgYW5kIG1heC4gQmVjYXVzZSB3ZSBhcmUgZ3JvdXBpbmcgdGhlIGRhdGEgaW4gdGhlIGRhdGFmcmFtZSBieSB0aGUgdHlwZSBvZiB0ZW1wZXJhdHVyZSByZWNvcmRlZCwgd2UgbmVlZCB0byBhc3NpZ24gdGhlIHRlbXBfdHlwZSBjb2x1bW4gdG8gdGhlIGdyb3VwIGFyZ3VtZW50LiBCZWNhdXNlIGVhY2ggdHlwZSBvZiB0ZW1wZXJhdHVyZSB3aWxsIGFsc28gaGF2ZSBhIGRpZmZlcmVudCBjb2xvciwgd2Ugd2lsbCBhc3NpZ24gdGVtcF90eXBlIHRvIHRoZSBjb2xvciBhcmd1bWVudCBhcyB3ZWxsLiBMZXQncyBzZWUgd2hhdCB0aGlzIGxvb2tzIGxpa2UhDQoNCmdncGxvdChsb25nX2RhdGEsIGFlcyh4ID0gRGF5LCB5ID0gdGVtcCwgZ3JvdXAgPSB0ZW1wX3R5cGUsIGNvbG9yID0gdGVtcF90eXBlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpDQpgYGANCg0KRG8geW91IHNlZSB3aHkgSSBjaGFuZ2VkIHRoZSBjb2x1bW4gbmFtZXM/IFIgdXNlcyB0aGUgY2F0ZWdvcmllcyBpbiB0aGUgdGVtcF90eXBlIGNvbHVtbiB0byBhZGQgbmFtZXMgdG8gdGhlIGxlZ2VuZC4gS2VlcGluZyB0aGUgImFjdHVhbF9tZWFuX3RlbXAiIChhbmQgc28gb24pIGxhYmVscyB3b3VsZCBub3QgaGF2ZSBiZWVuIG5lYXJseSBhcyBjbGVhciBpbiBhIGxlZ2VuZC4gSW4gb3VyIGdyYXBocywgd2Ugc2hvdWxkIGFpbSB0byBzaG93IGNvbXBsZXggaW5mb3JtYXRpb24gaW4gdGhlIHNpbXBsZXN0IHdheSBwb3NzaWJsZSAtIGhhdmluZyBjbGVhciBsZWdlbmQgYW5kIGF4aXMgdGl0bGVzIGlzIGtleSB0byB0aGF0LiBOb3csIGluIHRoaXMgY2FzZSwgdGhlIGNvbG9ycyBhcmVuJ3QgcXVpdGUgcmlnaHQhIExldCdzIHNldCB0aGVtIG1hbnVhbGx5LiANCg0KYGBge3J9DQojY3JlYXRlIHRoZSBjb2xvciBwYWxldHRlIGZvciB0aGUgZGF0YQ0KI1JlbWVtYmVyLCBvcmRlciBtYXR0ZXJzISBCYXNlZCBvbiB0aGUgb3JkZXIgb2YgdGhlIGxlZ2VuZCBpbiB0aGUgbGFzdCBncmFwaCwgSSB3aWxsIGluY2x1ZGUgdGhlIGNvbG9yIGZvciB0aGUgbWF4IHRlbXAsIHRoZW4gdGhlIG1lYW4sIHRoZW4gdGhlIG1pbi4gDQoNCmNvbG9ycyA8LSBjKCJyZWQiLCAiZ3JheSIsICJibHVlIikNCg0KZ2dwbG90KGxvbmdfZGF0YSwgYWVzKHggPSBEYXksIHkgPSB0ZW1wLCBncm91cCA9IHRlbXBfdHlwZSwgY29sb3IgPSB0ZW1wX3R5cGUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnMoeSA9ICJUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiRGFpbHkgVGVtcGVyYXR1cmUgaW4gTmV3IFlvcmsgQ2l0eSwgMjAxNCIsDQogICAgICAgY29sb3IgPSAiVGVtcGVyYXR1cmUgKEYpIikrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnMpDQpgYGANCg0KRG8geW91IHNlZSBob3cgbXVjaCBzaW1wbGVyIGFuZCBzaG9ydGVyIHRoZSBnZ3Bsb3QyIGNvZGUgaXMgbm93PyBSZXNoYXBpbmcgZGF0YSBkZWZpbml0ZWx5IHRha2VzIHNvbWUgZ2V0dGluZyB1c2VkIHRvLCBidXQgaXQnbGwgc2F2ZSB5b3UgdGltZSBpbiB0aGUgZnV0dXJlLiBCZWZvcmUgd2UgbW92ZSBvbiwgSSdsbCBzaG93IHlvdSBvbmUgbW9yZSB3YXkgdG8gc2V0IHRoZSBjb2xvcnMsIG5vdyB0aGF0IHdlIGhhdmUgdGhlIGRhdGEgaW4gbG9uZyBmb3JtYXQuIFRoaXMgdGhpcmQgdmVyc2lvbiB3aWxsIGludHJvZHVjZSB5b3UgdG8gYSBmdW5jdGlvbiB0aGF0IGlzIGhlbHBmdWwgd2l0aGluIGRwbHlyIGZ1bmN0aW9ucywgaWZlbHNlLiANCg0KYGBge3J9DQojVGhpcyB2ZXJzaW9uIGludm9sdmVzIGNyZWF0aW5nIGEgbmV3IGNvbHVtbiBpbiB0aGUgbG9uZyBkYXRhZnJhbWUgd2l0aCB0aGUgY29sb3IgdmFsdWVzIGluIGl0LiBFYWNoIGNvbG9yIHdpbGwgY29ycmVzcG9uZCB0byB0aGUgY29ycmVjdCB0ZW1wX3R5cGUuIA0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsb25nX2RhdGEgPC0gbG9uZ19kYXRhICU+JSANCiAgbXV0YXRlKGNvbG9ycyA9IGlmZWxzZSh0ZW1wX3R5cGUgPT0gIk1heCIsICJyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh0ZW1wX3R5cGUgPT0gIk1lYW4iLCAiZ3JheSIsICJibHVlIikpKQ0KDQojTGV0J3Mgd2FsayB0aHJvdWdoIHRoZSBzeW50YXggb2YgdGhlIGlmZWxzZSBmdW5jdGlvbiAobm90ZSB0aGF0IGl0IHN0YW5kIGZvciAiaWYgZWxzZSIpDQojWW91IGNhbiByZWFkIHRoZSBjb2RlIGxpa2UgdGhpczogaWYgdGVtcF90eXBlIGlzIGVxdWFsIHRvIE1heCwgc2V0IHRoZSB2YWx1ZSB0byByZWQNCiNpZiB0ZW1wIHR5cGUgaXMgZXF1YWwgdG8gTWVhbiwgc2V0IHRoZSBjb2xvciB0byBncmF5LiANCiNGb3IgYWxsIG90aGVycywgc2V0IHRoZSBjb2xvciB0byBibHVlLiANCiNJZiB5b3UgbG9vayB1cCB0aGUgZG9jdW1lbnRhdGlvbiB0byBpZmVsc2UsIHlvdSdsbCBzZWUganVzdCBob3cgc2ltcGxlIGl0IGlzOg0KI2lmZWxzZSh0ZXN0LCB5ZXMsIG5vKQ0KI3lvdSBnaXZlIHRoZSBmdW5jdGlvbiB0aGUgdGVzdCwgYW5kIHNldCBhIHZhbHVlIHRvIGNvcnJlc3BvbmQgdG8geWVzIChUcnVlKSBhbmQgbm8gKEZhbHNlKSBhbnN3ZXJzLiBJbiB0aGlzIGNvZGUsIEkgaGF2ZSBuZXN0ZWQgYW4gaWZlbHNlIGZ1bmN0aW9uIGluc2lkZSBvZiBhbm90aGVyIG9uZSwgYmFzaWNhbGx5IHRlbGxpbmcgUiB0aGF0IG5vIG9yIGZhbHNlIHZhbHVlcyBiYXNlZCBvbiB0aGUgZmlyc3QgY2FsbCB0byBpZmVsc2UgYXJlIHN1YmplY3QgdG8gYW5vdGhlciBpZmVsc2Ugc3RhdGVtZW50LiBWYWx1ZXMgdGhhdCBhcmUgbm8gb3IgZmFsc2UgaW4gYm90aCBjYWxscyBvdCBpZmVsc2Ugd2lsbCBiZSBibHVlIChub3RlIHRoYXQgdGhlc2UgYXJlIHRoZSBtaW5pbXVtIHZhbHVlcykuDQojTGV0J3MgZ3JhcGggdGhpcyENCg0KZ2dwbG90KGxvbmdfZGF0YSwgYWVzKHggPSBEYXksIHkgPSB0ZW1wLCBncm91cCA9IHRlbXBfdHlwZSwgY29sb3IgPSBjb2xvcnMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnMoeSA9ICJUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiRGFpbHkgVGVtcGVyYXR1cmUgaW4gTmV3IFlvcmsgQ2l0eSwgMjAxNCIsDQogICAgICAgY29sb3IgPSAiVGVtcGVyYXR1cmUgKEYpIikrDQogIHNjYWxlX2NvbG9yX2lkZW50aXR5KGd1aWRlID0gImxlZ2VuZCIsIGxhYmVscyA9IGMoIk1pbiIsICJNZWFuIiwgIk1heCIpKQ0KDQojSWYgeW91IHdhbnQgdG8gdXNlIHRoaXMgbWV0aG9kLCB5b3UgbmVlZCB0byBhbHNvIGluY2x1ZGUgdGhlIHNjYWxlX2NvbG9yX2lkZW50aXR5IGFyZ3VtZW50IC0gdGhpcyB0ZWxscyBSIHRvIHVzZSBjb2xvcnMgZnJvbSB0aGUgZGF0YS4gSSBhbHNvIGhhZCB0byBzcGVjaWZ5IHRoZSBsZWdlbmQgbGFiZWwgbmFtZXMgdXNpbmcgdGhlIGxhYmVscyA9IGFyZ3VtZW50IC0gYWdhaW4sIFIgaXMgd2VpcmQgYWJvdXQgdmFyaWFibGUgb3JkZXIsIGFuZCBJIGhhZCB0byBpbmNsdWRlIHRoZSBsYWJlbCBuYW1lcyBpbiB0aGUgc2FtZSBvcmRlciB0aGF0IFIgdXNlcyBpbiB0aGUgbGVnZW5kLiBGb3Igd2hhdGV2ZXIgcmVhc29uLCB0aGlzIG9yZGVyIGlzIGEgYml0IHJhbmRvbS4NCmBgYA0KT3ZlcmFsbCwgdGhlIHNlY29uZCBtZXRob2Qgb2YgYWRkaW5nIGNvbG9yIGZvciBtdWx0aXBsZSB2YXJpYWJsZXMgKHJlc2hhcGluZyB0aGUgZGF0YSBhbmQgdXNpbmcgYSBjb2xvciBwYWxldHRlIG9iamVjdCB0byBzZXQgY29sb3JzKSBpcyBwcm9iYWJseSB0aGUgbW9zdCBmbGV4aWJsZSBtZXRob2QuIE9mdGVuLCB5b3UnbGwgYmUgYWJsZSB0byBzZXQgcGFsZXR0ZXMgdXNpbmcgZnVuY3Rpb25zLCB3aGljaCBtYWtlcyB0aGUgcHJvY2VzcyBldmVuIGZhc3RlcjsgaXQncyB1bmxpa2VseSB0aGF0IHlvdSdsbCBuZWVkIHRvIG1hbnVhbGx5IHNwZWNpZnkgY29sb3JzLiBJbiB0aGUgbmV4dCBjaHVuayBvZiBjb2RlLCBJJ2xsIGdpdmUgYW4gZXhhbXBsZSB1c2luZyBhIHBhY2thZ2UgdGhhdCBjb250YWlucyBzb21lIHJlYWxseSBuaWNlIGNvbG9yIHBhbGV0dGVzIGluc3BpcmVkIGJ5IFVTIG5hdGlvbmFsIHBhcmtzLiBNb3JlIGluZm8gb24gdGhlIHBhbGV0dGVzIGFyZSBoZXJlOiBodHRwczovL2dpdGh1Yi5jb20va2F0aWVqb2xseS9uYXRpb25hbHBhcmtjb2xvcnMuIFlvdSBjYW4gdXNlIHRoZSBjb2RlIGZyb20gdGhlIGdpdGh1YiBsaW5rIHRvIGluc3RhbGwgdGhlIHBhY2thZ2UsIHRvby4gDQpPdGhlciBwYWNrYWdlcywgbGlrZSBSQ29sb3JCcmV3ZXIsIGFsc28gcHJvdmlkZSBhIHJhbmdlIG9mIHBhbGV0dGVzIHRvIGNob29zZSBmcm9tLiANCg0KYGBge3J9DQojSSBhbHJlYWR5IGhhdmUgdGhpcyBpbnN0YWxsZWQgLSBJIGxpa2UgdXNpbmcgdGhlc2UgY29sb3JzIGZvciBwcmVzZW50YXRpb25zLiANCmluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikNCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigia2F0aWVqb2xseS9uYXRpb25hbHBhcmtjb2xvcnMiKQ0KbGlicmFyeShuYXRpb25hbHBhcmtjb2xvcnMpDQoNCiNJJ3ZlIGp1c3QgcGlja2VkIGEgcmFuZG9tIHBhbGV0dGUsIHRoZXNlIGNvbG9ycyBhcmVuJ3QgbWVhbmluZ2Z1bC4gDQpwYWxldHRlIDwtIHBhcmtfcGFsZXR0ZSgiU21va3lNb3VudGFpbnMiLCBuID0gMykNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KI05vdyBncmFwaCBpdCB3aXRoIHRoZSBwYWxldHRlIQ0KZ2dwbG90KGxvbmdfZGF0YSwgYWVzKHggPSBEYXksIHkgPSB0ZW1wLCBncm91cCA9IHRlbXBfdHlwZSwgY29sb3IgPSB0ZW1wX3R5cGUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnMoeSA9ICJUZW1wZXJhdHVyZSIsIHggPSAiRGF5IiwgDQogICAgICAgdGl0bGUgPSAiRGFpbHkgVGVtcGVyYXR1cmUgaW4gTmV3IFlvcmsgQ2l0eSwgMjAxNCIsDQogICAgICAgY29sb3IgPSAiVGVtcGVyYXR1cmUgKEYpIikrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlKQ0KYGBgDQpTbyBub3cgeW91IGtub3cgdGhlIGJhc2ljcyBvZiBncmFwaGluZyB3aXRoIGdncGxvdDIhIFRoZXJlIGFyZSBqdXN0IGEgZmV3IG1vcmUgdG9waWNzIHRvIGNvdmVyIHRoYXQgeW91IHdpbGwgZmluZCBoZWxwZnVsLiBGaXJzdCwgd2hhdCBpZiBJIGRvbid0IHdhbnQgdG8gdXNlIGEgc2NhdHRlciBwbG90PyBHZ3Bsb3QyIGNvbWVzIHdpdGggYSB3aWRlIHJhbmdlIG9mIGdlb20gcG9zc2liaWxpdGllcyEgSXQncyBzbyBlYXN5IHRvIHByb2R1Y2UgZGlmZmVyZW50IGtpbmRzIG9mIHBsb3RzIG9mIHlvdXIgZGF0YS4gTGV0J3MgbWFrZSBhIGxpbmUgcGxvdCB3aXRoIHRoZSBkYXRhIHdlIGFscmVhZHkgaGF2ZS4gDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QobG9uZ19kYXRhLCBhZXMoeCA9IERheSwgeSA9IHRlbXAsIGdyb3VwID0gdGVtcF90eXBlLCBjb2xvciA9IHRlbXBfdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkNCg0KYGBgDQpUaGUgbGluZSBwbG90IGRvZXNuJ3QgbG9vayBuaWNlIGFuZCBzbW9vdGggYmVjYXVzZSB3ZSdyZSB3b3JraW5nIHdpdGggZGFpbHkgZGF0YSAtIHRoZXJlIGFyZSBhIGxvdCBvZiBkYXRhIHBvaW50cywgYW5kIHRoZSB0ZW1wZXJhdHVyZXMgbW92ZSBhcm91bmQgYSBsb3QhIEJ1dCBhcyB5b3UgY2FuIHNlZSwgc3dpdGNoaW5nIHRvIGEgbGluZSBwbG90IHdhcyBzbyBlYXN5LiBOZXh0LCB3ZSBjYW4gbG9vayBhdCBhIGJhciBwbG90LiBMaW5lIHBsb3RzLCBzY2F0dGVyIHBsb3RzLCBhbmQgYmFyIHBsb3RzIHdpbGwgYmUgdGhlIG1vc3QgY29tbW9uIHBsb3RzIHlvdSdsbCB1c2UuIA0KDQpgYGB7cn0NCiNSZW1lbWJlciB0aGF0IGJhciBwbG90cyBkb24ndCByZXF1aXJlIHggYW5kIHkgdmFyaWFibGVzIC0gd2UganVzdCBuZWVkIG9uZSB5IHZhcmlhYmxlIChpbiB0aGlzIGNhc2UsIHRlbXBlcmF0dXJlKSBhbmQgY2F0ZWdvcmllcyBmb3IgdGhlIHgtYXhpcyAoaW4gdGhpcyBjYXNlLCB0ZW1wX3R5cGUpLiBMZXQncyBtYWtlIGEgc2ltcGxlIGJhciBwbG90IGZvciBvbmUgZGF5Og0KDQpkYXkxIDwtIGxvbmdfZGF0YSAlPiUgZmlsdGVyKERheSA9PSAxKQ0KDQpnZ3Bsb3QoZGF5MSwgYWVzKHkgPSB0ZW1wLCB4ID0gdGVtcF90eXBlLCBncm91cCA9IHRlbXBfdHlwZSwgZmlsbCA9IHRlbXBfdHlwZSkpKw0KICBnZW9tX2JhcihzdGF0ID0gIklkZW50aXR5IikrDQogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSBUeXBlIiwgeSA9ICJUZW1wZXJhdHVyZSIsDQogICAgICAgdGl0bGUgPSAiVGVtcGVyYXR1cmVzIGluIE9uZSBEYXkgaW4gTllDIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkNCg0KI1NvbWUgdGhpbmdzIHRvIG5vdGUgYWJvdXQgdGhpcyBjb2RlOiBiZWNhdXNlIEkgaGF2ZSBpbmNsdWRlZCB0aGUgY2F0ZWdvcmllcyBhcyB4LXZhbHVlcywgSSBuZWVkIHRvIGluY2x1ZGUgdGhlIGFyZ3VtZW50IHN0YXQgPSAiSWRlbnRpdHkiIGluIHRoZSBnZW9tX2JhciBsYXllci4gV2l0aG91dCBnb2luZyBpbnRvIHRvbyBtdWNoIGRldGFpbCwgdGhpcyBhcmd1bWVudCB0ZWxscyBSIHRoYXQgdGhlIGhlaWdodCBvZiB0aGUgY29sdW1ucyBzaG91bGQgYmUgZXF1YWwgdG8gdGhlIHRlbXAgdmFsdWVzLiBOb3RlIGFsc28gdGhhdCBpbnN0ZWFkIG9mIGNvbG9yLCB3ZSB1c2UgdGhlIGZpbGw9IGFyZ3VtZW50IGhlcmUgLSB0aGUgY29sb3IgYXJndW1lbnQgaXMgZm9yIGxpbmVzIGFuZCBwb2ludHMsIHdoaWxlIHNvbGlkIHBvbHlnb25zIG5lZWQgdG8gYmUgYXNzaWduZWQgY29sb3JzIHVzaW5nIHRoZSBmaWxsIGFyZ3VtZW50LiBBcyBhbiBleGVyY2lzZSwgdHJ5IHNlZWluZyB3aGF0IGhhcHBlbnMgd2hlbiB5b3UgdXNlIGNvbG9yID0gaW5zdGVhZCEgV2hlbiB5b3UgdXNlIGZpbGwsIHRoZSBzY2FsZV9jb2xvcl9tYW51YWwgYXJndW1lbnQgYWxzbyBjaGFuZ2VzIHRvIHNjYWxlX2ZpbGxfbWFudWFsIHRvIHNldCB0aGUgY29sb3IgcGFsZXR0ZS4gRmluYWxseSwgUiB3aWxsIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGUgYSBsZWdlbmQgd2hlbiB5b3UgYXNzaWduIGNvbG9ycyB1c2luZyB0aGUgZ3JvdXAgYWVzdGhldGljIC0gSSBkaWRuJ3QgbmVlZCBhIGxlZ2VuZCBpbiB0aGlzIGdyYXBoLCBzbyBJIHVzZWQgdGhlIHRoZW1lKCkgYXJndW1lbnQgdG8gc2V0IHRoZSBsZWdlbmQgcG9zaXRpb24gdG8gIm5vbmUiLiBUaGlzIGRlbGV0ZXMgdGhlIGxlZ2VuZCBmcm9tIHRoZSBwbG90LCBhbmQgaXMgd29ydGggcmVtZW1iZXJpbmcuIA0KYGBgDQpMZXQncyB0aGluayBhYm91dCBzb21lIG90aGVyIHdheXMgeW91IGNhbiBjdXN0b21pemUgeW91ciBwbG90cy4gT25lIHdheSB0aGF0IHdlIGNhbiBtYWtlIG91ciBwbG90IGxvb2sgbmljZSBpcyBieSBhZGRpbmcgYSB2aXN1YWwgdGhlbWUuIFRoZXJlIGFyZSBhIG51bWJlciBvZiB0aGVtZXMgeW91IGNhbiBhZGQgdG8geW91ciBwbG90IC0gd2UnbGwgZG93bmxvYWQgYSBuZXcgcGFja2FnZSBub3cgdGhhdCBjb250YWlucyBzb21lIGFkZGl0aW9uYWwgdGhlbWVzIGFzIHdlbGwuIA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2d0aGVtZXMpDQoNCiNJIHByZWZlciB0aGUgbWluaW1hbCB0aGVtZSB0aGF0IGNvbWVzIGxvYWRlZCB3aXRoIGdncGxvdDIgLSBpdCBtYWtlcyBwbG90cyBsb29rIHZlcnkgc2xlZWsgDQpnZ3Bsb3QobG9uZ19kYXRhLCBhZXMoeCA9IERheSwgeSA9IHRlbXAsIGdyb3VwID0gdGVtcF90eXBlLCBjb2xvciA9IHRlbXBfdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQpgYGB7cn0NCiNUaGUgZ2d0aGVtZXMgcGFja2FnZSBjb21lcyB3aXRoIHNvbWUgb3RoZXIgdXNlZnVsIHRoZW1lcy4gTGV0J3MgdHJ5IGEgZmV3IG1vcmU6DQojSWYgeW91IHdhbnQgeW91ciBwbG90IHRvIGxvb2sgbGlrZSB0aGUgcGxvdHMgaW4gdGhlIEVjb25vbWlzdCBtYWdhemluZSwgeW91IG1pZ2h0IHVzZSB0aGlzIHRoZW1lOg0KDQpnZ3Bsb3QobG9uZ19kYXRhLCBhZXMoeCA9IERheSwgeSA9IHRlbXAsIGdyb3VwID0gdGVtcF90eXBlLCBjb2xvciA9IHRlbXBfdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkrDQogIHRoZW1lX2Vjb25vbWlzdCgpDQpgYGANCmBgYHtyfQ0KDQojVGhpcyB0aGVtZSBtaW1pY3MgcGxvdHMgZHJhd24gYnkgdGhlIFdhbGwgU3RyZWV0IEpvdXJuYWw6DQpnZ3Bsb3QobG9uZ19kYXRhLCBhZXMoeCA9IERheSwgeSA9IHRlbXAsIGdyb3VwID0gdGVtcF90eXBlLCBjb2xvciA9IHRlbXBfdHlwZSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkrDQogIHRoZW1lX3dzaigpDQpgYGANCg0KSWYgeW91IHR5cGUgdGhlbWVfIHlvdSBzaG91bGQgZ2V0IGEgZHJvcCBkb3duIG1lbnUgb2YgYWxsIG9mIHRoZSBwb3NzaWJsZSB0aGVtZXMgdG8gY2hvb3NlIGZyb20gLSBJIHdvdWxkIGVuY291cmFnZSB5b3UgdG8gcGxheSBhcm91bmQgd2l0aCB0aGVtLCBhbmQgc2VlIHdoaWNoIG9uZSB5b3UgbGlrZSBiZXN0ISANCg0KYGBge3J9DQojRmluYWxseSwgeW91IGNhbiB1c2UgdGhlIHRoZW1lIGZ1bmN0aW9uIHRvIGNoYW5nZSB0aGUgY2VudGVyaW5nIG9mIHRoZSB0aXRsZSBhbmQgb3RoZXIgdGV4dC4gQnkgdGhlIGRlZmF1bHQsIGV2ZXJ5dGhpbmcgaXMgbGVmdC1hbGlnbmVkLiANCg0KZ2dwbG90KGxvbmdfZGF0YSwgYWVzKHggPSBEYXksIHkgPSB0ZW1wLCBncm91cCA9IHRlbXBfdHlwZSwgY29sb3IgPSB0ZW1wX3R5cGUpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh5ID0gIlRlbXBlcmF0dXJlIiwgeCA9ICJEYXkiLCANCiAgICAgICB0aXRsZSA9ICJEYWlseSBUZW1wZXJhdHVyZSBpbiBOZXcgWW9yayBDaXR5LCAyMDE0IiwNCiAgICAgICBjb2xvciA9ICJUZW1wZXJhdHVyZSAoRikiKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUpICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KI05vdGUgdGhhdCB0aGUgZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSBhcmd1bWVudCBpcyB0ZWxsaW5nIFIgdG8gY2VudGVyLWFsaWduIHRoZSB0aXRsZSB0ZXh0DQojWW91IGNhbiBwbGF5IGFyb3VuZCB3aXRoIHRoZSBoanVzdCBhcmd1bWVudCB0byBtYW51YWxseSBjaGFuZ2UgdGhlIHRpdGxlIHBvc2l0aW9uIChhbHRob3VnaCBJIGRvbid0IHJlYWxseSBzZWUgYW55IHJlYXNvbiB0byBkbyB0aGlzKQ0KYGBgDQpGaW5hbGx5LCBjYW4geW91IHVzZSBtb3JlIHRoYW4gb25lIHBsb3QgdHlwZSBpbiB0aGUgc2FtZSBwbG90PyBZb3Ugc3VyZSBjYW4hIFRoZSBjb2RlIGJlbG93IHNob3dzIHdoYXQgdGhpcyBsb29rcyBsaWtlIGJ5IGFkZGluZyBhIHRyZW5kIGxpbmUgdG8gdGhlIGRhdGEgdXNpbmcgYSBzbW9vdGhpbmcgbWV0aG9kIChkb24ndCB3b3JyeSBhYm91dCBob3cgaXQgd29ya3MsIHRoaXMgaXMganVzdCBhbiBleGFtcGxlKS4gSW4gdGhpcyBleGFtcGxlLCBiZWNhdXNlIHdlIGFyZSB1c2luZyB0aGUgc21vb3RoaW5nIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIGF2ZXJhZ2UgdmFsdWVzIG9mIGVhY2ggdGVtcGVyYXR1cmUgdHlwZSwgd2UgZG9uJ3QgbmVlZCB0byBjaGFuZ2UgdGhlIGFlc3RoZXRpY3MuIElmLCBmb3IgZXhhbXBsZSwgeW91IHdhbnRlZCB0byBtYWtlIGEgbGluZSBncmFwaCB3aXRoIG9uZSB2YXJpYWJsZSBvdmVyIHRpbWUgYW5kIGEgcG9pbnQgZ3JhcGggd2l0aCBhIGRpZmZlcmVudCB2YXJpYWJsZSBvdmVyIHRpbWUsIHlvdSB3b3VsZCBuZWVkIHRvIG1hbnVhbGx5IGluY2x1ZGUgdGhlIGFlc3RoZXRpY3MgaW4gZWFjaCBnZW9tIGxheWVyIChsaWtlIHdlIGRpZCB0aGUgZmlyc3QgdGltZSB3ZSBhZGRlZCBjb2xvciAtIGluIHRoYXQgZXhhbXBsZSwgZWFjaCB2YXJpYWJsZSBoYWQgaXRzIG93biBnZW9tIGxheWVyLCBhbmQgd2UgaGFkIHRvIG1hcCB0aGUgYWVzdGhldGljcyBmb3IgZWFjaCBvbmUpLiANCg0KYGBge3J9DQoNCmdncGxvdChsb25nX2RhdGEsIGFlcyh4ID0gRGF5LCB5ID0gdGVtcCwgZ3JvdXAgPSB0ZW1wX3R5cGUsIGNvbG9yID0gdGVtcF90eXBlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChjb2xvciA9ICJibGFjayIpKw0KICBsYWJzKHkgPSAiVGVtcGVyYXR1cmUiLCB4ID0gIkRheSIsIA0KICAgICAgIHRpdGxlID0gIkRhaWx5IFRlbXBlcmF0dXJlIGluIE5ldyBZb3JrIENpdHksIDIwMTQiLA0KICAgICAgIGNvbG9yID0gIlRlbXBlcmF0dXJlIChGKSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSkgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQpgYGANCkFuZCB0aGVyZSB5b3UgaGF2ZSBpdCEgWW91IGFyZSBub3cgYSBwcm8gYXQgdXNpbmcgZ2dwbG90Mi4gWW91IHNob3VsZCBoYXZlIGFsbCB0aGUgdG9vbHMgeW91IG5lZWQgdG8gbWFrZSBiZWF1dGlmdWwgYW5kIGVmZmVjdGl2ZSB2aXN1YWxpemF0aW9uIGluIFIuIElmIHlvdSB3YW50IG1vcmUgaW5mb3JtYXRpb24gb24gZGlmZmVyZW50IHR5cGVzIG9mIGdyYXBocywgb3IgeW91IGp1c3Qgd2FudCBhIGhlbHBmdWwgcmVmZXJlbmNlIHRvIHJlZmVyIHRvIGFzIHlvdSBwcm9ncmVzcyB0aHJvdWdoIHRoZSBjb3Vyc2UsIHlvdSBjYW4gZmluZCBhbiBleGNlbGxlbnQgZ2dwbG90MiBjaGVhdCBzaGVldCBoZXJlOiBodHRwczovL3d3dy5tYXRocy51c3lkLmVkdS5hdS91L1VHL1NNL1NUQVQzMDIyL3IvY3VycmVudC9NaXNjL2RhdGEtdmlzdWFsaXphdGlvbi0yLjEucGRmLiANCg0KDQpSZXNvdXJjZXMNCg0KRml2ZVRoaXJ0eUVpZ2h0ICgyMDE0KS4gVVMuIFdlYXRoZXIgSGlzdG9yeS4gW0RhdGEgU2V0XS4gUmV0cmlldmVkIGZyb206IGh0dHBzOi8vZ2l0aHViLmNvbS9maXZldGhpcnR5ZWlnaHQvZGF0YS90cmVlL21hc3Rlci91cy13ZWF0aGVyLWhpc3RvcnkuIA0KDQpQcmFiaGFrYXJhbiwgUy4gKDIwMTcpLiBUaGUgQ29tcGxldGUgZ2dwbG90MiBUdXRvcmlhbCAtIFBhcnQxIHwgSW50cm9kdWN0aW9uIFRvIGdncGxvdDIuIFJldHJpZXZlZCBmcm9tOiBodHRwOi8vci1zdGF0aXN0aWNzLmNvL0NvbXBsZXRlLUdncGxvdDItVHV0b3JpYWwtUGFydDEtV2l0aC1SLUNvZGUuaHRtbC4g