This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
5.Simulating Non-Linear Two-Class Data and Comparing SVM
Kernels
Step 1: Simulate non-linear data Explanation: I generated 100 random
points (x1 and x2) and assigned class labels based on a circular
boundary (x1² + x2² > 0.5). I then split the data into training and
testing sets.
# Load libraries
library(e1071)
library(ggplot2)
set.seed(123)
# Create 100 observations
n <- 100
x1 <- runif(n, -1, 1)
x2 <- runif(n, -1, 1)
# Non-linear boundary: circle
y <- ifelse(x1^2 + x2^2 > 0.5, 1, 0)
data <- data.frame(x1 = x1, x2 = x2, y = as.factor(y))
# Train-test split
train_idx <- sample(1:n, 70)
train_data <- data[train_idx, ]
test_data <- data[-train_idx, ]
Step 2: Fit SVM with linear kernel Explanation: I trained a Support
Vector Classifier (SVC) using a linear kernel on the training data, made
predictions on both train and test sets, and calculated their error
rates.
svm_linear <- svm(y ~ ., data = train_data, kernel = "linear", cost = 1)
pred_train_linear <- predict(svm_linear, train_data)
pred_test_linear <- predict(svm_linear, test_data)
train_err_linear <- mean(pred_train_linear != train_data$y)
test_err_linear <- mean(pred_test_linear != test_data$y)
Step 3: Fit SVM with polynomial kernel Explanation: I trained an SVM
with a polynomial kernel (degree = 2) to capture the non-linear pattern
in the data. I predicted on train and test sets and computed the
corresponding errors.
svm_poly <- svm(y ~ ., data = train_data, kernel = "polynomial", degree = 2, cost = 1)
pred_train_poly <- predict(svm_poly, train_data)
pred_test_poly <- predict(svm_poly, test_data)
train_err_poly <- mean(pred_train_poly != train_data$y)
test_err_poly <- mean(pred_test_poly != test_data$y)
Step 4: Fit SVM with radial kernel Explanation: I fitted an SVM with
a radial basis function (RBF) kernel, which is good for non-linear
decision boundaries, and measured the train and test error rates.
svm_radial <- svm(y ~ ., data = train_data, kernel = "radial", gamma = 1, cost = 1)
pred_train_radial <- predict(svm_radial, train_data)
pred_test_radial <- predict(svm_radial, test_data)
train_err_radial <- mean(pred_train_radial != train_data$y)
test_err_radial <- mean(pred_test_radial != test_data$y)
Step 5: Compare training and test errors Explanation: I created a
summary table comparing the training and test errors across the linear,
polynomial, and radial models to see which performed best.
error_df <- data.frame(
Model = c("Linear", "Polynomial", "Radial"),
TrainError = c(train_err_linear, train_err_poly, train_err_radial),
TestError = c(test_err_linear, test_err_poly, test_err_radial)
)
print(error_df)
Step 6: Plot decision boundaries Explanation: I plotted the decision
boundaries by predicting on a grid of points and visually checked how
well each model separated the two classes.
# Create grid
x1_seq <- seq(-1, 1, length = 100)
x2_seq <- seq(-1, 1, length = 100)
grid <- expand.grid(x1 = x1_seq, x2 = x2_seq)
# Add predictions
grid$linear <- predict(svm_linear, grid)
grid$poly <- predict(svm_poly, grid)
grid$radial <- predict(svm_radial, grid)
# Plot radial kernel (you can repeat for poly/linear)
ggplot() +
geom_point(data = grid, aes(x = x1, y = x2, color = radial), alpha = 0.3) +
geom_point(data = train_data, aes(x = x1, y = x2, shape = y), size = 2) +
labs(title = "SVM with Radial Kernel: Decision Boundary") +
theme_minimal()

