library(tidyverse)
library(openintro)
## Warning: package 'openintro' was built under R version 4.3.3
## Warning: package 'usdata' was built under R version 4.3.3
library(dplyr)

The file UniversalBank.rds contains data on 5000 customers. The data include customer demographic information (age, income, etc.), the customer’s relationship with the bank (mortgage, securities account, etc.), and the customer response to the last personal loan campaign (Personal Loan). Among these 5000 customers, only 480 (= 9.6%) accepted the personal loan that was offered to them in the earlier campaign.

Data Description:

Variable Description
ID Customer ID
Age Customer’s age in completed years
Experience # years of professional experience
Income Annual income of the customer ($000)
ZIPCode Home Address ZIP code
Family Family size of the customer
CCAvg Avg. spending on credit cards per month ($000)
Education_1 Education Level = 1 if Undergrad; 0 otherwise
Education_2 Education Level = 1 if Graduate; 0 otherwise
Education_3 Education Level = 1 if Advanced/Professional; 0 otherwise
Mortgage Value of house mortgage if any. ($000)
PersonalLoan Did this customer accept the personal loan offered in the last campaign?
SecuritiesAccount Does the customer have a securities account with the bank?
CDAccount Does the customer have a certificate of deposit (CD) account with the bank?
Online Does the customer use internet banking facilities?
CreditCard Does the customer use a credit card issued by UniversalBank?

Question 1

Read and preprocess the data:

  1. Read the data file and assign into an R object.
  2. Drop ID and ZIPcode from the dataset.
  3. Convert binary categorical variables into factor variables.
  4. Handle missing values, if there is any.
  5. Normalize all numerical variables.

Answer to Question 1

# Inserting the code here

bank_data <- readRDS("~/Documents/UNH/Semester-3/SupervisedMachineLearning/test/UniversalBank.rds")

# Dropping 'ID' and 'ZIPCode'
bank_data <- bank_data %>% select(-ID, -ZIPCode)

# Converting binary categorical variables to factors
binary_vars <- c("PersonalLoan", "SecuritiesAccount", "CDAccount", "Online", "CreditCard")

bank_data[binary_vars] <- lapply(bank_data[binary_vars], factor)

# Checking for missing values
sum(is.na(bank_data))
## [1] 0
# Removing rows with missing values if any exist
bank_data <- na.omit(bank_data)

# Identifying numerical variables
numerical_vars <- c("Age", "Experience", "Income", "Family", "CCAvg", "Mortgage")

# Normalizing the numerical variables to scale between 0 and 1
bank_data[numerical_vars] <- lapply(bank_data[numerical_vars], function(x) (x - min(x)) / (max(x) - min(x)))

Question 2

Partition the data into training (60%) and testing (40%) sets. Use top 60% as training sample and remaining as test data.

Answer to Question 2

# Insert the code here

# Setingthe seed for reproducibility
set.seed(123)

# Defining the split index (60% training data)
train_indices <- sample(1:nrow(bank_data), size = 0.6 * nrow(bank_data))

# Splitting the data
train_data <- bank_data[train_indices, ]  # 60% training data
test_data <- bank_data[-train_indices, ]   # 40% testing data

# Checking the size of train and test data
nrow(train_data)  # Should be 60% of the original data
## [1] 3000
nrow(test_data)   # Should be 40% of the original data
## [1] 2000

Question 3

Perform a k-NN classification with all predictors except ID and ZIP code using:
a. k = 1.
b. k = 2.
c. k = 3.
d. k = 4.

For each k=1,2,3,4, compute accuracy based on test dataset. Whick k is the best?

Answer to Question 3

# Insert the code here
# Loading the  necessary package
library(class)

# Define the target variable (PersonalLoan) for both training and test datasets
train_labels <- train_data$PersonalLoan
test_labels <- test_data$PersonalLoan

# Exclude the target variable from training and test datasets (use only predictors)
train_predictors <- train_data %>% select(-PersonalLoan)
test_predictors <- test_data %>% select(-PersonalLoan)

