1 Report Purpose and Dataset Description

This report completes the Week #4 multiple linear regression workflow using the Ames Housing data. The workflow includes:

  • creating an analytic dataset with engineered variables,
  • exploratory analysis,
  • a full multiple regression model with multicollinearity diagnostics (VIF),
  • Box–Cox transformation assessment,
  • stepwise AIC model selection,
  • goodness-of-fit comparison using \(R^2\), adjusted \(R^2\), Mallows’ \(C_p\), and PRESS,
  • and a final model with clean coefficient interpretation.

The response is:

  • Sale_Price (USD): home sale price.

2 Research Questions

  1. Which structural and amenity features most influence home sale prices?
  2. Do regression assumptions appear reasonable in the full model?
  3. Does a Box–Cox transformation improve assumption behavior?
  4. Can a reduced model improve stability by reducing multicollinearity?
  5. Which final model best balances interpretability and fit?

3 Data Preparation and Exploratory Analysis

3.1 Rationale

We construct a focused analytic dataset using interpretable predictors related to size, quality, age, and amenities. We also create engineered predictors that reduce redundancy and improve interpretability.

3.2 Import and Preview

housing <- AmesHousing::make_ames()
dim(housing)

[1] 2930 81

head(housing[, 1:6])

Interpretation.
The Ames dataset contains 2,930 homes and 81 variables. We will use a focused subset for regression to keep results interpretable.

3.3 Analytic Dataset and Engineered Variables

Engineered variables: - Total_Baths = Full + 0.5×Half (including basement baths)
- House_Age = max(Year_Built) − Year_Built
- Years_Since_Remod = max(Year_Remod_Add) − Year_Remod_Add

dat0 <- housing %>%
  dplyr::select(
    Sale_Price,
    Gr_Liv_Area, Total_Bsmt_SF, First_Flr_SF, Second_Flr_SF,
    Overall_Qual, Overall_Cond,
    Year_Built, Year_Remod_Add,
    Full_Bath, Half_Bath, Bsmt_Full_Bath, Bsmt_Half_Bath,
    Garage_Cars, Garage_Area,
    Fireplaces,
    Lot_Area, Mas_Vnr_Area
  ) %>%
  tidyr::drop_na(Sale_Price)

dat <- dat0 %>%
  mutate(
    Total_Baths = Full_Bath + 0.5 * Half_Bath + Bsmt_Full_Bath + 0.5 * Bsmt_Half_Bath,
    House_Age = max(Year_Built, na.rm = TRUE) - Year_Built,
    Years_Since_Remod = max(Year_Remod_Add, na.rm = TRUE) - Year_Remod_Add,
    Overall_Qual_S = as.numeric(Overall_Qual),
    Overall_Cond_S = as.numeric(Overall_Cond)
  ) %>%
  dplyr::select(
    Sale_Price,
    Gr_Liv_Area, Total_Bsmt_SF, First_Flr_SF, Second_Flr_SF,
    Overall_Qual_S, Overall_Cond_S,
    House_Age, Years_Since_Remod,
    Total_Baths, Garage_Cars, Garage_Area,
    Fireplaces, Lot_Area, Mas_Vnr_Area
  ) %>%
  drop_na()

dim(dat)

[1] 2930 15

pander::pander(head(dat), caption = "Preview of analytic dataset (first 6 rows).")
Preview of analytic dataset (first 6 rows). (continued below)
Sale_Price Gr_Liv_Area Total_Bsmt_SF First_Flr_SF Second_Flr_SF
215000 1656 1080 1656 0
105000 896 882 896 0
172000 1329 1329 1329 0
244000 2110 2110 2110 0
189900 1629 928 928 701
195500 1604 926 926 678
Table continues below
Overall_Qual_S Overall_Cond_S House_Age Years_Since_Remod Total_Baths
6 5 50 50 2
5 6 49 49 1
6 6 52 52 1.5
7 5 42 42 3.5
5 5 13 12 2.5
6 6 12 12 2.5
Garage_Cars Garage_Area Fireplaces Lot_Area Mas_Vnr_Area
2 528 2 31770 112
1 730 0 11622 0
1 312 0 14267 108
2 522 2 11160 0
2 482 1 13830 0
2 470 1 9978 20

Interpretation.
The analytic dataset contains 2,930 observations and 15 columns (Sale_Price + 14 predictors). The engineered variables summarize modernization and bathroom availability in an interpretable way.

3.4 Exploratory Relationships

set.seed(321)
small <- dat %>% dplyr::sample_n(min(1000, nrow(dat)))

GGally::ggpairs(
  dplyr::select(
    small,
    Sale_Price, Gr_Liv_Area, Total_Bsmt_SF,
    Overall_Qual_S, Total_Baths, Garage_Cars, Fireplaces
  )
)

Interpretation.
EDA shows strong positive relationships between sale price and size (living area, basement), overall quality, bathrooms, and amenities. Increasing spread at higher prices suggests mild heteroscedasticity.

4 Full Model and Diagnostics (Clean Output)

4.1 Rationale

We fit a full multiple regression model, then summarize results cleanly using: - a compact fit-statistics table, - a clean coefficient table (with CIs), - a VIF table for multicollinearity, - diagnostic plots.

4.2 Fit the Full Model

full_formula <- Sale_Price ~ Gr_Liv_Area + Total_Bsmt_SF +
  First_Flr_SF + Second_Flr_SF +
  Overall_Qual_S + Overall_Cond_S +
  House_Age + Years_Since_Remod +
  Total_Baths + Garage_Cars + Garage_Area +
  Fireplaces + Lot_Area + Mas_Vnr_Area

m_full <- lm(full_formula, data = dat)

4.2.1 Full Model Fit Statistics (Clean)

fit_full <- broom::glance(m_full) %>%
  dplyr::select(r.squared, adj.r.squared, sigma, statistic, p.value, df)

pander::pander(
  fit_full,
  caption = "Full Model: Key Fit Statistics"
)
Full Model: Key Fit Statistics
r.squared adj.r.squared sigma statistic p.value df
0.813 0.8121 34628 905.3 0 14

Interpretation (numeric).
The full model achieves Adjusted \(R^2 \approx 0.812\), meaning it explains about 81% of the variation in sale price. The overall F-test is highly significant (very small p-value), indicating the predictors jointly explain substantial variation in prices.

4.2.2 Full Model Coefficients (Clean)

coef_full <- broom::tidy(m_full, conf.int = TRUE) %>%
  dplyr::mutate(across(where(is.numeric), ~ round(.x, 4))) %>%
  dplyr::arrange(p.value)

pander::pander(
  coef_full,
  caption = "Full Model: Coefficients with 95% Confidence Intervals"
)
Full Model: Coefficients with 95% Confidence Intervals (continued below)
term estimate std.error statistic p.value conf.low
(Intercept) -77702 6299 -12.33 0 -90053
Total_Bsmt_SF 19.49 2.639 7.386 0 14.32
Overall_Qual_S 18168 771.2 23.56 0 16656
Overall_Cond_S 4595 683 6.728 0 3256
House_Age -263.7 37.36 -7.059 0 -337
Years_Since_Remod -243.3 44.72 -5.441 0 -331
Total_Baths 7264 1168 6.22 0 4974
Garage_Area 32.02 6.81 4.702 0 18.67
Fireplaces 8071 1174 6.874 0 5769
Lot_Area 0.5961 0.089 6.696 0 0.4216
Mas_Vnr_Area 38.17 4.181 9.128 0 29.97
First_Flr_SF 25.43 14.4 1.767 0.0774 -2.793
Gr_Liv_Area 21.89 14.03 1.56 0.1189 -5.623
Garage_Cars 2841 1982 1.434 0.1518 -1044
Second_Flr_SF 14.43 14.2 1.016 0.3097 -13.42
conf.high
-65350
24.67
19680
5934
-190.5
-155.6
9554
45.37
10373
0.7707
46.37
53.66
49.4
6727
42.28

Interpretation (numeric).
The full model typically identifies quality, bathrooms, basement size, fireplaces, and lot size as important predictors. However, interpretation of individual square-footage coefficients is unreliable if multicollinearity is severe.

4.3 Multicollinearity (VIF) — Clean

