View the latest recording of this lecture

In previous lectures we have considered model comparison of nested regression models, and nested ANOVA type models.

The comparison of nested general linear models using F tests follows naturally.

Natural ordering of GLMs

image
image

Comparison on Nested Linear Models

For any linear model \(M0\) nested within \(M1\), we can test:

using an F test.

The hypotheses can be stated in terms of parameters of model \(M1\).

The F test statistic is

\[F = \frac{[RSS_{M0} - RSS_{M1}]/d}{RSS_{M1}/r}\] where d is the difference in the number of (regression) parameters between the models, and r is the residual degrees of freedom for \(M1\).

If \(H_0\) is correct then F has an F distribution with \(d,r\) degrees of freedom.

Extreme large values of the test statistic provide evidence against \(H_0\).

Hence if \(f_{obs}\) is the observed value of the test statistic, and X is a random variable from an \(F_{d,r}\) distribution, then the P-value is given by \(P= P(X \ge f_{obs})\)

This test can be carried out in R using anova(m0.lm, m1.lm) where m0.lm and m1.lm are respectively the \(M0\) and \(M1\) fitted models.

The Samara Data revisited

Recall that we were modelling the mean speed of fall of samara (fruit from a maple tree) as a function of the disk loading (a covariate) and the tree from which it fell (a factor) for each fruit.

We fitted separate linear regressions for each of the three trees.

We shall now consider simpler models:

We shall compare these models with each other, and with the separate regressions model.

Different Regressions Model

Download samara.csv

## Samara <- read.csv(file = "samara.csv", header = TRUE)
Samara$Tree <- factor(Samara$Tree)
Samara.lm.m2 <- lm(Velocity ~ Tree + Load + Tree:Load, data = Samara)
summary(Samara.lm.m2)

Call:
lm(formula = Velocity ~ Tree + Load + Tree:Load, data = Samara)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.120023 -0.049465 -0.001298  0.049938  0.145571 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)   0.5414     0.2632   2.057   0.0488 *
Tree2        -0.8408     0.3356  -2.505   0.0181 *
Tree3        -0.2987     0.4454  -0.671   0.5078  
Load          3.0629     1.1599   2.641   0.0132 *
Tree2:Load    3.7343     1.5000   2.490   0.0188 *
Tree3:Load    0.8205     2.2837   0.359   0.7220  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.07554 on 29 degrees of freedom
Multiple R-squared:  0.8436,    Adjusted R-squared:  0.8167 
F-statistic: 31.29 on 5 and 29 DF,  p-value: 7.656e-11

Parallel Regressions Model

Samara.lm.m1 <- lm(Velocity ~ Tree + Load, data = Samara)
summary(Samara.lm.m1)

Call:
lm(formula = Velocity ~ Tree + Load, data = Samara)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.13572 -0.06027 -0.01576  0.05973  0.17130 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.07561    0.16871   0.448    0.657    
Tree2       -0.01047    0.03440  -0.304    0.763    
Tree3       -0.05879    0.04629  -1.270    0.213    
Load         5.12257    0.73875   6.934 8.88e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.08101 on 31 degrees of freedom
Multiple R-squared:  0.8078,    Adjusted R-squared:  0.7892 
F-statistic: 43.43 on 3 and 31 DF,  p-value: 3.261e-11

Common Regressions Model

Samara.lm.m0 <- lm(Velocity ~ Load, data = Samara)
summary(Samara.lm.m0)

Call:
lm(formula = Velocity ~ Load, data = Samara)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.16168 -0.05332 -0.01511  0.05528  0.17086 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.09326    0.10743  -0.868    0.392    
Load         5.82019    0.51119  11.386  5.7e-13 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.08067 on 33 degrees of freedom
Multiple R-squared:  0.7971,    Adjusted R-squared:  0.7909 
F-statistic: 129.6 on 1 and 33 DF,  p-value: 5.704e-13

Comparing Models

anova(Samara.lm.m1, Samara.lm.m2)
Analysis of Variance Table

Model 1: Velocity ~ Tree + Load
Model 2: Velocity ~ Tree + Load + Tree:Load
  Res.Df     RSS Df Sum of Sq     F  Pr(>F)  
1     31 0.20344                             
2     29 0.16549  2  0.037949 3.325 0.05011 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova(Samara.lm.m0, Samara.lm.m1)
Analysis of Variance Table

