Ridge regression is a regularization technique that addresses the issue of multicollinearity in regression problems. Multicollinearity occurs when two or more predictor variables (features) are highly correlated, leading to unstable estimates of the regression coefficients in ordinary least squares (OLS) regression. This instability manifests as large variance in the coefficient estimates, making the model less reliable and harder to generalize to new data.
How Ridge Regression Works
Ridge regression introduces a penalty term to the ordinary least squares loss function, which shrinks the regression coefficients, making them more stable. The modified loss function in Ridge regression is as follows:
\[
\text{Ridge Loss Function:} \quad L(\beta) = \sum_{i=1}^n (y_i - \hat{y}_i)^2 + \lambda \sum_{j=1}^p \beta_j^2
\]
Where:
- \(y_i\) are the observed responses.
- \(\hat{y}_i\) are the predicted responses based on the regression model.
- \(\beta_j\) are the coefficients of the predictor variables.
- \(\lambda\) is the tuning parameter that controls the strength of the regularization (penalty).
The first term in the loss function represents the ordinary least squares error (the sum of squared residuals), while the second term is the Ridge penalty, which adds a penalty proportional to the sum of the squares of the coefficients.
By introducing this penalty, Ridge regression forces the model to reduce the magnitude of the coefficients, especially in cases where the coefficients are inflated due to multicollinearity.
How Ridge Regression Addresses Multicollinearity
Shrinking Coefficients: In the presence of multicollinearity, the OLS estimates tend to have large variances, leading to large or erratic coefficients. Ridge regression shrinks these coefficients by adding a penalty based on their size. This shrinkage reduces their variance, leading to more stable and reliable coefficient estimates.
Bias-Variance Tradeoff: While Ridge regression introduces a small amount of bias (because the coefficients are shrunk towards zero), it dramatically reduces variance. This reduction in variance can result in a lower overall error in prediction, particularly when multicollinearity inflates the variances in OLS regression. The key advantage here is improved generalization to new data.
Handling Collinear Predictors: When predictor variables are highly correlated, the Ridge penalty effectively distributes the “influence” of these correlated variables across them by shrinking their coefficients. This means that instead of one variable having a disproportionately large coefficient due to multicollinearity, several correlated variables will have smaller but more stable coefficients.
Dependence on the Regularization Parameter (\(\lambda\)): The strength of the Ridge penalty is controlled by the parameter \(\lambda\). When \(\lambda = 0\), Ridge regression reduces to ordinary least squares regression, meaning no regularization is applied. As \(\lambda\) increases, the shrinkage effect increases, leading to more regularized coefficients. The optimal value of \(\lambda\) is typically chosen via cross-validation.
Mathematical Insights into Ridge Regression
In the case of OLS regression, the coefficient estimates \(\hat{\beta}\) can be computed as:
\[
\hat{\beta}_{OLS} = (X^TX)^{-1}X^Ty
\]
Where \(X\) is the matrix of predictors. When the predictors are highly collinear, \(X^TX\) becomes close to singular, meaning that its inverse is not well-defined or leads to large values in the coefficients. Ridge regression modifies this computation by adding the penalty term:
\[
\hat{\beta}_{Ridge} = (X^TX + \lambda I)^{-1}X^Ty
\]
Here, \(I\) is the identity matrix, and \(\lambda I\) is added to the diagonal of \(X^TX\), making the matrix invertible even when multicollinearity exists. This regularization reduces the sensitivity of the coefficients to the correlations between predictors.
Example in R
Let’s see how Ridge regression can be implemented in R using the glmnet
package, which provides a convenient interface for Ridge and Lasso regression.
# Load necessary library
library(glmnet)
# Generate some example data
set.seed(123)
X <- matrix(rnorm(100*10), 100, 10) # 100 samples, 10 predictors
y <- rnorm(100)
# Fit Ridge regression model (alpha = 0 for Ridge)
ridge_model <- glmnet(X, y, alpha = 0)
# Cross-validation to find optimal lambda
cv_ridge <- cv.glmnet(X, y, alpha = 0)
# Optimal lambda
optimal_lambda <- cv_ridge$lambda.min
print(optimal_lambda)
# Fit the final Ridge model using the optimal lambda
final_ridge_model <- glmnet(X, y, alpha = 0, lambda = optimal_lambda)
# Coefficients of the final model
coef(final_ridge_model)
In this example:
- The
glmnet()
function is used to fit a Ridge regression model. Setting alpha = 0
ensures that Ridge regression (and not Lasso regression) is used.
cv.glmnet()
is used to perform cross-validation, selecting the best \(\lambda\) that minimizes prediction error.
- The final model is fitted using the optimal \(\lambda\), and the coefficients are extracted.
Summary of Ridge Regression’s Benefits in the Presence of Multicollinearity
- Stabilizes coefficient estimates: By shrinking coefficients, Ridge regression reduces the impact of multicollinearity, producing more reliable estimates.
- Improves generalization: By addressing the variance introduced by multicollinearity, Ridge regression enhances the model’s ability to generalize to unseen data.
- Reduces overfitting: The penalty term discourages overly complex models, mitigating overfitting caused by multicollinear predictors.
In essence, Ridge regression is a robust tool for handling the instability in regression models caused by multicollinearity, offering a principled approach to balancing bias and variance.
References
No references.
LS0tCnRpdGxlOiAiUmlkZ2UgYW5kIExhc3NvIFJlZ3Jlc3Npb24iCnBhcmFtczoKICBjYXRlZ29yeTogMwogIHN0YWNrczogMAogIG51bWJlcjogNDQyCiAgdGltZTogMTAKICBsZXZlbDogYmVnaW5uZXIKICB0YWdzOiByZWdyZXNzaW9uLG9scyxtYWNoaW5lIGxlYXJuaW5nCiAgZGVzY3JpcHRpb246ICJJbnRyb2R1Y2VzIGxpbmVhciByZWdyZXNzaW9uIGFuZCBzdGF0aXN0aWNhbCBsZWFybmVycy4gU2hvd3MKICAgICAgICAgICAgICAgIGhvdyB0byBidWlsZCBhbmQgZXZhbHVhdGUgYSByZWdyZXNzaW9uIG1vZGVsLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKLS0tCnRpdGxlOiAiPHNtYWxsPmByIHBhcmFtcyRjYXRlZ29yeWAuYHIgcGFyYW1zJG51bWJlcmA8L3NtYWxsPjxici8+PHNwYW4gc3R5bGU9J2NvbG9yOiAjMkU0MDUzOyBmb250LXNpemU6IDAuOWVtJz5gciBybWFya2Rvd246Om1ldGFkYXRhJHRpdGxlYDwvc3Bhbj4iCi0tLQoKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2luc2VydDJEQi5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAoKUmlkZ2UgcmVncmVzc2lvbiBpcyBhIHJlZ3VsYXJpemF0aW9uIHRlY2huaXF1ZSB0aGF0IGFkZHJlc3NlcyB0aGUgaXNzdWUgb2YgbXVsdGljb2xsaW5lYXJpdHkgaW4gcmVncmVzc2lvbiBwcm9ibGVtcy4gTXVsdGljb2xsaW5lYXJpdHkgb2NjdXJzIHdoZW4gdHdvIG9yIG1vcmUgcHJlZGljdG9yIHZhcmlhYmxlcyAoZmVhdHVyZXMpIGFyZSBoaWdobHkgY29ycmVsYXRlZCwgbGVhZGluZyB0byB1bnN0YWJsZSBlc3RpbWF0ZXMgb2YgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGluIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgKE9MUykgcmVncmVzc2lvbi4gVGhpcyBpbnN0YWJpbGl0eSBtYW5pZmVzdHMgYXMgbGFyZ2UgdmFyaWFuY2UgaW4gdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcywgbWFraW5nIHRoZSBtb2RlbCBsZXNzIHJlbGlhYmxlIGFuZCBoYXJkZXIgdG8gZ2VuZXJhbGl6ZSB0byBuZXcgZGF0YS4KCiMjIyBIb3cgUmlkZ2UgUmVncmVzc2lvbiBXb3JrcwoKUmlkZ2UgcmVncmVzc2lvbiBpbnRyb2R1Y2VzIGEgcGVuYWx0eSB0ZXJtIHRvIHRoZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIGxvc3MgZnVuY3Rpb24sIHdoaWNoIHNocmlua3MgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCBtYWtpbmcgdGhlbSBtb3JlIHN0YWJsZS4gVGhlIG1vZGlmaWVkIGxvc3MgZnVuY3Rpb24gaW4gUmlkZ2UgcmVncmVzc2lvbiBpcyBhcyBmb2xsb3dzOgoKJCQKXHRleHR7UmlkZ2UgTG9zcyBGdW5jdGlvbjp9IFxxdWFkIEwoXGJldGEpID0gXHN1bV97aT0xfV5uICh5X2kgLSBcaGF0e3l9X2kpXjIgKyBcbGFtYmRhIFxzdW1fe2o9MX1ecCBcYmV0YV9qXjIKJCQKCldoZXJlOgoKLSAgICR5X2kkIGFyZSB0aGUgb2JzZXJ2ZWQgcmVzcG9uc2VzLgotICAgJFxoYXR7eX1faSQgYXJlIHRoZSBwcmVkaWN0ZWQgcmVzcG9uc2VzIGJhc2VkIG9uIHRoZSByZWdyZXNzaW9uIG1vZGVsLgotICAgJFxiZXRhX2okIGFyZSB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzLgotICAgJFxsYW1iZGEkIGlzIHRoZSB0dW5pbmcgcGFyYW1ldGVyIHRoYXQgY29udHJvbHMgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWd1bGFyaXphdGlvbiAocGVuYWx0eSkuCgpUaGUgZmlyc3QgdGVybSBpbiB0aGUgbG9zcyBmdW5jdGlvbiByZXByZXNlbnRzIHRoZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIGVycm9yICh0aGUgc3VtIG9mIHNxdWFyZWQgcmVzaWR1YWxzKSwgd2hpbGUgdGhlIHNlY29uZCB0ZXJtIGlzIHRoZSBSaWRnZSBwZW5hbHR5LCB3aGljaCBhZGRzIGEgcGVuYWx0eSBwcm9wb3J0aW9uYWwgdG8gdGhlIHN1bSBvZiB0aGUgc3F1YXJlcyBvZiB0aGUgY29lZmZpY2llbnRzLgoKQnkgaW50cm9kdWNpbmcgdGhpcyBwZW5hbHR5LCBSaWRnZSByZWdyZXNzaW9uIGZvcmNlcyB0aGUgbW9kZWwgdG8gcmVkdWNlIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGNvZWZmaWNpZW50cywgZXNwZWNpYWxseSBpbiBjYXNlcyB3aGVyZSB0aGUgY29lZmZpY2llbnRzIGFyZSBpbmZsYXRlZCBkdWUgdG8gbXVsdGljb2xsaW5lYXJpdHkuCgojIyMgSG93IFJpZGdlIFJlZ3Jlc3Npb24gQWRkcmVzc2VzIE11bHRpY29sbGluZWFyaXR5CgoxLiAgKipTaHJpbmtpbmcgQ29lZmZpY2llbnRzKio6IEluIHRoZSBwcmVzZW5jZSBvZiBtdWx0aWNvbGxpbmVhcml0eSwgdGhlIE9MUyBlc3RpbWF0ZXMgdGVuZCB0byBoYXZlIGxhcmdlIHZhcmlhbmNlcywgbGVhZGluZyB0byBsYXJnZSBvciBlcnJhdGljIGNvZWZmaWNpZW50cy4gUmlkZ2UgcmVncmVzc2lvbiBzaHJpbmtzIHRoZXNlIGNvZWZmaWNpZW50cyBieSBhZGRpbmcgYSBwZW5hbHR5IGJhc2VkIG9uIHRoZWlyIHNpemUuIFRoaXMgc2hyaW5rYWdlIHJlZHVjZXMgdGhlaXIgdmFyaWFuY2UsIGxlYWRpbmcgdG8gbW9yZSBzdGFibGUgYW5kIHJlbGlhYmxlIGNvZWZmaWNpZW50IGVzdGltYXRlcy4KCjIuICAqKkJpYXMtVmFyaWFuY2UgVHJhZGVvZmYqKjogV2hpbGUgUmlkZ2UgcmVncmVzc2lvbiBpbnRyb2R1Y2VzIGEgc21hbGwgYW1vdW50IG9mIGJpYXMgKGJlY2F1c2UgdGhlIGNvZWZmaWNpZW50cyBhcmUgc2hydW5rIHRvd2FyZHMgemVybyksIGl0IGRyYW1hdGljYWxseSByZWR1Y2VzIHZhcmlhbmNlLiBUaGlzIHJlZHVjdGlvbiBpbiB2YXJpYW5jZSBjYW4gcmVzdWx0IGluIGEgbG93ZXIgb3ZlcmFsbCBlcnJvciBpbiBwcmVkaWN0aW9uLCBwYXJ0aWN1bGFybHkgd2hlbiBtdWx0aWNvbGxpbmVhcml0eSBpbmZsYXRlcyB0aGUgdmFyaWFuY2VzIGluIE9MUyByZWdyZXNzaW9uLiBUaGUga2V5IGFkdmFudGFnZSBoZXJlIGlzIGltcHJvdmVkIGdlbmVyYWxpemF0aW9uIHRvIG5ldyBkYXRhLgoKMy4gICoqSGFuZGxpbmcgQ29sbGluZWFyIFByZWRpY3RvcnMqKjogV2hlbiBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBoaWdobHkgY29ycmVsYXRlZCwgdGhlIFJpZGdlIHBlbmFsdHkgZWZmZWN0aXZlbHkgZGlzdHJpYnV0ZXMgdGhlICJpbmZsdWVuY2UiIG9mIHRoZXNlIGNvcnJlbGF0ZWQgdmFyaWFibGVzIGFjcm9zcyB0aGVtIGJ5IHNocmlua2luZyB0aGVpciBjb2VmZmljaWVudHMuIFRoaXMgbWVhbnMgdGhhdCBpbnN0ZWFkIG9mIG9uZSB2YXJpYWJsZSBoYXZpbmcgYSBkaXNwcm9wb3J0aW9uYXRlbHkgbGFyZ2UgY29lZmZpY2llbnQgZHVlIHRvIG11bHRpY29sbGluZWFyaXR5LCBzZXZlcmFsIGNvcnJlbGF0ZWQgdmFyaWFibGVzIHdpbGwgaGF2ZSBzbWFsbGVyIGJ1dCBtb3JlIHN0YWJsZSBjb2VmZmljaWVudHMuCgo0LiAgKipEZXBlbmRlbmNlIG9uIHRoZSBSZWd1bGFyaXphdGlvbiBQYXJhbWV0ZXIgKCoqJFxsYW1iZGEkKTogVGhlIHN0cmVuZ3RoIG9mIHRoZSBSaWRnZSBwZW5hbHR5IGlzIGNvbnRyb2xsZWQgYnkgdGhlIHBhcmFtZXRlciAkXGxhbWJkYSQuIFdoZW4gJFxsYW1iZGEgPSAwJCwgUmlkZ2UgcmVncmVzc2lvbiByZWR1Y2VzIHRvIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiwgbWVhbmluZyBubyByZWd1bGFyaXphdGlvbiBpcyBhcHBsaWVkLiBBcyAkXGxhbWJkYSQgaW5jcmVhc2VzLCB0aGUgc2hyaW5rYWdlIGVmZmVjdCBpbmNyZWFzZXMsIGxlYWRpbmcgdG8gbW9yZSByZWd1bGFyaXplZCBjb2VmZmljaWVudHMuIFRoZSBvcHRpbWFsIHZhbHVlIG9mICRcbGFtYmRhJCBpcyB0eXBpY2FsbHkgY2hvc2VuIHZpYSBjcm9zcy12YWxpZGF0aW9uLgoKIyMjIE1hdGhlbWF0aWNhbCBJbnNpZ2h0cyBpbnRvIFJpZGdlIFJlZ3Jlc3Npb24KCkluIHRoZSBjYXNlIG9mIE9MUyByZWdyZXNzaW9uLCB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzICRcaGF0e1xiZXRhfSQgY2FuIGJlIGNvbXB1dGVkIGFzOgoKJCQKXGhhdHtcYmV0YX1fe09MU30gPSAoWF5UWCleey0xfVheVHkKJCQKCldoZXJlICRYJCBpcyB0aGUgbWF0cml4IG9mIHByZWRpY3RvcnMuIFdoZW4gdGhlIHByZWRpY3RvcnMgYXJlIGhpZ2hseSBjb2xsaW5lYXIsICRYXlRYJCBiZWNvbWVzIGNsb3NlIHRvIHNpbmd1bGFyLCBtZWFuaW5nIHRoYXQgaXRzIGludmVyc2UgaXMgbm90IHdlbGwtZGVmaW5lZCBvciBsZWFkcyB0byBsYXJnZSB2YWx1ZXMgaW4gdGhlIGNvZWZmaWNpZW50cy4gUmlkZ2UgcmVncmVzc2lvbiBtb2RpZmllcyB0aGlzIGNvbXB1dGF0aW9uIGJ5IGFkZGluZyB0aGUgcGVuYWx0eSB0ZXJtOgoKJCQKXGhhdHtcYmV0YX1fe1JpZGdlfSA9IChYXlRYICsgXGxhbWJkYSBJKV57LTF9WF5UeQokJAoKSGVyZSwgJEkkIGlzIHRoZSBpZGVudGl0eSBtYXRyaXgsIGFuZCAkXGxhbWJkYSBJJCBpcyBhZGRlZCB0byB0aGUgZGlhZ29uYWwgb2YgJFheVFgkLCBtYWtpbmcgdGhlIG1hdHJpeCBpbnZlcnRpYmxlIGV2ZW4gd2hlbiBtdWx0aWNvbGxpbmVhcml0eSBleGlzdHMuIFRoaXMgcmVndWxhcml6YXRpb24gcmVkdWNlcyB0aGUgc2Vuc2l0aXZpdHkgb2YgdGhlIGNvZWZmaWNpZW50cyB0byB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gcHJlZGljdG9ycy4KCiMjIyBFeGFtcGxlIGluIFIKCkxldCdzIHNlZSBob3cgUmlkZ2UgcmVncmVzc2lvbiBjYW4gYmUgaW1wbGVtZW50ZWQgaW4gUiB1c2luZyB0aGUgYGdsbW5ldGAgcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgYSBjb252ZW5pZW50IGludGVyZmFjZSBmb3IgUmlkZ2UgYW5kIExhc3NvIHJlZ3Jlc3Npb24uCgpgYGAgcgojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcnkKbGlicmFyeShnbG1uZXQpCgojIEdlbmVyYXRlIHNvbWUgZXhhbXBsZSBkYXRhCnNldC5zZWVkKDEyMykKWCA8LSBtYXRyaXgocm5vcm0oMTAwKjEwKSwgMTAwLCAxMCkgICMgMTAwIHNhbXBsZXMsIDEwIHByZWRpY3RvcnMKeSA8LSBybm9ybSgxMDApCgojIEZpdCBSaWRnZSByZWdyZXNzaW9uIG1vZGVsIChhbHBoYSA9IDAgZm9yIFJpZGdlKQpyaWRnZV9tb2RlbCA8LSBnbG1uZXQoWCwgeSwgYWxwaGEgPSAwKQoKIyBDcm9zcy12YWxpZGF0aW9uIHRvIGZpbmQgb3B0aW1hbCBsYW1iZGEKY3ZfcmlkZ2UgPC0gY3YuZ2xtbmV0KFgsIHksIGFscGhhID0gMCkKCiMgT3B0aW1hbCBsYW1iZGEKb3B0aW1hbF9sYW1iZGEgPC0gY3ZfcmlkZ2UkbGFtYmRhLm1pbgpwcmludChvcHRpbWFsX2xhbWJkYSkKCiMgRml0IHRoZSBmaW5hbCBSaWRnZSBtb2RlbCB1c2luZyB0aGUgb3B0aW1hbCBsYW1iZGEKZmluYWxfcmlkZ2VfbW9kZWwgPC0gZ2xtbmV0KFgsIHksIGFscGhhID0gMCwgbGFtYmRhID0gb3B0aW1hbF9sYW1iZGEpCgojIENvZWZmaWNpZW50cyBvZiB0aGUgZmluYWwgbW9kZWwKY29lZihmaW5hbF9yaWRnZV9tb2RlbCkKYGBgCgpJbiB0aGlzIGV4YW1wbGU6CgotICAgVGhlIGBnbG1uZXQoKWAgZnVuY3Rpb24gaXMgdXNlZCB0byBmaXQgYSBSaWRnZSByZWdyZXNzaW9uIG1vZGVsLiBTZXR0aW5nIGBhbHBoYSA9IDBgIGVuc3VyZXMgdGhhdCBSaWRnZSByZWdyZXNzaW9uIChhbmQgbm90IExhc3NvIHJlZ3Jlc3Npb24pIGlzIHVzZWQuCi0gICBgY3YuZ2xtbmV0KClgIGlzIHVzZWQgdG8gcGVyZm9ybSBjcm9zcy12YWxpZGF0aW9uLCBzZWxlY3RpbmcgdGhlIGJlc3QgJFxsYW1iZGEkIHRoYXQgbWluaW1pemVzIHByZWRpY3Rpb24gZXJyb3IuCi0gICBUaGUgZmluYWwgbW9kZWwgaXMgZml0dGVkIHVzaW5nIHRoZSBvcHRpbWFsICRcbGFtYmRhJCwgYW5kIHRoZSBjb2VmZmljaWVudHMgYXJlIGV4dHJhY3RlZC4KCiMjIyBTdW1tYXJ5IG9mIFJpZGdlIFJlZ3Jlc3Npb27igJlzIEJlbmVmaXRzIGluIHRoZSBQcmVzZW5jZSBvZiBNdWx0aWNvbGxpbmVhcml0eQoKLSAgICoqU3RhYmlsaXplcyBjb2VmZmljaWVudCBlc3RpbWF0ZXMqKjogQnkgc2hyaW5raW5nIGNvZWZmaWNpZW50cywgUmlkZ2UgcmVncmVzc2lvbiByZWR1Y2VzIHRoZSBpbXBhY3Qgb2YgbXVsdGljb2xsaW5lYXJpdHksIHByb2R1Y2luZyBtb3JlIHJlbGlhYmxlIGVzdGltYXRlcy4KLSAgICoqSW1wcm92ZXMgZ2VuZXJhbGl6YXRpb24qKjogQnkgYWRkcmVzc2luZyB0aGUgdmFyaWFuY2UgaW50cm9kdWNlZCBieSBtdWx0aWNvbGxpbmVhcml0eSwgUmlkZ2UgcmVncmVzc2lvbiBlbmhhbmNlcyB0aGUgbW9kZWwncyBhYmlsaXR5IHRvIGdlbmVyYWxpemUgdG8gdW5zZWVuIGRhdGEuCi0gICAqKlJlZHVjZXMgb3ZlcmZpdHRpbmcqKjogVGhlIHBlbmFsdHkgdGVybSBkaXNjb3VyYWdlcyBvdmVybHkgY29tcGxleCBtb2RlbHMsIG1pdGlnYXRpbmcgb3ZlcmZpdHRpbmcgY2F1c2VkIGJ5IG11bHRpY29sbGluZWFyIHByZWRpY3RvcnMuCgpJbiBlc3NlbmNlLCBSaWRnZSByZWdyZXNzaW9uIGlzIGEgcm9idXN0IHRvb2wgZm9yIGhhbmRsaW5nIHRoZSBpbnN0YWJpbGl0eSBpbiByZWdyZXNzaW9uIG1vZGVscyBjYXVzZWQgYnkgbXVsdGljb2xsaW5lYXJpdHksIG9mZmVyaW5nIGEgcHJpbmNpcGxlZCBhcHByb2FjaCB0byBiYWxhbmNpbmcgYmlhcyBhbmQgdmFyaWFuY2UuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIEZpbGVzICYgUmVzb3VyY2VzCgpgYGB7ciB6aXBGaWxlcywgZWNobz1GQUxTRX0KemlwTmFtZSA9IHNwcmludGYoIkxlc3NvbkZpbGVzLSVzLSVzLnppcCIsIAogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwKICAgICAgICAgICAgICAgICBwYXJhbXMkbnVtYmVyKQoKdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCAKICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LCIuIixwYXJhbXMkbnVtYmVyKQoKIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SCmtuaXRyOjpyYXdfaHRtbChkb3dubG9hZEZpbGVzTGluaygiLiIsIHppcE5hbWUsIHRleHRBTGluaykpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBSZWZlcmVuY2VzCgpObyByZWZlcmVuY2VzLgoKIyMgRXJyYXRhCgpbTGV0IHVzIGtub3ddKGh0dHBzOi8vZm9ybS5qb3Rmb3JtLmNvbS8yMTIxODcwNzI3ODQxNTcpe3RhcmdldD0iX2JsYW5rIn0uCg==