Multiple Regression

In multiple linear regression, we model the response variable as a linear combination of several predictors, plus a single error term. Assume that we have a single response \(Y\), and \(p\) predictors \(X^{(1)}, X^{(2)}, ..., X^{(p)}\). The hypothetical form for a multiple regression model would be as follows:

\[Y = \beta_0 + \beta_1 X^{(1)} + \beta_2 X^{(2)} + ... + \beta_p X^{(p)} + e\]

We make the same assumptions for the error term \(e\) as we did for simple linear regression. The fitted model will have the form:

\[\hat Y = \hat\beta_0 + \hat\beta_1 X^{(1)} + \hat\beta_2 X^{(2)} + ... + \hat\beta_p X^{(p)}\] This fitted model will be obtained by finding the parameter estimates that minimize the sum of squared errors, as was the case in simple linear regression.

NYC Restaurant Dataset

In this lesson, we will be explorting the “New York City Restaurant” dataset, which is stored in the file nyc.txt. This tab-separated text file contains information for 168 Italian restaurants in New York City. The dataset contains six variables for each restaurant:

Variable Description
Price The average price, in USD, for a meal at the restaurant (including one drink and a tip).
Food The average customer rating of the food, on a scale from 1 to 30.
Decor The average customer rating of the decor, on a scale from 1 to 30.
Service The average cusstomer rating of the service, on a scale from 1 to 30.
Wait The average wait time, in minutes, on a Saturday evening.
East A binary variable. Equals 1 if the restaurant is east of 5th Avenue, and 0 otherwise.
df <- read.table("nyc.txt", sep="\t", header = TRUE)
summary(df)
     Price           Food          Decor          Service          Wait            East      
 Min.   :19.0   Min.   :16.0   Min.   : 6.00   Min.   :14.0   Min.   : 0.00   Min.   :0.000  
 1st Qu.:36.0   1st Qu.:19.0   1st Qu.:16.00   1st Qu.:18.0   1st Qu.:16.75   1st Qu.:0.000  
 Median :43.0   Median :20.5   Median :18.00   Median :20.0   Median :23.00   Median :1.000  
 Mean   :42.7   Mean   :20.6   Mean   :17.69   Mean   :19.4   Mean   :22.92   Mean   :0.631  
 3rd Qu.:50.0   3rd Qu.:22.0   3rd Qu.:19.00   3rd Qu.:21.0   3rd Qu.:29.00   3rd Qu.:1.000  
 Max.   :65.0   Max.   :25.0   Max.   :25.00   Max.   :24.0   Max.   :46.00   Max.   :1.000  

The variable East is a qualitative (categorical) variable categorical that we will not be using in this lesson.

Pairs Plot

We will create a pairs plot of the 5 variables that we are interested in.

pairs(df[1:5])

Full Model

Our goal is to create a regression model with price as the response and some combination of the other four variables as predictors. We will begin with the “full” model that uses all four available predictors. Our fitted model will have the following form:

\[\hat {Price} = \hat\beta_0 + \hat\beta_1\cdot Food + \hat\beta_2\cdot Decor + \hat\beta_3\cdot Service + \hat\beta_4\cdot Wait\]

mod1 <- lm(Price ~ Food + Decor + Service + Wait, df)
summary(mod1)