Model 1: Velocity ~ Load
Model 2: Velocity ~ Tree + Load
  Res.Df     RSS Df Sum of Sq      F Pr(>F)
1     33 0.21476                           
2     31 0.20344  2  0.011322 0.8626 0.4319
anova(Samara.lm.m0, Samara.lm.m2)
Analysis of Variance Table

Model 1: Velocity ~ Load
Model 2: Velocity ~ Tree + Load + Tree:Load
  Res.Df     RSS Df Sum of Sq      F  Pr(>F)  
1     33 0.21476                              
2     29 0.16549  4  0.049272 2.1585 0.09885 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Comments

Models fitted as follows:

  • Samara.lm.m2 is separate regressions model. It has 6 regression parameters (3 for intercepts, 3 for slopes) and RSS of 0.16549.
  • Samara.lm.m1 is parallel regressions model. It has 4 regression parameters (3 for intercepts, 1 for slope) and RSS of 0.20344.
  • Samara.lm.m0 is single regressions model. It has 2 regression parameters (1 for intercept, 1 for slope) and RSS of 0.21476.

Comparison of \(M2\) and \(M1\) gives very borderline result (P=0.05011). We would just barely retain \(M1\) if we were working at a 5% significance level.

Comparison of \(M1\) and \(M0\) provides no evidence to prefer \(M1\) (P=0.4319).

Comparison of \(M2\) and \(M0\) shows that \(M0\) should be retained at the 5% significance level (though there is weak evidence in favour of \(M2\)).

What happens if you put all three models in the same anova?

anova(Samara.lm.m0, Samara.lm.m1, Samara.lm.m2)
Analysis of Variance Table

Model 1: Velocity ~ Load
Model 2: Velocity ~ Tree + Load
Model 3: Velocity ~ Tree + Load + Tree:Load
  Res.Df     RSS Df Sum of Sq     F  Pr(>F)  
1     33 0.21476                             
2     31 0.20344  2  0.011322 0.992 0.38306  
3     29 0.16549  2  0.037949 3.325 0.05011 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

We see that the p-value for comparing M0 and M1 is now 0.38306 instead of 0.4319. Why is there a change in the p-value?

The reason is that the denominator for the F test is based on the biggest model to hand (M2), namely using RSS=0.16549 on 29 df, whereas for the previous analysis the biggest model to hand was M1, using RSS=0.20344 on 31 df. This is enough of a difference to change the p-value to 0.38306.

The lesson then is that if we are going to quote a p-value then we need to decide once and for all whether to use the different slopes model or not.

Fitted model is

Overall, it seems that single regression is probably adequate.

\[E[ \mbox{Velocity}] = -0.093 + 5.82 \mbox{Load}\]

Comparison of Models for Body Fat

In this section, we are concerned with modelling a small data set on human body fat.

The response is percentage fat. Age is a numerical covariate, gender is a factor.

Various model comparisons and model summaries are provided. Decide which is the best model, and write down the fitted model equation for males and females.

image
image

Data for Task

Download fat.csv

## Fat <- read.csv(file = "fat.csv", header = TRUE)
head(Fat)
  X Age Percent.Fat Gender
1 1  23         9.5      M
2 2  23        27.9      F
3 3  27         7.8      M
4 4  27        17.8      M
5 5  39        31.4      F
6 6  41        25.9      F

Coplot for Data from Task

The function coplot() produces a conditioning plot.

Syntax is coplot(y ~ x | A)

This plots y against x for each level of factor A.

coplot(Percent.Fat ~ Age | Gender, data = Fat)

unlabelled

A similar result si obtained using ggplot() with the group parameter specified. (not shown)

R code for models fitting and comparisons

Fat.lm.0 <- lm(Percent.Fat ~ Age, data = Fat)
Fat.lm.1 <- lm(Percent.Fat ~ Gender + Age, data = Fat)
Fat.lm.2 <- lm(Percent.Fat ~ Gender + Age + Gender:Age, data = Fat)
anova(Fat.lm.0, Fat.lm.1)
Analysis of Variance Table

Model 1: Percent.Fat ~ Age
Model 2: Percent.Fat ~ Gender + Age
  Res.Df    RSS Df Sum of Sq      F  Pr(>F)  
1     16 529.66                              
2     15 360.88  1    168.79 7.0157 0.01824 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova(Fat.lm.1, Fat.lm.2)
Analysis of Variance Table

