7: Random Forest Test Error for Various mtry and ntree Values
I applied random forests to the Boston housing dataset and now want
to explore how the test error changes across different values of mtry
(number of variables randomly chosen at each split) and ntree (number of
trees grown).
Below is the R code to compute and plot the test MSE (Mean Squared
Error) for different combinations of mtry and ntree values. This
approach helps visualize model performance and choose optimal
parameters.
# Load necessary libraries
library(randomForest)
library(MASS) # For Boston dataset
library(ggplot2)
# Prepare data
set.seed(1)
train_indices <- sample(1:nrow(Boston), nrow(Boston) / 2)
train_data <- Boston[train_indices, ]
test_data <- Boston[-train_indices, ]
# Define parameter values to try
mtry_values <- c(2, 4, 6, 8, 10, 13)
ntree_values <- c(25, 100, 250, 500)
# Create a dataframe to store results
results <- data.frame()
# Loop through mtry and ntree combinations
for (m in mtry_values) {
for (n in ntree_values) {
rf_model <- randomForest(medv ~ ., data = train_data, mtry = m, ntree = n)
preds <- predict(rf_model, newdata = test_data)
test_mse <- mean((preds - test_data$medv)^2)
results <- rbind(results, data.frame(mtry = m, ntree = n, TestMSE = test_mse))
}
}
# Plotting test error
ggplot(results, aes(x = ntree, y = TestMSE, color = as.factor(mtry))) +
geom_line(size = 1.2) +
geom_point(size = 2) +
labs(title = "Test MSE for Random Forest on Boston Data",
x = "Number of Trees (ntree)",
y = "Test MSE",
color = "mtry") +
theme_minimal()