Call:
lm(formula = Price ~ Food + Decor + Service + Wait, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-14.5265  -3.8743  -0.1174   3.6356  19.0440 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -25.81378    4.82789  -5.347 2.98e-07 ***
Food          1.57176    0.37249   4.220 4.05e-05 ***
Decor         1.85427    0.21715   8.539 9.09e-15 ***
Service       0.08922    0.39637   0.225    0.822    
Wait          0.07006    0.05370   1.305    0.194    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.791 on 163 degrees of freedom
Multiple R-squared:  0.6209,    Adjusted R-squared:  0.6116 
F-statistic: 66.75 on 4 and 163 DF,  p-value: < 2.2e-16

We will briefly explain the various parts of the model summary.

Coefficient Estimates

The coefficient estimates \(\beta_0, \beta_1, \beta_2, \beta_3, \beta_4\) are shown in the first column of the section labeled “Coefficients”. We can use these to see that the fitted model is given by:

\[\hat {Price} = -25.814 + 1.5718\cdot Food + 1.8543\cdot Decor + 0.08922\cdot Service + 0.07006\cdot Wait\]

Notice that some of the coefficients in this model are very small. That is not a huge concern, in and of itself. What we want to know, however, is if any of the coefficients are so small, that we cannot say that they are non-zero with a reasonably high degree of certainty. We can check that using t-tests on each of the estimates.

t-Tests

R automatically performs a t-Test of the form \(H_0: \beta_i = 0\), \(H_A: \beta_i \neq 0\) for each of the coefficients in the model. Let’s display the model summary again to see these results.

summary(mod1)

Call:
lm(formula = Price ~ Food + Decor + Service + Wait, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-14.5265  -3.8743  -0.1174   3.6356  19.0440 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -25.81378    4.82789  -5.347 2.98e-07 ***
Food          1.57176    0.37249   4.220 4.05e-05 ***
Decor         1.85427    0.21715   8.539 9.09e-15 ***
Service       0.08922    0.39637   0.225    0.822    
Wait          0.07006    0.05370   1.305    0.194    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.791 on 163 degrees of freedom
Multiple R-squared:  0.6209,    Adjusted R-squared:  0.6116 
F-statistic: 66.75 on 4 and 163 DF,  p-value: < 2.2e-16

Notice that the results of the t-tests for the intercept, Food, and Decor are statistically significant, while the results of the tests for Service and Wait are NOT statistically significant. We can be quite confident that the true values of \(\beta_0\), \(\beta_1\), and \(\beta_2\) are non-zero. We cannot say with a large degree of certainty that the true values of the parameters \(\beta_3\) and \(\beta_4\) are non-zero.

If we are not confident that \(\beta_3\) and \(\beta_4\) are non-zero, then we are not confident that Service and Wait have an effect on the price. We should consider removing these from the model. We will do this in a moment.

Residual Standard Error

Recall that \(\sigma^2 = \mathrm{Var}[e]\). For simple linear regression, the quantity \(s^2 = \frac{SSE}{n - 2}\) provides an unbaised estimate of \(\sigma^2\). For multiple regression, our unbiased estimate is given by:

\[s^2 = \frac{SSE}{n-p-1}\] The square root of this quantity, \(s\), is called the residual standard error. It approximates the standard deviation of our error term.

For our model, we see that \(s = 5.791\). Let’s compare that with the standard deviation of our response variable:

sd(df$Price)
[1] 9.292814

R-Squared and Adjusted R-Squared

Note that summary output for the model states two R-squared values: “Multiple R-squared”" and “Adjusted R-squared”. The first value, multiple r-squared, is the standard version of r^2 that we are used to. In particular:

\[r^2 = 1 - \frac{SSE}{SST} \approx 1 - \frac{s^2}{s^2_Y}\]

Adjusted r-squared is a modification of the r^2 value that applies a small penalty for having additional (potentially unnecessary) predictors in your model. It is defined as follows:

\[r_{adj}^2 = 1 - \frac{s^2}{s_Y^2} = 1 - \frac{\frac{1}{n-p-1}SSE}{\frac{1}{n-1}SST} = 1 - \frac{(n-1) SSE}{(n-p-1)SST} = r^2 - (1-r^2) \frac{p}{n-p-1}\]

When considering several possible models, each with a different numbers of predictors, we prefer to use the adjusted r-squared to compare the models (as opposed to the standard r-squared value). This will help us to avoid creating models that contain unnessary predictors.

F-Test

The model summary outputs the results of an F-test. This is a test of the following hypotheses:

\(H_0 : \beta_1 = \beta_2 = ... = \beta_p = 0\)

\(H_A :\) There is at least one \(\beta_i \neq 0\)
summary(mod1)

Call:
lm(formula = Price ~ Food + Decor + Service + Wait, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-14.5265  -3.8743  -0.1174   3.6356  19.0440 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -25.81378    4.82789  -5.347 2.98e-07 ***
Food          1.57176    0.37249   4.220 4.05e-05 ***
Decor         1.85427    0.21715   8.539 9.09e-15 ***
Service       0.08922    0.39637   0.225    0.822    
Wait          0.07006    0.05370   1.305    0.194    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.791 on 163 degrees of freedom
Multiple R-squared:  0.6209,    Adjusted R-squared:  0.6116 
F-statistic: 66.75 on 4 and 163 DF,  p-value: < 2.2e-16

Since the p-value for the F-test is so small, we can be confident that at least some of the coefficients in our model are non-zero.

Create a Smaller Model

Since the t-tests for the coefficients of Service and Wait were not statistically significant, we will remove those from the model.

mod2 <- lm(Price ~ Food + Decor, df)
summary(mod2)

Call:
lm(formula = Price ~ Food + Decor, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-14.945  -3.766  -0.153   3.701  18.757 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -24.5002     4.7230  -5.187 6.19e-07 ***
Food          1.6461     0.2615   6.294 2.68e-09 ***
Decor         1.8820     0.1919   9.810  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.788 on 165 degrees of freedom
Multiple R-squared:  0.6167,    Adjusted R-squared:  0.6121 
F-statistic: 132.7 on 2 and 165 DF,  p-value: < 2.2e-16

Notice that the multiple r-squared value has decreased,but the adjusted r-squared value has increased.

Residual Analysis

We will conclude by analyzing the residuals for our reduced model.

plot(mod2$residuals ~ mod2$fitted.values, pch=21, col="black", bg="salmon",
     xlab="Fitted Value", ylab="Residuals", main="Residual Plot")
abline(h=0, col="darkred", lwd=2)

res <- mod2$residuals
par(mfrow=c(1,2))
hist(res, col='orchid', breaks=10)
qqnorm(res)
qqline(res)
par(mfrow=c(1,1))

shapiro.test(res)

    Shapiro-Wilk normality test

data:  res
W = 0.98647, p-value = 0.1044

Generating Predictions

nd <- data.frame(Food = c(21, 24, 18), Decor = c(25, 13, 16))
predict(mod2, newdata = nd, interval = "prediction", level = 0.99)
       fit      lwr      upr
1 57.11936 41.58650 72.65222
2 39.47363 23.81404 55.13321
3 35.24278 20.03783 50.44773
LS0tDQp0aXRsZTogIkxlc3NvbiAxNiAtIEludHJvIHRvIE11bHRpcGxlIFJlZ3Jlc3Npb24iDQphdXRob3I6ICJSb2JiaWUgQmVhbmUiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAyDQotLS0NCg0KIyBNdWx0aXBsZSBSZWdyZXNzaW9uDQoNCkluIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uLCB3ZSBtb2RlbCB0aGUgcmVzcG9uc2UgdmFyaWFibGUgYXMgYSBsaW5lYXIgY29tYmluYXRpb24gb2Ygc2V2ZXJhbCBwcmVkaWN0b3JzLCBwbHVzIGEgc2luZ2xlIGVycm9yIHRlcm0uIEFzc3VtZSB0aGF0IHdlIGhhdmUgYSBzaW5nbGUgcmVzcG9uc2UgJFkkLCBhbmQgJHAkIHByZWRpY3RvcnMgJFheeygxKX0sIFheeygyKX0sIC4uLiwgWF57KHApfSQuIFRoZSBoeXBvdGhldGljYWwgZm9ybSBmb3IgYSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIHdvdWxkIGJlIGFzIGZvbGxvd3M6DQoNCiQkWSA9IFxiZXRhXzAgKyBcYmV0YV8xIFheeygxKX0gKyBcYmV0YV8yIFheeygyKX0gKyAuLi4gKyBcYmV0YV9wIFheeyhwKX0gKyBlJCQNCg0KV2UgbWFrZSB0aGUgc2FtZSBhc3N1bXB0aW9ucyBmb3IgdGhlIGVycm9yIHRlcm0gJGUkIGFzIHdlIGRpZCBmb3Igc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uLiBUaGUgZml0dGVkIG1vZGVsIHdpbGwgaGF2ZSB0aGUgZm9ybTogDQoNCiQkXGhhdCBZID0gXGhhdFxiZXRhXzAgKyBcaGF0XGJldGFfMSBYXnsoMSl9ICsgXGhhdFxiZXRhXzIgWF57KDIpfSArIC4uLiArIFxoYXRcYmV0YV9wIFheeyhwKX0kJA0KVGhpcyBmaXR0ZWQgbW9kZWwgd2lsbCBiZSBvYnRhaW5lZCBieSBmaW5kaW5nIHRoZSBwYXJhbWV0ZXIgZXN0aW1hdGVzIHRoYXQgbWluaW1pemUgdGhlIHN1bSBvZiBzcXVhcmVkIGVycm9ycywgYXMgd2FzIHRoZSBjYXNlIGluIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbi4gDQoNCiMgTllDIFJlc3RhdXJhbnQgRGF0YXNldA0KDQpJbiB0aGlzIGxlc3Nvbiwgd2Ugd2lsbCBiZSBleHBsb3J0aW5nIHRoZSAiTmV3IFlvcmsgQ2l0eSBSZXN0YXVyYW50IiBkYXRhc2V0LCB3aGljaCBpcyBzdG9yZWQgaW4gdGhlIGZpbGUgYG55Yy50eHRgLiBUaGlzIHRhYi1zZXBhcmF0ZWQgdGV4dCBmaWxlIGNvbnRhaW5zIGluZm9ybWF0aW9uIGZvciAxNjggSXRhbGlhbiByZXN0YXVyYW50cyBpbiBOZXcgWW9yayBDaXR5LiBUaGUgZGF0YXNldCBjb250YWlucyBzaXggdmFyaWFibGVzIGZvciBlYWNoIHJlc3RhdXJhbnQ6IA0KDQo8Y2VudGVyPg0KVmFyaWFibGUgfCBEZXNjcmlwdGlvbg0KLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KKipgUHJpY2VgKiogfCBUaGUgYXZlcmFnZSBwcmljZSwgaW4gVVNELCBmb3IgYSBtZWFsIGF0IHRoZSByZXN0YXVyYW50IChpbmNsdWRpbmcgb25lIGRyaW5rIGFuZCBhIHRpcCkuDQoqKmBGb29kYCoqIHwgVGhlIGF2ZXJhZ2UgY3VzdG9tZXIgcmF0aW5nIG9mIHRoZSBmb29kLCBvbiBhIHNjYWxlIGZyb20gMSB0byAzMC4gDQoqKmBEZWNvcmAqKiB8IFRoZSBhdmVyYWdlIGN1c3RvbWVyIHJhdGluZyBvZiB0aGUgZGVjb3IsIG9uIGEgc2NhbGUgZnJvbSAxIHRvIDMwLiANCioqYFNlcnZpY2VgKiogfCBUaGUgYXZlcmFnZSBjdXNzdG9tZXIgcmF0aW5nIG9mIHRoZSBzZXJ2aWNlLCBvbiBhIHNjYWxlIGZyb20gMSB0byAzMC4gIA0KKipgV2FpdGAqKiB8IFRoZSBhdmVyYWdlIHdhaXQgdGltZSwgaW4gbWludXRlcywgb24gYSBTYXR1cmRheSBldmVuaW5nLiANCioqYEVhc3RgKiogfCBBIGJpbmFyeSB2YXJpYWJsZS4gRXF1YWxzIDEgaWYgdGhlIHJlc3RhdXJhbnQgaXMgZWFzdCBvZiA1dGggQXZlbnVlLCBhbmQgMCBvdGhlcndpc2UuIA0KPC9jZW50ZXI+DQoNCg0KYGBge3J9DQpkZiA8LSByZWFkLnRhYmxlKCJueWMudHh0Iiwgc2VwPSJcdCIsIGhlYWRlciA9IFRSVUUpDQpzdW1tYXJ5KGRmKQ0KYGBgDQoNClRoZSB2YXJpYWJsZSBgRWFzdGAgaXMgYSBxdWFsaXRhdGl2ZSAoY2F0ZWdvcmljYWwpIHZhcmlhYmxlIGNhdGVnb3JpY2FsIHRoYXQgd2Ugd2lsbCBub3QgYmUgdXNpbmcgaW4gdGhpcyBsZXNzb24uIA0KDQojIFBhaXJzIFBsb3QNCg0KV2Ugd2lsbCBjcmVhdGUgYSBwYWlycyBwbG90IG9mIHRoZSA1IHZhcmlhYmxlcyB0aGF0IHdlIGFyZSBpbnRlcmVzdGVkIGluLiANCg0KYGBge3J9DQpwYWlycyhkZlsxOjVdKQ0KYGBgDQoNCiMgRnVsbCBNb2RlbA0KDQpPdXIgZ29hbCBpcyB0byBjcmVhdGUgYSByZWdyZXNzaW9uIG1vZGVsIHdpdGggcHJpY2UgYXMgdGhlIHJlc3BvbnNlIGFuZCBzb21lIGNvbWJpbmF0aW9uIG9mIHRoZSBvdGhlciBmb3VyIHZhcmlhYmxlcyBhcyBwcmVkaWN0b3JzLiBXZSB3aWxsIGJlZ2luIHdpdGggdGhlICJmdWxsIiBtb2RlbCB0aGF0IHVzZXMgYWxsIGZvdXIgYXZhaWxhYmxlIHByZWRpY3RvcnMuIE91ciBmaXR0ZWQgbW9kZWwgd2lsbCBoYXZlIHRoZSBmb2xsb3dpbmcgZm9ybToNCg0KJCRcaGF0IHtQcmljZX0gPSBcaGF0XGJldGFfMCArIFxoYXRcYmV0YV8xXGNkb3QgRm9vZCArIFxoYXRcYmV0YV8yXGNkb3QgRGVjb3IgKyBcaGF0XGJldGFfM1xjZG90IFNlcnZpY2UgKyBcaGF0XGJldGFfNFxjZG90IFdhaXQkJA0KDQpgYGB7cn0NCm1vZDEgPC0gbG0oUHJpY2UgfiBGb29kICsgRGVjb3IgKyBTZXJ2aWNlICsgV2FpdCwgZGYpDQpzdW1tYXJ5KG1vZDEpDQpgYGANCg0KV2Ugd2lsbCBicmllZmx5IGV4cGxhaW4gdGhlIHZhcmlvdXMgcGFydHMgb2YgdGhlIG1vZGVsIHN1bW1hcnkuIA0KDQojIyBDb2VmZmljaWVudCBFc3RpbWF0ZXMNCg0KVGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcyAkXGJldGFfMCwgXGJldGFfMSwgXGJldGFfMiwgXGJldGFfMywgXGJldGFfNCQgYXJlIHNob3duIGluIHRoZSBmaXJzdCBjb2x1bW4gb2YgdGhlIHNlY3Rpb24gbGFiZWxlZCAiQ29lZmZpY2llbnRzIi4gV2UgY2FuIHVzZSB0aGVzZSB0byBzZWUgdGhhdCB0aGUgZml0dGVkIG1vZGVsIGlzIGdpdmVuIGJ5Og0KDQokJFxoYXQge1ByaWNlfSA9IC0yNS44MTQgKyAxLjU3MThcY2RvdCBGb29kICsgMS44NTQzXGNkb3QgRGVjb3IgKyAwLjA4OTIyXGNkb3QgU2VydmljZSArIDAuMDcwMDZcY2RvdCBXYWl0JCQNCg0KTm90aWNlIHRoYXQgc29tZSBvZiB0aGUgY29lZmZpY2llbnRzIGluIHRoaXMgbW9kZWwgYXJlIHZlcnkgc21hbGwuIFRoYXQgaXMgbm90IGEgaHVnZSBjb25jZXJuLCBpbiBhbmQgb2YgaXRzZWxmLiBXaGF0IHdlIHdhbnQgdG8ga25vdywgaG93ZXZlciwgaXMgaWYgYW55IG9mIHRoZSBjb2VmZmljaWVudHMgYXJlIHNvIHNtYWxsLCB0aGF0IHdlIGNhbm5vdCBzYXkgdGhhdCB0aGV5IGFyZSBub24temVybyB3aXRoIGEgcmVhc29uYWJseSBoaWdoIGRlZ3JlZSBvZiBjZXJ0YWludHkuIFdlIGNhbiBjaGVjayB0aGF0IHVzaW5nIHQtdGVzdHMgb24gZWFjaCBvZiB0aGUgZXN0aW1hdGVzLg0KDQojIyB0LVRlc3RzDQoNClIgYXV0b21hdGljYWxseSBwZXJmb3JtcyBhIHQtVGVzdCBvZiB0aGUgZm9ybSAkSF8wOiBcYmV0YV9pID0gMCQsICRIX0E6IFxiZXRhX2kgXG5lcSAwJCBmb3IgZWFjaCBvZiB0aGUgY29lZmZpY2llbnRzIGluIHRoZSBtb2RlbC4gTGV0J3MgZGlzcGxheSB0aGUgbW9kZWwgc3VtbWFyeSBhZ2FpbiB0byBzZWUgdGhlc2UgcmVzdWx0cy4gDQoNCmBgYHtyfQ0Kc3VtbWFyeShtb2QxKQ0KYGBgDQoNCk5vdGljZSB0aGF0IHRoZSByZXN1bHRzIG9mIHRoZSB0LXRlc3RzIGZvciB0aGUgaW50ZXJjZXB0LCBgRm9vZGAsIGFuZCBgRGVjb3JgIGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCB3aGlsZSB0aGUgcmVzdWx0cyBvZiB0aGUgdGVzdHMgZm9yIGBTZXJ2aWNlYCBhbmQgYFdhaXRgIGFyZSBOT1Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gV2UgY2FuIGJlIHF1aXRlIGNvbmZpZGVudCB0aGF0IHRoZSB0cnVlIHZhbHVlcyBvZiAkXGJldGFfMCQsICRcYmV0YV8xJCwgYW5kICRcYmV0YV8yJCBhcmUgbm9uLXplcm8uIFdlIGNhbm5vdCBzYXkgd2l0aCBhIGxhcmdlIGRlZ3JlZSBvZiBjZXJ0YWludHkgdGhhdCB0aGUgdHJ1ZSB2YWx1ZXMgb2YgdGhlIHBhcmFtZXRlcnMgJFxiZXRhXzMkIGFuZCAkXGJldGFfNCQgYXJlIG5vbi16ZXJvLiANCg0KSWYgd2UgYXJlIG5vdCBjb25maWRlbnQgdGhhdCAkXGJldGFfMyQgYW5kICRcYmV0YV80JCBhcmUgbm9uLXplcm8sIHRoZW4gd2UgYXJlIG5vdCBjb25maWRlbnQgdGhhdCBgU2VydmljZWAgYW5kIGBXYWl0YCBoYXZlIGFuIGVmZmVjdCBvbiB0aGUgcHJpY2UuIFdlIHNob3VsZCBjb25zaWRlciByZW1vdmluZyB0aGVzZSBmcm9tIHRoZSBtb2RlbC4gV2Ugd2lsbCBkbyB0aGlzIGluIGEgbW9tZW50LiANCg0KDQojIyBSZXNpZHVhbCBTdGFuZGFyZCBFcnJvcg0KDQpSZWNhbGwgdGhhdCAkXHNpZ21hXjIgPSBcbWF0aHJte1Zhcn1bZV0kLiBGb3Igc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uLCB0aGUgcXVhbnRpdHkgJHNeMiA9IFxmcmFje1NTRX17biAtIDJ9JCBwcm92aWRlcyBhbiB1bmJhaXNlZCBlc3RpbWF0ZSBvZiAkXHNpZ21hXjIkLiBGb3IgbXVsdGlwbGUgcmVncmVzc2lvbiwgb3VyIHVuYmlhc2VkIGVzdGltYXRlIGlzIGdpdmVuIGJ5Og0KDQokJHNeMiA9IFxmcmFje1NTRX17bi1wLTF9JCQNClRoZSBzcXVhcmUgcm9vdCBvZiB0aGlzIHF1YW50aXR5LCAkcyQsIGlzIGNhbGxlZCB0aGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IuIEl0IGFwcHJveGltYXRlcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIG91ciBlcnJvciB0ZXJtLiANCg0KRm9yIG91ciBtb2RlbCwgd2Ugc2VlIHRoYXQgJHMgPSA1Ljc5MSQuIExldCdzIGNvbXBhcmUgdGhhdCB3aXRoIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2Ygb3VyIHJlc3BvbnNlIHZhcmlhYmxlOg0KDQpgYGB7cn0NCnNkKGRmJFByaWNlKQ0KYGBgDQoNCg0KIyMgUi1TcXVhcmVkIGFuZCBBZGp1c3RlZCBSLVNxdWFyZWQNCg0KTm90ZSB0aGF0IHN1bW1hcnkgb3V0cHV0IGZvciB0aGUgbW9kZWwgc3RhdGVzIHR3byBSLXNxdWFyZWQgdmFsdWVzOiAiTXVsdGlwbGUgUi1zcXVhcmVkIiIgYW5kICJBZGp1c3RlZCBSLXNxdWFyZWQiLiBUaGUgZmlyc3QgdmFsdWUsIG11bHRpcGxlIHItc3F1YXJlZCwgaXMgdGhlIHN0YW5kYXJkIHZlcnNpb24gb2Ygcl4yIHRoYXQgd2UgYXJlIHVzZWQgdG8uIEluIHBhcnRpY3VsYXI6DQoNCiQkcl4yID0gMSAtIFxmcmFje1NTRX17U1NUfSBcYXBwcm94IDEgLSBcZnJhY3tzXjJ9e3NeMl9ZfSQkDQoNCkFkanVzdGVkIHItc3F1YXJlZCBpcyBhIG1vZGlmaWNhdGlvbiBvZiB0aGUgcl4yIHZhbHVlIHRoYXQgYXBwbGllcyBhIHNtYWxsIHBlbmFsdHkgZm9yIGhhdmluZyBhZGRpdGlvbmFsIChwb3RlbnRpYWxseSB1bm5lY2Vzc2FyeSkgcHJlZGljdG9ycyBpbiB5b3VyIG1vZGVsLiBJdCBpcyBkZWZpbmVkIGFzIGZvbGxvd3M6DQoNCg0KJCRyX3thZGp9XjIgPSAxIC0gXGZyYWN7c14yfXtzX1leMn0gPSAxIC0gXGZyYWN7XGZyYWN7MX17bi1wLTF9U1NFfXtcZnJhY3sxfXtuLTF9U1NUfSA9IDEgLSBcZnJhY3sobi0xKSBTU0V9eyhuLXAtMSlTU1R9ID0gcl4yIC0gKDEtcl4yKSBcZnJhY3twfXtuLXAtMX0kJA0KDQpXaGVuIGNvbnNpZGVyaW5nIHNldmVyYWwgcG9zc2libGUgbW9kZWxzLCBlYWNoIHdpdGggYSBkaWZmZXJlbnQgbnVtYmVycyBvZiBwcmVkaWN0b3JzLCB3ZSBwcmVmZXIgdG8gdXNlIHRoZSBhZGp1c3RlZCByLXNxdWFyZWQgdG8gY29tcGFyZSB0aGUgbW9kZWxzIChhcyBvcHBvc2VkIHRvIHRoZSBzdGFuZGFyZCByLXNxdWFyZWQgdmFsdWUpLiBUaGlzIHdpbGwgaGVscCB1cyB0byBhdm9pZCBjcmVhdGluZyBtb2RlbHMgdGhhdCBjb250YWluIHVubmVzc2FyeSBwcmVkaWN0b3JzLiANCg0KDQojIyBGLVRlc3QNCg0KVGhlIG1vZGVsIHN1bW1hcnkgb3V0cHV0cyB0aGUgcmVzdWx0cyBvZiBhbiBGLXRlc3QuIFRoaXMgaXMgYSB0ZXN0IG9mIHRoZSBmb2xsb3dpbmcgaHlwb3RoZXNlczoNCg0KPGNlbnRlcj4NCiRIXzAgOiBcYmV0YV8xID0gXGJldGFfMiA9IC4uLiA9IFxiZXRhX3AgPSAwJA0KDQokSF9BIDokIFRoZXJlIGlzIGF0IGxlYXN0IG9uZSAkXGJldGFfaSBcbmVxIDAkDQo8L2NlbnRlcj4NCg0KYGBge3J9DQpzdW1tYXJ5KG1vZDEpDQpgYGANCg0KU2luY2UgdGhlIHAtdmFsdWUgZm9yIHRoZSBGLXRlc3QgaXMgc28gc21hbGwsIHdlIGNhbiBiZSBjb25maWRlbnQgdGhhdCBhdCBsZWFzdCBzb21lIG9mIHRoZSBjb2VmZmljaWVudHMgaW4gb3VyIG1vZGVsIGFyZSBub24temVyby4gDQoNCg0KIyBDcmVhdGUgYSBTbWFsbGVyIE1vZGVsDQoNClNpbmNlIHRoZSB0LXRlc3RzIGZvciB0aGUgY29lZmZpY2llbnRzIG9mIGBTZXJ2aWNlYCBhbmQgYFdhaXRgIHdlcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHdlIHdpbGwgcmVtb3ZlIHRob3NlIGZyb20gdGhlIG1vZGVsLiANCg0KYGBge3J9DQptb2QyIDwtIGxtKFByaWNlIH4gRm9vZCArIERlY29yLCBkZikNCnN1bW1hcnkobW9kMikNCmBgYA0KDQpOb3RpY2UgdGhhdCB0aGUgbXVsdGlwbGUgci1zcXVhcmVkIHZhbHVlIGhhcyBkZWNyZWFzZWQsYnV0IHRoZSBhZGp1c3RlZCByLXNxdWFyZWQgdmFsdWUgaGFzIGluY3JlYXNlZC4gDQoNCg0KIyBSZXNpZHVhbCBBbmFseXNpcw0KDQpXZSB3aWxsIGNvbmNsdWRlIGJ5IGFuYWx5emluZyB0aGUgcmVzaWR1YWxzIGZvciBvdXIgcmVkdWNlZCBtb2RlbC4gDQoNCmBgYHtyfQ0KcGxvdChtb2QyJHJlc2lkdWFscyB+IG1vZDIkZml0dGVkLnZhbHVlcywgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9InNhbG1vbiIsDQogICAgIHhsYWI9IkZpdHRlZCBWYWx1ZSIsIHlsYWI9IlJlc2lkdWFscyIsIG1haW49IlJlc2lkdWFsIFBsb3QiKQ0KDQphYmxpbmUoaD0wLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmBgYA0KDQoNCmBgYHtyfQ0KcmVzIDwtIG1vZDIkcmVzaWR1YWxzDQpwYXIobWZyb3c9YygxLDIpKQ0KaGlzdChyZXMsIGNvbD0nb3JjaGlkJywgYnJlYWtzPTEwKQ0KcXFub3JtKHJlcykNCnFxbGluZShyZXMpDQpwYXIobWZyb3c9YygxLDEpKQ0KYGBgDQoNCmBgYHtyfQ0Kc2hhcGlyby50ZXN0KHJlcykNCmBgYA0KDQojIEdlbmVyYXRpbmcgUHJlZGljdGlvbnMNCg0KYGBge3J9DQpuZCA8LSBkYXRhLmZyYW1lKEZvb2QgPSBjKDIxLCAyNCwgMTgpLCBEZWNvciA9IGMoMjUsIDEzLCAxNikpDQpwcmVkaWN0KG1vZDIsIG5ld2RhdGEgPSBuZCwgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIsIGxldmVsID0gMC45OSkNCmBgYA0KDQo=