pkgs <- c("tidyverse", "dplyr", "haven", "foreign", "lme4", "plyr", "nlme", "lsr", "emmeans", "afex", "knitr", "kableExtra", "QuantPsyc", "car", "readxl", "pastecs")
packages <- rownames(installed.packages())
p_to_install <- pkgs[!(pkgs %in% packages)]
if(length(p_to_install) > 0){
install.packages(p_to_install)
}
lapply(pkgs, library, character.only = TRUE)
album_df <- read.delim("Album Sales 2.dat")
A note on assumptions
Here are the 3 assumptions that apply to all parametric tests:
- Normally distributed data
- Shapiro-Wilk test: caution–it’s easy to get a significant result if
your sample is large enough
- Q-Q plot: each value is compared to the expected value. If normally
distributed, you get a diagonal line.
- Plots()
- REGRESSION
- ANOVA
- Assumption that distributions within groups are normally
distributed
- Homogeneity of variance: The variances should be
the same throughout the data.
- REGRESSION
- Homoscedasticity: inspect plot comparing residuals vs predicted
values
- ANOVA
- Levene’s or Bartlett’s test (compares variances between groups)
- Mauchly’s sphericity test (repeated measures ANOVA)
- Independence
- REGRESSION
- Durbin-Watson: residuals are correlated.
- Multicollinearity: predictors are highly correlated. Test with VIF
and/or correlation matrix
Linear Regression
Does money spent on advertising predict album sales?
Here is the dataset
we’ll be using in addition to Madalina’s dataset.
A record company wants to know if they spend $100,000 on advertising,
how many albums could they expect to sell?
- adverts: 1 unit = $1,000
- sales: albums sold
## adverts sales airplay attract
## 1 10.256 330 43 10
## 2 985.685 120 28 7
## 3 1445.563 360 35 7
## 4 1188.193 270 33 7
## 5 574.513 220 44 5
## 6 568.954 170 19 5
# Create the figure
fig <- ggplot(data = album_df, aes(x = adverts, y = sales)) +
geom_point(alpha = 0.3, color = "#C06C84") +
geom_smooth(method = "lm", formula = y ~ x, color = "#7D0552", alpha = .3, size = 1) +
labs(x = "Advertisements", y = "Sales") +
theme_bw() +
labs(title = "Albums Sold Predicted by Money Spent on Advertisements")
# Print the figure
print(fig)

# Save figure
# ggsave("figure.jpg", dpi = 300, width = 5, height = 4, units = "in", type = "cairo")
# Sometimes I find scientific notation super confusing.
options(scipen = 999)
# Run a linear regression (OLS) using adverts to predict sales
model_lm <- lm(sales ~ adverts, data = album_df)
summary(model_lm)
##
## Call:
## lm(formula = sales ~ adverts, data = album_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -152.949 -43.796 -0.393 37.040 211.866
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 134.139938 7.536575 17.799 <0.0000000000000002 ***
## adverts 0.096124 0.009632 9.979 <0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 65.99 on 198 degrees of freedom
## Multiple R-squared: 0.3346, Adjusted R-squared: 0.3313
## F-statistic: 99.59 on 1 and 198 DF, p-value: < 0.00000000000000022
How do we interpret the output?
How do we interpret the estimates? How about the
intercept?
What does it mean if R-squared is .33? What does it mean for the
remaining .67?
Because there is only one predictor, this value represents the square
of the simple correlation between advertising and album sales – we can
find the square root of R2 by running:
## [1] 0.5784462
So, a 1-unit increase in advertising predicts an increase in .096
albums sold. In other words, for every $1,000 we spend on advertising,
we predict we’d sell an extra 96 albums.
What if we spend $100,000?
Remember that the equation for linear regression is:
\[Y_i = b_0 + b_1X_i + e_i\]
If we apply it to our data, the equation becomes:
\[album\ sales_i = b_0 + b_1advertising\
budget_i\] \[album\ sales_i = 134.14
+ (.096*advertising\ budget)\] \[=
134.14 + (.096*100)\] \[=
143.74\]
In other words, if they spend $100,000, we predict they’d
sell around 144,000 albums
Multiple regression
Let’s go over those assumptions in more detail:
- Multicollinearity: there should be no perfect
linear relationship between two or more predictors. This is an issue
because if the predictors are related, then we can’t tease apart their
unique contributions
- Otherwise, you may have:
- Untrustworthy coefficients: once the variance is accounted for by
the first predictor, the second predictor accounts for little unique
variance.
- Homoscedasticity: at each level of the predictor,
the variance of the residuals should be constant
- Independent errors: for any two observations, the
residual terms should be uncorrelated (use Durbin-Watson test)
Here, we’re going to include the variable airplay,
which is how much the songs have been played on the radio and
attract, which is the attractiveness of the band.
# Run a multiple linear regression (OLS)
model_mult <- lm(sales ~ adverts + airplay + attract, data = album_df)
# OR
model_mult <- update(model_lm, .~. + airplay + attract) # update prior models instead of writing them out again.
Let’s compare the simple regression to the multiple regression
##
## Call:
## lm(formula = sales ~ adverts, data = album_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -152.949 -43.796 -0.393 37.040 211.866
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 134.139938 7.536575 17.799 <0.0000000000000002 ***
## adverts 0.096124 0.009632 9.979 <0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 65.99 on 198 degrees of freedom
## Multiple R-squared: 0.3346, Adjusted R-squared: 0.3313
## F-statistic: 99.59 on 1 and 198 DF, p-value: < 0.00000000000000022
##
## Call:
## lm(formula = sales ~ adverts + airplay + attract, data = album_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -121.324 -28.336 -0.451 28.967 144.132
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -26.612958 17.350001 -1.534 0.127
## adverts 0.084885 0.006923 12.261 < 0.0000000000000002 ***
## airplay 3.367425 0.277771 12.123 < 0.0000000000000002 ***
## attract 11.086335 2.437849 4.548 0.00000949 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 47.09 on 196 degrees of freedom
## Multiple R-squared: 0.6647, Adjusted R-squared: 0.6595
## F-statistic: 129.5 on 3 and 196 DF, p-value: < 0.00000000000000022
R-squared: how much of the variance in the DV is
accounted for by the regression model
Adjusted r-squared: how much of the variance in the
DV would be accounted for if the model had been taken from the
population (conservative version)
1. What do you think of the model fit?
2. How would you interpret the estimates for each predictor?
Which model is better?
The big problem with R2 is that when you add more variables to the
model, it will always go up. If you are deciding which of two models
fits the data better, the model with more predictor variables in will
always fit better. The Akaike information criterion (AIC) is a measure
of fit which penalizes the model for having more variables – a little
like adjusted R2.
AIC(model_lm, model_mult)
## df AIC
## model_lm 3 2247.375
## model_mult 5 2114.337
anova(model_lm, model_mult)
## Analysis of Variance Table
##
## Model 1: sales ~ adverts
## Model 2: sales ~ adverts + airplay + attract
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 198 862264
## 2 196 434575 2 427690 96.447 < 0.00000000000000022 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Standardized betas
These estimates tell us the number of SDs by which the outcome will
change as a result of one SD change in the predictor. This makes it
easier to compare each effect to each other because they are not
dependent on the units of measurements of the variables (e.g., 1 unit
adverts = $1k).
For reference, here are the standard deviations of our
predictors:
sd_table <- function(v1,v2,v3) {
sd1 <- sd(v1)
sd2 <- sd(v2)
sd3 <- sd(v3)
print(c(sd1, sd2, sd3))}
sd_table(album_df$adverts, album_df$airplay, album_df$attract)
## [1] 485.65521 12.26958 1.39529
# standardizes the betas. do NOT use this with interaction terms.
lm.beta(model_mult)
## adverts airplay attract
## 0.5108462 0.5119881 0.1916834
- adverts: as the advertising budget increases by 1
SD ($485,655), album sales increase by 0.511 SD.
- airplay: as the number of radio plays increases by
1 SD (12.27), album sales increase by 0.512 SD.
- attract: a band rated 1 SD (1.40 units) higher on
attractiveness can expect an additioinal 0.192 SD in sales.
Diagnostics
Durbin-Watson: testing the assumption of independence
durbinWatsonTest(model_mult)
## lag Autocorrelation D-W Statistic p-value
## 1 0.0026951 1.949819 0.702
## Alternative hypothesis: rho != 0
VIF: testing the assumption of no multicollinearity
VIF is variance inflation factor and used to measure
multicollinearity.
tolerance = 1/VIF
- If the largest VIF is greater 10, then there’s cause for
concern
- If the average VIF is substantially greater than 1, the model may be
biased
- Tolerance below 0.1 means there’s a serious problem
- Tolerance below 0.2 means there’s a potential problem
Otherwise, there is no collinearity
## adverts airplay attract
## 1.014593 1.042504 1.038455
# average vif
mean(vif(model_mult))
## [1] 1.03185
# tolerance
1/vif(model_mult)
## adverts airplay attract
## 0.9856172 0.9592287 0.9629695
Using plots for diagnostics
Residuals vs Fitted: is used to check the
assumptions of linearity. If the residuals are spread equally around a
horizontal line without distinct patterns (red line is approximately
horizontal at zero), that is a good indication of having a linear
relationship.
Normal Q-Q: is used to check the normality of
residuals assumption. If the majority of the residuals follow the
straight dashed line, then the assumption is fulfilled.
Scale-Location: is used to check the
homoscedasticity of residuals (equal variance of residuals). If the
residuals are spread randomly and the see a horizontal line with equally
(randomly) spread points, then the assumption is fulfilled.
Residuals vs Leverage: is used to identify any
influential value in our dataset. Influential values are extreme values
that might influence the regression results when included or excluded
from the analysis. Look for cases outside of a dashed line (if there is
a concerning point, you’ll see red lines pop up).