vif_full <- car::vif(m_full)
vif_tbl <- tibble::tibble(
  Predictor = names(vif_full),
  VIF = as.numeric(vif_full)
) %>%
  dplyr::arrange(desc(VIF)) %>%
  dplyr::mutate(VIF = round(VIF, 2))

pander::pander(vif_tbl, caption = "Full Model: VIF (Multicollinearity Diagnostic)")
Full Model: VIF (Multicollinearity Diagnostic)
Predictor VIF
Gr_Liv_Area 122.9
Second_Flr_SF 90.44
First_Flr_SF 77.75
Garage_Cars 5.56
Garage_Area 5.25
Total_Bsmt_SF 3.31
House_Age 3.12
Overall_Qual_S 2.89
Total_Baths 2.17
Years_Since_Remod 2.13
Fireplaces 1.41
Overall_Cond_S 1.41
Mas_Vnr_Area 1.36
Lot_Area 1.2

Interpretation (numeric).
Very large VIF values for square-footage variables indicate severe multicollinearity, inflating standard errors and making coefficients unstable. This motivates a reduced model via stepwise AIC.

4.4 Diagnostic Plots (Full Model)

op <- par(mfrow = c(2, 2))
plot(m_full)

par(op)

Interpretation (visual).
Diagnostics show mild heteroscedasticity (increasing spread at higher fitted values) and some tail departure in the Q–Q plot. This motivates assessing a Box–Cox transformation of the response.

5 Box–Cox Transformation (Clean Output)

5.1 Rationale

Box–Cox searches for a power transformation of the response that improves normality and stabilizes variance. The chosen \(\lambda\) maximizes the likelihood.

5.2 Lambda Selection

bc <- MASS::boxcox(m_full, lambda = seq(-1, 1, by = 0.05), plotit = TRUE)

lambda_hat <- bc$x[which.max(bc$y)]
lambda_hat

[1] 0.1515152

Interpretation (numeric).
A \(\lambda\) near 0 indicates a log-type transformation; \(\lambda\) near 1 indicates no transformation. Here, \(\lambda\) is typically near 0.15, suggesting a mild power transform consistent with price data.

5.3 Fit Box–Cox Model (Clean)

y <- dat$Sale_Price
eps <- ifelse(any(y <= 0), 1, 0)

y_bc <- if (abs(lambda_hat) < 1e-8) log(y + eps) else ((y + eps)^lambda_hat - 1) / lambda_hat

m_bc <- lm(
  y_bc ~ Gr_Liv_Area + Total_Bsmt_SF + First_Flr_SF + Second_Flr_SF +
    Overall_Qual_S + Overall_Cond_S + House_Age + Years_Since_Remod +
    Total_Baths + Garage_Cars + Garage_Area + Fireplaces +
    Lot_Area + Mas_Vnr_Area,
  data = dat
)

5.3.1 Box–Cox Fit Statistics (Clean)

fit_bc <- broom::glance(m_bc) %>%
  dplyr::select(r.squared, adj.r.squared, sigma, statistic, p.value, df)

pander::pander(
  fit_bc,
  caption = "Box–Cox Model: Key Fit Statistics (Transformed Response)"
)
Box–Cox Model: Key Fit Statistics (Transformed Response)
r.squared adj.r.squared sigma statistic p.value df
0.8671 0.8664 0.9242 1358 0 14

Interpretation (numeric).
The Box–Cox model often increases adjusted \(R^2\) relative to the untransformed models (commonly around 0.866). This indicates better fit on the transformed scale and typically improves residual behavior, but coefficients are harder to interpret in dollars.

5.3.2 Diagnostics (Box–Cox)

op <- par(mfrow = c(2, 2))
plot(m_bc)

par(op)

Interpretation (visual).
Residual patterns often look more stable (less fanning) and the Q–Q plot aligns more closely with normality. However, interpretability is reduced since the response is transformed.

6 Stepwise AIC Model and Model Comparison (Clean Output)

6.1 Rationale

We use stepwise AIC to reduce redundancy and multicollinearity while keeping the response in dollars. We compare the full and stepwise models using \(R^2\), adjusted \(R^2\), Mallows’ \(C_p\), and PRESS.

6.2 Stepwise AIC Model

m_step <- MASS::stepAIC(m_full, trace = FALSE)

6.2.1 Stepwise Fit Statistics (Clean)

fit_step <- broom::glance(m_step) %>%
  dplyr::select(r.squared, adj.r.squared, sigma, statistic, p.value, df)

pander::pander(
  fit_step,
  caption = "Stepwise AIC Model: Key Fit Statistics"
)
Stepwise AIC Model: Key Fit Statistics
r.squared adj.r.squared sigma statistic p.value df
0.8129 0.8121 34628 974.8 0 13

Interpretation (numeric).
The stepwise model maintains essentially the same adjusted \(R^2\) as the full model while using fewer predictors, supporting a simpler model with similar explanatory power.

6.2.2 Stepwise Coefficients (Clean)

coef_step <- broom::tidy(m_step, conf.int = TRUE) %>%
  dplyr::mutate(across(where(is.numeric), ~ round(.x, 4))) %>%
  dplyr::arrange(p.value)

pander::pander(
  coef_step,
  caption = "Stepwise AIC Model: Coefficients with 95% Confidence Intervals"
)
Stepwise AIC Model: Coefficients with 95% Confidence Intervals (continued below)
term estimate std.error statistic p.value conf.low
(Intercept) -77725 6299 -12.34 0 -90077
Gr_Liv_Area 35.99 2.063 17.44 0 31.94
Total_Bsmt_SF 19.38 2.637 7.35 0 14.21
Overall_Qual_S 18180 771.1 23.58 0 16668
Overall_Cond_S 4626 682.3 6.781 0 3288
House_Age -267 37.23 -7.172 0 -340
Years_Since_Remod -242.3 44.71 -5.42 0 -329.9
Total_Baths 7324 1166 6.28 0 5037
Garage_Area 31.99 6.81 4.698 0 18.64
Fireplaces 8092 1174 6.893 0 5790
Lot_Area 0.5982 0.089 6.721 0 0.4237
Mas_Vnr_Area 38.41 4.175 9.2 0 30.22
First_Flr_SF 11.14 3.063 3.639 3e-04 5.138
Garage_Cars 2887 1981 1.458 0.1451 -997.1
conf.high
-65373
40.03
24.55
19692
5964
-194
-154.6
9611
45.34
10394
0.7727
46.59
17.15
6772

6.2.3 Stepwise VIF (Clean)

vif_step <- car::vif(m_step)
vif_step_tbl <- tibble::tibble(
  Predictor = names(vif_step),
  VIF = as.numeric(vif_step)
) %>%
  dplyr::arrange(desc(VIF)) %>%
  dplyr::mutate(VIF = round(VIF, 2))

pander::pander(vif_step_tbl, caption = "Stepwise AIC Model: VIF")
Stepwise AIC Model: VIF
Predictor VIF
Garage_Cars 5.55
Garage_Area 5.25
First_Flr_SF 3.52
Total_Bsmt_SF 3.3
House_Age 3.1
Overall_Qual_S 2.89
Gr_Liv_Area 2.66
Total_Baths 2.17
Years_Since_Remod 2.12
Fireplaces 1.41
Overall_Cond_S 1.4
Mas_Vnr_Area 1.36
Lot_Area 1.2

Interpretation (numeric).
VIF values drop substantially relative to the full model, indicating improved coefficient stability and reduced multicollinearity (especially among square footage predictors).

6.3 Goodness-of-Fit Comparison: Full vs Stepwise (Cp and PRESS)

gof_table <- function(m, mse_full, n){
  e   <- resid(m)
  SSE <- sum(e^2)
  R2    <- summary(m)$r.squared
  R2adj <- summary(m)$adj.r.squared
  p     <- length(coef(m))

  Cp    <- SSE/mse_full - (n - 2 * p)

  X <- model.matrix(m)
  H <- X %*% solve(t(X) %*% X) %*% t(X)
  d <- e/(1 - diag(H))
  PRESS <- sum(d^2)

  tibble::tibble(
    SSE = SSE, R2 = R2, R2_Adj = R2adj,
    Cp = Cp, PRESS = PRESS, p = p
  )
}

n <- nobs(m_full)
mse_full <- mean(resid(m_full)^2)

