Introduction to Multiple Regression

Indian systolic blood pressure example

# filename
fn.data <- "http://statacumen.com/teach/ADA2/ADA2_notes_Ch02_indian.dat"
indian <- read.table(fn.data, header=TRUE)

# Create the "fraction of their life" variable
# yrage = years since migration divided by age
indian$yrage <- indian$yrmig / indian$age
# continuous color for wt
# ggplot: Plot the data with linear regression fit and confidence bands
library(ggplot2)
p <- ggplot(indian, aes(x = yrage, y = sysbp, label = id))
p <- p + geom_point(aes(colour=wt), size=2)
# plot labels next to points
p <- p + geom_text(hjust = 0.5, vjust = -0.5, alpha = 0.25, colour = 2)
# plot regression line and confidence band
p <- p + geom_smooth(method = lm)
p <- p + labs(title="Indian sysbp by yrage with continuous wt")
print(p)
# categorical color for wt
indian$wtcat <- rep(NA, nrow(indian))
indian$wtcat <- "M" # init as medium
indian$wtcat[(indian$wt < 60)] <- "L" # update low
indian$wtcat[(indian$wt >= 70)] <- "H" # update high
# define as a factor variable with a specific order
indian$wtcat <- ordered(indian$wtcat, levels=c("L", "M", "H"))
#
library(ggplot2)
p <- ggplot(indian, aes(x = yrage, y = sysbp, label = id))
p <- p + geom_point(aes(colour=wtcat, shape=wtcat), size=2)
library(R.oo) # for ascii code lookup
p <- p + scale_shape_manual(values=charToInt(sort(unique(indian$wtcat))))
# plot regression line and confidence band
p <- p + geom_smooth(method = lm)
p <- p + labs(title="Indian sysbp by yrage with categorical wt")
print(p)
# fit the simple linear regression model
lm.sysbp.yrage <- lm(sysbp ~ yrage, data = indian)
# use Anova() from library(car) to get ANOVA table (Type 3 SS, df)
library(car)
Anova(lm.sysbp.yrage, type=3)
# fit the multiple linear regression model, (" + wt" added)
lm.sysbp.yrage.wt <- lm(sysbp ~ yrage + wt, data = indian)
library(car)
Anova(lm.sysbp.yrage.wt, type=3)
summary(lm.sysbp.yrage.wt)

GCE exam score example

#### Example: GCE
fn.data <- "http://statacumen.com/teach/ADA2/ADA2_notes_Ch02_gce.dat"
gce <- read.table(fn.data, header=TRUE)

library(ggplot2)
#suppressMessages(suppressWarnings(library(GGally)))
library(GGally)
#p <- ggpairs(gce)
# put scatterplots on top so y axis is vertical
p <- ggpairs(gce, upper = list(continuous = "points"), 
             lower = list(continuous = "cor"))
print(p)

# correlation matrix and associated p-values testing "H0: rho == 0"
library(Hmisc)
rcorr(as.matrix(gce))
# y ~ x1
lm.y.x1 <- lm(y ~ x1, data = gce)
library(car)
Anova(lm.y.x1, type=3)
summary(lm.y.x1)
# plot diagnistics
par(mfrow=c(2,3))
plot(lm.y.x1, which = c(1,4,6))
plot(gce$x1, lm.y.x1$residuals, main="Residuals vs x1")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.y.x1$residuals, las = 1, id.n = 3, main="QQ Plot")
# residuals vs order of data
plot(lm.y.x1$residuals, main="Residuals vs Order of data")
# horizontal line at zero
abline(h = 0, col = "gray75")
# y ~ x2
lm.y.x2 <- lm(y ~ x2, data = gce)
library(car)
Anova(lm.y.x2, type=3)
summary(lm.y.x2)

# plot diagnistics
par(mfrow=c(2,3))
plot(lm.y.x2, which = c(1,4,6))
plot(gce$x2, lm.y.x2$residuals, main="Residuals vs x2")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.y.x2$residuals, las = 1, id.n = 3, main="QQ Plot")
# residuals vs order of data
plot(lm.y.x2$residuals, main="Residuals vs Order of data")
# horizontal line at zero
abline(h = 0, col = "gray75")
# y ~ x1 + x2
lm.y.x1.x2 <- lm(y ~ x1 + x2, data = gce)
library(car)
Anova(lm.y.x1.x2, type=3)
summary(lm.y.x1.x2)

# plot diagnistics
par(mfrow=c(2,3))
plot(lm.y.x1.x2, which = c(1,4,6))
plot(gce$x1, lm.y.x1.x2$residuals, main="Residuals vs x1")
# horizontal line at zero
abline(h = 0, col = "gray75")
plot(gce$x2, lm.y.x1.x2$residuals, main="Residuals vs x2")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.y.x1.x2$residuals, las = 1, id.n = 3, main="QQ Plot")

Yes, we’ve seen that X1 may be used to predict Y , and that X2 does not explain significantly more variability in the model with X1

The partial regression residual plot, or added variable plot, is a graphical tool that provides information about the need for transformations in a multiple regression model.

library(car)
avPlots(lm.y.x1.x2, id.n=3)
# function to create partial regression plot
partial.regression.plot <- function (y, x, sel, ...) {
  m <- as.matrix(x[, -sel])
  # residuals of y regressed on all x's except "sel"
  y1 <- lm(y ~ m)$res
  # residuals of x regressed on all other x's
  x1 <- lm(x[, sel] ~ m)$res
  # plot residuals of y vs residuals of x
  plot( y1 ~ x1, main="Partial regression plot", ylab="y | others", ...)
  # add grid
  grid(lty = "solid")
  # add red regression line
  abline(lm(y1 ~ x1), col = "red", lwd = 2)
}

