Welcome to the off-platform project for linear regression in R! There are two main goals of this project. The first is to investigate the datasets that come built-in to R. The second is to learn how to quickly write and interpret linear regression models.
As you move through this project you’ll begin to see that creating and analyzing linear regression model takes very few lines of code. The tricky work of being a data scientist begins to shift from writing your code to explaining your results.
This project is written in an R Notebook. We suggest opening this file using RStudio. If you click the “Preview” button, you should see these instructions rendered to an HTML page. We suggest following along with these instructions from the Preview window while coding along in the provided code blocks.
Let’s get started!
Investigating the R Datasets Package
When you first downloaded R to your computer, you also downloaded several datasets. These can be found in the datasets
package. Let’s begin by investigating this package by looking at the documentation. First make sure the datasets
package is loaded by calling library(datasets)
. Then type ?datasets
in the code block below. You should see the documentation for the datasets
package appear in the “Help” tab in RStudio.
That documentation didn’t tell us much — but it did give us a hint on where to go to find a complete list of the datasets. Call the line of code recommended in the documentation of datasets
. Note that this will open a new tab in RStudio. Make sure to come back to this tab after looking through the datasets.
You should see a list of datasets. The documentation gives us a brief description on the datasets, but it’s still a bit tough to understand what the data actually looks like. You can access a dataset in R using the notation datasets::dataset_name
. For example, take a look at the head of the dataset named ToothGrowth
using the line head(datasets::ToothGrowth)
. What columns exist? You can also simply use ToothGrowth
to access the dataset — you don’t need to include the name of the package that it came from.
Finally, you can pull up the documentation for the data using ?ToothGrowth
. What does the supp
column represent in this case? the treatment values
# Print the head of the ToothGrowth dataset
datasets::ToothGrowth
?ToothGrowth
Great! We now have the tools to explore all of the datasets that come with R. Let’s now think about which ones might be useful for linear regression. With linear regression, we’re looking for a dataset where one column might be explained by another (or in the case of multiple linear regression, one column being explained by multiple other columns).
Try to find at least 3 different datasets that might be good candidates for linear regression. Use the code block below to look up the documentation for several datasets. In the next section we’ll begin the first step of statistical model building — confirming data assumptions.
Confirming Data Assumptions
In this section, we’ll walk through a few datasets that both meet and do not meet the assumptions necessary for linear regression. We’ll also leave space for you to investigate datasets that you’re intrested.
Let’s start be testing the first assumption needed for linear regression — the data needs to be roughly linear. Let’s do that visually using the ggplot2
package (make sure this package is installed and loaded).
To do so, pass your dataset into a call to ggplot()
and include an aes()
with the columns that should go on the x and y axes. Then add a geom_point()
layer. For example, ggplot(cars, aes(speed, dist)) + geom_point()
will create a scatter plot showing the speed of cars on the x axis and the distance it took them to stop on the y axis. Does that look like a linear relationship?
ggplot(cars, aes(speed, dist))+ geom_point()
We also created a graph using the state.x77
dataset where Illiteracy
was on the x axis and Income
was on the y axis. There’s one small hiccup in using this dataset. state.x77
isn’t a data frame. Use as.data.frame(state.x77)
to transform it into a data frame. Does that one look linear?
ggplot(as.data.frame(state.x77), aes(Illiteracy, Income))+
geom_point()

Finally, we created a graph using the pressure
dataset. This dataset describes the relationship between the temperature and vapor pressure of mercury. Plot temperature
on the x axis and pressure
on the y axis. What looks different about this graph?

# Load the ggplot2 package
library(tidyverse)
library(modelr)
options(na.action = na.warn)
library(lubridate)

That third graph certainly didn’t look linear. This looks to be a quadratic or exponential relationship — linear regression wouldn’t be appropriate.
Another way of testing for a linear relationship is to compute the correlation coefficient using cor.test()
. Pass the two columns of your dataset into this function to see the correlation coefficient.
Was there a stronger correlation between the speed and stopping distance in the car dataset or between state illiteracy and state income? Remember, the relationship is stronger if the correlation coefficient is further away from 0.
# Find the correlation coefficient
cor.test(state.x77$Illiteracy, state.x77$Income)
Pearson's product-moment correlation
data: state.x77$Illiteracy and state.x77$Income
t = -3.3668, df = 48, p-value = 0.001505
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.6378257 -0.1807128
sample estimates:
cor
-0.4370752
Finally, let’s check for outliers in the dataset to see if anything looks particularly off. For the cars
dataset, create a boxplot showing the distribuition of the speed
variable. For the state.x77
dataset, create a boxplot showing the distribution of the Illiteracy
dataset. Again, remember that the state.x77
dataset first has to be put into a data frame using as.data.frame()
. You can store this data frame version of the data in a variable if you’d like.
# Create a box plot of your cars datasets.
ggplot(cars)+
geom_boxplot(aes(speed, speed))
Warning: Continuous x aesthetic -- did you forget aes(group=...)?

# Create a box plot of your statte.x77 datasets.
ggplot(as.data.frame(state.x77))+
geom_boxplot(aes(Illiteracy, Illiteracy))
Warning: Continuous x aesthetic -- did you forget aes(group=...)?

While we’re looking at the cars and states datasets, we encourage you to experiment with other datasets as well! Use this space to explore assumptions of linear regression for datasets from the datasets
package that you’re interested.
# Explore other datasets here
ggplot(diamonds)+
geom_boxplot(aes(carat, carat))
Warning: Continuous x aesthetic -- did you forget aes(group=...)?