gof <- dplyr::bind_rows(
  Full     = gof_table(m_full, mse_full, n) %>% mutate(Model = "Full"),
  Stepwise = gof_table(m_step, mse_full, n) %>% mutate(Model = "Stepwise AIC")
) %>%
  relocate(Model) %>%
  mutate(across(where(is.numeric), ~ round(.x, 3)))

pander::pander(gof, caption = "Goodness-of-Fit: Full vs Stepwise (R2, Adj R2, Cp, PRESS)")
Goodness-of-Fit: Full vs Stepwise (R2, Adj R2, Cp, PRESS)
Model SSE R2 R2_Adj Cp PRESS p
Full 3.495e+12 0.813 0.812 30 3.629e+12 15
Stepwise AIC 3.497e+12 0.813 0.812 29.04 3.626e+12 14

Interpretation (numeric).
If the stepwise model matches the full model on adjusted \(R^2\) and PRESS while using fewer predictors and lower VIF, it is preferred for interpretability and stability. Cp close to the number of parameters supports appropriate model complexity.

7 Final Model and Interpretation (Clean Output)

7.1 Final Model Choice

We choose the stepwise AIC model as the final model because it: - preserves interpretability in dollars, - maintains essentially identical fit to the full model, - and reduces multicollinearity substantially.

m_final <- m_step

7.2 Final Diagnostics

op <- par(mfrow = c(2, 2))
plot(m_final)

par(op)

Interpretation (visual).
The final model diagnostics are acceptable for regression inference, with mild heteroscedasticity but strong overall fit. Reduced multicollinearity improves coefficient stability compared to the full model.

7.3 Key Coefficient Interpretations (Clean Summary Table)

key_terms <- c("Overall_Qual_S","Total_Baths","House_Age","Years_Since_Remod",
               "Fireplaces","Gr_Liv_Area","Garage_Area","Mas_Vnr_Area","Lot_Area")

key_tbl <- broom::tidy(m_final, conf.int = TRUE) %>%
  dplyr::filter(term %in% key_terms) %>%
  dplyr::mutate(across(where(is.numeric), ~ round(.x, 3))) %>%
  dplyr::arrange(desc(abs(estimate)))

pander::pander(key_tbl, caption = "Final Model: Selected Key Coefficients (Dollar Scale)")
Final Model: Selected Key Coefficients (Dollar Scale) (continued below)
term estimate std.error statistic p.value conf.low
Overall_Qual_S 18180 771.1 23.58 0 16668
Fireplaces 8092 1174 6.893 0 5790
Total_Baths 7324 1166 6.28 0 5037
House_Age -267 37.23 -7.172 0 -340
Years_Since_Remod -242.3 44.7 -5.42 0 -329.9
Mas_Vnr_Area 38.41 4.175 9.2 0 30.22
Gr_Liv_Area 35.99 2.063 17.44 0 31.94
Garage_Area 31.99 6.81 4.698 0 18.64
Lot_Area 0.598 0.089 6.721 0 0.424
conf.high
19692
10394
9611
-194
-154.6
46.59
40.03
45.34
0.773

Interpretation (numeric).
Interpret coefficients as “holding all else constant.” For example: - Overall_Qual_S indicates the dollar premium per 1-unit increase in quality rating. - Total_Baths indicates the dollar premium per additional effective bathroom. - House_Age and Years_Since_Remod show depreciation and remodeling effects (negative values). - Gr_Liv_Area, Garage_Area, and Mas_Vnr_Area represent size/amenity premiums per square foot.

8 Conclusions and Future Work

8.1 Conclusions

The final model indicates that Ames home sale prices are strongly driven by: - overall quality, - living area and basement size, - total bathrooms, - amenities (fireplaces and garage area), - and modernity (age and time since remodel).

8.2 Model Choice Summary

Box–Cox improves assumption behavior and increases adjusted \(R^2\) on a transformed scale, but reduces interpretability. The stepwise AIC model retains dollar-scale interpretation, substantially lowers multicollinearity, and preserves predictive fit compared to the full model. Therefore, stepwise AIC is the preferred final model for this assignment.

8.3 Limitations and Future Work

This analysis does not include neighborhood/location variables, which are often major drivers of price. Future work could incorporate spatial predictors and explore nonlinear models (splines, tree-based methods) with validation through cross-validation or a train/test split.

