Load and Explore the Data

We begin by reading in the data and looking at a summary of it.

df <- read.table("ex02.txt", sep="\t", header=TRUE)
summary(df)
       x               y          
 Min.   :2.283   Min.   :  46.79  
 1st Qu.:3.767   1st Qu.: 381.51  
 Median :4.985   Median : 953.84  
 Mean   :5.085   Mean   :1862.38  
 3rd Qu.:6.416   3rd Qu.:2888.49  
 Max.   :7.918   Max.   :7982.39  

Create a scatterplot.

plot(y ~ x, df, pch=21, col="black", bg="cyan")

Linear Model

We will begin our analysis by considering a linear model of the form: \(Y = \hat{\beta}_0 + \hat{\beta}_1 X + e\)

m1 <- lm(y ~ x, df)
summary(m1) 

Call:
lm(formula = y ~ x, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-2189.4  -671.4  -170.1   516.8  3842.2 

Coefficients:
            Estimate Std. Error t value Pr(>|t|) 2.96e-15 ***
x            1012.61      65.69  15.416  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1083 on 98 degrees of freedom
Multiple R-squared:  0.708, Adjusted R-squared:  0.705 
F-statistic: 237.6 on 1 and 98 DF,  p-value: < 2.2e-16

Plot the fitted line.

plot(y ~ x, df, pch=21, col="black", bg="cyan")
abline(m1$coefficients, col="darkred", lwd=2)

We now create a residual plot.

plot(m1$residuals ~ df$x, pch=21, col="black", bg="cyan", 
     xlab="x", ylab="Residuals", main="Residual Plot")
abline(h=0, col="darkred", lwd=2)

The residuals exhibit a trend, as well as heteroskedasticity (unequal variance).

We now assess the normality of the residuals with a histogram and a QQ-plot.

res1 <- m1$residuals
par(mfrow=c(1,2))
hist(res1, col='orchid')
qqnorm(res1)
qqline(res1)
par(mfrow=c(1,1))

These plots indicate that the residuals were drawn from a right-skewed distribution.

Exponential Model

We will now consider a model of the form \(Y = \hat{\beta}_0 + \hat{\beta}_1 e^X + \varepsilon\).

m2 <- lm(y ~ exp(x), df)
summary(m2) 

Call:
lm(formula = y ~ exp(x), data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-3783.0  -543.9  -229.4   436.6  4134.5 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 689.4541   132.2450   5.213 1.03e-06 ***   2.2769     0.1476  15.430  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1082 on 98 degrees of freedom
Multiple R-squared:  0.7084,    Adjusted R-squared:  0.7054 
F-statistic: 238.1 on 1 and 98 DF,  p-value: < 2.2e-16

We plot the fitted curve.

plot(y ~ x, df, pch=21, col="black", bg="cyan")
ptn = seq(from=2,to=8, by=0.1)
lines(ptn, predict(m2, data.frame(x=ptn)), col="darkred", lwd=2)

We generate a residual plot.

plot(m2$residuals ~ df$x, pch=21, col="black", bg="cyan", 
     xlab="x", ylab="Residuals", main="Residual Plot")
abline(h=0, col="darkred", lwd=2)

There is still a slight trend. The heteroskedasticity is also still present.

We will add prediction intervals to the scatterplot.

plot(y ~ x, df, pch=21, col="black", bg="cyan")
p2 <- predict(m2, newdata=data.frame(x=ptn), interval="prediction", level=0.95)
lines(ptn, p2[,"fit"], col="darkred", lwd=2)
lines(ptn, p2[,"lwr"], col="darkorange", lwd=2)
lines(ptn, p2[,"upr"], col="darkorange", lwd=2)

We now assess the normality of the residuals with a histogram and a QQ-plot.

res2 <- m2$residuals
par(mfrow=c(1,2))
hist(res2, col='orchid')
qqnorm(res2)
qqline(res2)
par(mfrow=c(1,1))

These plots suggests that the residuals were drawn from a heavy-tailed distribution.

Log-Level (or Log-Linear) Model

Let’s plot the natural log of y against x.

plot(log(y) ~ x, df, pch=21, col="black", bg="cyan")

Perhaps we will consider a model of the form: \(\ln(Y) = \hat{\beta}_0 + \hat{\beta}_1 X + \varepsilon\)

m3 <- lm(log(y) ~ x, df)
summary(m3) 
     Min       1Q   Median       3Q      Max 
-1.00249 -0.26117  0.03103  0.26751  0.99605 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   3.1290     0.1465   21.36   <2e-16 ***
x             0.7335     0.0274   26.77   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4517 on 98 degrees of freedom
Multiple R-squared:  0.8797,    Adjusted R-squared:  0.8785 
F-statistic: 716.6 on 1 and 98 DF,  p-value: < 2.2e-16

Let’s consider the residual plot. Note that these are residuals of ln(Y), and not Y.

plot(m3$residuals ~ df$x, pch=21, col="black", bg="cyan", 
     xlab="x", ylab="Residuals", main="Residual Plot")
abline(h=0, col="darkred", lwd=2)

There is no heteroskedasticity in this residual plot, but there does appear to be a slight trend.

We now assess the normality of the residuals with a histogram and a QQ-plot.

res3 <- m3$residuals
par(mfrow=c(1,2))
hist(res3, col='orchid')
qqnorm(res3)
qqline(res3)
par(mfrow=c(1,1))

These plots suggest that the residuals were likey drawn from a slightly heavy-tailed distribution.

We will add the fitted curve and to the scatter plot of ln(y) against y.

plot(log(y) ~ x, df, pch=21, col="black", bg="cyan")
p3 <- predict(m3, newdata=data.frame(x=ptn), interval="prediction", level=0.95)
lines(ptn, p3[,"fit"], col="darkred", lwd=2)
lines(ptn, p3[,"lwr"], col="darkorange", lwd=2)
lines(ptn, p3[,"upr"], col="darkorange", lwd=2)

We can exponentiate the values of log(Y) to transform back to be in terms of Y.

plot(y ~ x, df, pch=21, col="black", bg="cyan")
p3 <- predict(m3, newdata=data.frame(x=ptn), interval="prediction", level=0.95)
lines(ptn, exp(p3[,"fit"]), col="darkred", lwd=2)
lines(ptn, exp(p3[,"lwr"]), col="darkorange", lwd=2)
lines(ptn, exp(p3[,"upr"]), col="darkorange", lwd=2)

Log-Log Model

Let’s plot the natural log of y against the natural log of x.

plot(log(y) ~ log(x), df, pch=21, col="black", bg="cyan")

This appears to be an approximately linear relationship. We will consider a model of the form: \(\ln(Y) = \hat{\beta}_0 + \hat{\beta}_1 \ln(X) + \varepsilon\)

m4 <- lm(log(y) ~ log(x), df)
summary(m4) 

Call:
lm(formula = log(y) ~ log(x), data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.96888 -0.24472 -0.01224  0.23851  0.91477 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.2986     0.1855   7.001  3.2e-10 ***
log(x)        3.5432     0.1154  30.699  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3997 on 98 degrees of freedom
Multiple R-squared:  0.9058,    Adjusted R-squared:  0.9048 
F-statistic: 942.4 on 1 and 98 DF,  p-value: < 2.2e-16

Let’s consider the residual plot. Note that these are residuals of ln(Y), and not Y.

plot(m4$residuals ~ df$x, pch=21, col="black", bg="cyan", 
     xlab="x", ylab="Residuals", main="Residual Plot")
abline(h=0, col="darkred", lwd=2)

There is no apparent heteroskedasticity or trend in this residual plot.

We now assess the normality of the residuals with a histogram and a QQ-plot.

res4 <- m4$residuals
par(mfrow=c(1,2))
hist(res4, col='orchid')
qqnorm(res4)
qqline(res4)
par(mfrow=c(1,1))

These plots suggest that the residuals were perhaps drawn from a slightly heavy-tailed distribution.

We will add the fitted curve and to the scatter plot of ln(y) against y.

plot(log(y) ~ log(x), df, pch=21, col="black", bg="cyan")
p4 <- predict(m4, newdata=data.frame(x=ptn), interval="prediction", level=0.95)
lines(log(ptn), p4[,"fit"], col="darkred", lwd=2)
lines(log(ptn), p4[,"lwr"], col="darkorange", lwd=2)
lines(log(ptn), p4[,"upr"], col="darkorange", lwd=2)

We can exponentiate the values of log(Y) to transform back to be in terms of Y.

plot(y ~ x, df, pch=21, col="black", bg="cyan")
p4 <- predict(m4, newdata=data.frame(x=ptn), interval="prediction", level=0.95)
lines(ptn, exp(p4[,"fit"]), col="darkred", lwd=2)
lines(ptn, exp(p4[,"lwr"]), col="darkorange", lwd=2)
lines(ptn, exp(p4[,"upr"]), col="darkorange", lwd=2)

Generating Predictions with the Transformed Model

When using this model to create predictions for Y, we need to first generate a prediction for ln(Y), and then exponentiate. Let’s construct a 95% prediction interval for Y when X = 6.5.

ln_yhat = predict(m4, data.frame(x=c(6.5)), interval="prediction", level=0.95)
yhat = exp(ln_yhat)
yhat
       fit      lwr      upr
1 2781.552 1249.637 6191.424

Note that we cannot directly compare r^2 values for linear and log-linear models. We can directly compare SSE values (assuming we transform everything back to Y), but we shouldn’t use SSE exclusively to determine which model to use.

# Linear
sum((m1$residuals)^2)
[1] 114917119
sum((df$y - m1$fitted.values)^2)
[1] 114917119
# Exponential
sum((m2$residuals)^2)   
[1] 114762921
# Log-Linear
sum((df$y - exp(m3$fitted.values))^2)  
[1] 112548872
# Log-Log
sum((df$y - exp(m4$fitted.values))^2)  
[1] 90860143
LS0tDQp0aXRsZTogIkxlc3NvbiAxNCAtIExvZ2FyaXRobWljIFRyYW5zZm9ybWF0aW9ucyAoUGFydCAyKSINCmF1dGhvcjogIlJvYmJpZSBCZWFuZSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDINCi0tLQ0KDQojIExvYWQgYW5kIEV4cGxvcmUgdGhlIERhdGENCg0KV2UgYmVnaW4gYnkgcmVhZGluZyBpbiB0aGUgZGF0YSBhbmQgbG9va2luZyBhdCBhIHN1bW1hcnkgb2YgaXQuIA0KDQpgYGB7cn0NCmRmIDwtIHJlYWQudGFibGUoImV4MDIudHh0Iiwgc2VwPSJcdCIsIGhlYWRlcj1UUlVFKQ0Kc3VtbWFyeShkZikNCmBgYA0KDQpDcmVhdGUgYSBzY2F0dGVycGxvdC4NCg0KYGBge3J9DQpwbG90KHkgfiB4LCBkZiwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iKQ0KYGBgDQoNCg0KDQojIExpbmVhciBNb2RlbA0KDQpXZSB3aWxsIGJlZ2luIG91ciBhbmFseXNpcyBieSBjb25zaWRlcmluZyBhIGxpbmVhciBtb2RlbCBvZiB0aGUgZm9ybTogJFkgPSBcaGF0e1xiZXRhfV8wICsgXGhhdHtcYmV0YX1fMSBYICsgZSQgDQoNCmBgYHtyfQ0KbTEgPC0gbG0oeSB+IHgsIGRmKQ0Kc3VtbWFyeShtMSkgDQpgYGANCg0KUGxvdCB0aGUgZml0dGVkIGxpbmUuIA0KDQpgYGB7cn0NCnBsb3QoeSB+IHgsIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQphYmxpbmUobTEkY29lZmZpY2llbnRzLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmBgYA0KDQoNCldlIG5vdyBjcmVhdGUgYSByZXNpZHVhbCBwbG90LiANCg0KYGBge3J9DQpwbG90KG0xJHJlc2lkdWFscyB+IGRmJHgsIHBjaD0yMSwgY29sPSJibGFjayIsIGJnPSJjeWFuIiwgDQogICAgIHhsYWI9IngiLCB5bGFiPSJSZXNpZHVhbHMiLCBtYWluPSJSZXNpZHVhbCBQbG90IikNCg0KYWJsaW5lKGg9MCwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpgYGANCg0KVGhlIHJlc2lkdWFscyBleGhpYml0IGEgdHJlbmQsIGFzIHdlbGwgYXMgaGV0ZXJvc2tlZGFzdGljaXR5ICh1bmVxdWFsIHZhcmlhbmNlKS4gDQoNCldlIG5vdyBhc3Nlc3MgdGhlIG5vcm1hbGl0eSBvZiB0aGUgcmVzaWR1YWxzIHdpdGggYSBoaXN0b2dyYW0gYW5kIGEgUVEtcGxvdC4NCg0KYGBge3J9DQpyZXMxIDwtIG0xJHJlc2lkdWFscw0KcGFyKG1mcm93PWMoMSwyKSkNCmhpc3QocmVzMSwgY29sPSdvcmNoaWQnKQ0KcXFub3JtKHJlczEpDQpxcWxpbmUocmVzMSkNCnBhcihtZnJvdz1jKDEsMSkpDQpgYGANCg0KVGhlc2UgcGxvdHMgaW5kaWNhdGUgdGhhdCB0aGUgcmVzaWR1YWxzIHdlcmUgZHJhd24gZnJvbSBhIHJpZ2h0LXNrZXdlZCBkaXN0cmlidXRpb24uIA0KDQoNCg0KIyBFeHBvbmVudGlhbCBNb2RlbA0KDQpXZSB3aWxsIG5vdyBjb25zaWRlciBhIG1vZGVsIG9mIHRoZSBmb3JtICRZID0gXGhhdHtcYmV0YX1fMCArIFxoYXR7XGJldGF9XzEgZV5YICsgXHZhcmVwc2lsb24kLg0KDQpgYGB7cn0NCm0yIDwtIGxtKHkgfiBleHAoeCksIGRmKQ0Kc3VtbWFyeShtMikgDQpgYGANCg0KV2UgcGxvdCB0aGUgZml0dGVkIGN1cnZlLiANCg0KYGBge3J9DQpwbG90KHkgfiB4LCBkZiwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iKQ0KDQpwdG4gPSBzZXEoZnJvbT0yLHRvPTgsIGJ5PTAuMSkNCmxpbmVzKHB0biwgcHJlZGljdChtMiwgZGF0YS5mcmFtZSh4PXB0bikpLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmBgYA0KDQpXZSBnZW5lcmF0ZSBhIHJlc2lkdWFsIHBsb3QuIA0KDQpgYGB7cn0NCnBsb3QobTIkcmVzaWR1YWxzIH4gZGYkeCwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iLCANCiAgICAgeGxhYj0ieCIsIHlsYWI9IlJlc2lkdWFscyIsIG1haW49IlJlc2lkdWFsIFBsb3QiKQ0KDQphYmxpbmUoaD0wLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmBgYA0KDQpUaGVyZSBpcyBzdGlsbCBhIHNsaWdodCB0cmVuZC4gVGhlIGhldGVyb3NrZWRhc3RpY2l0eSBpcyBhbHNvIHN0aWxsIHByZXNlbnQuIA0KDQpXZSB3aWxsIGFkZCBwcmVkaWN0aW9uIGludGVydmFscyB0byB0aGUgc2NhdHRlcnBsb3QuIA0KDQpgYGB7cn0NCnBsb3QoeSB+IHgsIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQoNCnAyIDwtIHByZWRpY3QobTIsIG5ld2RhdGE9ZGF0YS5mcmFtZSh4PXB0biksIGludGVydmFsPSJwcmVkaWN0aW9uIiwgbGV2ZWw9MC45NSkNCmxpbmVzKHB0biwgcDJbLCJmaXQiXSwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpsaW5lcyhwdG4sIHAyWywibHdyIl0sIGNvbD0iZGFya29yYW5nZSIsIGx3ZD0yKQ0KbGluZXMocHRuLCBwMlssInVwciJdLCBjb2w9ImRhcmtvcmFuZ2UiLCBsd2Q9MikNCmBgYA0KDQoNCldlIG5vdyBhc3Nlc3MgdGhlIG5vcm1hbGl0eSBvZiB0aGUgcmVzaWR1YWxzIHdpdGggYSBoaXN0b2dyYW0gYW5kIGEgUVEtcGxvdC4NCg0KYGBge3J9DQpyZXMyIDwtIG0yJHJlc2lkdWFscw0KcGFyKG1mcm93PWMoMSwyKSkNCmhpc3QocmVzMiwgY29sPSdvcmNoaWQnKQ0KcXFub3JtKHJlczIpDQpxcWxpbmUocmVzMikNCnBhcihtZnJvdz1jKDEsMSkpDQpgYGANCg0KVGhlc2UgcGxvdHMgc3VnZ2VzdHMgdGhhdCB0aGUgcmVzaWR1YWxzIHdlcmUgZHJhd24gZnJvbSBhIGhlYXZ5LXRhaWxlZCBkaXN0cmlidXRpb24uIA0KIA0KDQoNCiMgTG9nLUxldmVsIChvciBMb2ctTGluZWFyKSBNb2RlbA0KDQpMZXQncyBwbG90IHRoZSBuYXR1cmFsIGxvZyBvZiB5IGFnYWluc3QgeC4gDQoNCg0KYGBge3J9DQpwbG90KGxvZyh5KSB+IHgsIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQpgYGANCg0KUGVyaGFwcyB3ZSB3aWxsIGNvbnNpZGVyIGEgbW9kZWwgb2YgdGhlIGZvcm06ICRcbG4oWSkgPSBcaGF0e1xiZXRhfV8wICsgXGhhdHtcYmV0YX1fMSBYICsgXHZhcmVwc2lsb24kDQoNCg0KYGBge3J9DQptMyA8LSBsbShsb2coeSkgfiB4LCBkZikNCnN1bW1hcnkobTMpIA0KYGBgDQoNCkxldCdzIGNvbnNpZGVyIHRoZSByZXNpZHVhbCBwbG90LiBOb3RlIHRoYXQgdGhlc2UgYXJlIHJlc2lkdWFscyBvZiBsbihZKSwgYW5kIG5vdCBZLiANCg0KYGBge3J9DQpwbG90KG0zJHJlc2lkdWFscyB+IGRmJHgsIHBjaD0yMSwgY29sPSJibGFjayIsIGJnPSJjeWFuIiwgDQogICAgIHhsYWI9IngiLCB5bGFiPSJSZXNpZHVhbHMiLCBtYWluPSJSZXNpZHVhbCBQbG90IikNCg0KYWJsaW5lKGg9MCwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpgYGANCg0KVGhlcmUgaXMgbm8gaGV0ZXJvc2tlZGFzdGljaXR5IGluIHRoaXMgcmVzaWR1YWwgcGxvdCwgYnV0IHRoZXJlIGRvZXMgYXBwZWFyIHRvIGJlIGEgc2xpZ2h0IHRyZW5kLiAgDQoNCg0KV2Ugbm93IGFzc2VzcyB0aGUgbm9ybWFsaXR5IG9mIHRoZSByZXNpZHVhbHMgd2l0aCBhIGhpc3RvZ3JhbSBhbmQgYSBRUS1wbG90Lg0KDQpgYGB7cn0NCnJlczMgPC0gbTMkcmVzaWR1YWxzDQpwYXIobWZyb3c9YygxLDIpKQ0KaGlzdChyZXMzLCBjb2w9J29yY2hpZCcpDQpxcW5vcm0ocmVzMykNCnFxbGluZShyZXMzKQ0KcGFyKG1mcm93PWMoMSwxKSkNCmBgYA0KDQpUaGVzZSBwbG90cyBzdWdnZXN0IHRoYXQgdGhlIHJlc2lkdWFscyB3ZXJlIGxpa2V5IGRyYXduIGZyb20gYSBzbGlnaHRseSBoZWF2eS10YWlsZWQgZGlzdHJpYnV0aW9uLiANCiANCg0KDQpXZSB3aWxsIGFkZCB0aGUgZml0dGVkIGN1cnZlIGFuZCAgdG8gdGhlIHNjYXR0ZXIgcGxvdCBvZiBsbih5KSBhZ2FpbnN0IHkuIA0KDQoNCg0KYGBge3J9DQpwbG90KGxvZyh5KSB+IHgsIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQoNCnAzIDwtIHByZWRpY3QobTMsIG5ld2RhdGE9ZGF0YS5mcmFtZSh4PXB0biksIGludGVydmFsPSJwcmVkaWN0aW9uIiwgbGV2ZWw9MC45NSkNCmxpbmVzKHB0biwgcDNbLCJmaXQiXSwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpsaW5lcyhwdG4sIHAzWywibHdyIl0sIGNvbD0iZGFya29yYW5nZSIsIGx3ZD0yKQ0KbGluZXMocHRuLCBwM1ssInVwciJdLCBjb2w9ImRhcmtvcmFuZ2UiLCBsd2Q9MikNCmBgYA0KDQpXZSBjYW4gZXhwb25lbnRpYXRlIHRoZSB2YWx1ZXMgb2YgbG9nKFkpIHRvIHRyYW5zZm9ybSBiYWNrIHRvIGJlIGluIHRlcm1zIG9mIFkuIA0KDQpgYGB7cn0NCnBsb3QoeSB+IHgsIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQoNCnAzIDwtIHByZWRpY3QobTMsIG5ld2RhdGE9ZGF0YS5mcmFtZSh4PXB0biksIGludGVydmFsPSJwcmVkaWN0aW9uIiwgbGV2ZWw9MC45NSkNCmxpbmVzKHB0biwgZXhwKHAzWywiZml0Il0pLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmxpbmVzKHB0biwgZXhwKHAzWywibHdyIl0pLCBjb2w9ImRhcmtvcmFuZ2UiLCBsd2Q9MikNCmxpbmVzKHB0biwgZXhwKHAzWywidXByIl0pLCBjb2w9ImRhcmtvcmFuZ2UiLCBsd2Q9MikNCmBgYA0KDQoNCiMgTG9nLUxvZyBNb2RlbA0KDQpMZXQncyBwbG90IHRoZSBuYXR1cmFsIGxvZyBvZiB5IGFnYWluc3QgdGhlIG5hdHVyYWwgbG9nIG9mIHguIA0KDQoNCmBgYHtyfQ0KcGxvdChsb2coeSkgfiBsb2coeCksIGRmLCBwY2g9MjEsIGNvbD0iYmxhY2siLCBiZz0iY3lhbiIpDQpgYGANCg0KVGhpcyBhcHBlYXJzIHRvIGJlIGFuIGFwcHJveGltYXRlbHkgbGluZWFyIHJlbGF0aW9uc2hpcC4gV2Ugd2lsbCBjb25zaWRlciBhIG1vZGVsIG9mIHRoZSBmb3JtOiAkXGxuKFkpID0gXGhhdHtcYmV0YX1fMCArIFxoYXR7XGJldGF9XzEgXGxuKFgpICsgXHZhcmVwc2lsb24kDQoNCg0KYGBge3J9DQptNCA8LSBsbShsb2coeSkgfiBsb2coeCksIGRmKQ0Kc3VtbWFyeShtNCkgDQpgYGANCg0KTGV0J3MgY29uc2lkZXIgdGhlIHJlc2lkdWFsIHBsb3QuIE5vdGUgdGhhdCB0aGVzZSBhcmUgcmVzaWR1YWxzIG9mIGxuKFkpLCBhbmQgbm90IFkuIA0KDQpgYGB7cn0NCnBsb3QobTQkcmVzaWR1YWxzIH4gZGYkeCwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iLCANCiAgICAgeGxhYj0ieCIsIHlsYWI9IlJlc2lkdWFscyIsIG1haW49IlJlc2lkdWFsIFBsb3QiKQ0KDQphYmxpbmUoaD0wLCBjb2w9ImRhcmtyZWQiLCBsd2Q9MikNCmBgYA0KDQpUaGVyZSBpcyBubyBhcHBhcmVudCBoZXRlcm9za2VkYXN0aWNpdHkgb3IgdHJlbmQgaW4gdGhpcyByZXNpZHVhbCBwbG90LiAgDQoNCg0KV2Ugbm93IGFzc2VzcyB0aGUgbm9ybWFsaXR5IG9mIHRoZSByZXNpZHVhbHMgd2l0aCBhIGhpc3RvZ3JhbSBhbmQgYSBRUS1wbG90Lg0KDQpgYGB7cn0NCnJlczQgPC0gbTQkcmVzaWR1YWxzDQpwYXIobWZyb3c9YygxLDIpKQ0KaGlzdChyZXM0LCBjb2w9J29yY2hpZCcpDQpxcW5vcm0ocmVzNCkNCnFxbGluZShyZXM0KQ0KcGFyKG1mcm93PWMoMSwxKSkNCmBgYA0KDQpUaGVzZSBwbG90cyBzdWdnZXN0IHRoYXQgdGhlIHJlc2lkdWFscyB3ZXJlIHBlcmhhcHMgZHJhd24gZnJvbSBhIHNsaWdodGx5IGhlYXZ5LXRhaWxlZCBkaXN0cmlidXRpb24uIA0KIA0KDQoNCldlIHdpbGwgYWRkIHRoZSBmaXR0ZWQgY3VydmUgYW5kICB0byB0aGUgc2NhdHRlciBwbG90IG9mIGxuKHkpIGFnYWluc3QgeS4gDQoNCg0KDQpgYGB7cn0NCnBsb3QobG9nKHkpIH4gbG9nKHgpLCBkZiwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iKQ0KDQpwNCA8LSBwcmVkaWN0KG00LCBuZXdkYXRhPWRhdGEuZnJhbWUoeD1wdG4pLCBpbnRlcnZhbD0icHJlZGljdGlvbiIsIGxldmVsPTAuOTUpDQpsaW5lcyhsb2cocHRuKSwgcDRbLCJmaXQiXSwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpsaW5lcyhsb2cocHRuKSwgcDRbLCJsd3IiXSwgY29sPSJkYXJrb3JhbmdlIiwgbHdkPTIpDQpsaW5lcyhsb2cocHRuKSwgcDRbLCJ1cHIiXSwgY29sPSJkYXJrb3JhbmdlIiwgbHdkPTIpDQpgYGANCg0KV2UgY2FuIGV4cG9uZW50aWF0ZSB0aGUgdmFsdWVzIG9mIGxvZyhZKSB0byB0cmFuc2Zvcm0gYmFjayB0byBiZSBpbiB0ZXJtcyBvZiBZLiANCg0KYGBge3J9DQpwbG90KHkgfiB4LCBkZiwgcGNoPTIxLCBjb2w9ImJsYWNrIiwgYmc9ImN5YW4iKQ0KDQpwNCA8LSBwcmVkaWN0KG00LCBuZXdkYXRhPWRhdGEuZnJhbWUoeD1wdG4pLCBpbnRlcnZhbD0icHJlZGljdGlvbiIsIGxldmVsPTAuOTUpDQpsaW5lcyhwdG4sIGV4cChwNFssImZpdCJdKSwgY29sPSJkYXJrcmVkIiwgbHdkPTIpDQpsaW5lcyhwdG4sIGV4cChwNFssImx3ciJdKSwgY29sPSJkYXJrb3JhbmdlIiwgbHdkPTIpDQpsaW5lcyhwdG4sIGV4cChwNFssInVwciJdKSwgY29sPSJkYXJrb3JhbmdlIiwgbHdkPTIpDQpgYGANCg0KDQojIEdlbmVyYXRpbmcgUHJlZGljdGlvbnMgd2l0aCB0aGUgVHJhbnNmb3JtZWQgTW9kZWwgDQoNCldoZW4gdXNpbmcgdGhpcyBtb2RlbCB0byBjcmVhdGUgcHJlZGljdGlvbnMgZm9yIFksIHdlIG5lZWQgdG8gZmlyc3QgZ2VuZXJhdGUgYSBwcmVkaWN0aW9uIGZvciBsbihZKSwgYW5kIHRoZW4gZXhwb25lbnRpYXRlLiBMZXQncyBjb25zdHJ1Y3QgYSA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbCBmb3IgWSB3aGVuIFggPSA2LjUuDQoNCg0KYGBge3J9DQpsbl95aGF0ID0gcHJlZGljdChtNCwgZGF0YS5mcmFtZSh4PWMoNi41KSksIGludGVydmFsPSJwcmVkaWN0aW9uIiwgbGV2ZWw9MC45NSkNCnloYXQgPSBleHAobG5feWhhdCkNCnloYXQNCmBgYA0KDQpOb3RlIHRoYXQgd2UgY2Fubm90IGRpcmVjdGx5IGNvbXBhcmUgcl4yIHZhbHVlcyBmb3IgbGluZWFyIGFuZCBsb2ctbGluZWFyIG1vZGVscy4gV2UgY2FuIGRpcmVjdGx5IGNvbXBhcmUgU1NFIHZhbHVlcyAoYXNzdW1pbmcgd2UgdHJhbnNmb3JtIGV2ZXJ5dGhpbmcgYmFjayB0byBZKSwgYnV0IHdlIHNob3VsZG4ndCB1c2UgU1NFIGV4Y2x1c2l2ZWx5IHRvIGRldGVybWluZSB3aGljaCBtb2RlbCB0byB1c2UuIA0KDQoNCmBgYHtyfQ0KIyBMaW5lYXINCnN1bSgobTEkcmVzaWR1YWxzKV4yKQ0Kc3VtKChkZiR5IC0gbTEkZml0dGVkLnZhbHVlcyleMikNCmBgYA0KDQoNCmBgYHtyfQ0KIyBFeHBvbmVudGlhbA0Kc3VtKChtMiRyZXNpZHVhbHMpXjIpICAgDQpgYGANCg0KDQpgYGB7cn0NCiMgTG9nLUxpbmVhcg0Kc3VtKChkZiR5IC0gZXhwKG0zJGZpdHRlZC52YWx1ZXMpKV4yKSAgDQpgYGANCg0KDQpgYGB7cn0NCiMgTG9nLUxvZw0Kc3VtKChkZiR5IC0gZXhwKG00JGZpdHRlZC52YWx1ZXMpKV4yKSAgDQpgYGANCg0KDQoNCg0K