Making and Assessing the Model
Now that we’ve confirmed the assumptions necessary for linear regression, let’s make the models and see how they do!
Before creating our models, let’s randomly split our data into training and test sets. 60% of the data should go into the training set and 40% of the data should go into the test set. We included set.seed(123)
at the top of our code block. This makes it so that if you re-run your code, the data will be split in the same way every time. It’s still randomly split, but setting the seed allows us to reproduce the random split every time we run our code.
# Setting the randomizer's seed
set.seed(123)
samplecar <- sample(c(TRUE, FALSE), nrow(cars), replace=T, prob=c(0.6, 0.4))
#Split your data into training (60%) and test (40%) sets
traincar <- cars[samplecar, ]
testcar <- cars[!samplecar, ]
set.seed(123)
samplestt <- sample(c(TRUE, FALSE), nrow(state.x77), replace=T, prob=c(0.6, 0.4))
#Split your data into training (60%) and test (40%) sets
trainstt <- state.x77[samplestt, ]
teststt <- state.x77[!samplestt, ]
We can now make our linear regression models using the trainings set! Create a linear regression model using the cars
dataset that predicts dist
based on speed
. Similarly, create a model using the state.x77
dataset that predicts Income
based on Illiteracy
.
# Create your linear regression models
modelcar <- lm(dist~speed, data=traincar)
modelcar
modelstt <- lm(Income~Illiteracy, data = trainstt)
modelstt
Call:
lm(formula = Income ~ Illiteracy, data = trainstt)
Coefficients:
(Intercept) Illiteracy
4739 -360
residual standard error (RSE)
Let’s now look at the RSE of each model using sigma()
. What do these number mean? Remember, the units of RSE are specific to each dataset. Write your answer as a comment in your code block.
# Find the residual standard error(RSE) of each model
# the rse = 15.35, meaning that the actual distance will off from the model by 15.35 miles '''
sigma(modelcar)
[1] 15.35049
sigma(modelstt)
[1] 461.8565
This means that the true distance it takes a car to stop will be 15.35
feet off from what the model predicted, on average. Similarly, the model’s prediction for average income was off by 461.86
dollars on average.
R-squared
But are these numbers good or bad? It’s sometimes hard to tell. Let’s take a look at the R Squared value for each model. As a reminder, you can find R Squared values using this code summary(model)$r.squared
.
Try to articulate what these values mean as a comment in your code. We’ll discuss our results after the code block.
# Find the R Squared value of modelcar
summary(modelcar)$r.squared
[1] 0.7110617
# Find the R Squared value of modelstt
summary(modelstt)$r.squared
[1] 0.2039413
The R Squared value measures the proportion of variance explained. In other words, 71% of the variance found in the car’s stopping distance can be explained by the speed of the car. On the other hand, only 20% of the variance in a state’s income can be explained by the state’s illiteracy level.
Finally, let’s look at the rest of summary()
for each model. This time, focus on the coefficients and the Pr(>|t|)
value of each model. Again, try writing a comment in your code articulating what these values mean. We’ll discuss our results after the code block.
# Find the R Squared value of modelcar
summary(modelcar)
Call:
lm(formula = dist ~ speed, data = traincar)
Residuals:
Min 1Q Median 3Q Max
-28.619 -8.412 -2.793 8.185 42.280
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -24.888 8.851 -2.812 0.00889 **
speed 4.275 0.515 8.301 4.94e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 15.35 on 28 degrees of freedom
Multiple R-squared: 0.7111, Adjusted R-squared: 0.7007
F-statistic: 68.91 on 1 and 28 DF, p-value: 4.944e-09
# Find the R Squared value of modelstt
summary(modelstt)
Call:
lm(formula = Income ~ Illiteracy, data = trainstt)
Residuals:
Min 1Q Median 3Q Max
-792.8 -359.6 -16.8 327.7 1005.2
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4738.8 178.0 26.615 <2e-16 ***
Illiteracy -360.0 134.4 -2.678 0.0122 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 461.9 on 28 degrees of freedom
Multiple R-squared: 0.2039, Adjusted R-squared: 0.1755
F-statistic: 7.173 on 1 and 28 DF, p-value: 0.01224
Just like with the R Squared value, these values are showing that the speed
variable in the cars dataset might be a better fit linear regression than the Illiteracy
variable in the state dataset.
The easiest way to see this is to look at the stars by each coefficient. For the car dataset, the speed
coefficient has three stars, meaning the p-value is less than 0.001
. This means that if there was truly no relationship between speed
and dist
, we would expect to see data like this from about 1 out of 1000 random samples.
On the other hand, the states dataset has a slightly higher p-value for Illiteracy
, and therefore has only one star. A p-value of 0.012
means that if there were no relationship between Illiteracy
and Income
, we would find data that looks like this in about 1 out of every 100 random samples. That’s still pretty good, but we’re about ten times as certain that a relationship exists between the variables in the car dataset.
Once again, we’ve added a code block below for you to do this process on another dataset that you feel might be suitable for linear regression.
# 6. Find the R Squared value of modeldiam
summary(modeldiam)
Call:
lm(formula = price ~ carat, data = train_diam)
Residuals:
Min 1Q Median 3Q Max
-18556.4 -799.3 -18.8 533.7 12735.2
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2253.16 16.68 -135.1 <2e-16 ***
carat 7750.01 18.00 430.5 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1541 on 32578 degrees of freedom
Multiple R-squared: 0.8505, Adjusted R-squared: 0.8505
F-statistic: 1.854e+05 on 1 and 32578 DF, p-value: < 2.2e-16
The easiest way to see this is to look at the stars by each coefficient. For the diamonds dataset, the carat
coefficient has three stars, meaning the p-value is less than 0.001
. This means that if there was truly no relationship between carat
and price
, we would expect to see data like this from about 1 out of 1000 random samples.
Graphing the Residuals and Adding A LOESS Smoother
Nice work! Let’s now graph the residuals. Add a column namedestimate
to your training sets. These columns should be created by calling predict()
using your models as a parameter. Also add a column named residuals
to the training set by calling residuals()
using your models as a parameter.
Once those columns have been created, create a graph that shows both the estimated values and the residuals. Your x and y axes should be the same features, however instead of plotting the original data, plot the estimated values and the residuals.
We also included segments to connect each residual to their corresponding estimate.
pltcar <- traincar %>%
ggplot(aes(speed, dist))+
geom_point(aes(size = abs(residuals)))+
geom_point(aes(y=estimate), color="green")+
geom_smooth(method = "lm")+
geom_smooth(se = FALSE, color="blue")+
geom_segment(aes(xend = speed, yend = estimate), color="red")
pltcar
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Let’s also add a visualization of the model and LOESS smoother to our scatter point. Grab your code for your original scatterplot, but make sure to use your training set rather then the original dataset. Then add geom_smooth(method = "lm")
to visualize the model and geom_smooth(se = FALSE, color = "red")
to add a LOESS smoother.
Do these visualizations confirm what you saw when calculating the R Squared value of each model?
# Add a LOESS smoother to your scatterplot
pltcar <- traincar %>%
ggplot(aes(speed, dist))+
geom_point()+
geom_smooth(method = "lm")+
geom_smooth(se = FALSE, color="red")
pltcar
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Here’s a code block for you to try these visualizations on different datasets.
Upgrading To A Multiple Linear Regression Model
Everything that we’ve done so far seems to indicate that our model for the states dataset is good, but could be better. This is the perfect opportunity to try to upgrade it to a multiple linear regression model. Take a look at the head of that dataset again. Do you think there’s another column that could help explain a state’s Income
? Create a new model using at least two features as predictor variables. Print out the summary()
of that model. How does it compare to your first model?
Again, try to write a few sentences as a comment describing the summary of your new model. After the code block we’ll walk you through our process.
# 6. Find the R Squared value of modeldiam
summary(modelstt2)
Call:
lm(formula = Income ~ Illiteracy + `HS Grad` + Population, data = trainstt)
Residuals:
Min 1Q Median 3Q Max
-742.60 -242.41 -27.38 163.06 927.16
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2220.82211 944.27073 2.352 0.0265 *
Illiteracy -63.22238 188.22968 -0.336 0.7397
`HS Grad` 37.32795 14.45953 2.582 0.0158 *
Population 0.05780 0.02349 2.460 0.0208 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 396.9 on 26 degrees of freedom
Multiple R-squared: 0.4542, Adjusted R-squared: 0.3912
F-statistic: 7.211 on 3 and 26 DF, p-value: 0.001121
We first created a model using Illiteracy
and HS Grad
as predictor variables. Note that because of the space in name HS Grad
, make sure to put it in backticks in your code. The R Squared value for that model was 0.3271
— a notable improvement from the first model.
However, in looking at the p-value for the coefficients, it appears that Illiteracy
is no longer statistically significant. Remember, we want a p-value of 0.05
or less!
We then confirmed that intuition by removing Illiteracy
from the model entirely. The R Squared value barely dropped — Illiteracy
was barely contributing to the model.
Finally, we decided to see if the population of a state contributed to that state’s average income. We added Population
to the linear regression model and found that coefficient had a smaller p-value of 0.0506
. That is incredibly close to being statistically significant!
Review
To recap, there were two main goals of this project. The first was to explore the datasets that come built-in to R. We specifically used cars
and state.x77
, but we hope you explored other datasets on your own. See if you can reproduce this entire linear regression pipeline on your own with a different dataset.
The second goal of this project was to illustrate how R streamlines the linear regression process with almost every dataset. The code hardly changes! Because of this, we can’t stress enough the importance of understanding and explaining your model. As you become more familiar with R, the code becomes the easy part! Articulating your findings becomes the real challenge.
To take your linear regression skills to the next level, try finding a dataset online, making a linear regression model, and interpreting your results. There are tons of online resources, be we’ve found the UCI Machine Learning Repository to be a great starting place.
LS0tCnRpdGxlOiAiTGluZWFyIFJlZ3Jlc3Npb24gVXNpbmcgUiBEYXRhc2V0cyIKYXV0aG9yOiBLaGFpCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCldlbGNvbWUgdG8gdGhlIG9mZi1wbGF0Zm9ybSBwcm9qZWN0IGZvciBsaW5lYXIgcmVncmVzc2lvbiBpbiBSISBUaGVyZSBhcmUgdHdvIG1haW4gZ29hbHMgb2YgdGhpcyBwcm9qZWN0LiBUaGUgZmlyc3QgaXMgdG8gaW52ZXN0aWdhdGUgdGhlIGRhdGFzZXRzIHRoYXQgY29tZSBidWlsdC1pbiB0byBSLiBUaGUgc2Vjb25kIGlzIHRvIGxlYXJuIGhvdyB0byBxdWlja2x5IHdyaXRlIGFuZCBpbnRlcnByZXQgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzLiAKCkFzIHlvdSBtb3ZlIHRocm91Z2ggdGhpcyBwcm9qZWN0IHlvdSdsbCBiZWdpbiB0byBzZWUgdGhhdCBjcmVhdGluZyBhbmQgYW5hbHl6aW5nIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHRha2VzIHZlcnkgZmV3IGxpbmVzIG9mIGNvZGUuIFRoZSB0cmlja3kgd29yayBvZiBiZWluZyBhIGRhdGEgc2NpZW50aXN0IGJlZ2lucyB0byBzaGlmdCBmcm9tIHdyaXRpbmcgeW91ciBjb2RlIHRvIGV4cGxhaW5pbmcgeW91ciByZXN1bHRzLiAKClRoaXMgcHJvamVjdCBpcyB3cml0dGVuIGluIGFuIFIgTm90ZWJvb2suIFdlIHN1Z2dlc3Qgb3BlbmluZyB0aGlzIGZpbGUgdXNpbmcgUlN0dWRpby4gSWYgeW91IGNsaWNrIHRoZSAiUHJldmlldyIgYnV0dG9uLCB5b3Ugc2hvdWxkIHNlZSB0aGVzZSBpbnN0cnVjdGlvbnMgcmVuZGVyZWQgdG8gYW4gSFRNTCBwYWdlLiBXZSBzdWdnZXN0IGZvbGxvd2luZyBhbG9uZyB3aXRoIHRoZXNlIGluc3RydWN0aW9ucyBmcm9tIHRoZSBQcmV2aWV3IHdpbmRvdyB3aGlsZSBjb2RpbmcgYWxvbmcgaW4gdGhlIHByb3ZpZGVkIGNvZGUgYmxvY2tzLgoKTGV0J3MgZ2V0IHN0YXJ0ZWQhCgojIyMgSW52ZXN0aWdhdGluZyB0aGUgUiBEYXRhc2V0cyBQYWNrYWdlCgpXaGVuIHlvdSBmaXJzdCBkb3dubG9hZGVkIFIgdG8geW91ciBjb21wdXRlciwgeW91IGFsc28gZG93bmxvYWRlZCBzZXZlcmFsIGRhdGFzZXRzLiBUaGVzZSBjYW4gYmUgZm91bmQgaW4gdGhlIGBkYXRhc2V0c2AgcGFja2FnZS4gTGV0J3MgYmVnaW4gYnkgaW52ZXN0aWdhdGluZyB0aGlzIHBhY2thZ2UgYnkgbG9va2luZyBhdCB0aGUgZG9jdW1lbnRhdGlvbi4gRmlyc3QgbWFrZSBzdXJlIHRoZSBgZGF0YXNldHNgIHBhY2thZ2UgaXMgbG9hZGVkIGJ5IGNhbGxpbmcgYGxpYnJhcnkoZGF0YXNldHMpYC4gVGhlbiB0eXBlIGA/ZGF0YXNldHNgIGluIHRoZSBjb2RlIGJsb2NrIGJlbG93LiBZb3Ugc2hvdWxkIHNlZSB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGBkYXRhc2V0c2AgcGFja2FnZSBhcHBlYXIgaW4gdGhlICJIZWxwIiB0YWIgaW4gUlN0dWRpby4KCmBgYHtyIGxvb2tpbmcgZm9yIGRhdGFzZXRzfQojIExvYWQgZGF0YXNldHMgYW5kIGxvb2sgYXQgaXRzIGRvY3VtZW50YXRpb24KbGlicmFyeShkYXRhc2V0cykKP2RhdGFzZXRzCmBgYAoKVGhhdCBkb2N1bWVudGF0aW9uIGRpZG4ndCB0ZWxsIHVzIG11Y2ggJm1kYXNoOyBidXQgaXQgZGlkIGdpdmUgdXMgYSBoaW50IG9uIHdoZXJlIHRvIGdvIHRvIGZpbmQgYSBjb21wbGV0ZSBsaXN0IG9mIHRoZSBkYXRhc2V0cy4gQ2FsbCB0aGUgbGluZSBvZiBjb2RlIHJlY29tbWVuZGVkIGluIHRoZSBkb2N1bWVudGF0aW9uIG9mIGBkYXRhc2V0c2AuIE5vdGUgdGhhdCB0aGlzIHdpbGwgb3BlbiBhIG5ldyB0YWIgaW4gUlN0dWRpby4gTWFrZSBzdXJlIHRvIGNvbWUgYmFjayB0byB0aGlzIHRhYiBhZnRlciBsb29raW5nIHRocm91Z2ggdGhlIGRhdGFzZXRzLgoKYGBge3J9CmxpYnJhcnkoaGVscD0iZGF0YXNldHMiKQpgYGAKCllvdSBzaG91bGQgc2VlIGEgbGlzdCBvZiBkYXRhc2V0cy4gVGhlIGRvY3VtZW50YXRpb24gZ2l2ZXMgdXMgYSBicmllZiBkZXNjcmlwdGlvbiBvbiB0aGUgZGF0YXNldHMsIGJ1dCBpdCdzIHN0aWxsIGEgYml0IHRvdWdoIHRvIHVuZGVyc3RhbmQgd2hhdCB0aGUgZGF0YSBhY3R1YWxseSBsb29rcyBsaWtlLiBZb3UgY2FuIGFjY2VzcyBhIGRhdGFzZXQgaW4gUiB1c2luZyB0aGUgbm90YXRpb24gYGRhdGFzZXRzOjpkYXRhc2V0X25hbWVgLiBGb3IgZXhhbXBsZSwgdGFrZSBhIGxvb2sgYXQgdGhlIGhlYWQgb2YgdGhlIGRhdGFzZXQgbmFtZWQgYFRvb3RoR3Jvd3RoYCB1c2luZyB0aGUgbGluZSBgaGVhZChkYXRhc2V0czo6VG9vdGhHcm93dGgpYC4gV2hhdCBjb2x1bW5zIGV4aXN0PyBZb3UgY2FuIGFsc28gc2ltcGx5IHVzZSBgVG9vdGhHcm93dGhgIHRvIGFjY2VzcyB0aGUgZGF0YXNldCAmbWRhc2g7IHlvdSBkb24ndCBuZWVkIHRvIGluY2x1ZGUgdGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UgdGhhdCBpdCBjYW1lIGZyb20uCgpGaW5hbGx5LCB5b3UgY2FuIHB1bGwgdXAgdGhlIGRvY3VtZW50YXRpb24gZm9yIHRoZSBkYXRhIHVzaW5nIGA/VG9vdGhHcm93dGhgLiBXaGF0IGRvZXMgdGhlIGBzdXBwYCBjb2x1bW4gcmVwcmVzZW50IGluIHRoaXMgY2FzZT8gKnRoZSB0cmVhdG1lbnQgdmFsdWVzKgoKYGBge3Igc2VsZWN0aW5nIGRhdGEgc2V0c30KIyBQcmludCB0aGUgaGVhZCBvZiB0aGUgVG9vdGhHcm93dGggZGF0YXNldApkYXRhc2V0czo6VG9vdGhHcm93dGgKP1Rvb3RoR3Jvd3RoCmBgYAoKR3JlYXQhIFdlIG5vdyBoYXZlIHRoZSB0b29scyB0byBleHBsb3JlIGFsbCBvZiB0aGUgZGF0YXNldHMgdGhhdCBjb21lIHdpdGggUi4gTGV0J3Mgbm93IHRoaW5rIGFib3V0IHdoaWNoIG9uZXMgbWlnaHQgYmUgdXNlZnVsIGZvciBsaW5lYXIgcmVncmVzc2lvbi4gV2l0aCBsaW5lYXIgcmVncmVzc2lvbiwgd2UncmUgbG9va2luZyBmb3IgYSBkYXRhc2V0IHdoZXJlIG9uZSBjb2x1bW4gbWlnaHQgYmUgZXhwbGFpbmVkIGJ5IGFub3RoZXIgKG9yIGluIHRoZSBjYXNlIG9mIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uLCBvbmUgY29sdW1uIGJlaW5nIGV4cGxhaW5lZCBieSBtdWx0aXBsZSBvdGhlciBjb2x1bW5zKS4KClRyeSB0byBmaW5kIGF0IGxlYXN0IDMgZGlmZmVyZW50IGRhdGFzZXRzIHRoYXQgbWlnaHQgYmUgZ29vZCBjYW5kaWRhdGVzIGZvciBsaW5lYXIgcmVncmVzc2lvbi4gVXNlIHRoZSBjb2RlIGJsb2NrIGJlbG93IHRvIGxvb2sgdXAgdGhlIGRvY3VtZW50YXRpb24gZm9yIHNldmVyYWwgZGF0YXNldHMuIEluIHRoZSBuZXh0IHNlY3Rpb24gd2UnbGwgYmVnaW4gdGhlIGZpcnN0IHN0ZXAgb2Ygc3RhdGlzdGljYWwgbW9kZWwgYnVpbGRpbmcgJm1kYXNoOyBjb25maXJtaW5nIGRhdGEgYXNzdW1wdGlvbnMuCgpgYGB7ciB2aWV3aW5nIHRoZSBkYXRhIHNldHN9CiMgRmluZCBhdCBsZWFzdCB0aHJlZSBkYXRhc2V0cyB0aGF0IHNlZW0gbGlrZSBnb29kIGNhbmRpZGF0ZXMgZm9yIGxpbmVhciByZWdyZXNzaW9uCm55Y2ZsaWdodHMxMzo6ZmxpZ2h0cwpkYXRhKCJkaWFtb25kcyIpCmRhdGFzZXRzOjpjYXJzCgpgYGAKCiMjIyBDb25maXJtaW5nIERhdGEgQXNzdW1wdGlvbnMKCkluIHRoaXMgc2VjdGlvbiwgd2UnbGwgd2FsayB0aHJvdWdoIGEgZmV3IGRhdGFzZXRzIHRoYXQgYm90aCBtZWV0IGFuZCBkbyBub3QgbWVldCB0aGUgYXNzdW1wdGlvbnMgbmVjZXNzYXJ5IGZvciBsaW5lYXIgcmVncmVzc2lvbi4gV2UnbGwgYWxzbyBsZWF2ZSBzcGFjZSBmb3IgeW91IHRvIGludmVzdGlnYXRlIGRhdGFzZXRzIHRoYXQgeW91J3JlIGludHJlc3RlZC4KCkxldCdzIHN0YXJ0IGJlIHRlc3RpbmcgdGhlIGZpcnN0IGFzc3VtcHRpb24gbmVlZGVkIGZvciBsaW5lYXIgcmVncmVzc2lvbiAmbWRhc2g7IHRoZSBkYXRhIG5lZWRzIHRvIGJlIHJvdWdobHkgbGluZWFyLiBMZXQncyBkbyB0aGF0IHZpc3VhbGx5IHVzaW5nIHRoZSBgZ2dwbG90MmAgcGFja2FnZSAobWFrZSBzdXJlIHRoaXMgcGFja2FnZSBpcyBpbnN0YWxsZWQgYW5kIGxvYWRlZCkuCgpUbyBkbyBzbywgcGFzcyB5b3VyIGRhdGFzZXQgaW50byBhIGNhbGwgdG8gYGdncGxvdCgpYCBhbmQgaW5jbHVkZSBhbiBgYWVzKClgIHdpdGggdGhlIGNvbHVtbnMgdGhhdCBzaG91bGQgZ28gb24gdGhlIHggYW5kIHkgYXhlcy4gVGhlbiBhZGQgYSBgZ2VvbV9wb2ludCgpYCBsYXllci4gRm9yIGV4YW1wbGUsIGBnZ3Bsb3QoY2FycywgYWVzKHNwZWVkLCBkaXN0KSkgKyBnZW9tX3BvaW50KClgIHdpbGwgY3JlYXRlIGEgc2NhdHRlciBwbG90IHNob3dpbmcgdGhlIHNwZWVkIG9mIGNhcnMgb24gdGhlIHggYXhpcyBhbmQgdGhlIGRpc3RhbmNlIGl0IHRvb2sgdGhlbSB0byBzdG9wIG9uIHRoZSB5IGF4aXMuIERvZXMgdGhhdCBsb29rIGxpa2UgYSBsaW5lYXIgcmVsYXRpb25zaGlwPwoKYGBge3IgdGhlIGNhciBkYXRhLCBwbG90IGRpc3Qgb24gc3BwZWR9CmdncGxvdChjYXJzLCBhZXMoc3BlZWQsIGRpc3QpKSsgZ2VvbV9wb2ludCgpCmBgYAoKV2UgYWxzbyBjcmVhdGVkIGEgZ3JhcGggdXNpbmcgdGhlIGBzdGF0ZS54NzdgIGRhdGFzZXQgd2hlcmUgYElsbGl0ZXJhY3lgIHdhcyBvbiB0aGUgeCBheGlzIGFuZCBgSW5jb21lYCB3YXMgb24gdGhlIHkgYXhpcy4gVGhlcmUncyBvbmUgc21hbGwgX2hpY2N1cF8gaW4gdXNpbmcgdGhpcyBkYXRhc2V0LiBgc3RhdGUueDc3YCBpc24ndCBhIGRhdGEgZnJhbWUuIFVzZSBgYXMuZGF0YS5mcmFtZShzdGF0ZS54NzcpYCB0byB0cmFuc2Zvcm0gaXQgaW50byBhIGRhdGEgZnJhbWUuIERvZXMgdGhhdCBvbmUgbG9vayBsaW5lYXI/CmBgYHtyIHN0YXRlLng3NyBpbmNvbWUgb24gaWxsaXRlcmFjeSB9CgpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShzdGF0ZS54NzcpLCBhZXMoSWxsaXRlcmFjeSwgSW5jb21lKSkrCiAgZ2VvbV9wb2ludCgpCmBgYAoKRmluYWxseSwgd2UgY3JlYXRlZCBhIGdyYXBoIHVzaW5nIHRoZSBgcHJlc3N1cmVgIGRhdGFzZXQuIFRoaXMgZGF0YXNldCBkZXNjcmliZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0ZW1wZXJhdHVyZSBhbmQgdmFwb3IgcHJlc3N1cmUgb2YgbWVyY3VyeS4gUGxvdCBgdGVtcGVyYXR1cmVgIG9uIHRoZSB4IGF4aXMgYW5kIGBwcmVzc3VyZWAgb24gdGhlIHkgYXhpcy4gV2hhdCBsb29rcyBkaWZmZXJlbnQgYWJvdXQgdGhpcyBncmFwaD8KYGBge3J9CmdncGxvdChwcmVzc3VyZSwgYWVzKHRlbXBlcmF0dXJlLCBwcmVzc3VyZSkpKwogIGdlb21fcG9pbnQoKQpgYGAKCgpgYGB7cn0KIyBMb2FkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobW9kZWxyKQpvcHRpb25zKG5hLmFjdGlvbiA9IG5hLndhcm4pCmxpYnJhcnkobHVicmlkYXRlKQpgYGAKCgpgYGB7cn0KIyBQbG90IHlvdXIgZGF0YXNldHMKZ2dwbG90KGRpYW1vbmRzLCBhZXMoY3V0LCBwcmljZSkpK2dlb21fYm94cGxvdCgpCmdncGxvdChkaWFtb25kcywgYWVzKGNvbG9yLCBwcmljZSkpK2dlb21fYm94cGxvdCgpCmdncGxvdChkaWFtb25kcywgYWVzKGNsYXJpdHksIHByaWNlKSkrZ2VvbV9ib3hwbG90KCkKYGBgCgpUaGF0IHRoaXJkIGdyYXBoIGNlcnRhaW5seSBkaWRuJ3QgbG9vayBsaW5lYXIuIFRoaXMgbG9va3MgdG8gYmUgYSBxdWFkcmF0aWMgb3IgZXhwb25lbnRpYWwgcmVsYXRpb25zaGlwICZtZGFzaDsgbGluZWFyIHJlZ3Jlc3Npb24gd291bGRuJ3QgYmUgYXBwcm9wcmlhdGUuCgpBbm90aGVyIHdheSBvZiB0ZXN0aW5nIGZvciBhIGxpbmVhciByZWxhdGlvbnNoaXAgaXMgdG8gY29tcHV0ZSB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgdXNpbmcgYGNvci50ZXN0KClgLiBQYXNzIHRoZSB0d28gY29sdW1ucyBvZiB5b3VyIGRhdGFzZXQgaW50byB0aGlzIGZ1bmN0aW9uIHRvIHNlZSB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQuCgpXYXMgdGhlcmUgYSBzdHJvbmdlciBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzcGVlZCBhbmQgc3RvcHBpbmcgZGlzdGFuY2UgaW4gdGhlIGNhciBkYXRhc2V0IG9yIGJldHdlZW4gc3RhdGUgaWxsaXRlcmFjeSBhbmQgc3RhdGUgaW5jb21lPyBSZW1lbWJlciwgdGhlIHJlbGF0aW9uc2hpcCBpcyBzdHJvbmdlciBpZiB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgZnVydGhlciBhd2F5IGZyb20gMC4KCmBgYHtyfQojIEZpbmQgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50CmNvci50ZXN0KHN0YXRlLng3NyRJbGxpdGVyYWN5LCBzdGF0ZS54NzckSW5jb21lKQpgYGAKCkZpbmFsbHksIGxldCdzIGNoZWNrIGZvciBvdXRsaWVycyBpbiB0aGUgZGF0YXNldCB0byBzZWUgaWYgYW55dGhpbmcgbG9va3MgcGFydGljdWxhcmx5IG9mZi4gRm9yIHRoZSBgY2Fyc2AgZGF0YXNldCwgY3JlYXRlIGEgYm94cGxvdCBzaG93aW5nIHRoZSBkaXN0cmlidWl0aW9uIG9mIHRoZSBgc3BlZWRgIHZhcmlhYmxlLiBGb3IgdGhlIGBzdGF0ZS54NzdgIGRhdGFzZXQsIGNyZWF0ZSBhIGJveHBsb3Qgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBgSWxsaXRlcmFjeWAgZGF0YXNldC4gQWdhaW4sIHJlbWVtYmVyIHRoYXQgdGhlIGBzdGF0ZS54NzdgIGRhdGFzZXQgZmlyc3QgaGFzIHRvIGJlIHB1dCBpbnRvIGEgZGF0YSBmcmFtZSB1c2luZyBgYXMuZGF0YS5mcmFtZSgpYC4gWW91IGNhbiBzdG9yZSB0aGlzIGRhdGEgZnJhbWUgdmVyc2lvbiBvZiB0aGUgZGF0YSBpbiBhIHZhcmlhYmxlIGlmIHlvdSdkIGxpa2UuCgpgYGB7cn0KIyBDcmVhdGUgYSBib3ggcGxvdCBvZiB5b3VyIGNhcnMgZGF0YXNldHMuCmdncGxvdChjYXJzKSsKICBnZW9tX2JveHBsb3QoYWVzKHNwZWVkLCBzcGVlZCkpCmBgYAoKYGBge3IgYm94cGxvdCBzdGF0ZS54Nzd9CiMgQ3JlYXRlIGEgYm94IHBsb3Qgb2YgeW91ciBzdGF0dGUueDc3IGRhdGFzZXRzLgpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShzdGF0ZS54NzcpKSsKICBnZW9tX2JveHBsb3QoYWVzKElsbGl0ZXJhY3ksIElsbGl0ZXJhY3kpKQpgYGAKCldoaWxlIHdlJ3JlIGxvb2tpbmcgYXQgdGhlIGNhcnMgYW5kIHN0YXRlcyBkYXRhc2V0cywgd2UgZW5jb3VyYWdlIHlvdSB0byBleHBlcmltZW50IHdpdGggb3RoZXIgZGF0YXNldHMgYXMgd2VsbCEgVXNlIHRoaXMgc3BhY2UgdG8gZXhwbG9yZSBhc3N1bXB0aW9ucyBvZiBsaW5lYXIgcmVncmVzc2lvbiBmb3IgZGF0YXNldHMgZnJvbSB0aGUgYGRhdGFzZXRzYCBwYWNrYWdlIHRoYXQgeW91J3JlIGludGVyZXN0ZWQuCgpgYGB7ciBkaWFtb25kcyBib3hwbG90IHByaWNlIG9uIGNhcmF0fQojIEV4cGxvcmUgb3RoZXIgZGF0YXNldHMgaGVyZQpnZ3Bsb3QoZGlhbW9uZHMpKwogIGdlb21fYm94cGxvdChhZXMoY2FyYXQsIGNhcmF0KSkKYGBgCgoKIyMjIE1ha2luZyBhbmQgQXNzZXNzaW5nIHRoZSBNb2RlbAoKTm93IHRoYXQgd2UndmUgY29uZmlybWVkIHRoZSBhc3N1bXB0aW9ucyBuZWNlc3NhcnkgZm9yIGxpbmVhciByZWdyZXNzaW9uLCBsZXQncyBtYWtlIHRoZSBtb2RlbHMgYW5kIHNlZSBob3cgdGhleSBkbyEKCkJlZm9yZSBjcmVhdGluZyBvdXIgbW9kZWxzLCBsZXQncyByYW5kb21seSBzcGxpdCBvdXIgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMuIDYwJSBvZiB0aGUgZGF0YSBzaG91bGQgZ28gaW50byB0aGUgdHJhaW5pbmcgc2V0IGFuZCA0MCUgb2YgdGhlIGRhdGEgc2hvdWxkIGdvIGludG8gdGhlIHRlc3Qgc2V0LiBXZSBpbmNsdWRlZCBgc2V0LnNlZWQoMTIzKWAgYXQgdGhlIHRvcCBvZiBvdXIgY29kZSBibG9jay4gKipUaGlzIG1ha2VzIGl0IHNvIHRoYXQgaWYgeW91IHJlLXJ1biB5b3VyIGNvZGUsIHRoZSBkYXRhIHdpbGwgYmUgc3BsaXQgaW4gdGhlIHNhbWUgd2F5IGV2ZXJ5IHRpbWUuKiogSXQncyBzdGlsbCByYW5kb21seSBzcGxpdCwgYnV0IHNldHRpbmcgdGhlIHNlZWQgYWxsb3dzIHVzIHRvIHJlcHJvZHVjZSB0aGUgcmFuZG9tIHNwbGl0IGV2ZXJ5IHRpbWUgd2UgcnVuIG91ciBjb2RlLgoKYGBge3IgYnVpbGQgdGhlIG1vZGVsIGZvciBjYXIgZGF0YXNldHN9CiMgU2V0dGluZyB0aGUgcmFuZG9taXplcidzIHNlZWQKc2V0LnNlZWQoMTIzKQpzYW1wbGVjYXIgPC0gc2FtcGxlKGMoVFJVRSwgRkFMU0UpLCBucm93KGNhcnMpLCByZXBsYWNlPVQsIHByb2I9YygwLjYsIDAuNCkpCiNTcGxpdCB5b3VyIGRhdGEgaW50byB0cmFpbmluZyAoNjAlKSBhbmQgdGVzdCAoNDAlKSBzZXRzCnRyYWluY2FyIDwtIGNhcnNbc2FtcGxlY2FyLCBdCnRlc3RjYXIgPC0gY2Fyc1shc2FtcGxlY2FyLCBdCmBgYAoKCmBgYHtyIGJ1aWxkIHRoZSBtb2RlbCBmb3Igc3RhdGUueDc3IGRhdGFzZXRzfQpzZXQuc2VlZCgxMjMpCnNhbXBsZXN0dCA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIG5yb3coc3RhdGUueDc3KSwgcmVwbGFjZT1ULCBwcm9iPWMoMC42LCAwLjQpKQojU3BsaXQgeW91ciBkYXRhIGludG8gdHJhaW5pbmcgKDYwJSkgYW5kIHRlc3QgKDQwJSkgc2V0cwp0cmFpbnN0dCA8LSBzdGF0ZS54Nzdbc2FtcGxlc3R0LCBdCnRlc3RzdHQgPC0gc3RhdGUueDc3WyFzYW1wbGVzdHQsIF0KYGBgCgoKV2UgY2FuIG5vdyBtYWtlIG91ciBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbHMgdXNpbmcgdGhlIHRyYWluaW5ncyBzZXQhCkNyZWF0ZSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIHRoZSBgY2Fyc2AgZGF0YXNldCB0aGF0IHByZWRpY3RzIGBkaXN0YCBiYXNlZCBvbiBgc3BlZWRgLiBTaW1pbGFybHksIGNyZWF0ZSBhIG1vZGVsIHVzaW5nIHRoZSBgc3RhdGUueDc3YCBkYXRhc2V0IHRoYXQgcHJlZGljdHMgYEluY29tZWAgYmFzZWQgb24gYElsbGl0ZXJhY3lgLgoKYGBge3IgbGluZWFyIHJlZyB3aXRoZSBjYXJzfQojIENyZWF0ZSB5b3VyIGxpbmVhciByZWdyZXNzaW9uIG1vZGVscwptb2RlbGNhciA8LSBsbShkaXN0fnNwZWVkLCBkYXRhPXRyYWluY2FyKQptb2RlbGNhcgpgYGAKCgpgYGB7ciBsaW5lYXIgcmVnIHdpdGhlIHN0YXRlLng3N30KbW9kZWxzdHQgPC0gbG0oSW5jb21lfklsbGl0ZXJhY3ksIGRhdGEgPSB0cmFpbnN0dCkKbW9kZWxzdHQKYGBgCgojIyMjIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yIChSU0UpCkxldCdzIG5vdyBsb29rIGF0IHRoZSBSU0Ugb2YgZWFjaCBtb2RlbCB1c2luZyBgc2lnbWEoKWAuIFdoYXQgZG8gdGhlc2UgbnVtYmVyIG1lYW4/IFJlbWVtYmVyLCB0aGUgdW5pdHMgb2YgUlNFIGFyZSBzcGVjaWZpYyB0byBlYWNoIGRhdGFzZXQuIFdyaXRlIHlvdXIgYW5zd2VyIGFzIGEgY29tbWVudCBpbiB5b3VyIGNvZGUgYmxvY2suCgpgYGB7ciBSU0UgZm9yIG1vZGVsY2FyfQojIEZpbmQgdGhlIHJlc2lkdWFsIHN0YW5kYXJkIGVycm9yKFJTRSkgb2YgZWFjaCBtb2RlbAojIHRoZSByc2UgPSAxNS4zNSwgbWVhbmluZyB0aGF0IHRoZSBhY3R1YWwgZGlzdGFuY2Ugd2lsbCBvZmYgZnJvbSB0aGUgbW9kZWwgYnkgMTUuMzUgZmVldCAnJycKc2lnbWEobW9kZWxjYXIpCmBgYAoKCmBgYHtyIFJTRSBmb3IgbW9kZWxzdHR9CiMgRmluZCB0aGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IoUlNFKSBvZiBlYWNoIG1vZGVsCnNpZ21hKG1vZGVsc3R0KQpgYGAKClRoaXMgbWVhbnMgdGhhdCB0aGUgdHJ1ZSBkaXN0YW5jZSBpdCB0YWtlcyBhIGNhciB0byBzdG9wIHdpbGwgYmUgYDE1LjM1YCBmZWV0IG9mZiBmcm9tIHdoYXQgdGhlIG1vZGVsIHByZWRpY3RlZCwgb24gYXZlcmFnZS4gU2ltaWxhcmx5LCB0aGUgbW9kZWwncyBwcmVkaWN0aW9uIGZvciBhdmVyYWdlIGluY29tZSB3YXMgb2ZmIGJ5IGA0NjEuODZgIGRvbGxhcnMgb24gYXZlcmFnZS4gCgojIyMjIFItc3F1YXJlZApCdXQgYXJlIHRoZXNlIG51bWJlcnMgZ29vZCBvciBiYWQ/IEl0J3Mgc29tZXRpbWVzIGhhcmQgdG8gdGVsbC4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIFIgU3F1YXJlZCB2YWx1ZSBmb3IgZWFjaCBtb2RlbC4gQXMgYSByZW1pbmRlciwgeW91IGNhbiBmaW5kIFIgU3F1YXJlZCB2YWx1ZXMgdXNpbmcgdGhpcyBjb2RlIGBzdW1tYXJ5KG1vZGVsKSRyLnNxdWFyZWRgLgoKVHJ5IHRvIGFydGljdWxhdGUgd2hhdCB0aGVzZSB2YWx1ZXMgbWVhbiBhcyBhIGNvbW1lbnQgaW4geW91ciBjb2RlLiBXZSdsbCBkaXNjdXNzIG91ciByZXN1bHRzIGFmdGVyIHRoZSBjb2RlIGJsb2NrLgoKYGBge3Igci1zcXVhcmVkIGZvciBtb2RlbGNhcn0KIyBGaW5kIHRoZSBSIFNxdWFyZWQgdmFsdWUgb2YgbW9kZWxjYXIKc3VtbWFyeShtb2RlbGNhcikkci5zcXVhcmVkCgojIEZpbmQgdGhlIFIgU3F1YXJlZCB2YWx1ZSBvZiBtb2RlbHN0dApzdW1tYXJ5KG1vZGVsc3R0KSRyLnNxdWFyZWQKYGBgCgpUaGUgUiBTcXVhcmVkIHZhbHVlIG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGV4cGxhaW5lZC4gSW4gb3RoZXIgd29yZHMsIF83MSUgb2YgdGhlIHZhcmlhbmNlIGZvdW5kIGluIHRoZSBjYXIncyBzdG9wcGluZyBkaXN0YW5jZSBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSBzcGVlZCBvZiB0aGUgY2FyLl8gT24gdGhlIG90aGVyIGhhbmQsIG9ubHkgMjAlIG9mIHRoZSB2YXJpYW5jZSBpbiBhIHN0YXRlJ3MgaW5jb21lIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIHN0YXRlJ3MgaWxsaXRlcmFjeSBsZXZlbC4KCkZpbmFsbHksIGxldCdzIGxvb2sgYXQgdGhlIHJlc3Qgb2YgYHN1bW1hcnkoKWAgZm9yIGVhY2ggbW9kZWwuIFRoaXMgdGltZSwgZm9jdXMgb24gdGhlIGNvZWZmaWNpZW50cyBhbmQgdGhlIGBQcig+fHR8KWAgdmFsdWUgb2YgZWFjaCBtb2RlbC4gQWdhaW4sIHRyeSB3cml0aW5nIGEgY29tbWVudCBpbiB5b3VyIGNvZGUgYXJ0aWN1bGF0aW5nIHdoYXQgdGhlc2UgdmFsdWVzIG1lYW4uIFdlJ2xsIGRpc2N1c3Mgb3VyIHJlc3VsdHMgYWZ0ZXIgdGhlIGNvZGUgYmxvY2suCgpgYGB7ciBzdW1tYXJ5IG9mIGVhY2ggbW9kZWx9CiMgRmluZCB0aGUgUiBTcXVhcmVkIHZhbHVlIG9mIG1vZGVsY2FyCnN1bW1hcnkobW9kZWxjYXIpCgojIEZpbmQgdGhlIFIgU3F1YXJlZCB2YWx1ZSBvZiBtb2RlbHN0dApzdW1tYXJ5KG1vZGVsc3R0KQoKYGBgCgpKdXN0IGxpa2Ugd2l0aCB0aGUgUiBTcXVhcmVkIHZhbHVlLCB0aGVzZSB2YWx1ZXMgYXJlIHNob3dpbmcgdGhhdCB0aGUgYHNwZWVkYCB2YXJpYWJsZSBpbiB0aGUgY2FycyBkYXRhc2V0IG1pZ2h0IGJlIGEgYmV0dGVyIGZpdCBsaW5lYXIgcmVncmVzc2lvbiB0aGFuIHRoZSBgSWxsaXRlcmFjeWAgdmFyaWFibGUgaW4gdGhlIHN0YXRlIGRhdGFzZXQuICAgCgpUaGUgZWFzaWVzdCB3YXkgdG8gc2VlIHRoaXMgaXMgdG8gbG9vayBhdCB0aGUgc3RhcnMgYnkgZWFjaCBjb2VmZmljaWVudC4gRm9yIHRoZSBjYXIgZGF0YXNldCwgdGhlIGBzcGVlZGAgY29lZmZpY2llbnQgaGFzIHRocmVlIHN0YXJzLCBtZWFuaW5nIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiBgMC4wMDFgLiBUaGlzIG1lYW5zIHRoYXQgaWYgdGhlcmUgd2FzIHRydWx5IG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGBzcGVlZGAgYW5kIGBkaXN0YCwgX3dlIHdvdWxkIGV4cGVjdCB0byBzZWUgZGF0YSBsaWtlIHRoaXMgZnJvbSBhYm91dCAxIG91dCBvZiAxMDAwIHJhbmRvbSBzYW1wbGVzLl8KCk9uIHRoZSBvdGhlciBoYW5kLCB0aGUgc3RhdGVzIGRhdGFzZXQgaGFzIGEgc2xpZ2h0bHkgaGlnaGVyIHAtdmFsdWUgZm9yIGBJbGxpdGVyYWN5YCwgYW5kIHRoZXJlZm9yZSBoYXMgb25seSBvbmUgc3Rhci4gQSBwLXZhbHVlIG9mIGAwLjAxMmAgbWVhbnMgdGhhdCBpZiB0aGVyZSB3ZXJlIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGBJbGxpdGVyYWN5YCBhbmQgYEluY29tZWAsIF93ZSB3b3VsZCBmaW5kIGRhdGEgdGhhdCBsb29rcyBsaWtlIHRoaXMgaW4gYWJvdXQgMSBvdXQgb2YgZXZlcnkgMTAwIHJhbmRvbSBzYW1wbGVzLl8gVGhhdCdzIHN0aWxsIHByZXR0eSBnb29kLCBidXQgd2UncmUgYWJvdXQgdGVuIHRpbWVzIGFzIGNlcnRhaW4gdGhhdCBhIHJlbGF0aW9uc2hpcCBleGlzdHMgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGluIHRoZSBjYXIgZGF0YXNldC4KCk9uY2UgYWdhaW4sIHdlJ3ZlIGFkZGVkIGEgY29kZSBibG9jayBiZWxvdyBmb3IgeW91IHRvIGRvIHRoaXMgcHJvY2VzcyBvbiBhbm90aGVyIGRhdGFzZXQgdGhhdCB5b3UgZmVlbCBtaWdodCBiZSBzdWl0YWJsZSBmb3IgbGluZWFyIHJlZ3Jlc3Npb24uCgpgYGB7ciBidWlsZCBtb2RlbCBmb3IgZGlhbW9uZHMgZGF0YXNldH0KIyAxLiByYW5kb20gc2FtcGxpbmcKc2V0LnNlZWQoMTIzKQpzYW1wbGVfZGlhbSA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIG5yb3coZGlhbW9uZHMpLCByZXBsYWNlPVQsIHByb2I9YygwLjYsIDAuNCkpCgojIDIuIFNwbGl0IHlvdXIgZGF0YSBpbnRvIHRyYWluaW5nICg2MCUpIGFuZCB0ZXN0ICg0MCUpIHNldHMKdHJhaW5fZGlhbSA8LSBkaWFtb25kc1tzYW1wbGVfZGlhbSwgXQp0ZXN0X2RpYW0gPC0gZGlhbW9uZHNbIXNhbXBsZV9kaWFtLCBdCgojIDMuIENyZWF0ZSB5b3VyIGxpbmVhciByZWdyZXNzaW9uIG1vZGVscyBvbiB0aGUgdHJhaW4gc2V0Cm1vZGVsZGlhbSA8LSBsbShwcmljZX5jYXJhdCwgZGF0YT10cmFpbl9kaWFtKQptb2RlbGRpYW0KCiMgNC4gRmluZCB0aGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IoUlNFKSBvZiB0aGUgbW9kZWwgdXNpbmcgc2lnbWEoKQojIFRoaXMgbWVhbnMgdGhhdCBvbiBhdmVyYWdlIHRoZSBtb2RlbCB3aWxsIGJlIG9mZiBieSAkMSw1NDEgb2YgdGhlIHRydWUgcHJpY2Ugb2YgdGhlIGNhcmF0LgpzaWdtYShtb2RlbGRpYW0pCgojIDUuIEZpbmQgdGhlIFIgU3F1YXJlZCB2YWx1ZSBvZiBtb2RlbGRpYW0KIyA4NSUgb2YgdGhlIHZhcmlhbmNlIGluIGEgZGlhbW9uZHMnIHByaWNlIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIGRpYW1kbmRzJyBjYXJhdCBsZXZlbC4Kc3VtbWFyeShtb2RlbGRpYW0pJHIuc3F1YXJlZAoKIyA2LiBGaW5kIHRoZSBSIFNxdWFyZWQgdmFsdWUgb2YgbW9kZWxkaWFtCnN1bW1hcnkobW9kZWxkaWFtKQoKYGBgClRoZSBlYXNpZXN0IHdheSB0byBzZWUgdGhpcyBpcyB0byBsb29rIGF0IHRoZSBfc3RhcnMgYnkgZWFjaCBjb2VmZmljaWVudC5fIEZvciB0aGUgZGlhbW9uZHMgZGF0YXNldCwgdGhlIGBjYXJhdGAgY29lZmZpY2llbnQgaGFzIHRocmVlIHN0YXJzLCBtZWFuaW5nIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiBgMC4wMDFgLiBUaGlzIG1lYW5zIHRoYXQgaWYgdGhlcmUgd2FzIHRydWx5IG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGBjYXJhdGAgYW5kIGBwcmljZWAsIF93ZSB3b3VsZCBleHBlY3QgdG8gc2VlIGRhdGEgbGlrZSB0aGlzIGZyb20gYWJvdXQgMSBvdXQgb2YgMTAwMCByYW5kb20gc2FtcGxlcy5fCgojIyMgR3JhcGhpbmcgdGhlIFJlc2lkdWFscyBhbmQgQWRkaW5nIEEgTE9FU1MgU21vb3RoZXIKCk5pY2Ugd29yayEgTGV0J3Mgbm93IGdyYXBoIHRoZSByZXNpZHVhbHMuIEFkZCBhIGNvbHVtbiBuYW1lZGBlc3RpbWF0ZWAgdG8geW91ciB0cmFpbmluZyBzZXRzLiBUaGVzZSBjb2x1bW5zIHNob3VsZCBiZSBjcmVhdGVkIGJ5IGNhbGxpbmcgYHByZWRpY3QoKWAgdXNpbmcgeW91ciBtb2RlbHMgYXMgYSBwYXJhbWV0ZXIuIEFsc28gYWRkIGEgY29sdW1uIG5hbWVkIGByZXNpZHVhbHNgIHRvIHRoZSB0cmFpbmluZyBzZXQgYnkgY2FsbGluZyBgcmVzaWR1YWxzKClgIHVzaW5nIHlvdXIgbW9kZWxzIGFzIGEgcGFyYW1ldGVyLgoKT25jZSB0aG9zZSBjb2x1bW5zIGhhdmUgYmVlbiBjcmVhdGVkLCBjcmVhdGUgYSBncmFwaCB0aGF0IHNob3dzIGJvdGggdGhlIGVzdGltYXRlZCB2YWx1ZXMgYW5kIHRoZSByZXNpZHVhbHMuIFlvdXIgeCBhbmQgeSBheGVzIHNob3VsZCBiZSB0aGUgc2FtZSBmZWF0dXJlcywgX2hvd2V2ZXIgaW5zdGVhZCBvZiBwbG90dGluZyB0aGUgb3JpZ2luYWwgZGF0YSwgcGxvdCB0aGUgZXN0aW1hdGVkIHZhbHVlcyBhbmQgdGhlIHJlc2lkdWFscy5fCgpXZSBhbHNvIGluY2x1ZGVkIHNlZ21lbnRzIHRvIGNvbm5lY3QgZWFjaCByZXNpZHVhbCB0byB0aGVpciBjb3JyZXNwb25kaW5nIGVzdGltYXRlLgoKYGBge3J9CiNzYXZlIHByZWRpY3RlZCBhbmQgcmVzaWR1YWwgdmFsdWVzIHRvIGRmCnRyYWluY2FyJGVzdGltYXRlIDwtcHJlZGljdChtb2RlbGNhcikKdHJhaW5jYXIkcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhtb2RlbGNhcikKCiNjcmVhdGUgdmlzdWFsaXphdGlvbgpwbHRjYXIgPC0gdHJhaW5jYXIgJT4lIAogIGdncGxvdChhZXMoc3BlZWQsIGRpc3QpKSsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gYWJzKHJlc2lkdWFscykpKSsKICBnZW9tX3BvaW50KGFlcyh5PWVzdGltYXRlKSwgY29sb3I9ImdyZWVuIikrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikrCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgY29sb3I9ImJsdWUiKSsKICBnZW9tX3NlZ21lbnQoYWVzKHhlbmQgPSBzcGVlZCwgeWVuZCA9IGVzdGltYXRlKSwgY29sb3I9InJlZCIpCnBsdGNhcgpgYGAKCkxldCdzIGFsc28gYWRkIGEgdmlzdWFsaXphdGlvbiBvZiB0aGUgbW9kZWwgYW5kIExPRVNTIHNtb290aGVyIHRvIG91ciBzY2F0dGVyIHBvaW50LiBHcmFiIHlvdXIgY29kZSBmb3IgeW91ciBvcmlnaW5hbCBzY2F0dGVycGxvdCwgYnV0IG1ha2Ugc3VyZSB0byB1c2UgeW91ciB0cmFpbmluZyBzZXQgcmF0aGVyIHRoZW4gdGhlIG9yaWdpbmFsIGRhdGFzZXQuIFRoZW4gYWRkIGBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKWAgdG8gdmlzdWFsaXplIHRoZSBtb2RlbCBhbmQgYGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpYCB0byBhZGQgYSBMT0VTUyBzbW9vdGhlci4KCkRvIHRoZXNlIHZpc3VhbGl6YXRpb25zIGNvbmZpcm0gd2hhdCB5b3Ugc2F3IHdoZW4gY2FsY3VsYXRpbmcgdGhlIFIgU3F1YXJlZCB2YWx1ZSBvZiBlYWNoIG1vZGVsPwoKYGBge3J9CiMgQWRkIGEgTE9FU1Mgc21vb3RoZXIgdG8geW91ciBzY2F0dGVycGxvdApwbHRjYXIgPC0gdHJhaW5jYXIgJT4lIAogIGdncGxvdChhZXMoc3BlZWQsIGRpc3QpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikrCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgY29sb3I9InJlZCIpCnBsdGNhcgpgYGAKCkhlcmUncyBhIGNvZGUgYmxvY2sgZm9yIHlvdSB0byB0cnkgdGhlc2UgdmlzdWFsaXphdGlvbnMgb24gZGlmZmVyZW50IGRhdGFzZXRzLgoKYGBge3J9CgpgYGAKCgoKIyMjIFVwZ3JhZGluZyBUbyBBIE11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIE1vZGVsCgpFdmVyeXRoaW5nIHRoYXQgd2UndmUgZG9uZSBzbyBmYXIgc2VlbXMgdG8gaW5kaWNhdGUgdGhhdCBvdXIgbW9kZWwgZm9yIHRoZSBzdGF0ZXMgZGF0YXNldCBpcyBnb29kLCBidXQgY291bGQgYmUgYmV0dGVyLiBUaGlzIGlzIHRoZSBwZXJmZWN0IG9wcG9ydHVuaXR5IHRvIHRyeSB0byB1cGdyYWRlIGl0IHRvIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwuIFRha2UgYSBsb29rIGF0IHRoZSBoZWFkIG9mIHRoYXQgZGF0YXNldCBhZ2Fpbi4gRG8geW91IHRoaW5rIHRoZXJlJ3MgYW5vdGhlciBjb2x1bW4gdGhhdCBjb3VsZCBoZWxwIGV4cGxhaW4gYSBzdGF0ZSdzIGBJbmNvbWVgPyBDcmVhdGUgYSBuZXcgbW9kZWwgdXNpbmcgYXQgbGVhc3QgdHdvIGZlYXR1cmVzIGFzIHByZWRpY3RvciB2YXJpYWJsZXMuIFByaW50IG91dCB0aGUgYHN1bW1hcnkoKWAgb2YgdGhhdCBtb2RlbC4gSG93IGRvZXMgaXQgY29tcGFyZSB0byB5b3VyIGZpcnN0IG1vZGVsPwoKQWdhaW4sIHRyeSB0byB3cml0ZSBhIGZldyBzZW50ZW5jZXMgYXMgYSBjb21tZW50IGRlc2NyaWJpbmcgdGhlIHN1bW1hcnkgb2YgeW91ciBuZXcgbW9kZWwuIEFmdGVyIHRoZSBjb2RlIGJsb2NrIHdlJ2xsIHdhbGsgeW91IHRocm91Z2ggb3VyIHByb2Nlc3MuCgpgYGB7cn0KIyAzLiBDcmVhdGUgYSBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbAptb2RlbHN0dDIgPC0gbG0oSW5jb21lIH4gSWxsaXRlcmFjeSArIGBIUyBHcmFkYCArIFBvcHVsYXRpb24sIGRhdGEgPSB0cmFpbnN0dCkKCiMgNC4gRmluZCB0aGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IoUlNFKSBvZiB0aGUgbW9kZWwgdXNpbmcgc2lnbWEoKQojIFRoaXMgbWVhbnMgdGhhdCBvbiBhdmVyYWdlIHRoZSBtb2RlbCB3aWxsIGJlIG9mZiBieSAkNDMyLjQzIG9mIHRoZSB0cnVlIHByaWNlIG9mIHRoZSBpbmNvbWUuCnNpZ21hKG1vZGVsc3R0MikKCiMgNS4gRmluZCB0aGUgUiBTcXVhcmVkIHZhbHVlIG9mIG1vZGVsZGlhbQojIDg1JSBvZiB0aGUgdmFyaWFuY2UgaW4gYSBkaWFtb25kcycgcHJpY2UgY2FuIGJlIGV4cGxhaW5lZCBieSB0aGUgZGlhbWRuZHMnIGNhcmF0IGxldmVsLgpzdW1tYXJ5KG1vZGVsc3R0Mikkci5zcXVhcmVkCgojIDYuIEZpbmQgdGhlIFIgU3F1YXJlZCB2YWx1ZSBvZiBtb2RlbGRpYW0Kc3VtbWFyeShtb2RlbHN0dDIpCmBgYAoKV2UgZmlyc3QgY3JlYXRlZCBhIG1vZGVsIHVzaW5nIGBJbGxpdGVyYWN5YCBhbmQgYEhTIEdyYWRgIGFzIHByZWRpY3RvciB2YXJpYWJsZXMuIE5vdGUgdGhhdCBiZWNhdXNlIG9mIHRoZSBzcGFjZSBpbiBuYW1lIGBIUyBHcmFkYCwgbWFrZSBzdXJlIHRvIHB1dCBpdCBpbiBiYWNrdGlja3MgaW4geW91ciBjb2RlLiBUaGUgUiBTcXVhcmVkIHZhbHVlIGZvciB0aGF0IG1vZGVsIHdhcyBgMC4zMjcxYCAmbWRhc2g7IGEgbm90YWJsZSBpbXByb3ZlbWVudCBmcm9tIHRoZSBmaXJzdCBtb2RlbC4KCkhvd2V2ZXIsIGluIGxvb2tpbmcgYXQgdGhlIHAtdmFsdWUgZm9yIHRoZSBjb2VmZmljaWVudHMsIGl0IGFwcGVhcnMgdGhhdCBgSWxsaXRlcmFjeWAgaXMgbm8gbG9uZ2VyIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuIFJlbWVtYmVyLCB3ZSB3YW50IGEgcC12YWx1ZSBvZiBgMC4wNWAgb3IgbGVzcyEKCldlIHRoZW4gY29uZmlybWVkIHRoYXQgaW50dWl0aW9uIGJ5IHJlbW92aW5nIGBJbGxpdGVyYWN5YCBmcm9tIHRoZSBtb2RlbCBlbnRpcmVseS4gVGhlIFIgU3F1YXJlZCB2YWx1ZSBiYXJlbHkgZHJvcHBlZCAmbWRhc2g7IGBJbGxpdGVyYWN5YCB3YXMgYmFyZWx5IGNvbnRyaWJ1dGluZyB0byB0aGUgbW9kZWwuCgpGaW5hbGx5LCB3ZSBkZWNpZGVkIHRvIHNlZSBpZiB0aGUgcG9wdWxhdGlvbiBvZiBhIHN0YXRlIGNvbnRyaWJ1dGVkIHRvIHRoYXQgc3RhdGUncyBhdmVyYWdlIGluY29tZS4gV2UgYWRkZWQgYFBvcHVsYXRpb25gIHRvIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBhbmQgZm91bmQgdGhhdCBjb2VmZmljaWVudCBoYWQgYSBzbWFsbGVyIHAtdmFsdWUgb2YgYDAuMDUwNmAuIFRoYXQgaXMgaW5jcmVkaWJseSBjbG9zZSB0byBiZWluZyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IQoKIyMjIFJldmlldwoKVG8gcmVjYXAsIHRoZXJlIHdlcmUgdHdvIG1haW4gZ29hbHMgb2YgdGhpcyBwcm9qZWN0LiBUaGUgZmlyc3Qgd2FzIHRvIGV4cGxvcmUgdGhlIGRhdGFzZXRzIHRoYXQgY29tZSBidWlsdC1pbiB0byBSLiBXZSBzcGVjaWZpY2FsbHkgdXNlZCBgY2Fyc2AgYW5kIGBzdGF0ZS54NzdgLCBidXQgd2UgaG9wZSB5b3UgZXhwbG9yZWQgb3RoZXIgZGF0YXNldHMgb24geW91ciBvd24uIFNlZSBpZiB5b3UgY2FuIHJlcHJvZHVjZSB0aGlzIGVudGlyZSBsaW5lYXIgcmVncmVzc2lvbiBwaXBlbGluZSBvbiB5b3VyIG93biB3aXRoIGEgZGlmZmVyZW50IGRhdGFzZXQuCgpUaGUgc2Vjb25kIGdvYWwgb2YgdGhpcyBwcm9qZWN0IHdhcyB0byBpbGx1c3RyYXRlIGhvdyBSIHN0cmVhbWxpbmVzIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBwcm9jZXNzIHdpdGggYWxtb3N0IGV2ZXJ5IGRhdGFzZXQuIFRoZSBjb2RlIGhhcmRseSBjaGFuZ2VzISBCZWNhdXNlIG9mIHRoaXMsIHdlIGNhbid0IHN0cmVzcyBlbm91Z2ggdGhlIGltcG9ydGFuY2Ugb2YgdW5kZXJzdGFuZGluZyBhbmQgZXhwbGFpbmluZyB5b3VyIG1vZGVsLiBBcyB5b3UgYmVjb21lIG1vcmUgZmFtaWxpYXIgd2l0aCBSLCB0aGUgY29kZSBiZWNvbWVzIHRoZSBlYXN5IHBhcnQhIEFydGljdWxhdGluZyB5b3VyIGZpbmRpbmdzIGJlY29tZXMgdGhlIHJlYWwgY2hhbGxlbmdlLgoKVG8gdGFrZSB5b3VyIGxpbmVhciByZWdyZXNzaW9uIHNraWxscyB0byB0aGUgbmV4dCBsZXZlbCwgdHJ5IGZpbmRpbmcgYSBkYXRhc2V0IG9ubGluZSwgbWFraW5nIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIGFuZCBpbnRlcnByZXRpbmcgeW91ciByZXN1bHRzLiBUaGVyZSBhcmUgdG9ucyBvZiBvbmxpbmUgcmVzb3VyY2VzLCBiZSB3ZSd2ZSBmb3VuZCB0aGUgW1VDSSBNYWNoaW5lIExlYXJuaW5nIFJlcG9zaXRvcnldKGh0dHA6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL2RhdGFzZXRzLnBocCkgdG8gYmUgYSBncmVhdCBzdGFydGluZyBwbGFjZS4KCg==