LS0tDQp0aXRsZTogIkludmVzdGlhdGluZyB0aGUgQW1lcyBIb3VzaW5nIE1hcmtldCB3aXRoIE11bHRpcGxlIFJlZ3Jlc3Npb24iDQphdXRob3I6ICJSeWFuIEdvcm1hbiINCmRhdGU6ICIyMDI1LTA5LTIyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQpoMS50aXRsZSB7IGZvbnQtc2l6ZTogMjRweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiBEYXJrUmVkOyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsgfQ0KaDQuYXV0aG9yIHsgZm9udC1zaXplOiAyMHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6IERhcmtSZWQ7IHRleHQtYWxpZ246IGNlbnRlcjsgfQ0KaDQuZGF0ZSB7IGZvbnQtc2l6ZTogMThweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiBEYXJrQmx1ZTsgdGV4dC1hbGlnbjogY2VudGVyOyB9DQoNCmgxIHsgZm9udC1zaXplOiAyMnB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6IG5hdnk7IHRleHQtYWxpZ246IGxlZnQ7IH0NCmgyIHsgZm9udC1zaXplOiAyMHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6IG5hdnk7IHRleHQtYWxpZ246IGxlZnQ7IH0NCmgzIHsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6IG5hdnk7IHRleHQtYWxpZ246IGxlZnQ7IH0NCmg0IHsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6IGRhcmtyZWQ7IHRleHQtYWxpZ246IGxlZnQ7IH0NCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KPC9zdHlsZT4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCg0KbmVlZGVkIDwtIGMoImtuaXRyIiwidGlkeXZlcnNlIiwiQW1lc0hvdXNpbmciLCJHR2FsbHkiLCJNQVNTIiwiY2FyIiwiYnJvb20iLCJwYW5kZXIiKQ0KDQpmb3IgKHAgaW4gbmVlZGVkKSB7DQogIGlmICghcmVxdWlyZShwLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcyhwLCByZXBvcyA9ICJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKQ0KICAgIGxpYnJhcnkocCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KICB9DQp9DQoNCnNldC5zZWVkKDMyMSkNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvICAgID0gVFJVRSwNCiAgd2FybmluZyA9IEZBTFNFLA0KICBtZXNzYWdlID0gRkFMU0UsDQogIHJlc3VsdHMgPSAiYXNpcyIsDQogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLA0KICBmaWcucG9zICA9ICJodCINCikNCmBgYA0KDQoNCiMgIFJlcG9ydCBQdXJwb3NlIGFuZCBEYXRhc2V0IERlc2NyaXB0aW9uDQoNClRoaXMgcmVwb3J0IGNvbXBsZXRlcyB0aGUgV2VlayAjNCBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiB3b3JrZmxvdyB1c2luZyB0aGUgKipBbWVzIEhvdXNpbmcqKiBkYXRhLiBUaGUgd29ya2Zsb3cgaW5jbHVkZXM6DQoNCi0gY3JlYXRpbmcgYW4gYW5hbHl0aWMgZGF0YXNldCB3aXRoIGVuZ2luZWVyZWQgdmFyaWFibGVzLCAgDQotIGV4cGxvcmF0b3J5IGFuYWx5c2lzLCAgDQotIGEgZnVsbCBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIHdpdGggbXVsdGljb2xsaW5lYXJpdHkgZGlhZ25vc3RpY3MgKFZJRiksICANCi0gQm944oCTQ294IHRyYW5zZm9ybWF0aW9uIGFzc2Vzc21lbnQsICANCi0gc3RlcHdpc2UgQUlDIG1vZGVsIHNlbGVjdGlvbiwgIA0KLSBnb29kbmVzcy1vZi1maXQgY29tcGFyaXNvbiB1c2luZyBcKFJeMlwpLCBhZGp1c3RlZCBcKFJeMlwpLCBNYWxsb3dz4oCZIFwoQ19wXCksIGFuZCBQUkVTUywgIA0KLSBhbmQgYSBmaW5hbCBtb2RlbCB3aXRoIGNsZWFuIGNvZWZmaWNpZW50IGludGVycHJldGF0aW9uLg0KDQpUaGUgcmVzcG9uc2UgaXM6DQoNCi0gKipTYWxlX1ByaWNlIChVU0QpKio6IGhvbWUgc2FsZSBwcmljZS4NCg0KIyAgUmVzZWFyY2ggUXVlc3Rpb25zDQoNCjEuIFdoaWNoIHN0cnVjdHVyYWwgYW5kIGFtZW5pdHkgZmVhdHVyZXMgbW9zdCBpbmZsdWVuY2UgaG9tZSBzYWxlIHByaWNlcz8gIA0KMi4gRG8gcmVncmVzc2lvbiBhc3N1bXB0aW9ucyBhcHBlYXIgcmVhc29uYWJsZSBpbiB0aGUgZnVsbCBtb2RlbD8gIA0KMy4gRG9lcyBhIEJveOKAk0NveCB0cmFuc2Zvcm1hdGlvbiBpbXByb3ZlIGFzc3VtcHRpb24gYmVoYXZpb3I/ICANCjQuIENhbiBhIHJlZHVjZWQgbW9kZWwgaW1wcm92ZSBzdGFiaWxpdHkgYnkgcmVkdWNpbmcgbXVsdGljb2xsaW5lYXJpdHk/ICANCjUuIFdoaWNoIGZpbmFsIG1vZGVsIGJlc3QgYmFsYW5jZXMgaW50ZXJwcmV0YWJpbGl0eSBhbmQgZml0Pw0KDQojICBEYXRhIFByZXBhcmF0aW9uIGFuZCBFeHBsb3JhdG9yeSBBbmFseXNpcw0KDQojIyAgUmF0aW9uYWxlDQoNCldlIGNvbnN0cnVjdCBhIGZvY3VzZWQgYW5hbHl0aWMgZGF0YXNldCB1c2luZyBpbnRlcnByZXRhYmxlIHByZWRpY3RvcnMgcmVsYXRlZCB0byBzaXplLCBxdWFsaXR5LCBhZ2UsIGFuZCBhbWVuaXRpZXMuIFdlIGFsc28gY3JlYXRlIGVuZ2luZWVyZWQgcHJlZGljdG9ycyB0aGF0IHJlZHVjZSByZWR1bmRhbmN5IGFuZCBpbXByb3ZlIGludGVycHJldGFiaWxpdHkuDQoNCiMjICBJbXBvcnQgYW5kIFByZXZpZXcNCg0KYGBge3IgaW1wb3J0LXByZXZpZXd9DQpob3VzaW5nIDwtIEFtZXNIb3VzaW5nOjptYWtlX2FtZXMoKQ0KZGltKGhvdXNpbmcpDQpoZWFkKGhvdXNpbmdbLCAxOjZdKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb24uKiogIA0KVGhlIEFtZXMgZGF0YXNldCBjb250YWlucyAqKjIsOTMwKiogaG9tZXMgYW5kICoqODEqKiB2YXJpYWJsZXMuIFdlIHdpbGwgdXNlIGEgZm9jdXNlZCBzdWJzZXQgZm9yIHJlZ3Jlc3Npb24gdG8ga2VlcCByZXN1bHRzIGludGVycHJldGFibGUuDQoNCiMjICBBbmFseXRpYyBEYXRhc2V0IGFuZCBFbmdpbmVlcmVkIFZhcmlhYmxlcw0KDQpFbmdpbmVlcmVkIHZhcmlhYmxlczoNCi0gKipUb3RhbF9CYXRocyoqID0gRnVsbCArIDAuNcOXSGFsZiAoaW5jbHVkaW5nIGJhc2VtZW50IGJhdGhzKSAgDQotICoqSG91c2VfQWdlKiogPSBtYXgoWWVhcl9CdWlsdCkg4oiSIFllYXJfQnVpbHQgIA0KLSAqKlllYXJzX1NpbmNlX1JlbW9kKiogPSBtYXgoWWVhcl9SZW1vZF9BZGQpIOKIkiBZZWFyX1JlbW9kX0FkZCAgDQoNCmBgYHtyIGFuYWx5dGljLWRhdGF9DQpkYXQwIDwtIGhvdXNpbmcgJT4lDQogIGRwbHlyOjpzZWxlY3QoDQogICAgU2FsZV9QcmljZSwNCiAgICBHcl9MaXZfQXJlYSwgVG90YWxfQnNtdF9TRiwgRmlyc3RfRmxyX1NGLCBTZWNvbmRfRmxyX1NGLA0KICAgIE92ZXJhbGxfUXVhbCwgT3ZlcmFsbF9Db25kLA0KICAgIFllYXJfQnVpbHQsIFllYXJfUmVtb2RfQWRkLA0KICAgIEZ1bGxfQmF0aCwgSGFsZl9CYXRoLCBCc210X0Z1bGxfQmF0aCwgQnNtdF9IYWxmX0JhdGgsDQogICAgR2FyYWdlX0NhcnMsIEdhcmFnZV9BcmVhLA0KICAgIEZpcmVwbGFjZXMsDQogICAgTG90X0FyZWEsIE1hc19WbnJfQXJlYQ0KICApICU+JQ0KICB0aWR5cjo6ZHJvcF9uYShTYWxlX1ByaWNlKQ0KDQpkYXQgPC0gZGF0MCAlPiUNCiAgbXV0YXRlKA0KICAgIFRvdGFsX0JhdGhzID0gRnVsbF9CYXRoICsgMC41ICogSGFsZl9CYXRoICsgQnNtdF9GdWxsX0JhdGggKyAwLjUgKiBCc210X0hhbGZfQmF0aCwNCiAgICBIb3VzZV9BZ2UgPSBtYXgoWWVhcl9CdWlsdCwgbmEucm0gPSBUUlVFKSAtIFllYXJfQnVpbHQsDQogICAgWWVhcnNfU2luY2VfUmVtb2QgPSBtYXgoWWVhcl9SZW1vZF9BZGQsIG5hLnJtID0gVFJVRSkgLSBZZWFyX1JlbW9kX0FkZCwNCiAgICBPdmVyYWxsX1F1YWxfUyA9IGFzLm51bWVyaWMoT3ZlcmFsbF9RdWFsKSwNCiAgICBPdmVyYWxsX0NvbmRfUyA9IGFzLm51bWVyaWMoT3ZlcmFsbF9Db25kKQ0KICApICU+JQ0KICBkcGx5cjo6c2VsZWN0KA0KICAgIFNhbGVfUHJpY2UsDQogICAgR3JfTGl2X0FyZWEsIFRvdGFsX0JzbXRfU0YsIEZpcnN0X0Zscl9TRiwgU2Vjb25kX0Zscl9TRiwNCiAgICBPdmVyYWxsX1F1YWxfUywgT3ZlcmFsbF9Db25kX1MsDQogICAgSG91c2VfQWdlLCBZZWFyc19TaW5jZV9SZW1vZCwNCiAgICBUb3RhbF9CYXRocywgR2FyYWdlX0NhcnMsIEdhcmFnZV9BcmVhLA0KICAgIEZpcmVwbGFjZXMsIExvdF9BcmVhLCBNYXNfVm5yX0FyZWENCiAgKSAlPiUNCiAgZHJvcF9uYSgpDQoNCmRpbShkYXQpDQpwYW5kZXI6OnBhbmRlcihoZWFkKGRhdCksIGNhcHRpb24gPSAiUHJldmlldyBvZiBhbmFseXRpYyBkYXRhc2V0IChmaXJzdCA2IHJvd3MpLiIpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbi4qKiAgDQpUaGUgYW5hbHl0aWMgZGF0YXNldCBjb250YWlucyAqKjIsOTMwIG9ic2VydmF0aW9ucyBhbmQgMTUgY29sdW1ucyoqIChTYWxlX1ByaWNlICsgMTQgcHJlZGljdG9ycykuIFRoZSBlbmdpbmVlcmVkIHZhcmlhYmxlcyBzdW1tYXJpemUgbW9kZXJuaXphdGlvbiBhbmQgYmF0aHJvb20gYXZhaWxhYmlsaXR5IGluIGFuIGludGVycHJldGFibGUgd2F5Lg0KDQojIyAgRXhwbG9yYXRvcnkgUmVsYXRpb25zaGlwcw0KDQpgYGB7ciBlZGEtZ2dwYWlyc30NCnNldC5zZWVkKDMyMSkNCnNtYWxsIDwtIGRhdCAlPiUgZHBseXI6OnNhbXBsZV9uKG1pbigxMDAwLCBucm93KGRhdCkpKQ0KDQpHR2FsbHk6OmdncGFpcnMoDQogIGRwbHlyOjpzZWxlY3QoDQogICAgc21hbGwsDQogICAgU2FsZV9QcmljZSwgR3JfTGl2X0FyZWEsIFRvdGFsX0JzbXRfU0YsDQogICAgT3ZlcmFsbF9RdWFsX1MsIFRvdGFsX0JhdGhzLCBHYXJhZ2VfQ2FycywgRmlyZXBsYWNlcw0KICApDQopDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbi4qKiAgDQpFREEgc2hvd3Mgc3Ryb25nIHBvc2l0aXZlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzYWxlIHByaWNlIGFuZCBzaXplIChsaXZpbmcgYXJlYSwgYmFzZW1lbnQpLCBvdmVyYWxsIHF1YWxpdHksIGJhdGhyb29tcywgYW5kIGFtZW5pdGllcy4gSW5jcmVhc2luZyBzcHJlYWQgYXQgaGlnaGVyIHByaWNlcyBzdWdnZXN0cyBtaWxkIGhldGVyb3NjZWRhc3RpY2l0eS4NCg0KIyAgRnVsbCBNb2RlbCBhbmQgRGlhZ25vc3RpY3MgKENsZWFuIE91dHB1dCkNCg0KIyMgIFJhdGlvbmFsZQ0KDQpXZSBmaXQgYSBmdWxsIG11bHRpcGxlIHJlZ3Jlc3Npb24gbW9kZWwsIHRoZW4gc3VtbWFyaXplIHJlc3VsdHMgY2xlYW5seSB1c2luZzoNCi0gYSBjb21wYWN0IGZpdC1zdGF0aXN0aWNzIHRhYmxlLA0KLSBhIGNsZWFuIGNvZWZmaWNpZW50IHRhYmxlICh3aXRoIENJcyksDQotIGEgVklGIHRhYmxlIGZvciBtdWx0aWNvbGxpbmVhcml0eSwNCi0gZGlhZ25vc3RpYyBwbG90cy4NCg0KIyMgIEZpdCB0aGUgRnVsbCBNb2RlbA0KDQpgYGB7ciBmdWxsLW1vZGVsLWZpdCwgcmVzdWx0cz0naGlkZSd9DQpmdWxsX2Zvcm11bGEgPC0gU2FsZV9QcmljZSB+IEdyX0xpdl9BcmVhICsgVG90YWxfQnNtdF9TRiArDQogIEZpcnN0X0Zscl9TRiArIFNlY29uZF9GbHJfU0YgKw0KICBPdmVyYWxsX1F1YWxfUyArIE92ZXJhbGxfQ29uZF9TICsNCiAgSG91c2VfQWdlICsgWWVhcnNfU2luY2VfUmVtb2QgKw0KICBUb3RhbF9CYXRocyArIEdhcmFnZV9DYXJzICsgR2FyYWdlX0FyZWEgKw0KICBGaXJlcGxhY2VzICsgTG90X0FyZWEgKyBNYXNfVm5yX0FyZWENCg0KbV9mdWxsIDwtIGxtKGZ1bGxfZm9ybXVsYSwgZGF0YSA9IGRhdCkNCmBgYA0KDQojIyMgIEZ1bGwgTW9kZWwgRml0IFN0YXRpc3RpY3MgKENsZWFuKQ0KDQpgYGB7ciBmdWxsLW1vZGVsLWdsYW5jZX0NCmZpdF9mdWxsIDwtIGJyb29tOjpnbGFuY2UobV9mdWxsKSAlPiUNCiAgZHBseXI6OnNlbGVjdChyLnNxdWFyZWQsIGFkai5yLnNxdWFyZWQsIHNpZ21hLCBzdGF0aXN0aWMsIHAudmFsdWUsIGRmKQ0KDQpwYW5kZXI6OnBhbmRlcigNCiAgZml0X2Z1bGwsDQogIGNhcHRpb24gPSAiRnVsbCBNb2RlbDogS2V5IEZpdCBTdGF0aXN0aWNzIg0KKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb24gKG51bWVyaWMpLioqICANClRoZSBmdWxsIG1vZGVsIGFjaGlldmVzICoqQWRqdXN0ZWQgXChSXjIgXGFwcHJveCAwLjgxMlwpKiosIG1lYW5pbmcgaXQgZXhwbGFpbnMgYWJvdXQgKio4MSUqKiBvZiB0aGUgdmFyaWF0aW9uIGluIHNhbGUgcHJpY2UuIFRoZSBvdmVyYWxsIEYtdGVzdCBpcyBoaWdobHkgc2lnbmlmaWNhbnQgKHZlcnkgc21hbGwgcC12YWx1ZSksIGluZGljYXRpbmcgdGhlIHByZWRpY3RvcnMgam9pbnRseSBleHBsYWluIHN1YnN0YW50aWFsIHZhcmlhdGlvbiBpbiBwcmljZXMuDQoNCiMjIyAgRnVsbCBNb2RlbCBDb2VmZmljaWVudHMgKENsZWFuKQ0KDQpgYGB7ciBmdWxsLW1vZGVsLXRpZHl9DQpjb2VmX2Z1bGwgPC0gYnJvb206OnRpZHkobV9mdWxsLCBjb25mLmludCA9IFRSVUUpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiByb3VuZCgueCwgNCkpKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UocC52YWx1ZSkNCg0KcGFuZGVyOjpwYW5kZXIoDQogIGNvZWZfZnVsbCwNCiAgY2FwdGlvbiA9ICJGdWxsIE1vZGVsOiBDb2VmZmljaWVudHMgd2l0aCA5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbHMiDQopDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbiAobnVtZXJpYykuKiogIA0KVGhlIGZ1bGwgbW9kZWwgdHlwaWNhbGx5IGlkZW50aWZpZXMgcXVhbGl0eSwgYmF0aHJvb21zLCBiYXNlbWVudCBzaXplLCBmaXJlcGxhY2VzLCBhbmQgbG90IHNpemUgYXMgaW1wb3J0YW50IHByZWRpY3RvcnMuIEhvd2V2ZXIsIGludGVycHJldGF0aW9uIG9mIGluZGl2aWR1YWwgc3F1YXJlLWZvb3RhZ2UgY29lZmZpY2llbnRzIGlzIHVucmVsaWFibGUgaWYgbXVsdGljb2xsaW5lYXJpdHkgaXMgc2V2ZXJlLg0KDQojIyAgTXVsdGljb2xsaW5lYXJpdHkgKFZJRikg4oCUIENsZWFuDQoNCmBgYHtyIHZpZi1mdWxsLWNsZWFufQ0KdmlmX2Z1bGwgPC0gY2FyOjp2aWYobV9mdWxsKQ0KdmlmX3RibCA8LSB0aWJibGU6OnRpYmJsZSgNCiAgUHJlZGljdG9yID0gbmFtZXModmlmX2Z1bGwpLA0KICBWSUYgPSBhcy5udW1lcmljKHZpZl9mdWxsKQ0KKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhWSUYpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShWSUYgPSByb3VuZChWSUYsIDIpKQ0KDQpwYW5kZXI6OnBhbmRlcih2aWZfdGJsLCBjYXB0aW9uID0gIkZ1bGwgTW9kZWw6IFZJRiAoTXVsdGljb2xsaW5lYXJpdHkgRGlhZ25vc3RpYykiKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb24gKG51bWVyaWMpLioqICANClZlcnkgbGFyZ2UgVklGIHZhbHVlcyBmb3Igc3F1YXJlLWZvb3RhZ2UgdmFyaWFibGVzIGluZGljYXRlIHNldmVyZSBtdWx0aWNvbGxpbmVhcml0eSwgaW5mbGF0aW5nIHN0YW5kYXJkIGVycm9ycyBhbmQgbWFraW5nIGNvZWZmaWNpZW50cyB1bnN0YWJsZS4gVGhpcyBtb3RpdmF0ZXMgYSByZWR1Y2VkIG1vZGVsIHZpYSBzdGVwd2lzZSBBSUMuDQoNCiMjICBEaWFnbm9zdGljIFBsb3RzIChGdWxsIE1vZGVsKQ0KDQpgYGB7ciBmdWxsLWRpYWdub3N0aWNzfQ0Kb3AgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkNCnBsb3QobV9mdWxsKQ0KcGFyKG9wKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb24gKHZpc3VhbCkuKiogIA0KRGlhZ25vc3RpY3Mgc2hvdyBtaWxkIGhldGVyb3NjZWRhc3RpY2l0eSAoaW5jcmVhc2luZyBzcHJlYWQgYXQgaGlnaGVyIGZpdHRlZCB2YWx1ZXMpIGFuZCBzb21lIHRhaWwgZGVwYXJ0dXJlIGluIHRoZSBR4oCTUSBwbG90LiBUaGlzIG1vdGl2YXRlcyBhc3Nlc3NpbmcgYSBCb3jigJNDb3ggdHJhbnNmb3JtYXRpb24gb2YgdGhlIHJlc3BvbnNlLg0KDQojICBCb3jigJNDb3ggVHJhbnNmb3JtYXRpb24gKENsZWFuIE91dHB1dCkNCg0KIyMgIFJhdGlvbmFsZQ0KDQpCb3jigJNDb3ggc2VhcmNoZXMgZm9yIGEgcG93ZXIgdHJhbnNmb3JtYXRpb24gb2YgdGhlIHJlc3BvbnNlIHRoYXQgaW1wcm92ZXMgbm9ybWFsaXR5IGFuZCBzdGFiaWxpemVzIHZhcmlhbmNlLiBUaGUgY2hvc2VuIFwoXGxhbWJkYVwpIG1heGltaXplcyB0aGUgbGlrZWxpaG9vZC4NCg0KIyMgIExhbWJkYSBTZWxlY3Rpb24NCg0KYGBge3IgYm94Y294LWxhbWJkYX0NCmJjIDwtIE1BU1M6OmJveGNveChtX2Z1bGwsIGxhbWJkYSA9IHNlcSgtMSwgMSwgYnkgPSAwLjA1KSwgcGxvdGl0ID0gVFJVRSkNCmxhbWJkYV9oYXQgPC0gYmMkeFt3aGljaC5tYXgoYmMkeSldDQpsYW1iZGFfaGF0DQpgYGANCg0KKipJbnRlcnByZXRhdGlvbiAobnVtZXJpYykuKiogIA0KQSBcKFxsYW1iZGFcKSBuZWFyIDAgaW5kaWNhdGVzIGEgbG9nLXR5cGUgdHJhbnNmb3JtYXRpb247IFwoXGxhbWJkYVwpIG5lYXIgMSBpbmRpY2F0ZXMgbm8gdHJhbnNmb3JtYXRpb24uIEhlcmUsIFwoXGxhbWJkYVwpIGlzIHR5cGljYWxseSBuZWFyICoqMC4xNSoqLCBzdWdnZXN0aW5nIGEgbWlsZCBwb3dlciB0cmFuc2Zvcm0gY29uc2lzdGVudCB3aXRoIHByaWNlIGRhdGEuDQoNCiMjICBGaXQgQm944oCTQ294IE1vZGVsIChDbGVhbikNCg0KYGBge3IgYm94Y294LWZpdCwgcmVzdWx0cz0naGlkZSd9DQp5IDwtIGRhdCRTYWxlX1ByaWNlDQplcHMgPC0gaWZlbHNlKGFueSh5IDw9IDApLCAxLCAwKQ0KDQp5X2JjIDwtIGlmIChhYnMobGFtYmRhX2hhdCkgPCAxZS04KSBsb2coeSArIGVwcykgZWxzZSAoKHkgKyBlcHMpXmxhbWJkYV9oYXQgLSAxKSAvIGxhbWJkYV9oYXQNCg0KbV9iYyA8LSBsbSgNCiAgeV9iYyB+IEdyX0xpdl9BcmVhICsgVG90YWxfQnNtdF9TRiArIEZpcnN0X0Zscl9TRiArIFNlY29uZF9GbHJfU0YgKw0KICAgIE92ZXJhbGxfUXVhbF9TICsgT3ZlcmFsbF9Db25kX1MgKyBIb3VzZV9BZ2UgKyBZZWFyc19TaW5jZV9SZW1vZCArDQogICAgVG90YWxfQmF0aHMgKyBHYXJhZ2VfQ2FycyArIEdhcmFnZV9BcmVhICsgRmlyZXBsYWNlcyArDQogICAgTG90X0FyZWEgKyBNYXNfVm5yX0FyZWEsDQogIGRhdGEgPSBkYXQNCikNCmBgYA0KDQojIyMgIEJveOKAk0NveCBGaXQgU3RhdGlzdGljcyAoQ2xlYW4pDQoNCmBgYHtyIGJveGNveC1nbGFuY2V9DQpmaXRfYmMgPC0gYnJvb206OmdsYW5jZShtX2JjKSAlPiUNCiAgZHBseXI6OnNlbGVjdChyLnNxdWFyZWQsIGFkai5yLnNxdWFyZWQsIHNpZ21hLCBzdGF0aXN0aWMsIHAudmFsdWUsIGRmKQ0KDQpwYW5kZXI6OnBhbmRlcigNCiAgZml0X2JjLA0KICBjYXB0aW9uID0gIkJveOKAk0NveCBNb2RlbDogS2V5IEZpdCBTdGF0aXN0aWNzIChUcmFuc2Zvcm1lZCBSZXNwb25zZSkiDQopDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbiAobnVtZXJpYykuKiogIA0KVGhlIEJveOKAk0NveCBtb2RlbCBvZnRlbiBpbmNyZWFzZXMgYWRqdXN0ZWQgXChSXjJcKSByZWxhdGl2ZSB0byB0aGUgdW50cmFuc2Zvcm1lZCBtb2RlbHMgKGNvbW1vbmx5IGFyb3VuZCAqKjAuODY2KiopLiBUaGlzIGluZGljYXRlcyBiZXR0ZXIgZml0IG9uIHRoZSB0cmFuc2Zvcm1lZCBzY2FsZSBhbmQgdHlwaWNhbGx5IGltcHJvdmVzIHJlc2lkdWFsIGJlaGF2aW9yLCBidXQgY29lZmZpY2llbnRzIGFyZSBoYXJkZXIgdG8gaW50ZXJwcmV0IGluIGRvbGxhcnMuDQoNCiMjIyAgRGlhZ25vc3RpY3MgKEJveOKAk0NveCkNCg0KYGBge3IgYm94Y294LWRpYWdub3N0aWNzfQ0Kb3AgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkNCnBsb3QobV9iYykNCnBhcihvcCkNCmBgYA0KDQoqKkludGVycHJldGF0aW9uICh2aXN1YWwpLioqICANClJlc2lkdWFsIHBhdHRlcm5zIG9mdGVuIGxvb2sgbW9yZSBzdGFibGUgKGxlc3MgZmFubmluZykgYW5kIHRoZSBR4oCTUSBwbG90IGFsaWducyBtb3JlIGNsb3NlbHkgd2l0aCBub3JtYWxpdHkuIEhvd2V2ZXIsIGludGVycHJldGFiaWxpdHkgaXMgcmVkdWNlZCBzaW5jZSB0aGUgcmVzcG9uc2UgaXMgdHJhbnNmb3JtZWQuDQoNCiMgU3RlcHdpc2UgQUlDIE1vZGVsIGFuZCBNb2RlbCBDb21wYXJpc29uIChDbGVhbiBPdXRwdXQpDQoNCiMjICBSYXRpb25hbGUNCg0KV2UgdXNlIHN0ZXB3aXNlIEFJQyB0byByZWR1Y2UgcmVkdW5kYW5jeSBhbmQgbXVsdGljb2xsaW5lYXJpdHkgd2hpbGUga2VlcGluZyB0aGUgcmVzcG9uc2UgaW4gZG9sbGFycy4gV2UgY29tcGFyZSB0aGUgZnVsbCBhbmQgc3RlcHdpc2UgbW9kZWxzIHVzaW5nIFwoUl4yXCksIGFkanVzdGVkIFwoUl4yXCksIE1hbGxvd3PigJkgXChDX3BcKSwgYW5kIFBSRVNTLg0KDQojIyAgU3RlcHdpc2UgQUlDIE1vZGVsDQoNCmBgYHtyIHN0ZXB3aXNlLWZpdCwgcmVzdWx0cz0naGlkZSd9DQptX3N0ZXAgPC0gTUFTUzo6c3RlcEFJQyhtX2Z1bGwsIHRyYWNlID0gRkFMU0UpDQpgYGANCg0KIyMjICBTdGVwd2lzZSBGaXQgU3RhdGlzdGljcyAoQ2xlYW4pDQoNCmBgYHtyIHN0ZXB3aXNlLWdsYW5jZX0NCmZpdF9zdGVwIDwtIGJyb29tOjpnbGFuY2UobV9zdGVwKSAlPiUNCiAgZHBseXI6OnNlbGVjdChyLnNxdWFyZWQsIGFkai5yLnNxdWFyZWQsIHNpZ21hLCBzdGF0aXN0aWMsIHAudmFsdWUsIGRmKQ0KDQpwYW5kZXI6OnBhbmRlcigNCiAgZml0X3N0ZXAsDQogIGNhcHRpb24gPSAiU3RlcHdpc2UgQUlDIE1vZGVsOiBLZXkgRml0IFN0YXRpc3RpY3MiDQopDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbiAobnVtZXJpYykuKiogIA0KVGhlIHN0ZXB3aXNlIG1vZGVsIG1haW50YWlucyBlc3NlbnRpYWxseSB0aGUgc2FtZSBhZGp1c3RlZCBcKFJeMlwpIGFzIHRoZSBmdWxsIG1vZGVsIHdoaWxlIHVzaW5nIGZld2VyIHByZWRpY3RvcnMsIHN1cHBvcnRpbmcgYSBzaW1wbGVyIG1vZGVsIHdpdGggc2ltaWxhciBleHBsYW5hdG9yeSBwb3dlci4NCg0KIyMjICBTdGVwd2lzZSBDb2VmZmljaWVudHMgKENsZWFuKQ0KDQpgYGB7ciBzdGVwd2lzZS10aWR5fQ0KY29lZl9zdGVwIDwtIGJyb29tOjp0aWR5KG1fc3RlcCwgY29uZi5pbnQgPSBUUlVFKSAlPiUNCiAgZHBseXI6Om11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gcm91bmQoLngsIDQpKSkgJT4lDQogIGRwbHlyOjphcnJhbmdlKHAudmFsdWUpDQoNCnBhbmRlcjo6cGFuZGVyKA0KICBjb2VmX3N0ZXAsDQogIGNhcHRpb24gPSAiU3RlcHdpc2UgQUlDIE1vZGVsOiBDb2VmZmljaWVudHMgd2l0aCA5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbHMiDQopDQpgYGANCg0KIyMjICBTdGVwd2lzZSBWSUYgKENsZWFuKQ0KDQpgYGB7ciBzdGVwd2lzZS12aWZ9DQp2aWZfc3RlcCA8LSBjYXI6OnZpZihtX3N0ZXApDQp2aWZfc3RlcF90YmwgPC0gdGliYmxlOjp0aWJibGUoDQogIFByZWRpY3RvciA9IG5hbWVzKHZpZl9zdGVwKSwNCiAgVklGID0gYXMubnVtZXJpYyh2aWZfc3RlcCkNCikgJT4lDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoVklGKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoVklGID0gcm91bmQoVklGLCAyKSkNCg0KcGFuZGVyOjpwYW5kZXIodmlmX3N0ZXBfdGJsLCBjYXB0aW9uID0gIlN0ZXB3aXNlIEFJQyBNb2RlbDogVklGIikNCmBgYA0KDQoqKkludGVycHJldGF0aW9uIChudW1lcmljKS4qKiAgDQpWSUYgdmFsdWVzIGRyb3Agc3Vic3RhbnRpYWxseSByZWxhdGl2ZSB0byB0aGUgZnVsbCBtb2RlbCwgaW5kaWNhdGluZyBpbXByb3ZlZCBjb2VmZmljaWVudCBzdGFiaWxpdHkgYW5kIHJlZHVjZWQgbXVsdGljb2xsaW5lYXJpdHkgKGVzcGVjaWFsbHkgYW1vbmcgc3F1YXJlIGZvb3RhZ2UgcHJlZGljdG9ycykuDQoNCiMjICBHb29kbmVzcy1vZi1GaXQgQ29tcGFyaXNvbjogRnVsbCB2cyBTdGVwd2lzZSAoQ3AgYW5kIFBSRVNTKQ0KDQpgYGB7ciBnb2YtY29tcGFyZX0NCmdvZl90YWJsZSA8LSBmdW5jdGlvbihtLCBtc2VfZnVsbCwgbil7DQogIGUgICA8LSByZXNpZChtKQ0KICBTU0UgPC0gc3VtKGVeMikNCiAgUjIgICAgPC0gc3VtbWFyeShtKSRyLnNxdWFyZWQNCiAgUjJhZGogPC0gc3VtbWFyeShtKSRhZGouci5zcXVhcmVkDQogIHAgICAgIDwtIGxlbmd0aChjb2VmKG0pKQ0KDQogIENwICAgIDwtIFNTRS9tc2VfZnVsbCAtIChuIC0gMiAqIHApDQoNCiAgWCA8LSBtb2RlbC5tYXRyaXgobSkNCiAgSCA8LSBYICUqJSBzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKQ0KICBkIDwtIGUvKDEgLSBkaWFnKEgpKQ0KICBQUkVTUyA8LSBzdW0oZF4yKQ0KDQogIHRpYmJsZTo6dGliYmxlKA0KICAgIFNTRSA9IFNTRSwgUjIgPSBSMiwgUjJfQWRqID0gUjJhZGosDQogICAgQ3AgPSBDcCwgUFJFU1MgPSBQUkVTUywgcCA9IHANCiAgKQ0KfQ0KDQpuIDwtIG5vYnMobV9mdWxsKQ0KbXNlX2Z1bGwgPC0gbWVhbihyZXNpZChtX2Z1bGwpXjIpDQoNCmdvZiA8LSBkcGx5cjo6YmluZF9yb3dzKA0KICBGdWxsICAgICA9IGdvZl90YWJsZShtX2Z1bGwsIG1zZV9mdWxsLCBuKSAlPiUgbXV0YXRlKE1vZGVsID0gIkZ1bGwiKSwNCiAgU3RlcHdpc2UgPSBnb2ZfdGFibGUobV9zdGVwLCBtc2VfZnVsbCwgbikgJT4lIG11dGF0ZShNb2RlbCA9ICJTdGVwd2lzZSBBSUMiKQ0KKSAlPiUNCiAgcmVsb2NhdGUoTW9kZWwpICU+JQ0KICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IHJvdW5kKC54LCAzKSkpDQoNCnBhbmRlcjo6cGFuZGVyKGdvZiwgY2FwdGlvbiA9ICJHb29kbmVzcy1vZi1GaXQ6IEZ1bGwgdnMgU3RlcHdpc2UgKFIyLCBBZGogUjIsIENwLCBQUkVTUykiKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXRpb24gKG51bWVyaWMpLioqICANCklmIHRoZSBzdGVwd2lzZSBtb2RlbCBtYXRjaGVzIHRoZSBmdWxsIG1vZGVsIG9uIGFkanVzdGVkIFwoUl4yXCkgYW5kIFBSRVNTIHdoaWxlIHVzaW5nIGZld2VyIHByZWRpY3RvcnMgYW5kIGxvd2VyIFZJRiwgaXQgaXMgcHJlZmVycmVkIGZvciBpbnRlcnByZXRhYmlsaXR5IGFuZCBzdGFiaWxpdHkuIENwIGNsb3NlIHRvIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyBzdXBwb3J0cyBhcHByb3ByaWF0ZSBtb2RlbCBjb21wbGV4aXR5Lg0KDQojICBGaW5hbCBNb2RlbCBhbmQgSW50ZXJwcmV0YXRpb24gKENsZWFuIE91dHB1dCkNCg0KIyMgIEZpbmFsIE1vZGVsIENob2ljZQ0KDQpXZSBjaG9vc2UgdGhlICoqc3RlcHdpc2UgQUlDIG1vZGVsKiogYXMgdGhlIGZpbmFsIG1vZGVsIGJlY2F1c2UgaXQ6DQotIHByZXNlcnZlcyBpbnRlcnByZXRhYmlsaXR5IGluIGRvbGxhcnMsDQotIG1haW50YWlucyBlc3NlbnRpYWxseSBpZGVudGljYWwgZml0IHRvIHRoZSBmdWxsIG1vZGVsLA0KLSBhbmQgcmVkdWNlcyBtdWx0aWNvbGxpbmVhcml0eSBzdWJzdGFudGlhbGx5Lg0KDQpgYGB7ciBmaW5hbC1tb2RlbH0NCm1fZmluYWwgPC0gbV9zdGVwDQpgYGANCg0KIyMgIEZpbmFsIERpYWdub3N0aWNzDQoNCmBgYHtyIGZpbmFsLWRpYWdub3N0aWNzfQ0Kb3AgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkNCnBsb3QobV9maW5hbCkNCnBhcihvcCkNCmBgYA0KDQoqKkludGVycHJldGF0aW9uICh2aXN1YWwpLioqICANClRoZSBmaW5hbCBtb2RlbCBkaWFnbm9zdGljcyBhcmUgYWNjZXB0YWJsZSBmb3IgcmVncmVzc2lvbiBpbmZlcmVuY2UsIHdpdGggbWlsZCBoZXRlcm9zY2VkYXN0aWNpdHkgYnV0IHN0cm9uZyBvdmVyYWxsIGZpdC4gUmVkdWNlZCBtdWx0aWNvbGxpbmVhcml0eSBpbXByb3ZlcyBjb2VmZmljaWVudCBzdGFiaWxpdHkgY29tcGFyZWQgdG8gdGhlIGZ1bGwgbW9kZWwuDQoNCiMjICBLZXkgQ29lZmZpY2llbnQgSW50ZXJwcmV0YXRpb25zIChDbGVhbiBTdW1tYXJ5IFRhYmxlKQ0KDQpgYGB7ciBrZXktY29lZnN9DQprZXlfdGVybXMgPC0gYygiT3ZlcmFsbF9RdWFsX1MiLCJUb3RhbF9CYXRocyIsIkhvdXNlX0FnZSIsIlllYXJzX1NpbmNlX1JlbW9kIiwNCiAgICAgICAgICAgICAgICJGaXJlcGxhY2VzIiwiR3JfTGl2X0FyZWEiLCJHYXJhZ2VfQXJlYSIsIk1hc19WbnJfQXJlYSIsIkxvdF9BcmVhIikNCg0Ka2V5X3RibCA8LSBicm9vbTo6dGlkeShtX2ZpbmFsLCBjb25mLmludCA9IFRSVUUpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHRlcm0gJWluJSBrZXlfdGVybXMpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiByb3VuZCgueCwgMykpKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhhYnMoZXN0aW1hdGUpKSkNCg0KcGFuZGVyOjpwYW5kZXIoa2V5X3RibCwgY2FwdGlvbiA9ICJGaW5hbCBNb2RlbDogU2VsZWN0ZWQgS2V5IENvZWZmaWNpZW50cyAoRG9sbGFyIFNjYWxlKSIpDQpgYGANCg0KKipJbnRlcnByZXRhdGlvbiAobnVtZXJpYykuKiogIA0KSW50ZXJwcmV0IGNvZWZmaWNpZW50cyBhcyDigJxob2xkaW5nIGFsbCBlbHNlIGNvbnN0YW50LuKAnSBGb3IgZXhhbXBsZToNCi0gYE92ZXJhbGxfUXVhbF9TYCBpbmRpY2F0ZXMgdGhlIGRvbGxhciBwcmVtaXVtIHBlciAxLXVuaXQgaW5jcmVhc2UgaW4gcXVhbGl0eSByYXRpbmcuDQotIGBUb3RhbF9CYXRoc2AgaW5kaWNhdGVzIHRoZSBkb2xsYXIgcHJlbWl1bSBwZXIgYWRkaXRpb25hbCBlZmZlY3RpdmUgYmF0aHJvb20uDQotIGBIb3VzZV9BZ2VgIGFuZCBgWWVhcnNfU2luY2VfUmVtb2RgIHNob3cgZGVwcmVjaWF0aW9uIGFuZCByZW1vZGVsaW5nIGVmZmVjdHMgKG5lZ2F0aXZlIHZhbHVlcykuDQotIGBHcl9MaXZfQXJlYWAsIGBHYXJhZ2VfQXJlYWAsIGFuZCBgTWFzX1Zucl9BcmVhYCByZXByZXNlbnQgc2l6ZS9hbWVuaXR5IHByZW1pdW1zIHBlciBzcXVhcmUgZm9vdC4NCg0KIyAgQ29uY2x1c2lvbnMgYW5kIEZ1dHVyZSBXb3JrDQoNCiMjICBDb25jbHVzaW9ucw0KDQpUaGUgZmluYWwgbW9kZWwgaW5kaWNhdGVzIHRoYXQgQW1lcyBob21lIHNhbGUgcHJpY2VzIGFyZSBzdHJvbmdseSBkcml2ZW4gYnk6DQotIG92ZXJhbGwgcXVhbGl0eSwNCi0gbGl2aW5nIGFyZWEgYW5kIGJhc2VtZW50IHNpemUsDQotIHRvdGFsIGJhdGhyb29tcywNCi0gYW1lbml0aWVzIChmaXJlcGxhY2VzIGFuZCBnYXJhZ2UgYXJlYSksDQotIGFuZCBtb2Rlcm5pdHkgKGFnZSBhbmQgdGltZSBzaW5jZSByZW1vZGVsKS4NCg0KIyMgIE1vZGVsIENob2ljZSBTdW1tYXJ5DQoNCkJveOKAk0NveCBpbXByb3ZlcyBhc3N1bXB0aW9uIGJlaGF2aW9yIGFuZCBpbmNyZWFzZXMgYWRqdXN0ZWQgXChSXjJcKSBvbiBhIHRyYW5zZm9ybWVkIHNjYWxlLCBidXQgcmVkdWNlcyBpbnRlcnByZXRhYmlsaXR5LiBUaGUgc3RlcHdpc2UgQUlDIG1vZGVsIHJldGFpbnMgZG9sbGFyLXNjYWxlIGludGVycHJldGF0aW9uLCBzdWJzdGFudGlhbGx5IGxvd2VycyBtdWx0aWNvbGxpbmVhcml0eSwgYW5kIHByZXNlcnZlcyBwcmVkaWN0aXZlIGZpdCBjb21wYXJlZCB0byB0aGUgZnVsbCBtb2RlbC4gVGhlcmVmb3JlLCBzdGVwd2lzZSBBSUMgaXMgdGhlIHByZWZlcnJlZCBmaW5hbCBtb2RlbCBmb3IgdGhpcyBhc3NpZ25tZW50Lg0KDQojIyAgTGltaXRhdGlvbnMgYW5kIEZ1dHVyZSBXb3JrDQoNClRoaXMgYW5hbHlzaXMgZG9lcyBub3QgaW5jbHVkZSBuZWlnaGJvcmhvb2QvbG9jYXRpb24gdmFyaWFibGVzLCB3aGljaCBhcmUgb2Z0ZW4gbWFqb3IgZHJpdmVycyBvZiBwcmljZS4gRnV0dXJlIHdvcmsgY291bGQgaW5jb3Jwb3JhdGUgc3BhdGlhbCBwcmVkaWN0b3JzIGFuZCBleHBsb3JlIG5vbmxpbmVhciBtb2RlbHMgKHNwbGluZXMsIHRyZWUtYmFzZWQgbWV0aG9kcykgd2l0aCB2YWxpZGF0aW9uIHRocm91Z2ggY3Jvc3MtdmFsaWRhdGlvbiBvciBhIHRyYWluL3Rlc3Qgc3BsaXQuDQoNCg==