Statistics is the practice of using data from a sample to make inferences about some broader population of interest. This class focuses on using linear and logistic models built from a sample of data to learn about relationships in the broader population and to make predictions.

Set up R Studio

A couple reminders from the R Basics document. Go to Tools –> Global Options. On the General tab, next to Save workspace to .RData on exit, choose Never and uncheck the box next to Restore .Rdata into workspace at startup. You can also go to the Appearance tab to customize the look of R Studio. Some people like black screens better than white.

Save this file to somewhere OTHER THAN YOUR DOWNLOADS FOLDER! Save often.

Install new libraries and load the libraries we will use

We need to install any new packages we plan to load in an R markdown document. Once installed, you won’t have to install them again. Today, we need to install the tidyverse and fueleconomy packages. You can either go to the Packages tab and click Install. Type tidyverse fueleconomy (separated by a space) and follow the prompts. Or else, in the console, type install.packages("tidyverse", "fueleconomy").

Then you load the libraries by running the following piece of code. You need to do this in every R markdown file where you use functions or datasets from these package. We will get into the habit of putting these at the very top of our documents. This will be one of the only documents where I do not have all the libraries listed at the top. Also note that I’ve added warning=FALSE, message=FALSE to the code chunk options, next to the r. This will prevent messages and warnings from being printed out.

library(tidyverse) #for plotting and summarizing
library(fueleconomy) #for the dataset

Intro to Graphing Data

GOAL:

Visually examine distributions of both quantitative and categorical variables. By the end of these notes and activities, you should be able to do the following tasks.

  • Create a histogram of a quantitative variable using a reasonable number of bins or binwidth so that the graph shows enough detail but not too much.
  • Describe the shape, center, and spread of the distribution of a quantitative variable. Only one statistic should be use to describe each of the shape and spread, usually mean and standard deviation or median and IQR.
  • Create a table to summarize how often each level of a categorical variable occurs. Sort the table from largest to smallest or smallest to largest.
  • Create a barplot to visually show how often each level of a categorical variable occurs.

Usually one of the first things we want to do with new data is visualize it. If you haven’t wanted to do this in the past, you’ll want to do it now because it’s going to be so easy! We will use functions from a package called ggplot2 to create our visualizations. This package is based on a visualization framework called the “Grammar of Graphics”. We will only discuss a few key details of the framework: data, geometric objects, and aesthetic attributes. The main idea is that “A statistical graphic is a mapping of data variables to aesthetic attributes of geometric objects.”

  1. Data: Our data set that contains variables (the columns) with many observations (the rows).
  2. Geometric objects: What we observe on our plot - points, lines, bars, etc.
  3. Aesthetic attributes: parts of the geometric object that we observe: x/y position, color, shape, size, etc.

In general, a basic plot can be created using the following template, where everything between the <> would be modified to fit your needs.

ggplot(data = <DATA>) +
  <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))

We could also write it like this:

<DATA> %>% 
  ggplot() +
  <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))

NOTE: The %>% is called a pipe operator. It should be read, “and then.” It is used to “pipe” the object before it/on its left into the function after it/on its right. It makes for more readable code. In R Studio, the keyboard shortcuts to type the pipe are Ctrl+Shift+M on Windows and Cmd+Shift+M on Macs.

The ggplot2 cheatsheet is a good reference that I would encourage you to have open as we go through examples.

We will also be doing some basic data summaries using the dplyr package. Both dplyr and ggplot2 are part of the tidyverse package, which is a collection of packages that are useful in data visualization and manipulation. We already installed and loaded this package.

The data: We will use a subset of the vehicles data from the fueleconomy library throughout. These are fuel economy data from the EPA. Some variables have been excluded or modified from the original dataset. For more details search for vehicles in the Help section or run ?vehicles in the console. First, take a moment to explore that data and see what is there. Run the code below and then try to answer the questions below. Don’t worry about the code syntax for now.

# First, filter vehicles to 2015 vehicles
# Save to a dataset called vehicles_2015
vehicles_2015 <- vehicles %>% filter(year == 2015)

# Give basic summary stats of each variable
vehicles_2015 %>% 
  mutate(across(where(is.character), as.factor)) %>% 
  summary()
##        id             make             model          year     
##  Min.   :34644   BMW    :36   A8 L        :  4   Min.   :2015  
##  1st Qu.:34705   MINI   :34   6           :  3   1st Qu.:2015  
##  Median :34823   Volvo  :18   CX-5 2WD    :  3   Median :2015  
##  Mean   :34801   Jaguar :13   Fit         :  3   Mean   :2015  
##  3rd Qu.:34878   Audi   :11   Forester AWD:  3   3rd Qu.:2015  
##  Max.   :34932   Mazda  :11   MX-5        :  3   Max.   :2015  
##                  (Other):82   (Other)     :186                 
##                              class                trans   
##  Compact Cars                   :40   Automatic (S8) :56  
##  Two Seaters                    :31   Automatic (S6) :47  
##  Large Cars                     :22   Manual 6-spd   :31  
##  Subcompact Cars                :21   Automatic 6-spd:25  
##  Small Sport Utility Vehicle 4WD:20   Auto(AM-S7)    : 7  
##  Midsize Cars                   :18   Automatic 8-spd: 6  
##  (Other)                        :53   (Other)        :33  
##                drive         cyl             displ      
##  4-Wheel Drive    :15   Min.   : 4.000   Min.   :1.200  
##  All-Wheel Drive  :67   1st Qu.: 4.000   1st Qu.:2.000  
##  Front-Wheel Drive:61   Median : 6.000   Median :3.000  
##  Rear-Wheel Drive :62   Mean   : 5.824   Mean   :3.212  
##                         3rd Qu.: 8.000   3rd Qu.:4.400  
##                         Max.   :12.000   Max.   :6.800  
##                         NA's   :1        NA's   :1      
##                          fuel          hwy             cty        
##  Diesel                    :  3   Min.   : 18.0   Min.   : 11.00  
##  Electricity               :  1   1st Qu.: 24.0   1st Qu.: 16.00  
##  Gasoline or E85           : 13   Median : 28.0   Median : 20.00  
##  Premium                   :127   Mean   : 28.6   Mean   : 20.81  
##  Premium Gas or Electricity:  1   3rd Qu.: 32.0   3rd Qu.: 25.00  
##  Premium or E85            :  3   Max.   :101.0   Max.   :126.00  
##  Regular                   : 57

YOUR TURN!

Check out the basic features of the dataset:

  • Examine the first six cases. (What are the cases?)
  • How many cases and variables are there?
  • What are the names of the variables?
  • Open the dataset in a spreadsheet type viewer (type View(vehicles_2015) in the console or click on it over in the Environment). Scroll through some of the data. Any questions about the data?

What about the quality of the dataset?

  • How do you think the data are collected? Try doing some searching to learn more.
  • Can you think of any complications?

Univariate visualization/summarization of quantitative variables

Research questions: What is the range of highway miles per gallon (hwy)? What are typical highway mpg? Are highway mpg’s variable across vehicles?

As you visualize quantitative variables, keep in mind:

  • Center: Where is the center of the distribution? What is a typical value of the variable?
  • Variability: How spread out are the values? A lot or a little?
  • Shape: How are values distributed along the observed range? Is the distribution symmetric, right-skewed (tail is longer on the right, pulled further out to the right), left-skewed, bimodal, or uniform (flat)?
  • Outliers: Are there any outliers, i.e. values that are unusually large/small relative to the bulk of other values?
  • Context: In the context of your research, what do you learn from the plot or table? How would you describe your findings to a broad audience?

We will often talk about the distribution of a variable. This is the values the variables take and how often. You should incorporate the answers to the questions above in your description of a distribution. You should also use numerical summaries, which we’ll talk about shortly. Think about trying to describe the distribution to someone who doesn’t have the picture in front of them.

Histograms

Histograms are constructed by (1) dividing up the observed range of the variable into “bins” of equal width and (2) counting up the number of cases that fall into each bin. Try out the code below. Notice it’s telling you that it has chosen the number of bins for you: 30.

ggplot(data = vehicles_2015) +
  geom_histogram(aes(x = hwy))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

YOUR TURN!