7. SVM Analysis for Predicting High vs Low Gas Mileage
In this problem, I use SVM methods to classify cars based on whether
they have high or low gas mileage using the Auto dataset.
(a) Create a binary variable
I created a new binary variable called mpg01 in the Auto dataset. It
takes the value 1 if a car’s mpg is above the median, and 0
otherwise.
library(ISLR)
Attaching package: ‘ISLR’
The following object is masked _by_ ‘.GlobalEnv’:
Auto
data(Auto)
Auto$mpg01 <- ifelse(Auto$mpg > median(Auto$mpg), 1, 0)
Auto$mpg01 <- as.factor(Auto$mpg01) # Make it a factor for classification
(b) Fit a support vector classifier (linear kernel)
I removed the mpg variable since it’s used to create mpg01 and could
leak information. I split the data into training and test sets, then
used cross-validation to train a support vector classifier (linear
kernel) with different cost values.
set.seed(1)
library(e1071)
library(caret)
Loading required package: lattice
Registered S3 method overwritten by 'data.table':
method from
print.data.table
# Remove mpg and prepare data
auto_data <- Auto[, !names(Auto) %in% c("mpg")]
train_idx <- sample(1:nrow(auto_data), nrow(auto_data) * 0.7)
train <- auto_data[train_idx, ]
test <- auto_data[-train_idx, ]
# Tune linear SVM
tune_linear <- tune(svm, mpg01 ~ ., data = train, kernel = "linear",
ranges = list(cost = c(0.01, 0.1, 1, 10, 100)))
summary(tune_linear)
Parameter tuning of ‘svm’:
- sampling method: 10-fold cross validation
- best parameters:
- best performance: 0.08015873
- Detailed performance results:
NA
I observed that a lower cost (like 1 or 10) gives better
generalization and cross-validation error. Very small cost (e.g., 0.01)
underfits; high cost (e.g., 100) can overfit.
(c) Repeat with radial and polynomial kernels
I repeated the tuning process using a radial basis function (RBF)
kernel and a polynomial kernel.
Radial SVM:
tune_radial <- tune(svm, mpg01 ~ ., data = train, kernel = "radial",
ranges = list(cost = c(0.1, 1, 10), gamma = c(0.5, 1, 2)))
summary(tune_radial)
Polynomial SVM:
tune_poly <- tune(svm, mpg01 ~ ., data = train, kernel = "polynomial",
ranges = list(cost = c(0.1, 1, 10), degree = c(2, 3, 4)))
summary(tune_poly)
I found that the radial kernel generally performed better than
polynomial and linear for this dataset. Tuning gamma and degree was
crucial: too large values led to overfitting.
(d) Plotting the results
Since there are more than 2 predictors, I used plot.svm() on pairs of
variables to visualize the decision boundary.
# Best radial model
best_radial <- tune_radial$best.model
# Plot mpg01 using two predictors at a time
plot(best_radial, train, horsepower ~ weight)
plot(best_radial, train, displacement ~ acceleration)
These plots show how the decision boundary behaves differently across
variable pairs. With the radial kernel, boundaries curved more naturally
around clusters, supporting my earlier results.
SVM Modeling on OJ Dataset
(a) Create training and test sets
I randomly selected 800 observations from the OJ dataset for
training, and used the remaining data for testing.
library(ISLR2)
library(e1071)
set.seed(1)
train_idx <- sample(1:nrow(OJ), 800)
train <- OJ[train_idx, ]
test <- OJ[-train_idx, ]
(b) Fit a support vector classifier with cost = 0.01
I fit a linear SVM using cost = 0.01, predicting Purchase from the
other variables.
svm_linear <- svm(Purchase ~ ., data = train, kernel = "linear", cost = 0.01)
summary(svm_linear)
Call:
svm(formula = Purchase ~ ., data = train, kernel = "linear", cost = 0.01)
Parameters:
SVM-Type: C-classification
SVM-Kernel: linear
cost: 0.01
Number of Support Vectors: 435
( 219 216 )
Number of Classes: 2
Levels:
CH MM
From the summary, I observed:
The number of support vectors was large (because of low cost). Many
observations were close to the decision boundary.
(c) Calculate training and test error rates
I predicted on both train and test data and calculated the error
rates.
pred_train_linear <- predict(svm_linear, train)
pred_test_linear <- predict(svm_linear, test)
train_err_linear <- mean(pred_train_linear != train$Purchase)
test_err_linear <- mean(pred_test_linear != test$Purchase)
train_err_linear
test_err_linear
I found that both training and test errors were relatively high,
suggesting underfitting with cost = 0.01.
(d) Tune cost parameter using cross-validation
I used tune() to search for the best cost value between 0.01 and
10.
set.seed(1)
tune_linear <- tune(svm, Purchase ~ ., data = train, kernel = "linear",
ranges = list(cost = c(0.01, 0.1, 1, 10)))
# Extract best model
best_linear <- tune_linear$best.model
I observed that the best cost value was usually around 0.1 or 1,
depending on the cross-validation results.
(e) Recompute training and test errors using optimal cost
I refitted the SVM using the best cost and recalculated the
errors.
pred_train_best_linear <- predict(best_linear, train)
pred_test_best_linear <- predict(best_linear, test)
# Training and test error rates
train_err_best_linear <- mean(pred_train_best_linear != train$Purchase)
test_err_best_linear <- mean(pred_test_best_linear != test$Purchase)
# View errors
train_err_best_linear
[1] 0.165
test_err_best_linear
[1] 0.162963
(f) Repeat (b)–(e) with radial kernel
I fit an SVM with a radial kernel using the default gamma.
svm_radial <- svm(Purchase ~ ., data = train, kernel = "radial", cost = 0.01)
summary(svm_radial)
I repeated predictions and error calculations just like before.
I then tuned cost for radial:
set.seed(1)
tune_radial <- tune(svm, Purchase ~ ., data = train, kernel = "radial",
ranges = list(cost = c(0.01, 0.1, 1, 10)))
summary(tune_radial)
After fitting the best radial model, I computed training and test
errors.
(g) Repeat (b)–(e) with polynomial kernel (degree = 2)
I fit an SVM with a polynomial kernel (degree = 2).
svm_poly <- svm(Purchase ~ ., data = train, kernel = "polynomial", degree = 2, cost = 0.01)
summary(svm_poly)
I repeated the same steps: predicted, calculated errors, and tuned
cost.
set.seed(1)
tune_poly <- tune(svm, Purchase ~ ., data = train, kernel = "polynomial", degree = 2,
ranges = list(cost = c(0.01, 0.1, 1, 10)))
summary(tune_poly)
Then I recalculated the training and test errors after tuning.
(h) Overall best approach
I compared the test errors from all three kernels: linear, radial,
and polynomial.
I observed:
The radial kernel usually gave the lowest test error. Polynomial was
decent but sometimes overfit. Linear was the simplest but didn’t capture
complex patterns. Overall, the radial kernel performed best on the OJ
dataset.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgotLS0tLQoKIyA1LlNpbXVsYXRpbmcgTm9uLUxpbmVhciBUd28tQ2xhc3MgRGF0YSBhbmQgQ29tcGFyaW5nIFNWTSBLZXJuZWxzCgpTdGVwIDE6IFNpbXVsYXRlIG5vbi1saW5lYXIgZGF0YQpFeHBsYW5hdGlvbjoKSSBnZW5lcmF0ZWQgMTAwIHJhbmRvbSBwb2ludHMgKHgxIGFuZCB4MikgYW5kIGFzc2lnbmVkIGNsYXNzIGxhYmVscyBiYXNlZCBvbiBhIGNpcmN1bGFyIGJvdW5kYXJ5ICh4McKyICsgeDLCsiA+IDAuNSkuIEkgdGhlbiBzcGxpdCB0aGUgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHMuCgpgYGB7cn0KIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KGUxMDcxKQpsaWJyYXJ5KGdncGxvdDIpCnNldC5zZWVkKDEyMykKCiMgQ3JlYXRlIDEwMCBvYnNlcnZhdGlvbnMKbiA8LSAxMDAKeDEgPC0gcnVuaWYobiwgLTEsIDEpCngyIDwtIHJ1bmlmKG4sIC0xLCAxKQoKIyBOb24tbGluZWFyIGJvdW5kYXJ5OiBjaXJjbGUKeSA8LSBpZmVsc2UoeDFeMiArIHgyXjIgPiAwLjUsIDEsIDApCmRhdGEgPC0gZGF0YS5mcmFtZSh4MSA9IHgxLCB4MiA9IHgyLCB5ID0gYXMuZmFjdG9yKHkpKQoKIyBUcmFpbi10ZXN0IHNwbGl0CnRyYWluX2lkeCA8LSBzYW1wbGUoMTpuLCA3MCkKdHJhaW5fZGF0YSA8LSBkYXRhW3RyYWluX2lkeCwgXQp0ZXN0X2RhdGEgPC0gZGF0YVstdHJhaW5faWR4LCBdCmBgYAoKClN0ZXAgMjogRml0IFNWTSB3aXRoIGxpbmVhciBrZXJuZWwKRXhwbGFuYXRpb246CkkgdHJhaW5lZCBhIFN1cHBvcnQgVmVjdG9yIENsYXNzaWZpZXIgKFNWQykgdXNpbmcgYSBsaW5lYXIga2VybmVsIG9uIHRoZSB0cmFpbmluZyBkYXRhLCBtYWRlIHByZWRpY3Rpb25zIG9uIGJvdGggdHJhaW4gYW5kIHRlc3Qgc2V0cywgYW5kIGNhbGN1bGF0ZWQgdGhlaXIgZXJyb3IgcmF0ZXMuCgoKYGBge3J9CnN2bV9saW5lYXIgPC0gc3ZtKHkgfiAuLCBkYXRhID0gdHJhaW5fZGF0YSwga2VybmVsID0gImxpbmVhciIsIGNvc3QgPSAxKQpwcmVkX3RyYWluX2xpbmVhciA8LSBwcmVkaWN0KHN2bV9saW5lYXIsIHRyYWluX2RhdGEpCnByZWRfdGVzdF9saW5lYXIgPC0gcHJlZGljdChzdm1fbGluZWFyLCB0ZXN0X2RhdGEpCgp0cmFpbl9lcnJfbGluZWFyIDwtIG1lYW4ocHJlZF90cmFpbl9saW5lYXIgIT0gdHJhaW5fZGF0YSR5KQp0ZXN0X2Vycl9saW5lYXIgPC0gbWVhbihwcmVkX3Rlc3RfbGluZWFyICE9IHRlc3RfZGF0YSR5KQpgYGAKCgpTdGVwIDM6IEZpdCBTVk0gd2l0aCBwb2x5bm9taWFsIGtlcm5lbApFeHBsYW5hdGlvbjoKSSB0cmFpbmVkIGFuIFNWTSB3aXRoIGEgcG9seW5vbWlhbCBrZXJuZWwgKGRlZ3JlZSA9IDIpIHRvIGNhcHR1cmUgdGhlIG5vbi1saW5lYXIgcGF0dGVybiBpbiB0aGUgZGF0YS4gSSBwcmVkaWN0ZWQgb24gdHJhaW4gYW5kIHRlc3Qgc2V0cyBhbmQgY29tcHV0ZWQgdGhlIGNvcnJlc3BvbmRpbmcgZXJyb3JzLgoKYGBge3J9CnN2bV9wb2x5IDwtIHN2bSh5IH4gLiwgZGF0YSA9IHRyYWluX2RhdGEsIGtlcm5lbCA9ICJwb2x5bm9taWFsIiwgZGVncmVlID0gMiwgY29zdCA9IDEpCnByZWRfdHJhaW5fcG9seSA8LSBwcmVkaWN0KHN2bV9wb2x5LCB0cmFpbl9kYXRhKQpwcmVkX3Rlc3RfcG9seSA8LSBwcmVkaWN0KHN2bV9wb2x5LCB0ZXN0X2RhdGEpCgp0cmFpbl9lcnJfcG9seSA8LSBtZWFuKHByZWRfdHJhaW5fcG9seSAhPSB0cmFpbl9kYXRhJHkpCnRlc3RfZXJyX3BvbHkgPC0gbWVhbihwcmVkX3Rlc3RfcG9seSAhPSB0ZXN0X2RhdGEkeSkKYGBgCgoKU3RlcCA0OiBGaXQgU1ZNIHdpdGggcmFkaWFsIGtlcm5lbApFeHBsYW5hdGlvbjoKSSBmaXR0ZWQgYW4gU1ZNIHdpdGggYSByYWRpYWwgYmFzaXMgZnVuY3Rpb24gKFJCRikga2VybmVsLCB3aGljaCBpcyBnb29kIGZvciBub24tbGluZWFyIGRlY2lzaW9uIGJvdW5kYXJpZXMsIGFuZCBtZWFzdXJlZCB0aGUgdHJhaW4gYW5kIHRlc3QgZXJyb3IgcmF0ZXMuCgoKYGBge3J9CnN2bV9yYWRpYWwgPC0gc3ZtKHkgfiAuLCBkYXRhID0gdHJhaW5fZGF0YSwga2VybmVsID0gInJhZGlhbCIsIGdhbW1hID0gMSwgY29zdCA9IDEpCnByZWRfdHJhaW5fcmFkaWFsIDwtIHByZWRpY3Qoc3ZtX3JhZGlhbCwgdHJhaW5fZGF0YSkKcHJlZF90ZXN0X3JhZGlhbCA8LSBwcmVkaWN0KHN2bV9yYWRpYWwsIHRlc3RfZGF0YSkKCnRyYWluX2Vycl9yYWRpYWwgPC0gbWVhbihwcmVkX3RyYWluX3JhZGlhbCAhPSB0cmFpbl9kYXRhJHkpCnRlc3RfZXJyX3JhZGlhbCA8LSBtZWFuKHByZWRfdGVzdF9yYWRpYWwgIT0gdGVzdF9kYXRhJHkpCmBgYAoKU3RlcCA1OiBDb21wYXJlIHRyYWluaW5nIGFuZCB0ZXN0IGVycm9ycwpFeHBsYW5hdGlvbjoKSSBjcmVhdGVkIGEgc3VtbWFyeSB0YWJsZSBjb21wYXJpbmcgdGhlIHRyYWluaW5nIGFuZCB0ZXN0IGVycm9ycyBhY3Jvc3MgdGhlIGxpbmVhciwgcG9seW5vbWlhbCwgYW5kIHJhZGlhbCBtb2RlbHMgdG8gc2VlIHdoaWNoIHBlcmZvcm1lZCBiZXN0LgoKYGBge3J9CmVycm9yX2RmIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWwgPSBjKCJMaW5lYXIiLCAiUG9seW5vbWlhbCIsICJSYWRpYWwiKSwKICBUcmFpbkVycm9yID0gYyh0cmFpbl9lcnJfbGluZWFyLCB0cmFpbl9lcnJfcG9seSwgdHJhaW5fZXJyX3JhZGlhbCksCiAgVGVzdEVycm9yID0gYyh0ZXN0X2Vycl9saW5lYXIsIHRlc3RfZXJyX3BvbHksIHRlc3RfZXJyX3JhZGlhbCkKKQpwcmludChlcnJvcl9kZikKYGBgCgoKU3RlcCA2OiBQbG90IGRlY2lzaW9uIGJvdW5kYXJpZXMKRXhwbGFuYXRpb246CkkgcGxvdHRlZCB0aGUgZGVjaXNpb24gYm91bmRhcmllcyBieSBwcmVkaWN0aW5nIG9uIGEgZ3JpZCBvZiBwb2ludHMgYW5kIHZpc3VhbGx5IGNoZWNrZWQgaG93IHdlbGwgZWFjaCBtb2RlbCBzZXBhcmF0ZWQgdGhlIHR3byBjbGFzc2VzLgoKYGBge3J9CiMgQ3JlYXRlIGdyaWQKeDFfc2VxIDwtIHNlcSgtMSwgMSwgbGVuZ3RoID0gMTAwKQp4Ml9zZXEgPC0gc2VxKC0xLCAxLCBsZW5ndGggPSAxMDApCmdyaWQgPC0gZXhwYW5kLmdyaWQoeDEgPSB4MV9zZXEsIHgyID0geDJfc2VxKQoKIyBBZGQgcHJlZGljdGlvbnMKZ3JpZCRsaW5lYXIgPC0gcHJlZGljdChzdm1fbGluZWFyLCBncmlkKQpncmlkJHBvbHkgPC0gcHJlZGljdChzdm1fcG9seSwgZ3JpZCkKZ3JpZCRyYWRpYWwgPC0gcHJlZGljdChzdm1fcmFkaWFsLCBncmlkKQoKIyBQbG90IHJhZGlhbCBrZXJuZWwgKHlvdSBjYW4gcmVwZWF0IGZvciBwb2x5L2xpbmVhcikKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGdyaWQsIGFlcyh4ID0geDEsIHkgPSB4MiwgY29sb3IgPSByYWRpYWwpLCBhbHBoYSA9IDAuMykgKwogIGdlb21fcG9pbnQoZGF0YSA9IHRyYWluX2RhdGEsIGFlcyh4ID0geDEsIHkgPSB4Miwgc2hhcGUgPSB5KSwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlNWTSB3aXRoIFJhZGlhbCBLZXJuZWw6IERlY2lzaW9uIEJvdW5kYXJ5IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCgojIDcuIFNWTSBBbmFseXNpcyBmb3IgUHJlZGljdGluZyBIaWdoIHZzIExvdyBHYXMgTWlsZWFnZQoKSW4gdGhpcyBwcm9ibGVtLCBJIHVzZSBTVk0gbWV0aG9kcyB0byBjbGFzc2lmeSBjYXJzIGJhc2VkIG9uIHdoZXRoZXIgdGhleSBoYXZlIGhpZ2ggb3IgbG93IGdhcyBtaWxlYWdlIHVzaW5nIHRoZSBBdXRvIGRhdGFzZXQuCgojIChhKSBDcmVhdGUgYSBiaW5hcnkgdmFyaWFibGUKSSBjcmVhdGVkIGEgbmV3IGJpbmFyeSB2YXJpYWJsZSBjYWxsZWQgbXBnMDEgaW4gdGhlIEF1dG8gZGF0YXNldC4KSXQgdGFrZXMgdGhlIHZhbHVlIDEgaWYgYSBjYXLigJlzIG1wZyBpcyBhYm92ZSB0aGUgbWVkaWFuLCBhbmQgMCBvdGhlcndpc2UuCgpgYGB7cn0KbGlicmFyeShJU0xSKQpkYXRhKEF1dG8pCgpBdXRvJG1wZzAxIDwtIGlmZWxzZShBdXRvJG1wZyA+IG1lZGlhbihBdXRvJG1wZyksIDEsIDApCkF1dG8kbXBnMDEgPC0gYXMuZmFjdG9yKEF1dG8kbXBnMDEpICAjIE1ha2UgaXQgYSBmYWN0b3IgZm9yIGNsYXNzaWZpY2F0aW9uCmBgYAojIChiKSBGaXQgYSBzdXBwb3J0IHZlY3RvciBjbGFzc2lmaWVyIChsaW5lYXIga2VybmVsKQpJIHJlbW92ZWQgdGhlIG1wZyB2YXJpYWJsZSBzaW5jZSBpdOKAmXMgdXNlZCB0byBjcmVhdGUgbXBnMDEgYW5kIGNvdWxkIGxlYWsgaW5mb3JtYXRpb24uCkkgc3BsaXQgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdCBzZXRzLCB0aGVuIHVzZWQgY3Jvc3MtdmFsaWRhdGlvbiB0byB0cmFpbiBhIHN1cHBvcnQgdmVjdG9yIGNsYXNzaWZpZXIgKGxpbmVhciBrZXJuZWwpIHdpdGggZGlmZmVyZW50IGNvc3QgdmFsdWVzLgoKYGBge3J9CnNldC5zZWVkKDEpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoY2FyZXQpCgojIFJlbW92ZSBtcGcgYW5kIHByZXBhcmUgZGF0YQphdXRvX2RhdGEgPC0gQXV0b1ssICFuYW1lcyhBdXRvKSAlaW4lIGMoIm1wZyIpXQp0cmFpbl9pZHggPC0gc2FtcGxlKDE6bnJvdyhhdXRvX2RhdGEpLCBucm93KGF1dG9fZGF0YSkgKiAwLjcpCnRyYWluIDwtIGF1dG9fZGF0YVt0cmFpbl9pZHgsIF0KdGVzdCA8LSBhdXRvX2RhdGFbLXRyYWluX2lkeCwgXQoKIyBUdW5lIGxpbmVhciBTVk0KdHVuZV9saW5lYXIgPC0gdHVuZShzdm0sIG1wZzAxIH4gLiwgZGF0YSA9IHRyYWluLCBrZXJuZWwgPSAibGluZWFyIiwKICAgICAgICAgICAgICAgICAgICByYW5nZXMgPSBsaXN0KGNvc3QgPSBjKDAuMDEsIDAuMSwgMSwgMTAsIDEwMCkpKQoKc3VtbWFyeSh0dW5lX2xpbmVhcikKYGBgCgpJIG9ic2VydmVkIHRoYXQgYSBsb3dlciBjb3N0IChsaWtlIDEgb3IgMTApIGdpdmVzIGJldHRlciBnZW5lcmFsaXphdGlvbiBhbmQgY3Jvc3MtdmFsaWRhdGlvbiBlcnJvci4KVmVyeSBzbWFsbCBjb3N0IChlLmcuLCAwLjAxKSB1bmRlcmZpdHM7IGhpZ2ggY29zdCAoZS5nLiwgMTAwKSBjYW4gb3ZlcmZpdC4KCiMgKGMpIFJlcGVhdCB3aXRoIHJhZGlhbCBhbmQgcG9seW5vbWlhbCBrZXJuZWxzCkkgcmVwZWF0ZWQgdGhlIHR1bmluZyBwcm9jZXNzIHVzaW5nIGEgcmFkaWFsIGJhc2lzIGZ1bmN0aW9uIChSQkYpIGtlcm5lbCBhbmQgYSBwb2x5bm9taWFsIGtlcm5lbC4KClJhZGlhbCBTVk06CgpgYGB7cn0KdHVuZV9yYWRpYWwgPC0gdHVuZShzdm0sIG1wZzAxIH4gLiwgZGF0YSA9IHRyYWluLCBrZXJuZWwgPSAicmFkaWFsIiwKICAgICAgICAgICAgICAgICAgICByYW5nZXMgPSBsaXN0KGNvc3QgPSBjKDAuMSwgMSwgMTApLCBnYW1tYSA9IGMoMC41LCAxLCAyKSkpCgpzdW1tYXJ5KHR1bmVfcmFkaWFsKQpgYGAKClBvbHlub21pYWwgU1ZNOgoKYGBge3J9CnR1bmVfcG9seSA8LSB0dW5lKHN2bSwgbXBnMDEgfiAuLCBkYXRhID0gdHJhaW4sIGtlcm5lbCA9ICJwb2x5bm9taWFsIiwKICAgICAgICAgICAgICAgICAgcmFuZ2VzID0gbGlzdChjb3N0ID0gYygwLjEsIDEsIDEwKSwgZGVncmVlID0gYygyLCAzLCA0KSkpCgpzdW1tYXJ5KHR1bmVfcG9seSkKYGBgCgpJIGZvdW5kIHRoYXQgdGhlIHJhZGlhbCBrZXJuZWwgZ2VuZXJhbGx5IHBlcmZvcm1lZCBiZXR0ZXIgdGhhbiBwb2x5bm9taWFsIGFuZCBsaW5lYXIgZm9yIHRoaXMgZGF0YXNldC4KVHVuaW5nIGdhbW1hIGFuZCBkZWdyZWUgd2FzIGNydWNpYWw6IHRvbyBsYXJnZSB2YWx1ZXMgbGVkIHRvIG92ZXJmaXR0aW5nLgoKIyAoZCkgUGxvdHRpbmcgdGhlIHJlc3VsdHMKU2luY2UgdGhlcmUgYXJlIG1vcmUgdGhhbiAyIHByZWRpY3RvcnMsIEkgdXNlZCBwbG90LnN2bSgpIG9uIHBhaXJzIG9mIHZhcmlhYmxlcyB0byB2aXN1YWxpemUgdGhlIGRlY2lzaW9uIGJvdW5kYXJ5LgoKYGBge3J9CiMgQmVzdCByYWRpYWwgbW9kZWwKYmVzdF9yYWRpYWwgPC0gdHVuZV9yYWRpYWwkYmVzdC5tb2RlbAoKIyBQbG90IG1wZzAxIHVzaW5nIHR3byBwcmVkaWN0b3JzIGF0IGEgdGltZQpwbG90KGJlc3RfcmFkaWFsLCB0cmFpbiwgaG9yc2Vwb3dlciB+IHdlaWdodCkKcGxvdChiZXN0X3JhZGlhbCwgdHJhaW4sIGRpc3BsYWNlbWVudCB+IGFjY2VsZXJhdGlvbikKYGBgCgpUaGVzZSBwbG90cyBzaG93IGhvdyB0aGUgZGVjaXNpb24gYm91bmRhcnkgYmVoYXZlcyBkaWZmZXJlbnRseSBhY3Jvc3MgdmFyaWFibGUgcGFpcnMuCldpdGggdGhlIHJhZGlhbCBrZXJuZWwsIGJvdW5kYXJpZXMgY3VydmVkIG1vcmUgbmF0dXJhbGx5IGFyb3VuZCBjbHVzdGVycywgc3VwcG9ydGluZyBteSBlYXJsaWVyIHJlc3VsdHMuCgojIFNWTSBNb2RlbGluZyBvbiBPSiBEYXRhc2V0CgojIChhKSBDcmVhdGUgdHJhaW5pbmcgYW5kIHRlc3Qgc2V0cwpJIHJhbmRvbWx5IHNlbGVjdGVkIDgwMCBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgT0ogZGF0YXNldCBmb3IgdHJhaW5pbmcsIGFuZCB1c2VkIHRoZSByZW1haW5pbmcgZGF0YSBmb3IgdGVzdGluZy4KCmBgYHtyfQpsaWJyYXJ5KElTTFIyKQpsaWJyYXJ5KGUxMDcxKQpzZXQuc2VlZCgxKQoKdHJhaW5faWR4IDwtIHNhbXBsZSgxOm5yb3coT0opLCA4MDApCnRyYWluIDwtIE9KW3RyYWluX2lkeCwgXQp0ZXN0IDwtIE9KWy10cmFpbl9pZHgsIF0KYGBgCgojIChiKSBGaXQgYSBzdXBwb3J0IHZlY3RvciBjbGFzc2lmaWVyIHdpdGggY29zdCA9IDAuMDEKSSBmaXQgYSBsaW5lYXIgU1ZNIHVzaW5nIGNvc3QgPSAwLjAxLCBwcmVkaWN0aW5nIFB1cmNoYXNlIGZyb20gdGhlIG90aGVyIHZhcmlhYmxlcy4KCmBgYHtyfQpzdm1fbGluZWFyIDwtIHN2bShQdXJjaGFzZSB+IC4sIGRhdGEgPSB0cmFpbiwga2VybmVsID0gImxpbmVhciIsIGNvc3QgPSAwLjAxKQpzdW1tYXJ5KHN2bV9saW5lYXIpCmBgYAoKRnJvbSB0aGUgc3VtbWFyeSwgSSBvYnNlcnZlZDoKClRoZSBudW1iZXIgb2Ygc3VwcG9ydCB2ZWN0b3JzIHdhcyBsYXJnZSAoYmVjYXVzZSBvZiBsb3cgY29zdCkuCk1hbnkgb2JzZXJ2YXRpb25zIHdlcmUgY2xvc2UgdG8gdGhlIGRlY2lzaW9uIGJvdW5kYXJ5LgoKIyAoYykgQ2FsY3VsYXRlIHRyYWluaW5nIGFuZCB0ZXN0IGVycm9yIHJhdGVzCkkgcHJlZGljdGVkIG9uIGJvdGggdHJhaW4gYW5kIHRlc3QgZGF0YSBhbmQgY2FsY3VsYXRlZCB0aGUgZXJyb3IgcmF0ZXMuCgpgYGB7cn0KcHJlZF90cmFpbl9saW5lYXIgPC0gcHJlZGljdChzdm1fbGluZWFyLCB0cmFpbikKcHJlZF90ZXN0X2xpbmVhciA8LSBwcmVkaWN0KHN2bV9saW5lYXIsIHRlc3QpCgp0cmFpbl9lcnJfbGluZWFyIDwtIG1lYW4ocHJlZF90cmFpbl9saW5lYXIgIT0gdHJhaW4kUHVyY2hhc2UpCnRlc3RfZXJyX2xpbmVhciA8LSBtZWFuKHByZWRfdGVzdF9saW5lYXIgIT0gdGVzdCRQdXJjaGFzZSkKdHJhaW5fZXJyX2xpbmVhcgp0ZXN0X2Vycl9saW5lYXIKYGBgCgpJIGZvdW5kIHRoYXQgYm90aCB0cmFpbmluZyBhbmQgdGVzdCBlcnJvcnMgd2VyZSByZWxhdGl2ZWx5IGhpZ2gsIHN1Z2dlc3RpbmcgdW5kZXJmaXR0aW5nIHdpdGggY29zdCA9IDAuMDEuCgojIChkKSBUdW5lIGNvc3QgcGFyYW1ldGVyIHVzaW5nIGNyb3NzLXZhbGlkYXRpb24KSSB1c2VkIHR1bmUoKSB0byBzZWFyY2ggZm9yIHRoZSBiZXN0IGNvc3QgdmFsdWUgYmV0d2VlbiAwLjAxIGFuZCAxMC4KCmBgYHtyfQpzZXQuc2VlZCgxKQp0dW5lX2xpbmVhciA8LSB0dW5lKHN2bSwgUHVyY2hhc2UgfiAuLCBkYXRhID0gdHJhaW4sIGtlcm5lbCA9ICJsaW5lYXIiLAogICAgICAgICAgICAgICAgICAgIHJhbmdlcyA9IGxpc3QoY29zdCA9IGMoMC4wMSwgMC4xLCAxLCAxMCkpKQoKIyBFeHRyYWN0IGJlc3QgbW9kZWwKYmVzdF9saW5lYXIgPC0gdHVuZV9saW5lYXIkYmVzdC5tb2RlbApgYGAKCkkgb2JzZXJ2ZWQgdGhhdCB0aGUgYmVzdCBjb3N0IHZhbHVlIHdhcyB1c3VhbGx5IGFyb3VuZCAwLjEgb3IgMSwgZGVwZW5kaW5nIG9uIHRoZSBjcm9zcy12YWxpZGF0aW9uIHJlc3VsdHMuCgojIChlKSBSZWNvbXB1dGUgdHJhaW5pbmcgYW5kIHRlc3QgZXJyb3JzIHVzaW5nIG9wdGltYWwgY29zdApJIHJlZml0dGVkIHRoZSBTVk0gdXNpbmcgdGhlIGJlc3QgY29zdCBhbmQgcmVjYWxjdWxhdGVkIHRoZSBlcnJvcnMuCgpgYGB7cn0KcHJlZF90cmFpbl9iZXN0X2xpbmVhciA8LSBwcmVkaWN0KGJlc3RfbGluZWFyLCB0cmFpbikKcHJlZF90ZXN0X2Jlc3RfbGluZWFyIDwtIHByZWRpY3QoYmVzdF9saW5lYXIsIHRlc3QpCgojIFRyYWluaW5nIGFuZCB0ZXN0IGVycm9yIHJhdGVzCnRyYWluX2Vycl9iZXN0X2xpbmVhciA8LSBtZWFuKHByZWRfdHJhaW5fYmVzdF9saW5lYXIgIT0gdHJhaW4kUHVyY2hhc2UpCnRlc3RfZXJyX2Jlc3RfbGluZWFyIDwtIG1lYW4ocHJlZF90ZXN0X2Jlc3RfbGluZWFyICE9IHRlc3QkUHVyY2hhc2UpCgojIFZpZXcgZXJyb3JzCnRyYWluX2Vycl9iZXN0X2xpbmVhcgp0ZXN0X2Vycl9iZXN0X2xpbmVhcgpgYGAKCiMgKGYpIFJlcGVhdCAoYinigJMoZSkgd2l0aCByYWRpYWwga2VybmVsCkkgZml0IGFuIFNWTSB3aXRoIGEgcmFkaWFsIGtlcm5lbCB1c2luZyB0aGUgZGVmYXVsdCBnYW1tYS4KCmBgYHtyfQpzdm1fcmFkaWFsIDwtIHN2bShQdXJjaGFzZSB+IC4sIGRhdGEgPSB0cmFpbiwga2VybmVsID0gInJhZGlhbCIsIGNvc3QgPSAwLjAxKQpzdW1tYXJ5KHN2bV9yYWRpYWwpCmBgYAoKSSByZXBlYXRlZCBwcmVkaWN0aW9ucyBhbmQgZXJyb3IgY2FsY3VsYXRpb25zIGp1c3QgbGlrZSBiZWZvcmUuCgpJIHRoZW4gdHVuZWQgY29zdCBmb3IgcmFkaWFsOgoKYGBge3J9CnNldC5zZWVkKDEpCnR1bmVfcmFkaWFsIDwtIHR1bmUoc3ZtLCBQdXJjaGFzZSB+IC4sIGRhdGEgPSB0cmFpbiwga2VybmVsID0gInJhZGlhbCIsCiAgICAgICAgICAgICAgICAgICAgcmFuZ2VzID0gbGlzdChjb3N0ID0gYygwLjAxLCAwLjEsIDEsIDEwKSkpCnN1bW1hcnkodHVuZV9yYWRpYWwpCmBgYAoKQWZ0ZXIgZml0dGluZyB0aGUgYmVzdCByYWRpYWwgbW9kZWwsIEkgY29tcHV0ZWQgdHJhaW5pbmcgYW5kIHRlc3QgZXJyb3JzLgoKIyAoZykgUmVwZWF0IChiKeKAkyhlKSB3aXRoIHBvbHlub21pYWwga2VybmVsIChkZWdyZWUgPSAyKQpJIGZpdCBhbiBTVk0gd2l0aCBhIHBvbHlub21pYWwga2VybmVsIChkZWdyZWUgPSAyKS4KCmBgYHtyfQpzdm1fcG9seSA8LSBzdm0oUHVyY2hhc2UgfiAuLCBkYXRhID0gdHJhaW4sIGtlcm5lbCA9ICJwb2x5bm9taWFsIiwgZGVncmVlID0gMiwgY29zdCA9IDAuMDEpCnN1bW1hcnkoc3ZtX3BvbHkpCmBgYAoKSSByZXBlYXRlZCB0aGUgc2FtZSBzdGVwczogcHJlZGljdGVkLCBjYWxjdWxhdGVkIGVycm9ycywgYW5kIHR1bmVkIGNvc3QuCgpgYGB7cn0Kc2V0LnNlZWQoMSkKdHVuZV9wb2x5IDwtIHR1bmUoc3ZtLCBQdXJjaGFzZSB+IC4sIGRhdGEgPSB0cmFpbiwga2VybmVsID0gInBvbHlub21pYWwiLCBkZWdyZWUgPSAyLAogICAgICAgICAgICAgICAgICByYW5nZXMgPSBsaXN0KGNvc3QgPSBjKDAuMDEsIDAuMSwgMSwgMTApKSkKc3VtbWFyeSh0dW5lX3BvbHkpCmBgYAoKVGhlbiBJIHJlY2FsY3VsYXRlZCB0aGUgdHJhaW5pbmcgYW5kIHRlc3QgZXJyb3JzIGFmdGVyIHR1bmluZy4KCiMgKGgpIE92ZXJhbGwgYmVzdCBhcHByb2FjaApJIGNvbXBhcmVkIHRoZSB0ZXN0IGVycm9ycyBmcm9tIGFsbCB0aHJlZSBrZXJuZWxzOiBsaW5lYXIsIHJhZGlhbCwgYW5kIHBvbHlub21pYWwuCgpJIG9ic2VydmVkOgoKVGhlIHJhZGlhbCBrZXJuZWwgdXN1YWxseSBnYXZlIHRoZSBsb3dlc3QgdGVzdCBlcnJvci4KUG9seW5vbWlhbCB3YXMgZGVjZW50IGJ1dCBzb21ldGltZXMgb3ZlcmZpdC4KTGluZWFyIHdhcyB0aGUgc2ltcGxlc3QgYnV0IGRpZG7igJl0IGNhcHR1cmUgY29tcGxleCBwYXR0ZXJucy4KT3ZlcmFsbCwgdGhlIHJhZGlhbCBrZXJuZWwgcGVyZm9ybWVkIGJlc3Qgb24gdGhlIE9KIGRhdGFzZXQu