# First install the required packages:

#installed.packages('openintro')
#installed.packages('tidyverse')
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ---------------------------------------------------------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5     v purrr   0.3.4
v tibble  3.1.2     v dplyr   1.0.6
v tidyr   1.1.3     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts ------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(openintro)
Loading required package: airports
Loading required package: cherryblossom
Loading required package: usdata

Introduction

This workbook is an in class assignment. After completion you will have a good practical knowledge of Multiple Regression and Logistic Regression.

There are two types of exercises in this Tutorial.

Response questions These questions are thought exercises and require a written response.

Response Question Example:

What is the Capital of North Dakota?

Response: Bismarck

Coding questions These questions require entering R code in the provided chunk.

Coding question example

Write the R code to calculate the average of the whole numbers from 1 to 10, enter your code here:

mean(1,10)
[1] 1

Section 1 Loans

We will consider data about loans from the peer-to-peer lender, Lending Club. The data is contained in the loan.csv file contained in the project directory.

  1. Coding Question 1 load the data into a new tibble called loan
loan <- read_csv('loan.csv')

-- Column specification ---------------------------------------------------------------------------------------------------------
cols(
  interest_rate = col_double(),
  income_ver = col_character(),
  debt_to_income = col_double(),
  credit_util = col_double(),
  bankruptcy = col_double(),
  term = col_double(),
  issued = col_character(),
  credit_checks = col_double()
)

You may find the following variable dictionary useful.

Variable dictionary for loan.

variable description
interest_rate Interest rate for the loan
income_ver Categorical variable describing whether the borrower’s income source and amount have been verified, levels verified,source_only, not
dept_to_income Debt-to-income ratio, which is the percent of total debt of the borrower divided by their total income.
credit_util Of all the Credit available to the borrower, what fraction are they using. For example the credit utilization on the credit card would be the card’s balance divided by the card’s credit limit
bankruptcy An indicator variable for whether the borrower has a past bankruptcy in her record. This variable takes a value of 1 if the answer is “yes” and 0 if the answer is “no”.
term The length of the loan, in months.
issued The month and year the loan was issued.
credit_checks Number of credit checks in the last 12 months. For example, when filing an application for a credit cards, it is common for the company receiving the application to run a credit check.

Using Categorical Variables as Predictors

Recall the single variable models we have been studying. The prediction looks like this. \[ \hat{Y} = \hat{\beta_0} + \hat{\beta_1}X\] Where the variables denoted by the \(\hat{\,}\) over them are the estimates obtained by lm.

In every case we have, more or less implicitly, assumed that X is a numeric variable. Would this make any sense if \(X\) is a categorical variable?

  1. Response Question What is a categorical variable?

A variable which is not quantitative

  1. Coding Question
    Consider the variable income_ver, what are the possible values of income_ver and what is the proportion of all records in each category of income_ver? Use code to find this, do not use the above dictionary, it might be wrong or out of date.
group_by(loan, income_ver) %>% summarise(proportion = n()/nrow(loan))

So if we are interested in determining the variation of interest_rate as a function of income_ver. What does lm mean for problems like this?

To understand how to handle categorical variables, we will start with special type of categorical variable called an indicator variable. We have such a variable in the loan data set, it’s called bankruptcy and it takes the value 0 if the applicant has had no previous bankruptcies and 1 if the applicant has had at leat one previous bankruptcy.

  1. Coding Question Find the proportion of applicants with no bankruptcy and the proportion of applicants who have had at least one bankruptcy.
group_by(loan, income_ver) %>% summarise(proportion = n()/nrow(loan))
  1. Response Questions What is the difference between the variables income_ver and bankruptcy?
group_by(loan, bankruptcy) %>% summarise(proportion = n())

Income_ver is a categorical variable while bankruptcy is a quantitative variable.

Given a value \(x\) of bankruptcy does it makes sense to multiply \(x\) by a number, e.g., \(2.3*x\)? Hint: consider the possible values of \(x\)


  1. Coding Question

Summarize the results of regressing interest_rate on bankruptcy using lm

summarise(loan, income_ver)
summarise(loan, bankruptcy)
NA
  1. Response Question

Interpret the results of this regression:

The R^2 shows that the model is not too accurate given the low R-squared value and high residual percentage. The low p-value shows that there is a significant relationship between interest rate and bankruptcy.

  1. Coding Question What is the average interest rate for applicants who have had no bankruptcies?
summary(lm(interest_rate ~ bankruptcy, data = loan)) 

Call:
lm(formula = interest_rate ~ bankruptcy, data = loan)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.7648 -3.6448 -0.4548  2.7120 18.6020 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  12.3380     0.0533 231.490  < 2e-16 ***
bankruptcy    0.7368     0.1529   4.819 1.47e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.996 on 9998 degrees of freedom
Multiple R-squared:  0.002317,  Adjusted R-squared:  0.002217 
F-statistic: 23.22 on 1 and 9998 DF,  p-value: 1.467e-06
  1. Response Question How does this value compare with the estimated intercept?

This value is the same as the estimated intercept.

How can you explain this value?

When x equals 0, the intercept is the expected mean of the y value.

  1. Coding Question

What is the average interest rate for people who have had at least one bankruptcy?

group_by( loan, bankruptcy) %>% summarize(average_int = interest_rate)
`summarise()` has grouped output by 'bankruptcy'. You can override using the `.groups` argument.
  1. Could you have determined this value from the regression summary? If so, how?

Yes. The avg_interest_rate(13.07479) = the estimated std intercept(12.3380) + 1 * estimated std bankruptcy(0.7368)

  1. How do you interpret the meaning of slope in this context?