Model 1: Percent.Fat ~ Gender + Age
Model 2: Percent.Fat ~ Gender + Age + Gender:Age
  Res.Df    RSS Df Sum of Sq      F Pr(>F)  
1     15 360.88                             
2     14 282.02  1    78.853 3.9144 0.0679 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(Fat.lm.0)

Call:
lm(formula = Percent.Fat ~ Age, data = Fat)

Residuals:
     Min       1Q   Median       3Q      Max 
-10.2166  -3.3214  -0.8424   1.9466  12.0753 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   3.2209     5.0762   0.635    0.535    
Age           0.5480     0.1056   5.191 8.93e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 5.754 on 16 degrees of freedom
Multiple R-squared:  0.6274,    Adjusted R-squared:  0.6041 
F-statistic: 26.94 on 1 and 16 DF,  p-value: 8.93e-05
summary(Fat.lm.1)

Call:
lm(formula = Percent.Fat ~ Gender + Age, data = Fat)

Residuals:
   Min     1Q Median     3Q    Max 
-6.638 -3.455 -1.103  3.297  8.952 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  15.0708     6.2243   2.421   0.0286 *
GenderM      -9.7914     3.6966  -2.649   0.0182 *
Age           0.3392     0.1196   2.835   0.0125 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 4.905 on 15 degrees of freedom
Multiple R-squared:  0.7461,    Adjusted R-squared:  0.7123 
F-statistic: 22.04 on 2 and 15 DF,  p-value: 3.424e-05
summary(Fat.lm.2)

Call:
lm(formula = Percent.Fat ~ Gender + Age + Gender:Age, data = Fat)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.6756 -2.8862 -0.2464  1.9100  9.1641 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  20.1116     6.2395   3.223  0.00613 **
GenderM     -29.2692    10.4098  -2.812  0.01386 * 
Age           0.2401     0.1204   1.994  0.06600 . 
GenderM:Age   0.5725     0.2893   1.978  0.06790 . 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 4.488 on 14 degrees of freedom
Multiple R-squared:  0.8016,    Adjusted R-squared:  0.7591 
F-statistic: 18.86 on 3 and 14 DF,  p-value: 3.455e-05

Task: Fitted model equation of chosen model

What is the preferred model’s equation?

Solution

Since we are talking about a one degree of freedom difference, the p-value from anova(Fat.lm.1, Fat.lm.2) is the same as the p-value for the interaction term in Fat.lm.2, namely 0.0679. So we don’t use the interaction model.

Similarly the difference between the first two models is one df, so the p-value from anova(Fat.lm.0, Fat.lm.1) would be the same as for the coefficient of GenderM, namely 0.0182.

So we need to use the second model.

The equation is Fat = 15.0708 -9.7914 * GenderM + 0.3392 * Age

or Fat = 15.0708 + 0.3392 * Age for females and

Fat = 5.2794 + 0.3392* Age for males.