hist(model_mult$residuals)

shapiro.test(album_df$sales)
##
## Shapiro-Wilk normality test
##
## data: album_df$sales
## W = 0.98479, p-value = 0.02965
Added variable plots
These plots tell us whether the variables we’re including in the
model are relevant to the model. If the slope is not close to 0 then we
conclude that the variable is relevant to the model.
The x-axis represents the partial residuals of the predictor
variable, and the y-axis represents the partial residuals of the
response variable. The line in the plot represents the fitted values
from a linear regression model of the partial residuals of the response
variable on the partial residuals of the predictor variable.

model_cor <- cor(album_df %>%
dplyr::select(adverts, airplay, attract))
corrplot::corrplot(model_cor)

What if the assumptions are violated?
- Violation of linearity: incorporate nonlinear transformation (e.g.,
log transformation); polynomial terms
- Violation of independence: use multilevel modeling
- Violation of homoscedasticity: transform the DV
- Violation of normality: transform the DV
Replicating Madalina’s Python code
df <- read_xlsx("/Users/kareenadelrosario/Downloads/data (1).xlsx")
# Create a simple regression plot
ggplot(df, aes(x = Age, y = BELIEFcc)) +
geom_point(color = "#C06C84", alpha = 0.3) + # Scatter plot
geom_smooth(method = "lm", color = "#7D0552", size = 1) + # Regression line
labs(x = "Age", y = "Belief in science") + # Label the x and y axis
theme_minimal() + # Use a minimal theme
theme(legend.position = "none") # Remove legend

# Save figure
# ggsave("figure.tif", width = 5, height = 4, dpi = 300, type = "cairo-png")
md <- lm(BELIEFcc ~ Age, data = df)
summary(md)
##
## Call:
## lm(formula = BELIEFcc ~ Age, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -70.718 -14.050 6.061 20.728 28.975
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 76.41025 5.68958 13.430 <0.0000000000000002 ***
## Age -0.07277 0.10968 -0.664 0.508
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 25.68 on 219 degrees of freedom
## Multiple R-squared: 0.002006, Adjusted R-squared: -0.002551
## F-statistic: 0.4402 on 1 and 219 DF, p-value: 0.5077
df_plot <- df %>%
mutate(Gender.f = case_when(
Gender == 1 ~ "Female",
Gender == 2 ~ "Male")) %>%
mutate(Gender.f = factor(Gender.f, levels = c("Female", "Male"))) %>%
filter(!is.na(Gender.f))
ggplot(df_plot, aes(x=Gender.f, y=BELIEFcc, fill = Gender.f)) +
geom_bar(stat="summary", position = "dodge") +
ylim(0, 100) +
theme_minimal() + # Optional: Adds a minimal theme for aesthetics
labs(x="Party", y="Trust") # Labeling axes