For each unit of x, y increases 0.7368.

  1. Which is more important the estimated slope or \(R^2\)?

The estimated slope is more important. Without the slope we would have no understanding of the relationship between the two variables.

Now for Categorical variables in general.

  1. Coding Question Print the summary of regressing interest_rate on income_ver
group_by(loan, bankruptcy) %>%
  summarise(avg_interest_rate = mean(interest_rate)) %>%
  filter(bankruptcy == 1)
NA
  1. Response Question How many variables does the regression say we have?

Three: not, source_only & verified

  1. Coding Question Calculate mean(interest_rate) for each level of the categorical variable income_ver
regression2 <- lm(interest_rate ~ income_ver, data = loan)
summary(regression2)

Call:
lm(formula = interest_rate ~ income_ver, data = loan)

Residuals:
    Min      1Q  Median      3Q     Max 
-9.0437 -3.7495 -0.6795  2.5345 19.6905 

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)           11.09946    0.08091  137.18   <2e-16 ***
income_versource_only  1.41602    0.11074   12.79   <2e-16 ***
income_ververified     3.25429    0.12970   25.09   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.851 on 9997 degrees of freedom
Multiple R-squared:  0.05945,   Adjusted R-squared:  0.05926 
F-statistic: 315.9 on 2 and 9997 DF,  p-value: < 2.2e-16
  1. Response Question
  1. How do your values correspond to the coefficient values in the regression? The y values are the same. The other variables are different from their coefficients.

  2. Given what you know now why do you think you have two new variables related to income_ver? The income_ver is dependent on multiple variables such as income and loan.

  3. Do you get an extra variable in case of single variable regression? If so what is it? No the single variable regression should only have one dependent variable and one independent variable.

  4. How would you write a regression model for the regression of interest_rate on income_verified? Y = income_verified + B*interest_rate

Multiple Regression

Multiple regression means that we are regressing on a sum of variables. In fact when we regress on a categorical variable we are doing multiple regression! Why? Regression is meant to consider at least two categories.

Since the loan data set gives us a lot of variables let’s try regression on all of them. (run the code below)

group_by(loan, income_ver) %>%
  summarise(avg_interest_rate = mean(interest_rate))
  1. Response Question
  1. Comment on the \(p\)-values for the variables, noting anything interesting.

All of the variables are significant except ‘issuedMar2018’ and ‘issuedJan2018’

  1. Comment on the difference between \(R^2\) and adj-\(R^2\). Which do you think is more variable. Do you think the value of either \(R^2\) is too low to make this model useful?

The adjusted r-squared is better to measure the significant variables.

  1. How would you suggest making the model better? Removing the issued variable from the model.

Model Selection

The multi-variate model we have just constructed is not necessarily the best model.

Why might this be the case? The issued variable is not significant and may be making the model less accurate.

How might we try to improve things? Removing the issued variable.

Identifying variables that might not be important.

Let’s look at the coefficient estimates for the full model (the one with all the variables)

summary(lm(interest_rate ~ income_ver + debt_to_income + credit_util + bankruptcy + term + issued + credit_checks, data = loan))

Call:
lm(formula = interest_rate ~ income_ver + debt_to_income + credit_util + 
    bankruptcy + term + issued + credit_checks, data = loan)

Residuals:
     Min       1Q   Median       3Q      Max 
-19.9070  -3.4362  -0.7239   2.5397  18.0874 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)            3.969e+00  2.087e-01  19.016  < 2e-16 ***
income_versource_only  1.083e+00  1.036e-01  10.456  < 2e-16 ***
income_ververified     2.482e+00  1.223e-01  20.293  < 2e-16 ***
debt_to_income         3.787e-02  3.121e-03  12.137  < 2e-16 ***
credit_util           -4.323e-06  8.733e-07  -4.950 7.54e-07 ***
bankruptcy             5.043e-01  1.383e-01   3.645 0.000269 ***
term                   1.495e-01  4.123e-03  36.257  < 2e-16 ***
issuedJan2018         -2.061e-02  1.128e-01  -0.183 0.854969    
issuedMar2018         -9.280e-02  1.112e-01  -0.834 0.404037    
credit_checks          2.233e-01  1.917e-02  11.647  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.489 on 9966 degrees of freedom
  (24 observations deleted due to missingness)
Multiple R-squared:  0.1942,    Adjusted R-squared:  0.1934 
F-statistic: 266.8 on 9 and 9966 DF,  p-value: < 2.2e-16
  1. Response Question Look at the \(p\)-values. What are the largest what are smallest. Are any of the variable estimates not significant at the 95% level?

The largest p-values are both of the ‘issued’ variables. The smallest are ‘term’ and ‘income_verified’.

  1. Coding Question Rerun the regression leaving out the non-significant variables.
coef(summary(lm(interest_rate ~ income_ver + debt_to_income + credit_util + bankruptcy + term + issued + credit_checks, data = loan)))
                           Estimate   Std. Error    t value      Pr(>|t|)
(Intercept)            3.969028e+00 2.087232e-01 19.0157518  3.163114e-79
income_versource_only  1.082767e+00 1.035565e-01 10.4558002  1.866232e-25
income_ververified     2.482072e+00 1.223104e-01 20.2932296  9.462920e-90
debt_to_income         3.787448e-02 3.120564e-03 12.1370626  1.160422e-33
credit_util           -4.323176e-06 8.733479e-07 -4.9501194  7.538276e-07
bankruptcy             5.042764e-01 1.383482e-01  3.6449793  2.687739e-04
term                   1.495000e-01 4.123314e-03 36.2572457 1.696856e-270
issuedJan2018         -2.060967e-02 1.127529e-01 -0.1827863  8.549694e-01
issuedMar2018         -9.279620e-02 1.112041e-01 -0.8344677  4.040375e-01
credit_checks          2.232706e-01 1.916941e-02 11.6472314  3.770754e-31
  1. Response Questions

