The Need for Parsimony

In multiple regression, including too many predictors can lead to unstable estimates (multicollinearity) and overfitting. Variable selection aims to find a subset of predictors that provides the best balance between model fit and simplicity (parsimony), often measured using criteria like Adjusted , AIC, or Mallows’ Cp.

In this lecture, we use the Ames Housing dataset to demonstrate three classical variable selection methods (Forward, Backward, Stepwise) and the more comprehensive Best Subset Selection. Our response variable remains the log of the Sale Price (log_Sale_Price).

Setup and Data Loading

We load the necessary libraries, including leaps for subset selection, and prepare our data by selecting a broader set of potential predictors and handling missing values.

# Load Necessary Packages
library(tidyverse)
library(modeldata)
library(leaps) # For Best Subset Selection

# Load the Ames Housing data
data(ames)

# Select a broad set of key predictors and handle missing values
full_data <- ames %>%
  drop_na() %>%
  select(Gr_Liv_Area, Year_Built, Garage_Area, Total_Bsmt_SF, Garage_Cars, Year_Remod_Add, 
         First_Flr_SF, Full_Bath, Garage_Type, Fireplaces, Second_Flr_SF, Longitude, Foundation, 
         Lot_Area, Latitude, Heating_QC, TotRms_AbvGrd, Open_Porch_SF, Mas_Vnr_Area, Overall_Cond,
         Sale_Price) %>%
  mutate(log_Sale_Price = log(Sale_Price)) %>%
  select(-Sale_Price)

cat("Predictors available for selection:\n")
Predictors available for selection:
print(names(full_data)[-which(names(full_data) == "log_Sale_Price")])
 [1] "Gr_Liv_Area"    "Year_Built"     "Garage_Area"    "Total_Bsmt_SF"  "Garage_Cars"   
 [6] "Year_Remod_Add" "First_Flr_SF"   "Full_Bath"      "Garage_Type"    "Fireplaces"    
[11] "Second_Flr_SF"  "Longitude"      "Foundation"     "Lot_Area"       "Latitude"      
[16] "Heating_QC"     "TotRms_AbvGrd"  "Open_Porch_SF"  "Mas_Vnr_Area"   "Overall_Cond"  
cat("\nNumber of observations remaining:", nrow(full_data), "\n\n")

Number of observations remaining: 2930 
# Define the Full Model (The upper boundary for selection methods)
full_model <- lm(log_Sale_Price ~ ., data = full_data)

# FULL MODEL SUMMARY
summary(full_model)

Call:
lm(formula = log_Sale_Price ~ ., data = full_data)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.55316 -0.07719 -0.00017  0.08183  0.66645 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)                    -6.398e+01  1.548e+01  -4.134 3.67e-05 ***
Gr_Liv_Area                     1.962e-04  6.714e-05   2.922 0.003500 ** 
Year_Built                      3.078e-03  2.345e-04  13.125  < 2e-16 ***
Garage_Area                     9.995e-05  3.299e-05   3.030 0.002470 ** 
Total_Bsmt_SF                   1.279e-04  1.463e-05   8.745  < 2e-16 ***
Garage_Cars                     6.034e-02  1.000e-02   6.033 1.82e-09 ***
Year_Remod_Add                  1.301e-03  2.361e-04   5.512 3.87e-08 ***
First_Flr_SF                    1.105e-04  6.868e-05   1.608 0.107889    
Full_Bath                       2.588e-03  8.180e-03   0.316 0.751765    
Garage_TypeBasment             -5.109e-02  2.850e-02  -1.793 0.073109 .  
Garage_TypeBuiltIn             -2.182e-02  1.394e-02  -1.565 0.117788    
Garage_TypeCarPort             -1.669e-01  4.294e-02  -3.887 0.000104 ***
Garage_TypeDetchd              -5.378e-02  9.067e-03  -5.931 3.36e-09 ***
Garage_TypeMore_Than_Two_Types -1.229e-01  3.569e-02  -3.442 0.000585 ***
Garage_TypeNo_Garage           -5.289e-02  1.800e-02  -2.938 0.003328 ** 
Fireplaces                      7.279e-02  5.629e-03  12.930  < 2e-16 ***
Second_Flr_SF                   6.994e-05  6.721e-05   1.041 0.298164    
Longitude                      -3.094e-01  1.353e-01  -2.287 0.022286 *  
FoundationCBlock               -2.609e-02  1.275e-02  -2.046 0.040809 *  
FoundationPConc                 2.620e-02  1.517e-02   1.727 0.084351 .  
FoundationSlab                 -1.167e-01  3.089e-02  -3.779 0.000160 ***
FoundationStone                 7.776e-03  5.041e-02   0.154 0.877419    
FoundationWood                 -7.088e-03  7.559e-02  -0.094 0.925296    
Lot_Area                        2.095e-06  4.238e-07   4.945 8.06e-07 ***
Latitude                        8.845e-01  1.782e-01   4.964 7.29e-07 ***
Heating_QCFair                 -5.770e-02  1.894e-02  -3.047 0.002335 ** 
Heating_QCGood                 -3.004e-02  9.373e-03  -3.205 0.001364 ** 
Heating_QCPoor                 -7.323e-01  9.510e-02  -7.701 1.84e-14 ***
Heating_QCTypical              -5.630e-02  8.817e-03  -6.386 1.98e-10 ***
TotRms_AbvGrd                  -1.885e-03  3.383e-03  -0.557 0.577387    
Open_Porch_SF                   1.048e-05  4.881e-05   0.215 0.830000    
Mas_Vnr_Area                    6.314e-05  1.992e-05   3.170 0.001542 ** 
Overall_CondPoor                2.849e-02  8.083e-02   0.352 0.724565    
Overall_CondFair                1.719e-01  6.620e-02   2.596 0.009475 ** 
Overall_CondBelow_Average       3.258e-01  6.436e-02   5.063 4.39e-07 ***
Overall_CondAverage             4.309e-01  6.290e-02   6.850 8.98e-12 ***
Overall_CondAbove_Average       4.757e-01  6.289e-02   7.565 5.19e-14 ***
Overall_CondGood                5.350e-01  6.304e-02   8.487  < 2e-16 ***
Overall_CondVery_Good           5.696e-01  6.420e-02   8.872  < 2e-16 ***
Overall_CondExcellent           6.544e-01  6.794e-02   9.633  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1627 on 2890 degrees of freedom
Multiple R-squared:  0.8427,    Adjusted R-squared:  0.8406 
F-statistic:   397 on 39 and 2890 DF,  p-value: < 2.2e-16