LS0tDQp0aXRsZTogIkxlY3R1cmUgMjY6IENvbXBhcmlzb24gb2YgZ2VuZXJhbCBsaW5lYXIgbW9kZWxzIg0Kc3VidGl0bGU6IDE2MS4yNTEgUmVncmVzc2lvbiBNb2RlbGxpbmcNCmF1dGhvcjogIlByZXNlbnRlZCBieSBKb25hdGhhbiBHb2RmcmV5IDxhLmouZ29kZnJleUBtYXNzZXkuYWMubno+IiAgDQpkYXRlOiAiV2VlayA5IG9mIFNlbWVzdGVyIDIsIGByIGx1YnJpZGF0ZTo6eWVhcihsdWJyaWRhdGU6Om5vdygpKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiB5ZXRpDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOg0KICAgIHdpZGVzY3JlZW46IHRydWUNCiAgICBzbWFsbGVyOiB0cnVlDQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgc2xpZHlfcHJlc2VudGF0aW9uOiANCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KDQoNCg0KDQpbVmlldyB0aGUgbGF0ZXN0IHJlY29yZGluZyBvZiB0aGlzIGxlY3R1cmVdKGh0dHBzOi8vUi1SZXNvdXJjZXMubWFzc2V5LmFjLm56L3ZpZGVvcy8yNTFMMjYubXA0KQ0KPCEtLS0gRGF0YSBpcyBvbg0KaHR0cHM6Ly9yLXJlc291cmNlcy5tYXNzZXkuYWMubnovZGF0YS8xNjEyNTEvDQotLS0+DQoNCmBgYHtyIHNldHVwLCBwdXJsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCm9wdHNfY2h1bmskc2V0KGRldj1jKCJwbmciLCAicGRmIikpDQpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD03LCBmaWcucGF0aD0iRmlndXJlcy8iLCBmaWcuYWx0PSJ1bmxhYmVsbGVkIikNCm9wdHNfY2h1bmskc2V0KGNvbW1lbnQ9IiIsIGZpZy5hbGlnbj0iY2VudGVyIiwgdGlkeT1UUlVFKQ0Kb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICcnKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGJyb29tKQ0KYGBgDQoNCg0KPCEtLS0gRG8gbm90IGVkaXQgYW55dGhpbmcgYWJvdmUgdGhpcyBsaW5lLiAtLS0+DQoNCkluIHByZXZpb3VzIGxlY3R1cmVzIHdlIGhhdmUgY29uc2lkZXJlZCBtb2RlbCBjb21wYXJpc29uIG9mIG5lc3RlZCAgICByZWdyZXNzaW9uIG1vZGVscywgYW5kIG5lc3RlZCBBTk9WQSB0eXBlIG1vZGVscy4NCg0KVGhlIGNvbXBhcmlzb24gb2YgbmVzdGVkIGdlbmVyYWwgbGluZWFyIG1vZGVscyB1c2luZyAqRiogdGVzdHMgZm9sbG93cw0KICAgIG5hdHVyYWxseS4NCg0KIyMgTmF0dXJhbCBvcmRlcmluZyBvZiBHTE1zDQoNCg0KIVtpbWFnZV0oLi4vZ3JhcGhpY3MvZ2xtX2NvbXAucG5nKQ0KDQojIyBDb21wYXJpc29uIG9uIE5lc3RlZCBMaW5lYXIgTW9kZWxzDQoNCkZvciBhbnkgbGluZWFyIG1vZGVsICRNMCQgbmVzdGVkIHdpdGhpbiAkTTEkLCB3ZSBjYW4gdGVzdDoNCg0KKiAkSF8wJDogJE0wJCBhZGVxdWF0ZSB2cw0KDQoqICRIXzEkOiAkTTAkIG5vdCBhZGVxdWF0ZS4NCg0KDQp1c2luZyBhbiAqRiogdGVzdC4NCg0KVGhlIGh5cG90aGVzZXMgY2FuIGJlIHN0YXRlZCBpbiB0ZXJtcyBvZiBwYXJhbWV0ZXJzIG9mIG1vZGVsICRNMSQuDQoNClRoZSAqRiogdGVzdCBzdGF0aXN0aWMgaXMNCg0KJCRGID0gXGZyYWN7W1JTU197TTB9IC0gUlNTX3tNMX1dL2R9e1JTU197TTF9L3J9JCQgd2hlcmUgKmQqIGlzDQogICAgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIG51bWJlciBvZiAocmVncmVzc2lvbikgcGFyYW1ldGVycyBiZXR3ZWVuIHRoZQ0KICAgIG1vZGVscywgYW5kICpyKiBpcyB0aGUgcmVzaWR1YWwgZGVncmVlcyBvZiBmcmVlZG9tIGZvciAkTTEkLg0KDQoNCg0KSWYgJEhfMCQgaXMgY29ycmVjdCB0aGVuICpGKiBoYXMgYW4gKkYqIGRpc3RyaWJ1dGlvbiB3aXRoICRkLHIkDQogICAgZGVncmVlcyBvZiBmcmVlZG9tLg0KDQpFeHRyZW1lIGxhcmdlIHZhbHVlcyBvZiB0aGUgdGVzdCBzdGF0aXN0aWMgcHJvdmlkZSBldmlkZW5jZSBhZ2FpbnN0DQogICAgJEhfMCQuDQoNCkhlbmNlIGlmICRmX3tvYnN9JCBpcyB0aGUgb2JzZXJ2ZWQgdmFsdWUgb2YgdGhlIHRlc3Qgc3RhdGlzdGljLA0KICAgIGFuZCAqWCogaXMgYSByYW5kb20gdmFyaWFibGUgZnJvbSBhbiAkRl97ZCxyfSQgZGlzdHJpYnV0aW9uLA0KICAgIHRoZW4gdGhlICpQKi12YWx1ZSBpcyBnaXZlbiBieSAkUD0gUChYIFxnZSBmX3tvYnN9KSQNCg0KVGhpcyB0ZXN0IGNhbiBiZSBjYXJyaWVkIG91dCBpbiBSIHVzaW5nIGBhbm92YShtMC5sbSwgbTEubG0pYCB3aGVyZSBgbTAubG1gIGFuZCBgbTEubG1gIGFyZSByZXNwZWN0aXZlbHkgdGhlICRNMCQgYW5kICRNMSQgZml0dGVkIG1vZGVscy4NCg0KIyMgVGhlIFNhbWFyYSBEYXRhIHJldmlzaXRlZA0KDQpSZWNhbGwgdGhhdCB3ZSB3ZXJlIG1vZGVsbGluZyB0aGUgbWVhbiBzcGVlZCBvZiBmYWxsIG9mIHNhbWFyYQ0KICAgIChmcnVpdCBmcm9tIGEgbWFwbGUgdHJlZSkgYXMgYSBmdW5jdGlvbiBvZiB0aGUgZGlzayBsb2FkaW5nIChhDQogICAgY292YXJpYXRlKSBhbmQgdGhlIHRyZWUgZnJvbSB3aGljaCBpdCBmZWxsIChhIGZhY3RvcikgZm9yIGVhY2gNCiAgICBmcnVpdC4NCg0KV2UgZml0dGVkIHNlcGFyYXRlIGxpbmVhciByZWdyZXNzaW9ucyBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgdHJlZXMuDQoNCldlIHNoYWxsIG5vdyBjb25zaWRlciBzaW1wbGVyIG1vZGVsczoNCiAgICANCi0gUGFyYWxsZWwgcmVncmVzc2lvbnMgZm9yIGVhY2ggdHJlZSAoaS5lLiBlcXVhbCBzbG9wZSBmb3IgYExvYWRgIGZvciBhbGwgICAgICAgIHRyZWVzKTsNCi0gQSBzaW5nbGUgcmVncmVzc2lvbiBtb2RlbCBmb3IgZXZlcnkgZnJ1aXQgKGkuZS4gZXF1YWwgc2xvcGUgYW5kIGludGVyY2VwdCBmb3IgZWFjaCB0cmVlKS4NCiAgICANCldlIHNoYWxsIGNvbXBhcmUgdGhlc2UgbW9kZWxzIHdpdGggZWFjaCBvdGhlciwgYW5kIHdpdGggdGhlIHNlcGFyYXRlIHJlZ3Jlc3Npb25zIG1vZGVsLg0KDQoNCiMjIyBEaWZmZXJlbnQgUmVncmVzc2lvbnMgTW9kZWwNCg0KYHIgeGZ1bjo6ZW1iZWRfZmlsZSgiLi4vLi4vZGF0YS9zYW1hcmEuY3N2IilgDQoNCmBgYHtyIFNhbWFyYS5sbS5tMiwgZWNobz0tMSwgZXZhbD0tMn0NClNhbWFyYSA8LSByZWFkLmNzdihmaWxlPSIuLi8uLi9kYXRhL3NhbWFyYS5jc3YiLCBoZWFkZXI9VFJVRSkNClNhbWFyYSA8LSByZWFkLmNzdihmaWxlPSJzYW1hcmEuY3N2IiwgaGVhZGVyPVRSVUUpDQpTYW1hcmEkVHJlZSA8LSBmYWN0b3IoU2FtYXJhJFRyZWUpDQpTYW1hcmEubG0ubTIgPC0gbG0oVmVsb2NpdHl+IFRyZWUgK0xvYWQgKyBUcmVlOkxvYWQsIGRhdGEgPSBTYW1hcmEpDQpzdW1tYXJ5KFNhbWFyYS5sbS5tMikNCmBgYA0KDQoNCiMjIyBQYXJhbGxlbCBSZWdyZXNzaW9ucyBNb2RlbA0KDQpgYGB7ciBTYW1hcmEubG0ubTF9DQpTYW1hcmEubG0ubTEgPC0gbG0oVmVsb2NpdHkgfiBUcmVlICsgTG9hZCwgZGF0YT1TYW1hcmEpDQpzdW1tYXJ5KFNhbWFyYS5sbS5tMSkNCmBgYA0KDQoNCiMjIyBDb21tb24gUmVncmVzc2lvbnMgTW9kZWwNCg0KYGBge3IgU2FtYXJhLmxtLm0wfQ0KU2FtYXJhLmxtLm0wIDwtIGxtKFZlbG9jaXR5IH4gTG9hZCwgZGF0YT1TYW1hcmEpDQpzdW1tYXJ5KFNhbWFyYS5sbS5tMCkNCmBgYA0KDQojIyMgQ29tcGFyaW5nIE1vZGVscw0KDQpgYGB7ciB9DQphbm92YShTYW1hcmEubG0ubTEsIFNhbWFyYS5sbS5tMikNCmFub3ZhKFNhbWFyYS5sbS5tMCwgU2FtYXJhLmxtLm0xKQ0KYW5vdmEoU2FtYXJhLmxtLm0wLCBTYW1hcmEubG0ubTIpDQpgYGANCg0KIA0KDQojIyMgQ29tbWVudHMNCg0KTW9kZWxzIGZpdHRlZCBhcyBmb2xsb3dzOg0KDQotIGBTYW1hcmEubG0ubTJgIGlzIHNlcGFyYXRlIHJlZ3Jlc3Npb25zIG1vZGVsLiBJdCBoYXMgNiAgICAgICAgcmVncmVzc2lvbiBwYXJhbWV0ZXJzICgzIGZvciBpbnRlcmNlcHRzLCAzIGZvciBzbG9wZXMpIGFuZCBSU1MNCiAgICAgICAgb2YgKjAuMTY1NDkqLg0KLSBgU2FtYXJhLmxtLm0xYCBpcyBwYXJhbGxlbCByZWdyZXNzaW9ucyBtb2RlbC4gSXQgaGFzIDQgICAgICAgcmVncmVzc2lvbiBwYXJhbWV0ZXJzICgzIGZvciBpbnRlcmNlcHRzLCAxIGZvciBzbG9wZSkgYW5kIFJTUyBvZiAgICAgKjAuMjAzNDQqLg0KLSBgU2FtYXJhLmxtLm0wYCBpcyBzaW5nbGUgcmVncmVzc2lvbnMgbW9kZWwuIEl0IGhhcyAyIHJlZ3Jlc3Npb24gIHBhcmFtZXRlcnMgKDEgZm9yIGludGVyY2VwdCwgMSBmb3Igc2xvcGUpIGFuZCBSU1Mgb2YgKjAuMjE0NzYqLg0KDQpDb21wYXJpc29uIG9mICRNMiQgYW5kICRNMSQgZ2l2ZXMgdmVyeSBib3JkZXJsaW5lIHJlc3VsdA0KICAgICgqUD0wLjA1MDExKikuIFdlIHdvdWxkIGp1c3QgYmFyZWx5IHJldGFpbiAkTTEkIGlmIHdlIHdlcmUgd29ya2luZyBhdCBhIDUlDQogICAgc2lnbmlmaWNhbmNlIGxldmVsLg0KDQpDb21wYXJpc29uIG9mICRNMSQgYW5kICRNMCQgcHJvdmlkZXMgbm8gZXZpZGVuY2UgdG8gcHJlZmVyDQogICAgJE0xJCAoKlA9MC40MzE5KikuDQoNCkNvbXBhcmlzb24gb2YgJE0yJCBhbmQgJE0wJCBzaG93cyB0aGF0ICRNMCQgc2hvdWxkIGJlIHJldGFpbmVkDQogICAgYXQgdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbCAodGhvdWdoIHRoZXJlIGlzIHdlYWsgZXZpZGVuY2UgaW4NCiAgICBmYXZvdXIgb2YgJE0yJCkuDQoNCiMjIyMgV2hhdCBoYXBwZW5zIGlmIHlvdSBwdXQgYWxsIHRocmVlIG1vZGVscyBpbiB0aGUgc2FtZSBhbm92YT8gDQpgYGB7ciB9DQphbm92YShTYW1hcmEubG0ubTAsICBTYW1hcmEubG0ubTEsIFNhbWFyYS5sbS5tMikNCmBgYA0KDQpXZSBzZWUgdGhhdCB0aGUgcC12YWx1ZSBmb3IgY29tcGFyaW5nIE0wIGFuZCBNMSBpcyBub3cgKjAuMzgzMDYqICBpbnN0ZWFkIG9mICowLjQzMTkqLiBXaHkgaXMgdGhlcmUgYSBjaGFuZ2UgaW4gdGhlIHAtdmFsdWU/IA0KDQpUaGUgcmVhc29uIGlzIHRoYXQgdGhlIGRlbm9taW5hdG9yIGZvciB0aGUgRiB0ZXN0IGlzIGJhc2VkIG9uIHRoZSBiaWdnZXN0IG1vZGVsIHRvIGhhbmQgKE0yKSwgbmFtZWx5IHVzaW5nICpSU1M9MC4xNjU0OSogb24gKjI5KiBkZiwgd2hlcmVhcyBmb3IgdGhlIHByZXZpb3VzIGFuYWx5c2lzIHRoZSBiaWdnZXN0IG1vZGVsIHRvIGhhbmQgd2FzIE0xLCB1c2luZyAqUlNTPTAuMjAzNDQqIG9uICozMSogZGYuIFRoaXMgaXMgZW5vdWdoIG9mIGEgZGlmZmVyZW5jZSB0byBjaGFuZ2UgdGhlIHAtdmFsdWUgdG8gKjAuMzgzMDYqLiANCg0KVGhlIGxlc3NvbiB0aGVuIGlzIHRoYXQgaWYgd2UgYXJlIGdvaW5nIHRvIHF1b3RlIGEgcC12YWx1ZSB0aGVuIHdlIG5lZWQgdG8gZGVjaWRlIG9uY2UgYW5kIGZvciBhbGwgd2hldGhlciB0byB1c2UgdGhlIGBkaWZmZXJlbnQgc2xvcGVzYCBtb2RlbCBvciBub3QuIA0KDQojIyMjIEZpdHRlZCBtb2RlbCBpcw0KDQpPdmVyYWxsLCBpdCBzZWVtcyB0aGF0IHNpbmdsZSByZWdyZXNzaW9uIGlzIHByb2JhYmx5IGFkZXF1YXRlLg0KDQokJEVbIFxtYm94e1ZlbG9jaXR5fV0gPSAtMC4wOTMgKyA1LjgyICBcbWJveHtMb2FkfSQkDQoNCiMjIENvbXBhcmlzb24gb2YgTW9kZWxzIGZvciBCb2R5IEZhdA0KDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgYXJlIGNvbmNlcm5lZCB3aXRoIG1vZGVsbGluZyBhIHNtYWxsIGRhdGEgc2V0IG9uIGh1bWFuIGJvZHkgZmF0Lg0KDQpUaGUgcmVzcG9uc2UgaXMgcGVyY2VudGFnZSBmYXQuIEFnZSBpcyBhIG51bWVyaWNhbCBjb3ZhcmlhdGUsIGdlbmRlciBpcyBhIGZhY3Rvci4NCg0KVmFyaW91cyBtb2RlbCBjb21wYXJpc29ucyBhbmQgbW9kZWwgc3VtbWFyaWVzIGFyZSBwcm92aWRlZC4gRGVjaWRlIHdoaWNoIGlzIHRoZSBiZXN0IG1vZGVsLCBhbmQgd3JpdGUgZG93biB0aGUgZml0dGVkIG1vZGVsIGVxdWF0aW9uIGZvciBtYWxlcyBhbmQgZmVtYWxlcy4NCg0KDQohW2ltYWdlXSguLi9ncmFwaGljcy9ib2R5ZmF0LmpwZykNCg0KICANCg0KIyMjIERhdGEgZm9yIFRhc2sgDQoNCmByIHhmdW46OmVtYmVkX2ZpbGUoIi4uLy4uL2RhdGEvZmF0LmNzdiIpYA0KDQpgYGB7ciBnZXRGYXQsIGVjaG89LTEsIGV2YWw9LTJ9DQpGYXQgPC0gcmVhZC5jc3YoZmlsZT0iLi4vLi4vZGF0YS9mYXQuY3N2IiwgaGVhZGVyPVRSVUUpDQpGYXQgPC0gcmVhZC5jc3YoZmlsZT0iZmF0LmNzdiIsIGhlYWRlcj1UUlVFKQ0KaGVhZChGYXQpDQpgYGANCg0KIyMjIENvcGxvdCBmb3IgRGF0YSBmcm9tIFRhc2sgDQoNCg0KVGhlIGZ1bmN0aW9uIGBjb3Bsb3QoKWAgIHByb2R1Y2VzIGEgKipjb25kaXRpb25pbmcgcGxvdCoqLg0KDQpTeW50YXggaXMgYGNvcGxvdCh5IH4geCB8IEEpYA0KICAgIA0KDQpUaGlzIHBsb3RzIGB5YCBhZ2FpbnN0IGB4YCBmb3IgZWFjaCBsZXZlbCBvZiBmYWN0b3IgYEFgLg0KDQpgYGB7cn0NCmNvcGxvdChQZXJjZW50LkZhdCB+IEFnZSB8IEdlbmRlciwgZGF0YSA9IEZhdCkNCmBgYA0KDQpBIHNpbWlsYXIgcmVzdWx0IHNpIG9idGFpbmVkIHVzaW5nIGBnZ3Bsb3QoKWAgd2l0aCB0aGUgYGdyb3VwYCBwYXJhbWV0ZXIgc3BlY2lmaWVkLiAobm90IHNob3duKQ0KDQojIyMgUiBjb2RlIGZvciBtb2RlbHMgZml0dGluZyBhbmQgY29tcGFyaXNvbnMNCg0KYGBge3IgZmF0TW9kZWxzfQ0KRmF0LmxtLjAgPC0gbG0oUGVyY2VudC5GYXQgfiBBZ2UsIGRhdGEgPSBGYXQpDQpGYXQubG0uMSA8LWxtKFBlcmNlbnQuRmF0IH4gR2VuZGVyICsgQWdlLCBkYXRhID0gRmF0KQ0KRmF0LmxtLjIgPC0gbG0oUGVyY2VudC5GYXR+IEdlbmRlcitBZ2UgKyBHZW5kZXI6QWdlLCBkYXRhID0gRmF0KQ0KYW5vdmEoRmF0LmxtLjAsIEZhdC5sbS4xKQ0KYW5vdmEoRmF0LmxtLjEsIEZhdC5sbS4yKQ0Kc3VtbWFyeShGYXQubG0uMCkNCnN1bW1hcnkoRmF0LmxtLjEpDQpzdW1tYXJ5KEZhdC5sbS4yKQ0KYGBgDQoNCiMjIyBUYXNrOiBGaXR0ZWQgbW9kZWwgZXF1YXRpb24gb2YgY2hvc2VuIG1vZGVsDQoNCldoYXQgaXMgdGhlIHByZWZlcnJlZCBtb2RlbCdzIGVxdWF0aW9uPw0KDQoNCiMjIyMjIFNvbHV0aW9uDQoNClNpbmNlIHdlIGFyZSB0YWxraW5nIGFib3V0IGEgb25lIGRlZ3JlZSBvZiBmcmVlZG9tIGRpZmZlcmVuY2UsIHRoZSBwLXZhbHVlIGZyb20gDQphbm92YShGYXQubG0uMSwgRmF0LmxtLjIpIGlzIHRoZSBzYW1lIGFzIHRoZSBwLXZhbHVlIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybSBpbiBGYXQubG0uMiwgbmFtZWx5IDAuMDY3OS4gIFNvIHdlIGRvbid0IHVzZSB0aGUgaW50ZXJhY3Rpb24gbW9kZWwuICANCg0KU2ltaWxhcmx5IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGZpcnN0IHR3byBtb2RlbHMgaXMgb25lIGRmLCBzbyB0aGUgcC12YWx1ZSBmcm9tIGFub3ZhKEZhdC5sbS4wLCBGYXQubG0uMSkgd291bGQgYmUgdGhlIHNhbWUgYXMgZm9yIHRoZSBjb2VmZmljaWVudCBvZiBHZW5kZXJNLCBuYW1lbHkgMC4wMTgyLiANCg0KU28gd2UgbmVlZCB0byB1c2UgdGhlIHNlY29uZCBtb2RlbC4gIA0KDQpUaGUgZXF1YXRpb24gaXMgRmF0ID0gMTUuMDcwOCAgIC05Ljc5MTQgKiBHZW5kZXJNICAgKyAgIDAuMzM5MiAqIEFnZSAgDQoNCm9yIEZhdCA9IDE1LjA3MDggKyAgMC4zMzkyICogQWdlICAgIGZvciBmZW1hbGVzIGFuZCANCg0KRmF0ID0gNS4yNzk0ICsgIDAuMzM5MiogQWdlIGZvciBtYWxlcy4NCg==