par(mfrow=c(1, 2))
partial.regression.plot(gce$y, cbind(gce$x1, gce$x2), 1, xlab="x1 | others")
partial.regression.plot(gce$y, cbind(gce$x1, gce$x2), 2, xlab="x2 | others")
gce10 <- gce[-10,]
# y ~ x1 + x2
lm.y10.x1.x2 <- lm(y ~ x1 + x2, data = gce10)
library(car)
Anova(lm.y10.x1.x2, type=3)
summary(lm.y10.x1.x2)

# plot diagnistics
par(mfrow=c(2,3))
plot(lm.y10.x1.x2, which = c(1,4,6))
plot(gce10$x1, lm.y10.x1.x2$residuals, main="Residuals vs x1")
# horizontal line at zero
abline(h = 0, col = "gray75")
plot(gce10$x2, lm.y10.x1.x2$residuals, main="Residuals vs x2")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.y10.x1.x2$residuals, las = 1, id.n = 3, main="QQ Plot")

A Taste of Model Selection for Multiple Regression

Backward Elimination

Maximum likelihood and AIC/BIC

  • AIC = -2ln(L) + 2k
  • BIC = -2ln(L) + kln(n)

Example: Peru Indian blood pressure

# filename
fn.data <- "http://statacumen.com/teach/ADA2/ADA2_notes_Ch02_indian.dat"
indian <- read.table(fn.data, header=TRUE)
# Create the "fraction of their life" variable
# yrage = years since migration divided by age
indian$yrage <- indian$yrmig / indian$age
# subset of variables we want in our model
indian2 <- subset(indian, select=c("sysbp", "wt", "ht", "chin"
                                   , "fore", "calf", "pulse", "yrage"))
library(ggplot2)
#suppressMessages(suppressWarnings(library(GGally)))
library(GGally)
#p <- ggpairs(indian2)
# put scatterplots on top so y axis is vertical
p <- ggpairs(indian2, upper = list(continuous = "points")
             , lower = list(continuous = "cor"))
print(p)

# correlation matrix and associated p-values testing "H0: rho == 0"
library(Hmisc)
rcorr(as.matrix(indian2))
# fit full model
lm.indian2.full <- lm(sysbp ~ wt + ht + chin + fore + calf + pulse + yrage, data = indian2)
library(car)
Anova(lm.indian2.full, type=3)
summary(lm.indian2.full)
# model reduction using update() and subtracting (removing) model terms
lm.indian2.red <- lm.indian2.full;
# remove calf
lm.indian2.red <- update(lm.indian2.red, ~ . - calf ); summary(lm.indian2.red);
# remove pulse
lm.indian2.red <- update(lm.indian2.red, ~ . - pulse); summary(lm.indian2.red);
# remove fore
lm.indian2.red <- update(lm.indian2.red, ~ . - fore ); summary(lm.indian2.red);
# remove ht
lm.indian2.red <- update(lm.indian2.red, ~ . - ht ); summary(lm.indian2.red);
# remove chin
lm.indian2.red <- update(lm.indian2.red, ~ . - chin ); summary(lm.indian2.red);
# all are significant, stop.
# final model: sysbp ~ wt + yrage
lm.indian2.final <- lm.indian2.red
## AIC
# option: test="F" includes additional information
# for parameter estimate tests that we're familiar with
# option: for BIC, include k=log(nrow( [data.frame name] ))
lm.indian2.red.AIC <- step(lm.indian2.full, direction="backward", test="F")
# BIC (not shown)
# step(lm.indian2.full, direction="backward", test="F", k=log(nrow(indian2)))
library(car)
Anova(lm.indian2.final, type=3)
summary(lm.indian2.final)
# plot diagnistics
par(mfrow=c(2,3))
plot(lm.indian2.final, which = c(1,4,6))
plot(indian2$wt, lm.indian2.final$residuals, main="Residuals vs wt")
# horizontal line at zero
abline(h = 0, col = "gray75")
plot(indian2$yrage, lm.indian2.final$residuals, main="Residuals vs yrage")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.indian2.final$residuals, las = 1, id.n = 3, main="QQ Plot")

library(car)
avPlots(lm.indian2.final, id.n=3)

Example: Dennis Cook’s Rat Data

#### Example: Rat liver
fn.data <- "http://statacumen.com/teach/ADA2/ADA2_notes_Ch03_ratliver.csv"
ratliver <- read.csv(fn.data)
ratliver <- ratliver[,c(4,1,2,3)] # reorder columns so response is the first

library(ggplot2)
#suppressMessages(suppressWarnings(library(GGally)))
library(GGally)
#p <- ggpairs(ratliver)
# put scatterplots on top so y axis is vertical
p <- ggpairs(ratliver, upper = list(continuous = "points"), lower = list(continuous = "cor"))
print(p)

# correlation matrix and associated p-values testing "H0: rho == 0"
library(Hmisc)
rcorr(as.matrix(ratliver))
# fit full model
lm.ratliver.full <- lm(y ~ bodywt + liverwt + dose, data = ratliver)
library(car)
Anova(lm.ratliver.full, type=3)
summary(lm.ratliver.full)

lm.ratliver.red.AIC <- step(lm.ratliver.full, direction="backward", test="F")
lm.ratliver.final <- lm.ratliver.red.AIC

