Due: Wednesday, November 6, 2019
Libraries
library(tidyverse)
library(caret)
library(ggplot2)
library(dplyr)
library(GGally)
library(corrplot)
library(rpart)
library(gplots)
library(ggpubr)
Problem 2.11
The dataset ToyotaCorolla.csv contains data on used cars on sale during the late summer of 2004 in the Netherlands. It has 1436 records containing details on 38 attributes, including Price, Age, Kilometers, HP, and other specifications.
- Explore the data using the data visualization capabilities of R. Which of the pairs among the variables seem to be correlated?
toy.df <- read.csv("/Users/miketrevathan/OneDrive/Documents/MIT/Data Mining/Boot Camp/R Data Camp/Dataset/ToyotaCorolla.csv")
toy_cor <- subset(toy.df, select = -c(Model, Fuel_Type, Color))
ggcorr(toy_cor, hjust = 1)

toy_cor_matrix <- data.frame(cor(toy_cor))
toy.plot <- ggplot(toy.df)+geom_point(aes(toy.df$Mfg_Year, toy.df$Price))
toy.plot2 <- ggplot(toy.df)+geom_point(aes(toy.df$Mfg_Year, toy.df$Age_08_04))
toy.plot3 <- ggplot(toy.df)+geom_col(aes(toy.df$Mfg_Year, toy.df$Boardcomputer))
toy.plot4 <- ggplot(toy.df)+geom_point(aes(toy.df$Id, toy.df$Age_08_04))
ggarrange(toy.plot, toy.plot2, toy.plot3, toy.plot4, ncol = 2, nrow = 2)

The structure of the data is viewed str(toy_cor) and the three variables that were not numerical were Fuel_Type, Model, and Color. The highly correlating attributes (highlighted in dark red or dark blue) were Price & Year, Age & Year, Boardcomputer & Year, and ID & Age. These values were plotted to visualize the suggested correlation.
- We plan to analyze the data using various data mining techniques described in future chapters. Prepare the data for use as follows:
- The dataset has two categorical attributes, Fuel Type and Metallic. Describe how you would convert these to binary variables. Confirm this using R’s functions to transform categorical data into dummies.
- Prepare the dataset (as factored into dummies) for data mining techniques of supervised learning by creating partitions in R. Select all the variables and use default values for the random seed and partitioning percentages for training (50%), validation (30%), and test (20%) sets. Describe the roles that these par- titions will play in modeling.
set.seed(1)
library(dummies)
toy.df$Model <- as.character(toy.df$Model)
toy.df.dum <- dummy.data.frame(toy.df, sep = ".", dummy.class = "factor")
toy.df.dum <- toy.df.dum[, -c(10,13)] # drop one of the dummy variables from Color and Fuel_Type.
head(t(t(names(toy.df.dum))),22)
[,1]
[1,] "Id"
[2,] "Model"
[3,] "Price"
[4,] "Age_08_04"
[5,] "Mfg_Month"
[6,] "Mfg_Year"
[7,] "KM"
[8,] "Fuel_Type.CNG"
[9,] "Fuel_Type.Diesel"
[10,] "HP"
[11,] "Met_Color"
[12,] "Color.Black"
[13,] "Color.Blue"
[14,] "Color.Green"
[15,] "Color.Grey"
[16,] "Color.Red"
[17,] "Color.Silver"
[18,] "Color.Violet"
[19,] "Color.White"
[20,] "Color.Yellow"
[21,] "Automatic"
[22,] "CC"
The Factor variables Fuel_Type and Color were removed from the database as a matrix and recombined back into a dataframe, as per the textbook guidance. Another way to do this is to remove Model from the database and apply the dummy.data.frame and removing the extra variable. If dummy.data.frame is used on the raw data, it will also convert Model into multiple columns.
set.seed(0)
## partitioning into training (50%), validation (30%), test (20%)
# randomly sample 50% of the row IDs for training
train.rows <- sample(rownames(toy.df.dum), dim(toy.df)[1]*0.5)
# sample 30% of the row IDs into the validation set, drawing only from records
# not already in the training set
# use setdiff() to find records not already in the training set
valid.rows <- sample(setdiff(rownames(toy.df.dum), train.rows),
dim(toy.df)[1]*0.3)
# assign the remaining 20% row IDs serve as test
test.rows <- setdiff(rownames(toy.df.dum), union(train.rows, valid.rows))
# create the 3 data frames by collecting all columns from the appropriate rows
train.data <- toy.df[train.rows, ]
valid.data <- toy.df[valid.rows, ]
test.data <- toy.df[test.rows, ]
The dataset was prepared by splitting the data between 50% for train, 30% for validation, and 20% for test. This method was used to ensure that the same values were not randomly selected in multiple data sets. Additionally, the validation section is used to tune the model to ensure robust model before predicting against the test data.
Problem 3.3
Laptop Sales at a London Computer Chain: Bar Charts and Boxplots. The file LaptopSalesJanuary2008.csv contains data for all sales of laptops at a computer chain in London in January 2008. This is a subset of the full dataset that includes data for the entire year.
- Create a bar chart, showing the average retail price by store. Which store has the highest average? Which has the lowest?
- To better compare retail prices across stores, create side-by-side boxplots of retail price by store. Now compare the prices in the two stores from (a). Does there seem to be a difference between their price distributions?
lap.df <- read.csv("/Users/miketrevathan/OneDrive/Documents/MIT/Data Mining/Boot Camp/R Data Camp/Dataset/LaptopSalesJanuary2008.csv")
store.avg <- aggregate(lap.df$Retail.Price ~ lap.df$Store.Postcode, data = lap.df, mean)
store.avg
ggplot(store.avg)+geom_col(aes(x=store.avg$`lap.df$Store.Postcode`,y=store.avg$`lap.df$Retail.Price`))+theme(axis.text.x = element_text(angle = 90)) + coord_cartesian(ylim=c(475, 500))