# Convert to matrix for knn function
train_matrix <- as.matrix(train_predictors)
test_matrix <- as.matrix(test_predictors)

# Function to compute accuracy
compute_accuracy <- function(k) {
  # Perform k-NN classification
  knn_predictions <- knn(train_matrix, test_matrix, cl = train_labels, k = k)
  
  # Calculate accuracy
  accuracy <- sum(knn_predictions == test_labels) / length(test_labels)
  return(accuracy)
}

# Compute accuracy for k = 1, 2, 3, 4
accuracy_k1 <- compute_accuracy(1)
accuracy_k2 <- compute_accuracy(2)
accuracy_k3 <- compute_accuracy(3)
accuracy_k4 <- compute_accuracy(4)

# Print the accuracies
accuracy_k1  # Accuracy for k = 1
## [1] 0.962
accuracy_k2  # Accuracy for k = 2
## [1] 0.9565
accuracy_k3  # Accuracy for k = 3
## [1] 0.96
accuracy_k4  # Accuracy for k = 4
## [1] 0.955

Question 4

Consider the following customer:

Age = 40, Experience = 10, Income = 84, Family = 2, CCAvg = 2, Education_1 = 0, Education_2 = 1, Education_3 = 0, Mortgage = 0, SecuritiesAccount = 0, CDAccount = 0, Online = 1, and CreditCard = 1.

Perform a k-NN classification with all predictors except ID and ZIP code using th best k. How would this customer be classified?

Answer to Question 4

# Insert the yor code here

# Defining the new customer data
new_customer <- data.frame(
  Age = 40,
  Experience = 10,
  Income = 84,
  Family = 2,
  CCAvg = 2,
  Education_1 = 0,
  Education_2 = 1,
  Education_3 = 0,
  Mortgage = 0,
  SecuritiesAccount = 0,
  CDAccount = 0,
  Online = 1,
  CreditCard = 1
)

# Normalizing the new customer data using the same scaling as the training data
normalize <- function(x, min_val, max_val) {
  return ((x - min_val) / (max_val - min_val))
}

# Normalizing the new customer's numeric values based on the training data's range
numerical_vars <- c("Age", "Experience", "Income", "Family", "CCAvg", "Mortgage")
for (var in numerical_vars) {
  new_customer[[var]] <- normalize(new_customer[[var]], min(train_data[[var]]), max(train_data[[var]]))
}

# Converting categorical variables of the new customer to factors (to match the training data)
binary_vars <- c("SecuritiesAccount", "CDAccount", "Online", "CreditCard", "Education_1", "Education_2", "Education_3")
new_customer[binary_vars] <- lapply(new_customer[binary_vars], factor)

# Performing k-NN classification for the new customer (using the best k = 1 from previous analysis)
knn_prediction <- knn(train_matrix, as.matrix(new_customer), cl = train_labels, k = 1)

