1 Library

library(tidyverse)
library(magrittr)

2 A simple example

2.1 Overview of the data

data("USArrests")
names(USArrests)
[1] "Murder"   "Assault"  "UrbanPop" "Rape"    
glimpse(USArrests)
Rows: 50
Columns: 4
$ Murder   <dbl> 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, 2.6, 10.4, 7.2, 2.2, 6.0…
$ Assault  <int> 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, 249, 113, 56, 115, 109, …
$ UrbanPop <int> 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57, 66, 52, 66, 51, 67, 85,…
$ Rape     <dbl> 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8, 20.2, 14.2, 24.0, 21.0,…

2.2 Fit the model

Varialble ~ X1 + X2 + X2

Equation <- "Murder ~ Assault + UrbanPop + Rape"

Model <- lm(Equation, 
            data = USArrests)

2.3 General results

summary(Model)

Call:
lm(formula = Equation, data = USArrests)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.3990 -1.9127 -0.3444  1.2557  7.4279 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.276639   1.737997   1.885   0.0657 .  
Assault      0.039777   0.005912   6.729 2.33e-08 ***
UrbanPop    -0.054694   0.027880  -1.962   0.0559 .  
Rape         0.061399   0.055740   1.102   0.2764    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.574 on 46 degrees of freedom
Multiple R-squared:  0.6721,    Adjusted R-squared:  0.6507 
F-statistic: 31.42 on 3 and 46 DF,  p-value: 3.322e-11
# Murder_ESTIMATED = 3.276639 + 
        # 0.039777*Assault + -0.054694*UrbanPop + Rap +  0.061399residual

We get from the main output:

  • An overview of the residuals
  • Parameters: estimates, standard errores, t values, p values, and stars,
  • Residual standard errors
  • Degrees of freedom
  • F-statistics: Used to assess the overall significance of the regression model by testing the null hypothesis that all the regression coefficients (except the intercept) are equal to zero. The F-test provides a measure of whether the linear relationship between the independent variables and the dependent variable is statistically significant.
jtools::summ(Model)
MODEL INFO:
Observations: 50
Dependent Variable: Murder
Type: OLS linear regression 

MODEL FIT:
F(3,46) = 31.42, p = 0.00
R² = 0.67
Adj. R² = 0.65 

Standard errors: OLS
------------------------------------------------
                     Est.   S.E.   t val.      p
----------------- ------- ------ -------- ------
(Intercept)          3.28   1.74     1.89   0.07
Assault              0.04   0.01     6.73   0.00
UrbanPop            -0.05   0.03    -1.96   0.06
Rape                 0.06   0.06     1.10   0.28
------------------------------------------------
TableResults <- broom::tidy(Model)
TableResults

2.4 Zoom in the parameters:

coef(Model)
(Intercept)     Assault    UrbanPop        Rape 
 3.27663918  0.03977717 -0.05469363  0.06139942 
confint(Model)
                  2.5 %      97.5 %
(Intercept) -0.22176766 6.775046016
Assault      0.02787760 0.051676734
UrbanPop    -0.11081365 0.001426387
Rape        -0.05079988 0.173598724

2.5 Diagnostic

2.5.1 The plot() function

plot(Model)

How to interpret these plots?

  • Residuals vs Fitted values: Check for non-linear patterns. If there are not non-linear relationships in the model we should see residuals equally spread.
  • Normal Q-Q (quantile-quantile) plot: If the residuals are normally distributed. They should follow a straight line.
  • Root of standardized residuals vs Fitted values (scale-location or spread location plot): Checks for homoscedasticity, if residuals are spread equally along the ranges of predictors. The vertical axis typically represents the square root of the absolute standardized residuals or the standardized residuals. The square root transformation is applied to stabilize the variance and ensure that negative residuals have meaningful values. Alternatively, the standardized residuals themselves can be used
  • Standardized residuals vs Leverage: To check for outliers.

2.6 Slow down: plots with the residuals

Y_Estimated <- predict(Model)
Residuals <- residuals(Model)

Diagnostic <- data.frame(Y_Estimated, Residuals)

Diagnostic
ggplot(data = Diagnostic) +
  geom_point(aes(x = Y_Estimated, y = Residuals)) +
  ggtitle("Spread of the residuals") +
  xlab("Estimated variable") + ylab("residuals") +
  theme_light()

ggplot(data = Diagnostic) +
  geom_histogram(aes(x = Residuals), binwidth = 0.7) +
  theme_light()

2.7 QQ Plots

Diagnostic %<>% arrange(Residuals) 
Diagnostic
Observations <- dim(USArrests)[1]
Probabilities <- seq(0.01, 0.99, 0.02)
Probabilities <- (1:Observations - 0.5)/Observations

Diagnostic %<>% mutate(Theoretical_Quantiles = qnorm(Probabilities))
Diagnostic
ggplot(data = Diagnostic) +
  geom_point(aes(x = Theoretical_Quantiles, y = Residuals)) +
  ggtitle("QQ Plot") +
  xlab("Theoretical Quantiles") + ylab("residuals") +
  theme_light()

Model$df.residual
[1] 46
estimated_sd <- sqrt(sum(Diagnostic$Residuals^2)/Model$df.residual)

Diagnostic %<>% mutate(Stand_Residuals = Residuals/estimated_sd) 
Diagnostic
ggplot(data = Diagnostic) +
  geom_point(aes(x = Theoretical_Quantiles, y = Stand_Residuals)) + 
  geom_line(aes(x = Theoretical_Quantiles, y = Theoretical_Quantiles)) +
  ggtitle("QQ Plot") +
  xlab("Theoretical Quantiles") + ylab("Standardized residuals") +
  theme_light()

2.8 Scale-location plot

Diagnostic %<>%
  mutate(sqrt_abs_std_resid = sqrt(abs(Stand_Residuals)) )

Diagnostic
ggplot(Diagnostic, aes(x = Y_Estimated, y = sqrt_abs_std_resid)) +
  geom_point() +
  geom_smooth(method = "loess", se = FALSE) +
  labs(x = "Predicted Values", y = "Scale-Location") +
  ggtitle("Scale-Location Plot") +
  theme_minimal()

2.9 Leverage

The leverage plot, also known as the leverage-residuals plot or the Cook’s distance plot, is a diagnostic plot used in linear regression analysis. It helps identify influential observations that have a significant impact on the regression model’s results.

Leverage refers to the potential of an observation to have a disproportionate effect on the estimated regression coefficients. Observations with high leverage can have a substantial impact on the regression line, either by exerting a pulling effect or by being outliers.

In the leverage plot, each point represents an observation from the dataset. The vertical axis shows the standardized residuals, which indicate how far each observation’s actual value deviates from its predicted value, taking into account the variability of the residuals. The horizontal axis represents the leverage values of the observations, which measure the potential influence of each observation on the estimated regression coefficients.

Leverage values are calculated using the “Hat” matrix, which is a matrix that maps the observed values to the predicted values. High leverage values suggest that an observation has a greater ability to affect the estimated regression coefficients. Observations with high leverage are located towards the ends of the horizontal axis.

Influential Observations: Observations with high leverage and large residuals can be considered influential observations. They have the potential to significantly affect the regression model’s parameters and can distort the results if they are outliers or if their predictors have extreme values.

Cook’s Distance: In addition to the leverage plot, Cook’s distance is often shown on the same graph or as a separate plot. Cook’s distance measures the influence of each observation on the entire regression model. Large values of Cook’s distance suggest influential observations that significantly affect the regression model’s results.

By examining the leverage plot and Cook’s distance, you can identify influential observations that may require further investigation. These observations may have a substantial impact on the regression analysis and could potentially affect the model’s conclusions.

It’s important to note that the interpretation of influential observations should be done cautiously, considering the context and objectives of the analysis. Influential observations may warrant additional scrutiny, but they should not be automatically removed without careful consideration and justification.

2.10 Multiolinearity: VIF

VIF is calculated for each independent variable in the regression model. For each variable, the VIF is obtained by regressing that variable against all the other independent variables in the model.

VIF = 1 / (1 - R²)

  • VIF = 1: No multicollinearity. The variable is not correlated with any other independent variables.
  • VIF > 1 and < 5: Moderate multicollinearity. The variable is correlated with other independent variables but not to a severe extent.
  • VIF > 5: High multicollinearity. The variable is highly correlated with other independent variables, which may cause challenges in interpreting the coefficient estimates.
cor(USArrests)
             Murder   Assault   UrbanPop      Rape
Murder   1.00000000 0.8018733 0.06957262 0.5635788
Assault  0.80187331 1.0000000 0.25887170 0.6652412
UrbanPop 0.06957262 0.2588717 1.00000000 0.4113412
Rape     0.56357883 0.6652412 0.41134124 1.0000000
regclass::VIF(Model)
 Assault UrbanPop     Rape 
1.794715 1.204229 2.015462 

2.11 Statistical tests

2.11.1 Correlation of the residuals

car::durbinWatsonTest(Model)
 lag Autocorrelation D-W Statistic p-value
   1       0.1014268       1.77713   0.446
 Alternative hypothesis: rho != 0
# H0 (null hypothesis): There is no correlation among the residuals.
# HA (alternative hypothesis): The residuals are autocorrelated.

# p-value is less than 0.05, reject the null hypothesis and conclude that the residuals in this regression model are autocorrelated

2.11.2 Normality of the residuals

tseries::jarque.bera.test(residuals(Model))

    Jarque Bera Test

data:  residuals(Model)
X-squared = 3.2393, df = 2, p-value = 0.198
# The null hypothesis is that the data are normally distributed
# If the p-value is less than the significance level (usually 0.05), we reject the null hypothesis and conclude that the data are not normally distributed.
ks.test(residuals(Model), "pnorm")

    Exact one-sample Kolmogorov-Smirnov test

data:  residuals(Model)
D = 0.24998, p-value = 0.003069
alternative hypothesis: two-sided
#  If the p-value is less than the significance level (usually 0.05), we reject the null hypothesis and conclude that the residuals do not follow a normal distribution.