The lowest average is Store.Postcode is 481 dollars at W4 3PH. The highest average is 494 dollars at N1 76QA (although, the three shown in the bar chart are +/- a couple dollars in price difference.
ggplot(lap.df) + geom_boxplot(aes(lap.df$Store.Postcode, lap.df$Retail.Price)) + theme(axis.text.x = element_text(angle = 90))

Comparing N1 760A (highest) with W4 3PH (lowest) the medians are similar, however the lowest - W4 3PH has a larger range of prices and more outliers outside the 1st and 4th quartiles.
Problem 4.1
Breakfast Cereals. Use the data for the breakfast cereals example in Section 4.8 to explore and summarize the data as follows:
- Which variables are quantitative/numerical? Which are ordinal? Which are nominal?
cereal.df <- read.csv("/Users/miketrevathan/OneDrive/Documents/MIT/Data Mining/Boot Camp/R Data Camp/Dataset/Cereals.csv")
str(cereal.df)
'data.frame': 77 obs. of 16 variables:
$ name : Factor w/ 77 levels "100%_Bran","100%_Natural_Bran",..: 1 2 3 4 5 6 7 8 9 10 ...
$ mfr : Factor w/ 7 levels "A","G","K","N",..: 4 6 3 3 7 2 3 2 7 5 ...
$ type : Factor w/ 2 levels "C","H": 1 1 1 1 1 1 1 1 1 1 ...
$ calories: int 70 120 70 50 110 110 110 130 90 90 ...
$ protein : int 4 3 4 4 2 2 2 3 2 3 ...
$ fat : int 1 5 1 0 2 2 0 2 1 0 ...
$ sodium : int 130 15 260 140 200 180 125 210 200 210 ...
$ fiber : num 10 2 9 14 1 1.5 1 2 4 5 ...
$ carbo : num 5 8 7 8 14 10.5 11 18 15 13 ...
$ sugars : int 6 8 5 0 8 10 14 8 6 5 ...
$ potass : int 280 135 320 330 NA 70 30 100 125 190 ...
$ vitamins: int 25 0 25 25 25 25 25 25 25 25 ...
$ shelf : int 3 3 3 3 3 1 2 3 1 3 ...
$ weight : num 1 1 1 1 1 1 1 1.33 1 1 ...
$ cups : num 0.33 1 0.33 0.5 0.75 0.75 1 0.75 0.67 0.67 ...
$ rating : num 68.4 34 59.4 93.7 34.4 ...
Nominal(character/type): Name, mfr, type; Ordinal (ordered): Rating, Shelf Height; Quantitative/Numerical: All the rest of the variables
- Compute the mean, median, min, max, and standard deviation for each of the quantitative variables. This can be done through R’s sapply() function (e.g., sap- ply(data, mean, na.rm = TRUE)).
cereal.df.nofac <- subset(cereal.df, select = -c(name, mfr, type))
data.frame(mean=sapply(cereal.df.nofac, mean, na.rm = TRUE),
sd=sapply(cereal.df.nofac, sd, na.rm = TRUE),
min=sapply(cereal.df.nofac, min, na.rm = TRUE),
max=sapply(cereal.df.nofac, max, na.rm = TRUE),
median=sapply(cereal.df.nofac, median, na.rm = TRUE))
- Use R to plot a histogram for each of the quantitative variables. Based on the histograms and summary statistics, answer the following questions:
- Which variables have the largest variability?
- Which variables seem skewed?
- Are there any values that seem extreme?
ggplot(gather(cereal.df.nofac), aes(value)) +
geom_histogram(bins = 10) +
facet_wrap(~key, scales = 'free_x')

ggpairs(cereal.df.nofac)

i. The variabiles with the highest variability are sugars, sodium, carbs, and shelf height ii. The variables that seem skewed are fiber, fat, and patass iii. The values that seem extreme are vitamin value at 100, rating value at 100, potassium at 300, and fiber at 15.
- Use R to plot a side-by-side boxplot comparing the calories in hot vs. cold cereals. What does this plot show us?
ggplot(cereal.df) +
geom_boxplot(aes(cereal.df$type, cereal.df$calories))

NA
This shows us that there are only a few observations for Hot Cereal vs Cold Cereal and that Cold cereal has a much more predictable (i.e. less variable) amount of calories.
- Use R to plot a side-by-side boxplot of consumer rating as a function of the shelf height. If we were to predict consumer rating from shelf height, does it appear that we need to keep all three categories of shelf height?
cereal.df$shelf <- as.factor(cereal.df$shelf)
ggplot(cereal.df) +
geom_boxplot(aes(cereal.df$shelf, cereal.df$rating))

Yes, it does appear that there is a difference between teh shelf heights in terms of consumer ratings. However, it might be okay to reduce the variables to shelf 2 or not shelf 2.
- Compute the correlation table for the quantitative variable(functioncor()).Inaddi- tion, generate a matrix plot for these variables (function plot(data)).
- Which pair of variables is most strongly correlated?
- How can we reduce the number of variables based on these correlations?
- How would the correlations change if we normalized the data first?
cereal.df$shelf <- as.integer(cereal.df$shelf)
cereal_cor <- subset(cereal.df, select = -c(name, mfr, type))
ggcorr(cereal_cor, hjust = 1)

cor <- as.data.frame(cor(cereal_cor))
cor
pm <- ggpairs(cereal_cor)
pm

i. The highest correlated variables are fiber & potassium, rating & sugars, and ratings & calories ii. The values that are highly correlating in the dataset can be removed (one at a time) to see the resulting impact to the model. Only one of the highly correlating variables needs to be included, but it will take some trial/error to understand which variable is the best one to keep. iii. The correlations will change with the normalization of the data becuase the variance of the individual dependent variables will be normalized. Depending on the standard deviation of the variable, the deviation with respect to the mean or medium will adjust the values relative change, and this will alter the respective correlation between the variables.
- Consider the first PC of the analysis of the 13 numerical variables in Table 4.11. Describe briefly what this PC represents.
The purpose of PCA (pricipal component analysis) is to determine the combination of dependent variables that contains and describes most of the data. The idea is to reduce the number of dependent variables to (1) make the model simpler, and (2) prevent overfitting by reducing the multi-collinearity in the model.
LS0tCnRpdGxlOiAiMTUuMDYyIEhvbWV3b3JrIDEiCmF1dGhvcjogIk1pY2hhZWwgVHJldmF0aGFuIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCiMjIyMjIyBEdWU6IFdlZG5lc2RheSwgTm92ZW1iZXIgNiwgMjAxOQoKLS0tCgojIyMjIExpYnJhcmllcwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjYXJldCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShycGFydCkKbGlicmFyeShncGxvdHMpCmxpYnJhcnkoZ2dwdWJyKQpgYGAKCi0tLQoKIyMjIyBQcm9ibGVtIDIuMTEKCgpUaGUgZGF0YXNldCBUb3lvdGFDb3JvbGxhLmNzdiBjb250YWlucyBkYXRhIG9uIHVzZWQgY2FycyBvbiBzYWxlIGR1cmluZyB0aGUgbGF0ZSBzdW1tZXIgb2YgMjAwNCBpbiB0aGUgTmV0aGVybGFuZHMuIEl0IGhhcyAxNDM2IHJlY29yZHMgY29udGFpbmluZyBkZXRhaWxzIG9uIDM4IGF0dHJpYnV0ZXMsIGluY2x1ZGluZyBQcmljZSwgQWdlLCBLaWxvbWV0ZXJzLCBIUCwgYW5kIG90aGVyIHNwZWNpZmljYXRpb25zLgoKMS4gRXhwbG9yZSB0aGUgZGF0YSB1c2luZyB0aGUgZGF0YSB2aXN1YWxpemF0aW9uIGNhcGFiaWxpdGllcyBvZiBSLiBXaGljaCBvZiB0aGUgcGFpcnMgYW1vbmcgdGhlIHZhcmlhYmxlcyBzZWVtIHRvIGJlIGNvcnJlbGF0ZWQ/CgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp0b3kuZGYgPC0gcmVhZC5jc3YoIi9Vc2Vycy9taWtldHJldmF0aGFuL09uZURyaXZlL0RvY3VtZW50cy9NSVQvRGF0YSBNaW5pbmcvQm9vdCBDYW1wL1IgRGF0YSBDYW1wL0RhdGFzZXQvVG95b3RhQ29yb2xsYS5jc3YiKQp0b3lfY29yIDwtIHN1YnNldCh0b3kuZGYsIHNlbGVjdCA9IC1jKE1vZGVsLCBGdWVsX1R5cGUsIENvbG9yKSkKZ2djb3JyKHRveV9jb3IsIGhqdXN0ID0gMSkKdG95X2Nvcl9tYXRyaXggPC0gZGF0YS5mcmFtZShjb3IodG95X2NvcikpCgp0b3kucGxvdCA8LSBnZ3Bsb3QodG95LmRmKStnZW9tX3BvaW50KGFlcyh0b3kuZGYkTWZnX1llYXIsIHRveS5kZiRQcmljZSkpCnRveS5wbG90MiA8LSBnZ3Bsb3QodG95LmRmKStnZW9tX3BvaW50KGFlcyh0b3kuZGYkTWZnX1llYXIsIHRveS5kZiRBZ2VfMDhfMDQpKQp0b3kucGxvdDMgPC0gZ2dwbG90KHRveS5kZikrZ2VvbV9jb2woYWVzKHRveS5kZiRNZmdfWWVhciwgdG95LmRmJEJvYXJkY29tcHV0ZXIpKQp0b3kucGxvdDQgPC0gZ2dwbG90KHRveS5kZikrZ2VvbV9wb2ludChhZXModG95LmRmJElkLCB0b3kuZGYkQWdlXzA4XzA0KSkKZ2dhcnJhbmdlKHRveS5wbG90LCB0b3kucGxvdDIsIHRveS5wbG90MywgdG95LnBsb3Q0LCBuY29sID0gMiwgbnJvdyA9IDIpCmBgYAoKPGJyPjxwIHN0eWxlPSJjb2xvcjpibHVlIj5UaGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhIGlzIHZpZXdlZCBzdHIodG95X2NvcikgYW5kIHRoZSB0aHJlZSB2YXJpYWJsZXMgdGhhdCB3ZXJlIG5vdCBudW1lcmljYWwgd2VyZSBGdWVsX1R5cGUsIE1vZGVsLCBhbmQgQ29sb3IuIFRoZSBoaWdobHkgY29ycmVsYXRpbmcgYXR0cmlidXRlcyAoaGlnaGxpZ2h0ZWQgaW4gZGFyayByZWQgb3IgZGFyayBibHVlKSB3ZXJlIFByaWNlICYgWWVhciwgQWdlICYgWWVhciwgQm9hcmRjb21wdXRlciAmIFllYXIsIGFuZCBJRCAmIEFnZS4gVGhlc2UgdmFsdWVzIHdlcmUgcGxvdHRlZCB0byB2aXN1YWxpemUgdGhlIHN1Z2dlc3RlZCBjb3JyZWxhdGlvbi48L3A+PGJyPgoKMi4gV2UgcGxhbiB0byBhbmFseXplIHRoZSBkYXRhIHVzaW5nIHZhcmlvdXMgZGF0YSBtaW5pbmcgdGVjaG5pcXVlcyBkZXNjcmliZWQgaW4gZnV0dXJlIGNoYXB0ZXJzLiBQcmVwYXJlIHRoZSBkYXRhIGZvciB1c2UgYXMgZm9sbG93czoKICAgKyBUaGUgZGF0YXNldCBoYXMgdHdvIGNhdGVnb3JpY2FsIGF0dHJpYnV0ZXMsIEZ1ZWwgVHlwZSBhbmQgTWV0YWxsaWMuIERlc2NyaWJlIGhvdyB5b3Ugd291bGQgY29udmVydCB0aGVzZSB0byBiaW5hcnkgdmFyaWFibGVzLiBDb25maXJtIHRoaXMgdXNpbmcgUuKAmXMgZnVuY3Rpb25zIHRvIHRyYW5zZm9ybSBjYXRlZ29yaWNhbCBkYXRhIGludG8gZHVtbWllcy4KICAgKyBQcmVwYXJlIHRoZSBkYXRhc2V0IChhcyBmYWN0b3JlZCBpbnRvIGR1bW1pZXMpIGZvciBkYXRhIG1pbmluZyB0ZWNobmlxdWVzIG9mIHN1cGVydmlzZWQgbGVhcm5pbmcgYnkgY3JlYXRpbmcgcGFydGl0aW9ucyBpbiBSLiBTZWxlY3QgYWxsIHRoZSB2YXJpYWJsZXMgYW5kIHVzZSBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIHJhbmRvbSBzZWVkIGFuZCBwYXJ0aXRpb25pbmcgcGVyY2VudGFnZXMgZm9yIHRyYWluaW5nICg1MCUpLCB2YWxpZGF0aW9uICgzMCUpLCBhbmQgdGVzdCAoMjAlKSBzZXRzLiBEZXNjcmliZSB0aGUgcm9sZXMgdGhhdCB0aGVzZSBwYXItIHRpdGlvbnMgd2lsbCBwbGF5IGluIG1vZGVsaW5nLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2V0LnNlZWQoMSkKbGlicmFyeShkdW1taWVzKQp0b3kuZGYkTW9kZWwgPC0gYXMuY2hhcmFjdGVyKHRveS5kZiRNb2RlbCkKdG95LmRmLmR1bSA8LSBkdW1teS5kYXRhLmZyYW1lKHRveS5kZiwgc2VwID0gIi4iLCBkdW1teS5jbGFzcyA9ICJmYWN0b3IiKQp0b3kuZGYuZHVtIDwtIHRveS5kZi5kdW1bLCAtYygxMCwxMyldICMgZHJvcCBvbmUgb2YgdGhlIGR1bW15IHZhcmlhYmxlcyBmcm9tIENvbG9yIGFuZCBGdWVsX1R5cGUuCmhlYWQodCh0KG5hbWVzKHRveS5kZi5kdW0pKSksMjIpCmBgYAo8YnI+PHAgc3R5bGU9ImNvbG9yOmJsdWUiPlRoZSBGYWN0b3IgdmFyaWFibGVzIEZ1ZWxfVHlwZSBhbmQgQ29sb3Igd2VyZSByZW1vdmVkIGZyb20gdGhlIGRhdGFiYXNlIGFzIGEgbWF0cml4IGFuZCByZWNvbWJpbmVkIGJhY2sgaW50byBhIGRhdGFmcmFtZSwgYXMgcGVyIHRoZSB0ZXh0Ym9vayBndWlkYW5jZS4gQW5vdGhlciB3YXkgdG8gZG8gdGhpcyBpcyB0byByZW1vdmUgTW9kZWwgZnJvbSB0aGUgZGF0YWJhc2UgYW5kIGFwcGx5IHRoZSBkdW1teS5kYXRhLmZyYW1lIGFuZCByZW1vdmluZyB0aGUgZXh0cmEgdmFyaWFibGUuIElmIGR1bW15LmRhdGEuZnJhbWUgaXMgdXNlZCBvbiB0aGUgcmF3IGRhdGEsIGl0IHdpbGwgYWxzbyBjb252ZXJ0IE1vZGVsIGludG8gbXVsdGlwbGUgY29sdW1ucy48L3A+PGJyPgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnNldC5zZWVkKDApCiMjIHBhcnRpdGlvbmluZyBpbnRvIHRyYWluaW5nICg1MCUpLCB2YWxpZGF0aW9uICgzMCUpLCB0ZXN0ICgyMCUpCiMgcmFuZG9tbHkgc2FtcGxlIDUwJSBvZiB0aGUgcm93IElEcyBmb3IgdHJhaW5pbmcKdHJhaW4ucm93cyA8LSBzYW1wbGUocm93bmFtZXModG95LmRmLmR1bSksIGRpbSh0b3kuZGYpWzFdKjAuNSkKIyBzYW1wbGUgMzAlIG9mIHRoZSByb3cgSURzIGludG8gdGhlIHZhbGlkYXRpb24gc2V0LCBkcmF3aW5nIG9ubHkgZnJvbSByZWNvcmRzCiMgbm90IGFscmVhZHkgaW4gdGhlIHRyYWluaW5nIHNldAojIHVzZSBzZXRkaWZmKCkgdG8gZmluZCByZWNvcmRzIG5vdCBhbHJlYWR5IGluIHRoZSB0cmFpbmluZyBzZXQKdmFsaWQucm93cyA8LSBzYW1wbGUoc2V0ZGlmZihyb3duYW1lcyh0b3kuZGYuZHVtKSwgdHJhaW4ucm93cyksCiAgICAgICAgICAgICAgZGltKHRveS5kZilbMV0qMC4zKQojIGFzc2lnbiB0aGUgcmVtYWluaW5nIDIwJSByb3cgSURzIHNlcnZlIGFzIHRlc3QKdGVzdC5yb3dzIDwtIHNldGRpZmYocm93bmFtZXModG95LmRmLmR1bSksIHVuaW9uKHRyYWluLnJvd3MsIHZhbGlkLnJvd3MpKQojIGNyZWF0ZSB0aGUgMyBkYXRhIGZyYW1lcyBieSBjb2xsZWN0aW5nIGFsbCBjb2x1bW5zIGZyb20gdGhlIGFwcHJvcHJpYXRlIHJvd3MKdHJhaW4uZGF0YSA8LSB0b3kuZGZbdHJhaW4ucm93cywgXQp2YWxpZC5kYXRhIDwtIHRveS5kZlt2YWxpZC5yb3dzLCBdCnRlc3QuZGF0YSA8LSB0b3kuZGZbdGVzdC5yb3dzLCBdCmBgYAoKPGJyPjxwIHN0eWxlPSJjb2xvcjpibHVlIj5UaGUgZGF0YXNldCB3YXMgcHJlcGFyZWQgYnkgc3BsaXR0aW5nIHRoZSBkYXRhIGJldHdlZW4gNTAlIGZvciB0cmFpbiwgMzAlIGZvciB2YWxpZGF0aW9uLCBhbmQgMjAlIGZvciB0ZXN0LiBUaGlzIG1ldGhvZCB3YXMgdXNlZCB0byBlbnN1cmUgdGhhdCB0aGUgc2FtZSB2YWx1ZXMgd2VyZSBub3QgcmFuZG9tbHkgc2VsZWN0ZWQgaW4gbXVsdGlwbGUgZGF0YSBzZXRzLiBBZGRpdGlvbmFsbHksIHRoZSB2YWxpZGF0aW9uIHNlY3Rpb24gaXMgdXNlZCB0byB0dW5lIHRoZSBtb2RlbCB0byBlbnN1cmUgcm9idXN0IG1vZGVsIGJlZm9yZSBwcmVkaWN0aW5nIGFnYWluc3QgdGhlIHRlc3QgZGF0YS4gPC9wPgoKLS0tCgojIyMjIFByb2JsZW0gMy4zCgpMYXB0b3AgU2FsZXMgYXQgYSBMb25kb24gQ29tcHV0ZXIgQ2hhaW46IEJhciBDaGFydHMgYW5kIEJveHBsb3RzLiBUaGUgZmlsZSBMYXB0b3BTYWxlc0phbnVhcnkyMDA4LmNzdiBjb250YWlucyBkYXRhIGZvciBhbGwgc2FsZXMgb2YgbGFwdG9wcyBhdCBhIGNvbXB1dGVyIGNoYWluIGluIExvbmRvbiBpbiBKYW51YXJ5IDIwMDguIFRoaXMgaXMgYSBzdWJzZXQgb2YgdGhlIGZ1bGwgZGF0YXNldCB0aGF0IGluY2x1ZGVzIGRhdGEgZm9yIHRoZSBlbnRpcmUgeWVhci4KCmEuICBDcmVhdGUgYSBiYXIgY2hhcnQsIHNob3dpbmcgdGhlIGF2ZXJhZ2UgcmV0YWlsIHByaWNlIGJ5IHN0b3JlLiBXaGljaCBzdG9yZSBoYXMgdGhlIGhpZ2hlc3QgYXZlcmFnZT8gV2hpY2ggaGFzIHRoZSBsb3dlc3Q/CmIuICBUbyBiZXR0ZXIgY29tcGFyZSByZXRhaWwgcHJpY2VzIGFjcm9zcyBzdG9yZXMsIGNyZWF0ZSBzaWRlLWJ5LXNpZGUgYm94cGxvdHMgb2YgcmV0YWlsIHByaWNlIGJ5IHN0b3JlLiBOb3cgY29tcGFyZSB0aGUgcHJpY2VzIGluIHRoZSB0d28gc3RvcmVzIGZyb20gKGEpLiBEb2VzIHRoZXJlIHNlZW0gdG8gYmUgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlaXIgcHJpY2UgZGlzdHJpYnV0aW9ucz8KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxhcC5kZiA8LSByZWFkLmNzdigiL1VzZXJzL21pa2V0cmV2YXRoYW4vT25lRHJpdmUvRG9jdW1lbnRzL01JVC9EYXRhIE1pbmluZy9Cb290IENhbXAvUiBEYXRhIENhbXAvRGF0YXNldC9MYXB0b3BTYWxlc0phbnVhcnkyMDA4LmNzdiIpCnN0b3JlLmF2ZyA8LSBhZ2dyZWdhdGUobGFwLmRmJFJldGFpbC5QcmljZSB+IGxhcC5kZiRTdG9yZS5Qb3N0Y29kZSwgZGF0YSA9IGxhcC5kZiwgbWVhbikKc3RvcmUuYXZnCmdncGxvdChzdG9yZS5hdmcpK2dlb21fY29sKGFlcyh4PXN0b3JlLmF2ZyRgbGFwLmRmJFN0b3JlLlBvc3Rjb2RlYCx5PXN0b3JlLmF2ZyRgbGFwLmRmJFJldGFpbC5QcmljZWApKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDQ3NSwgNTAwKSkKYGBgCjxicj48cCBzdHlsZT0iY29sb3I6Ymx1ZSI+VGhlIGxvd2VzdCBhdmVyYWdlIGlzIFN0b3JlLlBvc3Rjb2RlIGlzIDQ4MSBkb2xsYXJzIGF0IFc0IDNQSC4gVGhlIGhpZ2hlc3QgYXZlcmFnZSBpcyA0OTQgZG9sbGFycyBhdCBOMSA3NlFBIChhbHRob3VnaCwgdGhlIHRocmVlIHNob3duIGluIHRoZSBiYXIgY2hhcnQgYXJlICsvLSBhIGNvdXBsZSBkb2xsYXJzIGluIHByaWNlIGRpZmZlcmVuY2UuPC9wPjxicj4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChsYXAuZGYpICsgZ2VvbV9ib3hwbG90KGFlcyhsYXAuZGYkU3RvcmUuUG9zdGNvZGUsIGxhcC5kZiRSZXRhaWwuUHJpY2UpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQoKYGBgCgo8YnI+PHAgc3R5bGU9ImNvbG9yOmJsdWUiPkNvbXBhcmluZyBOMSA3NjBBIChoaWdoZXN0KSB3aXRoIFc0IDNQSCAobG93ZXN0KSB0aGUgbWVkaWFucyBhcmUgc2ltaWxhciwgaG93ZXZlciB0aGUgbG93ZXN0IC0gVzQgM1BIIGhhcyBhIGxhcmdlciByYW5nZSBvZiBwcmljZXMgYW5kIG1vcmUgb3V0bGllcnMgb3V0c2lkZSB0aGUgMXN0IGFuZCA0dGggcXVhcnRpbGVzLjwvUD48YnI+CgotLS0KCiMjIyMgUHJvYmxlbSA0LjEKCkJyZWFrZmFzdCBDZXJlYWxzLiBVc2UgdGhlIGRhdGEgZm9yIHRoZSBicmVha2Zhc3QgY2VyZWFscyBleGFtcGxlIGluIFNlY3Rpb24gNC44IHRvIGV4cGxvcmUgYW5kIHN1bW1hcml6ZSB0aGUgZGF0YSBhcyBmb2xsb3dzOgoKYS4gIFdoaWNoIHZhcmlhYmxlcyBhcmUgcXVhbnRpdGF0aXZlL251bWVyaWNhbD8gV2hpY2ggYXJlIG9yZGluYWw/IFdoaWNoIGFyZSBub21pbmFsPwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpjZXJlYWwuZGYgPC0gcmVhZC5jc3YoIi9Vc2Vycy9taWtldHJldmF0aGFuL09uZURyaXZlL0RvY3VtZW50cy9NSVQvRGF0YSBNaW5pbmcvQm9vdCBDYW1wL1IgRGF0YSBDYW1wL0RhdGFzZXQvQ2VyZWFscy5jc3YiKQpzdHIoY2VyZWFsLmRmKQpgYGAKPGJyPjxwIHN0eWxlPSJjb2xvcjpibHVlIj4KTm9taW5hbChjaGFyYWN0ZXIvdHlwZSk6IE5hbWUsIG1mciwgdHlwZTsgCk9yZGluYWwgKG9yZGVyZWQpOiBSYXRpbmcsIFNoZWxmIEhlaWdodDsgClF1YW50aXRhdGl2ZS9OdW1lcmljYWw6IEFsbCB0aGUgcmVzdCBvZiB0aGUgdmFyaWFibGVzPC9wPjxicj4KCmIuICBDb21wdXRlIHRoZSBtZWFuLCBtZWRpYW4sIG1pbiwgbWF4LCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBlYWNoIG9mIHRoZSBxdWFudGl0YXRpdmUgdmFyaWFibGVzLiBUaGlzIGNhbiBiZSBkb25lIHRocm91Z2ggUuKAmXMgc2FwcGx5KCkgZnVuY3Rpb24gKGUuZy4sIHNhcC0gcGx5KGRhdGEsIG1lYW4sIG5hLnJtID0gVFJVRSkpLgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpjZXJlYWwuZGYubm9mYWMgPC0gc3Vic2V0KGNlcmVhbC5kZiwgc2VsZWN0ID0gLWMobmFtZSwgbWZyLCB0eXBlKSkKZGF0YS5mcmFtZShtZWFuPXNhcHBseShjZXJlYWwuZGYubm9mYWMsIG1lYW4sIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgIHNkPXNhcHBseShjZXJlYWwuZGYubm9mYWMsIHNkLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgIG1pbj1zYXBwbHkoY2VyZWFsLmRmLm5vZmFjLCBtaW4sIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgIG1heD1zYXBwbHkoY2VyZWFsLmRmLm5vZmFjLCBtYXgsIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgIG1lZGlhbj1zYXBwbHkoY2VyZWFsLmRmLm5vZmFjLCBtZWRpYW4sIG5hLnJtID0gVFJVRSkpCmBgYAo8YnI+PGZvbnQgY29sb3I9ImJsdWUiPjwvZm9udD48YnI+CgpjLiAgVXNlIFIgdG8gcGxvdCBhIGhpc3RvZ3JhbSBmb3IgZWFjaCBvZiB0aGUgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcy4gQmFzZWQgb24gdGhlIGhpc3RvZ3JhbXMgYW5kIHN1bW1hcnkgc3RhdGlzdGljcywgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgogICAgaS4gV2hpY2ggdmFyaWFibGVzIGhhdmUgdGhlIGxhcmdlc3QgdmFyaWFiaWxpdHk/CiAgICBpaS4gV2hpY2ggdmFyaWFibGVzIHNlZW0gc2tld2VkPwogICAgaWlpLiBBcmUgdGhlcmUgYW55IHZhbHVlcyB0aGF0IHNlZW0gZXh0cmVtZT8KICAgIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZ2F0aGVyKGNlcmVhbC5kZi5ub2ZhYyksIGFlcyh2YWx1ZSkpICsgCiAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTApICsgCiAgICBmYWNldF93cmFwKH5rZXksIHNjYWxlcyA9ICdmcmVlX3gnKQoKZ2dwYWlycyhjZXJlYWwuZGYubm9mYWMpCgpgYGAKCjxicj48Zm9udCBjb2xvcj0iYmx1ZSI+CiAgIGkuIFRoZSB2YXJpYWJpbGVzIHdpdGggdGhlIGhpZ2hlc3QgdmFyaWFiaWxpdHkgYXJlIHN1Z2Fycywgc29kaXVtLCBjYXJicywgYW5kIHNoZWxmIGhlaWdodAogICBpaS4gVGhlIHZhcmlhYmxlcyB0aGF0IHNlZW0gc2tld2VkIGFyZSBmaWJlciwgZmF0LCBhbmQgcGF0YXNzCiAgIGlpaS4gVGhlIHZhbHVlcyB0aGF0IHNlZW0gZXh0cmVtZSBhcmUgdml0YW1pbiB2YWx1ZSBhdCAxMDAsIHJhdGluZyB2YWx1ZSBhdCAxMDAsIHBvdGFzc2l1bSBhdCAzMDAsIGFuZCBmaWJlciBhdCAxNS4KPC9mb250Pjxicj4KCmQuICBVc2UgUiB0byBwbG90IGEgc2lkZS1ieS1zaWRlIGJveHBsb3QgY29tcGFyaW5nIHRoZSBjYWxvcmllcyBpbiBob3QgdnMuIGNvbGQgY2VyZWFscy4KV2hhdCBkb2VzIHRoaXMgcGxvdCBzaG93IHVzPwpgYGB7cn0KZ2dwbG90KGNlcmVhbC5kZikgKyAKICAgIGdlb21fYm94cGxvdChhZXMoY2VyZWFsLmRmJHR5cGUsIGNlcmVhbC5kZiRjYWxvcmllcykpCiAgICAKYGBgCjxicj48Zm9udCBjb2xvcj0iYmx1ZSI+ClRoaXMgc2hvd3MgdXMgdGhhdCB0aGVyZSBhcmUgb25seSBhIGZldyBvYnNlcnZhdGlvbnMgZm9yIEhvdCBDZXJlYWwgdnMgQ29sZCBDZXJlYWwgYW5kIHRoYXQgQ29sZCBjZXJlYWwgaGFzIGEgbXVjaCBtb3JlIHByZWRpY3RhYmxlIChpLmUuIGxlc3MgdmFyaWFibGUpIGFtb3VudCBvZiBjYWxvcmllcy4gCjwvZm9udD48YnI+CgplLiBVc2UgUiB0byBwbG90IGEgc2lkZS1ieS1zaWRlIGJveHBsb3Qgb2YgY29uc3VtZXIgcmF0aW5nIGFzIGEgZnVuY3Rpb24gb2YgdGhlIHNoZWxmIGhlaWdodC4gSWYgd2Ugd2VyZSB0byBwcmVkaWN0IGNvbnN1bWVyIHJhdGluZyBmcm9tIHNoZWxmIGhlaWdodCwgZG9lcyBpdCBhcHBlYXIgdGhhdCB3ZSBuZWVkIHRvIGtlZXAgYWxsIHRocmVlIGNhdGVnb3JpZXMgb2Ygc2hlbGYgaGVpZ2h0PwpgYGB7cn0KY2VyZWFsLmRmJHNoZWxmIDwtIGFzLmZhY3RvcihjZXJlYWwuZGYkc2hlbGYpCmdncGxvdChjZXJlYWwuZGYpICsgCiAgICBnZW9tX2JveHBsb3QoYWVzKGNlcmVhbC5kZiRzaGVsZiwgY2VyZWFsLmRmJHJhdGluZykpCmBgYAoKPGJyPjxmb250IGNvbG9yPSJibHVlIj4KWWVzLCBpdCBkb2VzIGFwcGVhciB0aGF0IHRoZXJlIGlzIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRlaCBzaGVsZiBoZWlnaHRzIGluIHRlcm1zIG9mIGNvbnN1bWVyIHJhdGluZ3MuIEhvd2V2ZXIsIGl0IG1pZ2h0IGJlIG9rYXkgdG8gcmVkdWNlIHRoZSB2YXJpYWJsZXMgdG8gc2hlbGYgMiBvciBub3Qgc2hlbGYgMi4gIAo8L2ZvbnQ+PGJyPgoKZi4gQ29tcHV0ZSB0aGUgY29ycmVsYXRpb24gdGFibGUgZm9yIHRoZSBxdWFudGl0YXRpdmUgdmFyaWFibGUoZnVuY3Rpb25jb3IoKSkuSW5hZGRpLSB0aW9uLCBnZW5lcmF0ZSBhIG1hdHJpeCBwbG90IGZvciB0aGVzZSB2YXJpYWJsZXMgKGZ1bmN0aW9uIHBsb3QoZGF0YSkpLgogICAgaS4gV2hpY2ggcGFpciBvZiB2YXJpYWJsZXMgaXMgbW9zdCBzdHJvbmdseSBjb3JyZWxhdGVkPwogICAgaWkuIEhvdyBjYW4gd2UgcmVkdWNlIHRoZSBudW1iZXIgb2YgdmFyaWFibGVzIGJhc2VkIG9uIHRoZXNlIGNvcnJlbGF0aW9ucz8KICAgIGlpaS4gSG93IHdvdWxkIHRoZSBjb3JyZWxhdGlvbnMgY2hhbmdlIGlmIHdlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgZmlyc3Q/CiAgICAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2VyZWFsLmRmJHNoZWxmIDwtIGFzLmludGVnZXIoY2VyZWFsLmRmJHNoZWxmKQpjZXJlYWxfY29yIDwtIHN1YnNldChjZXJlYWwuZGYsIHNlbGVjdCA9IC1jKG5hbWUsIG1mciwgdHlwZSkpCmdnY29ycihjZXJlYWxfY29yLCBoanVzdCA9IDEpCmNvciA8LSBhcy5kYXRhLmZyYW1lKGNvcihjZXJlYWxfY29yKSkKY29yCnBtIDwtIGdncGFpcnMoY2VyZWFsX2NvcikKcG0KCmBgYAoKPGJyPjxmb250IGNvbG9yPSJibHVlIj4KICAgaS4gVGhlIGhpZ2hlc3QgY29ycmVsYXRlZCB2YXJpYWJsZXMgYXJlIGZpYmVyICYgcG90YXNzaXVtLCByYXRpbmcgJiBzdWdhcnMsIGFuZCByYXRpbmdzICYgY2Fsb3JpZXMKICAgaWkuIFRoZSB2YWx1ZXMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlbGF0aW5nIGluIHRoZSBkYXRhc2V0IGNhbiBiZSByZW1vdmVkIChvbmUgYXQgYSB0aW1lKSB0byBzZWUgdGhlIHJlc3VsdGluZyBpbXBhY3QgdG8gdGhlIG1vZGVsLiBPbmx5IG9uZSBvZiB0aGUgaGlnaGx5IGNvcnJlbGF0aW5nIHZhcmlhYmxlcyBuZWVkcyB0byBiZSBpbmNsdWRlZCwgYnV0IGl0IHdpbGwgdGFrZSBzb21lIHRyaWFsL2Vycm9yIHRvIHVuZGVyc3RhbmQgd2hpY2ggdmFyaWFibGUgaXMgdGhlIGJlc3Qgb25lIHRvIGtlZXAuCiAgIGlpaS4gVGhlIGNvcnJlbGF0aW9ucyB3aWxsIGNoYW5nZSB3aXRoIHRoZSBub3JtYWxpemF0aW9uIG9mIHRoZSBkYXRhIGJlY3Vhc2UgdGhlIHZhcmlhbmNlIG9mIHRoZSBpbmRpdmlkdWFsIGRlcGVuZGVudCB2YXJpYWJsZXMgd2lsbCBiZSBub3JtYWxpemVkLiBEZXBlbmRpbmcgb24gdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgdmFyaWFibGUsIHRoZSBkZXZpYXRpb24gd2l0aCByZXNwZWN0IHRvIHRoZSBtZWFuIG9yIG1lZGl1bSB3aWxsIGFkanVzdCB0aGUgdmFsdWVzIHJlbGF0aXZlIGNoYW5nZSwgYW5kIHRoaXMgd2lsbCBhbHRlciB0aGUgcmVzcGVjdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuIAo8L2ZvbnQ+PGJyPgoKZy4gQ29uc2lkZXIgdGhlIGZpcnN0IFBDIG9mIHRoZSBhbmFseXNpcyBvZiB0aGUgMTMgbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiBUYWJsZSA0LjExLgpEZXNjcmliZSBicmllZmx5IHdoYXQgdGhpcyBQQyByZXByZXNlbnRzLgoKPGJyPjxmb250IGNvbG9yPSJibHVlIj4KVGhlIHB1cnBvc2Ugb2YgUENBIChwcmljaXBhbCBjb21wb25lbnQgYW5hbHlzaXMpIGlzIHRvIGRldGVybWluZSB0aGUgY29tYmluYXRpb24gb2YgZGVwZW5kZW50IHZhcmlhYmxlcyB0aGF0IGNvbnRhaW5zIGFuZCBkZXNjcmliZXMgbW9zdCBvZiB0aGUgZGF0YS4gVGhlIGlkZWEgaXMgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgZGVwZW5kZW50IHZhcmlhYmxlcyB0byAoMSkgbWFrZSB0aGUgbW9kZWwgc2ltcGxlciwgYW5kICgyKSBwcmV2ZW50IG92ZXJmaXR0aW5nIGJ5IHJlZHVjaW5nIHRoZSBtdWx0aS1jb2xsaW5lYXJpdHkgaW4gdGhlIG1vZGVsLiAKPC9mb250Pjxicj4K