# Printing the predicted class for the new customer
knn_prediction
## [1] 1
## Levels: 0 1
LS0tCnRpdGxlOiAiRUNPTiAzMjAwOiBIb21ld29yayAxIgphdXRob3I6ICJTYXR5YSBOYXJheWFuYSBQYW5kYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG9wZW5pbnRybykKbGlicmFyeShkcGx5cikKYGBgCgpUaGUgZmlsZSBgVW5pdmVyc2FsQmFuay5yZHNgIGNvbnRhaW5zIGRhdGEgb24gNTAwMCBjdXN0b21lcnMuIFRoZSBkYXRhIGluY2x1ZGUgY3VzdG9tZXIgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gKGFnZSwgaW5jb21lLCBldGMuKSwgdGhlIGN1c3RvbWVy4oCZcyByZWxhdGlvbnNoaXAgd2l0aCB0aGUgYmFuayAobW9ydGdhZ2UsIHNlY3VyaXRpZXMgYWNjb3VudCwgZXRjLiksIGFuZCB0aGUgY3VzdG9tZXIgcmVzcG9uc2UgdG8gdGhlIGxhc3QgcGVyc29uYWwgbG9hbiBjYW1wYWlnbiAoUGVyc29uYWwgTG9hbikuIEFtb25nIHRoZXNlIDUwMDAgY3VzdG9tZXJzLCBvbmx5IDQ4MCAoPSA5LjYlKSBhY2NlcHRlZCB0aGUgcGVyc29uYWwgbG9hbiB0aGF0IHdhcyBvZmZlcmVkIHRvIHRoZW0gaW4gdGhlIGVhcmxpZXIgY2FtcGFpZ24uCgpEYXRhIERlc2NyaXB0aW9uOgoKfCBWYXJpYWJsZSAgICAgICAgICAgIHwgRGVzY3JpcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgSUQgICAgICAgICAgICAgICAgICB8IEN1c3RvbWVyIElEICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBBZ2UgICAgICAgICAgICAgICAgIHwgQ3VzdG9tZXIncyBhZ2UgaW4gY29tcGxldGVkIHllYXJzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IEV4cGVyaWVuY2UgICAgICAgICAgfCAjIHllYXJzIG9mIHByb2Zlc3Npb25hbCBleHBlcmllbmNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgSW5jb21lICAgICAgICAgICAgICB8IEFubnVhbCBpbmNvbWUgb2YgdGhlIGN1c3RvbWVyICgkMDAwKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBaSVBDb2RlICAgICAgICAgICAgIHwgSG9tZSBBZGRyZXNzIFpJUCBjb2RlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IEZhbWlseSAgICAgICAgICAgICAgfCBGYW1pbHkgc2l6ZSBvZiB0aGUgY3VzdG9tZXIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgQ0NBdmcgICAgICAgICAgICAgICB8IEF2Zy4gc3BlbmRpbmcgb24gY3JlZGl0IGNhcmRzIHBlciBtb250aCAoJDAwMCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBFZHVjYXRpb25fMSAgICAgICAgIHwgRWR1Y2F0aW9uIExldmVsID0gMSBpZiBVbmRlcmdyYWQ7IDAgb3RoZXJ3aXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IEVkdWNhdGlvbl8yICAgICAgICAgfCBFZHVjYXRpb24gTGV2ZWwgPSAxIGlmIEdyYWR1YXRlOyAwIG90aGVyd2lzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgRWR1Y2F0aW9uXzMgICAgICAgICB8IEVkdWNhdGlvbiBMZXZlbCA9IDEgaWYgQWR2YW5jZWQvUHJvZmVzc2lvbmFsOyAwIG90aGVyd2lzZSAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBNb3J0Z2FnZSAgICAgICAgICAgIHwgVmFsdWUgb2YgaG91c2UgbW9ydGdhZ2UgaWYgYW55LiAoJDAwMCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IFBlcnNvbmFsTG9hbiAgICAgICAgfCBEaWQgdGhpcyBjdXN0b21lciBhY2NlcHQgdGhlIHBlcnNvbmFsIGxvYW4gb2ZmZXJlZCBpbiB0aGUgbGFzdCBjYW1wYWlnbj8gICAgICAgICAgICB8CnwgU2VjdXJpdGllc0FjY291bnQgICB8IERvZXMgdGhlIGN1c3RvbWVyIGhhdmUgYSBzZWN1cml0aWVzIGFjY291bnQgd2l0aCB0aGUgYmFuaz8gICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBDREFjY291bnQgICAgICAgICAgIHwgRG9lcyB0aGUgY3VzdG9tZXIgaGF2ZSBhIGNlcnRpZmljYXRlIG9mIGRlcG9zaXQgKENEKSBhY2NvdW50IHdpdGggdGhlIGJhbms/ICAgICAgICAgfAp8IE9ubGluZSAgICAgICAgICAgICAgfCBEb2VzIHRoZSBjdXN0b21lciB1c2UgaW50ZXJuZXQgYmFua2luZyBmYWNpbGl0aWVzPyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgQ3JlZGl0Q2FyZCAgICAgICAgICB8IERvZXMgdGhlIGN1c3RvbWVyIHVzZSBhIGNyZWRpdCBjYXJkIGlzc3VlZCBieSBVbml2ZXJzYWxCYW5rPyAgICAgICAgICAgICAgICAgICAgICAgIHwKCiMjIyBRdWVzdGlvbiAxCgpSZWFkIGFuZCBwcmVwcm9jZXNzIHRoZSBkYXRhOiAKCmEuIFJlYWQgdGhlIGRhdGEgZmlsZSBhbmQgYXNzaWduIGludG8gYW4gYFJgIG9iamVjdC4gIApiLiBEcm9wIElEIGFuZCBaSVBjb2RlIGZyb20gdGhlIGRhdGFzZXQuICAKYy4gQ29udmVydCBiaW5hcnkgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGludG8gZmFjdG9yIHZhcmlhYmxlcy4gIApkLiBIYW5kbGUgbWlzc2luZyB2YWx1ZXMsIGlmIHRoZXJlIGlzIGFueS4gIAplLiBOb3JtYWxpemUgYWxsIG51bWVyaWNhbCB2YXJpYWJsZXMuICAKCgojIyMgX0Fuc3dlciB0byBRdWVzdGlvbiAxXwoKYGBge3IgUTF9CiMgSW5zZXJ0aW5nIHRoZSBjb2RlIGhlcmUKCmJhbmtfZGF0YSA8LSByZWFkUkRTKCJ+L0RvY3VtZW50cy9VTkgvU2VtZXN0ZXItMy9TdXBlcnZpc2VkTWFjaGluZUxlYXJuaW5nL3Rlc3QvVW5pdmVyc2FsQmFuay5yZHMiKQoKIyBEcm9wcGluZyAnSUQnIGFuZCAnWklQQ29kZScKYmFua19kYXRhIDwtIGJhbmtfZGF0YSAlPiUgc2VsZWN0KC1JRCwgLVpJUENvZGUpCgojIENvbnZlcnRpbmcgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB0byBmYWN0b3JzCmJpbmFyeV92YXJzIDwtIGMoIlBlcnNvbmFsTG9hbiIsICJTZWN1cml0aWVzQWNjb3VudCIsICJDREFjY291bnQiLCAiT25saW5lIiwgIkNyZWRpdENhcmQiKQoKYmFua19kYXRhW2JpbmFyeV92YXJzXSA8LSBsYXBwbHkoYmFua19kYXRhW2JpbmFyeV92YXJzXSwgZmFjdG9yKQoKIyBDaGVja2luZyBmb3IgbWlzc2luZyB2YWx1ZXMKc3VtKGlzLm5hKGJhbmtfZGF0YSkpCgojIFJlbW92aW5nIHJvd3Mgd2l0aCBtaXNzaW5nIHZhbHVlcyBpZiBhbnkgZXhpc3QKYmFua19kYXRhIDwtIG5hLm9taXQoYmFua19kYXRhKQoKIyBJZGVudGlmeWluZyBudW1lcmljYWwgdmFyaWFibGVzCm51bWVyaWNhbF92YXJzIDwtIGMoIkFnZSIsICJFeHBlcmllbmNlIiwgIkluY29tZSIsICJGYW1pbHkiLCAiQ0NBdmciLCAiTW9ydGdhZ2UiKQoKIyBOb3JtYWxpemluZyB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcyB0byBzY2FsZSBiZXR3ZWVuIDAgYW5kIDEKYmFua19kYXRhW251bWVyaWNhbF92YXJzXSA8LSBsYXBwbHkoYmFua19kYXRhW251bWVyaWNhbF92YXJzXSwgZnVuY3Rpb24oeCkgKHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSkpCgpgYGAKCgojIyMgUXVlc3Rpb24gMgoKUGFydGl0aW9uIHRoZSBkYXRhIGludG8gdHJhaW5pbmcgKDYwJSkgYW5kIHRlc3RpbmcgKDQwJSkgc2V0cy4gVXNlIHRvcCA2MCUgYXMgdHJhaW5pbmcgc2FtcGxlIGFuZCByZW1haW5pbmcgYXMgdGVzdCBkYXRhLgoKIyMjIF9BbnN3ZXIgdG8gUXVlc3Rpb24gMl8KCmBgYHtyIFEyfQojIEluc2VydCB0aGUgY29kZSBoZXJlCgojIFNldGluZ3RoZSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzKQoKIyBEZWZpbmluZyB0aGUgc3BsaXQgaW5kZXggKDYwJSB0cmFpbmluZyBkYXRhKQp0cmFpbl9pbmRpY2VzIDwtIHNhbXBsZSgxOm5yb3coYmFua19kYXRhKSwgc2l6ZSA9IDAuNiAqIG5yb3coYmFua19kYXRhKSkKCiMgU3BsaXR0aW5nIHRoZSBkYXRhCnRyYWluX2RhdGEgPC0gYmFua19kYXRhW3RyYWluX2luZGljZXMsIF0gICMgNjAlIHRyYWluaW5nIGRhdGEKdGVzdF9kYXRhIDwtIGJhbmtfZGF0YVstdHJhaW5faW5kaWNlcywgXSAgICMgNDAlIHRlc3RpbmcgZGF0YQoKIyBDaGVja2luZyB0aGUgc2l6ZSBvZiB0cmFpbiBhbmQgdGVzdCBkYXRhCm5yb3codHJhaW5fZGF0YSkgICMgU2hvdWxkIGJlIDYwJSBvZiB0aGUgb3JpZ2luYWwgZGF0YQpucm93KHRlc3RfZGF0YSkgICAjIFNob3VsZCBiZSA0MCUgb2YgdGhlIG9yaWdpbmFsIGRhdGEKCgpgYGAKCiMjIyBRdWVzdGlvbiAzCgpQZXJmb3JtIGEgay1OTiBjbGFzc2lmaWNhdGlvbiB3aXRoIGFsbCBwcmVkaWN0b3JzIGV4Y2VwdCBJRCBhbmQgWklQIGNvZGUgdXNpbmc6ICAKYS4gayA9IDEuICAKYi4gayA9IDIuICAKYy4gayA9IDMuICAKZC4gayA9IDQuICAgCgpGb3IgZWFjaCBrPTEsMiwzLDQsIGNvbXB1dGUgYWNjdXJhY3kgYmFzZWQgb24gdGVzdCBkYXRhc2V0LiBXaGljayBrIGlzIHRoZSBiZXN0PwoKIyMjIF9BbnN3ZXIgdG8gUXVlc3Rpb24gM18KCmBgYHtyIFEzfQojIEluc2VydCB0aGUgY29kZSBoZXJlCiMgTG9hZGluZyB0aGUgIG5lY2Vzc2FyeSBwYWNrYWdlCmxpYnJhcnkoY2xhc3MpCgojIERlZmluZSB0aGUgdGFyZ2V0IHZhcmlhYmxlIChQZXJzb25hbExvYW4pIGZvciBib3RoIHRyYWluaW5nIGFuZCB0ZXN0IGRhdGFzZXRzCnRyYWluX2xhYmVscyA8LSB0cmFpbl9kYXRhJFBlcnNvbmFsTG9hbgp0ZXN0X2xhYmVscyA8LSB0ZXN0X2RhdGEkUGVyc29uYWxMb2FuCgojIEV4Y2x1ZGUgdGhlIHRhcmdldCB2YXJpYWJsZSBmcm9tIHRyYWluaW5nIGFuZCB0ZXN0IGRhdGFzZXRzICh1c2Ugb25seSBwcmVkaWN0b3JzKQp0cmFpbl9wcmVkaWN0b3JzIDwtIHRyYWluX2RhdGEgJT4lIHNlbGVjdCgtUGVyc29uYWxMb2FuKQp0ZXN0X3ByZWRpY3RvcnMgPC0gdGVzdF9kYXRhICU+JSBzZWxlY3QoLVBlcnNvbmFsTG9hbikKCiMgQ29udmVydCB0byBtYXRyaXggZm9yIGtubiBmdW5jdGlvbgp0cmFpbl9tYXRyaXggPC0gYXMubWF0cml4KHRyYWluX3ByZWRpY3RvcnMpCnRlc3RfbWF0cml4IDwtIGFzLm1hdHJpeCh0ZXN0X3ByZWRpY3RvcnMpCgojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgYWNjdXJhY3kKY29tcHV0ZV9hY2N1cmFjeSA8LSBmdW5jdGlvbihrKSB7CiAgIyBQZXJmb3JtIGstTk4gY2xhc3NpZmljYXRpb24KICBrbm5fcHJlZGljdGlvbnMgPC0ga25uKHRyYWluX21hdHJpeCwgdGVzdF9tYXRyaXgsIGNsID0gdHJhaW5fbGFiZWxzLCBrID0gaykKICAKICAjIENhbGN1bGF0ZSBhY2N1cmFjeQogIGFjY3VyYWN5IDwtIHN1bShrbm5fcHJlZGljdGlvbnMgPT0gdGVzdF9sYWJlbHMpIC8gbGVuZ3RoKHRlc3RfbGFiZWxzKQogIHJldHVybihhY2N1cmFjeSkKfQoKIyBDb21wdXRlIGFjY3VyYWN5IGZvciBrID0gMSwgMiwgMywgNAphY2N1cmFjeV9rMSA8LSBjb21wdXRlX2FjY3VyYWN5KDEpCmFjY3VyYWN5X2syIDwtIGNvbXB1dGVfYWNjdXJhY3koMikKYWNjdXJhY3lfazMgPC0gY29tcHV0ZV9hY2N1cmFjeSgzKQphY2N1cmFjeV9rNCA8LSBjb21wdXRlX2FjY3VyYWN5KDQpCgojIFByaW50IHRoZSBhY2N1cmFjaWVzCmFjY3VyYWN5X2sxICAjIEFjY3VyYWN5IGZvciBrID0gMQphY2N1cmFjeV9rMiAgIyBBY2N1cmFjeSBmb3IgayA9IDIKYWNjdXJhY3lfazMgICMgQWNjdXJhY3kgZm9yIGsgPSAzCmFjY3VyYWN5X2s0ICAjIEFjY3VyYWN5IGZvciBrID0gNAoKCmBgYAoKIyMjIFF1ZXN0aW9uIDQKCkNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgY3VzdG9tZXI6IAoKQWdlID0gNDAsIEV4cGVyaWVuY2UgPSAxMCwgSW5jb21lID0gODQsIEZhbWlseSA9IDIsIENDQXZnID0gMiwgRWR1Y2F0aW9uXzEgPSAwLCBFZHVjYXRpb25fMiA9IDEsIEVkdWNhdGlvbl8zID0gMCwgTW9ydGdhZ2UgPSAwLCBTZWN1cml0aWVzQWNjb3VudCA9IDAsIENEQWNjb3VudCA9IDAsIE9ubGluZSA9IDEsIGFuZCBDcmVkaXRDYXJkID0gMS4KClBlcmZvcm0gYSBrLU5OIGNsYXNzaWZpY2F0aW9uIHdpdGggYWxsIHByZWRpY3RvcnMgZXhjZXB0IElEIGFuZCBaSVAgY29kZSB1c2luZyB0aCBiZXN0IGsuIEhvdyB3b3VsZCB0aGlzIGN1c3RvbWVyIGJlIGNsYXNzaWZpZWQ/CgojIyMgX0Fuc3dlciB0byBRdWVzdGlvbiA0XwoKYGBge3IgUTR9CiMgSW5zZXJ0IHRoZSB5b3IgY29kZSBoZXJlCgojIERlZmluaW5nIHRoZSBuZXcgY3VzdG9tZXIgZGF0YQpuZXdfY3VzdG9tZXIgPC0gZGF0YS5mcmFtZSgKICBBZ2UgPSA0MCwKICBFeHBlcmllbmNlID0gMTAsCiAgSW5jb21lID0gODQsCiAgRmFtaWx5ID0gMiwKICBDQ0F2ZyA9IDIsCiAgRWR1Y2F0aW9uXzEgPSAwLAogIEVkdWNhdGlvbl8yID0gMSwKICBFZHVjYXRpb25fMyA9IDAsCiAgTW9ydGdhZ2UgPSAwLAogIFNlY3VyaXRpZXNBY2NvdW50ID0gMCwKICBDREFjY291bnQgPSAwLAogIE9ubGluZSA9IDEsCiAgQ3JlZGl0Q2FyZCA9IDEKKQoKIyBOb3JtYWxpemluZyB0aGUgbmV3IGN1c3RvbWVyIGRhdGEgdXNpbmcgdGhlIHNhbWUgc2NhbGluZyBhcyB0aGUgdHJhaW5pbmcgZGF0YQpub3JtYWxpemUgPC0gZnVuY3Rpb24oeCwgbWluX3ZhbCwgbWF4X3ZhbCkgewogIHJldHVybiAoKHggLSBtaW5fdmFsKSAvIChtYXhfdmFsIC0gbWluX3ZhbCkpCn0KCiMgTm9ybWFsaXppbmcgdGhlIG5ldyBjdXN0b21lcidzIG51bWVyaWMgdmFsdWVzIGJhc2VkIG9uIHRoZSB0cmFpbmluZyBkYXRhJ3MgcmFuZ2UKbnVtZXJpY2FsX3ZhcnMgPC0gYygiQWdlIiwgIkV4cGVyaWVuY2UiLCAiSW5jb21lIiwgIkZhbWlseSIsICJDQ0F2ZyIsICJNb3J0Z2FnZSIpCmZvciAodmFyIGluIG51bWVyaWNhbF92YXJzKSB7CiAgbmV3X2N1c3RvbWVyW1t2YXJdXSA8LSBub3JtYWxpemUobmV3X2N1c3RvbWVyW1t2YXJdXSwgbWluKHRyYWluX2RhdGFbW3Zhcl1dKSwgbWF4KHRyYWluX2RhdGFbW3Zhcl1dKSkKfQoKIyBDb252ZXJ0aW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBvZiB0aGUgbmV3IGN1c3RvbWVyIHRvIGZhY3RvcnMgKHRvIG1hdGNoIHRoZSB0cmFpbmluZyBkYXRhKQpiaW5hcnlfdmFycyA8LSBjKCJTZWN1cml0aWVzQWNjb3VudCIsICJDREFjY291bnQiLCAiT25saW5lIiwgIkNyZWRpdENhcmQiLCAiRWR1Y2F0aW9uXzEiLCAiRWR1Y2F0aW9uXzIiLCAiRWR1Y2F0aW9uXzMiKQpuZXdfY3VzdG9tZXJbYmluYXJ5X3ZhcnNdIDwtIGxhcHBseShuZXdfY3VzdG9tZXJbYmluYXJ5X3ZhcnNdLCBmYWN0b3IpCgojIFBlcmZvcm1pbmcgay1OTiBjbGFzc2lmaWNhdGlvbiBmb3IgdGhlIG5ldyBjdXN0b21lciAodXNpbmcgdGhlIGJlc3QgayA9IDEgZnJvbSBwcmV2aW91cyBhbmFseXNpcykKa25uX3ByZWRpY3Rpb24gPC0ga25uKHRyYWluX21hdHJpeCwgYXMubWF0cml4KG5ld19jdXN0b21lciksIGNsID0gdHJhaW5fbGFiZWxzLCBrID0gMSkKCiMgUHJpbnRpbmcgdGhlIHByZWRpY3RlZCBjbGFzcyBmb3IgdGhlIG5ldyBjdXN0b21lcgprbm5fcHJlZGljdGlvbgoKCmBgYAoK