Compare this more parsimonious model with the full model. What are your observations? The R-Squared is higher but the R-Squared is lower.

If you were to delete a variable from this model, which one would you delete? None because removing any other variables would reduce the accuracy of the model.

  1. Code Question Estimate the model you just proposed.
regression3 <- lm(formula = interest_rate ~ income_ver + debt_to_income + credit_util +
                    bankruptcy + term + credit_checks, data = loan)
summary(regression3)

Call:
lm(formula = interest_rate ~ income_ver + debt_to_income + credit_util + 
    bankruptcy + term + credit_checks, data = loan)

Residuals:
     Min       1Q   Median       3Q      Max 
-19.8988  -3.4316  -0.7204   2.5421  18.1083 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)            3.928e+00  1.960e-01  20.042  < 2e-16 ***
income_versource_only  1.080e+00  1.035e-01  10.436  < 2e-16 ***
income_ververified     2.479e+00  1.223e-01  20.278  < 2e-16 ***
debt_to_income         3.790e-02  3.120e-03  12.148  < 2e-16 ***
credit_util           -4.319e-06  8.733e-07  -4.946 7.68e-07 ***
bankruptcy             5.055e-01  1.383e-01   3.654  0.00026 ***
term                   1.495e-01  4.122e-03  36.272  < 2e-16 ***
credit_checks          2.233e-01  1.917e-02  11.652  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.488 on 9968 degrees of freedom
  (24 observations deleted due to missingness)
Multiple R-squared:  0.1941,    Adjusted R-squared:  0.1935 
F-statistic: 342.9 on 7 and 9968 DF,  p-value: < 2.2e-16
  1. Response Question

What are your observations? Without the ‘issued’ variable in the model the accuracy is best. All of the current variables are significant for the improvement of this model.