Automated Selection Methods (AIC Criterion)

The step() function in provides fast, automated selection based on the Akaike Information Criterion (AIC), where the goal is to find the model that minimizes AIC.

Forward Selection

Forward Selection starts with a model containing only the intercept (the null model) and sequentially adds the single predictor that provides the greatest additional improvement to the fit (minimum AIC) until no further addition significantly improves the model.

# Start with the null model (intercept only)
null_model <- lm(log_Sale_Price ~ 1, data = full_data)

# Perform Forward Selection
model_forward <- step(null_model, 
                      scope = list(lower = null_model, upper = full_model), 
                      direction = "forward",
                      trace = 0) 

cat("--- FORWARD SELECTION (Final Model Formula) ---\n")
--- FORWARD SELECTION (Final Model Formula) ---
print(formula(model_forward))
log_Sale_Price ~ Gr_Liv_Area + Year_Built + Overall_Cond + Total_Bsmt_SF + 
    Garage_Cars + Fireplaces + Heating_QC + Year_Remod_Add + 
    Garage_Type + Lot_Area + Foundation + Latitude + Garage_Area + 
    Mas_Vnr_Area + First_Flr_SF + Longitude

Backward Elimination

Backward Elimination starts with the full model (containing all predictors) and sequentially removes the single least significant predictor (highest P-value / maximum AIC increase) until all remaining predictors are deemed significant or until removal no longer improves the model.# Start with the full model

# Perform Backward Elimination
model_backward <- step(full_model, 
                       direction = "backward", 
                       trace = 0) 

cat("--- BACKWARD ELIMINATION (Final Model Formula) ---\n")
--- BACKWARD ELIMINATION (Final Model Formula) ---
print(formula(model_backward))
log_Sale_Price ~ Gr_Liv_Area + Year_Built + Garage_Area + Total_Bsmt_SF + 
    Garage_Cars + Year_Remod_Add + First_Flr_SF + Garage_Type + 
    Fireplaces + Longitude + Foundation + Lot_Area + Latitude + 
    Heating_QC + Mas_Vnr_Area + Overall_Cond

Stepwise Selection (Both Directions)

Stepwise Selection is a hybrid approach that iteratively performs both forward and backward steps. At each stage, it may add or remove a predictor based on the AIC change.

# Start with the full model
# Perform Stepwise Selection
model_stepwise <- step(full_model, 
                       direction = "both", 
                       trace = 0) 

cat("--- STEPWISE SELECTION (Final Model Formula) ---\n")
--- STEPWISE SELECTION (Final Model Formula) ---
print(formula(model_stepwise))
log_Sale_Price ~ Gr_Liv_Area + Year_Built + Garage_Area + Total_Bsmt_SF + 
    Garage_Cars + Year_Remod_Add + First_Flr_SF + Garage_Type + 
    Fireplaces + Longitude + Foundation + Lot_Area + Latitude + 
    Heating_QC + Mas_Vnr_Area + Overall_Cond

Observation: Notice that for this dataset, all three automated methods (Forward, Backward, and Stepwise) tend to converge on the same final model, which indicates a robust set of significant predictors.

Model Contrast: Full vs. Selected

Finally, we compare the summary statistics of the original Full Model versus the Selected Model (using the results from Backward Elimination) to highlight the benefit of variable selection.

# We will use the model chosen by Backward Elimination (model_backward) for comparison
final_selected_model <- model_backward

cat("\n\n--- MODEL CONTRAST: Full vs. Selected ---\n")


--- MODEL CONTRAST: Full vs. Selected ---
cat("--- Full Model Metrics ---\n")
--- Full Model Metrics ---
cat("R-squared (Full Model):", summary(full_model)$r.squared, "\n")
R-squared (Full Model): 0.8426886 
cat("Adjusted R-squared (Full Model):", summary(full_model)$adj.r.squared, "\n")
Adjusted R-squared (Full Model): 0.8405657 
cat("Number of Coefficients (Full Model):", length(coef(full_model)), "\n")
Number of Coefficients (Full Model): 40 
cat("\n--- Selected Model Metrics ---\n")

--- Selected Model Metrics ---
cat("R-squared (Selected Model):", summary(final_selected_model)$r.squared, "\n")
R-squared (Selected Model): 0.8426038 
cat("Adjusted R-squared (Selected Model):", summary(final_selected_model)$adj.r.squared, "\n")
Adjusted R-squared (Selected Model): 0.8407003 
cat("Number of Coefficients (Selected Model):", length(coef(final_selected_model)), "\n")
Number of Coefficients (Selected Model): 36 

Conclusion

A successful variable selection process, as demonstrated here, achieves a selected model with:

  1. Similar or Higher Adjusted \(R^2\): This confirms that the removed variables were not contributing meaningfully to the overall predictive power of the model.

  2. Fewer Parameters: The final model is more parsimonious, making the coefficients easier to interpret and potentially leading to better out-of-sample prediction (reduced risk of overfitting).

  3. More Stable Coefficients: By removing redundant or non-significant variables, the remaining coefficients typically have smaller standard errors, increasing the precision of our estimates.