Try changing the number of bins (fill in the number of bins below). Which number of bins seems “best”? Why?

ggplot(data = vehicles_2015) +
  geom_histogram(aes(x = hwy), bins = ___)

We can customize plots in various ways, like I did below, but the most important part is creating a plot that allows us to see the distribution of our variable of interest, hwy in this case.

ggplot(data = vehicles_2015) +
  geom_histogram(aes(x = hwy), bins = 25, fill = "lightblue") +
  labs(x = "Highway MPG", 
       y = "Number of vehicles") +
  theme_minimal() 

Notice: Things like bins, color, fill, etc. are outside of the aesthetic mapping. Remember that all the arguments inside the aesthetic map variables to aesthetics. Everything else happens outside of the aesthetic.

Density Plots

A density plot is essentially a smooth version of the histogram. Instead of sorting cases into discrete bins, the “density” of cases is calculated across the entire range of values. The greater the number of cases, the greater the density! The density is then scaled so that the area under the density curve always equals 1, and the area under any region of the curve represents the fraction of cases that lie in that range. Density plots can be especially helpful when working with very large datasets (at least 10,000 observations).

YOUR TURN!

Run and modify the following code to look at the distribution of highway mpg for All-Wheel Drive and Front-Wheel Drive vehicles. What would you remark about the differences between the two? (Think back to center, variability, shape, outliers, and scientific context.) Is it easy to make these comparisons?

vehicles_2015 %>%
  filter(drive == "All-Wheel Drive") %>% 
  ggplot(aes(x=hwy)) +
  geom_density(fill = "orange") 

vehicles_2015 %>%
  filter(____________) %>% 
  ggplot(aes(x=hwy)) +
  geom_density()

Measures of Center and Spread

Numerical measures of the center and spread can help us better understand the distribution of a quantitative variable. Try the following code to compute the mean, median, standard deviation (SD), and IQR of hwy. The IQR is the interquartile range, the difference between the 3rd quartile (aka 75th percentile, Q3) and 1st quartile. With these additional statistics, how would you describe the distribution of hwy?

vehicles_2015 %>%
  summarize(
    mean_hwy = mean(hwy),
    median_hwy = median(hwy),
    sd_hwy = sd(hwy),
    IQR_hwy = IQR(hwy)
  )

YOUR TURN!

  1. In general, we either use the mean and standard deviation or median and IQR to describe the shape and spread of a distribution. When would you use each and why?

  2. Create a graph to show the distribution of displ and use words and statistics to describe the distribution.

  3. Try examining the distribution of hwy for the entire vehicles dataset. Be sure to use a reasonable number of bins. Describe the distribution using words and statistics.

Other resources

  • For a deeper dive into ggplot with more examples, see my notes from Intro Data Science. In this class we will focus on a smaller subset of graphs than we do in that class. So, don’t feel like you need to know all the material I cover there.

  • You can watch a short video of me using the penguins dataset to do some plotting and summarizing of quantitative variables. You can download the files to follow along below. Save these files as you’ll use them in the next section too.

Univariate visualization/summarization of categorical variables

Research Question: How many 2015 vehicles are Fords?

As you visualize categorical variables, keep in mind:

  • Variability: Are cases evenly spread out among the categories or are some categories more common than others?
  • Context: In the context of your research, what do you learn from the plot or table? How would you describe your findings to a broad audience?

Tables

Use the table below to help answer your question:

vehicles_2015 %>% 
  count(make)

Look at the next two tables. How do they differ? Can you figure out what the code is doing?

vehicles_2015 %>% 
  count(make) %>%  
  mutate(prop = n/sum(n))
vehicles_2015 %>% 
  count(make) %>%  
  mutate(prop = n/sum(n)) %>% 
  arrange(desc(n))

Barplots

Barplots are a good way to visualize the distribution of a categorical variable Try out the code below. This shows two different ways you can create the same barplot.

In the first set of code that uses geom_bar, the function computes the counts for you. You only have to give it an x aesthetic. In the second set of code that uses geom_col, you have to compute the counts (or percentages or whatever you want to be on the x-axis) first and use that as your y aesthetic. This is a good option if you have an already summarized dataset.

vehicles_2015 %>%
  ggplot(aes(x = make)) +
  geom_bar()

vehicles_2015 %>% 
  count(make) %>% 
  mutate(prop = n/sum(n)) %>% 
  ggplot(aes(x = make, y = n)) +
  geom_col()

YOUR TURN!

  1. What are some pros and cons about the graph I created above? How might you fix some of the cons?
  2. Try modifying the code from above to put the proportion, prop, on the y-axis of the barplot rather than the count.

As with histograms, you can make many modifications to barplots. I have illustrated some of them in the plots below.

#Plot 1
vehicles_2015 %>% 
  mutate(make_ordered = fct_infreq(make)) %>% #creates a new variable that is the same as the `make` variable but is in frequency order
  ggplot(aes(y = fct_rev(make_ordered))) + #reverse the order so largest is first, also put it on the y-axis
  geom_bar(fill = "lightblue") +
  labs(x = "Make of vehicle", 
       title = "Number of vehicles (2015)", 
       y = NULL) + # I skip the y-axis label since the title makes it clear
  theme_minimal()

#Plot 2
vehicles_2015 %>% 
  mutate(make_ordered = fct_infreq(make)) %>% 
  count(make_ordered) %>% 
  mutate(prop = n/sum(n)) %>% 
  ggplot(aes(y = fct_rev(make_ordered), x = round(prop,2))) + #`round()` will round the number to the specified number of decimal places - 2 in this case
  geom_point(color = "darkolivegreen") +
  labs(x = "Make of vehicle", 
       title = "Proportion of vehicles (2015)", 
       y = NULL) + # I skip the y-axis label since the title makes it clear
  theme_minimal()

A few suggestions when you create barplots:

  • If there is no natural ordering, display by frequency. The default ordering in R is alphabetical.
  • When there are many categories, flip the coordinates. It is easier to make comparisons and easier to read categories with long names. I actually prefer this when there are only a few categories.
  • Provide useful labels! This is a good thing to do with any type of plot.
  • Plotting dots rather than bars is a good idea if you do not want to start at 0. For example, if you are plotting averages for different categories.

YOUR TURN!

  1. Choose another categorical variable and create a barplot. If you are looking for colors, here is one resource to find some options. R often picks a good default for you. I encourage you to stay away from colors that are distracting to the eye. Summarize your findings in a contextually meaningful way.

  2. Make a barplot using a categorical variable from the larger, vehicles, dataset. Summarize your findings in a contextually meaningful way.

  3. Pick a new quantitative variable from the data set.

  • Construct a histogram. Play around with the bin width, color, etc.
  • Construct a density plot. Play around with the color.
  • Challenge: Do a Google search and try to figure out how to add transparency to the density plot.
  • Describe the shape, center, and spread of the distribution. You should use one statistic for each of the center and spread. Any other interesting features? Summarize your findings in 1-2 short sentences.

Other resources

  • Watch a short video of me doing a couple examples of plotting and summarizing with categorical data. The files to follow along are in the previous section.