Numeric vs Categorical Predictors
# Numeric
df$Gender <- as.numeric(df$Gender)
model <- lm(BELIEFcc ~ Age + Gender, data = df)
summary(model)
##
## Call:
## lm(formula = BELIEFcc ~ Age + Gender, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -74.366 -12.143 5.994 21.255 33.830
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 60.79657 7.74482 7.850 0.000000000000186 ***
## Age -0.07665 0.10786 -0.711 0.47808
## Gender 9.70256 3.32806 2.915 0.00392 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 25.25 on 218 degrees of freedom
## Multiple R-squared: 0.03946, Adjusted R-squared: 0.03064
## F-statistic: 4.477 on 2 and 218 DF, p-value: 0.01243
# Factor
df$Gender <- factor(df$Gender)
model <- lm(BELIEFcc ~ Age + Gender, data = df)
summary(model)
##
## Call:
## lm(formula = BELIEFcc ~ Age + Gender, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -74.85 -12.13 6.14 20.93 34.36
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 70.62086 5.96097 11.847 < 0.0000000000000002 ***
## Age -0.08698 0.10909 -0.797 0.42615
## Gender2 10.45065 3.51412 2.974 0.00327 **
## Gender4 13.28167 25.63469 0.518 0.60491
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 25.28 on 217 degrees of freedom
## Multiple R-squared: 0.04144, Adjusted R-squared: 0.02819
## F-statistic: 3.127 on 3 and 217 DF, p-value: 0.02668
What if I want to change the reference group? How can I do that?
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIExpbmVhciBSZWdyZXNzaW9uIgphdXRob3I6ICJLYXJlZW5hIGRlbCBSb3NhcmlvIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiByZWFkYWJsZQogICAgaGlnaGxpZ2h0OiBhcnJvdwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCgpgYGB7ciwgbG9hZCBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KcGtncyA8LSBjKCJ0aWR5dmVyc2UiLCAiZHBseXIiLCAiaGF2ZW4iLCAiZm9yZWlnbiIsICJsbWU0IiwgInBseXIiLCAibmxtZSIsICJsc3IiLCAiZW1tZWFucyIsICJhZmV4IiwgImtuaXRyIiwgImthYmxlRXh0cmEiLCAiUXVhbnRQc3ljIiwgImNhciIsICJyZWFkeGwiLCAicGFzdGVjcyIpCgpwYWNrYWdlcyA8LSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkKcF90b19pbnN0YWxsIDwtIHBrZ3NbIShwa2dzICVpbiUgcGFja2FnZXMpXQoKaWYobGVuZ3RoKHBfdG9faW5zdGFsbCkgPiAwKXsKICBpbnN0YWxsLnBhY2thZ2VzKHBfdG9faW5zdGFsbCkKfQoKbGFwcGx5KHBrZ3MsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKCmFsYnVtX2RmIDwtIHJlYWQuZGVsaW0oIkFsYnVtIFNhbGVzIDIuZGF0IikKYGBgCgotLS0tLS0tLS0tLS0tCgojIyBBIG5vdGUgb24gYXNzdW1wdGlvbnMKCkhlcmUgYXJlIHRoZSAzIGFzc3VtcHRpb25zIHRoYXQgYXBwbHkgdG8gYWxsIHBhcmFtZXRyaWMgdGVzdHM6CgogIDEuICoqTm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YSoqCiAgICAgICogU2hhcGlyby1XaWxrIHRlc3Q6IGNhdXRpb24tLWl0J3MgZWFzeSB0byBnZXQgYSBzaWduaWZpY2FudCByZXN1bHQgaWYgeW91ciBzYW1wbGUgaXMgbGFyZ2UgZW5vdWdoCiAgICAgICogUS1RIHBsb3Q6IGVhY2ggdmFsdWUgaXMgY29tcGFyZWQgdG8gdGhlIGV4cGVjdGVkIHZhbHVlLiBJZiBub3JtYWxseSBkaXN0cmlidXRlZCwgeW91IGdldCBhIGRpYWdvbmFsIGxpbmUuCiAgICAgICogUGxvdHMoKQogICAgICAgIC0gUkVHUkVTU0lPTgogICAgICAgICAgLSBBc3N1bXB0aW9uIG9mIGxpbmVhcml0eQogICAgICAgIC0gQU5PVkEKICAgICAgICAgIC0gQXNzdW1wdGlvbiB0aGF0IGRpc3RyaWJ1dGlvbnMgd2l0aGluIGdyb3VwcyBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKICAgICAgCiAgMi4gKipIb21vZ2VuZWl0eSBvZiB2YXJpYW5jZSoqOiBUaGUgdmFyaWFuY2VzIHNob3VsZCBiZSB0aGUgc2FtZSB0aHJvdWdob3V0IHRoZSBkYXRhLgogICAgICAqIFJFR1JFU1NJT04KICAgICAgICAtIEhvbW9zY2VkYXN0aWNpdHk6IGluc3BlY3QgcGxvdCBjb21wYXJpbmcgcmVzaWR1YWxzIHZzIHByZWRpY3RlZCB2YWx1ZXMKICAgICAgKiBBTk9WQSAKICAgICAgICAtIExldmVuZSdzIG9yIEJhcnRsZXR0J3MgdGVzdCAoY29tcGFyZXMgdmFyaWFuY2VzIGJldHdlZW4gZ3JvdXBzKQogICAgICAgIC0gTWF1Y2hseSdzIHNwaGVyaWNpdHkgdGVzdCAocmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEpCgogIDMuICoqSW5kZXBlbmRlbmNlKiogCiAgICAgICogUkVHUkVTU0lPTgogICAgICAgIC0gRHVyYmluLVdhdHNvbjogcmVzaWR1YWxzIGFyZSBjb3JyZWxhdGVkLgogICAgICAgIC0gTXVsdGljb2xsaW5lYXJpdHk6IHByZWRpY3RvcnMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkLiBUZXN0IHdpdGggVklGIGFuZC9vciBjb3JyZWxhdGlvbiBtYXRyaXgKCi0tLS0tLS0tLS0KCiMgTGluZWFyIFJlZ3Jlc3Npb24KIyMgRG9lcyBtb25leSBzcGVudCBvbiBhZHZlcnRpc2luZyBwcmVkaWN0IGFsYnVtIHNhbGVzPwoKSGVyZSBpcyB0aGUgW2RhdGFzZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9rYXJlZW5hLWRlbHJvc2FyaW8vcmVncmVzc2lvbl9yY29kZS9ibG9iL21haW4vQWxidW0lMjBTYWxlcyUyMDIuZGF0KSB3ZSdsbCBiZSB1c2luZyBpbiBhZGRpdGlvbiB0byBNYWRhbGluYSdzIGRhdGFzZXQuCgpBIHJlY29yZCBjb21wYW55IHdhbnRzIHRvIGtub3cgaWYgdGhleSBzcGVuZCAkMTAwLDAwMCBvbiBhZHZlcnRpc2luZywgaG93IG1hbnkgYWxidW1zIGNvdWxkIHRoZXkgZXhwZWN0IHRvIHNlbGw/CgogIC0gYWR2ZXJ0czogMSB1bml0ID0gJDEsMDAwCiAgLSBzYWxlczogYWxidW1zIHNvbGQKCmBgYHtyfQpoZWFkKGFsYnVtX2RmKQpgYGAKCmBgYHtyIHZpc3VhbGl6aW5nIHJlZ3Jlc3Npb24sIHdhcm5pbmc9RkFMU0V9CiMgQ3JlYXRlIHRoZSBmaWd1cmUKZmlnIDwtIGdncGxvdChkYXRhID0gYWxidW1fZGYsIGFlcyh4ID0gYWR2ZXJ0cywgeSA9IHNhbGVzKSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC4zLCBjb2xvciA9ICIjQzA2Qzg0IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgY29sb3IgPSAiIzdEMDU1MiIsIGFscGhhID0gLjMsIHNpemUgPSAxKSArCiAgbGFicyh4ID0gIkFkdmVydGlzZW1lbnRzIiwgeSA9ICJTYWxlcyIpICsKICB0aGVtZV9idygpICsKICBsYWJzKHRpdGxlID0gIkFsYnVtcyBTb2xkIFByZWRpY3RlZCBieSBNb25leSBTcGVudCBvbiBBZHZlcnRpc2VtZW50cyIpCgojIFByaW50IHRoZSBmaWd1cmUKcHJpbnQoZmlnKQoKIyBTYXZlIGZpZ3VyZQojIGdnc2F2ZSgiZmlndXJlLmpwZyIsIGRwaSA9IDMwMCwgd2lkdGggPSA1LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsIHR5cGUgPSAiY2Fpcm8iKQoKYGBgCgpgYGB7ciB0ZXN0aW5nIHJlZ3Jlc3Npb259CiMgU29tZXRpbWVzIEkgZmluZCBzY2llbnRpZmljIG5vdGF0aW9uIHN1cGVyIGNvbmZ1c2luZy4gCm9wdGlvbnMoc2NpcGVuID0gOTk5KQoKIyBSdW4gYSBsaW5lYXIgcmVncmVzc2lvbiAoT0xTKSB1c2luZyBhZHZlcnRzIHRvIHByZWRpY3Qgc2FsZXMKbW9kZWxfbG0gPC0gbG0oc2FsZXMgfiBhZHZlcnRzLCBkYXRhID0gYWxidW1fZGYpCnN1bW1hcnkobW9kZWxfbG0pCmBgYAoKIyMjIyBIb3cgZG8gd2UgaW50ZXJwcmV0IHRoZSBvdXRwdXQ/CgoxLiBIb3cgZG8gd2UgaW50ZXJwcmV0IHRoZSBlc3RpbWF0ZXM/IEhvdyBhYm91dCB0aGUgaW50ZXJjZXB0PwoKMi4gV2hhdCBkb2VzIGl0IG1lYW4gaWYgUi1zcXVhcmVkIGlzIC4zMz8gV2hhdCBkb2VzIGl0IG1lYW4gZm9yIHRoZSByZW1haW5pbmcgLjY3PwoKQmVjYXVzZSB0aGVyZSBpcyBvbmx5IG9uZSBwcmVkaWN0b3IsIHRoaXMgdmFsdWUgcmVwcmVzZW50cyB0aGUgc3F1YXJlIG9mIHRoZSBzaW1wbGUgY29ycmVsYXRpb24gYmV0d2VlbiBhZHZlcnRpc2luZyBhbmQgYWxidW0gc2FsZXMg4oCTIHdlIGNhbiBmaW5kIHRoZSBzcXVhcmUgcm9vdCBvZiBSMiBieSBydW5uaW5nOgoKYGBge3J9CnNxcnQoMC4zMzQ2KQpgYGAKClNvLCBhIDEtdW5pdCBpbmNyZWFzZSBpbiBhZHZlcnRpc2luZyBwcmVkaWN0cyBhbiBpbmNyZWFzZSBpbiAuMDk2IGFsYnVtcyBzb2xkLiBJbiBvdGhlciB3b3JkcywgZm9yIGV2ZXJ5ICQxLDAwMCB3ZSBzcGVuZCBvbiBhZHZlcnRpc2luZywgd2UgcHJlZGljdCB3ZSdkIHNlbGwgYW4gZXh0cmEgOTYgYWxidW1zLiAKCi0tLS0tLS0tLS0tLS0tLQoKKldoYXQgaWYgd2Ugc3BlbmQgJDEwMCwwMDA/KgoKClJlbWVtYmVyIHRoYXQgdGhlIGVxdWF0aW9uIGZvciBsaW5lYXIgcmVncmVzc2lvbiBpczoKCiQkWV9pID0gYl8wICsgYl8xWF9pICsgZV9pJCQKCklmIHdlIGFwcGx5IGl0IHRvIG91ciBkYXRhLCB0aGUgZXF1YXRpb24gYmVjb21lczoKCiQkYWxidW1cIHNhbGVzX2kgID0gYl8wICsgYl8xYWR2ZXJ0aXNpbmdcIGJ1ZGdldF9pJCQKJCRhbGJ1bVwgc2FsZXNfaSAgPSAxMzQuMTQgKyAoLjA5NiphZHZlcnRpc2luZ1wgYnVkZ2V0KSQkCiQkPSAxMzQuMTQgKyAoLjA5NioxMDApJCQKJCQ9IDE0My43NCQkCgoqKkluIG90aGVyIHdvcmRzLCBpZiB0aGV5IHNwZW5kICQxMDAsMDAwLCB3ZSBwcmVkaWN0IHRoZXknZCBzZWxsIGFyb3VuZCAxNDQsMDAwIGFsYnVtcyoqCgotLS0tLS0tCgojIE11bHRpcGxlIHJlZ3Jlc3Npb24KCkxldCdzIGdvIG92ZXIgdGhvc2UgYXNzdW1wdGlvbnMgaW4gbW9yZSBkZXRhaWw6CgogIDEuICoqTXVsdGljb2xsaW5lYXJpdHk6KiogdGhlcmUgc2hvdWxkIGJlIG5vIHBlcmZlY3QgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBvciBtb3JlIHByZWRpY3RvcnMuIFRoaXMgaXMgYW4gaXNzdWUgYmVjYXVzZSBpZiB0aGUgcHJlZGljdG9ycyBhcmUgcmVsYXRlZCwgdGhlbiB3ZSBjYW4ndCB0ZWFzZSBhcGFydCB0aGVpciB1bmlxdWUgY29udHJpYnV0aW9ucwogICAgICBhLiBPdGhlcndpc2UsIHlvdSBtYXkgaGF2ZToKICAgICAgICAgIDEuIFVudHJ1c3R3b3J0aHkgY29lZmZpY2llbnRzOiBvbmNlIHRoZSB2YXJpYW5jZSBpcyBhY2NvdW50ZWQgZm9yIGJ5IHRoZSBmaXJzdCBwcmVkaWN0b3IsIHRoZSBzZWNvbmQgcHJlZGljdG9yIGFjY291bnRzIGZvciBsaXR0bGUgdW5pcXVlIHZhcmlhbmNlLgogIDIuICoqSG9tb3NjZWRhc3RpY2l0eToqKiBhdCBlYWNoIGxldmVsIG9mIHRoZSBwcmVkaWN0b3IsIHRoZSB2YXJpYW5jZSBvZiB0aGUgcmVzaWR1YWxzIHNob3VsZCBiZSBjb25zdGFudAogIDMuICoqSW5kZXBlbmRlbnQgZXJyb3JzOioqIGZvciBhbnkgdHdvIG9ic2VydmF0aW9ucywgdGhlIHJlc2lkdWFsIHRlcm1zIHNob3VsZCBiZSB1bmNvcnJlbGF0ZWQgKHVzZSBEdXJiaW4tV2F0c29uIHRlc3QpCgoKLS0tLS0tCgpIZXJlLCB3ZSdyZSBnb2luZyB0byBpbmNsdWRlIHRoZSB2YXJpYWJsZSAqKmFpcnBsYXkqKiwgd2hpY2ggaXMgaG93IG11Y2ggdGhlIHNvbmdzIGhhdmUgYmVlbiBwbGF5ZWQgb24gdGhlIHJhZGlvIGFuZCAqKmF0dHJhY3QqKiwgd2hpY2ggaXMgdGhlIGF0dHJhY3RpdmVuZXNzIG9mIHRoZSBiYW5kLgoKYGBge3J9CiMgUnVuIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gKE9MUykKbW9kZWxfbXVsdCA8LSBsbShzYWxlcyB+IGFkdmVydHMgKyBhaXJwbGF5ICsgYXR0cmFjdCwgZGF0YSA9IGFsYnVtX2RmKQoKIyBPUgoKbW9kZWxfbXVsdCA8LSB1cGRhdGUobW9kZWxfbG0sIC5+LiArIGFpcnBsYXkgKyBhdHRyYWN0KSAjIHVwZGF0ZSBwcmlvciBtb2RlbHMgaW5zdGVhZCBvZiB3cml0aW5nIHRoZW0gb3V0IGFnYWluLgpgYGAKCiMjIyBMZXQncyBjb21wYXJlIHRoZSBzaW1wbGUgcmVncmVzc2lvbiB0byB0aGUgbXVsdGlwbGUgcmVncmVzc2lvbgpgYGB7cn0Kc3VtbWFyeShtb2RlbF9sbSkKYGBgCgpgYGB7cn0Kc3VtbWFyeShtb2RlbF9tdWx0KQpgYGAKICAKICAqKlItc3F1YXJlZDoqKiBob3cgbXVjaCBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIERWIGlzIGFjY291bnRlZCBmb3IgYnkgdGhlIHJlZ3Jlc3Npb24gbW9kZWwKICAKICAqKkFkanVzdGVkIHItc3F1YXJlZDoqKiBob3cgbXVjaCBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIERWIHdvdWxkIGJlIGFjY291bnRlZCBmb3IgaWYgdGhlIG1vZGVsIGhhZCBiZWVuIHRha2VuIGZyb20gdGhlIHBvcHVsYXRpb24gKGNvbnNlcnZhdGl2ZSB2ZXJzaW9uKQoKICAgIDEuIFdoYXQgZG8geW91IHRoaW5rIG9mIHRoZSBtb2RlbCBmaXQ/CiAgICAyLiBIb3cgd291bGQgeW91IGludGVycHJldCB0aGUgZXN0aW1hdGVzIGZvciBlYWNoIHByZWRpY3Rvcj8KICAgIAotLS0tLS0tLS0tLS0tLS0tLS0KCgojIyMjIFdoaWNoIG1vZGVsIGlzIGJldHRlcj8KClRoZSBiaWcgcHJvYmxlbSB3aXRoIFIyIGlzIHRoYXQgd2hlbiB5b3UgYWRkIG1vcmUgdmFyaWFibGVzIHRvIHRoZSBtb2RlbCwgaXQgd2lsbCBhbHdheXMgZ28gdXAuIElmIHlvdSBhcmUgZGVjaWRpbmcgd2hpY2ggb2YgdHdvIG1vZGVscyBmaXRzIHRoZSBkYXRhIGJldHRlciwgdGhlIG1vZGVsIHdpdGggbW9yZSBwcmVkaWN0b3IgdmFyaWFibGVzIGluIHdpbGwgYWx3YXlzIGZpdCBiZXR0ZXIuIFRoZSBBa2Fpa2UgaW5mb3JtYXRpb24gY3JpdGVyaW9uIChBSUMpIGlzIGEgbWVhc3VyZSBvZiBmaXQgd2hpY2ggcGVuYWxpemVzIHRoZSBtb2RlbCBmb3IgaGF2aW5nIG1vcmUgdmFyaWFibGVzIOKAkyBhIGxpdHRsZSBsaWtlIGFkanVzdGVkIFIyLgoKYGBge3J9CkFJQyhtb2RlbF9sbSwgbW9kZWxfbXVsdCkKYGBgCgpgYGB7cn0KYW5vdmEobW9kZWxfbG0sIG1vZGVsX211bHQpCmBgYAoKIyMjIyBTdGFuZGFyZGl6ZWQgYmV0YXMKClRoZXNlIGVzdGltYXRlcyB0ZWxsIHVzIHRoZSBudW1iZXIgb2YgU0RzIGJ5IHdoaWNoIHRoZSBvdXRjb21lIHdpbGwgY2hhbmdlIGFzIGEgcmVzdWx0IG9mIG9uZSBTRCBjaGFuZ2UgaW4gdGhlIHByZWRpY3Rvci4gVGhpcyBtYWtlcyBpdCBlYXNpZXIgdG8gY29tcGFyZSBlYWNoIGVmZmVjdCB0byBlYWNoIG90aGVyIGJlY2F1c2UgdGhleSBhcmUgbm90IGRlcGVuZGVudCBvbiB0aGUgdW5pdHMgb2YgbWVhc3VyZW1lbnRzIG9mIHRoZSB2YXJpYWJsZXMgKGUuZy4sIDEgdW5pdCBhZHZlcnRzID0gJDFrKS4gCgpGb3IgcmVmZXJlbmNlLCBoZXJlIGFyZSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9ucyBvZiBvdXIgcHJlZGljdG9yczoKYGBge3J9CnNkX3RhYmxlIDwtIGZ1bmN0aW9uKHYxLHYyLHYzKSB7CiAgc2QxIDwtIHNkKHYxKQogIHNkMiA8LSBzZCh2MikKICBzZDMgPC0gc2QodjMpCiAgCiAgcHJpbnQoYyhzZDEsIHNkMiwgc2QzKSl9CgpzZF90YWJsZShhbGJ1bV9kZiRhZHZlcnRzLCBhbGJ1bV9kZiRhaXJwbGF5LCBhbGJ1bV9kZiRhdHRyYWN0KQpgYGAKCgpgYGB7cn0KIyBzdGFuZGFyZGl6ZXMgdGhlIGJldGFzLiBkbyBOT1QgdXNlIHRoaXMgd2l0aCBpbnRlcmFjdGlvbiB0ZXJtcy4KbG0uYmV0YShtb2RlbF9tdWx0KQpgYGAKCiAgKiAqKmFkdmVydHM6KiogYXMgdGhlIGFkdmVydGlzaW5nIGJ1ZGdldCBpbmNyZWFzZXMgYnkgMSBTRCAoJDQ4NSw2NTUpLCBhbGJ1bSBzYWxlcyBpbmNyZWFzZSBieSAwLjUxMSBTRC4KICAqICoqYWlycGxheToqKiBhcyB0aGUgbnVtYmVyIG9mIHJhZGlvIHBsYXlzIGluY3JlYXNlcyBieSAxIFNEICgxMi4yNyksIGFsYnVtIHNhbGVzIGluY3JlYXNlIGJ5IDAuNTEyIFNELgogICogKiphdHRyYWN0OioqIGEgYmFuZCByYXRlZCAxIFNEICgxLjQwIHVuaXRzKSBoaWdoZXIgb24gYXR0cmFjdGl2ZW5lc3MgY2FuIGV4cGVjdCBhbiBhZGRpdGlvaW5hbCAwLjE5MiBTRCBpbiBzYWxlcy4gCgojIyBEaWFnbm9zdGljcwoKIyMjIER1cmJpbi1XYXRzb246IHRlc3RpbmcgdGhlIGFzc3VtcHRpb24gb2YgaW5kZXBlbmRlbmNlCgpgYGB7cn0KZHVyYmluV2F0c29uVGVzdChtb2RlbF9tdWx0KQpgYGAKCiMjIyBWSUY6IHRlc3RpbmcgdGhlIGFzc3VtcHRpb24gb2Ygbm8gbXVsdGljb2xsaW5lYXJpdHkKClZJRiBpcyB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIGFuZCB1c2VkIHRvIG1lYXN1cmUgbXVsdGljb2xsaW5lYXJpdHkuCgp0b2xlcmFuY2UgPSAxL1ZJRgoKICAqIElmIHRoZSBsYXJnZXN0IFZJRiBpcyBncmVhdGVyIDEwLCB0aGVuIHRoZXJlJ3MgY2F1c2UgZm9yIGNvbmNlcm4KICAqIElmIHRoZSBhdmVyYWdlIFZJRiBpcyBzdWJzdGFudGlhbGx5IGdyZWF0ZXIgdGhhbiAxLCB0aGUgbW9kZWwgbWF5IGJlIGJpYXNlZAogICogVG9sZXJhbmNlIGJlbG93IDAuMSBtZWFucyB0aGVyZSdzIGEgc2VyaW91cyBwcm9ibGVtCiAgKiBUb2xlcmFuY2UgYmVsb3cgMC4yIG1lYW5zIHRoZXJlJ3MgYSBwb3RlbnRpYWwgcHJvYmxlbQogIApPdGhlcndpc2UsIHRoZXJlIGlzIG5vIGNvbGxpbmVhcml0eQoKYGBge3J9CiMgdmlmCnZpZihtb2RlbF9tdWx0KQoKIyBhdmVyYWdlIHZpZgptZWFuKHZpZihtb2RlbF9tdWx0KSkKCiMgdG9sZXJhbmNlCjEvdmlmKG1vZGVsX211bHQpCmBgYAoKIyMjIFVzaW5nIHBsb3RzIGZvciBkaWFnbm9zdGljcwoKKipSZXNpZHVhbHMgdnMgRml0dGVkOioqIGlzIHVzZWQgdG8gY2hlY2sgdGhlIGFzc3VtcHRpb25zIG9mIGxpbmVhcml0eS4gSWYgdGhlIHJlc2lkdWFscyBhcmUgc3ByZWFkIGVxdWFsbHkgYXJvdW5kIGEgaG9yaXpvbnRhbCBsaW5lIHdpdGhvdXQgZGlzdGluY3QgcGF0dGVybnMgKHJlZCBsaW5lIGlzIGFwcHJveGltYXRlbHkgaG9yaXpvbnRhbCBhdCB6ZXJvKSwgdGhhdCBpcyBhIGdvb2QgaW5kaWNhdGlvbiBvZiBoYXZpbmcgYSBsaW5lYXIgcmVsYXRpb25zaGlwLgoKKipOb3JtYWwgUS1ROioqIGlzIHVzZWQgdG8gY2hlY2sgdGhlIG5vcm1hbGl0eSBvZiByZXNpZHVhbHMgYXNzdW1wdGlvbi4gSWYgdGhlIG1ham9yaXR5IG9mIHRoZSByZXNpZHVhbHMgZm9sbG93IHRoZSBzdHJhaWdodCBkYXNoZWQgbGluZSwgdGhlbiB0aGUgYXNzdW1wdGlvbiBpcyBmdWxmaWxsZWQuCgoqKlNjYWxlLUxvY2F0aW9uOioqIGlzIHVzZWQgdG8gY2hlY2sgdGhlIGhvbW9zY2VkYXN0aWNpdHkgb2YgcmVzaWR1YWxzIChlcXVhbCB2YXJpYW5jZSBvZiByZXNpZHVhbHMpLiBJZiB0aGUgcmVzaWR1YWxzIGFyZSBzcHJlYWQgcmFuZG9tbHkgYW5kIHRoZSBzZWUgYSBob3Jpem9udGFsIGxpbmUgd2l0aCBlcXVhbGx5IChyYW5kb21seSkgc3ByZWFkIHBvaW50cywgdGhlbiB0aGUgYXNzdW1wdGlvbiBpcyBmdWxmaWxsZWQuCgoqKlJlc2lkdWFscyB2cyBMZXZlcmFnZToqKiBpcyB1c2VkIHRvIGlkZW50aWZ5IGFueSBpbmZsdWVudGlhbCB2YWx1ZSBpbiBvdXIgZGF0YXNldC4gSW5mbHVlbnRpYWwgdmFsdWVzIGFyZSBleHRyZW1lIHZhbHVlcyB0aGF0IG1pZ2h0IGluZmx1ZW5jZSB0aGUgcmVncmVzc2lvbiByZXN1bHRzIHdoZW4gaW5jbHVkZWQgb3IgZXhjbHVkZWQgZnJvbSB0aGUgYW5hbHlzaXMuIExvb2sgZm9yIGNhc2VzIG91dHNpZGUgb2YgYSBkYXNoZWQgbGluZSAoaWYgdGhlcmUgaXMgYSBjb25jZXJuaW5nIHBvaW50LCB5b3UnbGwgc2VlIHJlZCBsaW5lcyBwb3AgdXApLgoKYGBge3J9CnBsb3QobW9kZWxfbXVsdCkKYGBgCgpgYGB7cn0KaGlzdChtb2RlbF9tdWx0JHJlc2lkdWFscykKYGBgCgpgYGB7cn0Kc2hhcGlyby50ZXN0KGFsYnVtX2RmJHNhbGVzKQpgYGAKCiMjIyMgQWRkZWQgdmFyaWFibGUgcGxvdHMKClRoZXNlIHBsb3RzIHRlbGwgdXMgd2hldGhlciB0aGUgdmFyaWFibGVzIHdlJ3JlIGluY2x1ZGluZyBpbiB0aGUgbW9kZWwgYXJlIHJlbGV2YW50IHRvIHRoZSBtb2RlbC4gSWYgdGhlIHNsb3BlIGlzIG5vdCBjbG9zZSB0byAwIHRoZW4gd2UgY29uY2x1ZGUgdGhhdCB0aGUgdmFyaWFibGUgaXMgcmVsZXZhbnQgdG8gdGhlIG1vZGVsLgoKVGhlIHgtYXhpcyByZXByZXNlbnRzIHRoZSBwYXJ0aWFsIHJlc2lkdWFscyBvZiB0aGUgcHJlZGljdG9yIHZhcmlhYmxlLCBhbmQgdGhlIHktYXhpcyByZXByZXNlbnRzIHRoZSBwYXJ0aWFsIHJlc2lkdWFscyBvZiB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIFRoZSBsaW5lIGluIHRoZSBwbG90IHJlcHJlc2VudHMgdGhlIGZpdHRlZCB2YWx1ZXMgZnJvbSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIG9mIHRoZSBwYXJ0aWFsIHJlc2lkdWFscyBvZiB0aGUgcmVzcG9uc2UgdmFyaWFibGUgb24gdGhlIHBhcnRpYWwgcmVzaWR1YWxzIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGUuCgpgYGB7cn0KYXZQbG90cyhtb2RlbF9tdWx0KQpgYGAKCmBgYHtyfQptb2RlbF9jb3IgPC0gY29yKGFsYnVtX2RmICU+JSAKICAgICAgZHBseXI6OnNlbGVjdChhZHZlcnRzLCBhaXJwbGF5LCBhdHRyYWN0KSkKCmNvcnJwbG90Ojpjb3JycGxvdChtb2RlbF9jb3IpCmBgYAoKIyMjIFdoYXQgaWYgdGhlIGFzc3VtcHRpb25zIGFyZSB2aW9sYXRlZD8KCiAgKiBWaW9sYXRpb24gb2YgbGluZWFyaXR5OiBpbmNvcnBvcmF0ZSBub25saW5lYXIgdHJhbnNmb3JtYXRpb24gKGUuZy4sIGxvZyB0cmFuc2Zvcm1hdGlvbik7IHBvbHlub21pYWwgdGVybXMKICAqIFZpb2xhdGlvbiBvZiBpbmRlcGVuZGVuY2U6IHVzZSBtdWx0aWxldmVsIG1vZGVsaW5nCiAgKiBWaW9sYXRpb24gb2YgaG9tb3NjZWRhc3RpY2l0eTogdHJhbnNmb3JtIHRoZSBEVgogICogVmlvbGF0aW9uIG9mIG5vcm1hbGl0eTogdHJhbnNmb3JtIHRoZSBEVgoKIyMjIFRyYW5zZm9ybWF0aW9ucwoKV2hhdCB0YWtpbmcgdGhlIGxvZyBvZiBhIG51bWJlciBkb2VzIGlzIHRyYW5zZm9ybSBpdCwgZXNzZW50aWFsbHkgc2hyaW5raW5nIGl0IGFuZCBtYWtpbmcgZ3Jvd3RoIGF0IGhpZ2hlciBudW1iZXJzIG5vbi1saW5lYXIuIFdoZW4geW91IHRha2UgdGhlIGxvZyBvZiBhIHNlcmllcyBvZiBudW1iZXJzLCBpdCBjYW4gbWFrZSB0aGVtIGxpbmVhciBpZiB0aGV5IHdlcmUgZm9ybWVybHkgbm9uLWxpbmVhci4KClRyYW5zZm9ybWluZyB0aGUgZGF0YSB3b27igJl0IGNoYW5nZSB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcyAodGhlIHJlbGF0aXZlIGRpZmZlcmVuY2VzIGJldHdlZW4gcGVvcGxlIGZvciBhIGdpdmVuIHZhcmlhYmxlIHN0YXkgdGhlIHNhbWUpLCBidXQgaXQgZG9lcyBjaGFuZ2UgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gZGlmZmVyZW50IHZhcmlhYmxlcyAoYmVjYXVzZSBpdCBjaGFuZ2VzIHRoZSB1bml0cyBvZiBtZWFzdXJlbWVudCkuIAoKKkJlc3QgZm9yIGRhdGEgd2hlcmUgdGhlIDAncyBhcmUgbmF0dXJhbGx5IG9jY3VycmluZyBhbmQgbm90IGR1ZSB0byBlcnJvciBvciByZWNvcmRpbmcgbmVnYXRpdmUgdmFsdWVzIGFzIHplcm8uCgoKfFByb2JsZW0gICAgICAgICAgICAgICAgICAgICAgICAgIHwgVHJhbnNmb3JtYXRpb24gIHwgQ29uc2lkZXJhdGlvbnMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfHBvc2l0aXZlIHNrZXcsIHVuZXF1YWwgdmFyaWFuY2VzIHwgbG9nLCBzcXJ0ICAgICAgIHwgZm9yIGxvZywgYWRkIGNvbnN0YW50IGlmIHdvcmtpbmcgd2l0aCAwJ3Mgb3IgbmVnYXRpdmUgbnVtYmVyc3wKfG5lZ2F0aXZlIHNrZXcgICAgICAgICAgICAgICAgICAgIHwgcmV2ZXJzZSBzY29yZSAgIHwgcmVtZW1iZXIgdG8gcmV2ZXJzZSB5b3VyIHJldmVyc2Ugd2hlbiBpbnRlcnByZXRpbmcgICAgICAgICAgIHwKCgpgYGB7cn0Kc2tld19kZiA8LSByZWFkLmRlbGltKCIvVXNlcnMva2FyZWVuYWRlbHJvc2FyaW8vRG93bmxvYWRzL0Rvd25sb2FkRmVzdGl2YWwoTm8gT3V0bGllcikuZGF0IikKYGBgCgojIyMjIERheSAxCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQpoaXN0LmRheTEgPC0gZ2dwbG90KHNrZXdfZGYsIGFlcyhkYXkxKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCAKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIiwgYmlucyA9IDQwKSArIAogIGxhYnMoeCA9ICJIeWdpZW5lIHNjb3JlIG9uIGRheSAxIiwgeSA9ICJEZW5zaXR5IikgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIGFyZ3MgPSBsaXN0KG1lYW4gPSBtZWFuKHNrZXdfZGYkZGF5MSwgbmEucm0gPSBUUlVFKSwgc2QgPSBzZChza2V3X2RmJGRheTEsIG5hLnJtID0gVFJVRSkpLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMSkKCnByaW50KGhpc3QuZGF5MSkKYGBgCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQpnZ3Bsb3Qoc2tld19kZiwgYWVzKHNhbXBsZSA9IGRheTEpKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoY29sb3VyID0gInJlZCIpICsgIyBBZGQgYSByZWZlcmVuY2UgbGluZSBpbiByZWQKICB0aGVtZV9taW5pbWFsKCkgKyAjIFVzZSBhIG1pbmltYWwgdGhlbWUgZm9yIGFlc3RoZXRpY3MKICBnZ3RpdGxlKCJRLVEgUGxvdCIpCmBgYAoKIyMjIyBEYXkgMgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9Cmhpc3QuZGF5MiA8LSBnZ3Bsb3Qoc2tld19kZiwgYWVzKGRheTIpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIAogICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIGZpbGwgPSAid2hpdGUiLCBiaW5zID0gNDApICsgCiAgbGFicyh4ID0gIkh5Z2llbmUgc2NvcmUgb24gZGF5IDIiLCB5ID0gIkRlbnNpdHkiKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IG1lYW4oc2tld19kZiRkYXkyLCBuYS5ybSA9IFRSVUUpLCBzZCA9IHNkKHNrZXdfZGYkZGF5MiwgbmEucm0gPSBUUlVFKSksIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAxKQoKcHJpbnQoaGlzdC5kYXkyKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3Qoc2tld19kZiwgYWVzKHNhbXBsZSA9IGRheTIpKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoY29sb3VyID0gInJlZCIpICsgIyBBZGQgYSByZWZlcmVuY2UgbGluZSBpbiByZWQKICB0aGVtZV9taW5pbWFsKCkgKyAjIFVzZSBhIG1pbmltYWwgdGhlbWUgZm9yIGFlc3RoZXRpY3MKICBnZ3RpdGxlKCJRLVEgUGxvdCIpCmBgYAoKU2tldyAmIGt1cnRvc2lzIHNob3VsZCBiZSBuZWFyIDAuIAoKICAqIFNLRVc6IHBvc2l0aXZlIHNjb3JlID0gcmlnaHQgc2tldywgbmVnYXRpdmUgdmFsdWVzID0gbGVmdCBza2V3CiAgKiBLVVJUT1NJUzogcG9zaXRpdmUgc2NvcmUgPSBmYXQgdGFpbCwgbmVnYXRpdmUgdmFsdWVzID0gZmxhdCB0YWlsCgpgYGB7cn0KcGFzdGVjczo6c3RhdC5kZXNjKHNrZXdfZGZbLCBjKCJkYXkxIiwgImRheTIiKV0sIGJhc2ljID0gRkFMU0UsIG5vcm0gPSBUUlVFKQpgYGAKCmBgYHtyfQojIGxvZyB0cmFuc2Zvcm0gKGFkZCBjb25zdGFudCBiL2Mgd2UgaGF2ZSB6ZXJvcykKc2tld19kZiRkYXkxX2xvZyA8LSBsb2coc2tld19kZiRkYXkxICsgMSkKc2tld19kZiRkYXkyX2xvZyA8LSBsb2coc2tld19kZiRkYXkyICsgMSkKCiMgc3FydCB0cmFuc2Zvcm1hdGlvbnMKc2tld19kZiRkYXkxX3NxcnQgPC0gc3FydChza2V3X2RmJGRheTEpCnNrZXdfZGYkZGF5Ml9zcXJ0IDwtIHNxcnQoc2tld19kZiRkYXkyKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpoaXN0LmRheTJfbG9nIDwtIGdncGxvdChza2V3X2RmLCBhZXMoZGF5Ml9sb2cpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIAogICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIGZpbGwgPSAid2hpdGUiLCBiaW5zID0gNDApICsgCiAgbGFicyh4ID0gIkh5Z2llbmUgc2NvcmUgb24gZGF5IDIiLCB5ID0gIkRlbnNpdHkiKSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IG1lYW4oc2tld19kZiRkYXkyX2xvZywgbmEucm0gPSBUUlVFKSwgc2QgPSBzZChza2V3X2RmJGRheTJfbG9nLCBuYS5ybSA9IFRSVUUpKSwgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDEpCgpwcmludChoaXN0LmRheTJfbG9nKQpgYGAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpoaXN0LmRheTJfc3FydCA8LSBnZ3Bsb3Qoc2tld19kZiwgYWVzKGRheTJfc3FydCkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIsIGJpbnMgPSA0MCkgKyAKICBsYWJzKHggPSAiSHlnaWVuZSBzY29yZSBvbiBkYXkgMiIsIHkgPSAiRGVuc2l0eSIpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gbWVhbihza2V3X2RmJGRheTJfc3FydCwgbmEucm0gPSBUUlVFKSwgc2QgPSBzZChza2V3X2RmJGRheTJfc3FydCwgbmEucm0gPSBUUlVFKSksIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAxKQoKcHJpbnQoaGlzdC5kYXkyX3NxcnQpCmBgYAoKIyMjIyBDb25zaWRlcmF0aW9ucwoKU29tZXRpbWVzIHRyYW5zZm9ybWF0aW9ucyBjcmVhdGUgbW9yZSBwcm9ibGVtcyB0aGFuIHRoZXkgc29sdmUgKG5vdCBzaG93biwgYnV0IGRheSAxIHNjb3JlcyB3ZXJlIG5vcm1hbCwgYnV0IGhhdmUgYSBzbGlnaHQgc2tldyBhZnRlciB0aGUgdHJhbnNmb3JtYXRpb25zKS4gV2hhdCBhcmUgeW91ciBvdGhlciBvcHRpb25zIGZvciBub24tbm9ybWFsIGRhdGE/CiAgCiAgKiBOb24tcGFyYW1ldHJpYyB0ZXN0cwogICogQm9vdHN0cmFwcGluZwogICogRm9yIHplcm8taW5mbGF0ZWQgY291bnQgZGF0YSwgd2UgY2FuIHVzZSBwb2lzc29uIG9yIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVscwoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBSZXBsaWNhdGluZyBNYWRhbGluYSdzIFB5dGhvbiBjb2RlCgpgYGB7cn0KZGYgPC0gcmVhZF94bHN4KCIvVXNlcnMva2FyZWVuYWRlbHJvc2FyaW8vRG93bmxvYWRzL2RhdGEgKDEpLnhsc3giKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQojIENyZWF0ZSBhIHNpbXBsZSByZWdyZXNzaW9uIHBsb3QKZ2dwbG90KGRmLCBhZXMoeCA9IEFnZSwgeSA9IEJFTElFRmNjKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiI0MwNkM4NCIsIGFscGhhID0gMC4zKSArICMgU2NhdHRlciBwbG90CiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiIzdEMDU1MiIsIHNpemUgPSAxKSArICMgUmVncmVzc2lvbiBsaW5lCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiQmVsaWVmIGluIHNjaWVuY2UiKSArICMgTGFiZWwgdGhlIHggYW5kIHkgYXhpcwogIHRoZW1lX21pbmltYWwoKSArICMgVXNlIGEgbWluaW1hbCB0aGVtZQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgIyBSZW1vdmUgbGVnZW5kCgojIFNhdmUgZmlndXJlCiMgZ2dzYXZlKCJmaWd1cmUudGlmIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA0LCBkcGkgPSAzMDAsIHR5cGUgPSAiY2Fpcm8tcG5nIikKYGBgCgpgYGB7cn0KbWQgPC0gbG0oQkVMSUVGY2MgfiBBZ2UsIGRhdGEgPSBkZikKCnN1bW1hcnkobWQpCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmRmX3Bsb3QgPC0gZGYgJT4lIAogIG11dGF0ZShHZW5kZXIuZiA9IGNhc2Vfd2hlbigKICAgIEdlbmRlciA9PSAxIH4gIkZlbWFsZSIsCiAgICBHZW5kZXIgPT0gMiB+ICJNYWxlIikpICU+JQogIG11dGF0ZShHZW5kZXIuZiA9IGZhY3RvcihHZW5kZXIuZiwgbGV2ZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkpICU+JSAKICBmaWx0ZXIoIWlzLm5hKEdlbmRlci5mKSkKCmdncGxvdChkZl9wbG90LCBhZXMoeD1HZW5kZXIuZiwgeT1CRUxJRUZjYywgZmlsbCA9IEdlbmRlci5mKSkgKwogIGdlb21fYmFyKHN0YXQ9InN1bW1hcnkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB5bGltKDAsIDEwMCkgKwogIHRoZW1lX21pbmltYWwoKSArICMgT3B0aW9uYWw6IEFkZHMgYSBtaW5pbWFsIHRoZW1lIGZvciBhZXN0aGV0aWNzCiAgbGFicyh4PSJQYXJ0eSIsIHk9IlRydXN0IikgIyBMYWJlbGluZyBheGVzCmBgYAoKTnVtZXJpYyB2cyBDYXRlZ29yaWNhbCBQcmVkaWN0b3JzCmBgYHtyIGNhdGVnb3JpY2FsIHByZWRpY3RvcnN9CiMgTnVtZXJpYwpkZiRHZW5kZXIgPC0gYXMubnVtZXJpYyhkZiRHZW5kZXIpCm1vZGVsIDwtIGxtKEJFTElFRmNjIH4gQWdlICsgR2VuZGVyLCBkYXRhID0gZGYpCnN1bW1hcnkobW9kZWwpIApgYGAKCmBgYHtyfQojIEZhY3RvcgpkZiRHZW5kZXIgPC0gZmFjdG9yKGRmJEdlbmRlcikKbW9kZWwgPC0gbG0oQkVMSUVGY2MgfiBBZ2UgKyBHZW5kZXIsIGRhdGEgPSBkZikKc3VtbWFyeShtb2RlbCkgCmBgYAoKV2hhdCBpZiBJIHdhbnQgdG8gY2hhbmdlIHRoZSByZWZlcmVuY2UgZ3JvdXA/IEhvdyBjYW4gSSBkbyB0aGF0PwoKCgoK