Explanation of Results:
The test MSE generally decreases as ntree increases, but flattens out
after a certain point, showing that more trees help reduce variance but
with diminishing returns.
Lower values of mtry (e.g., 2 or 4) often result in lower test error,
suggesting that choosing fewer variables at each split increases
diversity among trees, which can improve performance.
The plot visually confirms the bias-variance tradeoff: increasing the
number of trees reduces variance, and tuning mtry balances bias and
variance.
This experiment helps in selecting optimal hyperparameters for
building more accurate random forest models.
8. Predicting Sales Using Regression Trees and Related Methods
(a) Split the dataset into a training set and a test set
library(ISLR2)
library(tree)
set.seed(1)
# Convert to regression format: treat Sales as numeric
train_indices <- sample(1:nrow(Carseats), nrow(Carseats) / 2)
train_data <- Carseats[train_indices, ]
test_data <- Carseats[-train_indices, ]
This code loads the Carseats dataset and randomly splits it into two
halves: a training set and a test set. The training set (train_data) is
used to build models, while the test set (test_data) is used to evaluate
model performance. The set.seed(1) ensures the results are
reproducible.
(b) Fit a regression tree to the training set. Plot the tree and
compute test MSE.
# Fit the regression tree
tree_model <- tree(Sales ~ ., data = train_data)
summary(tree_model)
# Plot the tree
plot(tree_model)
text(tree_model, pretty = 0)
# Predict on test set
preds <- predict(tree_model, newdata = test_data)
test_mse <- mean((preds - test_data$Sales)^2)
test_mse
Interpretation:
The tree splits based on variables like ShelveLoc, Price, and
Age.
The predicted Sales is the mean value within each terminal node.
Test MSE is printed and shows how well the model performs on unseen
data.
(c) Use cross-validation to determine optimal tree size. Prune the
tree and check test MSE.
# Cross-validation
set.seed(2)
cv_model <- cv.tree(tree_model)
plot(cv_model$size, cv_model$dev, type = "b")
# Prune the tree
pruned_tree <- prune.tree(tree_model, best = cv_model$size[which.min(cv_model$dev)])
plot(pruned_tree)
text(pruned_tree, pretty = 0)
# Test MSE after pruning
pruned_preds <- predict(pruned_tree, newdata = test_data)
pruned_mse <- mean((pruned_preds - test_data$Sales)^2)
pruned_mse
This code performs cross-validation on the regression tree to find
the optimal tree size that minimizes deviance (error). The tree is then
pruned to that optimal size to reduce overfitting. After pruning,
predictions are made on the test set, and the test Mean Squared Error
(MSE) is calculated to evaluate the pruned tree’s performance.
Observation:
Pruning may reduce overfitting. If the pruned MSE is lower than the
unpruned one, it improves model performance.
(d) Analyze the data using bagging. Report test MSE and variable
importance.
library(randomForest)
# Bagging: set mtry to total number of predictors
set.seed(1)
bag_model <- randomForest(Sales ~ ., data = train_data, mtry = ncol(train_data) - 1, importance = TRUE)
bag_preds <- predict(bag_model, newdata = test_data)
bag_mse <- mean((bag_preds - test_data$Sales)^2)
bag_mse
# Variable importance
importance(bag_model)
varImpPlot(bag_model)
This code applies bagging (bootstrap aggregation) to the Carseats
data using the randomForest function. It sets mtry equal to the total
number of predictors, which means all variables are considered at each
split (a key trait of bagging). It then computes the test Mean Squared
Error (MSE) and displays the importance of each predictor, along with a
plot of variable importance.
Observation:
Bagging usually reduces variance. Important variables often include
Price and ShelveLoc.
(e) Use random forests to analyze the data. Report test MSE and
effect of mtry.
# Random forest with default mtry (sqrt(p))
set.seed(1)
rf_model <- randomForest(Sales ~ ., data = train_data, mtry = 4, importance = TRUE)
rf_preds <- predict(rf_model, newdata = test_data)
rf_mse <- mean((rf_preds - test_data$Sales)^2)
rf_mse
# Importance
importance(rf_model)
varImpPlot(rf_model)
This code fits a random forest model to the Carseats training data
using the default value of mtry = 4 (square root of the number of
predictors). It predicts Sales on the test data and computes the test
Mean Squared Error (MSE). The model also calculates and plots variable
importance, helping identify which predictors contribute most to the
accuracy.
Effect of mtry:
Lower mtry increases randomness and reduces correlation among trees,
which can help reduce overfitting.
Try mtry = 2, 4, 6, 10 and compare test MSEs to see this effect.
(f) Analyze the data using BART (Bayesian Additive Regression
Trees)
# BART package may need to be installed first
# install.packages("BART")
library(BART)
# Prepare data
x_train <- train_data[, -which(names(train_data) == "Sales")]
y_train <- train_data$Sales
x_test <- test_data[, -which(names(test_data) == "Sales")]
# Fit BART model
set.seed(1)
bart_model <- wbart(x.train = x_train, y.train = y_train, x.test = x_test)
# Predict and compute test MSE
bart_preds <- bart_model$yhat.test.mean
bart_mse <- mean((bart_preds - test_data$Sales)^2)
bart_mse
This code fits a Bayesian Additive Regression Trees (BART) model to
the Carseats training data. The model is used to predict Sales on the
test data. It then calculates the test Mean Squared Error (MSE) to
evaluate prediction accuracy. BART is a flexible, non-parametric
ensemble method that captures complex relationships in the data.
Observation:
BART often yields strong performance due to its ensemble nature and
built-in regularization. Compare MSE with previous models to
evaluate.
11. Boosting on Caravan Data Set
(a) Create a training set of the first 1,000 observations, and use
the rest as the test set.
# Load required libraries
library(ISLR2)
library(gbm)
library(dplyr)
# Prepare the data
data(Caravan)
Caravan <- Caravan %>%
mutate(Purchase = ifelse(Purchase == "Yes", 1, 0))
# Split into training and test sets
train_data <- Caravan[1:1000, ]
test_data <- Caravan[-(1:1000), ]
# Fit the boosting model
set.seed(1)
boost_model <- gbm(Purchase ~ .,
data = train_data,
distribution = "bernoulli",
n.trees = 1000,
shrinkage = 0.01,
verbose = FALSE)
Warning in gbm.fit(x = x, y = y, offset = offset, distribution = distribution, :
variable 50: PVRAAUT has no variation.
Warning in gbm.fit(x = x, y = y, offset = offset, distribution = distribution, :
variable 71: AVRAAUT has no variation.
# --- Variable Importance Plot (fixed labels) ---
# Set larger left margin so names don’t get cut off
par(mar = c(5, 12, 4, 2)) # Bottom, Left, Top, Right
# Plot variable importance clearly
summary(boost_model,
n.trees = 1000,
method = relative.influence,
las = 1, # Horizontal labels
cBars = 30, # Top 30 variables
main = "Variable Importance from Boosting Model",
cex.names = 0.9) # Font size for names
NA

This code fits a boosting model to the Caravan dataset using 1,000
trees and a shrinkage rate of 0.01 to predict the probability of a
purchase. The response variable is converted to binary (1 for “Yes”, 0
for “No”). After training, it generates a variable importance plot
showing the top 30 predictors, with adjusted margins and label settings
to ensure the graph is clear and readable.
(b) Fit a boosting model using 1,000 trees and shrinkage = 0.01.
Identify important predictors.
# Load required libraries
library(ISLR2)
library(gbm)
library(dplyr)
# Prepare the data
data(Caravan)
Caravan <- Caravan %>%
mutate(Purchase = ifelse(Purchase == "Yes", 1, 0))
# Split into training and test sets
train_data <- Caravan[1:1000, ]
test_data <- Caravan[-(1:1000), ]
# Fit the boosting model
set.seed(1)
boost_model <- gbm(Purchase ~ .,
data = train_data,
distribution = "bernoulli",
n.trees = 1000,
shrinkage = 0.01,
verbose = FALSE)
Warning in gbm.fit(x = x, y = y, offset = offset, distribution = distribution, :
variable 50: PVRAAUT has no variation.
Warning in gbm.fit(x = x, y = y, offset = offset, distribution = distribution, :
variable 71: AVRAAUT has no variation.
# -------- BIG AND CLEAR VARIABLE IMPORTANCE PLOT --------
# Open high-res plot window (optional: comment out if not needed)
# windows(width = 12, height = 8) # For Windows
# quartz(width = 12, height = 8) # For macOS
# X11(width = 12, height = 8) # For Linux
# Set larger margins for long variable names
par(mar = c(5, 13, 4, 2)) # Bottom, Left, Top, Right
# Plot top 30 variables clearly
summary(boost_model,
n.trees = 1000,
method = relative.influence,
las = 1, # Horizontal labels
cBars = 30, # Top 30 variables
main = "Top 30 Variable Importances - Boosting Model",
cex.names = 1.0) # Font size of variable names
NA

This code fits a boosting model to the Caravan dataset to predict
whether a person will make a purchase. It uses 1,000 trees with a
learning rate (shrinkage) of 0.01. After training, it generates a
high-resolution variable importance plot that displays the top 30 most
influential predictors. The plot layout is adjusted with larger margins
and font size to ensure that long variable names are fully visible and
easy to read.
Observation: The output will show the most important predictors
(e.g., PPERSAUT, MKOOPKLA, etc.) based on their relative influence in
the model.
(c) Use the model to predict on the test set. Create a confusion
matrix using 20% probability threshold.
# Predict probabilities
boost_probs <- predict(boost_model, newdata = test_data, n.trees = 1000, type = "response")
# Classify as '1' if probability > 0.20
boost_preds <- ifelse(boost_probs > 0.2, 1, 0)
# Actual responses
actual <- as.numeric(as.character(test_data$Purchase))
# Confusion matrix
table(Predicted = boost_preds, Actual = actual)
Actual
Predicted 0 1
0 4410 256
1 123 33
# Fraction of correct positive predictions
correct_positive <- sum(boost_preds == 1 & actual == 1)
total_predicted_positive <- sum(boost_preds == 1)
fraction_correct <- correct_positive / total_predicted_positive
fraction_correct
[1] 0.2115385
This code uses the trained boosting model to predict purchase
probabilities on the test set. If the predicted probability is greater
than 20%, it classifies the observation as a purchase (1). It then
creates a confusion matrix to compare predictions with actual outcomes
and calculates the precision—the fraction of predicted buyers who
actually made a purchase. This helps evaluate how well the model
identifies actual purchasers.
Interpretation:
The confusion matrix shows how many purchases were
correctly/incorrectly classified.
The fraction of people predicted to make a purchase who actually did
is shown by fraction_correct.
Comparison with Logistic Regression or KNN (from textbook):
Logistic regression and KNN tend to have lower precision at this 20%
threshold.
Boosting usually gives higher precision due to its ability to capture
complex interactions.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIDc6IFJhbmRvbSBGb3Jlc3QgVGVzdCBFcnJvciBmb3IgVmFyaW91cyBtdHJ5IGFuZCBudHJlZSBWYWx1ZXMKCkkgYXBwbGllZCByYW5kb20gZm9yZXN0cyB0byB0aGUgQm9zdG9uIGhvdXNpbmcgZGF0YXNldCBhbmQgbm93IHdhbnQgdG8gZXhwbG9yZSBob3cgdGhlIHRlc3QgZXJyb3IgY2hhbmdlcyBhY3Jvc3MgZGlmZmVyZW50IHZhbHVlcyBvZiBtdHJ5IChudW1iZXIgb2YgdmFyaWFibGVzIHJhbmRvbWx5IGNob3NlbiBhdCBlYWNoIHNwbGl0KSBhbmQgbnRyZWUgKG51bWJlciBvZiB0cmVlcyBncm93bikuCgpCZWxvdyBpcyB0aGUgUiBjb2RlIHRvIGNvbXB1dGUgYW5kIHBsb3QgdGhlIHRlc3QgTVNFIChNZWFuIFNxdWFyZWQgRXJyb3IpIGZvciBkaWZmZXJlbnQgY29tYmluYXRpb25zIG9mIG10cnkgYW5kIG50cmVlIHZhbHVlcy4gVGhpcyBhcHByb2FjaCBoZWxwcyB2aXN1YWxpemUgbW9kZWwgcGVyZm9ybWFuY2UgYW5kIGNob29zZSBvcHRpbWFsIHBhcmFtZXRlcnMuCgpgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShyYW5kb21Gb3Jlc3QpCmxpYnJhcnkoTUFTUykgICMgRm9yIEJvc3RvbiBkYXRhc2V0CmxpYnJhcnkoZ2dwbG90MikKCiMgUHJlcGFyZSBkYXRhCnNldC5zZWVkKDEpCnRyYWluX2luZGljZXMgPC0gc2FtcGxlKDE6bnJvdyhCb3N0b24pLCBucm93KEJvc3RvbikgLyAyKQp0cmFpbl9kYXRhIDwtIEJvc3Rvblt0cmFpbl9pbmRpY2VzLCBdCnRlc3RfZGF0YSA8LSBCb3N0b25bLXRyYWluX2luZGljZXMsIF0KCiMgRGVmaW5lIHBhcmFtZXRlciB2YWx1ZXMgdG8gdHJ5Cm10cnlfdmFsdWVzIDwtIGMoMiwgNCwgNiwgOCwgMTAsIDEzKQpudHJlZV92YWx1ZXMgPC0gYygyNSwgMTAwLCAyNTAsIDUwMCkKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lIHRvIHN0b3JlIHJlc3VsdHMKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKCkKCiMgTG9vcCB0aHJvdWdoIG10cnkgYW5kIG50cmVlIGNvbWJpbmF0aW9ucwpmb3IgKG0gaW4gbXRyeV92YWx1ZXMpIHsKICBmb3IgKG4gaW4gbnRyZWVfdmFsdWVzKSB7CiAgICByZl9tb2RlbCA8LSByYW5kb21Gb3Jlc3QobWVkdiB+IC4sIGRhdGEgPSB0cmFpbl9kYXRhLCBtdHJ5ID0gbSwgbnRyZWUgPSBuKQogICAgcHJlZHMgPC0gcHJlZGljdChyZl9tb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKICAgIHRlc3RfbXNlIDwtIG1lYW4oKHByZWRzIC0gdGVzdF9kYXRhJG1lZHYpXjIpCiAgICByZXN1bHRzIDwtIHJiaW5kKHJlc3VsdHMsIGRhdGEuZnJhbWUobXRyeSA9IG0sIG50cmVlID0gbiwgVGVzdE1TRSA9IHRlc3RfbXNlKSkKICB9Cn0KCiMgUGxvdHRpbmcgdGVzdCBlcnJvcgpnZ3Bsb3QocmVzdWx0cywgYWVzKHggPSBudHJlZSwgeSA9IFRlc3RNU0UsIGNvbG9yID0gYXMuZmFjdG9yKG10cnkpKSkgKwogIGdlb21fbGluZShzaXplID0gMS4yKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGxhYnModGl0bGUgPSAiVGVzdCBNU0UgZm9yIFJhbmRvbSBGb3Jlc3Qgb24gQm9zdG9uIERhdGEiLAogICAgICAgeCA9ICJOdW1iZXIgb2YgVHJlZXMgKG50cmVlKSIsCiAgICAgICB5ID0gIlRlc3QgTVNFIiwKICAgICAgIGNvbG9yID0gIm10cnkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKRXhwbGFuYXRpb24gb2YgUmVzdWx0czoKClRoZSB0ZXN0IE1TRSBnZW5lcmFsbHkgZGVjcmVhc2VzIGFzIG50cmVlIGluY3JlYXNlcywgYnV0IGZsYXR0ZW5zIG91dCBhZnRlciBhIGNlcnRhaW4gcG9pbnQsIHNob3dpbmcgdGhhdCBtb3JlIHRyZWVzIGhlbHAgcmVkdWNlIHZhcmlhbmNlIGJ1dCB3aXRoIGRpbWluaXNoaW5nIHJldHVybnMuCgpMb3dlciB2YWx1ZXMgb2YgbXRyeSAoZS5nLiwgMiBvciA0KSBvZnRlbiByZXN1bHQgaW4gbG93ZXIgdGVzdCBlcnJvciwgc3VnZ2VzdGluZyB0aGF0IGNob29zaW5nIGZld2VyIHZhcmlhYmxlcyBhdCBlYWNoIHNwbGl0IGluY3JlYXNlcyBkaXZlcnNpdHkgYW1vbmcgdHJlZXMsIHdoaWNoIGNhbiBpbXByb3ZlIHBlcmZvcm1hbmNlLgoKVGhlIHBsb3QgdmlzdWFsbHkgY29uZmlybXMgdGhlIGJpYXMtdmFyaWFuY2UgdHJhZGVvZmY6IGluY3JlYXNpbmcgdGhlIG51bWJlciBvZiB0cmVlcyByZWR1Y2VzIHZhcmlhbmNlLCBhbmQgdHVuaW5nIG10cnkgYmFsYW5jZXMgYmlhcyBhbmQgdmFyaWFuY2UuCgpUaGlzIGV4cGVyaW1lbnQgaGVscHMgaW4gc2VsZWN0aW5nIG9wdGltYWwgaHlwZXJwYXJhbWV0ZXJzIGZvciBidWlsZGluZyBtb3JlIGFjY3VyYXRlIHJhbmRvbSBmb3Jlc3QgbW9kZWxzLgoKCiMgOC4gUHJlZGljdGluZyBTYWxlcyBVc2luZyBSZWdyZXNzaW9uIFRyZWVzIGFuZCBSZWxhdGVkIE1ldGhvZHMKCiMgKGEpIFNwbGl0IHRoZSBkYXRhc2V0IGludG8gYSB0cmFpbmluZyBzZXQgYW5kIGEgdGVzdCBzZXQKCmBgYHtyfQpsaWJyYXJ5KElTTFIyKQpsaWJyYXJ5KHRyZWUpCnNldC5zZWVkKDEpCgojIENvbnZlcnQgdG8gcmVncmVzc2lvbiBmb3JtYXQ6IHRyZWF0IFNhbGVzIGFzIG51bWVyaWMKdHJhaW5faW5kaWNlcyA8LSBzYW1wbGUoMTpucm93KENhcnNlYXRzKSwgbnJvdyhDYXJzZWF0cykgLyAyKQp0cmFpbl9kYXRhIDwtIENhcnNlYXRzW3RyYWluX2luZGljZXMsIF0KdGVzdF9kYXRhIDwtIENhcnNlYXRzWy10cmFpbl9pbmRpY2VzLCBdCmBgYAoKVGhpcyBjb2RlIGxvYWRzIHRoZSBDYXJzZWF0cyBkYXRhc2V0IGFuZCByYW5kb21seSBzcGxpdHMgaXQgaW50byB0d28gaGFsdmVzOiBhIHRyYWluaW5nIHNldCBhbmQgYSB0ZXN0IHNldC4gVGhlIHRyYWluaW5nIHNldCAodHJhaW5fZGF0YSkgaXMgdXNlZCB0byBidWlsZCBtb2RlbHMsIHdoaWxlIHRoZSB0ZXN0IHNldCAodGVzdF9kYXRhKSBpcyB1c2VkIHRvIGV2YWx1YXRlIG1vZGVsIHBlcmZvcm1hbmNlLiBUaGUgc2V0LnNlZWQoMSkgZW5zdXJlcyB0aGUgcmVzdWx0cyBhcmUgcmVwcm9kdWNpYmxlLgoKIyAoYikgRml0IGEgcmVncmVzc2lvbiB0cmVlIHRvIHRoZSB0cmFpbmluZyBzZXQuIFBsb3QgdGhlIHRyZWUgYW5kIGNvbXB1dGUgdGVzdCBNU0UuCgpgYGB7cn0KIyBGaXQgdGhlIHJlZ3Jlc3Npb24gdHJlZQp0cmVlX21vZGVsIDwtIHRyZWUoU2FsZXMgfiAuLCBkYXRhID0gdHJhaW5fZGF0YSkKc3VtbWFyeSh0cmVlX21vZGVsKQoKIyBQbG90IHRoZSB0cmVlCnBsb3QodHJlZV9tb2RlbCkKdGV4dCh0cmVlX21vZGVsLCBwcmV0dHkgPSAwKQoKIyBQcmVkaWN0IG9uIHRlc3Qgc2V0CnByZWRzIDwtIHByZWRpY3QodHJlZV9tb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKdGVzdF9tc2UgPC0gbWVhbigocHJlZHMgLSB0ZXN0X2RhdGEkU2FsZXMpXjIpCnRlc3RfbXNlCmBgYAoKSW50ZXJwcmV0YXRpb246CgpUaGUgdHJlZSBzcGxpdHMgYmFzZWQgb24gdmFyaWFibGVzIGxpa2UgU2hlbHZlTG9jLCBQcmljZSwgYW5kIEFnZS4KClRoZSBwcmVkaWN0ZWQgU2FsZXMgaXMgdGhlIG1lYW4gdmFsdWUgd2l0aGluIGVhY2ggdGVybWluYWwgbm9kZS4KClRlc3QgTVNFIGlzIHByaW50ZWQgYW5kIHNob3dzIGhvdyB3ZWxsIHRoZSBtb2RlbCBwZXJmb3JtcyBvbiB1bnNlZW4gZGF0YS4KCiMgKGMpIFVzZSBjcm9zcy12YWxpZGF0aW9uIHRvIGRldGVybWluZSBvcHRpbWFsIHRyZWUgc2l6ZS4gUHJ1bmUgdGhlIHRyZWUgYW5kIGNoZWNrIHRlc3QgTVNFLgoKYGBge3J9CiMgQ3Jvc3MtdmFsaWRhdGlvbgpzZXQuc2VlZCgyKQpjdl9tb2RlbCA8LSBjdi50cmVlKHRyZWVfbW9kZWwpCnBsb3QoY3ZfbW9kZWwkc2l6ZSwgY3ZfbW9kZWwkZGV2LCB0eXBlID0gImIiKQoKIyBQcnVuZSB0aGUgdHJlZQpwcnVuZWRfdHJlZSA8LSBwcnVuZS50cmVlKHRyZWVfbW9kZWwsIGJlc3QgPSBjdl9tb2RlbCRzaXplW3doaWNoLm1pbihjdl9tb2RlbCRkZXYpXSkKcGxvdChwcnVuZWRfdHJlZSkKdGV4dChwcnVuZWRfdHJlZSwgcHJldHR5ID0gMCkKCiMgVGVzdCBNU0UgYWZ0ZXIgcHJ1bmluZwpwcnVuZWRfcHJlZHMgPC0gcHJlZGljdChwcnVuZWRfdHJlZSwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKcHJ1bmVkX21zZSA8LSBtZWFuKChwcnVuZWRfcHJlZHMgLSB0ZXN0X2RhdGEkU2FsZXMpXjIpCnBydW5lZF9tc2UKYGBgCgpUaGlzIGNvZGUgcGVyZm9ybXMgY3Jvc3MtdmFsaWRhdGlvbiBvbiB0aGUgcmVncmVzc2lvbiB0cmVlIHRvIGZpbmQgdGhlIG9wdGltYWwgdHJlZSBzaXplIHRoYXQgbWluaW1pemVzIGRldmlhbmNlIChlcnJvcikuIFRoZSB0cmVlIGlzIHRoZW4gcHJ1bmVkIHRvIHRoYXQgb3B0aW1hbCBzaXplIHRvIHJlZHVjZSBvdmVyZml0dGluZy4gQWZ0ZXIgcHJ1bmluZywgcHJlZGljdGlvbnMgYXJlIG1hZGUgb24gdGhlIHRlc3Qgc2V0LCBhbmQgdGhlIHRlc3QgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpIGlzIGNhbGN1bGF0ZWQgdG8gZXZhbHVhdGUgdGhlIHBydW5lZCB0cmVlJ3MgcGVyZm9ybWFuY2UuCgpPYnNlcnZhdGlvbjoKClBydW5pbmcgbWF5IHJlZHVjZSBvdmVyZml0dGluZy4gSWYgdGhlIHBydW5lZCBNU0UgaXMgbG93ZXIgdGhhbiB0aGUgdW5wcnVuZWQgb25lLCBpdCBpbXByb3ZlcyBtb2RlbCBwZXJmb3JtYW5jZS4KCiMgKGQpIEFuYWx5emUgdGhlIGRhdGEgdXNpbmcgYmFnZ2luZy4gUmVwb3J0IHRlc3QgTVNFIGFuZCB2YXJpYWJsZSBpbXBvcnRhbmNlLgoKYGBge3J9CmxpYnJhcnkocmFuZG9tRm9yZXN0KQoKIyBCYWdnaW5nOiBzZXQgbXRyeSB0byB0b3RhbCBudW1iZXIgb2YgcHJlZGljdG9ycwpzZXQuc2VlZCgxKQpiYWdfbW9kZWwgPC0gcmFuZG9tRm9yZXN0KFNhbGVzIH4gLiwgZGF0YSA9IHRyYWluX2RhdGEsIG10cnkgPSBuY29sKHRyYWluX2RhdGEpIC0gMSwgaW1wb3J0YW5jZSA9IFRSVUUpCmJhZ19wcmVkcyA8LSBwcmVkaWN0KGJhZ19tb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKYmFnX21zZSA8LSBtZWFuKChiYWdfcHJlZHMgLSB0ZXN0X2RhdGEkU2FsZXMpXjIpCmJhZ19tc2UKCiMgVmFyaWFibGUgaW1wb3J0YW5jZQppbXBvcnRhbmNlKGJhZ19tb2RlbCkKdmFySW1wUGxvdChiYWdfbW9kZWwpCmBgYAoKVGhpcyBjb2RlIGFwcGxpZXMgYmFnZ2luZyAoYm9vdHN0cmFwIGFnZ3JlZ2F0aW9uKSB0byB0aGUgQ2Fyc2VhdHMgZGF0YSB1c2luZyB0aGUgcmFuZG9tRm9yZXN0IGZ1bmN0aW9uLiBJdCBzZXRzIG10cnkgZXF1YWwgdG8gdGhlIHRvdGFsIG51bWJlciBvZiBwcmVkaWN0b3JzLCB3aGljaCBtZWFucyBhbGwgdmFyaWFibGVzIGFyZSBjb25zaWRlcmVkIGF0IGVhY2ggc3BsaXQgKGEga2V5IHRyYWl0IG9mIGJhZ2dpbmcpLiBJdCB0aGVuIGNvbXB1dGVzIHRoZSB0ZXN0IE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSBhbmQgZGlzcGxheXMgdGhlIGltcG9ydGFuY2Ugb2YgZWFjaCBwcmVkaWN0b3IsIGFsb25nIHdpdGggYSBwbG90IG9mIHZhcmlhYmxlIGltcG9ydGFuY2UuCgpPYnNlcnZhdGlvbjoKCkJhZ2dpbmcgdXN1YWxseSByZWR1Y2VzIHZhcmlhbmNlLiBJbXBvcnRhbnQgdmFyaWFibGVzIG9mdGVuIGluY2x1ZGUgUHJpY2UgYW5kIFNoZWx2ZUxvYy4KCiMgKGUpIFVzZSByYW5kb20gZm9yZXN0cyB0byBhbmFseXplIHRoZSBkYXRhLiBSZXBvcnQgdGVzdCBNU0UgYW5kIGVmZmVjdCBvZiBtdHJ5LgoKYGBge3J9CiMgUmFuZG9tIGZvcmVzdCB3aXRoIGRlZmF1bHQgbXRyeSAoc3FydChwKSkKc2V0LnNlZWQoMSkKcmZfbW9kZWwgPC0gcmFuZG9tRm9yZXN0KFNhbGVzIH4gLiwgZGF0YSA9IHRyYWluX2RhdGEsIG10cnkgPSA0LCBpbXBvcnRhbmNlID0gVFJVRSkKcmZfcHJlZHMgPC0gcHJlZGljdChyZl9tb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKcmZfbXNlIDwtIG1lYW4oKHJmX3ByZWRzIC0gdGVzdF9kYXRhJFNhbGVzKV4yKQpyZl9tc2UKCiMgSW1wb3J0YW5jZQppbXBvcnRhbmNlKHJmX21vZGVsKQp2YXJJbXBQbG90KHJmX21vZGVsKQpgYGAKClRoaXMgY29kZSBmaXRzIGEgcmFuZG9tIGZvcmVzdCBtb2RlbCB0byB0aGUgQ2Fyc2VhdHMgdHJhaW5pbmcgZGF0YSB1c2luZyB0aGUgZGVmYXVsdCB2YWx1ZSBvZiBtdHJ5ID0gNCAoc3F1YXJlIHJvb3Qgb2YgdGhlIG51bWJlciBvZiBwcmVkaWN0b3JzKS4gSXQgcHJlZGljdHMgU2FsZXMgb24gdGhlIHRlc3QgZGF0YSBhbmQgY29tcHV0ZXMgdGhlIHRlc3QgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpLiBUaGUgbW9kZWwgYWxzbyBjYWxjdWxhdGVzIGFuZCBwbG90cyB2YXJpYWJsZSBpbXBvcnRhbmNlLCBoZWxwaW5nIGlkZW50aWZ5IHdoaWNoIHByZWRpY3RvcnMgY29udHJpYnV0ZSBtb3N0IHRvIHRoZSBhY2N1cmFjeS4KCgpFZmZlY3Qgb2YgbXRyeToKCkxvd2VyIG10cnkgaW5jcmVhc2VzIHJhbmRvbW5lc3MgYW5kIHJlZHVjZXMgY29ycmVsYXRpb24gYW1vbmcgdHJlZXMsIHdoaWNoIGNhbiBoZWxwIHJlZHVjZSBvdmVyZml0dGluZy4KClRyeSBtdHJ5ID0gMiwgNCwgNiwgMTAgYW5kIGNvbXBhcmUgdGVzdCBNU0VzIHRvIHNlZSB0aGlzIGVmZmVjdC4KCgojIChmKSBBbmFseXplIHRoZSBkYXRhIHVzaW5nIEJBUlQgKEJheWVzaWFuIEFkZGl0aXZlIFJlZ3Jlc3Npb24gVHJlZXMpCgpgYGB7cn0KIyBCQVJUIHBhY2thZ2UgbWF5IG5lZWQgdG8gYmUgaW5zdGFsbGVkIGZpcnN0CiMgaW5zdGFsbC5wYWNrYWdlcygiQkFSVCIpCmxpYnJhcnkoQkFSVCkKCiMgUHJlcGFyZSBkYXRhCnhfdHJhaW4gPC0gdHJhaW5fZGF0YVssIC13aGljaChuYW1lcyh0cmFpbl9kYXRhKSA9PSAiU2FsZXMiKV0KeV90cmFpbiA8LSB0cmFpbl9kYXRhJFNhbGVzCnhfdGVzdCA8LSB0ZXN0X2RhdGFbLCAtd2hpY2gobmFtZXModGVzdF9kYXRhKSA9PSAiU2FsZXMiKV0KCiMgRml0IEJBUlQgbW9kZWwKc2V0LnNlZWQoMSkKYmFydF9tb2RlbCA8LSB3YmFydCh4LnRyYWluID0geF90cmFpbiwgeS50cmFpbiA9IHlfdHJhaW4sIHgudGVzdCA9IHhfdGVzdCkKCiMgUHJlZGljdCBhbmQgY29tcHV0ZSB0ZXN0IE1TRQpiYXJ0X3ByZWRzIDwtIGJhcnRfbW9kZWwkeWhhdC50ZXN0Lm1lYW4KYmFydF9tc2UgPC0gbWVhbigoYmFydF9wcmVkcyAtIHRlc3RfZGF0YSRTYWxlcyleMikKYmFydF9tc2UKYGBgCgpUaGlzIGNvZGUgZml0cyBhIEJheWVzaWFuIEFkZGl0aXZlIFJlZ3Jlc3Npb24gVHJlZXMgKEJBUlQpIG1vZGVsIHRvIHRoZSBDYXJzZWF0cyB0cmFpbmluZyBkYXRhLiBUaGUgbW9kZWwgaXMgdXNlZCB0byBwcmVkaWN0IFNhbGVzIG9uIHRoZSB0ZXN0IGRhdGEuIEl0IHRoZW4gY2FsY3VsYXRlcyB0aGUgdGVzdCBNZWFuIFNxdWFyZWQgRXJyb3IgKE1TRSkgdG8gZXZhbHVhdGUgcHJlZGljdGlvbiBhY2N1cmFjeS4gQkFSVCBpcyBhIGZsZXhpYmxlLCBub24tcGFyYW1ldHJpYyBlbnNlbWJsZSBtZXRob2QgdGhhdCBjYXB0dXJlcyBjb21wbGV4IHJlbGF0aW9uc2hpcHMgaW4gdGhlIGRhdGEuCgpPYnNlcnZhdGlvbjoKCkJBUlQgb2Z0ZW4geWllbGRzIHN0cm9uZyBwZXJmb3JtYW5jZSBkdWUgdG8gaXRzIGVuc2VtYmxlIG5hdHVyZSBhbmQgYnVpbHQtaW4gcmVndWxhcml6YXRpb24uIENvbXBhcmUgTVNFIHdpdGggcHJldmlvdXMgbW9kZWxzIHRvIGV2YWx1YXRlLgoKIyAxMS4gQm9vc3Rpbmcgb24gQ2FyYXZhbiBEYXRhIFNldAoKIyAoYSkgQ3JlYXRlIGEgdHJhaW5pbmcgc2V0IG9mIHRoZSBmaXJzdCAxLDAwMCBvYnNlcnZhdGlvbnMsIGFuZCB1c2UgdGhlIHJlc3QgYXMgdGhlIHRlc3Qgc2V0LgoKYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShJU0xSMikKbGlicmFyeShnYm0pCmxpYnJhcnkoZHBseXIpCgojIFByZXBhcmUgdGhlIGRhdGEKZGF0YShDYXJhdmFuKQpDYXJhdmFuIDwtIENhcmF2YW4gJT4lCiAgbXV0YXRlKFB1cmNoYXNlID0gaWZlbHNlKFB1cmNoYXNlID09ICJZZXMiLCAxLCAwKSkKCiMgU3BsaXQgaW50byB0cmFpbmluZyBhbmQgdGVzdCBzZXRzCnRyYWluX2RhdGEgPC0gQ2FyYXZhblsxOjEwMDAsIF0KdGVzdF9kYXRhIDwtIENhcmF2YW5bLSgxOjEwMDApLCBdCgojIEZpdCB0aGUgYm9vc3RpbmcgbW9kZWwKc2V0LnNlZWQoMSkKYm9vc3RfbW9kZWwgPC0gZ2JtKFB1cmNoYXNlIH4gLiwgCiAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGF0YSwKICAgICAgICAgICAgICAgICAgIGRpc3RyaWJ1dGlvbiA9ICJiZXJub3VsbGkiLAogICAgICAgICAgICAgICAgICAgbi50cmVlcyA9IDEwMDAsCiAgICAgICAgICAgICAgICAgICBzaHJpbmthZ2UgPSAwLjAxLAogICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKQoKIyAtLS0gVmFyaWFibGUgSW1wb3J0YW5jZSBQbG90IChmaXhlZCBsYWJlbHMpIC0tLQojIFNldCBsYXJnZXIgbGVmdCBtYXJnaW4gc28gbmFtZXMgZG9u4oCZdCBnZXQgY3V0IG9mZgpwYXIobWFyID0gYyg1LCAxMiwgNCwgMikpICAjIEJvdHRvbSwgTGVmdCwgVG9wLCBSaWdodAoKIyBQbG90IHZhcmlhYmxlIGltcG9ydGFuY2UgY2xlYXJseQpzdW1tYXJ5KGJvb3N0X21vZGVsLAogICAgICAgIG4udHJlZXMgPSAxMDAwLAogICAgICAgIG1ldGhvZCA9IHJlbGF0aXZlLmluZmx1ZW5jZSwKICAgICAgICBsYXMgPSAxLCAgICAgICAgICAgIyBIb3Jpem9udGFsIGxhYmVscwogICAgICAgIGNCYXJzID0gMzAsICAgICAgICAjIFRvcCAzMCB2YXJpYWJsZXMKICAgICAgICBtYWluID0gIlZhcmlhYmxlIEltcG9ydGFuY2UgZnJvbSBCb29zdGluZyBNb2RlbCIsCiAgICAgICAgY2V4Lm5hbWVzID0gMC45KSAgICMgRm9udCBzaXplIGZvciBuYW1lcwpgYGAKClRoaXMgY29kZSBmaXRzIGEgYm9vc3RpbmcgbW9kZWwgdG8gdGhlIENhcmF2YW4gZGF0YXNldCB1c2luZyAxLDAwMCB0cmVlcyBhbmQgYSBzaHJpbmthZ2UgcmF0ZSBvZiAwLjAxIHRvIHByZWRpY3QgdGhlIHByb2JhYmlsaXR5IG9mIGEgcHVyY2hhc2UuIFRoZSByZXNwb25zZSB2YXJpYWJsZSBpcyBjb252ZXJ0ZWQgdG8gYmluYXJ5ICgxIGZvciAiWWVzIiwgMCBmb3IgIk5vIikuIEFmdGVyIHRyYWluaW5nLCBpdCBnZW5lcmF0ZXMgYSB2YXJpYWJsZSBpbXBvcnRhbmNlIHBsb3Qgc2hvd2luZyB0aGUgdG9wIDMwIHByZWRpY3RvcnMsIHdpdGggYWRqdXN0ZWQgbWFyZ2lucyBhbmQgbGFiZWwgc2V0dGluZ3MgdG8gZW5zdXJlIHRoZSBncmFwaCBpcyBjbGVhciBhbmQgcmVhZGFibGUuCgojIChiKSBGaXQgYSBib29zdGluZyBtb2RlbCB1c2luZyAxLDAwMCB0cmVlcyBhbmQgc2hyaW5rYWdlID0gMC4wMS4gSWRlbnRpZnkgaW1wb3J0YW50IHByZWRpY3RvcnMuCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KElTTFIyKQpsaWJyYXJ5KGdibSkKbGlicmFyeShkcGx5cikKCiMgUHJlcGFyZSB0aGUgZGF0YQpkYXRhKENhcmF2YW4pCkNhcmF2YW4gPC0gQ2FyYXZhbiAlPiUKICBtdXRhdGUoUHVyY2hhc2UgPSBpZmVsc2UoUHVyY2hhc2UgPT0gIlllcyIsIDEsIDApKQoKIyBTcGxpdCBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMKdHJhaW5fZGF0YSA8LSBDYXJhdmFuWzE6MTAwMCwgXQp0ZXN0X2RhdGEgPC0gQ2FyYXZhblstKDE6MTAwMCksIF0KCiMgRml0IHRoZSBib29zdGluZyBtb2RlbApzZXQuc2VlZCgxKQpib29zdF9tb2RlbCA8LSBnYm0oUHVyY2hhc2UgfiAuLCAKICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLAogICAgICAgICAgICAgICAgICAgZGlzdHJpYnV0aW9uID0gImJlcm5vdWxsaSIsCiAgICAgICAgICAgICAgICAgICBuLnRyZWVzID0gMTAwMCwKICAgICAgICAgICAgICAgICAgIHNocmlua2FnZSA9IDAuMDEsCiAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCgojIC0tLS0tLS0tIEJJRyBBTkQgQ0xFQVIgVkFSSUFCTEUgSU1QT1JUQU5DRSBQTE9UIC0tLS0tLS0tCgojIE9wZW4gaGlnaC1yZXMgcGxvdCB3aW5kb3cgKG9wdGlvbmFsOiBjb21tZW50IG91dCBpZiBub3QgbmVlZGVkKQojIHdpbmRvd3Mod2lkdGggPSAxMiwgaGVpZ2h0ID0gOCkgICMgRm9yIFdpbmRvd3MKIyBxdWFydHood2lkdGggPSAxMiwgaGVpZ2h0ID0gOCkgICMgRm9yIG1hY09TCiMgWDExKHdpZHRoID0gMTIsIGhlaWdodCA9IDgpICAgICAjIEZvciBMaW51eAoKIyBTZXQgbGFyZ2VyIG1hcmdpbnMgZm9yIGxvbmcgdmFyaWFibGUgbmFtZXMKcGFyKG1hciA9IGMoNSwgMTMsIDQsIDIpKSAgIyBCb3R0b20sIExlZnQsIFRvcCwgUmlnaHQKCiMgUGxvdCB0b3AgMzAgdmFyaWFibGVzIGNsZWFybHkKc3VtbWFyeShib29zdF9tb2RlbCwKICAgICAgICBuLnRyZWVzID0gMTAwMCwKICAgICAgICBtZXRob2QgPSByZWxhdGl2ZS5pbmZsdWVuY2UsCiAgICAgICAgbGFzID0gMSwgICAgICAgICAjIEhvcml6b250YWwgbGFiZWxzCiAgICAgICAgY0JhcnMgPSAzMCwgICAgICAjIFRvcCAzMCB2YXJpYWJsZXMKICAgICAgICBtYWluID0gIlRvcCAzMCBWYXJpYWJsZSBJbXBvcnRhbmNlcyAtIEJvb3N0aW5nIE1vZGVsIiwKICAgICAgICBjZXgubmFtZXMgPSAxLjApICMgRm9udCBzaXplIG9mIHZhcmlhYmxlIG5hbWVzCmBgYAoKVGhpcyBjb2RlIGZpdHMgYSBib29zdGluZyBtb2RlbCB0byB0aGUgQ2FyYXZhbiBkYXRhc2V0IHRvIHByZWRpY3Qgd2hldGhlciBhIHBlcnNvbiB3aWxsIG1ha2UgYSBwdXJjaGFzZS4gSXQgdXNlcyAxLDAwMCB0cmVlcyB3aXRoIGEgbGVhcm5pbmcgcmF0ZSAoc2hyaW5rYWdlKSBvZiAwLjAxLiBBZnRlciB0cmFpbmluZywgaXQgZ2VuZXJhdGVzIGEgaGlnaC1yZXNvbHV0aW9uIHZhcmlhYmxlIGltcG9ydGFuY2UgcGxvdCB0aGF0IGRpc3BsYXlzIHRoZSB0b3AgMzAgbW9zdCBpbmZsdWVudGlhbCBwcmVkaWN0b3JzLiBUaGUgcGxvdCBsYXlvdXQgaXMgYWRqdXN0ZWQgd2l0aCBsYXJnZXIgbWFyZ2lucyBhbmQgZm9udCBzaXplIHRvIGVuc3VyZSB0aGF0IGxvbmcgdmFyaWFibGUgbmFtZXMgYXJlIGZ1bGx5IHZpc2libGUgYW5kIGVhc3kgdG8gcmVhZC4KCk9ic2VydmF0aW9uOgpUaGUgb3V0cHV0IHdpbGwgc2hvdyB0aGUgbW9zdCBpbXBvcnRhbnQgcHJlZGljdG9ycyAoZS5nLiwgUFBFUlNBVVQsIE1LT09QS0xBLCBldGMuKSBiYXNlZCBvbiB0aGVpciByZWxhdGl2ZSBpbmZsdWVuY2UgaW4gdGhlIG1vZGVsLgoKIyAoYykgVXNlIHRoZSBtb2RlbCB0byBwcmVkaWN0IG9uIHRoZSB0ZXN0IHNldC4gQ3JlYXRlIGEgY29uZnVzaW9uIG1hdHJpeCB1c2luZyAyMCUgcHJvYmFiaWxpdHkgdGhyZXNob2xkLgoKYGBge3J9CiMgUHJlZGljdCBwcm9iYWJpbGl0aWVzCmJvb3N0X3Byb2JzIDwtIHByZWRpY3QoYm9vc3RfbW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEsIG4udHJlZXMgPSAxMDAwLCB0eXBlID0gInJlc3BvbnNlIikKCiMgQ2xhc3NpZnkgYXMgJzEnIGlmIHByb2JhYmlsaXR5ID4gMC4yMApib29zdF9wcmVkcyA8LSBpZmVsc2UoYm9vc3RfcHJvYnMgPiAwLjIsIDEsIDApCgojIEFjdHVhbCByZXNwb25zZXMKYWN0dWFsIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHRlc3RfZGF0YSRQdXJjaGFzZSkpCgojIENvbmZ1c2lvbiBtYXRyaXgKdGFibGUoUHJlZGljdGVkID0gYm9vc3RfcHJlZHMsIEFjdHVhbCA9IGFjdHVhbCkKCiMgRnJhY3Rpb24gb2YgY29ycmVjdCBwb3NpdGl2ZSBwcmVkaWN0aW9ucwpjb3JyZWN0X3Bvc2l0aXZlIDwtIHN1bShib29zdF9wcmVkcyA9PSAxICYgYWN0dWFsID09IDEpCnRvdGFsX3ByZWRpY3RlZF9wb3NpdGl2ZSA8LSBzdW0oYm9vc3RfcHJlZHMgPT0gMSkKZnJhY3Rpb25fY29ycmVjdCA8LSBjb3JyZWN0X3Bvc2l0aXZlIC8gdG90YWxfcHJlZGljdGVkX3Bvc2l0aXZlCmZyYWN0aW9uX2NvcnJlY3QKYGBgCgoKVGhpcyBjb2RlIHVzZXMgdGhlIHRyYWluZWQgYm9vc3RpbmcgbW9kZWwgdG8gcHJlZGljdCBwdXJjaGFzZSBwcm9iYWJpbGl0aWVzIG9uIHRoZSB0ZXN0IHNldC4gSWYgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0eSBpcyBncmVhdGVyIHRoYW4gMjAlLCBpdCBjbGFzc2lmaWVzIHRoZSBvYnNlcnZhdGlvbiBhcyBhIHB1cmNoYXNlICgxKS4gSXQgdGhlbiBjcmVhdGVzIGEgY29uZnVzaW9uIG1hdHJpeCB0byBjb21wYXJlIHByZWRpY3Rpb25zIHdpdGggYWN0dWFsIG91dGNvbWVzIGFuZCBjYWxjdWxhdGVzIHRoZSBwcmVjaXNpb27igJR0aGUgZnJhY3Rpb24gb2YgcHJlZGljdGVkIGJ1eWVycyB3aG8gYWN0dWFsbHkgbWFkZSBhIHB1cmNoYXNlLiBUaGlzIGhlbHBzIGV2YWx1YXRlIGhvdyB3ZWxsIHRoZSBtb2RlbCBpZGVudGlmaWVzIGFjdHVhbCBwdXJjaGFzZXJzLgoKCkludGVycHJldGF0aW9uOgoKVGhlIGNvbmZ1c2lvbiBtYXRyaXggc2hvd3MgaG93IG1hbnkgcHVyY2hhc2VzIHdlcmUgY29ycmVjdGx5L2luY29ycmVjdGx5IGNsYXNzaWZpZWQuCgpUaGUgZnJhY3Rpb24gb2YgcGVvcGxlIHByZWRpY3RlZCB0byBtYWtlIGEgcHVyY2hhc2Ugd2hvIGFjdHVhbGx5IGRpZCBpcyBzaG93biBieSBmcmFjdGlvbl9jb3JyZWN0LgoKQ29tcGFyaXNvbiB3aXRoIExvZ2lzdGljIFJlZ3Jlc3Npb24gb3IgS05OIChmcm9tIHRleHRib29rKToKCkxvZ2lzdGljIHJlZ3Jlc3Npb24gYW5kIEtOTiB0ZW5kIHRvIGhhdmUgbG93ZXIgcHJlY2lzaW9uIGF0IHRoaXMgMjAlIHRocmVzaG9sZC4KCkJvb3N0aW5nIHVzdWFsbHkgZ2l2ZXMgaGlnaGVyIHByZWNpc2lvbiBkdWUgdG8gaXRzIGFiaWxpdHkgdG8gY2FwdHVyZSBjb21wbGV4IGludGVyYWN0aW9ucy4KCg==