2.11.3 Heteroscedasticity of the residuals

lmtest::bptest(Model)

    studentized Breusch-Pagan test

data:  Model
BP = 2.9605, df = 3, p-value = 0.3978
#  If the p-value is less than the significance level (usually 0.05), we reject the null hypothesis and conclude that there is evidence of heteroscedasticity in the residuals.

2.12 How to compare models?

logLik(Model)
'log Lik.' -116.1404 (df=5)
AIC(Model)
[1] 242.2808
BIC(Model)
[1] 251.8409
Model_1 <- lm("Murder ~ Assault + UrbanPop + Rape", data = USArrests)
Model_2 <- lm("Murder ~ Assault + UrbanPop", data = USArrests)
summary(Model_1)

Call:
lm(formula = "Murder ~ Assault + UrbanPop + Rape", data = USArrests)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.3990 -1.9127 -0.3444  1.2557  7.4279 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.276639   1.737997   1.885   0.0657 .  
Assault      0.039777   0.005912   6.729 2.33e-08 ***
UrbanPop    -0.054694   0.027880  -1.962   0.0559 .  
Rape         0.061399   0.055740   1.102   0.2764    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.574 on 46 degrees of freedom
Multiple R-squared:  0.6721,    Adjusted R-squared:  0.6507 
F-statistic: 31.42 on 3 and 46 DF,  p-value: 3.322e-11
summary(Model_2)

Call:
lm(formula = "Murder ~ Assault + UrbanPop", data = USArrests)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.5530 -1.7093 -0.3677  1.2284  7.5985 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.207153   1.740790   1.842   0.0717 .  
Assault      0.043910   0.004579   9.590 1.22e-12 ***
UrbanPop    -0.044510   0.026363  -1.688   0.0980 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.58 on 47 degrees of freedom
Multiple R-squared:  0.6634,    Adjusted R-squared:  0.6491 
F-statistic: 46.32 on 2 and 47 DF,  p-value: 7.704e-12
summary(Model_1)$r.squared
[1] 0.6720656
summary(Model_2)$r.squared
[1] 0.6634156
summary(Model_1)$adj.r.squared
[1] 0.6506786
summary(Model_2)$adj.r.squared
[1] 0.6490928
logLik(Model_1)
'log Lik.' -116.1404 (df=5)
logLik(Model_2)
'log Lik.' -116.7913 (df=4)
AIC(Model_1)
[1] 242.2808
AIC(Model_2)
[1] 241.5826
BIC(Model_1)
[1] 251.8409
BIC(Model_2)
[1] 249.2307
anova(Model_1, Model_2)
Analysis of Variance Table

Model 1: Murder ~ Assault + UrbanPop + Rape
Model 2: Murder ~ Assault + UrbanPop
  Res.Df    RSS Df Sum of Sq      F Pr(>F)
1     46 304.83                           
2     47 312.87 -1   -8.0407 1.2134 0.2764

If p value is small, then…?

The LRT is used to assess whether the more complex model (alternative model) provides a significantly better fit compared to the simpler model (null model).

A smaller p-value indicates stronger evidence against the null hypothesis (that the two models are the same)

  • Small p value: We can conclude that the more complex model provides a significantly better fit compared to the simpler model. The additional variables or complexity in the alternative model are considered important and contribute to the model’s improved fit.

  • Large p values: We do not have enough evidence to conclude that the more complex model provides a significantly better fit compared to the simpler model.

2.13 A note on LRT

My note: I hate using the anova() function. It creates confusion. There (at least) another two alternatives

lmtest::lrtest(Model_1, Model_2)
Likelihood ratio test

Model 1: Murder ~ Assault + UrbanPop + Rape
Model 2: Murder ~ Assault + UrbanPop
  #Df  LogLik Df  Chisq Pr(>Chisq)
1   5 -116.14                     
2   4 -116.79 -1 1.3018     0.2539

The likelihood ratio test statistic is calculated as the ratio of the likelihoods of the two models:

LR = -2 * (log(L₀(β₀)) - log(L₁(β₁))) df = p₁ - p₀

lrt <- -2 * (logLik(Model_2) - logLik(Model_1))

df <- length(coef(Model_1)) - length(coef(Model_2))

# Calculate the p-value using the chi-square distribution
p_value <- 1 - pchisq(lrt, df)

p_value
'log Lik.' 0.2538886 (df=4)

3 Another example

# install.packages("datarium")
# devtools::install_github("kassmbara/datarium")

library(datarium)
Warning: package ‘datarium’ was built under R version 4.2.3
data("marketing", package = "datarium")
marketing
cor(marketing)
             youtube   facebook  newspaper     sales
youtube   1.00000000 0.05480866 0.05664787 0.7822244
facebook  0.05480866 1.00000000 0.35410375 0.5762226
newspaper 0.05664787 0.35410375 1.00000000 0.2282990
sales     0.78222442 0.57622257 0.22829903 1.0000000
marketing %<>% 
  mutate(Total =  youtube + facebook + newspaper) %>% 
  mutate(Prop_Newspaper = newspaper/Total) %>% 
  mutate(Prop_Youtube = youtube/Total)
ggplot(data = marketing) +
  geom_point(aes( x= Prop_Newspaper     , y = sales)) +
  theme_light()

ggplot(data = marketing) +
  geom_point(aes( x= Prop_Youtube, y = sales)) +
  theme_light()

ggplot(data = marketing) +
  geom_point(aes( x= newspaper     , y = sales)) +
  theme_light()

summary(marketing)
    youtube          facebook       newspaper          sales           Total       
 Min.   :  0.84   Min.   : 0.00   Min.   :  0.36   Min.   : 1.92   Min.   : 14.04  
 1st Qu.: 89.25   1st Qu.:11.97   1st Qu.: 15.30   1st Qu.:12.45   1st Qu.:148.26  
 Median :179.70   Median :27.48   Median : 30.90   Median :15.48   Median :248.82  
 Mean   :176.45   Mean   :27.92   Mean   : 36.66   Mean   :16.83   Mean   :241.03  
 3rd Qu.:262.59   3rd Qu.:43.83   3rd Qu.: 54.12   3rd Qu.:20.88   3rd Qu.:337.35  
 Max.   :355.68   Max.   :59.52   Max.   :136.80   Max.   :32.40   Max.   :520.32  
 Prop_Newspaper      Prop_Youtube    
 Min.   :0.001049   Min.   :0.01429  
 1st Qu.:0.074894   1st Qu.:0.58580  
 Median :0.144936   Median :0.73248  
 Mean   :0.178757   Mean   :0.67809  
 3rd Qu.:0.234432   3rd Qu.:0.84160  
 Max.   :0.654732   Max.   :0.95846  
Model_Sales_Marketing <- lm("sales ~ youtube + facebook + newspaper", 
                            data = marketing)
summary(Model_Sales_Marketing)

Call:
lm(formula = "sales ~ youtube + facebook + newspaper", data = marketing)

Residuals:
     Min       1Q   Median       3Q      Max 
-10.5932  -1.0690   0.2902   1.4272   3.3951 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.526667   0.374290   9.422   <2e-16 ***
youtube      0.045765   0.001395  32.809   <2e-16 ***
facebook     0.188530   0.008611  21.893   <2e-16 ***
newspaper   -0.001037   0.005871  -0.177     0.86    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.023 on 196 degrees of freedom
Multiple R-squared:  0.8972,    Adjusted R-squared:  0.8956 
F-statistic: 570.3 on 3 and 196 DF,  p-value: < 2.2e-16
plot(Model_Sales_Marketing)

summary(lm("sales ~ youtube + facebook + newspaper", data = marketing))

Call:
lm(formula = "sales ~ youtube + facebook + newspaper", data = marketing)

Residuals:
     Min       1Q   Median       3Q      Max 
-10.5932  -1.0690   0.2902   1.4272   3.3951 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.526667   0.374290   9.422   <2e-16 ***
youtube      0.045765   0.001395  32.809   <2e-16 ***
facebook     0.188530   0.008611  21.893   <2e-16 ***
newspaper   -0.001037   0.005871  -0.177     0.86    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.023 on 196 degrees of freedom
Multiple R-squared:  0.8972,    Adjusted R-squared:  0.8956 
F-statistic: 570.3 on 3 and 196 DF,  p-value: < 2.2e-16
summary(lm("sales ~ youtube + facebook", data = marketing))

Call:
lm(formula = "sales ~ youtube + facebook", data = marketing)

Residuals:
     Min       1Q   Median       3Q      Max 
-10.5572  -1.0502   0.2906   1.4049   3.3994 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.50532    0.35339   9.919   <2e-16 ***
youtube      0.04575    0.00139  32.909   <2e-16 ***
facebook     0.18799    0.00804  23.382   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.018 on 197 degrees of freedom
Multiple R-squared:  0.8972,    Adjusted R-squared:  0.8962 
F-statistic: 859.6 on 2 and 197 DF,  p-value: < 2.2e-16
summary(lm("sales ~ youtube", data = marketing))

Call:
lm(formula = "sales ~ youtube", data = marketing)

Residuals:
     Min       1Q   Median       3Q      Max 
-10.0632  -2.3454  -0.2295   2.4805   8.6548 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 8.439112   0.549412   15.36   <2e-16 ***
youtube     0.047537   0.002691   17.67   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.91 on 198 degrees of freedom
Multiple R-squared:  0.6119,    Adjusted R-squared:  0.6099 
F-statistic: 312.1 on 1 and 198 DF,  p-value: < 2.2e-16
summary(lm("sales ~  facebook + newspaper", data = marketing))

Call:
lm(formula = "sales ~  facebook + newspaper", data = marketing)

Residuals:
     Min       1Q   Median       3Q      Max 