LS0tDQp0aXRsZTogIk11bHRpLXJlZ3Jlc3Npb24iDQphdXRob3I6ICJSaWNobW9uZCBZZWJvYWgiDQpkYXRlOiAiQXVndXN0IDUsIDIwMjEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCmBgYHtyfQ0KIyBGaXJzdCBpbnN0YWxsIHRoZSByZXF1aXJlZCBwYWNrYWdlczoNCg0KI2luc3RhbGxlZC5wYWNrYWdlcygnb3BlbmludHJvJykNCiNpbnN0YWxsZWQucGFja2FnZXMoJ3RpZHl2ZXJzZScpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShvcGVuaW50cm8pDQpgYGANCg0KIyMgSW50cm9kdWN0aW9uDQoNClRoaXMgd29ya2Jvb2sgaXMgYW4gaW4gY2xhc3MgYXNzaWdubWVudC4gQWZ0ZXIgY29tcGxldGlvbiB5b3Ugd2lsbCBoYXZlIGEgZ29vZCBwcmFjdGljYWwga25vd2xlZGdlIG9mIE11bHRpcGxlIFJlZ3Jlc3Npb24gYW5kIExvZ2lzdGljIFJlZ3Jlc3Npb24uDQoNClRoZXJlIGFyZSB0d28gdHlwZXMgb2YgZXhlcmNpc2VzIGluIHRoaXMgVHV0b3JpYWwuDQoNCipSZXNwb25zZSBxdWVzdGlvbnMqIFRoZXNlIHF1ZXN0aW9ucyBhcmUgdGhvdWdodCBleGVyY2lzZXMgYW5kIHJlcXVpcmUgYSB3cml0dGVuIHJlc3BvbnNlLg0KDQoqKlJlc3BvbnNlIFF1ZXN0aW9uIEV4YW1wbGU6KioNCg0KV2hhdCBpcyB0aGUgQ2FwaXRhbCBvZiBOb3J0aCBEYWtvdGE/DQoNClJlc3BvbnNlOiAqKkJpc21hcmNrKioNCg0KKkNvZGluZyBxdWVzdGlvbnMqIFRoZXNlIHF1ZXN0aW9ucyByZXF1aXJlIGVudGVyaW5nIFIgY29kZSBpbiB0aGUgcHJvdmlkZWQgY2h1bmsuDQoNCioqQ29kaW5nIHF1ZXN0aW9uIGV4YW1wbGUqKg0KDQpXcml0ZSB0aGUgUiBjb2RlIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiB0aGUgd2hvbGUgbnVtYmVycyBmcm9tIDEgdG8gMTAsDQplbnRlciB5b3VyIGNvZGUgaGVyZToNCmBgYHtyfQ0KbWVhbigxLDEwKQ0KYGBgDQoNCg0KIyMgU2VjdGlvbiAxIExvYW5zDQoNCldlIHdpbGwgY29uc2lkZXIgZGF0YSBhYm91dCBsb2FucyBmcm9tIHRoZSBwZWVyLXRvLXBlZXIgbGVuZGVyLCBMZW5kaW5nIENsdWIuIFRoZSBkYXRhIGlzIGNvbnRhaW5lZCBpbiB0aGUgYGxvYW4uY3N2YCBmaWxlIGNvbnRhaW5lZCBpbiB0aGUgcHJvamVjdCBkaXJlY3RvcnkuDQoNCg0KKEApICoqQ29kaW5nIFF1ZXN0aW9uIDEqKg0KbG9hZCB0aGUgZGF0YSBpbnRvIGEgbmV3IHRpYmJsZSBjYWxsZWQgYGxvYW5gDQpgYGB7cn0NCmxvYW4gPC0gcmVhZF9jc3YoJ2xvYW4uY3N2JykNCmBgYA0KDQpZb3UgbWF5IGZpbmQgdGhlIGZvbGxvd2luZyB2YXJpYWJsZSBkaWN0aW9uYXJ5IHVzZWZ1bC4NCg0KVmFyaWFibGUgZGljdGlvbmFyeSBmb3IgYGxvYW5gLg0KPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KICAqKnZhcmlhYmxlKiogICAgICAgICoqZGVzY3JpcHRpb24qKg0KLS0tLS0tLS0tLS0tLS0gICAgICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYGludGVyZXN0X3JhdGVgICAgICAgIEludGVyZXN0IHJhdGUgZm9yIHRoZSBsb2FuDQpgaW5jb21lX3ZlcmAgICAgICAgICAgQ2F0ZWdvcmljYWwgdmFyaWFibGUgZGVzY3JpYmluZyB3aGV0aGVyIHRoZSBib3Jyb3dlcidzIGluY29tZSBzb3VyY2UgYW5kIGFtb3VudCBoYXZlIGJlZW4gdmVyaWZpZWQsIGxldmVscyBgdmVyaWZpZWRgLGBzb3VyY2Vfb25seWAsIGBub3RgDQpgZGVwdF90b19pbmNvbWVgICAgICAgRGVidC10by1pbmNvbWUgcmF0aW8sIHdoaWNoIGlzIHRoZSBwZXJjZW50IG9mIHRvdGFsIGRlYnQgb2YgdGhlIGJvcnJvd2VyIGRpdmlkZWQgYnkgdGhlaXIgdG90YWwgaW5jb21lLg0KYGNyZWRpdF91dGlsYCAgICAgICAgICAgT2YgYWxsIHRoZSBDcmVkaXQgYXZhaWxhYmxlIHRvIHRoZSBib3Jyb3dlciwgd2hhdCBmcmFjdGlvbiBhcmUgdGhleSB1c2luZy4gRm9yIGV4YW1wbGUgdGhlIGNyZWRpdCB1dGlsaXphdGlvbiBvbiB0aGUgY3JlZGl0IGNhcmQgd291bGQgYmUgdGhlIGNhcmQncyBiYWxhbmNlIGRpdmlkZWQgYnkgdGhlIGNhcmQncyBjcmVkaXQgbGltaXQNCmBiYW5rcnVwdGN5YCAgICAgICAgICAgQW4gaW5kaWNhdG9yIHZhcmlhYmxlIGZvciB3aGV0aGVyIHRoZSBib3Jyb3dlciBoYXMgYSBwYXN0IGJhbmtydXB0Y3kgaW4gaGVyIHJlY29yZC4gVGhpcyB2YXJpYWJsZSB0YWtlcyBhIHZhbHVlIG9mIDEgaWYgdGhlIGFuc3dlciBpcyAieWVzIiBhbmQgMCBpZiB0aGUgYW5zd2VyIGlzICJubyIuDQpgdGVybWAgICAgICAgICAgICAgICAgICBUaGUgbGVuZ3RoIG9mIHRoZSBsb2FuLCBpbiBtb250aHMuDQpgaXNzdWVkYCAgICAgICAgICAgICAgICBUaGUgbW9udGggYW5kIHllYXIgdGhlIGxvYW4gd2FzIGlzc3VlZC4NCmBjcmVkaXRfY2hlY2tzYCAgICAgICAgIE51bWJlciBvZiBjcmVkaXQgY2hlY2tzIGluIHRoZSBsYXN0IDEyIG1vbnRocy4gRm9yIGV4YW1wbGUsIHdoZW4gZmlsaW5nIGFuIGFwcGxpY2F0aW9uIGZvciBhIGNyZWRpdCBjYXJkcywgaXQgaXMgY29tbW9uIGZvciB0aGUgY29tcGFueSByZWNlaXZpbmcgdGhlIGFwcGxpY2F0aW9uIHRvIHJ1biBhIGNyZWRpdCBjaGVjay4NCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KIyMgVXNpbmcgQ2F0ZWdvcmljYWwgVmFyaWFibGVzIGFzIFByZWRpY3RvcnMNCg0KUmVjYWxsIHRoZSBzaW5nbGUgdmFyaWFibGUgbW9kZWxzIHdlIGhhdmUgYmVlbiBzdHVkeWluZy4gVGhlIHByZWRpY3Rpb24gbG9va3MgbGlrZSB0aGlzLg0KJCQgXGhhdHtZfSA9IFxoYXR7XGJldGFfMH0gKyBcaGF0e1xiZXRhXzF9WCQkDQpXaGVyZSB0aGUgdmFyaWFibGVzIGRlbm90ZWQgYnkgdGhlICRcaGF0e1wsfSQgb3ZlciB0aGVtIGFyZSB0aGUgZXN0aW1hdGVzIG9idGFpbmVkIGJ5IGBsbWAuDQoNCkluIGV2ZXJ5IGNhc2Ugd2UgaGF2ZSwgbW9yZSBvciBsZXNzIGltcGxpY2l0bHksIGFzc3VtZWQgdGhhdCBYIGlzIGEgbnVtZXJpYyB2YXJpYWJsZS4gV291bGQgdGhpcyBtYWtlIGFueSBzZW5zZSBpZiAkWCQgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZT8NCg0KKEApICoqUmVzcG9uc2UgUXVlc3Rpb24qKg0KIFdoYXQgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZT8NCiANCiBBIHZhcmlhYmxlIHdoaWNoIGlzIG5vdCBxdWFudGl0YXRpdmUgIA0KDQooQCkgKipDb2RpbmcgUXVlc3Rpb24qKiAgDQpDb25zaWRlciB0aGUgdmFyaWFibGUgYGluY29tZV92ZXJgLCB3aGF0IGFyZSB0aGUgcG9zc2libGUgdmFsdWVzIG9mIGBpbmNvbWVfdmVyYCBhbmQgd2hhdCBpcyB0aGUgcHJvcG9ydGlvbiBvZiBhbGwgcmVjb3JkcyBpbiBlYWNoIGNhdGVnb3J5IG9mIGBpbmNvbWVfdmVyYD8gVXNlIGNvZGUgdG8gZmluZCB0aGlzLCBkbyBub3QgdXNlIHRoZSBhYm92ZSBkaWN0aW9uYXJ5LCBpdCBtaWdodCBiZSB3cm9uZyBvciBvdXQgb2YgZGF0ZS4NCg0KYGBge3IsIHZhbHVlcyBvZiBpbmNvbWVfdmVyfQ0KZ3JvdXBfYnkobG9hbiwgaW5jb21lX3ZlcikgJT4lIHN1bW1hcmlzZShwcm9wb3J0aW9uID0gbigpL25yb3cobG9hbikpDQpgYGANClNvIGlmIHdlIGFyZSBpbnRlcmVzdGVkIGluIGRldGVybWluaW5nIHRoZSB2YXJpYXRpb24gb2YgYGludGVyZXN0X3JhdGVgIGFzIGEgZnVuY3Rpb24gb2YgYGluY29tZV92ZXJgLiBXaGF0IGRvZXMgYGxtYCAgbWVhbiBmb3IgcHJvYmxlbXMgbGlrZSB0aGlzPw0KDQpUbyB1bmRlcnN0YW5kIGhvdyB0byBoYW5kbGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB3ZSB3aWxsIHN0YXJ0IHdpdGggc3BlY2lhbCB0eXBlIG9mIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGNhbGxlZCBhbiBpbmRpY2F0b3IgdmFyaWFibGUuIFdlIGhhdmUgc3VjaCBhIHZhcmlhYmxlIGluIHRoZSBgbG9hbmAgZGF0YSBzZXQsIGl0J3MgY2FsbGVkIGBiYW5rcnVwdGN5YCBhbmQgaXQgdGFrZXMgdGhlIHZhbHVlIDAgaWYgdGhlIGFwcGxpY2FudCBoYXMgaGFkIG5vIHByZXZpb3VzIGJhbmtydXB0Y2llcyBhbmQgMSBpZiB0aGUgYXBwbGljYW50IGhhcyBoYWQgYXQgbGVhdCBvbmUgcHJldmlvdXMgYmFua3J1cHRjeS4NCg0KKEApICoqQ29kaW5nIFF1ZXN0aW9uKioNCkZpbmQgdGhlIHByb3BvcnRpb24gb2YgYXBwbGljYW50cyB3aXRoIG5vIGJhbmtydXB0Y3kgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGFwcGxpY2FudHMgd2hvIGhhdmUgaGFkIGF0IGxlYXN0IG9uZSBiYW5rcnVwdGN5Lg0KYGBge3J9DQpncm91cF9ieShsb2FuLCBiYW5rcnVwdGN5KSAlPiUgc3VtbWFyaXNlKHByb3BvcnRpb24gPSBuKCkpDQpgYGANCg0KKEApICoqUmVzcG9uc2UgUXVlc3Rpb25zKioNCldoYXQgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGBpbmNvbWVfdmVyYCBhbmQgYGJhbmtydXB0Y3lgPw0KDQpgYGB7cn0NCnN1bW1hcmlzZShsb2FuLCBpbmNvbWVfdmVyKQ0Kc3VtbWFyaXNlKGxvYW4sIGJhbmtydXB0Y3kpDQoNCmBgYA0KDQpJbmNvbWVfdmVyIGlzIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2hpbGUgYmFua3J1cHRjeSBpcyBhIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4NCg0KR2l2ZW4gYSB2YWx1ZSAkeCQgb2YgYGJhbmtydXB0Y3lgIGRvZXMgaXQgbWFrZXMgc2Vuc2UgdG8gbXVsdGlwbHkgJHgkIGJ5IGEgbnVtYmVyLCBlLmcuLCAkMi4zKngkPyAqSGludDogY29uc2lkZXIgdGhlIHBvc3NpYmxlIHZhbHVlcyBvZiAkeCQqDQoNCi0tLQ0KDQoNCihAKSAqKkNvZGluZyBRdWVzdGlvbioqDQoNClN1bW1hcml6ZSB0aGUgcmVzdWx0cyBvZiByZWdyZXNzaW5nIGBpbnRlcmVzdF9yYXRlYCBvbiBgYmFua3J1cHRjeWAgdXNpbmcgYGxtYCANCg0KYGBge3J9DQpzdW1tYXJ5KGxtKGludGVyZXN0X3JhdGUgfiBiYW5rcnVwdGN5LCBkYXRhID0gbG9hbikpIA0KYGBgDQooQCkgKipSZXNwb25zZSBRdWVzdGlvbioqDQoNCkludGVycHJldCB0aGUgcmVzdWx0cyBvZiB0aGlzIHJlZ3Jlc3Npb246DQoNClRoZSBSXjIgc2hvd3MgdGhhdCB0aGUgbW9kZWwgaXMgbm90IHRvbyBhY2N1cmF0ZSBnaXZlbiB0aGUgbG93IFItc3F1YXJlZCB2YWx1ZSBhbmQgaGlnaCByZXNpZHVhbCBwZXJjZW50YWdlLiBUaGUgbG93IHAtdmFsdWUgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGludGVyZXN0IHJhdGUgYW5kIGJhbmtydXB0Y3kuDQoNCihAKSAqKkNvZGluZyBRdWVzdGlvbioqDQpXaGF0IGlzIHRoZSBhdmVyYWdlIGludGVyZXN0IHJhdGUgZm9yIGFwcGxpY2FudHMgd2hvIGhhdmUgaGFkIG5vIGJhbmtydXB0Y2llcz8NCmBgYHtyfQ0KZ3JvdXBfYnkoIGxvYW4sIGJhbmtydXB0Y3kpICU+JSBzdW1tYXJpemUoYXZlcmFnZV9pbnQgPSBpbnRlcmVzdF9yYXRlKQ0KYGBgDQoNCihAKSAqKlJlc3BvbnNlIFF1ZXN0aW9uKioNCkhvdyBkb2VzIHRoaXMgdmFsdWUgY29tcGFyZSB3aXRoIHRoZSBlc3RpbWF0ZWQgaW50ZXJjZXB0Pw0KDQpUaGlzIHZhbHVlIGlzIHRoZSBzYW1lIGFzIHRoZSBlc3RpbWF0ZWQgaW50ZXJjZXB0Lg0KDQpIb3cgY2FuIHlvdSBleHBsYWluIHRoaXMgdmFsdWU/DQoNCldoZW4geCBlcXVhbHMgMCwgdGhlIGludGVyY2VwdCBpcyB0aGUgZXhwZWN0ZWQgbWVhbiBvZiB0aGUgeSB2YWx1ZS4NCg0KKEApICoqQ29kaW5nIFF1ZXN0aW9uKioNCg0KV2hhdCBpcyB0aGUgYXZlcmFnZSBpbnRlcmVzdCByYXRlIGZvciBwZW9wbGUgd2hvIGhhdmUgaGFkIGF0IGxlYXN0IG9uZSBiYW5rcnVwdGN5Pw0KDQpgYGB7cn0NCmdyb3VwX2J5KGxvYW4sIGJhbmtydXB0Y3kpICU+JQ0KICBzdW1tYXJpc2UoYXZnX2ludGVyZXN0X3JhdGUgPSBtZWFuKGludGVyZXN0X3JhdGUpKSAlPiUNCiAgZmlsdGVyKGJhbmtydXB0Y3kgPT0gMSkNCmBgYA0KMS4gQ291bGQgeW91IGhhdmUgZGV0ZXJtaW5lZCB0aGlzIHZhbHVlIGZyb20gdGhlIHJlZ3Jlc3Npb24gc3VtbWFyeT8gSWYgc28sIGhvdz8NCg0KWWVzLiBUaGUgYXZnX2ludGVyZXN0X3JhdGUoMTMuMDc0NzkpID0gIHRoZSBlc3RpbWF0ZWQgc3RkIGludGVyY2VwdCgxMi4zMzgwKSArIDEgKiBlc3RpbWF0ZWQgc3RkIGJhbmtydXB0Y3koMC43MzY4KQ0KDQoxLiBIb3cgZG8geW91IGludGVycHJldCB0aGUgbWVhbmluZyBvZiBzbG9wZSBpbiB0aGlzIGNvbnRleHQ/DQoNCkZvciBlYWNoIHVuaXQgb2YgeCwgeSBpbmNyZWFzZXMgMC43MzY4Lg0KDQoxLiBXaGljaCBpcyBtb3JlIGltcG9ydGFudCB0aGUgZXN0aW1hdGVkIHNsb3BlIG9yICRSXjIkPw0KDQpUaGUgZXN0aW1hdGVkIHNsb3BlIGlzIG1vcmUgaW1wb3J0YW50LiBXaXRob3V0IHRoZSBzbG9wZSB3ZSB3b3VsZCBoYXZlIG5vIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28gdmFyaWFibGVzLg0KDQojIyMjIE5vdyBmb3IgQ2F0ZWdvcmljYWwgdmFyaWFibGVzIGluIGdlbmVyYWwuDQoNCihAKSAqKkNvZGluZyBRdWVzdGlvbioqIA0KUHJpbnQgdGhlIHN1bW1hcnkgb2YgcmVncmVzc2luZyBgaW50ZXJlc3RfcmF0ZWAgb24gYGluY29tZV92ZXJgDQoNCmBgYHtyfQ0KcmVncmVzc2lvbjIgPC0gbG0oaW50ZXJlc3RfcmF0ZSB+IGluY29tZV92ZXIsIGRhdGEgPSBsb2FuKQ0Kc3VtbWFyeShyZWdyZXNzaW9uMikNCmBgYA0KDQooQCkgKipSZXNwb25zZSBRdWVzdGlvbioqDQpIb3cgbWFueSB2YXJpYWJsZXMgZG9lcyB0aGUgcmVncmVzc2lvbiBzYXkgd2UgaGF2ZT8NCg0KVGhyZWU6IG5vdCwgc291cmNlX29ubHkgJiB2ZXJpZmllZCANCg0KKEApICoqQ29kaW5nIFF1ZXN0aW9uKioNCkNhbGN1bGF0ZSAgYG1lYW4oaW50ZXJlc3RfcmF0ZSlgIGZvciBlYWNoIGxldmVsIG9mIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBgaW5jb21lX3ZlcmANCmBgYHtyfQ0KZ3JvdXBfYnkobG9hbiwgaW5jb21lX3ZlcikgJT4lDQogIHN1bW1hcmlzZShhdmdfaW50ZXJlc3RfcmF0ZSA9IG1lYW4oaW50ZXJlc3RfcmF0ZSkpDQpgYGANCg0KKEApICoqUmVzcG9uc2UgUXVlc3Rpb24qKg0KMS4gSG93IGRvIHlvdXIgdmFsdWVzIGNvcnJlc3BvbmQgdG8gdGhlIGNvZWZmaWNpZW50IHZhbHVlcyBpbiB0aGUgcmVncmVzc2lvbj8gVGhlIHkgdmFsdWVzIGFyZSB0aGUgc2FtZS4gVGhlIG90aGVyIHZhcmlhYmxlcyBhcmUgZGlmZmVyZW50IGZyb20gdGhlaXIgY29lZmZpY2llbnRzLg0KDQoyLiBHaXZlbiB3aGF0IHlvdSBrbm93IG5vdyB3aHkgZG8geW91IHRoaW5rIHlvdSBoYXZlIHR3byBuZXcgdmFyaWFibGVzIHJlbGF0ZWQgdG8gYGluY29tZV92ZXJgPyBUaGUgaW5jb21lX3ZlciBpcyBkZXBlbmRlbnQgb24gbXVsdGlwbGUgdmFyaWFibGVzIHN1Y2ggYXMgaW5jb21lIGFuZCBsb2FuLiAgICAgICAgICAgIA0KDQozLiBEbyB5b3UgZ2V0IGFuIGV4dHJhIHZhcmlhYmxlIGluIGNhc2Ugb2Ygc2luZ2xlIHZhcmlhYmxlIHJlZ3Jlc3Npb24/IElmIHNvIHdoYXQgaXMgaXQ/IE5vIHRoZSBzaW5nbGUgdmFyaWFibGUgcmVncmVzc2lvbiBzaG91bGQgb25seSBoYXZlIG9uZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIG9uZSBpbmRlcGVuZGVudCB2YXJpYWJsZS4gDQoNCjQuIEhvdyB3b3VsZCB5b3Ugd3JpdGUgYSByZWdyZXNzaW9uIG1vZGVsIGZvciB0aGUgcmVncmVzc2lvbiBvZiBgaW50ZXJlc3RfcmF0ZWAgb24gYGluY29tZV92ZXJpZmllZGA/IFkgPSBpbmNvbWVfdmVyaWZpZWQgKyBCKmludGVyZXN0X3JhdGUNCg0KIyMjIE11bHRpcGxlIFJlZ3Jlc3Npb24NCg0KTXVsdGlwbGUgcmVncmVzc2lvbiBtZWFucyB0aGF0IHdlIGFyZSByZWdyZXNzaW5nIG9uIGEgc3VtIG9mIHZhcmlhYmxlcy4gSW4gZmFjdCB3aGVuIHdlIHJlZ3Jlc3Mgb24gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3ZSBhcmUgZG9pbmcgbXVsdGlwbGUgcmVncmVzc2lvbiEgV2h5PyBSZWdyZXNzaW9uIGlzIG1lYW50IHRvIGNvbnNpZGVyIGF0IGxlYXN0IHR3byBjYXRlZ29yaWVzLg0KDQpTaW5jZSB0aGUgbG9hbiBkYXRhIHNldCBnaXZlcyB1cyBhIGxvdCBvZiB2YXJpYWJsZXMgbGV0J3MgdHJ5IHJlZ3Jlc3Npb24gb24gYWxsIG9mIHRoZW0uIChydW4gdGhlIGNvZGUgYmVsb3cpDQpgYGB7cn0NCnN1bW1hcnkobG0oaW50ZXJlc3RfcmF0ZSB+IGluY29tZV92ZXIgKyBkZWJ0X3RvX2luY29tZSArIGNyZWRpdF91dGlsICsgYmFua3J1cHRjeSArIHRlcm0gKyBpc3N1ZWQgKyBjcmVkaXRfY2hlY2tzLCBkYXRhID0gbG9hbikpDQpgYGANCihAKSAqKlJlc3BvbnNlIFF1ZXN0aW9uKioNCg0KMS4gQ29tbWVudCBvbiB0aGUgJHAkLXZhbHVlcyBmb3IgdGhlIHZhcmlhYmxlcywgbm90aW5nIGFueXRoaW5nIGludGVyZXN0aW5nLg0KDQogQWxsIG9mIHRoZSB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50IGV4Y2VwdCDigJhpc3N1ZWRNYXIyMDE44oCZIGFuZCDigJhpc3N1ZWRKYW4yMDE44oCZDQoNCjIuIENvbW1lbnQgb24gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiAkUl4yJCBhbmQgYWRqLSRSXjIkLiBXaGljaCBkbyB5b3UgdGhpbmsgaXMgbW9yZSB2YXJpYWJsZS4gRG8geW91IHRoaW5rIHRoZSB2YWx1ZSBvZiBlaXRoZXIgJFJeMiQgaXMgdG9vIGxvdyB0byBtYWtlIHRoaXMgbW9kZWwgdXNlZnVsPw0KDQpUaGUgYWRqdXN0ZWQgci1zcXVhcmVkIGlzIGJldHRlciB0byBtZWFzdXJlIHRoZSBzaWduaWZpY2FudCB2YXJpYWJsZXMuDQoNCjMuIEhvdyB3b3VsZCB5b3Ugc3VnZ2VzdCBtYWtpbmcgdGhlIG1vZGVsIGJldHRlcj8gUmVtb3ZpbmcgdGhlIGlzc3VlZCB2YXJpYWJsZSBmcm9tIHRoZSBtb2RlbC4NCg0KIyMjIE1vZGVsIFNlbGVjdGlvbg0KDQpUaGUgbXVsdGktdmFyaWF0ZSBtb2RlbCB3ZSBoYXZlIGp1c3QgY29uc3RydWN0ZWQgaXMgbm90IG5lY2Vzc2FyaWx5IHRoZSBiZXN0IG1vZGVsLiANCg0KV2h5IG1pZ2h0IHRoaXMgYmUgdGhlIGNhc2U/IFRoZSBpc3N1ZWQgdmFyaWFibGUgaXMgbm90IHNpZ25pZmljYW50IGFuZCBtYXkgYmUgbWFraW5nIHRoZSBtb2RlbCBsZXNzIGFjY3VyYXRlLg0KDQpIb3cgbWlnaHQgd2UgdHJ5IHRvIGltcHJvdmUgdGhpbmdzPyBSZW1vdmluZyB0aGUgaXNzdWVkIHZhcmlhYmxlLg0KDQojIyMjIElkZW50aWZ5aW5nIHZhcmlhYmxlcyB0aGF0IG1pZ2h0IG5vdCBiZSBpbXBvcnRhbnQuDQpMZXQncyBsb29rIGF0IHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMgZm9yIHRoZSAqKmZ1bGwqKiBtb2RlbCAodGhlIG9uZSB3aXRoIGFsbCB0aGUgdmFyaWFibGVzKQ0KYGBge3J9DQpjb2VmKHN1bW1hcnkobG0oaW50ZXJlc3RfcmF0ZSB+IGluY29tZV92ZXIgKyBkZWJ0X3RvX2luY29tZSArIGNyZWRpdF91dGlsICsgYmFua3J1cHRjeSArIHRlcm0gKyBpc3N1ZWQgKyBjcmVkaXRfY2hlY2tzLCBkYXRhID0gbG9hbikpKQ0KYGBgDQooQCkgKipSZXNwb25zZSBRdWVzdGlvbioqDQpMb29rIGF0IHRoZSAkcCQtdmFsdWVzLiBXaGF0IGFyZSB0aGUgbGFyZ2VzdCB3aGF0IGFyZSBzbWFsbGVzdC4gQXJlIGFueSBvZiB0aGUgdmFyaWFibGUgZXN0aW1hdGVzIG5vdCBzaWduaWZpY2FudCBhdCB0aGUgOTUlIGxldmVsPw0KDQpUaGUgbGFyZ2VzdCBwLXZhbHVlcyBhcmUgYm90aCBvZiB0aGUgJ2lzc3VlZCcgdmFyaWFibGVzLiBUaGUgc21hbGxlc3QgYXJlICd0ZXJtJyBhbmQgJ2luY29tZV92ZXJpZmllZCcuDQoNCihAKSAqKkNvZGluZyBRdWVzdGlvbioqDQpSZXJ1biB0aGUgcmVncmVzc2lvbiBsZWF2aW5nIG91dCB0aGUgbm9uLXNpZ25pZmljYW50IHZhcmlhYmxlcy4NCmBgYHtyfQ0KcmVncmVzc2lvbjMgPC0gbG0oZm9ybXVsYSA9IGludGVyZXN0X3JhdGUgfiBpbmNvbWVfdmVyICsgZGVidF90b19pbmNvbWUgKyBjcmVkaXRfdXRpbCArDQogICAgICAgICAgICAgICAgICAgIGJhbmtydXB0Y3kgKyB0ZXJtICsgY3JlZGl0X2NoZWNrcywgZGF0YSA9IGxvYW4pDQpzdW1tYXJ5KHJlZ3Jlc3Npb24zKQ0KYGBgDQooQCkgKipSZXNwb25zZSBRdWVzdGlvbnMqKg0KDQpDb21wYXJlIHRoaXMgbW9yZSBwYXJzaW1vbmlvdXMgbW9kZWwgd2l0aCB0aGUgZnVsbCBtb2RlbC4gV2hhdCBhcmUgeW91ciBvYnNlcnZhdGlvbnM/IFRoZSBSLVNxdWFyZWQgaXMgaGlnaGVyIGJ1dCB0aGUgUi1TcXVhcmVkIGlzIGxvd2VyLg0KDQpJZiB5b3Ugd2VyZSB0byBkZWxldGUgYSB2YXJpYWJsZSBmcm9tIHRoaXMgbW9kZWwsIHdoaWNoIG9uZSB3b3VsZCB5b3UgZGVsZXRlPyBOb25lIGJlY2F1c2UgcmVtb3ZpbmcgYW55IG90aGVyIHZhcmlhYmxlcyB3b3VsZCByZWR1Y2UgdGhlIGFjY3VyYWN5IG9mIHRoZSBtb2RlbC4NCg0KKEApICoqQ29kZSBRdWVzdGlvbioqDQpFc3RpbWF0ZSB0aGUgbW9kZWwgeW91IGp1c3QgcHJvcG9zZWQuDQoNCmBgYHtyfQ0Kc3VtbWFyeShyZWdyZXNzaW9uMykNCmBgYA0KDQooQCkgKipSZXNwb25zZSBRdWVzdGlvbioqDQoNCldoYXQgYXJlIHlvdXIgb2JzZXJ2YXRpb25zPyBXaXRob3V0IHRoZSAnaXNzdWVkJyB2YXJpYWJsZSBpbiB0aGUgbW9kZWwgdGhlIGFjY3VyYWN5IGlzIGJlc3QuIEFsbCBvZiB0aGUgY3VycmVudCB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50IGZvciB0aGUgaW1wcm92ZW1lbnQgb2YgdGhpcyBtb2RlbC4NCg0K