LS0tDQp0aXRsZTogIlZhcmlhYmxlIFNlbGVjdGlvbiBUZWNobmlxdWVzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogY2VydWxlYW4NCi0tLQ0KDQojIyBUaGUgTmVlZCBmb3IgUGFyc2ltb255DQoNCkluIG11bHRpcGxlIHJlZ3Jlc3Npb24sIGluY2x1ZGluZyB0b28gbWFueSBwcmVkaWN0b3JzIGNhbiBsZWFkIHRvIHVuc3RhYmxlIGVzdGltYXRlcyAobXVsdGljb2xsaW5lYXJpdHkpIGFuZCBvdmVyZml0dGluZy4gVmFyaWFibGUgc2VsZWN0aW9uIGFpbXMgdG8gZmluZCBhIHN1YnNldCBvZiBwcmVkaWN0b3JzIHRoYXQgcHJvdmlkZXMgdGhlIGJlc3QgYmFsYW5jZSBiZXR3ZWVuIG1vZGVsIGZpdCBhbmQgc2ltcGxpY2l0eSAocGFyc2ltb255KSwgb2Z0ZW4gbWVhc3VyZWQgdXNpbmcgY3JpdGVyaWEgbGlrZSBBZGp1c3RlZCAsIEFJQywgb3IgTWFsbG93cycgQ3AuDQoNCkluIHRoaXMgbGVjdHVyZSwgd2UgdXNlIHRoZSBBbWVzIEhvdXNpbmcgZGF0YXNldCB0byBkZW1vbnN0cmF0ZSB0aHJlZSBjbGFzc2ljYWwgdmFyaWFibGUgc2VsZWN0aW9uIG1ldGhvZHMgKEZvcndhcmQsIEJhY2t3YXJkLCBTdGVwd2lzZSkgYW5kIHRoZSBtb3JlIGNvbXByZWhlbnNpdmUgQmVzdCBTdWJzZXQgU2VsZWN0aW9uLiBPdXIgcmVzcG9uc2UgdmFyaWFibGUgcmVtYWlucyB0aGUgbG9nIG9mIHRoZSBTYWxlIFByaWNlIChgbG9nX1NhbGVfUHJpY2VgKS4NCg0KIyMgU2V0dXAgYW5kIERhdGEgTG9hZGluZw0KDQpXZSBsb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzLCBpbmNsdWRpbmcgYGxlYXBzYCBmb3Igc3Vic2V0IHNlbGVjdGlvbiwgYW5kIHByZXBhcmUgb3VyIGRhdGEgYnkgc2VsZWN0aW5nIGEgYnJvYWRlciBzZXQgb2YgcG90ZW50aWFsIHByZWRpY3RvcnMgYW5kIGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzLg0KDQpgYGB7cn0NCiMgTG9hZCBOZWNlc3NhcnkgUGFja2FnZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShtb2RlbGRhdGEpDQpsaWJyYXJ5KGxlYXBzKSAjIEZvciBCZXN0IFN1YnNldCBTZWxlY3Rpb24NCg0KIyBMb2FkIHRoZSBBbWVzIEhvdXNpbmcgZGF0YQ0KZGF0YShhbWVzKQ0KDQojIFNlbGVjdCBhIGJyb2FkIHNldCBvZiBrZXkgcHJlZGljdG9ycyBhbmQgaGFuZGxlIG1pc3NpbmcgdmFsdWVzDQpmdWxsX2RhdGEgPC0gYW1lcyAlPiUNCiAgZHJvcF9uYSgpICU+JQ0KICBzZWxlY3QoR3JfTGl2X0FyZWEsIFllYXJfQnVpbHQsIEdhcmFnZV9BcmVhLCBUb3RhbF9Cc210X1NGLCBHYXJhZ2VfQ2FycywgWWVhcl9SZW1vZF9BZGQsIA0KICAgICAgICAgRmlyc3RfRmxyX1NGLCBGdWxsX0JhdGgsIEdhcmFnZV9UeXBlLCBGaXJlcGxhY2VzLCBTZWNvbmRfRmxyX1NGLCBMb25naXR1ZGUsIEZvdW5kYXRpb24sIA0KICAgICAgICAgTG90X0FyZWEsIExhdGl0dWRlLCBIZWF0aW5nX1FDLCBUb3RSbXNfQWJ2R3JkLCBPcGVuX1BvcmNoX1NGLCBNYXNfVm5yX0FyZWEsIE92ZXJhbGxfQ29uZCwNCiAgICAgICAgIFNhbGVfUHJpY2UpICU+JQ0KICBtdXRhdGUobG9nX1NhbGVfUHJpY2UgPSBsb2coU2FsZV9QcmljZSkpICU+JQ0KICBzZWxlY3QoLVNhbGVfUHJpY2UpDQoNCmNhdCgiUHJlZGljdG9ycyBhdmFpbGFibGUgZm9yIHNlbGVjdGlvbjpcbiIpDQpwcmludChuYW1lcyhmdWxsX2RhdGEpWy13aGljaChuYW1lcyhmdWxsX2RhdGEpID09ICJsb2dfU2FsZV9QcmljZSIpXSkNCmNhdCgiXG5OdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHJlbWFpbmluZzoiLCBucm93KGZ1bGxfZGF0YSksICJcblxuIikNCg0KIyBEZWZpbmUgdGhlIEZ1bGwgTW9kZWwgKFRoZSB1cHBlciBib3VuZGFyeSBmb3Igc2VsZWN0aW9uIG1ldGhvZHMpDQpmdWxsX21vZGVsIDwtIGxtKGxvZ19TYWxlX1ByaWNlIH4gLiwgZGF0YSA9IGZ1bGxfZGF0YSkNCg0KIyBGVUxMIE1PREVMIFNVTU1BUlkNCnN1bW1hcnkoZnVsbF9tb2RlbCkNCmBgYA0KDQojIyBCZXN0IFN1YnNldCBTZWxlY3Rpb24gKEV4aGF1c3RpdmUgU2VhcmNoKQ0KDQpCZXN0IFN1YnNldCBTZWxlY3Rpb24gaXMgdGhlIG1vc3Qgcmlnb3JvdXMgYXBwcm9hY2guIEl0IGZpdHMgYWxsIHBvc3NpYmxlIG1vZGVscyAoc3Vic2V0cykgZm9yIGEgZ2l2ZW4gbnVtYmVyIG9mIHByZWRpY3RvcnMgKCkgYW5kIGlkZW50aWZpZXMgdGhlIHNpbmdsZSBiZXN0IG1vZGVsIGZvciBlYWNoICBiYXNlZCBvbiBjcml0ZXJpYSBsaWtlICBvciBBZGp1c3RlZCAuVGhlIHJlZ3N1YnNldHMoKSBmdW5jdGlvbiBwZXJmb3JtcyB0aGlzIGV4aGF1c3RpdmUgc2VhcmNoLiMgV2UgdXNlIHJlZ3N1YnNldHMgdG8gZmluZCB0aGUgYmVzdCBtb2RlbCBmb3IgMSBwcmVkaWN0b3IgdXAgdG8gMTAgcHJlZGljdG9ycy4NCg0KYGBge3J9DQpiZXN0X3N1YnNldCA8LSByZWdzdWJzZXRzKGxvZ19TYWxlX1ByaWNlIH4gLiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBmdWxsX2RhdGEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBudm1heCA9IDEwLCAgIyBMb29rIGZvciBtb2RlbHMgdXAgdG8gMTAgdmFyaWFibGVzDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJleGhhdXN0aXZlIikNCg0KIyBQbG90IDE6IE1hbGxvd3MnIENwIENyaXRlcmlvbg0KIyBUaGUgaWRlYWwgbW9kZWwgbWluaW1pemVzIENwIGFuZCBoYXMgQ3AgYXBwcm94aW1hdGVseSBlcXVhbCB0byBwICh0aGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMpLg0KcGxvdChiZXN0X3N1YnNldCwgc2NhbGUgPSAiQ3AiLCBtYWluID0gIk1hbGxvd3MnIENwIGZvciBCZXN0IFN1YnNldCBTZWxlY3Rpb24iKQ0KDQojIElkZW50aWZ5IHRoZSBtb2RlbCB0aGF0IG1pbmltaXplcyBNYWxsb3dzJyBDcA0KYmVzdF9tb2RlbF9zdW1tYXJ5IDwtIHN1bW1hcnkoYmVzdF9zdWJzZXQpDQpiZXN0X21vZGVsX2lkeCA8LSB3aGljaC5taW4oYmVzdF9tb2RlbF9zdW1tYXJ5JGNwKSAjIEZpbmRzIHRoZSByb3cgaW5kZXggKG1vZGVsIHNpemUpIHdpdGggdGhlIHNtYWxsZXN0IENwDQpiZXN0X21vZGVsX3ZhcnMgPC0gbmFtZXMoYmVzdF9tb2RlbF9zdW1tYXJ5JHdoaWNoW2Jlc3RfbW9kZWxfaWR4LF0pW2Jlc3RfbW9kZWxfc3VtbWFyeSR3aGljaFtiZXN0X21vZGVsX2lkeCxdXQ0KYmVzdF9tb2RlbF92YXJzIDwtIGJlc3RfbW9kZWxfdmFyc1tiZXN0X21vZGVsX3ZhcnMgIT0gIihJbnRlcmNlcHQpIl0NCg0KY2F0KHBhc3RlKCJcbi0tLSBCRVNUIFNVQlNFVCBTRUxFQ1RJT04gKENwIENyaXRlcmlvbikgLS0tXG4iKSkNCmNhdChwYXN0ZSgiT3B0aW1hbCBNb2RlbCBTaXplIChNaW4gQ3ApOiIsIGJlc3RfbW9kZWxfaWR4LCAiUHJlZGljdG9yc1xuIikpDQpjYXQoIlNlbGVjdGVkIFZhcmlhYmxlczoiLCBwYXN0ZShiZXN0X21vZGVsX3ZhcnMsIGNvbGxhcHNlID0gIiwgIiksICJcbiIpDQpgYGANCg0KTWFsbG93cycgKkNwKiBhdHRlbXB0cyB0byBiYWxhbmNlIG1vZGVsIGNvbXBsZXhpdHkgd2l0aCB0aGUgdmFyaWFuY2UtYmlhcyB0cmFkZS1vZmYuDQoNClRoYXQgaXMgdGhlIGZpcnN0LCBhbmQgb2Z0ZW4gdGhlIG1vc3QgaW1wb3J0YW50LCBkaWFnbm9zdGljIHBsb3QgZm9yIEJlc3QgU3Vic2V0IFNlbGVjdGlvbiENCg0KVGhlIGNvZGUgYHBsb3QoYmVzdF9zdWJzZXQsIHNjYWxlID0gIkNwIiwgbWFpbiA9ICJNYWxsb3dzJyBDcCBmb3IgQmVzdCBTdWJzZXQgU2VsZWN0aW9uIilgIGdlbmVyYXRlcyBhIHBsb3QgYmFzZWQgb24gKipNYWxsb3dzJyAkQ19wJCBzdGF0aXN0aWMqKi4NCg0KSGVyZSBpcyBob3cgeW91ciBncmFkdWF0ZSBzdHVkZW50cyBzaG91bGQgaW50ZXJwcmV0IHRoaXMgY3J1Y2lhbCB2aXN1YWxpemF0aW9uOg0KDQoxLiAgKipXaGF0IGlzICRDX3AkPyoqIE1hbGxvd3MnICRDX3AkIGVzdGltYXRlcyB0aGUgbWVhbiBzcXVhcmVkIGVycm9yIG9mIHByZWRpY3Rpb24gZm9yIHRoZSBtb2RlbC4gSXQgd29ya3MgYnkgYmFsYW5jaW5nIHR3byB0aGluZ3M6IHRoZSBtb2RlbCdzIGdvb2RuZXNzLW9mLWZpdCAoaXRzICRSXjIkKSBhbmQgdGhlIG51bWJlciBvZiBwcmVkaWN0b3JzICgkcCQpIGl0IHVzZXMuIEl0IGlzIGEgcGVuYWxpemVkIG1lYXN1cmUgb2YgZXJyb3IsIGFpbWluZyB0byBmaW5kIHRoZSBzd2VldCBzcG90IGJldHdlZW4gYmlhcyAodW5kZXJmaXR0aW5nKSBhbmQgdmFyaWFuY2UgKG92ZXJmaXR0aW5nKS4NCg0KMi4gICoqVGhlIEdvYWw6KiogVGhlIHByaW1hcnkgb2JqZWN0aXZlIHdoZW4gdmlld2luZyB0aGlzIHBsb3QgaXMgdG8gZmluZCB0aGUgbW9kZWwgc2l6ZSAoJHAkKSB0aGF0ICoqbWluaW1pemVzIHRoZSAkQ19wJCBzdGF0aXN0aWMqKi4gQSBzbWFsbGVyICRDX3AkIHN1Z2dlc3RzIGEgbW9yZSBiYWxhbmNlZCBtb2RlbC4NCg0KMy4gICoqVGhlICRDX3AgXGFwcHJveCBwJCBSdWxlOioqIEZvciBhIG1vZGVsIHRvIGJlIGNvbnNpZGVyZWQgYSBnb29kIGZpdCwgTWFsbG93cyBhcmd1ZWQgdGhhdCB0aGUgJENfcCQgdmFsdWUgc2hvdWxkIGJlIGFwcHJveGltYXRlbHkgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIGluIHRoZSBtb2RlbCAoJHAkKS4gU2luY2UgdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzICRwJCBpcyB0aGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgcGx1cyB0aGUgaW50ZXJjZXB0LCB5b3UgbG9vayBmb3IgYSByb3cgd2hlcmUgdGhlICRDX3AkIHZhbHVlIGlzIGNsb3NlIHRvIGl0cyB2ZXJ0aWNhbCBwb3NpdGlvbiBvbiB0aGUgcGxvdC4NCg0KVGhlcmVmb3JlLCB3aGVuIGV4YW1pbmluZyB0aGUgTWFsbG93cycgJENfcCQgcGxvdCwgeW91IGFyZSBsb29raW5nIGZvciB0aGUgcG9pbnQgdGhhdCBpcyBjbG9zZXN0IHRvIHRoZSBkaWFnb25hbCBsaW5lICRDX3AgPSBwJCwgb3Igc2ltcGx5IHRoZSBwb2ludCB0aGF0IGhpdHMgdGhlIG1pbmltdW0gdmFsdWUuIFRoaXMgd2lsbCBpbmRpY2F0ZSB0aGUgbW9zdCBvcHRpbWFsLCBwYXJzaW1vbmlvdXMgbW9kZWwgc2l6ZS4gDQoNCg0KYGBge3J9DQojIFBsb3QgMjogQWRqdXN0ZWQgUi1zcXVhcmVkIENyaXRlcmlvbg0KIyBUaGUgaWRlYWwgbW9kZWwgbWF4aW1pemVzIEFkanVzdGVkIFItc3F1YXJlZC4NCnBsb3QoYmVzdF9zdWJzZXQsIHNjYWxlID0gImFkanIyIiwgbWFpbiA9ICJBZGp1c3RlZCBSLXNxdWFyZWQgZm9yIEJlc3QgU3Vic2V0IFNlbGVjdGlvbiIpDQoNCiMgV2UgdXNlIHRoZSB3aGljaC5tYXgoKSBmdW5jdGlvbiBvbiB0aGUgYWRqcjIgY29tcG9uZW50IG9mIHRoZSBzdW1tYXJ5IG9iamVjdC4NCmFkanIyX21vZGVsX2lkeCA8LSB3aGljaC5tYXgoYmVzdF9tb2RlbF9zdW1tYXJ5JGFkanIyKQ0KYWRqcjJfbWF4X3ZhbHVlIDwtIG1heChiZXN0X21vZGVsX3N1bW1hcnkkYWRqcjIpDQphZGpyMl9tb2RlbF92YXJzIDwtIG5hbWVzKGJlc3RfbW9kZWxfc3VtbWFyeSR3aGljaFthZGpyMl9tb2RlbF9pZHgsXSlbYmVzdF9tb2RlbF9zdW1tYXJ5JHdoaWNoW2FkanIyX21vZGVsX2lkeCxdXQ0KYWRqcjJfbW9kZWxfdmFycyA8LSBhZGpyMl9tb2RlbF92YXJzW2FkanIyX21vZGVsX3ZhcnMgIT0gIihJbnRlcmNlcHQpIl0NCg0KY2F0KHBhc3RlKCJcbi0tLSBCRVNUIFNVQlNFVCBTRUxFQ1RJT04gKEFkanVzdGVkIFItc3F1YXJlZCBDcml0ZXJpb24pIC0tLVxuIikpDQpjYXQocGFzdGUoIk1heGltdW0gQWRqdXN0ZWQgUi1zcXVhcmVkOiIsIHJvdW5kKGFkanIyX21heF92YWx1ZSwgNCksICJcbiIpKQ0KY2F0KHBhc3RlKCJPcHRpbWFsIE1vZGVsIFNpemUgKE1heCBBZGogUjIpOiIsIGFkanIyX21vZGVsX2lkeCwgIlByZWRpY3RvcnNcbiIpKQ0KY2F0KCJTZWxlY3RlZCBWYXJpYWJsZXM6IiwgcGFzdGUoYWRqcjJfbW9kZWxfdmFycywgY29sbGFwc2UgPSAiLCAiKSwgIlxuIikNCmBgYA0KDQpUaGUgYHBsb3QoYmVzdF9zdWJzZXQsIHNjYWxlID0gImFkanIyIiwgbWFpbiA9ICJBZGp1c3RlZCBSLXNxdWFyZWQgZm9yIEJlc3QgU3Vic2V0IFNlbGVjdGlvbiIpYCBjb21tYW5kIGdlbmVyYXRlcyBhIHZpc3VhbGl6YXRpb24gdGhhdCBpcyBjcml0aWNhbCBmb3IgY2hvb3NpbmcgdGhlIG9wdGltYWwgbW9kZWwgc2l6ZSBhbmQgY29tcG9zaXRpb24gYWZ0ZXIgcGVyZm9ybWluZyAqKkJlc3QgU3Vic2V0IFNlbGVjdGlvbioqLg0KDQpIZXJlIGlzIGhvdyB5b3UgaW50ZXJwcmV0IHRoaXMgcGxvdDoNCg0KMS4gICoqU3RydWN0dXJlOioqIFRoZSBwbG90IGlzIGVzc2VudGlhbGx5IGEgaGVhdG1hcCBvciBncmlkIHdoZXJlIGVhY2ggKipyb3cqKiByZXByZXNlbnRzIHRoZSBiZXN0IHBvc3NpYmxlIG1vZGVsIGZvciBhIHNwZWNpZmljIG51bWJlciBvZiBwcmVkaWN0b3JzICgkcCQpLiBUaGUgKipjb2x1bW5zKiogbGlzdCBhbGwgdGhlIHBvdGVudGlhbCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgZnJvbSB5b3VyIGZ1bGwgZGF0YXNldC4NCg0KMi4gICoqTW9kZWwgU2l6ZSAoWS1BeGlzKToqKiBUaGUgdmVydGljYWwgYXhpcyAocm93cykgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgKCRwJCkgdXNlZCBpbiB0aGUgbW9kZWwsIHJhbmdpbmcgZnJvbSAkMSQgdXAgdG8gdGhlIG1heGltdW0gbnVtYmVyIHlvdSBzcGVjaWZpZWQgKGBudm1heD0xMGAgaW4gdGhlIENhbnZhcykuDQoNCjMuICAqKlZhcmlhYmxlIEluY2x1c2lvbiAoQ2VsbHMpOioqDQogICAgKiBBICoqZGFyayBzcXVhcmUqKiAob3Igc2hhZGVkIGNlbGwpIGluIGEgcm93IGluZGljYXRlcyB0aGF0IHRoZSB2YXJpYWJsZSBpbiB0aGF0IGNvbHVtbiAqKmlzIGluY2x1ZGVkKiogaW4gdGhlIG1vZGVsIG9mIHRoYXQgc2l6ZS4NCiAgICAqIEEgKipibGFuayBzcGFjZSoqIGluZGljYXRlcyB0aGUgdmFyaWFibGUgaXMgZXhjbHVkZWQuDQoNCjQuICAqKkludGVycHJldGF0aW9uIEdvYWw6IE1heGltaXppbmcgQWRqdXN0ZWQgJFJeMiQ6KioNCiAgICAqIFRoZSBnb2FsIG9mIHVzaW5nIHRoZSBBZGp1c3RlZCAkUl4yJCBjcml0ZXJpb24gaXMgdG8gZmluZCB0aGUgbW9kZWwgc2l6ZSAoJHAkKSB0aGF0IHJlc3VsdHMgaW4gdGhlICoqaGlnaGVzdCBwb3NzaWJsZSBBZGp1c3RlZCAkUl4yJCB2YWx1ZSoqLg0KICAgICogU2luY2UgQWRqdXN0ZWQgJFJeMiQgcGVuYWxpemVzIHRoZSBpbmNsdXNpb24gb2YgdW5uZWNlc3NhcnkgcHJlZGljdG9ycywgdGhpcyBwbG90IGhlbHBzIHZpc3VhbGx5IGlkZW50aWZ5IHRoZSBwb2ludCB3aGVyZSBhZGRpbmcgbW9yZSB2YXJpYWJsZXMgbm8gbG9uZ2VyIHByb3ZpZGVzIGEgc3Vic3RhbnRpYWwgcmV0dXJuIG9uIGV4cGxhbmF0b3J5IHBvd2VyLg0KDQo1LiAgKipEZWNpc2lvbiBSdWxlOioqDQogICAgKiBMb29rIGZvciB0aGUgcm93IChtb2RlbCBzaXplICRwJCkgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgKipsYXJnZXN0IEFkanVzdGVkICRSXjIkIHZhbHVlKiogKG9mdGVuIGluZGljYXRlZCBieSBhIHN0YXRpc3RpY2FsIHN1bW1hcnkgb3IgYSBsYWJlbCBuZXh0IHRvIHRoZSByb3cpLg0KICAgICogT25jZSB5b3UgaWRlbnRpZnkgdGhhdCBvcHRpbWFsIHJvdywgb2JzZXJ2ZSB3aGljaCB2YXJpYWJsZXMgYXJlIG1hcmtlZCBhcyBpbmNsdWRlZCBpbiB0aGF0IHJvdy4gVGhpcyBzZXQgb2YgcHJlZGljdG9ycyBmb3JtcyB0aGUgbW9zdCBwYXJzaW1vbmlvdXMgbW9kZWwgdGhhdCBtYXhpbWl6ZXMgZXhwbGFpbmVkIHZhcmlhbmNlIGFkanVzdGVkIGZvciBkZWdyZWVzIG9mIGZyZWVkb20uDQoNCkluIHNob3J0LCB5b3UgYXJlIGxvb2tpbmcgZm9yIHRoZSBtb2RlbCAocm93KSB0aGF0IGluY29ycG9yYXRlcyB0aGUgbWluaW11bSBudW1iZXIgb2YgdmFyaWFibGVzIG5lY2Vzc2FyeSB0byBhY2hpZXZlIHRoZSBtYXhpbXVtIEFkanVzdGVkICRSXjIkLiANCg0KQnkgZXhhbWluaW5nIHRoZSBwbG90cyBhbmQgdGhlIG1pbmltdW0gIHZhbHVlLCB3ZSBjYW4gb2JqZWN0aXZlbHkgY2hvb3NlIHRoZSBtb3N0IGVmZmljaWVudCBtb2RlbC4gDQoNCiMjIEF1dG9tYXRlZCBTZWxlY3Rpb24gTWV0aG9kcyAoQUlDIENyaXRlcmlvbikNCg0KVGhlIGBzdGVwKClgIGZ1bmN0aW9uIGluICBwcm92aWRlcyBmYXN0LCBhdXRvbWF0ZWQgc2VsZWN0aW9uIGJhc2VkIG9uIHRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpLCB3aGVyZSB0aGUgZ29hbCBpcyB0byBmaW5kIHRoZSBtb2RlbCB0aGF0IG1pbmltaXplcyBBSUMuDQoNCiMjIyBGb3J3YXJkIFNlbGVjdGlvbg0KDQpGb3J3YXJkIFNlbGVjdGlvbiBzdGFydHMgd2l0aCBhIG1vZGVsIGNvbnRhaW5pbmcgb25seSB0aGUgaW50ZXJjZXB0ICh0aGUgbnVsbCBtb2RlbCkgYW5kIHNlcXVlbnRpYWxseSBhZGRzIHRoZSBzaW5nbGUgcHJlZGljdG9yIHRoYXQgcHJvdmlkZXMgdGhlIGdyZWF0ZXN0IGFkZGl0aW9uYWwgaW1wcm92ZW1lbnQgdG8gdGhlIGZpdCAobWluaW11bSBBSUMpIHVudGlsIG5vIGZ1cnRoZXIgYWRkaXRpb24gc2lnbmlmaWNhbnRseSBpbXByb3ZlcyB0aGUgbW9kZWwuDQoNCmBgYHtyfQ0KIyBTdGFydCB3aXRoIHRoZSBudWxsIG1vZGVsIChpbnRlcmNlcHQgb25seSkNCm51bGxfbW9kZWwgPC0gbG0obG9nX1NhbGVfUHJpY2UgfiAxLCBkYXRhID0gZnVsbF9kYXRhKQ0KDQojIFBlcmZvcm0gRm9yd2FyZCBTZWxlY3Rpb24NCm1vZGVsX2ZvcndhcmQgPC0gc3RlcChudWxsX21vZGVsLCANCiAgICAgICAgICAgICAgICAgICAgICBzY29wZSA9IGxpc3QobG93ZXIgPSBudWxsX21vZGVsLCB1cHBlciA9IGZ1bGxfbW9kZWwpLCANCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiZm9yd2FyZCIsDQogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwKSANCg0KY2F0KCItLS0gRk9SV0FSRCBTRUxFQ1RJT04gKEZpbmFsIE1vZGVsIEZvcm11bGEpIC0tLVxuIikNCnByaW50KGZvcm11bGEobW9kZWxfZm9yd2FyZCkpDQpgYGANCg0KIyMjIEJhY2t3YXJkIEVsaW1pbmF0aW9uDQoNCkJhY2t3YXJkIEVsaW1pbmF0aW9uIHN0YXJ0cyB3aXRoIHRoZSBmdWxsIG1vZGVsIChjb250YWluaW5nIGFsbCBwcmVkaWN0b3JzKSBhbmQgc2VxdWVudGlhbGx5IHJlbW92ZXMgdGhlIHNpbmdsZSBsZWFzdCBzaWduaWZpY2FudCBwcmVkaWN0b3IgKGhpZ2hlc3QgUC12YWx1ZSAvIG1heGltdW0gQUlDIGluY3JlYXNlKSB1bnRpbCBhbGwgcmVtYWluaW5nIHByZWRpY3RvcnMgYXJlIGRlZW1lZCBzaWduaWZpY2FudCBvciB1bnRpbCByZW1vdmFsIG5vIGxvbmdlciBpbXByb3ZlcyB0aGUgbW9kZWwuIyBTdGFydCB3aXRoIHRoZSBmdWxsIG1vZGVsDQoNCmBgYHtyfQ0KIyBQZXJmb3JtIEJhY2t3YXJkIEVsaW1pbmF0aW9uDQptb2RlbF9iYWNrd2FyZCA8LSBzdGVwKGZ1bGxfbW9kZWwsIA0KICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYmFja3dhcmQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwKSANCg0KY2F0KCItLS0gQkFDS1dBUkQgRUxJTUlOQVRJT04gKEZpbmFsIE1vZGVsIEZvcm11bGEpIC0tLVxuIikNCnByaW50KGZvcm11bGEobW9kZWxfYmFja3dhcmQpKQ0KYGBgDQoNCiMjIyBTdGVwd2lzZSBTZWxlY3Rpb24gKEJvdGggRGlyZWN0aW9ucykNCg0KU3RlcHdpc2UgU2VsZWN0aW9uIGlzIGEgaHlicmlkIGFwcHJvYWNoIHRoYXQgaXRlcmF0aXZlbHkgcGVyZm9ybXMgYm90aCBmb3J3YXJkIGFuZCBiYWNrd2FyZCBzdGVwcy4gQXQgZWFjaCBzdGFnZSwgaXQgbWF5IGFkZCBvciByZW1vdmUgYSBwcmVkaWN0b3IgYmFzZWQgb24gdGhlIEFJQyBjaGFuZ2UuDQoNCmBgYHtyfQ0KIyBTdGFydCB3aXRoIHRoZSBmdWxsIG1vZGVsDQojIFBlcmZvcm0gU3RlcHdpc2UgU2VsZWN0aW9uDQptb2RlbF9zdGVwd2lzZSA8LSBzdGVwKGZ1bGxfbW9kZWwsIA0KICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYm90aCIsIA0KICAgICAgICAgICAgICAgICAgICAgICB0cmFjZSA9IDApIA0KDQpjYXQoIi0tLSBTVEVQV0lTRSBTRUxFQ1RJT04gKEZpbmFsIE1vZGVsIEZvcm11bGEpIC0tLVxuIikNCnByaW50KGZvcm11bGEobW9kZWxfc3RlcHdpc2UpKQ0KYGBgDQoNCk9ic2VydmF0aW9uOiBOb3RpY2UgdGhhdCBmb3IgdGhpcyBkYXRhc2V0LCBhbGwgdGhyZWUgYXV0b21hdGVkIG1ldGhvZHMgKEZvcndhcmQsIEJhY2t3YXJkLCBhbmQgU3RlcHdpc2UpIHRlbmQgdG8gY29udmVyZ2Ugb24gdGhlIHNhbWUgZmluYWwgbW9kZWwsIHdoaWNoIGluZGljYXRlcyBhIHJvYnVzdCBzZXQgb2Ygc2lnbmlmaWNhbnQgcHJlZGljdG9ycy4NCg0KIyMgTW9kZWwgQ29udHJhc3Q6IEZ1bGwgdnMuIFNlbGVjdGVkDQoNCkZpbmFsbHksIHdlIGNvbXBhcmUgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBvZiB0aGUgb3JpZ2luYWwgRnVsbCBNb2RlbCB2ZXJzdXMgdGhlIFNlbGVjdGVkIE1vZGVsICh1c2luZyB0aGUgcmVzdWx0cyBmcm9tIEJhY2t3YXJkIEVsaW1pbmF0aW9uKSB0byBoaWdobGlnaHQgdGhlIGJlbmVmaXQgb2YgdmFyaWFibGUgc2VsZWN0aW9uLg0KDQpgYGB7cn0NCiMgV2Ugd2lsbCB1c2UgdGhlIG1vZGVsIGNob3NlbiBieSBCYWNrd2FyZCBFbGltaW5hdGlvbiAobW9kZWxfYmFja3dhcmQpIGZvciBjb21wYXJpc29uDQpmaW5hbF9zZWxlY3RlZF9tb2RlbCA8LSBtb2RlbF9iYWNrd2FyZA0KDQpjYXQoIlxuXG4tLS0gTU9ERUwgQ09OVFJBU1Q6IEZ1bGwgdnMuIFNlbGVjdGVkIC0tLVxuIikNCmNhdCgiLS0tIEZ1bGwgTW9kZWwgTWV0cmljcyAtLS1cbiIpDQpjYXQoIlItc3F1YXJlZCAoRnVsbCBNb2RlbCk6Iiwgc3VtbWFyeShmdWxsX21vZGVsKSRyLnNxdWFyZWQsICJcbiIpDQpjYXQoIkFkanVzdGVkIFItc3F1YXJlZCAoRnVsbCBNb2RlbCk6Iiwgc3VtbWFyeShmdWxsX21vZGVsKSRhZGouci5zcXVhcmVkLCAiXG4iKQ0KY2F0KCJOdW1iZXIgb2YgQ29lZmZpY2llbnRzIChGdWxsIE1vZGVsKToiLCBsZW5ndGgoY29lZihmdWxsX21vZGVsKSksICJcbiIpDQoNCg0KY2F0KCJcbi0tLSBTZWxlY3RlZCBNb2RlbCBNZXRyaWNzIC0tLVxuIikNCmNhdCgiUi1zcXVhcmVkIChTZWxlY3RlZCBNb2RlbCk6Iiwgc3VtbWFyeShmaW5hbF9zZWxlY3RlZF9tb2RlbCkkci5zcXVhcmVkLCAiXG4iKQ0KY2F0KCJBZGp1c3RlZCBSLXNxdWFyZWQgKFNlbGVjdGVkIE1vZGVsKToiLCBzdW1tYXJ5KGZpbmFsX3NlbGVjdGVkX21vZGVsKSRhZGouci5zcXVhcmVkLCAiXG4iKQ0KY2F0KCJOdW1iZXIgb2YgQ29lZmZpY2llbnRzIChTZWxlY3RlZCBNb2RlbCk6IiwgbGVuZ3RoKGNvZWYoZmluYWxfc2VsZWN0ZWRfbW9kZWwpKSwgIlxuIikNCmBgYA0KDQojIyBDb25jbHVzaW9uDQpBIHN1Y2Nlc3NmdWwgdmFyaWFibGUgc2VsZWN0aW9uIHByb2Nlc3MsIGFzIGRlbW9uc3RyYXRlZCBoZXJlLCBhY2hpZXZlcyBhIHNlbGVjdGVkIG1vZGVsIHdpdGg6DQoNCjEuIF9fU2ltaWxhciBvciBIaWdoZXIgQWRqdXN0ZWQgJFJeMiRfXzogVGhpcyBjb25maXJtcyB0aGF0IHRoZSByZW1vdmVkIHZhcmlhYmxlcyB3ZXJlIG5vdCBjb250cmlidXRpbmcgbWVhbmluZ2Z1bGx5IHRvIHRoZSBvdmVyYWxsIHByZWRpY3RpdmUgcG93ZXIgb2YgdGhlIG1vZGVsLg0KDQoyLiBfX0Zld2VyIFBhcmFtZXRlcnNfXzogVGhlIGZpbmFsIG1vZGVsIGlzIG1vcmUgcGFyc2ltb25pb3VzLCBtYWtpbmcgdGhlIGNvZWZmaWNpZW50cyBlYXNpZXIgdG8gaW50ZXJwcmV0IGFuZCBwb3RlbnRpYWxseSBsZWFkaW5nIHRvIGJldHRlciBvdXQtb2Ytc2FtcGxlIHByZWRpY3Rpb24gKHJlZHVjZWQgcmlzayBvZiBvdmVyZml0dGluZykuDQoNCjMuIF9fTW9yZSBTdGFibGUgQ29lZmZpY2llbnRzX186IEJ5IHJlbW92aW5nIHJlZHVuZGFudCBvciBub24tc2lnbmlmaWNhbnQgdmFyaWFibGVzLCB0aGUgcmVtYWluaW5nIGNvZWZmaWNpZW50cyB0eXBpY2FsbHkgaGF2ZSBzbWFsbGVyIHN0YW5kYXJkIGVycm9ycywgaW5jcmVhc2luZyB0aGUgcHJlY2lzaW9uIG9mIG91ciBlc3RpbWF0ZXMu