-18.6347  -2.5739   0.8778   3.3188   9.5701 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 11.026705   0.753206  14.640   <2e-16 ***
facebook     0.199045   0.021870   9.101   <2e-16 ***
newspaper    0.006644   0.014909   0.446    0.656    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.14 on 197 degrees of freedom
Multiple R-squared:  0.3327,    Adjusted R-squared:  0.3259 
F-statistic: 49.11 on 2 and 197 DF,  p-value: < 2.2e-16
summary(lm("sales ~  newspaper", data = marketing))

Call:
lm(formula = "sales ~  newspaper", data = marketing)

Residuals:
    Min      1Q  Median      3Q     Max 
-13.473  -4.065  -1.007   4.207  15.330 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 14.82169    0.74570   19.88  < 2e-16 ***
newspaper    0.05469    0.01658    3.30  0.00115 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.111 on 198 degrees of freedom
Multiple R-squared:  0.05212,   Adjusted R-squared:  0.04733 
F-statistic: 10.89 on 1 and 198 DF,  p-value: 0.001148

4 A note on categorical variables

data("Salaries", package = "carData")
Salaries
Model_1 <- lm("salary ~ sex", data = Salaries)
summary(Model_1)

Call:
lm(formula = "salary ~ sex", data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-57290 -23502  -6828  19710 116455 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   101002       4809  21.001  < 2e-16 ***
sexMale        14088       5065   2.782  0.00567 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 30030 on 395 degrees of freedom
Multiple R-squared:  0.01921,   Adjusted R-squared:  0.01673 
F-statistic: 7.738 on 1 and 395 DF,  p-value: 0.005667
class(Salaries$sex)
[1] "factor"
levels(Salaries$sex)
[1] "Female" "Male"  
Salaries %<>%
  mutate(Sex_Character = sex) %>% 
  mutate(Sex_Male = if_else(Sex_Character == "Male", 1, 0),
         Sex_Female = if_else(Sex_Character == "Female", 1, 0))


# Salario = B0 +B_M*Male
Salaries
Model_2 <- lm("salary ~ Sex_Male", data = Salaries)
summary(Model_2)

Call:
lm(formula = "salary ~ Sex_Male", data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-57290 -23502  -6828  19710 116455 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   101002       4809  21.001  < 2e-16 ***
Sex_Male       14088       5065   2.782  0.00567 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 30030 on 395 degrees of freedom
Multiple R-squared:  0.01921,   Adjusted R-squared:  0.01673 
F-statistic: 7.738 on 1 and 395 DF,  p-value: 0.005667
Model_3 <- lm("salary ~ Sex_Female", data = Salaries)
summary(Model_3)

Call:
lm(formula = "salary ~ Sex_Female", data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-57290 -23502  -6828  19710 116455 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   115090       1587  72.503  < 2e-16 ***
Sex_Female    -14088       5065  -2.782  0.00567 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 30030 on 395 degrees of freedom
Multiple R-squared:  0.01921,   Adjusted R-squared:  0.01673 
F-statistic: 7.738 on 1 and 395 DF,  p-value: 0.005667
Salaries %>% group_by(sex) %>% summarise(MeanPerSex = mean(salary),
                                         PeopleInSurvey = n())
101002.4 - 115090.4 
[1] -14088

5 A note on interactions

names(Salaries)
[1] "rank"          "discipline"    "yrs.since.phd" "yrs.service"   "sex"           "salary"       
[7] "Sex_Character" "Sex_Male"      "Sex_Female"   
Model_1 <- Salaries %>% lm("salary ~ yrs.service + discipline", data = .)
summary(Model_1)

Call:
lm(formula = "salary ~ yrs.service + discipline", data = .)

Residuals:
   Min     1Q Median     3Q    Max 
-77537 -19699  -5135  15631 106625 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  91335.8     3005.4  30.391  < 2e-16 ***
yrs.service    862.8      109.2   7.904 2.73e-14 ***
disciplineB  13184.0     2846.8   4.631 4.95e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27870 on 394 degrees of freedom
Multiple R-squared:  0.1579,    Adjusted R-squared:  0.1536 
F-statistic: 36.94 on 2 and 394 DF,  p-value: 1.983e-15
class(Salaries$discipline)
[1] "factor"
levels(Salaries$discipline)
[1] "A" "B"
Salaries$discipline <- as.character(Salaries$discipline)

Salaries$discipline <- factor(Salaries$discipline, levels = c("B", "A"))
Salaries %>% group_by(discipline) %>% summarize(Meam =mean(salary), N = n()) 
names(Salaries)
[1] "rank"          "discipline"    "yrs.since.phd" "yrs.service"   "sex"           "salary"       
[7] "Sex_Character" "Sex_Male"      "Sex_Female"   
names(Salaries)[4] <- "Years_Service"
names(Salaries)
[1] "rank"          "discipline"    "yrs.since.phd" "Years_Service" "sex"           "salary"       
[7] "Sex_Character" "Sex_Male"      "Sex_Female"   
Salaries %<>%
  mutate(Sociology = if_else(discipline == "A", 1, 0),
         Engineer = if_else(discipline == "B", 1, 0)) %>% 
  mutate(Interac_YrServices_Engineer = Years_Service*Engineer) %>% 
  mutate(Interac_YrServices_Sociology = Years_Service*Sociology)
Equation_0 <- "salary ~ Years_Service + discipline + Years_Service*discipline"

Equation_1 <- "salary ~ Years_Service + Sociology + Years_Service*Sociology"

Equation_2 <- "salary ~ Years_Service + Sociology + Interac_YrServices_Sociology"
summary(lm(Equation_0, data = Salaries))

Call:
lm(formula = Equation_0, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-86326 -19779  -4999  16091 102274 

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)                98895.4     3068.4  32.230  < 2e-16 ***
Years_Service               1222.0      155.2   7.874 3.37e-14 ***
disciplineA                 -857.4     4750.7  -0.180  0.85687    
Years_Service:disciplineA   -695.2      215.9  -3.220  0.00139 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27540 on 393 degrees of freedom
Multiple R-squared:  0.1795,    Adjusted R-squared:  0.1733 
F-statistic: 28.67 on 3 and 393 DF,  p-value: < 2.2e-16
summary(lm(Equation_1, data = Salaries))

Call:
lm(formula = Equation_1, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-86326 -19779  -4999  16091 102274 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)              98895.4     3068.4  32.230  < 2e-16 ***
Years_Service             1222.0      155.2   7.874 3.37e-14 ***
Sociology                 -857.4     4750.7  -0.180  0.85687    
Years_Service:Sociology   -695.2      215.9  -3.220  0.00139 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27540 on 393 degrees of freedom
Multiple R-squared:  0.1795,    Adjusted R-squared:  0.1733 
F-statistic: 28.67 on 3 and 393 DF,  p-value: < 2.2e-16
summary(lm(Equation_2, data = Salaries))

Call:
lm(formula = Equation_2, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-86326 -19779  -4999  16091 102274 

Coefficients:
                             Estimate Std. Error t value Pr(>|t|)    
(Intercept)                   98895.4     3068.4  32.230  < 2e-16 ***
Years_Service                  1222.0      155.2   7.874 3.37e-14 ***
Sociology                      -857.4     4750.7  -0.180  0.85687    
Interac_YrServices_Sociology   -695.2      215.9  -3.220  0.00139 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27540 on 393 degrees of freedom
Multiple R-squared:  0.1795,    Adjusted R-squared:  0.1733 
F-statistic: 28.67 on 3 and 393 DF,  p-value: < 2.2e-16
names(Salaries)
 [1] "rank"                         "discipline"                   "yrs.since.phd"               
 [4] "Years_Service"                "sex"                          "salary"                      
 [7] "Sex_Character"                "Sex_Male"                     "Sex_Female"                  
[10] "Sociology"                    "Engineer"                     "Interac_YrServices_Engineer" 
[13] "Interac_YrServices_Sociology"
Equation_1 <- "salary ~ Years_Service + sex + discipline + sex*discipline"
Equation_2 <- "salary ~ Years_Service + Sex_Male + Sociology + Sex_Male*Sociology"

Equation_3 <- "salary ~ Years_Service + Sex_Male + Engineer + Sex_Male*Engineer"
summary(lm(Equation_1, data = Salaries))

Call:
lm(formula = Equation_1, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-77749 -19940  -5111  16007 104763 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         101606.3     6198.6  16.392  < 2e-16 ***
Years_Service          825.3      110.4   7.476 5.06e-13 ***
sexMale               3877.7     6400.1   0.606   0.5449    
disciplineA         -21986.2     8925.0  -2.463   0.0142 *  
sexMale:disciplineA   9962.5     9415.8   1.058   0.2907    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27790 on 392 degrees of freedom
Multiple R-squared:  0.167, Adjusted R-squared:  0.1585 
F-statistic: 19.64 on 4 and 392 DF,  p-value: 9.487e-15
summary(lm(Equation_2, data = Salaries))

Call:
lm(formula = Equation_2, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-77749 -19940  -5111  16007 104763 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)        101606.3     6198.6  16.392  < 2e-16 ***
Years_Service         825.3      110.4   7.476 5.06e-13 ***
Sex_Male             3877.7     6400.1   0.606   0.5449    
Sociology          -21986.2     8925.0  -2.463   0.0142 *  
Sex_Male:Sociology   9962.5     9415.8   1.058   0.2907    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27790 on 392 degrees of freedom
Multiple R-squared:  0.167, Adjusted R-squared:  0.1585 
F-statistic: 19.64 on 4 and 392 DF,  p-value: 9.487e-15
summary(lm(Equation_3, data = Salaries))

Call:
lm(formula = Equation_3, data = Salaries)

Residuals:
   Min     1Q Median     3Q    Max 
-77749 -19940  -5111  16007 104763 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)        79620.1     6669.9  11.937  < 2e-16 ***
Years_Service        825.3      110.4   7.476 5.06e-13 ***
Sex_Male           13840.2     6979.6   1.983   0.0481 *  
Engineer           21986.2     8925.0   2.463   0.0142 *  
Sex_Male:Engineer  -9962.5     9415.8  -1.058   0.2907    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 27790 on 392 degrees of freedom
Multiple R-squared:  0.167, Adjusted R-squared:  0.1585 
F-statistic: 19.64 on 4 and 392 DF,  p-value: 9.487e-15

6 A note on transformations

From this resource:

  • “Only the dependent/response variable is log-transformed. Exponentiate the coefficient, subtract one from this number, and multiply by 100. This gives the percent increase (or decrease) in the response for every one-unit increase in the independent variable. Example: the coefficient is 0.198. (exp(0.198) – 1) * 100 = 21.9. For every one-unit increase in the independent variable, our dependent variable increases by about 22%.

  • Only independent/predictor variable(s) is log-transformed. Divide the coefficient by 100. This tells us that a 1% increase in the independent variable increases (or decreases) the dependent variable by (coefficient/100) units. Example: the coefficient is 0.198. 0.198/100 = 0.00198. For every 1% increase in the independent variable, our dependent variable increases by about 0.002. For x percent increase, multiply the coefficient by log(1.x). Example: For every 10% increase in the independent variable, our dependent variable increases by about 0.198 * log(1.10) = 0.02.

  • Both dependent/response variable and independent/predictor variable(s) are log-transformed. Interpret the coefficient as the percent increase in the dependent variable for every 1% increase in the independent variable. Example: the coefficient is 0.198. For every 1% increase in the independent variable, our dependent variable increases by about 0.20%. For x percent increase, calculate 1.x to the power of the coefficient, subtract 1, and multiply by 100. Example: For every 20% increase in the independent variable, our dependent variable increases by about (1.20 0.198 – 1) * 100 = 3.7 percent.”

7 A note on “Marginals”

Marginal effects refer to the change in the predicted value of the dependent variable that results from a one-unit change in one of the independent variables, while holding all other independent variables constant.

Think of it as the specific slope on each point in the curve.

We could:

  • Caclulate the marginal effect for each individual
  • Calculate the marginal effect of a set of individuals
  • Calculate the Average Marginal Effect AME
  • Calculate the Marginal Effect on the Mean MEM

install.packages(“margins”) library(margins) mfx <- margins(m, variables = “x”) summary(mfx)

library(wooldridge) data(“card”)

library(jtools) export_sums()

mfx::logitmfx() mfx::probitmfx()

margins::margins()

LS0tDQp0aXRsZTogIlR1dG9yaWFsIC0gbGluZWFyIHJlZ3Jlc3Npb24iDQphdXRob3I6ICJPcmxhbmRvIFNhYm9nYWwtQ2FyZG9uYSINCmRhdGU6ICJTdW1tZXIgMjAyMyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KLS0tDQoNCiMgTGlicmFyeQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShtYWdyaXR0cikNCmBgYA0KDQoNCiMgQSBzaW1wbGUgZXhhbXBsZQ0KDQojIyBPdmVydmlldyBvZiB0aGUgZGF0YQ0KDQpgYGB7cn0NCmRhdGEoIlVTQXJyZXN0cyIpDQpgYGANCg0KYGBge3J9DQpuYW1lcyhVU0FycmVzdHMpDQpgYGANCg0KYGBge3J9DQpnbGltcHNlKFVTQXJyZXN0cykNCmBgYA0KDQoNCiMjIEZpdCB0aGUgbW9kZWwNCg0KVmFyaWFsYmxlIH4gWDEgKyBYMiArIFgyIA0KDQpgYGB7cn0NCkVxdWF0aW9uIDwtICJNdXJkZXIgfiBBc3NhdWx0ICsgVXJiYW5Qb3AgKyBSYXBlIg0KDQpNb2RlbCA8LSBsbShFcXVhdGlvbiwgDQogICAgICAgICAgICBkYXRhID0gVVNBcnJlc3RzKQ0KYGBgDQoNCiMjIEdlbmVyYWwgcmVzdWx0cw0KDQpgYGB7cn0NCnN1bW1hcnkoTW9kZWwpDQpgYGANCg0KYGBge3J9DQojIE11cmRlcl9FU1RJTUFURUQgPSAzLjI3NjYzOSArIA0KICAgICAgICAjIDAuMDM5Nzc3KkFzc2F1bHQgKyAtMC4wNTQ2OTQqVXJiYW5Qb3AgKyBSYXAgKyAgMC4wNjEzOTlyZXNpZHVhbA0KYGBgDQoNCg0KV2UgZ2V0IGZyb20gdGhlIG1haW4gb3V0cHV0Og0KDQotIEFuIG92ZXJ2aWV3IG9mIHRoZSByZXNpZHVhbHMNCi0gUGFyYW1ldGVyczogZXN0aW1hdGVzLCBzdGFuZGFyZCBlcnJvcmVzLCB0IHZhbHVlcywgcCB2YWx1ZXMsIGFuZCBzdGFycywNCi0gUmVzaWR1YWwgc3RhbmRhcmQgZXJyb3JzDQotIERlZ3JlZXMgb2YgZnJlZWRvbQ0KLSBGLXN0YXRpc3RpY3M6ICBVc2VkIHRvIGFzc2VzcyB0aGUgb3ZlcmFsbCBzaWduaWZpY2FuY2Ugb2YgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgYnkgdGVzdGluZyB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgYWxsIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyAoZXhjZXB0IHRoZSBpbnRlcmNlcHQpIGFyZSBlcXVhbCB0byB6ZXJvLiBUaGUgRi10ZXN0IHByb3ZpZGVzIGEgbWVhc3VyZSBvZiB3aGV0aGVyIHRoZSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcyBhbmQgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50Lg0KDQoNCmBgYHtyfQ0KanRvb2xzOjpzdW1tKE1vZGVsKQ0KYGBgDQoNCmBgYHtyfQ0KVGFibGVSZXN1bHRzIDwtIGJyb29tOjp0aWR5KE1vZGVsKQ0KVGFibGVSZXN1bHRzDQpgYGANCg0KDQojIyBab29tIGluIHRoZSBwYXJhbWV0ZXJzOg0KDQpgYGB7cn0NCmNvZWYoTW9kZWwpDQpgYGANCg0KYGBge3J9DQpjb25maW50KE1vZGVsKQ0KYGBgDQoNCiMjIERpYWdub3N0aWMNCg0KIyMjIFRoZSBwbG90KCkgZnVuY3Rpb24NCg0KYGBge3J9DQpwbG90KE1vZGVsKQ0KYGBgDQoNCkhvdyB0byBpbnRlcnByZXQgdGhlc2UgcGxvdHM/DQoNCi0gKipSZXNpZHVhbHMgdnMgRml0dGVkIHZhbHVlczoqKiBDaGVjayBmb3Igbm9uLWxpbmVhciBwYXR0ZXJucy4gSWYgdGhlcmUgYXJlIG5vdCBub24tbGluZWFyIHJlbGF0aW9uc2hpcHMgaW4gdGhlIG1vZGVsIHdlIHNob3VsZCBzZWUgcmVzaWR1YWxzIGVxdWFsbHkgc3ByZWFkLiANCi0gKipOb3JtYWwgUS1RIChxdWFudGlsZS1xdWFudGlsZSkgcGxvdDoqKiBJZiB0aGUgcmVzaWR1YWxzIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4gVGhleSBzaG91bGQgZm9sbG93IGEgc3RyYWlnaHQgbGluZS4gDQotICoqUm9vdCBvZiBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIHZzIEZpdHRlZCB2YWx1ZXMgKHNjYWxlLWxvY2F0aW9uIG9yIHNwcmVhZCBsb2NhdGlvbiBwbG90KToqKiBDaGVja3MgZm9yIGhvbW9zY2VkYXN0aWNpdHksICBpZiByZXNpZHVhbHMgYXJlIHNwcmVhZCBlcXVhbGx5IGFsb25nIHRoZSByYW5nZXMgb2YgcHJlZGljdG9ycy4gVGhlIHZlcnRpY2FsIGF4aXMgdHlwaWNhbGx5IHJlcHJlc2VudHMgdGhlIHNxdWFyZSByb290IG9mIHRoZSBhYnNvbHV0ZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIG9yIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzLiBUaGUgc3F1YXJlIHJvb3QgdHJhbnNmb3JtYXRpb24gaXMgYXBwbGllZCB0byBzdGFiaWxpemUgdGhlIHZhcmlhbmNlIGFuZCBlbnN1cmUgdGhhdCBuZWdhdGl2ZSByZXNpZHVhbHMgaGF2ZSBtZWFuaW5nZnVsIHZhbHVlcy4gQWx0ZXJuYXRpdmVseSwgdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgdGhlbXNlbHZlcyBjYW4gYmUgdXNlZA0KLSAqKlN0YW5kYXJkaXplZCByZXNpZHVhbHMgdnMgTGV2ZXJhZ2U6KiogVG8gY2hlY2sgZm9yIG91dGxpZXJzLiANCg0KDQojIyBTbG93IGRvd246IHBsb3RzIHdpdGggdGhlIHJlc2lkdWFscw0KDQpgYGB7cn0NCllfRXN0aW1hdGVkIDwtIHByZWRpY3QoTW9kZWwpDQpSZXNpZHVhbHMgPC0gcmVzaWR1YWxzKE1vZGVsKQ0KDQpEaWFnbm9zdGljIDwtIGRhdGEuZnJhbWUoWV9Fc3RpbWF0ZWQsIFJlc2lkdWFscykNCg0KRGlhZ25vc3RpYw0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IERpYWdub3N0aWMpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IFlfRXN0aW1hdGVkLCB5ID0gUmVzaWR1YWxzKSkgKw0KICBnZ3RpdGxlKCJTcHJlYWQgb2YgdGhlIHJlc2lkdWFscyIpICsNCiAgeGxhYigiRXN0aW1hdGVkIHZhcmlhYmxlIikgKyB5bGFiKCJyZXNpZHVhbHMiKSArDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBEaWFnbm9zdGljKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gUmVzaWR1YWxzKSwgYmlud2lkdGggPSAwLjcpICsNCiAgdGhlbWVfbGlnaHQoKQ0KYGBgDQoNCg0KIyMgUVEgUGxvdHMNCg0KYGBge3J9DQpEaWFnbm9zdGljICU8PiUgYXJyYW5nZShSZXNpZHVhbHMpIA0KRGlhZ25vc3RpYw0KYGBgDQoNCmBgYHtyfQ0KT2JzZXJ2YXRpb25zIDwtIGRpbShVU0FycmVzdHMpWzFdDQpQcm9iYWJpbGl0aWVzIDwtIHNlcSgwLjAxLCAwLjk5LCAwLjAyKQ0KUHJvYmFiaWxpdGllcyA8LSAoMTpPYnNlcnZhdGlvbnMgLSAwLjUpL09ic2VydmF0aW9ucw0KDQpEaWFnbm9zdGljICU8PiUgbXV0YXRlKFRoZW9yZXRpY2FsX1F1YW50aWxlcyA9IHFub3JtKFByb2JhYmlsaXRpZXMpKQ0KRGlhZ25vc3RpYw0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IERpYWdub3N0aWMpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IFRoZW9yZXRpY2FsX1F1YW50aWxlcywgeSA9IFJlc2lkdWFscykpICsNCiAgZ2d0aXRsZSgiUVEgUGxvdCIpICsNCiAgeGxhYigiVGhlb3JldGljYWwgUXVhbnRpbGVzIikgKyB5bGFiKCJyZXNpZHVhbHMiKSArDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KDQoNCg0KYGBge3J9DQpNb2RlbCRkZi5yZXNpZHVhbA0KZXN0aW1hdGVkX3NkIDwtIHNxcnQoc3VtKERpYWdub3N0aWMkUmVzaWR1YWxzXjIpL01vZGVsJGRmLnJlc2lkdWFsKQ0KDQpEaWFnbm9zdGljICU8PiUgbXV0YXRlKFN0YW5kX1Jlc2lkdWFscyA9IFJlc2lkdWFscy9lc3RpbWF0ZWRfc2QpIA0KRGlhZ25vc3RpYw0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IERpYWdub3N0aWMpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IFRoZW9yZXRpY2FsX1F1YW50aWxlcywgeSA9IFN0YW5kX1Jlc2lkdWFscykpICsgDQogIGdlb21fbGluZShhZXMoeCA9IFRoZW9yZXRpY2FsX1F1YW50aWxlcywgeSA9IFRoZW9yZXRpY2FsX1F1YW50aWxlcykpICsNCiAgZ2d0aXRsZSgiUVEgUGxvdCIpICsNCiAgeGxhYigiVGhlb3JldGljYWwgUXVhbnRpbGVzIikgKyB5bGFiKCJTdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIikgKw0KICB0aGVtZV9saWdodCgpDQpgYGANCg0KIyMgU2NhbGUtbG9jYXRpb24gcGxvdCANCg0KDQpgYGB7cn0NCkRpYWdub3N0aWMgJTw+JQ0KICBtdXRhdGUoc3FydF9hYnNfc3RkX3Jlc2lkID0gc3FydChhYnMoU3RhbmRfUmVzaWR1YWxzKSkgKQ0KDQpEaWFnbm9zdGljDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChEaWFnbm9zdGljLCBhZXMoeCA9IFlfRXN0aW1hdGVkLCB5ID0gc3FydF9hYnNfc3RkX3Jlc2lkKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArDQogIGxhYnMoeCA9ICJQcmVkaWN0ZWQgVmFsdWVzIiwgeSA9ICJTY2FsZS1Mb2NhdGlvbiIpICsNCiAgZ2d0aXRsZSgiU2NhbGUtTG9jYXRpb24gUGxvdCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQoNCiMjIExldmVyYWdlDQoNClRoZSBsZXZlcmFnZSBwbG90LCBhbHNvIGtub3duIGFzIHRoZSBsZXZlcmFnZS1yZXNpZHVhbHMgcGxvdCBvciB0aGUgQ29vaydzIGRpc3RhbmNlIHBsb3QsIGlzIGEgZGlhZ25vc3RpYyBwbG90IHVzZWQgaW4gbGluZWFyIHJlZ3Jlc3Npb24gYW5hbHlzaXMuIEl0IGhlbHBzIGlkZW50aWZ5IGluZmx1ZW50aWFsIG9ic2VydmF0aW9ucyB0aGF0IGhhdmUgYSBzaWduaWZpY2FudCBpbXBhY3Qgb24gdGhlIHJlZ3Jlc3Npb24gbW9kZWwncyByZXN1bHRzLg0KDQoNCkxldmVyYWdlIHJlZmVycyB0byB0aGUgcG90ZW50aWFsIG9mIGFuIG9ic2VydmF0aW9uIHRvIGhhdmUgYSBkaXNwcm9wb3J0aW9uYXRlIGVmZmVjdCBvbiB0aGUgZXN0aW1hdGVkIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLiBPYnNlcnZhdGlvbnMgd2l0aCBoaWdoIGxldmVyYWdlIGNhbiBoYXZlIGEgc3Vic3RhbnRpYWwgaW1wYWN0IG9uIHRoZSByZWdyZXNzaW9uIGxpbmUsIGVpdGhlciBieSBleGVydGluZyBhIHB1bGxpbmcgZWZmZWN0IG9yIGJ5IGJlaW5nIG91dGxpZXJzLg0KDQpJbiB0aGUgbGV2ZXJhZ2UgcGxvdCwgZWFjaCBwb2ludCByZXByZXNlbnRzIGFuIG9ic2VydmF0aW9uIGZyb20gdGhlIGRhdGFzZXQuIFRoZSB2ZXJ0aWNhbCBheGlzIHNob3dzIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzLCB3aGljaCBpbmRpY2F0ZSBob3cgZmFyIGVhY2ggb2JzZXJ2YXRpb24ncyBhY3R1YWwgdmFsdWUgZGV2aWF0ZXMgZnJvbSBpdHMgcHJlZGljdGVkIHZhbHVlLCB0YWtpbmcgaW50byBhY2NvdW50IHRoZSB2YXJpYWJpbGl0eSBvZiB0aGUgcmVzaWR1YWxzLiBUaGUgaG9yaXpvbnRhbCBheGlzIHJlcHJlc2VudHMgdGhlIGxldmVyYWdlIHZhbHVlcyBvZiB0aGUgb2JzZXJ2YXRpb25zLCB3aGljaCBtZWFzdXJlIHRoZSBwb3RlbnRpYWwgaW5mbHVlbmNlIG9mIGVhY2ggb2JzZXJ2YXRpb24gb24gdGhlIGVzdGltYXRlZCByZWdyZXNzaW9uIGNvZWZmaWNpZW50cy4NCg0KTGV2ZXJhZ2UgdmFsdWVzIGFyZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSAiKkhhdCoiIG1hdHJpeCwgd2hpY2ggaXMgYSBtYXRyaXggdGhhdCBtYXBzIHRoZSBvYnNlcnZlZCB2YWx1ZXMgdG8gdGhlIHByZWRpY3RlZCB2YWx1ZXMuIEhpZ2ggbGV2ZXJhZ2UgdmFsdWVzIHN1Z2dlc3QgdGhhdCBhbiBvYnNlcnZhdGlvbiBoYXMgYSBncmVhdGVyIGFiaWxpdHkgdG8gYWZmZWN0IHRoZSBlc3RpbWF0ZWQgcmVncmVzc2lvbiBjb2VmZmljaWVudHMuIE9ic2VydmF0aW9ucyB3aXRoIGhpZ2ggbGV2ZXJhZ2UgYXJlIGxvY2F0ZWQgdG93YXJkcyB0aGUgZW5kcyBvZiB0aGUgaG9yaXpvbnRhbCBheGlzLg0KDQpJbmZsdWVudGlhbCBPYnNlcnZhdGlvbnM6IE9ic2VydmF0aW9ucyB3aXRoIGhpZ2ggbGV2ZXJhZ2UgYW5kIGxhcmdlIHJlc2lkdWFscyBjYW4gYmUgY29uc2lkZXJlZCBpbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMuIFRoZXkgaGF2ZSB0aGUgcG90ZW50aWFsIHRvIHNpZ25pZmljYW50bHkgYWZmZWN0IHRoZSByZWdyZXNzaW9uIG1vZGVsJ3MgcGFyYW1ldGVycyBhbmQgY2FuIGRpc3RvcnQgdGhlIHJlc3VsdHMgaWYgdGhleSBhcmUgb3V0bGllcnMgb3IgaWYgdGhlaXIgcHJlZGljdG9ycyBoYXZlIGV4dHJlbWUgdmFsdWVzLg0KDQpDb29rJ3MgRGlzdGFuY2U6IEluIGFkZGl0aW9uIHRvIHRoZSBsZXZlcmFnZSBwbG90LCBDb29rJ3MgZGlzdGFuY2UgaXMgb2Z0ZW4gc2hvd24gb24gdGhlIHNhbWUgZ3JhcGggb3IgYXMgYSBzZXBhcmF0ZSBwbG90LiBDb29rJ3MgZGlzdGFuY2UgbWVhc3VyZXMgdGhlIGluZmx1ZW5jZSBvZiBlYWNoIG9ic2VydmF0aW9uIG9uIHRoZSBlbnRpcmUgcmVncmVzc2lvbiBtb2RlbC4gTGFyZ2UgdmFsdWVzIG9mIENvb2sncyBkaXN0YW5jZSBzdWdnZXN0IGluZmx1ZW50aWFsIG9ic2VydmF0aW9ucyB0aGF0IHNpZ25pZmljYW50bHkgYWZmZWN0IHRoZSByZWdyZXNzaW9uIG1vZGVsJ3MgcmVzdWx0cy4NCg0KQnkgZXhhbWluaW5nIHRoZSBsZXZlcmFnZSBwbG90IGFuZCBDb29rJ3MgZGlzdGFuY2UsIHlvdSBjYW4gaWRlbnRpZnkgaW5mbHVlbnRpYWwgb2JzZXJ2YXRpb25zIHRoYXQgbWF5IHJlcXVpcmUgZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBUaGVzZSBvYnNlcnZhdGlvbnMgbWF5IGhhdmUgYSBzdWJzdGFudGlhbCBpbXBhY3Qgb24gdGhlIHJlZ3Jlc3Npb24gYW5hbHlzaXMgYW5kIGNvdWxkIHBvdGVudGlhbGx5IGFmZmVjdCB0aGUgbW9kZWwncyBjb25jbHVzaW9ucy4NCg0KSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHRoZSBpbnRlcnByZXRhdGlvbiBvZiBpbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMgc2hvdWxkIGJlIGRvbmUgY2F1dGlvdXNseSwgY29uc2lkZXJpbmcgdGhlIGNvbnRleHQgYW5kIG9iamVjdGl2ZXMgb2YgdGhlIGFuYWx5c2lzLiBJbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMgbWF5IHdhcnJhbnQgYWRkaXRpb25hbCBzY3J1dGlueSwgYnV0IHRoZXkgc2hvdWxkIG5vdCBiZSBhdXRvbWF0aWNhbGx5IHJlbW92ZWQgd2l0aG91dCBjYXJlZnVsIGNvbnNpZGVyYXRpb24gYW5kIGp1c3RpZmljYXRpb24uDQoNCiMjIE11bHRpb2xpbmVhcml0eTogVklGDQoNClZJRiBpcyBjYWxjdWxhdGVkIGZvciBlYWNoIGluZGVwZW5kZW50IHZhcmlhYmxlIGluIHRoZSByZWdyZXNzaW9uIG1vZGVsLiBGb3IgZWFjaCB2YXJpYWJsZSwgdGhlIFZJRiBpcyBvYnRhaW5lZCBieSByZWdyZXNzaW5nIHRoYXQgdmFyaWFibGUgYWdhaW5zdCBhbGwgdGhlIG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwuDQoNClZJRiA9IDEgLyAoMSAtIFLCsikNCg0KLSBWSUYgPSAxOiBObyBtdWx0aWNvbGxpbmVhcml0eS4gVGhlIHZhcmlhYmxlIGlzIG5vdCBjb3JyZWxhdGVkIHdpdGggYW55IG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlcy4NCi0gVklGID4gMSBhbmQgPCA1OiBNb2RlcmF0ZSBtdWx0aWNvbGxpbmVhcml0eS4gVGhlIHZhcmlhYmxlIGlzIGNvcnJlbGF0ZWQgd2l0aCBvdGhlciBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYnV0IG5vdCB0byBhIHNldmVyZSBleHRlbnQuDQotIFZJRiA+IDU6IEhpZ2ggbXVsdGljb2xsaW5lYXJpdHkuIFRoZSB2YXJpYWJsZSBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlcywgd2hpY2ggbWF5IGNhdXNlIGNoYWxsZW5nZXMgaW4gaW50ZXJwcmV0aW5nIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMuDQoNCmBgYHtyfQ0KY29yKFVTQXJyZXN0cykNCmBgYA0KDQoNCmBgYHtyfQ0KcmVnY2xhc3M6OlZJRihNb2RlbCkNCmBgYA0KDQojIyBTdGF0aXN0aWNhbCB0ZXN0cw0KDQojIyMgQ29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscw0KDQpgYGB7cn0NCmNhcjo6ZHVyYmluV2F0c29uVGVzdChNb2RlbCkNCg0KIyBIMCAobnVsbCBoeXBvdGhlc2lzKTogVGhlcmUgaXMgbm8gY29ycmVsYXRpb24gYW1vbmcgdGhlIHJlc2lkdWFscy4NCiMgSEEgKGFsdGVybmF0aXZlIGh5cG90aGVzaXMpOiBUaGUgcmVzaWR1YWxzIGFyZSBhdXRvY29ycmVsYXRlZC4NCg0KIyBwLXZhbHVlIGlzIGxlc3MgdGhhbiAwLjA1LCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgcmVzaWR1YWxzIGluIHRoaXMgcmVncmVzc2lvbiBtb2RlbCBhcmUgYXV0b2NvcnJlbGF0ZWQNCmBgYA0KDQojIyMgTm9ybWFsaXR5IG9mIHRoZSByZXNpZHVhbHMNCg0KYGBge3J9DQp0c2VyaWVzOjpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFscyhNb2RlbCkpDQoNCiMgVGhlIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSBkYXRhIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZA0KIyBJZiB0aGUgcC12YWx1ZSBpcyBsZXNzIHRoYW4gdGhlIHNpZ25pZmljYW5jZSBsZXZlbCAodXN1YWxseSAwLjA1KSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgYW5kIGNvbmNsdWRlIHRoYXQgdGhlIGRhdGEgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZC4NCmBgYA0KDQpgYGB7cn0NCmtzLnRlc3QocmVzaWR1YWxzKE1vZGVsKSwgInBub3JtIikNCg0KIyAgSWYgdGhlIHAtdmFsdWUgaXMgbGVzcyB0aGFuIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgKHVzdWFsbHkgMC4wNSksIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGFuZCBjb25jbHVkZSB0aGF0IHRoZSByZXNpZHVhbHMgZG8gbm90IGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uDQpgYGANCg0KIyMjIEhldGVyb3NjZWRhc3RpY2l0eSBvZiB0aGUgcmVzaWR1YWxzDQoNCmBgYHtyfQ0KbG10ZXN0OjpicHRlc3QoTW9kZWwpDQoNCiMgIElmIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiB0aGUgc2lnbmlmaWNhbmNlIGxldmVsICh1c3VhbGx5IDAuMDUpLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSBvZiBoZXRlcm9zY2VkYXN0aWNpdHkgaW4gdGhlIHJlc2lkdWFscy4NCmBgYA0KDQojIyBIb3cgdG8gY29tcGFyZSBtb2RlbHM/DQoNCmBgYHtyfQ0KbG9nTGlrKE1vZGVsKQ0KQUlDKE1vZGVsKQ0KQklDKE1vZGVsKQ0KYGBgDQpgYGB7cn0NCk1vZGVsXzEgPC0gbG0oIk11cmRlciB+IEFzc2F1bHQgKyBVcmJhblBvcCArIFJhcGUiLCBkYXRhID0gVVNBcnJlc3RzKQ0KTW9kZWxfMiA8LSBsbSgiTXVyZGVyIH4gQXNzYXVsdCArIFVyYmFuUG9wIiwgZGF0YSA9IFVTQXJyZXN0cykNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShNb2RlbF8xKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShNb2RlbF8yKQ0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5KE1vZGVsXzEpJHIuc3F1YXJlZA0Kc3VtbWFyeShNb2RlbF8yKSRyLnNxdWFyZWQNCg0Kc3VtbWFyeShNb2RlbF8xKSRhZGouci5zcXVhcmVkDQpzdW1tYXJ5KE1vZGVsXzIpJGFkai5yLnNxdWFyZWQNCg0KbG9nTGlrKE1vZGVsXzEpDQpsb2dMaWsoTW9kZWxfMikNCg0KQUlDKE1vZGVsXzEpDQpBSUMoTW9kZWxfMikNCg0KQklDKE1vZGVsXzEpDQpCSUMoTW9kZWxfMikNCmBgYA0KDQpgYGB7cn0NCmFub3ZhKE1vZGVsXzEsIE1vZGVsXzIpDQpgYGANCg0KSWYgcCB2YWx1ZSBpcyBzbWFsbCwgdGhlbi4uLj8NCg0KVGhlIExSVCBpcyB1c2VkIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBtb3JlIGNvbXBsZXggbW9kZWwgKGFsdGVybmF0aXZlIG1vZGVsKSBwcm92aWRlcyBhIHNpZ25pZmljYW50bHkgYmV0dGVyIGZpdCBjb21wYXJlZCB0byB0aGUgc2ltcGxlciBtb2RlbCAobnVsbCBtb2RlbCkuDQoNCkEgc21hbGxlciBwLXZhbHVlIGluZGljYXRlcyBzdHJvbmdlciBldmlkZW5jZSBhZ2FpbnN0IHRoZSBudWxsIGh5cG90aGVzaXMgKHRoYXQgdGhlIHR3byBtb2RlbHMgYXJlIHRoZSBzYW1lKQ0KDQotIFNtYWxsIHAgdmFsdWU6IFdlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSBtb3JlIGNvbXBsZXggbW9kZWwgcHJvdmlkZXMgYSBzaWduaWZpY2FudGx5IGJldHRlciBmaXQgY29tcGFyZWQgdG8gdGhlIHNpbXBsZXIgbW9kZWwuIFRoZSBhZGRpdGlvbmFsIHZhcmlhYmxlcyBvciBjb21wbGV4aXR5IGluIHRoZSBhbHRlcm5hdGl2ZSBtb2RlbCBhcmUgY29uc2lkZXJlZCBpbXBvcnRhbnQgYW5kIGNvbnRyaWJ1dGUgdG8gdGhlIG1vZGVsJ3MgaW1wcm92ZWQgZml0Lg0KDQotIExhcmdlIHAgdmFsdWVzOiAgV2UgZG8gbm90IGhhdmUgZW5vdWdoIGV2aWRlbmNlIHRvIGNvbmNsdWRlIHRoYXQgdGhlIG1vcmUgY29tcGxleCBtb2RlbCBwcm92aWRlcyBhIHNpZ25pZmljYW50bHkgYmV0dGVyIGZpdCBjb21wYXJlZCB0byB0aGUgc2ltcGxlciBtb2RlbC4gDQoNCg0KIyMgQSBub3RlIG9uIExSVA0KDQpNeSBub3RlOiBJIGhhdGUgdXNpbmcgdGhlIGFub3ZhKCkgZnVuY3Rpb24uIEl0IGNyZWF0ZXMgY29uZnVzaW9uLiBUaGVyZSAoYXQgbGVhc3QpIGFub3RoZXIgdHdvIGFsdGVybmF0aXZlcw0KDQpgYGB7cn0NCmxtdGVzdDo6bHJ0ZXN0KE1vZGVsXzEsIE1vZGVsXzIpDQpgYGANCg0KVGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBzdGF0aXN0aWMgaXMgY2FsY3VsYXRlZCBhcyB0aGUgcmF0aW8gb2YgdGhlIGxpa2VsaWhvb2RzIG9mIHRoZSB0d28gbW9kZWxzOg0KDQpMUiA9IC0yICogKGxvZyhM4oKAKM6y4oKAKSkgLSBsb2coTOKCgSjOsuKCgSkpKQ0KZGYgPSBw4oKBIC0gcOKCgA0KDQoNCg0KYGBge3J9DQpscnQgPC0gLTIgKiAobG9nTGlrKE1vZGVsXzIpIC0gbG9nTGlrKE1vZGVsXzEpKQ0KDQpkZiA8LSBsZW5ndGgoY29lZihNb2RlbF8xKSkgLSBsZW5ndGgoY29lZihNb2RlbF8yKSkNCg0KIyBDYWxjdWxhdGUgdGhlIHAtdmFsdWUgdXNpbmcgdGhlIGNoaS1zcXVhcmUgZGlzdHJpYnV0aW9uDQpwX3ZhbHVlIDwtIDEgLSBwY2hpc3EobHJ0LCBkZikNCg0KcF92YWx1ZQ0KYGBgDQoNCiMgQW5vdGhlciBleGFtcGxlDQoNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJkYXRhcml1bSIpDQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigia2Fzc21iYXJhL2RhdGFyaXVtIikNCg0KbGlicmFyeShkYXRhcml1bSkNCmBgYA0KDQpgYGB7cn0NCmRhdGEoIm1hcmtldGluZyIsIHBhY2thZ2UgPSAiZGF0YXJpdW0iKQ0KbWFya2V0aW5nDQpgYGANCg0KYGBge3J9DQpjb3IobWFya2V0aW5nKQ0KYGBgDQoNCmBgYHtyfQ0KbWFya2V0aW5nICU8PiUgDQogIG11dGF0ZShUb3RhbCA9ICB5b3V0dWJlICsgZmFjZWJvb2sgKyBuZXdzcGFwZXIpICU+JSANCiAgbXV0YXRlKFByb3BfTmV3c3BhcGVyID0gbmV3c3BhcGVyL1RvdGFsKSAlPiUgDQogIG11dGF0ZShQcm9wX1lvdXR1YmUgPSB5b3V0dWJlL1RvdGFsKQ0KYGBgDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1hcmtldGluZykgKw0KICBnZW9tX3BvaW50KGFlcyggeD0gUHJvcF9OZXdzcGFwZXIgICAgICwgeSA9IHNhbGVzKSkgKw0KICB0aGVtZV9saWdodCgpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1hcmtldGluZykgKw0KICBnZW9tX3BvaW50KGFlcyggeD0gUHJvcF9Zb3V0dWJlLCB5ID0gc2FsZXMpKSArDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbWFya2V0aW5nKSArDQogIGdlb21fcG9pbnQoYWVzKCB4PSBuZXdzcGFwZXIgICAgICwgeSA9IHNhbGVzKSkgKw0KICB0aGVtZV9saWdodCgpDQpgYGANCg0KDQpgYGB7cn0NCnN1bW1hcnkobWFya2V0aW5nKQ0KYGBgDQoNCg0KYGBge3J9DQpNb2RlbF9TYWxlc19NYXJrZXRpbmcgPC0gbG0oInNhbGVzIH4geW91dHViZSArIGZhY2Vib29rICsgbmV3c3BhcGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1hcmtldGluZykNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoTW9kZWxfU2FsZXNfTWFya2V0aW5nKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChNb2RlbF9TYWxlc19NYXJrZXRpbmcpDQpgYGANCg0KDQpgYGB7cn0NCnN1bW1hcnkobG0oInNhbGVzIH4geW91dHViZSArIGZhY2Vib29rICsgbmV3c3BhcGVyIiwgZGF0YSA9IG1hcmtldGluZykpDQpzdW1tYXJ5KGxtKCJzYWxlcyB+IHlvdXR1YmUgKyBmYWNlYm9vayIsIGRhdGEgPSBtYXJrZXRpbmcpKQ0Kc3VtbWFyeShsbSgic2FsZXMgfiB5b3V0dWJlIiwgZGF0YSA9IG1hcmtldGluZykpDQpzdW1tYXJ5KGxtKCJzYWxlcyB+ICBmYWNlYm9vayArIG5ld3NwYXBlciIsIGRhdGEgPSBtYXJrZXRpbmcpKQ0Kc3VtbWFyeShsbSgic2FsZXMgfiAgbmV3c3BhcGVyIiwgZGF0YSA9IG1hcmtldGluZykpDQoNCmBgYA0KDQoNCiMgQSBub3RlIG9uIGNhdGVnb3JpY2FsIHZhcmlhYmxlcw0KDQpgYGB7cn0NCmRhdGEoIlNhbGFyaWVzIiwgcGFja2FnZSA9ICJjYXJEYXRhIikNCmBgYA0KDQpgYGB7cn0NClNhbGFyaWVzDQpgYGANCg0KDQpgYGB7cn0NCk1vZGVsXzEgPC0gbG0oInNhbGFyeSB+IHNleCIsIGRhdGEgPSBTYWxhcmllcykNCnN1bW1hcnkoTW9kZWxfMSkNCmBgYA0KDQpgYGB7cn0NCmNsYXNzKFNhbGFyaWVzJHNleCkNCmxldmVscyhTYWxhcmllcyRzZXgpDQpgYGANCg0KYGBge3J9DQpTYWxhcmllcyAlPD4lDQogIG11dGF0ZShTZXhfQ2hhcmFjdGVyID0gc2V4KSAlPiUgDQogIG11dGF0ZShTZXhfTWFsZSA9IGlmX2Vsc2UoU2V4X0NoYXJhY3RlciA9PSAiTWFsZSIsIDEsIDApLA0KICAgICAgICAgU2V4X0ZlbWFsZSA9IGlmX2Vsc2UoU2V4X0NoYXJhY3RlciA9PSAiRmVtYWxlIiwgMSwgMCkpDQoNCg0KIyBTYWxhcmlvID0gQjAgK0JfTSpNYWxlDQoNCg0KYGBgDQoNCg0KDQpgYGB7cn0NClNhbGFyaWVzDQpgYGANCg0KDQpgYGB7cn0NCk1vZGVsXzIgPC0gbG0oInNhbGFyeSB+IFNleF9NYWxlIiwgZGF0YSA9IFNhbGFyaWVzKQ0Kc3VtbWFyeShNb2RlbF8yKQ0KYGBgDQoNCmBgYHtyfQ0KTW9kZWxfMyA8LSBsbSgic2FsYXJ5IH4gU2V4X0ZlbWFsZSIsIGRhdGEgPSBTYWxhcmllcykNCnN1bW1hcnkoTW9kZWxfMykNCmBgYA0KDQpgYGB7cn0NClNhbGFyaWVzICU+JSBncm91cF9ieShzZXgpICU+JSBzdW1tYXJpc2UoTWVhblBlclNleCA9IG1lYW4oc2FsYXJ5KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGVvcGxlSW5TdXJ2ZXkgPSBuKCkpDQpgYGANCg0KYGBge3J9DQoxMDEwMDIuNCAtIDExNTA5MC40CQ0KYGBgDQoNCg0KIyBBIG5vdGUgb24gaW50ZXJhY3Rpb25zDQoNCmBgYHtyfQ0KbmFtZXMoU2FsYXJpZXMpDQpgYGANCg0KYGBge3J9DQpNb2RlbF8xIDwtIFNhbGFyaWVzICU+JSBsbSgic2FsYXJ5IH4geXJzLnNlcnZpY2UgKyBkaXNjaXBsaW5lIiwgZGF0YSA9IC4pDQpzdW1tYXJ5KE1vZGVsXzEpDQpgYGANCg0KDQpgYGB7cn0NCmNsYXNzKFNhbGFyaWVzJGRpc2NpcGxpbmUpDQpsZXZlbHMoU2FsYXJpZXMkZGlzY2lwbGluZSkNCmBgYA0KDQpgYGB7cn0NClNhbGFyaWVzJGRpc2NpcGxpbmUgPC0gYXMuY2hhcmFjdGVyKFNhbGFyaWVzJGRpc2NpcGxpbmUpDQoNClNhbGFyaWVzJGRpc2NpcGxpbmUgPC0gZmFjdG9yKFNhbGFyaWVzJGRpc2NpcGxpbmUsIGxldmVscyA9IGMoIkIiLCAiQSIpKQ0KYGBgDQoNCg0KYGBge3J9DQpTYWxhcmllcyAlPiUgZ3JvdXBfYnkoZGlzY2lwbGluZSkgJT4lIHN1bW1hcml6ZShNZWFtID1tZWFuKHNhbGFyeSksIE4gPSBuKCkpIA0KYGBgDQoNCmBgYHtyfQ0KbmFtZXMoU2FsYXJpZXMpDQpgYGANCg0KYGBge3J9DQpuYW1lcyhTYWxhcmllcylbNF0gPC0gIlllYXJzX1NlcnZpY2UiDQpgYGANCg0KYGBge3J9DQpuYW1lcyhTYWxhcmllcykNCmBgYA0KDQpgYGB7cn0NClNhbGFyaWVzICU8PiUNCiAgbXV0YXRlKFNvY2lvbG9neSA9IGlmX2Vsc2UoZGlzY2lwbGluZSA9PSAiQSIsIDEsIDApLA0KICAgICAgICAgRW5naW5lZXIgPSBpZl9lbHNlKGRpc2NpcGxpbmUgPT0gIkIiLCAxLCAwKSkgJT4lIA0KICBtdXRhdGUoSW50ZXJhY19ZclNlcnZpY2VzX0VuZ2luZWVyID0gWWVhcnNfU2VydmljZSpFbmdpbmVlcikgJT4lIA0KICBtdXRhdGUoSW50ZXJhY19ZclNlcnZpY2VzX1NvY2lvbG9neSA9IFllYXJzX1NlcnZpY2UqU29jaW9sb2d5KQ0KYGBgDQoNCg0KYGBge3J9DQpFcXVhdGlvbl8wIDwtICJzYWxhcnkgfiBZZWFyc19TZXJ2aWNlICsgZGlzY2lwbGluZSArIFllYXJzX1NlcnZpY2UqZGlzY2lwbGluZSINCg0KRXF1YXRpb25fMSA8LSAic2FsYXJ5IH4gWWVhcnNfU2VydmljZSArIFNvY2lvbG9neSArIFllYXJzX1NlcnZpY2UqU29jaW9sb2d5Ig0KDQpFcXVhdGlvbl8yIDwtICJzYWxhcnkgfiBZZWFyc19TZXJ2aWNlICsgU29jaW9sb2d5ICsgSW50ZXJhY19ZclNlcnZpY2VzX1NvY2lvbG9neSINCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShFcXVhdGlvbl8wLCBkYXRhID0gU2FsYXJpZXMpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShFcXVhdGlvbl8xLCBkYXRhID0gU2FsYXJpZXMpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShFcXVhdGlvbl8yLCBkYXRhID0gU2FsYXJpZXMpKQ0KYGBgDQoNCmBgYHtyfQ0KbmFtZXMoU2FsYXJpZXMpDQpgYGANCg0KDQpgYGB7cn0NCkVxdWF0aW9uXzEgPC0gInNhbGFyeSB+IFllYXJzX1NlcnZpY2UgKyBzZXggKyBkaXNjaXBsaW5lICsgc2V4KmRpc2NpcGxpbmUiDQpFcXVhdGlvbl8yIDwtICJzYWxhcnkgfiBZZWFyc19TZXJ2aWNlICsgU2V4X01hbGUgKyBTb2Npb2xvZ3kgKyBTZXhfTWFsZSpTb2Npb2xvZ3kiDQoNCkVxdWF0aW9uXzMgPC0gInNhbGFyeSB+IFllYXJzX1NlcnZpY2UgKyBTZXhfTWFsZSArIEVuZ2luZWVyICsgU2V4X01hbGUqRW5naW5lZXIiDQpgYGANCg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShFcXVhdGlvbl8xLCBkYXRhID0gU2FsYXJpZXMpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShFcXVhdGlvbl8yLCBkYXRhID0gU2FsYXJpZXMpKQ0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5KGxtKEVxdWF0aW9uXzMsIGRhdGEgPSBTYWxhcmllcykpDQpgYGANCg0KIyBBIG5vdGUgb24gdHJhbnNmb3JtYXRpb25zDQoNCltGcm9tIHRoaXMgcmVzb3VyY2VdKGh0dHBzOi8vZGF0YS5saWJyYXJ5LnZpcmdpbmlhLmVkdS9pbnRlcnByZXRpbmctbG9nLXRyYW5zZm9ybWF0aW9ucy1pbi1hLWxpbmVhci1tb2RlbC8pOg0KDQoNCi0gKioiT25seSB0aGUgZGVwZW5kZW50L3Jlc3BvbnNlIHZhcmlhYmxlIGlzIGxvZy10cmFuc2Zvcm1lZC4qKiBFeHBvbmVudGlhdGUgdGhlIGNvZWZmaWNpZW50LCBzdWJ0cmFjdCBvbmUgZnJvbSB0aGlzIG51bWJlciwgYW5kIG11bHRpcGx5IGJ5IDEwMC4gVGhpcyBnaXZlcyB0aGUgcGVyY2VudCBpbmNyZWFzZSAob3IgZGVjcmVhc2UpIGluIHRoZSByZXNwb25zZSBmb3IgZXZlcnkgb25lLXVuaXQgaW5jcmVhc2UgaW4gdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLiBFeGFtcGxlOiB0aGUgY29lZmZpY2llbnQgaXMgMC4xOTguIChleHAoMC4xOTgpIOKAkyAxKSAqIDEwMCA9IDIxLjkuIEZvciBldmVyeSBvbmUtdW5pdCBpbmNyZWFzZSBpbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUsIG91ciBkZXBlbmRlbnQgdmFyaWFibGUgaW5jcmVhc2VzIGJ5IGFib3V0IDIyJS4NCg0KLSAqKk9ubHkgaW5kZXBlbmRlbnQvcHJlZGljdG9yIHZhcmlhYmxlKHMpIGlzIGxvZy10cmFuc2Zvcm1lZC4qKiBEaXZpZGUgdGhlIGNvZWZmaWNpZW50IGJ5IDEwMC4gVGhpcyB0ZWxscyB1cyB0aGF0IGEgMSUgaW5jcmVhc2UgaW4gdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlIGluY3JlYXNlcyAob3IgZGVjcmVhc2VzKSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGJ5IChjb2VmZmljaWVudC8xMDApIHVuaXRzLiBFeGFtcGxlOiB0aGUgY29lZmZpY2llbnQgaXMgMC4xOTguIDAuMTk4LzEwMCA9IDAuMDAxOTguIEZvciBldmVyeSAxJSBpbmNyZWFzZSBpbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUsIG91ciBkZXBlbmRlbnQgdmFyaWFibGUgaW5jcmVhc2VzIGJ5IGFib3V0IDAuMDAyLiBGb3IgeCBwZXJjZW50IGluY3JlYXNlLCBtdWx0aXBseSB0aGUgY29lZmZpY2llbnQgYnkgbG9nKDEueCkuIEV4YW1wbGU6IEZvciBldmVyeSAxMCUgaW5jcmVhc2UgaW4gdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLCBvdXIgZGVwZW5kZW50IHZhcmlhYmxlIGluY3JlYXNlcyBieSBhYm91dCAwLjE5OCAqIGxvZygxLjEwKSA9IDAuMDIuDQoNCi0gKipCb3RoIGRlcGVuZGVudC9yZXNwb25zZSB2YXJpYWJsZSBhbmQgaW5kZXBlbmRlbnQvcHJlZGljdG9yIHZhcmlhYmxlKHMpIGFyZSBsb2ctdHJhbnNmb3JtZWQuKiogSW50ZXJwcmV0IHRoZSBjb2VmZmljaWVudCBhcyB0aGUgcGVyY2VudCBpbmNyZWFzZSBpbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGZvciBldmVyeSAxJSBpbmNyZWFzZSBpbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUuIEV4YW1wbGU6IHRoZSBjb2VmZmljaWVudCBpcyAwLjE5OC4gRm9yIGV2ZXJ5IDElIGluY3JlYXNlIGluIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSwgb3VyIGRlcGVuZGVudCB2YXJpYWJsZSBpbmNyZWFzZXMgYnkgYWJvdXQgMC4yMCUuIEZvciB4IHBlcmNlbnQgaW5jcmVhc2UsIGNhbGN1bGF0ZSAxLnggdG8gdGhlIHBvd2VyIG9mIHRoZSBjb2VmZmljaWVudCwgc3VidHJhY3QgMSwgYW5kIG11bHRpcGx5IGJ5IDEwMC4gRXhhbXBsZTogRm9yIGV2ZXJ5IDIwJSBpbmNyZWFzZSBpbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUsIG91ciBkZXBlbmRlbnQgdmFyaWFibGUgaW5jcmVhc2VzIGJ5IGFib3V0ICgxLjIwIDAuMTk4IOKAkyAxKSAqIDEwMCA9IDMuNyBwZXJjZW50LiINCg0KDQojIEEgbm90ZSBvbiAiTWFyZ2luYWxzIg0KDQpNYXJnaW5hbCBlZmZlY3RzIHJlZmVyIHRvIHRoZSBjaGFuZ2UgaW4gdGhlIHByZWRpY3RlZCB2YWx1ZSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHRoYXQgcmVzdWx0cyBmcm9tIGEgb25lLXVuaXQgY2hhbmdlIGluIG9uZSBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzLCB3aGlsZSBob2xkaW5nIGFsbCBvdGhlciBpbmRlcGVuZGVudCB2YXJpYWJsZXMgY29uc3RhbnQuDQoNClRoaW5rIG9mIGl0IGFzIHRoZSBzcGVjaWZpYyBzbG9wZSBvbiBlYWNoIHBvaW50IGluIHRoZSBjdXJ2ZS4gDQoNCldlIGNvdWxkOg0KDQotIENhY2x1bGF0ZSB0aGUgbWFyZ2luYWwgZWZmZWN0IGZvciBlYWNoIGluZGl2aWR1YWwNCi0gQ2FsY3VsYXRlIHRoZSBtYXJnaW5hbCBlZmZlY3Qgb2YgYSBzZXQgb2YgaW5kaXZpZHVhbHMNCi0gQ2FsY3VsYXRlICoqdGhlIEF2ZXJhZ2UgTWFyZ2luYWwgRWZmZWN0IEFNRSoqDQotIENhbGN1bGF0ZSB0aGUgKipNYXJnaW5hbCBFZmZlY3Qgb24gdGhlIE1lYW4gTUVNKioNCg0KDQoNCmluc3RhbGwucGFja2FnZXMoIm1hcmdpbnMiKQ0KbGlicmFyeShtYXJnaW5zKQ0KbWZ4IDwtIG1hcmdpbnMobSwgdmFyaWFibGVzID0gIngiKQ0Kc3VtbWFyeShtZngpDQoNCg0KbGlicmFyeSh3b29sZHJpZGdlKQ0KZGF0YSgiY2FyZCIpDQoNCmxpYnJhcnkoanRvb2xzKQ0KZXhwb3J0X3N1bXMoKQ0KDQptZng6OmxvZ2l0bWZ4KCkNCm1meDo6cHJvYml0bWZ4KCkNCg0KbWFyZ2luczo6bWFyZ2lucygpDQoNCg0K