# plot diagnistics
par(mfrow=c(2,3))
plot(lm.ratliver.final, which = c(1,4,6))
plot(ratliver$bodywt, lm.ratliver.final$residuals, main="Residuals vs bodywt")
# horizontal line at zero
abline(h = 0, col = "gray75")
plot(ratliver$dose, lm.ratliver.final$residuals, main="Residuals vs dose")
# horizontal line at zero
abline(h = 0, col = "gray75")
# Normality of Residuals
library(car)
qqPlot(lm.ratliver.final$residuals, las = 1, id.n = 3, main="QQ Plot")

library(car)
avPlots(lm.ratliver.final, id.n=3)
# remove case 3
ratliver3 <- ratliver[-3,]
# fit full model
lm.ratliver3.full <- lm(y ~ bodywt + liverwt + dose, data = ratliver3)
lm.ratliver3.red.AIC <- step(lm.ratliver3.full, direction="backward", test="F")

All varialbles are omitted!

# ggplot: Plot the data with linear regression fit and confidence bands
library(ggplot2)
p <- ggplot(ratliver, aes(x = bodywt, y = dose, label = 1:nrow(ratliver)))
# plot regression line and confidence band
p <- p + geom_smooth(method = lm)
p <- p + geom_point(alpha=1/3)
# plot labels next to points
p <- p + geom_text(hjust = 0.5, vjust = -0.5, alpha = 0.25, colour = 2)
p <- p + labs(title="Rat liver dose by bodywt: rat 3 overdosed")
print(p)
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIG11bHRpcGxlIHJlZ3Jlc3Npb24gYW5kIG1vZGVsIHNlbGVjdGlvbiIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCi0tLQoKIyMgSW50cm9kdWN0aW9uIHRvIE11bHRpcGxlIFJlZ3Jlc3Npb24KIyMjIEluZGlhbiBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBleGFtcGxlCmBgYHtyfQojIGZpbGVuYW1lCmZuLmRhdGEgPC0gImh0dHA6Ly9zdGF0YWN1bWVuLmNvbS90ZWFjaC9BREEyL0FEQTJfbm90ZXNfQ2gwMl9pbmRpYW4uZGF0IgppbmRpYW4gPC0gcmVhZC50YWJsZShmbi5kYXRhLCBoZWFkZXI9VFJVRSkKCiMgQ3JlYXRlIHRoZSAiZnJhY3Rpb24gb2YgdGhlaXIgbGlmZSIgdmFyaWFibGUKIyB5cmFnZSA9IHllYXJzIHNpbmNlIG1pZ3JhdGlvbiBkaXZpZGVkIGJ5IGFnZQppbmRpYW4keXJhZ2UgPC0gaW5kaWFuJHlybWlnIC8gaW5kaWFuJGFnZQojIGNvbnRpbnVvdXMgY29sb3IgZm9yIHd0CiMgZ2dwbG90OiBQbG90IHRoZSBkYXRhIHdpdGggbGluZWFyIHJlZ3Jlc3Npb24gZml0IGFuZCBjb25maWRlbmNlIGJhbmRzCmxpYnJhcnkoZ2dwbG90MikKcCA8LSBnZ3Bsb3QoaW5kaWFuLCBhZXMoeCA9IHlyYWdlLCB5ID0gc3lzYnAsIGxhYmVsID0gaWQpKQpwIDwtIHAgKyBnZW9tX3BvaW50KGFlcyhjb2xvdXI9d3QpLCBzaXplPTIpCiMgcGxvdCBsYWJlbHMgbmV4dCB0byBwb2ludHMKcCA8LSBwICsgZ2VvbV90ZXh0KGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjUsIGFscGhhID0gMC4yNSwgY29sb3VyID0gMikKIyBwbG90IHJlZ3Jlc3Npb24gbGluZSBhbmQgY29uZmlkZW5jZSBiYW5kCnAgPC0gcCArIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtKQpwIDwtIHAgKyBsYWJzKHRpdGxlPSJJbmRpYW4gc3lzYnAgYnkgeXJhZ2Ugd2l0aCBjb250aW51b3VzIHd0IikKcHJpbnQocCkKIyBjYXRlZ29yaWNhbCBjb2xvciBmb3Igd3QKaW5kaWFuJHd0Y2F0IDwtIHJlcChOQSwgbnJvdyhpbmRpYW4pKQppbmRpYW4kd3RjYXQgPC0gIk0iICMgaW5pdCBhcyBtZWRpdW0KaW5kaWFuJHd0Y2F0WyhpbmRpYW4kd3QgPCA2MCldIDwtICJMIiAjIHVwZGF0ZSBsb3cKaW5kaWFuJHd0Y2F0WyhpbmRpYW4kd3QgPj0gNzApXSA8LSAiSCIgIyB1cGRhdGUgaGlnaAojIGRlZmluZSBhcyBhIGZhY3RvciB2YXJpYWJsZSB3aXRoIGEgc3BlY2lmaWMgb3JkZXIKaW5kaWFuJHd0Y2F0IDwtIG9yZGVyZWQoaW5kaWFuJHd0Y2F0LCBsZXZlbHM9YygiTCIsICJNIiwgIkgiKSkKIwpsaWJyYXJ5KGdncGxvdDIpCnAgPC0gZ2dwbG90KGluZGlhbiwgYWVzKHggPSB5cmFnZSwgeSA9IHN5c2JwLCBsYWJlbCA9IGlkKSkKcCA8LSBwICsgZ2VvbV9wb2ludChhZXMoY29sb3VyPXd0Y2F0LCBzaGFwZT13dGNhdCksIHNpemU9MikKbGlicmFyeShSLm9vKSAjIGZvciBhc2NpaSBjb2RlIGxvb2t1cApwIDwtIHAgKyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWNoYXJUb0ludChzb3J0KHVuaXF1ZShpbmRpYW4kd3RjYXQpKSkpCiMgcGxvdCByZWdyZXNzaW9uIGxpbmUgYW5kIGNvbmZpZGVuY2UgYmFuZApwIDwtIHAgKyBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkKcCA8LSBwICsgbGFicyh0aXRsZT0iSW5kaWFuIHN5c2JwIGJ5IHlyYWdlIHdpdGggY2F0ZWdvcmljYWwgd3QiKQpwcmludChwKQpgYGAKCmBgYHtyfQojIGZpdCB0aGUgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsCmxtLnN5c2JwLnlyYWdlIDwtIGxtKHN5c2JwIH4geXJhZ2UsIGRhdGEgPSBpbmRpYW4pCiMgdXNlIEFub3ZhKCkgZnJvbSBsaWJyYXJ5KGNhcikgdG8gZ2V0IEFOT1ZBIHRhYmxlIChUeXBlIDMgU1MsIGRmKQpsaWJyYXJ5KGNhcikKQW5vdmEobG0uc3lzYnAueXJhZ2UsIHR5cGU9MykKYGBgCgpgYGB7cn0KIyBmaXQgdGhlIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLCAoIiArIHd0IiBhZGRlZCkKbG0uc3lzYnAueXJhZ2Uud3QgPC0gbG0oc3lzYnAgfiB5cmFnZSArIHd0LCBkYXRhID0gaW5kaWFuKQpsaWJyYXJ5KGNhcikKQW5vdmEobG0uc3lzYnAueXJhZ2Uud3QsIHR5cGU9MykKc3VtbWFyeShsbS5zeXNicC55cmFnZS53dCkKYGBgCgojIyMgR0NFIGV4YW0gc2NvcmUgZXhhbXBsZQpgYGB7cn0KIyMjIyBFeGFtcGxlOiBHQ0UKZm4uZGF0YSA8LSAiaHR0cDovL3N0YXRhY3VtZW4uY29tL3RlYWNoL0FEQTIvQURBMl9ub3Rlc19DaDAyX2djZS5kYXQiCmdjZSA8LSByZWFkLnRhYmxlKGZuLmRhdGEsIGhlYWRlcj1UUlVFKQoKbGlicmFyeShnZ3Bsb3QyKQojc3VwcHJlc3NNZXNzYWdlcyhzdXBwcmVzc1dhcm5pbmdzKGxpYnJhcnkoR0dhbGx5KSkpCmxpYnJhcnkoR0dhbGx5KQojcCA8LSBnZ3BhaXJzKGdjZSkKIyBwdXQgc2NhdHRlcnBsb3RzIG9uIHRvcCBzbyB5IGF4aXMgaXMgdmVydGljYWwKcCA8LSBnZ3BhaXJzKGdjZSwgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAicG9pbnRzIiksIAogICAgICAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAiY29yIikpCnByaW50KHApCgojIGNvcnJlbGF0aW9uIG1hdHJpeCBhbmQgYXNzb2NpYXRlZCBwLXZhbHVlcyB0ZXN0aW5nICJIMDogcmhvID09IDAiCmxpYnJhcnkoSG1pc2MpCnJjb3JyKGFzLm1hdHJpeChnY2UpKQpgYGAKCmBgYHtyfQojIHkgfiB4MQpsbS55LngxIDwtIGxtKHkgfiB4MSwgZGF0YSA9IGdjZSkKbGlicmFyeShjYXIpCkFub3ZhKGxtLnkueDEsIHR5cGU9MykKc3VtbWFyeShsbS55LngxKQojIHBsb3QgZGlhZ25pc3RpY3MKcGFyKG1mcm93PWMoMiwzKSkKcGxvdChsbS55LngxLCB3aGljaCA9IGMoMSw0LDYpKQpwbG90KGdjZSR4MSwgbG0ueS54MSRyZXNpZHVhbHMsIG1haW49IlJlc2lkdWFscyB2cyB4MSIpCiMgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JheTc1IikKIyBOb3JtYWxpdHkgb2YgUmVzaWR1YWxzCmxpYnJhcnkoY2FyKQpxcVBsb3QobG0ueS54MSRyZXNpZHVhbHMsIGxhcyA9IDEsIGlkLm4gPSAzLCBtYWluPSJRUSBQbG90IikKIyByZXNpZHVhbHMgdnMgb3JkZXIgb2YgZGF0YQpwbG90KGxtLnkueDEkcmVzaWR1YWxzLCBtYWluPSJSZXNpZHVhbHMgdnMgT3JkZXIgb2YgZGF0YSIpCiMgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JheTc1IikKYGBgCgpgYGB7cn0KIyB5IH4geDIKbG0ueS54MiA8LSBsbSh5IH4geDIsIGRhdGEgPSBnY2UpCmxpYnJhcnkoY2FyKQpBbm92YShsbS55LngyLCB0eXBlPTMpCnN1bW1hcnkobG0ueS54MikKCiMgcGxvdCBkaWFnbmlzdGljcwpwYXIobWZyb3c9YygyLDMpKQpwbG90KGxtLnkueDIsIHdoaWNoID0gYygxLDQsNikpCnBsb3QoZ2NlJHgyLCBsbS55LngyJHJlc2lkdWFscywgbWFpbj0iUmVzaWR1YWxzIHZzIHgyIikKIyBob3Jpem9udGFsIGxpbmUgYXQgemVybwphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmF5NzUiKQojIE5vcm1hbGl0eSBvZiBSZXNpZHVhbHMKbGlicmFyeShjYXIpCnFxUGxvdChsbS55LngyJHJlc2lkdWFscywgbGFzID0gMSwgaWQubiA9IDMsIG1haW49IlFRIFBsb3QiKQojIHJlc2lkdWFscyB2cyBvcmRlciBvZiBkYXRhCnBsb3QobG0ueS54MiRyZXNpZHVhbHMsIG1haW49IlJlc2lkdWFscyB2cyBPcmRlciBvZiBkYXRhIikKIyBob3Jpem9udGFsIGxpbmUgYXQgemVybwphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmF5NzUiKQpgYGAKCmBgYHtyfQojIHkgfiB4MSArIHgyCmxtLnkueDEueDIgPC0gbG0oeSB+IHgxICsgeDIsIGRhdGEgPSBnY2UpCmxpYnJhcnkoY2FyKQpBbm92YShsbS55LngxLngyLCB0eXBlPTMpCnN1bW1hcnkobG0ueS54MS54MikKCiMgcGxvdCBkaWFnbmlzdGljcwpwYXIobWZyb3c9YygyLDMpKQpwbG90KGxtLnkueDEueDIsIHdoaWNoID0gYygxLDQsNikpCnBsb3QoZ2NlJHgxLCBsbS55LngxLngyJHJlc2lkdWFscywgbWFpbj0iUmVzaWR1YWxzIHZzIHgxIikKIyBob3Jpem9udGFsIGxpbmUgYXQgemVybwphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmF5NzUiKQpwbG90KGdjZSR4MiwgbG0ueS54MS54MiRyZXNpZHVhbHMsIG1haW49IlJlc2lkdWFscyB2cyB4MiIpCiMgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JheTc1IikKIyBOb3JtYWxpdHkgb2YgUmVzaWR1YWxzCmxpYnJhcnkoY2FyKQpxcVBsb3QobG0ueS54MS54MiRyZXNpZHVhbHMsIGxhcyA9IDEsIGlkLm4gPSAzLCBtYWluPSJRUSBQbG90IikKYGBgClllcywgd2UndmUgc2VlbiB0aGF0IFgxIG1heSBiZSB1c2VkIHRvIHByZWRpY3QgWSAsIGFuZCB0aGF0IFgyIGRvZXMgbm90IGV4cGxhaW4gc2lnbmlmaWNhbnRseSBtb3JlIHZhcmlhYmlsaXR5IGluIHRoZSBtb2RlbCB3aXRoIFgxCgoqKlRoZSBwYXJ0aWFsIHJlZ3Jlc3Npb24gcmVzaWR1YWwgcGxvdCoqLCBvciAqKmFkZGVkIHZhcmlhYmxlIHBsb3QqKiwgaXMgYSBncmFwaGljYWwgdG9vbCB0aGF0IHByb3ZpZGVzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBuZWVkIGZvciB0cmFuc2Zvcm1hdGlvbnMgaW4gYSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsLgpgYGB7cn0KbGlicmFyeShjYXIpCmF2UGxvdHMobG0ueS54MS54MiwgaWQubj0zKQpgYGAKYGBge3J9CiMgZnVuY3Rpb24gdG8gY3JlYXRlIHBhcnRpYWwgcmVncmVzc2lvbiBwbG90CnBhcnRpYWwucmVncmVzc2lvbi5wbG90IDwtIGZ1bmN0aW9uICh5LCB4LCBzZWwsIC4uLikgewogIG0gPC0gYXMubWF0cml4KHhbLCAtc2VsXSkKICAjIHJlc2lkdWFscyBvZiB5IHJlZ3Jlc3NlZCBvbiBhbGwgeCdzIGV4Y2VwdCAic2VsIgogIHkxIDwtIGxtKHkgfiBtKSRyZXMKICAjIHJlc2lkdWFscyBvZiB4IHJlZ3Jlc3NlZCBvbiBhbGwgb3RoZXIgeCdzCiAgeDEgPC0gbG0oeFssIHNlbF0gfiBtKSRyZXMKICAjIHBsb3QgcmVzaWR1YWxzIG9mIHkgdnMgcmVzaWR1YWxzIG9mIHgKICBwbG90KCB5MSB+IHgxLCBtYWluPSJQYXJ0aWFsIHJlZ3Jlc3Npb24gcGxvdCIsIHlsYWI9InkgfCBvdGhlcnMiLCAuLi4pCiAgIyBhZGQgZ3JpZAogIGdyaWQobHR5ID0gInNvbGlkIikKICAjIGFkZCByZWQgcmVncmVzc2lvbiBsaW5lCiAgYWJsaW5lKGxtKHkxIH4geDEpLCBjb2wgPSAicmVkIiwgbHdkID0gMikKfQoKcGFyKG1mcm93PWMoMSwgMikpCnBhcnRpYWwucmVncmVzc2lvbi5wbG90KGdjZSR5LCBjYmluZChnY2UkeDEsIGdjZSR4MiksIDEsIHhsYWI9IngxIHwgb3RoZXJzIikKcGFydGlhbC5yZWdyZXNzaW9uLnBsb3QoZ2NlJHksIGNiaW5kKGdjZSR4MSwgZ2NlJHgyKSwgMiwgeGxhYj0ieDIgfCBvdGhlcnMiKQpgYGAKCmBgYHtyfQpnY2UxMCA8LSBnY2VbLTEwLF0KIyB5IH4geDEgKyB4MgpsbS55MTAueDEueDIgPC0gbG0oeSB+IHgxICsgeDIsIGRhdGEgPSBnY2UxMCkKbGlicmFyeShjYXIpCkFub3ZhKGxtLnkxMC54MS54MiwgdHlwZT0zKQpzdW1tYXJ5KGxtLnkxMC54MS54MikKCiMgcGxvdCBkaWFnbmlzdGljcwpwYXIobWZyb3c9YygyLDMpKQpwbG90KGxtLnkxMC54MS54Miwgd2hpY2ggPSBjKDEsNCw2KSkKcGxvdChnY2UxMCR4MSwgbG0ueTEwLngxLngyJHJlc2lkdWFscywgbWFpbj0iUmVzaWR1YWxzIHZzIHgxIikKIyBob3Jpem9udGFsIGxpbmUgYXQgemVybwphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmF5NzUiKQpwbG90KGdjZTEwJHgyLCBsbS55MTAueDEueDIkcmVzaWR1YWxzLCBtYWluPSJSZXNpZHVhbHMgdnMgeDIiKQojIGhvcml6b250YWwgbGluZSBhdCB6ZXJvCmFibGluZShoID0gMCwgY29sID0gImdyYXk3NSIpCiMgTm9ybWFsaXR5IG9mIFJlc2lkdWFscwpsaWJyYXJ5KGNhcikKcXFQbG90KGxtLnkxMC54MS54MiRyZXNpZHVhbHMsIGxhcyA9IDEsIGlkLm4gPSAzLCBtYWluPSJRUSBQbG90IikKYGBgCgojIyBBIFRhc3RlIG9mIE1vZGVsIFNlbGVjdGlvbiBmb3IgTXVsdGlwbGUgUmVncmVzc2lvbgojIyMgQmFja3dhcmQgRWxpbWluYXRpb24KKipNYXhpbXVtIGxpa2VsaWhvb2QgYW5kIEFJQy9CSUMqKgoKKiBBSUMgPSAtMmxuKEwpICsgMmsKKiBCSUMgPSAtMmxuKEwpICsga2xuKG4pCgoqKkV4YW1wbGU6IFBlcnUgSW5kaWFuIGJsb29kIHByZXNzdXJlKioKYGBge3J9CiMgZmlsZW5hbWUKZm4uZGF0YSA8LSAiaHR0cDovL3N0YXRhY3VtZW4uY29tL3RlYWNoL0FEQTIvQURBMl9ub3Rlc19DaDAyX2luZGlhbi5kYXQiCmluZGlhbiA8LSByZWFkLnRhYmxlKGZuLmRhdGEsIGhlYWRlcj1UUlVFKQojIENyZWF0ZSB0aGUgImZyYWN0aW9uIG9mIHRoZWlyIGxpZmUiIHZhcmlhYmxlCiMgeXJhZ2UgPSB5ZWFycyBzaW5jZSBtaWdyYXRpb24gZGl2aWRlZCBieSBhZ2UKaW5kaWFuJHlyYWdlIDwtIGluZGlhbiR5cm1pZyAvIGluZGlhbiRhZ2UKIyBzdWJzZXQgb2YgdmFyaWFibGVzIHdlIHdhbnQgaW4gb3VyIG1vZGVsCmluZGlhbjIgPC0gc3Vic2V0KGluZGlhbiwgc2VsZWN0PWMoInN5c2JwIiwgInd0IiwgImh0IiwgImNoaW4iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAiZm9yZSIsICJjYWxmIiwgInB1bHNlIiwgInlyYWdlIikpCmxpYnJhcnkoZ2dwbG90MikKI3N1cHByZXNzTWVzc2FnZXMoc3VwcHJlc3NXYXJuaW5ncyhsaWJyYXJ5KEdHYWxseSkpKQpsaWJyYXJ5KEdHYWxseSkKI3AgPC0gZ2dwYWlycyhpbmRpYW4yKQojIHB1dCBzY2F0dGVycGxvdHMgb24gdG9wIHNvIHkgYXhpcyBpcyB2ZXJ0aWNhbApwIDwtIGdncGFpcnMoaW5kaWFuMiwgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAicG9pbnRzIikKICAgICAgICAgICAgICwgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAiY29yIikpCnByaW50KHApCgojIGNvcnJlbGF0aW9uIG1hdHJpeCBhbmQgYXNzb2NpYXRlZCBwLXZhbHVlcyB0ZXN0aW5nICJIMDogcmhvID09IDAiCmxpYnJhcnkoSG1pc2MpCnJjb3JyKGFzLm1hdHJpeChpbmRpYW4yKSkKYGBgCgpgYGB7cn0KIyBmaXQgZnVsbCBtb2RlbApsbS5pbmRpYW4yLmZ1bGwgPC0gbG0oc3lzYnAgfiB3dCArIGh0ICsgY2hpbiArIGZvcmUgKyBjYWxmICsgcHVsc2UgKyB5cmFnZSwgZGF0YSA9IGluZGlhbjIpCmxpYnJhcnkoY2FyKQpBbm92YShsbS5pbmRpYW4yLmZ1bGwsIHR5cGU9MykKc3VtbWFyeShsbS5pbmRpYW4yLmZ1bGwpCmBgYApgYGB7cn0KIyBtb2RlbCByZWR1Y3Rpb24gdXNpbmcgdXBkYXRlKCkgYW5kIHN1YnRyYWN0aW5nIChyZW1vdmluZykgbW9kZWwgdGVybXMKbG0uaW5kaWFuMi5yZWQgPC0gbG0uaW5kaWFuMi5mdWxsOwojIHJlbW92ZSBjYWxmCmxtLmluZGlhbjIucmVkIDwtIHVwZGF0ZShsbS5pbmRpYW4yLnJlZCwgfiAuIC0gY2FsZiApOyBzdW1tYXJ5KGxtLmluZGlhbjIucmVkKTsKIyByZW1vdmUgcHVsc2UKbG0uaW5kaWFuMi5yZWQgPC0gdXBkYXRlKGxtLmluZGlhbjIucmVkLCB+IC4gLSBwdWxzZSk7IHN1bW1hcnkobG0uaW5kaWFuMi5yZWQpOwojIHJlbW92ZSBmb3JlCmxtLmluZGlhbjIucmVkIDwtIHVwZGF0ZShsbS5pbmRpYW4yLnJlZCwgfiAuIC0gZm9yZSApOyBzdW1tYXJ5KGxtLmluZGlhbjIucmVkKTsKIyByZW1vdmUgaHQKbG0uaW5kaWFuMi5yZWQgPC0gdXBkYXRlKGxtLmluZGlhbjIucmVkLCB+IC4gLSBodCApOyBzdW1tYXJ5KGxtLmluZGlhbjIucmVkKTsKIyByZW1vdmUgY2hpbgpsbS5pbmRpYW4yLnJlZCA8LSB1cGRhdGUobG0uaW5kaWFuMi5yZWQsIH4gLiAtIGNoaW4gKTsgc3VtbWFyeShsbS5pbmRpYW4yLnJlZCk7CiMgYWxsIGFyZSBzaWduaWZpY2FudCwgc3RvcC4KIyBmaW5hbCBtb2RlbDogc3lzYnAgfiB3dCArIHlyYWdlCmxtLmluZGlhbjIuZmluYWwgPC0gbG0uaW5kaWFuMi5yZWQKYGBgCmBgYHtyfQojIyBBSUMKIyBvcHRpb246IHRlc3Q9IkYiIGluY2x1ZGVzIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24KIyBmb3IgcGFyYW1ldGVyIGVzdGltYXRlIHRlc3RzIHRoYXQgd2UncmUgZmFtaWxpYXIgd2l0aAojIG9wdGlvbjogZm9yIEJJQywgaW5jbHVkZSBrPWxvZyhucm93KCBbZGF0YS5mcmFtZSBuYW1lXSApKQpsbS5pbmRpYW4yLnJlZC5BSUMgPC0gc3RlcChsbS5pbmRpYW4yLmZ1bGwsIGRpcmVjdGlvbj0iYmFja3dhcmQiLCB0ZXN0PSJGIikKIyBCSUMgKG5vdCBzaG93bikKIyBzdGVwKGxtLmluZGlhbjIuZnVsbCwgZGlyZWN0aW9uPSJiYWNrd2FyZCIsIHRlc3Q9IkYiLCBrPWxvZyhucm93KGluZGlhbjIpKSkKYGBgCmBgYHtyfQpsaWJyYXJ5KGNhcikKQW5vdmEobG0uaW5kaWFuMi5maW5hbCwgdHlwZT0zKQpzdW1tYXJ5KGxtLmluZGlhbjIuZmluYWwpCiMgcGxvdCBkaWFnbmlzdGljcwpwYXIobWZyb3c9YygyLDMpKQpwbG90KGxtLmluZGlhbjIuZmluYWwsIHdoaWNoID0gYygxLDQsNikpCnBsb3QoaW5kaWFuMiR3dCwgbG0uaW5kaWFuMi5maW5hbCRyZXNpZHVhbHMsIG1haW49IlJlc2lkdWFscyB2cyB3dCIpCiMgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JheTc1IikKcGxvdChpbmRpYW4yJHlyYWdlLCBsbS5pbmRpYW4yLmZpbmFsJHJlc2lkdWFscywgbWFpbj0iUmVzaWR1YWxzIHZzIHlyYWdlIikKIyBob3Jpem9udGFsIGxpbmUgYXQgemVybwphYmxpbmUoaCA9IDAsIGNvbCA9ICJncmF5NzUiKQojIE5vcm1hbGl0eSBvZiBSZXNpZHVhbHMKbGlicmFyeShjYXIpCnFxUGxvdChsbS5pbmRpYW4yLmZpbmFsJHJlc2lkdWFscywgbGFzID0gMSwgaWQubiA9IDMsIG1haW49IlFRIFBsb3QiKQoKbGlicmFyeShjYXIpCmF2UGxvdHMobG0uaW5kaWFuMi5maW5hbCwgaWQubj0zKQpgYGAKCiMjIyBFeGFtcGxlOiBEZW5uaXMgQ29vaydzIFJhdCBEYXRhCmBgYHtyfQojIyMjIEV4YW1wbGU6IFJhdCBsaXZlcgpmbi5kYXRhIDwtICJodHRwOi8vc3RhdGFjdW1lbi5jb20vdGVhY2gvQURBMi9BREEyX25vdGVzX0NoMDNfcmF0bGl2ZXIuY3N2IgpyYXRsaXZlciA8LSByZWFkLmNzdihmbi5kYXRhKQpyYXRsaXZlciA8LSByYXRsaXZlclssYyg0LDEsMiwzKV0gIyByZW9yZGVyIGNvbHVtbnMgc28gcmVzcG9uc2UgaXMgdGhlIGZpcnN0CgpsaWJyYXJ5KGdncGxvdDIpCiNzdXBwcmVzc01lc3NhZ2VzKHN1cHByZXNzV2FybmluZ3MobGlicmFyeShHR2FsbHkpKSkKbGlicmFyeShHR2FsbHkpCiNwIDwtIGdncGFpcnMocmF0bGl2ZXIpCiMgcHV0IHNjYXR0ZXJwbG90cyBvbiB0b3Agc28geSBheGlzIGlzIHZlcnRpY2FsCnAgPC0gZ2dwYWlycyhyYXRsaXZlciwgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAicG9pbnRzIiksIGxvd2VyID0gbGlzdChjb250aW51b3VzID0gImNvciIpKQpwcmludChwKQoKIyBjb3JyZWxhdGlvbiBtYXRyaXggYW5kIGFzc29jaWF0ZWQgcC12YWx1ZXMgdGVzdGluZyAiSDA6IHJobyA9PSAwIgpsaWJyYXJ5KEhtaXNjKQpyY29ycihhcy5tYXRyaXgocmF0bGl2ZXIpKQpgYGAKYGBge3J9CiMgZml0IGZ1bGwgbW9kZWwKbG0ucmF0bGl2ZXIuZnVsbCA8LSBsbSh5IH4gYm9keXd0ICsgbGl2ZXJ3dCArIGRvc2UsIGRhdGEgPSByYXRsaXZlcikKbGlicmFyeShjYXIpCkFub3ZhKGxtLnJhdGxpdmVyLmZ1bGwsIHR5cGU9MykKc3VtbWFyeShsbS5yYXRsaXZlci5mdWxsKQoKbG0ucmF0bGl2ZXIucmVkLkFJQyA8LSBzdGVwKGxtLnJhdGxpdmVyLmZ1bGwsIGRpcmVjdGlvbj0iYmFja3dhcmQiLCB0ZXN0PSJGIikKbG0ucmF0bGl2ZXIuZmluYWwgPC0gbG0ucmF0bGl2ZXIucmVkLkFJQwoKIyBwbG90IGRpYWduaXN0aWNzCnBhcihtZnJvdz1jKDIsMykpCnBsb3QobG0ucmF0bGl2ZXIuZmluYWwsIHdoaWNoID0gYygxLDQsNikpCnBsb3QocmF0bGl2ZXIkYm9keXd0LCBsbS5yYXRsaXZlci5maW5hbCRyZXNpZHVhbHMsIG1haW49IlJlc2lkdWFscyB2cyBib2R5d3QiKQojIGhvcml6b250YWwgbGluZSBhdCB6ZXJvCmFibGluZShoID0gMCwgY29sID0gImdyYXk3NSIpCnBsb3QocmF0bGl2ZXIkZG9zZSwgbG0ucmF0bGl2ZXIuZmluYWwkcmVzaWR1YWxzLCBtYWluPSJSZXNpZHVhbHMgdnMgZG9zZSIpCiMgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8KYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JheTc1IikKIyBOb3JtYWxpdHkgb2YgUmVzaWR1YWxzCmxpYnJhcnkoY2FyKQpxcVBsb3QobG0ucmF0bGl2ZXIuZmluYWwkcmVzaWR1YWxzLCBsYXMgPSAxLCBpZC5uID0gMywgbWFpbj0iUVEgUGxvdCIpCgpsaWJyYXJ5KGNhcikKYXZQbG90cyhsbS5yYXRsaXZlci5maW5hbCwgaWQubj0zKQpgYGAKYGBge3J9CiMgcmVtb3ZlIGNhc2UgMwpyYXRsaXZlcjMgPC0gcmF0bGl2ZXJbLTMsXQojIGZpdCBmdWxsIG1vZGVsCmxtLnJhdGxpdmVyMy5mdWxsIDwtIGxtKHkgfiBib2R5d3QgKyBsaXZlcnd0ICsgZG9zZSwgZGF0YSA9IHJhdGxpdmVyMykKbG0ucmF0bGl2ZXIzLnJlZC5BSUMgPC0gc3RlcChsbS5yYXRsaXZlcjMuZnVsbCwgZGlyZWN0aW9uPSJiYWNrd2FyZCIsIHRlc3Q9IkYiKQpgYGAKQWxsIHZhcmlhbGJsZXMgYXJlIG9taXR0ZWQhCmBgYHtyfQojIGdncGxvdDogUGxvdCB0aGUgZGF0YSB3aXRoIGxpbmVhciByZWdyZXNzaW9uIGZpdCBhbmQgY29uZmlkZW5jZSBiYW5kcwpsaWJyYXJ5KGdncGxvdDIpCnAgPC0gZ2dwbG90KHJhdGxpdmVyLCBhZXMoeCA9IGJvZHl3dCwgeSA9IGRvc2UsIGxhYmVsID0gMTpucm93KHJhdGxpdmVyKSkpCiMgcGxvdCByZWdyZXNzaW9uIGxpbmUgYW5kIGNvbmZpZGVuY2UgYmFuZApwIDwtIHAgKyBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkKcCA8LSBwICsgZ2VvbV9wb2ludChhbHBoYT0xLzMpCiMgcGxvdCBsYWJlbHMgbmV4dCB0byBwb2ludHMKcCA8LSBwICsgZ2VvbV90ZXh0KGhqdXN0ID0gMC41LCB2anVzdCA9IC0wLjUsIGFscGhhID0gMC4yNSwgY29sb3VyID0gMikKcCA8LSBwICsgbGFicyh0aXRsZT0iUmF0IGxpdmVyIGRvc2UgYnkgYm9keXd0OiByYXQgMyBvdmVyZG9zZWQiKQpwcmludChwKQpgYGAKCg==