LS0tCnRpdGxlOiAiV29ya2luZyB3aXRoIG9uZSB2YXJpYWJsZSIKb3V0cHV0OiAgIAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCgoqKlN0YXRpc3RpY3MgaXMgdGhlIHByYWN0aWNlIG9mIHVzaW5nIGRhdGEgZnJvbSBhIHNhbXBsZSB0byBtYWtlIGluZmVyZW5jZXMgYWJvdXQgc29tZSBicm9hZGVyIHBvcHVsYXRpb24gb2YgaW50ZXJlc3QuKiogVGhpcyBjbGFzcyBmb2N1c2VzIG9uIHVzaW5nIGxpbmVhciBhbmQgbG9naXN0aWMgbW9kZWxzIGJ1aWx0IGZyb20gYSBzYW1wbGUgb2YgZGF0YSB0byBsZWFybiBhYm91dCByZWxhdGlvbnNoaXBzIGluIHRoZSBicm9hZGVyIHBvcHVsYXRpb24gYW5kIHRvIG1ha2UgcHJlZGljdGlvbnMuCgojIyMgU2V0IHVwIFIgU3R1ZGlvCgpBIGNvdXBsZSByZW1pbmRlcnMgZnJvbSB0aGUgW1IgQmFzaWNzXShodHRwczovL3ItYmFzaWNzLm5ldGxpZnkuYXBwLykgZG9jdW1lbnQuIEdvIHRvIFRvb2xzIC0tPiBHbG9iYWwgT3B0aW9ucy4gT24gdGhlIEdlbmVyYWwgdGFiLCBuZXh0IHRvICpTYXZlIHdvcmtzcGFjZSB0byAuUkRhdGEgb24gZXhpdCosIGNob29zZSAqTmV2ZXIqIGFuZCB1bmNoZWNrIHRoZSBib3ggbmV4dCB0byAqUmVzdG9yZSAuUmRhdGEgaW50byB3b3Jrc3BhY2UgYXQgc3RhcnR1cCouIFlvdSBjYW4gYWxzbyBnbyB0byB0aGUgQXBwZWFyYW5jZSB0YWIgdG8gY3VzdG9taXplIHRoZSBsb29rIG9mIFIgU3R1ZGlvLiBTb21lIHBlb3BsZSBsaWtlIGJsYWNrIHNjcmVlbnMgYmV0dGVyIHRoYW4gd2hpdGUuCgpTYXZlIHRoaXMgZmlsZSB0byBzb21ld2hlcmUgKipPVEhFUiBUSEFOIFlPVVIgRE9XTkxPQURTIEZPTERFUioqISBTYXZlIG9mdGVuLgoKIyMjIEluc3RhbGwgbmV3IGxpYnJhcmllcyBhbmQgbG9hZCB0aGUgbGlicmFyaWVzIHdlIHdpbGwgdXNlCgpXZSBuZWVkIHRvIGluc3RhbGwgYW55IG5ldyBwYWNrYWdlcyB3ZSBwbGFuIHRvIGxvYWQgaW4gYW4gUiBtYXJrZG93biBkb2N1bWVudC4gT25jZSBpbnN0YWxsZWQsIHlvdSB3b24ndCBoYXZlIHRvIGluc3RhbGwgdGhlbSBhZ2Fpbi4gVG9kYXksIHdlIG5lZWQgdG8gaW5zdGFsbCB0aGUgYHRpZHl2ZXJzZWAgYW5kIGBmdWVsZWNvbm9teWAgcGFja2FnZXMuIFlvdSBjYW4gZWl0aGVyIGdvIHRvIHRoZSBQYWNrYWdlcyB0YWIgYW5kIGNsaWNrIEluc3RhbGwuIFR5cGUgYHRpZHl2ZXJzZWAgYGZ1ZWxlY29ub215YCAoc2VwYXJhdGVkIGJ5IGEgc3BhY2UpIGFuZCBmb2xsb3cgdGhlIHByb21wdHMuIE9yIGVsc2UsICppbiB0aGUgY29uc29sZSosIHR5cGUgYGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIsICJmdWVsZWNvbm9teSIpYC4gCgpUaGVuIHlvdSBsb2FkIHRoZSBsaWJyYXJpZXMgYnkgcnVubmluZyB0aGUgZm9sbG93aW5nIHBpZWNlIG9mIGNvZGUuIFlvdSBuZWVkIHRvIGRvIHRoaXMgaW4gKmV2ZXJ5KiBSIG1hcmtkb3duIGZpbGUgd2hlcmUgeW91IHVzZSBmdW5jdGlvbnMgb3IgZGF0YXNldHMgZnJvbSB0aGVzZSBwYWNrYWdlLiBXZSB3aWxsIGdldCBpbnRvIHRoZSBoYWJpdCBvZiBwdXR0aW5nIHRoZXNlIGF0IHRoZSB2ZXJ5IHRvcCBvZiBvdXIgZG9jdW1lbnRzLiBUaGlzIHdpbGwgYmUgb25lIG9mIHRoZSBvbmx5IGRvY3VtZW50cyB3aGVyZSBJIGRvIG5vdCBoYXZlIGFsbCB0aGUgbGlicmFyaWVzIGxpc3RlZCBhdCB0aGUgdG9wLiBBbHNvIG5vdGUgdGhhdCBJJ3ZlIGFkZGVkIGB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFYCB0byB0aGUgY29kZSBjaHVuayBvcHRpb25zLCBuZXh0IHRvIHRoZSBgcmAuIFRoaXMgd2lsbCBwcmV2ZW50IG1lc3NhZ2VzIGFuZCB3YXJuaW5ncyBmcm9tIGJlaW5nIHByaW50ZWQgb3V0LgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKSAjZm9yIHBsb3R0aW5nIGFuZCBzdW1tYXJpemluZwpsaWJyYXJ5KGZ1ZWxlY29ub215KSAjZm9yIHRoZSBkYXRhc2V0CmBgYAoKCiMjIEludHJvIHRvIEdyYXBoaW5nIERhdGEKCjxjZW50ZXI+CiFbXShpbWFnZXMvbW9kZXJuZGl2ZV9mbG93Y2hhcnRfZXhwbG9yZS5wbmcpe3dpZHRoPSI1MCUifQo8L2NlbnRlcj4KCgo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4KICA8c3Ryb25nPkdPQUw6PC9zdHJvbmc+CgpWaXN1YWxseSBleGFtaW5lIGRpc3RyaWJ1dGlvbnMgb2YgYm90aCBxdWFudGl0YXRpdmUgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gQnkgdGhlIGVuZCBvZiB0aGVzZSBub3RlcyBhbmQgYWN0aXZpdGllcywgeW91IHNob3VsZCBiZSBhYmxlIHRvIGRvIHRoZSBmb2xsb3dpbmcgdGFza3MuCgoqIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZSB1c2luZyBhIHJlYXNvbmFibGUgbnVtYmVyIG9mIGJpbnMgb3IgYmlud2lkdGggc28gdGhhdCB0aGUgZ3JhcGggc2hvd3MgZW5vdWdoIGRldGFpbCBidXQgbm90IHRvbyBtdWNoLiAgCiogRGVzY3JpYmUgdGhlIHNoYXBlLCBjZW50ZXIsIGFuZCBzcHJlYWQgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4gT25seSBvbmUgc3RhdGlzdGljIHNob3VsZCBiZSB1c2UgdG8gZGVzY3JpYmUgZWFjaCBvZiB0aGUgc2hhcGUgYW5kIHNwcmVhZCwgdXN1YWxseSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb3IgbWVkaWFuIGFuZCBJUVIuIAoqIENyZWF0ZSBhIHRhYmxlIHRvIHN1bW1hcml6ZSBob3cgb2Z0ZW4gZWFjaCBsZXZlbCBvZiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIG9jY3Vycy4gU29ydCB0aGUgdGFibGUgZnJvbSBsYXJnZXN0IHRvIHNtYWxsZXN0IG9yIHNtYWxsZXN0IHRvIGxhcmdlc3QuICAKKiBDcmVhdGUgYSBiYXJwbG90IHRvIHZpc3VhbGx5IHNob3cgaG93IG9mdGVuIGVhY2ggbGV2ZWwgb2YgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBvY2N1cnMuIAoKPC9kaXY+CgoKVXN1YWxseSBvbmUgb2YgdGhlIGZpcnN0IHRoaW5ncyB3ZSB3YW50IHRvIGRvIHdpdGggbmV3IGRhdGEgaXMgdmlzdWFsaXplIGl0LiBJZiB5b3UgaGF2ZW4ndCB3YW50ZWQgdG8gZG8gdGhpcyBpbiB0aGUgcGFzdCwgeW91J2xsIHdhbnQgdG8gZG8gaXQgbm93IGJlY2F1c2UgaXQncyBnb2luZyB0byBiZSBzbyBlYXN5ISBXZSB3aWxsIHVzZSBmdW5jdGlvbnMgZnJvbSBhIHBhY2thZ2UgY2FsbGVkIGBnZ3Bsb3QyYCB0byBjcmVhdGUgIG91ciB2aXN1YWxpemF0aW9ucy4gVGhpcyBwYWNrYWdlIGlzIGJhc2VkIG9uIGEgdmlzdWFsaXphdGlvbiBmcmFtZXdvcmsgY2FsbGVkIHRoZSBbIkdyYW1tYXIgb2YgR3JhcGhpY3MiXShodHRwczovL3d3dy5hbWF6b24uY29tL0dyYW1tYXItR3JhcGhpY3MtU3RhdGlzdGljcy1Db21wdXRpbmcvZHAvMDM4NzI0NTQ0OCkuIFdlIHdpbGwgb25seSBkaXNjdXNzIGEgZmV3IGtleSBkZXRhaWxzIG9mIHRoZSBmcmFtZXdvcms6IGRhdGEsIGdlb21ldHJpYyBvYmplY3RzLCBhbmQgYWVzdGhldGljIGF0dHJpYnV0ZXMuIFRoZSBtYWluIGlkZWEgaXMgdGhhdCAiQSBzdGF0aXN0aWNhbCBncmFwaGljIGlzIGEgbWFwcGluZyBvZiBkYXRhIHZhcmlhYmxlcyB0byBhZXN0aGV0aWMgYXR0cmlidXRlcyBvZiBnZW9tZXRyaWMgb2JqZWN0cy4iCgoxLiBEYXRhOiBPdXIgZGF0YSBzZXQgdGhhdCBjb250YWlucyAqdmFyaWFibGVzKiAodGhlIGNvbHVtbnMpIHdpdGggbWFueSAqb2JzZXJ2YXRpb25zKiAodGhlIHJvd3MpLiAgCjIuIEdlb21ldHJpYyBvYmplY3RzOiBXaGF0IHdlIG9ic2VydmUgb24gb3VyIHBsb3QgLSBwb2ludHMsIGxpbmVzLCBiYXJzLCBldGMuIAozLiBBZXN0aGV0aWMgYXR0cmlidXRlczogcGFydHMgb2YgdGhlIGdlb21ldHJpYyBvYmplY3QgdGhhdCB3ZSBvYnNlcnZlOiB4L3kgcG9zaXRpb24sIGNvbG9yLCBzaGFwZSwgc2l6ZSwgZXRjLgoKSW4gZ2VuZXJhbCwgYSBiYXNpYyBwbG90IGNhbiBiZSBjcmVhdGVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgdGVtcGxhdGUsIHdoZXJlIGV2ZXJ5dGhpbmcgYmV0d2VlbiB0aGUgYDw+YCB3b3VsZCBiZSBtb2RpZmllZCB0byBmaXQgeW91ciBuZWVkcy4KCmBgYApnZ3Bsb3QoZGF0YSA9IDxEQVRBPikgKwogIDxHRU9NX0ZVTkNUSU9OPihtYXBwaW5nID0gYWVzKDxNQVBQSU5HUz4pKQpgYGAKCldlIGNvdWxkIGFsc28gd3JpdGUgaXQgbGlrZSB0aGlzOgoKYGBgCjxEQVRBPiAlPiUgCiAgZ2dwbG90KCkgKwogIDxHRU9NX0ZVTkNUSU9OPihtYXBwaW5nID0gYWVzKDxNQVBQSU5HUz4pKQpgYGAgCgoqKk5PVEUqKjogVGhlIGAlPiVgIGlzIGNhbGxlZCBhICoqcGlwZSBvcGVyYXRvcioqLiBJdCBzaG91bGQgYmUgcmVhZCwgImFuZCB0aGVuLiIgSXQgaXMgdXNlZCB0byAicGlwZSIgdGhlIG9iamVjdCBiZWZvcmUgaXQvb24gaXRzIGxlZnQgaW50byB0aGUgZnVuY3Rpb24gYWZ0ZXIgaXQvb24gaXRzIHJpZ2h0LiBJdCBtYWtlcyBmb3IgbW9yZSByZWFkYWJsZSBjb2RlLiBJbiBSIFN0dWRpbywgdGhlIGtleWJvYXJkIHNob3J0Y3V0cyB0byB0eXBlIHRoZSBwaXBlIGFyZSBgQ3RybCtTaGlmdCtNYCBvbiBXaW5kb3dzIGFuZCBgQ21kK1NoaWZ0K01gIG9uIE1hY3MuCgpUaGUgZ2dwbG90MiBbY2hlYXRzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLykgaXMgYSBnb29kIHJlZmVyZW5jZSB0aGF0IEkgd291bGQgZW5jb3VyYWdlIHlvdSB0byBoYXZlIG9wZW4gYXMgd2UgZ28gdGhyb3VnaCBleGFtcGxlcy4gCgpXZSB3aWxsIGFsc28gYmUgZG9pbmcgc29tZSBiYXNpYyBkYXRhIHN1bW1hcmllcyB1c2luZyB0aGUgYGRwbHlyYCBwYWNrYWdlLiBCb3RoIGBkcGx5cmAgYW5kIGBnZ3Bsb3QyYCBhcmUgcGFydCBvZiB0aGUgYHRpZHl2ZXJzZWAgcGFja2FnZSwgd2hpY2ggaXMgYSBjb2xsZWN0aW9uIG9mIHBhY2thZ2VzIHRoYXQgYXJlIHVzZWZ1bCBpbiBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIG1hbmlwdWxhdGlvbi4gV2UgYWxyZWFkeSBpbnN0YWxsZWQgYW5kIGxvYWRlZCB0aGlzIHBhY2thZ2UuCgoqKlRoZSBkYXRhKio6IFdlIHdpbGwgdXNlIGEgc3Vic2V0IG9mIHRoZSBgdmVoaWNsZXNgIGRhdGEgZnJvbSB0aGUgYGZ1ZWxlY29ub215YCBsaWJyYXJ5IHRocm91Z2hvdXQuIFRoZXNlIGFyZSBmdWVsIGVjb25vbXkgZGF0YSBmcm9tIHRoZSBbRVBBXShodHRwczovL3d3dy5mdWVsZWNvbm9teS5nb3YvZmVnL2Rvd25sb2FkLnNodG1sKS4gU29tZSB2YXJpYWJsZXMgaGF2ZSBiZWVuIGV4Y2x1ZGVkIG9yIG1vZGlmaWVkIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQuIEZvciBtb3JlIGRldGFpbHMgc2VhcmNoIGZvciBgdmVoaWNsZXNgIGluIHRoZSBIZWxwIHNlY3Rpb24gb3IgcnVuIGA/dmVoaWNsZXNgIGluIHRoZSBjb25zb2xlLgpGaXJzdCwgdGFrZSBhIG1vbWVudCB0byBleHBsb3JlIHRoYXQgZGF0YSBhbmQgc2VlIHdoYXQgaXMgdGhlcmUuIFJ1biB0aGUgY29kZSBiZWxvdyBhbmQgdGhlbiB0cnkgdG8gYW5zd2VyIHRoZSBxdWVzdGlvbnMgYmVsb3cuIERvbid0IHdvcnJ5IGFib3V0IHRoZSBjb2RlIHN5bnRheCBmb3Igbm93LgoKYGBge3J9CiMgRmlyc3QsIGZpbHRlciB2ZWhpY2xlcyB0byAyMDE1IHZlaGljbGVzCiMgU2F2ZSB0byBhIGRhdGFzZXQgY2FsbGVkIHZlaGljbGVzXzIwMTUKdmVoaWNsZXNfMjAxNSA8LSB2ZWhpY2xlcyAlPiUgZmlsdGVyKHllYXIgPT0gMjAxNSkKCiMgR2l2ZSBiYXNpYyBzdW1tYXJ5IHN0YXRzIG9mIGVhY2ggdmFyaWFibGUKdmVoaWNsZXNfMjAxNSAlPiUgCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCBhcy5mYWN0b3IpKSAlPiUgCiAgc3VtbWFyeSgpCmBgYAoKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgogIDxzdHJvbmc+WU9VUiBUVVJOITwvc3Ryb25nPiAKICAKQ2hlY2sgb3V0IHRoZSBiYXNpYyBmZWF0dXJlcyBvZiB0aGUgZGF0YXNldDoKCiogRXhhbWluZSB0aGUgZmlyc3Qgc2l4IGNhc2VzLiAoV2hhdCBhcmUgdGhlIGNhc2VzPykgIAoqIEhvdyBtYW55IGNhc2VzIGFuZCB2YXJpYWJsZXMgYXJlIHRoZXJlPyAgCiogV2hhdCBhcmUgdGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXM/ICAKKiBPcGVuIHRoZSBkYXRhc2V0IGluIGEgc3ByZWFkc2hlZXQgdHlwZSB2aWV3ZXIgKHR5cGUgYFZpZXcodmVoaWNsZXNfMjAxNSlgIGluIHRoZSBjb25zb2xlIG9yIGNsaWNrIG9uIGl0IG92ZXIgaW4gdGhlIEVudmlyb25tZW50KS4gU2Nyb2xsIHRocm91Z2ggc29tZSBvZiB0aGUgZGF0YS4gQW55IHF1ZXN0aW9ucyBhYm91dCB0aGUgZGF0YT8KCldoYXQgYWJvdXQgdGhlIHF1YWxpdHkgb2YgdGhlIGRhdGFzZXQ/CgoqIEhvdyBkbyB5b3UgdGhpbmsgdGhlIGRhdGEgYXJlIGNvbGxlY3RlZD8gVHJ5IGRvaW5nIHNvbWUgc2VhcmNoaW5nIHRvIGxlYXJuIG1vcmUuICAKKiBDYW4geW91IHRoaW5rIG9mIGFueSBjb21wbGljYXRpb25zPwoKPC9kaXY+CgojIyBVbml2YXJpYXRlIHZpc3VhbGl6YXRpb24vc3VtbWFyaXphdGlvbiBvZiBxdWFudGl0YXRpdmUgdmFyaWFibGVzCgoqKlJlc2VhcmNoIHF1ZXN0aW9uczoqKiBXaGF0IGlzIHRoZSByYW5nZSBvZiBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24gKGBod3lgKT8gV2hhdCBhcmUgdHlwaWNhbCBoaWdod2F5IG1wZz8gQXJlIGhpZ2h3YXkgbXBnJ3MgdmFyaWFibGUgYWNyb3NzIHZlaGljbGVzPwoKQXMgeW91IHZpc3VhbGl6ZSBxdWFudGl0YXRpdmUgdmFyaWFibGVzLCBrZWVwIGluIG1pbmQ6CgotICoqQ2VudGVyKio6IFdoZXJlIGlzIHRoZSBjZW50ZXIgb2YgdGhlIGRpc3RyaWJ1dGlvbj8gV2hhdCBpcyBhIHR5cGljYWwgdmFsdWUgb2YgdGhlIHZhcmlhYmxlPwotICoqVmFyaWFiaWxpdHkqKjogSG93IHNwcmVhZCBvdXQgYXJlIHRoZSB2YWx1ZXM/IEEgbG90IG9yIGEgbGl0dGxlPwotICoqU2hhcGUqKjogSG93IGFyZSB2YWx1ZXMgZGlzdHJpYnV0ZWQgYWxvbmcgdGhlIG9ic2VydmVkIHJhbmdlPyBJcyB0aGUgZGlzdHJpYnV0aW9uIHN5bW1ldHJpYywgcmlnaHQtc2tld2VkICh0YWlsIGlzIGxvbmdlciBvbiB0aGUgcmlnaHQsIHB1bGxlZCBmdXJ0aGVyIG91dCB0byB0aGUgcmlnaHQpLCBsZWZ0LXNrZXdlZCwgYmltb2RhbCwgb3IgdW5pZm9ybSAoZmxhdCk/Ci0gKipPdXRsaWVycyoqOiBBcmUgdGhlcmUgYW55IG91dGxpZXJzLCBpLmUuIHZhbHVlcyB0aGF0IGFyZSB1bnVzdWFsbHkgbGFyZ2Uvc21hbGwgcmVsYXRpdmUgdG8gdGhlIGJ1bGsgb2Ygb3RoZXIgdmFsdWVzPwotICoqQ29udGV4dCoqOiBJbiB0aGUgY29udGV4dCBvZiB5b3VyIHJlc2VhcmNoLCB3aGF0IGRvIHlvdSBsZWFybiBmcm9tIHRoZSBwbG90IG9yIHRhYmxlPyBIb3cgd291bGQgeW91IGRlc2NyaWJlIHlvdXIgZmluZGluZ3MgdG8gYSBicm9hZCBhdWRpZW5jZT8KCldlIHdpbGwgb2Z0ZW4gdGFsayBhYm91dCB0aGUgKmRpc3RyaWJ1dGlvbiogb2YgYSB2YXJpYWJsZS4gVGhpcyBpcyB0aGUgdmFsdWVzIHRoZSB2YXJpYWJsZXMgdGFrZSBhbmQgaG93IG9mdGVuLiBZb3Ugc2hvdWxkIGluY29ycG9yYXRlIHRoZSBhbnN3ZXJzIHRvIHRoZSBxdWVzdGlvbnMgYWJvdmUgaW4geW91ciBkZXNjcmlwdGlvbiBvZiBhIGRpc3RyaWJ1dGlvbi4gWW91IHNob3VsZCBhbHNvIHVzZSBudW1lcmljYWwgc3VtbWFyaWVzLCB3aGljaCB3ZSdsbCB0YWxrIGFib3V0IHNob3J0bHkuIFRoaW5rIGFib3V0IHRyeWluZyB0byBkZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uIHRvIHNvbWVvbmUgd2hvIGRvZXNuJ3QgaGF2ZSB0aGUgcGljdHVyZSBpbiBmcm9udCBvZiB0aGVtLgoKIyMjIEhpc3RvZ3JhbXMKCkhpc3RvZ3JhbXMgYXJlIGNvbnN0cnVjdGVkIGJ5ICgxKSBkaXZpZGluZyB1cCB0aGUgb2JzZXJ2ZWQgcmFuZ2Ugb2YgdGhlIHZhcmlhYmxlIGludG8gImJpbnMiIG9mIGVxdWFsIHdpZHRoIGFuZCAoMikgY291bnRpbmcgdXAgdGhlIG51bWJlciBvZiBjYXNlcyB0aGF0IGZhbGwgaW50byBlYWNoIGJpbi4gVHJ5IG91dCB0aGUgY29kZSBiZWxvdy4gTm90aWNlIGl0J3MgdGVsbGluZyB5b3UgdGhhdCBpdCBoYXMgY2hvc2VuIHRoZSBudW1iZXIgb2YgYmlucyBmb3IgeW91OiAzMC4gCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSB2ZWhpY2xlc18yMDE1KSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBod3kpKQpgYGAKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgogIDxzdHJvbmc+WU9VUiBUVVJOITwvc3Ryb25nPiAKICAKICBUcnkgY2hhbmdpbmcgdGhlIG51bWJlciBvZiBiaW5zIChmaWxsIGluIHRoZSBudW1iZXIgb2YgYmlucyBiZWxvdykuIFdoaWNoIG51bWJlciBvZiBiaW5zIHNlZW1zICJiZXN0Ij8gV2h5PwoKYGBge3IsIGV2YWw9RkFMU0V9CmdncGxvdChkYXRhID0gdmVoaWNsZXNfMjAxNSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gaHd5KSwgYmlucyA9IF9fXykKYGBgCgo8L2Rpdj4KCgoKV2UgY2FuIGN1c3RvbWl6ZSBwbG90cyBpbiB2YXJpb3VzIHdheXMsIGxpa2UgSSBkaWQgYmVsb3csIGJ1dCB0aGUgbW9zdCBpbXBvcnRhbnQgcGFydCBpcyBjcmVhdGluZyBhIHBsb3QgdGhhdCBhbGxvd3MgdXMgdG8gc2VlIHRoZSBkaXN0cmlidXRpb24gb2Ygb3VyIHZhcmlhYmxlIG9mIGludGVyZXN0LCBgaHd5YCBpbiB0aGlzIGNhc2UuICAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHZlaGljbGVzXzIwMTUpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGh3eSksIGJpbnMgPSAyNSwgZmlsbCA9ICJsaWdodGJsdWUiKSArCiAgbGFicyh4ID0gIkhpZ2h3YXkgTVBHIiwgCiAgICAgICB5ID0gIk51bWJlciBvZiB2ZWhpY2xlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgCmBgYAoKKipOb3RpY2UqKjogVGhpbmdzIGxpa2UgYmlucywgY29sb3IsIGZpbGwsIGV0Yy4gYXJlICpvdXRzaWRlKiBvZiB0aGUgYWVzdGhldGljIG1hcHBpbmcuIFJlbWVtYmVyIHRoYXQgYWxsIHRoZSBhcmd1bWVudHMgKmluc2lkZSogdGhlIGFlc3RoZXRpYyBtYXAgdmFyaWFibGVzIHRvIGFlc3RoZXRpY3MuIEV2ZXJ5dGhpbmcgZWxzZSBoYXBwZW5zIG91dHNpZGUgb2YgdGhlIGFlc3RoZXRpYy4KCgojIyMgRGVuc2l0eSBQbG90cwoKQSBkZW5zaXR5IHBsb3QgaXMgZXNzZW50aWFsbHkgYSBzbW9vdGggdmVyc2lvbiBvZiB0aGUgaGlzdG9ncmFtLiBJbnN0ZWFkIG9mIHNvcnRpbmcgY2FzZXMgaW50byBkaXNjcmV0ZSBiaW5zLCB0aGUgImRlbnNpdHkiIG9mIGNhc2VzIGlzIGNhbGN1bGF0ZWQgYWNyb3NzIHRoZSBlbnRpcmUgcmFuZ2Ugb2YgdmFsdWVzLiBUaGUgZ3JlYXRlciB0aGUgbnVtYmVyIG9mIGNhc2VzLCB0aGUgZ3JlYXRlciB0aGUgZGVuc2l0eSEgVGhlIGRlbnNpdHkgaXMgdGhlbiBzY2FsZWQgc28gdGhhdCB0aGUgYXJlYSB1bmRlciB0aGUgZGVuc2l0eSBjdXJ2ZSAqKmFsd2F5cyBlcXVhbHMgMSoqLCBhbmQgdGhlIGFyZWEgdW5kZXIgYW55IHJlZ2lvbiBvZiB0aGUgY3VydmUgcmVwcmVzZW50cyB0aGUgZnJhY3Rpb24gb2YgY2FzZXMgdGhhdCBsaWUgaW4gdGhhdCByYW5nZS4gRGVuc2l0eSBwbG90cyBjYW4gYmUgZXNwZWNpYWxseSBoZWxwZnVsIHdoZW4gd29ya2luZyB3aXRoIHZlcnkgbGFyZ2UgZGF0YXNldHMgKGF0IGxlYXN0IDEwLDAwMCBvYnNlcnZhdGlvbnMpLgoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+CiAgPHN0cm9uZz5ZT1VSIFRVUk4hPC9zdHJvbmc+CiAgClJ1biBhbmQgbW9kaWZ5IHRoZSBmb2xsb3dpbmcgY29kZSB0byBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgaGlnaHdheSBtcGcgZm9yIEFsbC1XaGVlbCBEcml2ZSBhbmQgRnJvbnQtV2hlZWwgRHJpdmUgdmVoaWNsZXMuIFdoYXQgd291bGQgeW91IHJlbWFyayBhYm91dCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvPyAoVGhpbmsgYmFjayB0byBjZW50ZXIsIHZhcmlhYmlsaXR5LCBzaGFwZSwgb3V0bGllcnMsIGFuZCBzY2llbnRpZmljIGNvbnRleHQuKSBJcyBpdCBlYXN5IHRvIG1ha2UgdGhlc2UgY29tcGFyaXNvbnM/CgpgYGB7ciBldmFsPUZBTFNFfQp2ZWhpY2xlc18yMDE1ICU+JQogIGZpbHRlcihkcml2ZSA9PSAiQWxsLVdoZWVsIERyaXZlIikgJT4lIAogIGdncGxvdChhZXMoeD1od3kpKSArCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAib3JhbmdlIikgCgp2ZWhpY2xlc18yMDE1ICU+JQogIGZpbHRlcihfX19fX19fX19fX18pICU+JSAKICBnZ3Bsb3QoYWVzKHg9aHd5KSkgKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKPC9kaXY+CgojIyMgTWVhc3VyZXMgb2YgQ2VudGVyIGFuZCBTcHJlYWQKCk51bWVyaWNhbCBtZWFzdXJlcyBvZiB0aGUgY2VudGVyIGFuZCBzcHJlYWQgY2FuIGhlbHAgdXMgYmV0dGVyIHVuZGVyc3RhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4gVHJ5IHRoZSBmb2xsb3dpbmcgY29kZSB0byBjb21wdXRlIHRoZSBtZWFuLCBtZWRpYW4sIHN0YW5kYXJkIGRldmlhdGlvbiAoU0QpLCBhbmQgSVFSIG9mIGBod3lgLiBUaGUgSVFSIGlzIHRoZSBpbnRlcnF1YXJ0aWxlIHJhbmdlLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSAzcmQgcXVhcnRpbGUgKGFrYSA3NXRoIHBlcmNlbnRpbGUsIFEzKSBhbmQgMXN0IHF1YXJ0aWxlLiBXaXRoIHRoZXNlIGFkZGl0aW9uYWwgc3RhdGlzdGljcywgaG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGBod3lgPwoKYGBge3J9CnZlaGljbGVzXzIwMTUgJT4lCiAgc3VtbWFyaXplKAogICAgbWVhbl9od3kgPSBtZWFuKGh3eSksCiAgICBtZWRpYW5faHd5ID0gbWVkaWFuKGh3eSksCiAgICBzZF9od3kgPSBzZChod3kpLAogICAgSVFSX2h3eSA9IElRUihod3kpCiAgKQpgYGAKCgoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+CiAgPHN0cm9uZz5ZT1VSIFRVUk4hPC9zdHJvbmc+CgoxLiBJbiBnZW5lcmFsLCB3ZSBlaXRoZXIgdXNlIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb3IgbWVkaWFuIGFuZCBJUVIgdG8gZGVzY3JpYmUgdGhlIHNoYXBlIGFuZCBzcHJlYWQgb2YgYSBkaXN0cmlidXRpb24uIFdoZW4gd291bGQgeW91IHVzZSBlYWNoIGFuZCB3aHk/CgoyLiBDcmVhdGUgYSBncmFwaCB0byBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgYGRpc3BsYCBhbmQgdXNlIHdvcmRzIGFuZCBzdGF0aXN0aWNzIHRvIGRlc2NyaWJlIHRoZSBkaXN0cmlidXRpb24uIAoKMy4gVHJ5IGV4YW1pbmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGBod3lgIGZvciB0aGUgZW50aXJlIGB2ZWhpY2xlc2AgZGF0YXNldC4gQmUgc3VyZSB0byB1c2UgYSByZWFzb25hYmxlIG51bWJlciBvZiBiaW5zLiBEZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uIHVzaW5nIHdvcmRzIGFuZCBzdGF0aXN0aWNzLiAKCjwvZGl2PgoKCiMjIyBPdGhlciByZXNvdXJjZXMKCiogRm9yIGEgZGVlcGVyIGRpdmUgaW50byBgZ2dwbG90YCB3aXRoIG1vcmUgZXhhbXBsZXMsIHNlZSBteSBbbm90ZXNdKGh0dHBzOi8vZ2dwbG90LWRwbHlyLWludHJvLm5ldGxpZnkuYXBwLyNjcmVhdGluZy1ncmFwaHMtd2l0aC1nZ3Bsb3QpIGZyb20gSW50cm8gRGF0YSBTY2llbmNlLiBJbiB0aGlzIGNsYXNzIHdlIHdpbGwgZm9jdXMgb24gYSBzbWFsbGVyIHN1YnNldCBvZiBncmFwaHMgdGhhbiB3ZSBkbyBpbiB0aGF0IGNsYXNzLiBTbywgZG9uJ3QgZmVlbCBsaWtlIHlvdSBuZWVkIHRvIGtub3cgYWxsIHRoZSBtYXRlcmlhbCBJIGNvdmVyIHRoZXJlLiAKCiogWW91IGNhbiB3YXRjaCBhIFtzaG9ydCB2aWRlb10oaHR0cHM6Ly95b3V0dS5iZS9LMVN1RDQzSU5MUSkgb2YgbWUgdXNpbmcgdGhlIGBwZW5ndWluc2AgZGF0YXNldCB0byBkbyBzb21lIHBsb3R0aW5nIGFuZCBzdW1tYXJpemluZyBvZiBxdWFudGl0YXRpdmUgdmFyaWFibGVzLiBZb3UgY2FuIGRvd25sb2FkIHRoZSBmaWxlcyB0byBmb2xsb3cgYWxvbmcgYmVsb3cuIFNhdmUgdGhlc2UgZmlsZXMgYXMgeW91J2xsIHVzZSB0aGVtIGluIHRoZSBuZXh0IHNlY3Rpb24gdG9vLgoKYGBge3IsIGVjaG89RkFMU0V9CmxpYnJhcnkoZG93bmxvYWR0aGlzKQpkb3dubG9hZF9maWxlKAogIHBhdGggPSAiLi4vZGVtb3MvMDBfdW5pdmFyaWF0ZV9ub19jb2RlLlJtZCIsCiAgYnV0dG9uX2xhYmVsID0gIkRvd25sb2FkIGRlbW8gZmlsZSAod2l0aG91dCBjb2RlKSIsCiAgYnV0dG9uX3R5cGUgPSAid2FybmluZyIsCiAgaGFzX2ljb24gPSBUUlVFLAogIGljb24gPSAiZmEgZmEtc2F2ZSIsCiAgc2VsZl9jb250YWluZWQgPSBGQUxTRQopCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmRvd25sb2FkX2ZpbGUoCiAgcGF0aCA9ICIuLi9kZW1vcy8wMF91bml2YXJpYXRlX2NvZGUuUm1kIiwKICBidXR0b25fbGFiZWwgPSAiRG93bmxvYWQgZGVtbyBmaWxlICh3aXRoIGNvZGUpIiwKICBidXR0b25fdHlwZSA9ICJpbmZvIiwKICBoYXNfaWNvbiA9IFRSVUUsCiAgaWNvbiA9ICJmYSBmYS1zYXZlIiwKICBzZWxmX2NvbnRhaW5lZCA9IEZBTFNFCikKYGBgCgojIyBVbml2YXJpYXRlIHZpc3VhbGl6YXRpb24vc3VtbWFyaXphdGlvbiBvZiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKCioqUmVzZWFyY2ggUXVlc3Rpb24qKjogSG93IG1hbnkgMjAxNSB2ZWhpY2xlcyBhcmUgRm9yZHM/CgpBcyB5b3UgdmlzdWFsaXplIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywga2VlcCBpbiBtaW5kOgoKLSAqKlZhcmlhYmlsaXR5Kio6IEFyZSBjYXNlcyBldmVubHkgc3ByZWFkIG91dCBhbW9uZyB0aGUgY2F0ZWdvcmllcyBvciBhcmUgc29tZSBjYXRlZ29yaWVzIG1vcmUgY29tbW9uIHRoYW4gb3RoZXJzPwotICoqQ29udGV4dCoqOiBJbiB0aGUgY29udGV4dCBvZiB5b3VyIHJlc2VhcmNoLCB3aGF0IGRvIHlvdSBsZWFybiBmcm9tIHRoZSBwbG90IG9yIHRhYmxlPyBIb3cgd291bGQgeW91IGRlc2NyaWJlIHlvdXIgZmluZGluZ3MgdG8gYSBicm9hZCBhdWRpZW5jZT8KCiMjIyBUYWJsZXMKClVzZSB0aGUgdGFibGUgYmVsb3cgdG8gaGVscCBhbnN3ZXIgeW91ciBxdWVzdGlvbjoKCmBgYHtyfQp2ZWhpY2xlc18yMDE1ICU+JSAKICBjb3VudChtYWtlKQpgYGAKCkxvb2sgYXQgdGhlIG5leHQgdHdvIHRhYmxlcy4gSG93IGRvIHRoZXkgZGlmZmVyPyBDYW4geW91IGZpZ3VyZSBvdXQgd2hhdCB0aGUgY29kZSBpcyBkb2luZz8KCmBgYHtyfQp2ZWhpY2xlc18yMDE1ICU+JSAKICBjb3VudChtYWtlKSAlPiUgIAogIG11dGF0ZShwcm9wID0gbi9zdW0obikpCgp2ZWhpY2xlc18yMDE1ICU+JSAKICBjb3VudChtYWtlKSAlPiUgIAogIG11dGF0ZShwcm9wID0gbi9zdW0obikpICU+JSAKICBhcnJhbmdlKGRlc2MobikpCmBgYAoKCiMjIyBCYXJwbG90cwoKQmFycGxvdHMgYXJlIGEgZ29vZCB3YXkgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBUcnkgb3V0IHRoZSBjb2RlIGJlbG93LiBUaGlzIHNob3dzIHR3byBkaWZmZXJlbnQgd2F5cyB5b3UgY2FuIGNyZWF0ZSB0aGUgc2FtZSBiYXJwbG90LiAKCkluIHRoZSBmaXJzdCBzZXQgb2YgY29kZSB0aGF0IHVzZXMgYGdlb21fYmFyYCwgdGhlIGZ1bmN0aW9uIGNvbXB1dGVzIHRoZSBjb3VudHMgZm9yIHlvdS4gWW91IG9ubHkgaGF2ZSB0byBnaXZlIGl0IGFuIGB4YCBhZXN0aGV0aWMuIEluIHRoZSBzZWNvbmQgc2V0IG9mIGNvZGUgdGhhdCB1c2VzIGBnZW9tX2NvbGAsIHlvdSBoYXZlIHRvIGNvbXB1dGUgdGhlIGNvdW50cyAob3IgcGVyY2VudGFnZXMgb3Igd2hhdGV2ZXIgeW91IHdhbnQgdG8gYmUgb24gdGhlIHgtYXhpcykgZmlyc3QgYW5kIHVzZSB0aGF0IGFzIHlvdXIgYHlgIGFlc3RoZXRpYy4gVGhpcyBpcyBhIGdvb2Qgb3B0aW9uIGlmIHlvdSBoYXZlIGFuIGFscmVhZHkgc3VtbWFyaXplZCBkYXRhc2V0LiAKCmBgYHtyfQp2ZWhpY2xlc18yMDE1ICU+JQogIGdncGxvdChhZXMoeCA9IG1ha2UpKSArCiAgZ2VvbV9iYXIoKQoKdmVoaWNsZXNfMjAxNSAlPiUgCiAgY291bnQobWFrZSkgJT4lIAogIG11dGF0ZShwcm9wID0gbi9zdW0obikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBtYWtlLCB5ID0gbikpICsKICBnZW9tX2NvbCgpCmBgYAoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+CiAgPHN0cm9uZz5ZT1VSIFRVUk4hPC9zdHJvbmc+CiAgCiAgMS4gV2hhdCBhcmUgc29tZSBwcm9zIGFuZCBjb25zIGFib3V0IHRoZSBncmFwaCBJIGNyZWF0ZWQgYWJvdmU/IEhvdyBtaWdodCB5b3UgZml4IHNvbWUgb2YgdGhlIGNvbnM/ICAKICAyLiBUcnkgbW9kaWZ5aW5nIHRoZSBjb2RlIGZyb20gYWJvdmUgdG8gcHV0IHRoZSBwcm9wb3J0aW9uLCBgcHJvcGAsIG9uIHRoZSB5LWF4aXMgb2YgdGhlIGJhcnBsb3QgcmF0aGVyIHRoYW4gdGhlIGNvdW50LgoKPC9kaXY+CgpBcyB3aXRoIGhpc3RvZ3JhbXMsIHlvdSBjYW4gbWFrZSBtYW55IG1vZGlmaWNhdGlvbnMgdG8gYmFycGxvdHMuIEkgaGF2ZSBpbGx1c3RyYXRlZCBzb21lIG9mIHRoZW0gaW4gdGhlIHBsb3RzIGJlbG93LiAKCmBgYHtyfQojUGxvdCAxCnZlaGljbGVzXzIwMTUgJT4lIAogIG11dGF0ZShtYWtlX29yZGVyZWQgPSBmY3RfaW5mcmVxKG1ha2UpKSAlPiUgI2NyZWF0ZXMgYSBuZXcgdmFyaWFibGUgdGhhdCBpcyB0aGUgc2FtZSBhcyB0aGUgYG1ha2VgIHZhcmlhYmxlIGJ1dCBpcyBpbiBmcmVxdWVuY3kgb3JkZXIKICBnZ3Bsb3QoYWVzKHkgPSBmY3RfcmV2KG1ha2Vfb3JkZXJlZCkpKSArICNyZXZlcnNlIHRoZSBvcmRlciBzbyBsYXJnZXN0IGlzIGZpcnN0LCBhbHNvIHB1dCBpdCBvbiB0aGUgeS1heGlzCiAgZ2VvbV9iYXIoZmlsbCA9ICJsaWdodGJsdWUiKSArCiAgbGFicyh4ID0gIk1ha2Ugb2YgdmVoaWNsZSIsIAogICAgICAgdGl0bGUgPSAiTnVtYmVyIG9mIHZlaGljbGVzICgyMDE1KSIsIAogICAgICAgeSA9IE5VTEwpICsgIyBJIHNraXAgdGhlIHktYXhpcyBsYWJlbCBzaW5jZSB0aGUgdGl0bGUgbWFrZXMgaXQgY2xlYXIKICB0aGVtZV9taW5pbWFsKCkKCiNQbG90IDIKdmVoaWNsZXNfMjAxNSAlPiUgCiAgbXV0YXRlKG1ha2Vfb3JkZXJlZCA9IGZjdF9pbmZyZXEobWFrZSkpICU+JSAKICBjb3VudChtYWtlX29yZGVyZWQpICU+JSAKICBtdXRhdGUocHJvcCA9IG4vc3VtKG4pKSAlPiUgCiAgZ2dwbG90KGFlcyh5ID0gZmN0X3JldihtYWtlX29yZGVyZWQpLCB4ID0gcm91bmQocHJvcCwyKSkpICsgI2Byb3VuZCgpYCB3aWxsIHJvdW5kIHRoZSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgLSAyIGluIHRoaXMgY2FzZQogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya29saXZlZ3JlZW4iKSArCiAgbGFicyh4ID0gIk1ha2Ugb2YgdmVoaWNsZSIsIAogICAgICAgdGl0bGUgPSAiUHJvcG9ydGlvbiBvZiB2ZWhpY2xlcyAoMjAxNSkiLCAKICAgICAgIHkgPSBOVUxMKSArICMgSSBza2lwIHRoZSB5LWF4aXMgbGFiZWwgc2luY2UgdGhlIHRpdGxlIG1ha2VzIGl0IGNsZWFyCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKCkEgZmV3IHN1Z2dlc3Rpb25zIHdoZW4geW91IGNyZWF0ZSBiYXJwbG90czoKCiogSWYgdGhlcmUgaXMgbm8gbmF0dXJhbCBvcmRlcmluZywgZGlzcGxheSBieSBmcmVxdWVuY3kuIFRoZSBkZWZhdWx0IG9yZGVyaW5nIGluIFIgaXMgYWxwaGFiZXRpY2FsLiAgCiogV2hlbiB0aGVyZSBhcmUgbWFueSBjYXRlZ29yaWVzLCBmbGlwIHRoZSBjb29yZGluYXRlcy4gSXQgaXMgZWFzaWVyIHRvIG1ha2UgY29tcGFyaXNvbnMgYW5kIGVhc2llciB0byByZWFkIGNhdGVnb3JpZXMgd2l0aCBsb25nIG5hbWVzLiBJIGFjdHVhbGx5IHByZWZlciB0aGlzIHdoZW4gdGhlcmUgYXJlIG9ubHkgYSBmZXcgY2F0ZWdvcmllcy4gIAoqIFByb3ZpZGUgdXNlZnVsIGxhYmVscyEgVGhpcyBpcyBhIGdvb2QgdGhpbmcgdG8gZG8gd2l0aCBhbnkgdHlwZSBvZiBwbG90LiAgCiogUGxvdHRpbmcgZG90cyByYXRoZXIgdGhhbiBiYXJzIGlzIGEgZ29vZCBpZGVhIGlmIHlvdSBkbyBub3Qgd2FudCB0byBzdGFydCBhdCAwLiBGb3IgZXhhbXBsZSwgaWYgeW91IGFyZSBwbG90dGluZyBhdmVyYWdlcyBmb3IgZGlmZmVyZW50IGNhdGVnb3JpZXMuCgo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4KICA8c3Ryb25nPllPVVIgVFVSTiE8L3N0cm9uZz4KICAKMS4gQ2hvb3NlIGFub3RoZXIgY2F0ZWdvcmljYWwgdmFyaWFibGUgYW5kIGNyZWF0ZSBhIGJhcnBsb3QuIElmIHlvdSBhcmUgbG9va2luZyBmb3IgY29sb3JzLCBbaGVyZV0oaHR0cHM6Ly93d3cuci1ncmFwaC1nYWxsZXJ5LmNvbS9nZ3Bsb3QyLWNvbG9yLmh0bWwpIGlzIG9uZSByZXNvdXJjZSB0byBmaW5kIHNvbWUgb3B0aW9ucy4gUiBvZnRlbiBwaWNrcyBhIGdvb2QgZGVmYXVsdCBmb3IgeW91LiBJIGVuY291cmFnZSB5b3UgdG8gc3RheSBhd2F5IGZyb20gY29sb3JzIHRoYXQgYXJlIGRpc3RyYWN0aW5nIHRvIHRoZSBleWUuIFN1bW1hcml6ZSB5b3VyIGZpbmRpbmdzICppbiBhIGNvbnRleHR1YWxseSBtZWFuaW5nZnVsIHdheSouIAoKMi4gTWFrZSBhIGJhcnBsb3QgdXNpbmcgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBmcm9tIHRoZSBsYXJnZXIsIGB2ZWhpY2xlc2AsIGRhdGFzZXQuIFN1bW1hcml6ZSB5b3VyIGZpbmRpbmdzIGluIGEgY29udGV4dHVhbGx5IG1lYW5pbmdmdWwgd2F5LiAKCjMuIFBpY2sgYSBuZXcgKnF1YW50aXRhdGl2ZSogdmFyaWFibGUgZnJvbSB0aGUgZGF0YSBzZXQuIAogIAogICsgQ29uc3RydWN0IGEgaGlzdG9ncmFtLiBQbGF5IGFyb3VuZCB3aXRoIHRoZSBiaW4gd2lkdGgsIGNvbG9yLCBldGMuICAgIAogICsgQ29uc3RydWN0IGEgZGVuc2l0eSBwbG90LiBQbGF5IGFyb3VuZCB3aXRoIHRoZSBjb2xvci4gIAogICsgQ2hhbGxlbmdlOiBEbyBhIEdvb2dsZSBzZWFyY2ggYW5kIHRyeSB0byBmaWd1cmUgb3V0IGhvdyB0byBhZGQgdHJhbnNwYXJlbmN5IHRvIHRoZSBkZW5zaXR5IHBsb3QuICAKICArIERlc2NyaWJlIHRoZSBzaGFwZSwgY2VudGVyLCBhbmQgc3ByZWFkIG9mIHRoZSBkaXN0cmlidXRpb24uIFlvdSBzaG91bGQgdXNlIG9uZSBzdGF0aXN0aWMgZm9yIGVhY2ggb2YgdGhlIGNlbnRlciBhbmQgc3ByZWFkLiBBbnkgb3RoZXIgaW50ZXJlc3RpbmcgZmVhdHVyZXM/IFN1bW1hcml6ZSB5b3VyIGZpbmRpbmdzIGluIDEtMiBzaG9ydCBzZW50ZW5jZXMuIAoKPC9kaXY+CgojIyMgT3RoZXIgcmVzb3VyY2VzCgoqIFdhdGNoIGEgc2hvcnQgW3ZpZGVvXShodHRwczovL3lvdXR1LmJlL0tWR2tlV1VJS1IwKSBvZiBtZSBkb2luZyBhIGNvdXBsZSBleGFtcGxlcyBvZiBwbG90dGluZyBhbmQgc3VtbWFyaXppbmcgd2l0aCBjYXRlZ29yaWNhbCBkYXRhLiBUaGUgZmlsZXMgdG8gZm9sbG93IGFsb25nIGFyZSBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbi4KCgoK