library("dplyr")
library("tidyr")
library("ggplot2")
library("ROCR")
library("rpart")
library("rpart.plot")
library("caret")
library("randomForest")
library("tidyverse")
library("tm")
library("SnowballC")
library("softImpute")
library("glmnet")
library("Hmisc")
library("dummies")
library('tinytex')
library('GGally')
library('ggpubr')
library('gplots')

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. a) Explore the data using the data visualization capabilities of R.Which of the pairs among the variables seem to be correlated?

rm(list=ls())
ToyotaCorolla=read.csv("/Users/kayhanbabakan/OneDrive/MIT/Data Mining/Data_export/ToyotaCorolla.csv")
drops = c("Id","Model","Fuel_Type","Color","Cylinders")
TCData = ToyotaCorolla[,!colnames(ToyotaCorolla) %in% drops]
cormatrix = suppressWarnings(cor(TCData))
TCData$Boardcomputer = as.factor(TCData$Boardcomputer)
TCData$Powered_Windows = as.factor(TCData$Powered_Windows)
TCData$Central_Lock = as.factor(TCData$Central_Lock)
TCData$Central_Lock = as.factor(TCData$Radio)
TCData$Central_Lock = as.factor(TCData$Radio_cassette)

#heatmap
heatmap(cormatrix, Rowv = NA, Colv = NA)

data.frame(cormatrix)

#price/age/mfg_year
prcageyr=ggplot(ToyotaCorolla,aes(ToyotaCorolla$Age_08_04,Price,colour=Mfg_Year))+
  geom_point()
#mfg_year/bpardcomp
mfgbcmp=ggplot(ToyotaCorolla,aes(x=TCData$Mfg_Year,fill=Boardcomputer==1))+
  geom_histogram(binwidth=1,position='fill')
#powerwindow/centrallock
powcent=ggplot(ToyotaCorolla,aes(x=TCData$Powered_Windows,y=TCData$Central_Lock))+
  geom_col()
#radio/cassette
radcas=ggplot(ToyotaCorolla,aes(x=TCData$Radio,y=TCData$Radio_cassette))+
  geom_col()
ggarrange(prcageyr,mfgbcmp,powcent,radcas,nrow=2,ncol=2)

  1. We plan to analyze the data using various data mining techniques described in future chapters. Prepare the data for use as follows:
    1. The dataset has two categorical attributes, Fuel Type and Color. Describe how you would convert these to binary variables. Confirm this using R’s functions to transform categorical data into dummies.
    2. 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 partitions will play in modeling.
ToyotaCorolla$Model = as.character(ToyotaCorolla$Model)
ToyotaCorollaDummy=dummy.data.frame(ToyotaCorolla,dummy.class="factor")
non-list contrasts argument ignorednon-list contrasts argument ignored
ToyotaCorollaDummy=ToyotaCorollaDummy[,!colnames(ToyotaCorollaDummy) %in% "Fuel_TypeCNG"]
ToyotaCorollaDummy=ToyotaCorollaDummy[,!colnames(ToyotaCorollaDummy) %in% "ColorBeige"]
as.array(names(ToyotaCorollaDummy))
 [1] "Id"                "Model"             "Price"            
 [4] "Age_08_04"         "Mfg_Month"         "Mfg_Year"         
 [7] "KM"                "Fuel_TypeDiesel"   "Fuel_TypePetrol"  
[10] "HP"                "Met_Color"         "ColorBlack"       
[13] "ColorBlue"         "ColorGreen"        "ColorGrey"        
[16] "ColorRed"          "ColorSilver"       "ColorViolet"      
[19] "ColorWhite"        "ColorYellow"       "Automatic"        
[22] "CC"                "Doors"             "Cylinders"        
[25] "Gears"             "Quarterly_Tax"     "Weight"           
[28] "Mfr_Guarantee"     "BOVAG_Guarantee"   "Guarantee_Period" 
[31] "ABS"               "Airbag_1"          "Airbag_2"         
[34] "Airco"             "Automatic_airco"   "Boardcomputer"    
[37] "CD_Player"         "Central_Lock"      "Powered_Windows"  
[40] "Power_Steering"    "Radio"             "Mistlamps"        
[43] "Sport_Model"       "Backseat_Divider"  "Metallic_Rim"     
[46] "Radio_cassette"    "Parking_Assistant" "Tow_Bar"          

Analysis
a) I would convert hem into factors using as.factor function, create dummy varialbes using the dummy.data.frame function and remove one of the columns from my dummy variables as shown above.
b) we partion the data due to the need for building the model, testing it on a validation set (to determine the strength of the model) and using our testing data set as our preidction set.

set.seed(1)
train.rows <- sample(rownames(ToyotaCorolla), dim(ToyotaCorolla)[1]*0.5)
set.seed(1)
valid.rows <- sample(setdiff(rownames(ToyotaCorolla), train.rows),dim(ToyotaCorolla)[1]*0.3)
set.seed(1)
test.rows <- setdiff(rownames(ToyotaCorolla), union(train.rows, valid.rows))

train.data <- ToyotaCorolla[train.rows, ]
valid.data <- ToyotaCorolla[valid.rows, ]
test.data <- ToyotaCorolla[test.rows, ]

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. a. Create a bar chart, showing the average retail price by store. Which store has the highest average? Which has the lowest?


LaptopSales = read.csv("/Users/kayhanbabakan/OneDrive/MIT/Data Mining/Data_export/LaptopSalesJanuary2008.csv")
str(LaptopSales)
'data.frame':   7956 obs. of  17 variables:
 $ Date                  : Factor w/ 7303 levels "1/1/2008 0:01",..: 1 2 3 3 4 5 6 7 8 9 ...
 $ Configuration         : int  163 320 23 169 365 309 75 346 70 351 ...
 $ Customer.Postcode     : Factor w/ 834 levels "BR3 1AG","BR3 3LA",..: 230 563 208 533 229 613 464 320 733 580 ...
 $ Store.Postcode        : Factor w/ 16 levels "CR7 8LE","E2 0RY",..: 9 11 2 9 14 14 10 2 12 14 ...
 $ Retail.Price          : int  455 545 515 395 585 555 465 450 455 620 ...
 $ Screen.Size..Inches.  : int  15 15 15 15 15 15 15 15 15 15 ...
 $ Battery.Life..Hours.  : int  5 6 4 5 6 6 4 6 4 6 ...
 $ RAM..GB.              : int  1 1 1 1 2 1 2 2 2 2 ...
 $ Processor.Speeds..GHz.: num  2 2 2 2 2 2 2 1.5 2 1.5 ...
 $ Integrated.Wireless.  : Factor w/ 2 levels "No","Yes": 2 1 2 1 1 2 1 1 2 1 ...
 $ HD.Size..GB.          : int  80 300 300 40 120 120 80 40 120 300 ...
 $ Bundled.Applications. : Factor w/ 2 levels "No","Yes": 2 1 2 2 2 2 2 1 1 2 ...
 $ OS.X.Customer         : int  532041 529240 533095 529902 531684 529207 534575 530461 520898 530298 ...
 $ OS.Y.Customer         : int  180995 175537 181047 179641 180948 180969 168236 186176 180071 177435 ...
 $ OS.X.Store            : int  534057 528739 535652 534057 528924 528924 537175 535652 525155 528924 ...
 $ OS.Y.Store            : int  179682 173080 182961 179682 178440 178440 177885 182961 175180 178440 ...
 $ CustomerStoreDistance : num  2406 2508 3194 4155 3729 ...
ggplot(LaptopSales)+
  geom_bar(aes(Store.Postcode,Retail.Price),stat="summary",fun.y="mean")+
  theme(axis.text.x = element_text(angle = 90))


agg.data=aggregate(data = LaptopSales,Retail.Price~Store.Postcode,mean)
agg.data[order(agg.data$Retail.Price),]
Analysis
  • lowest average sales store in Post Code: W4 3PH
  • highest average sales store Post Code store: N17 6QA

  1. 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?
x=subset(LaptopSales,Store.Postcode %in% c("W4 3PH","N17 6QA"))
ggplot(LaptopSales)+ 
  geom_boxplot(aes(LaptopSales$Store.Postcode,LaptopSales$Retail.Price))+
  theme(axis.text.x = element_text(angle = 90))


ggplot(x)+ 
  geom_boxplot(aes(x$Store.Postcode,x$Retail.Price))+
  theme(axis.text.x = element_text(angle = 90))

Analysis
the median sale, 3rd and 1st quartiles of the higher sales store (left) are stronger. Additionally, store W43PH has a few additional outliers which need further investigation.


4.1 Breakfast Cereals. Use the data for the breakfast cereals example in Section 4.8 to explore and summarize the data as follows: a. Which variables are quantitative/numerical? Which are ordinal? Which are nominal?

breakfast = read.csv("/Users/kayhanbabakan/OneDrive/MIT/Data Mining/Data_export/Cereals.csv")
str(breakfast)
'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 ...

Ordinal Variables: Rating, Shelf
Nominal Variables: Manufacturer, Type, Name
Quantitative/Numerical: Calories, Protein, Fat, Sodium, Fiber, Carbo, Sugars, Potass, Vitamins, Weight, Cups


  1. 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=breakfast[,c("calories","protein","fat","sodium","fiber","carbo","sugars","potass","vitamins","weight","cups")]
data.frame(mean=sapply(cereal, mean,na.rm=TRUE),
           median=sapply(cereal, median,na.rm=TRUE),
           min=sapply(cereal, min,na.rm=TRUE),
           max=sapply(cereal, max,na.rm=TRUE),
           standardev=sapply(cereal,sd,na.rm=TRUE))
  1. Use R to plot a histogram for each of the quantitative variables. Based on the histograms and summary statistics, answer the following questions:
cereal %>%
  keep(is.numeric) %>%                     
  gather() %>%                             
  ggplot(aes(value),binwidth=5) +                     
    facet_wrap(~ key, scales = "free") +   
    geom_density()

  1. Which variables have the largest variability?
    Variabiles with the highest variability are: Sugars,Shelf, and Sodium
  2. Which variables seem skewed?
    Variables that are Skewed: Fat, Fiber, Potass, Vitamins
  3. Are there any values that seem extreme?
    Extreme values are vitamins at 100 g, Sugars at 300 g, protein at 6 g, fiber at 15g

  1. Use R to plot a side-by-side boxplot comparing the calories in hot vs. cold cereals.What does this plot show us?
hotvcold=subset(breakfast,breakfast$type %in% c("C","H"))
ggplot(hotvcold)+ 
  geom_boxplot(aes(hotvcold$type,hotvcold$calories))

Tells us that there are few H observations (hot cereals) and they are all of the same calorie content. of the cold ceral the median value is at the 3rd quartile due to a significant amount of cereals being in the 110 calorie range the data is highly skewed left.

  1. 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?
breakfast$shelf=as.factor(breakfast$shelf)
ggplot(breakfast)+ 
  geom_boxplot(aes(breakfast$shelf,breakfast$rating))


due to the similarites in the distribution of shelves 1/3, I believe we could group both of them together into their own category.

  1. Compute the correlation table for the quantitative variable (function cor()). Inaddition, generate a matrix plot for these variables (function plot(data)).
zz=data.frame(cor(cereal, use = "complete.obs"))
zz
plot(zz)

  1. Which pair of variables is most strongly correlated? Potassium and Fiber have the strongest correlation
ggplot(cereal,aes(potass,fiber))+
  geom_point()

  1. How can we reduce the number of variables based on these correlations?
    We can perform principal component analysis to reduce the # of dimensions through understanding how much of the variance is explaiend by Potassium to Fiber

  2. How would the correlations change if we normalized the data first?
    Normalizing the data first will greatly impact the PCA as the scale of the variables are not the same. Only when normalizing the data and bringing everything to a level playing field with the PCA work correctly.

  1. Consider the first PC of the analysis of the 13 numerical variables in Table 4.11. Describe briefly what this PC represents.
    The PC1 is dominated by the samount of sodium and is measuring the total amount of sodium in the given cereal.
LS0tCnRpdGxlOiAiSG9tZXdvcmsgMSA8L2JyPiA8c21hbGw+S2F5aGFuIEJhYmFrYW48YnI+MTUuMDYyPC9zbWFsbD4iCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJ0aWR5ciIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJST0NSIikKbGlicmFyeSgicnBhcnQiKQpsaWJyYXJ5KCJycGFydC5wbG90IikKbGlicmFyeSgiY2FyZXQiKQpsaWJyYXJ5KCJyYW5kb21Gb3Jlc3QiKQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJ0bSIpCmxpYnJhcnkoIlNub3diYWxsQyIpCmxpYnJhcnkoInNvZnRJbXB1dGUiKQpsaWJyYXJ5KCJnbG1uZXQiKQpsaWJyYXJ5KCJIbWlzYyIpCmxpYnJhcnkoImR1bW1pZXMiKQpsaWJyYXJ5KCd0aW55dGV4JykKbGlicmFyeSgnR0dhbGx5JykKbGlicmFyeSgnZ2dwdWJyJykKbGlicmFyeSgnZ3Bsb3RzJykKYGBgCgoyLjExKSBUaGUgZGF0YXNldCBUb3lvdGFDb3JvbGxhLmNzdiBjb250YWlucyBkYXRhIG9uIHVzZWQgY2FycyBvbiBzYWxlIGR1cmluZyB0aGUgbGF0ZSBzdW1tZXIgb2YgMjAwNCBpbiB0aGUgTmV0aGVybGFuZHMuIEl0IGhhcyAxNDM2IHJlY29yZHMgY29udGFpbmluZyBkZXRhaWxzIG9uIDM4IGF0dHJpYnV0ZXMsIGluY2x1ZGluZyBQcmljZSwgQWdlLCBLaWxvbWV0ZXJzLCBIUCwgYW5kIG90aGVyIHNwZWNpZmljYXRpb25zLgogIGEpIEV4cGxvcmUgdGhlIGRhdGEgdXNpbmcgdGhlIGRhdGEgdmlzdWFsaXphdGlvbiBjYXBhYmlsaXRpZXMgb2YgUi5XaGljaCBvZiB0aGUgcGFpcnMgYW1vbmcgdGhlIHZhcmlhYmxlcyBzZWVtIHRvIGJlIGNvcnJlbGF0ZWQ/CgpgYGB7cn0Kcm0obGlzdD1scygpKQpUb3lvdGFDb3JvbGxhPXJlYWQuY3N2KCIvVXNlcnMva2F5aGFuYmFiYWthbi9PbmVEcml2ZS9NSVQvRGF0YSBNaW5pbmcvRGF0YV9leHBvcnQvVG95b3RhQ29yb2xsYS5jc3YiKQpkcm9wcyA9IGMoIklkIiwiTW9kZWwiLCJGdWVsX1R5cGUiLCJDb2xvciIsIkN5bGluZGVycyIpClRDRGF0YSA9IFRveW90YUNvcm9sbGFbLCFjb2xuYW1lcyhUb3lvdGFDb3JvbGxhKSAlaW4lIGRyb3BzXQpjb3JtYXRyaXggPSBzdXBwcmVzc1dhcm5pbmdzKGNvcihUQ0RhdGEpKQpUQ0RhdGEkQm9hcmRjb21wdXRlciA9IGFzLmZhY3RvcihUQ0RhdGEkQm9hcmRjb21wdXRlcikKVENEYXRhJFBvd2VyZWRfV2luZG93cyA9IGFzLmZhY3RvcihUQ0RhdGEkUG93ZXJlZF9XaW5kb3dzKQpUQ0RhdGEkQ2VudHJhbF9Mb2NrID0gYXMuZmFjdG9yKFRDRGF0YSRDZW50cmFsX0xvY2spClRDRGF0YSRDZW50cmFsX0xvY2sgPSBhcy5mYWN0b3IoVENEYXRhJFJhZGlvKQpUQ0RhdGEkQ2VudHJhbF9Mb2NrID0gYXMuZmFjdG9yKFRDRGF0YSRSYWRpb19jYXNzZXR0ZSkKCiNoZWF0bWFwCmhlYXRtYXAoY29ybWF0cml4LCBSb3d2ID0gTkEsIENvbHYgPSBOQSkKZGF0YS5mcmFtZShjb3JtYXRyaXgpCgojcHJpY2UvYWdlL21mZ195ZWFyCnByY2FnZXlyPWdncGxvdChUb3lvdGFDb3JvbGxhLGFlcyhUb3lvdGFDb3JvbGxhJEFnZV8wOF8wNCxQcmljZSxjb2xvdXI9TWZnX1llYXIpKSsKICBnZW9tX3BvaW50KCkKI21mZ195ZWFyL2JwYXJkY29tcAptZmdiY21wPWdncGxvdChUb3lvdGFDb3JvbGxhLGFlcyh4PVRDRGF0YSRNZmdfWWVhcixmaWxsPUJvYXJkY29tcHV0ZXI9PTEpKSsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xLHBvc2l0aW9uPSdmaWxsJykKI3Bvd2Vyd2luZG93L2NlbnRyYWxsb2NrCnBvd2NlbnQ9Z2dwbG90KFRveW90YUNvcm9sbGEsYWVzKHg9VENEYXRhJFBvd2VyZWRfV2luZG93cyx5PVRDRGF0YSRDZW50cmFsX0xvY2spKSsKICBnZW9tX2NvbCgpCiNyYWRpby9jYXNzZXR0ZQpyYWRjYXM9Z2dwbG90KFRveW90YUNvcm9sbGEsYWVzKHg9VENEYXRhJFJhZGlvLHk9VENEYXRhJFJhZGlvX2Nhc3NldHRlKSkrCiAgZ2VvbV9jb2woKQpnZ2FycmFuZ2UocHJjYWdleXIsbWZnYmNtcCxwb3djZW50LHJhZGNhcyxucm93PTIsbmNvbD0yKQpgYGAKYikgV2UgcGxhbiB0byBhbmFseXplIHRoZSBkYXRhIHVzaW5nIHZhcmlvdXMgZGF0YSBtaW5pbmcgdGVjaG5pcXVlcyBkZXNjcmliZWQgaW4gZnV0dXJlIGNoYXB0ZXJzLiBQcmVwYXJlIHRoZSBkYXRhIGZvciB1c2UgYXMgZm9sbG93czoKICAgIGkuIFRoZSBkYXRhc2V0IGhhcyB0d28gY2F0ZWdvcmljYWwgYXR0cmlidXRlcywgRnVlbCBUeXBlIGFuZCBDb2xvci4gRGVzY3JpYmUgaG93IHlvdSB3b3VsZCBjb252ZXJ0IHRoZXNlIHRvIGJpbmFyeSB2YXJpYWJsZXMuIAogICAgQ29uZmlybSB0aGlzIHVzaW5nIFLigJlzIGZ1bmN0aW9ucyB0byB0cmFuc2Zvcm0gY2F0ZWdvcmljYWwgZGF0YSBpbnRvIGR1bW1pZXMuCiAgICBpaS4gUHJlcGFyZSB0aGUgZGF0YXNldCAoYXMgZmFjdG9yZWQgaW50byBkdW1taWVzKSBmb3IgZGF0YSBtaW5pbmcgdGVjaG5pcXVlcyBvZiBzdXBlcnZpc2VkIGxlYXJuaW5nIGJ5IGNyZWF0aW5nIHBhcnRpdGlvbnMgaW4gUi4gU2VsZWN0IGFsbCB0aGUgdmFyaWFibGVzIGFuZCB1c2UgZGVmYXVsdCB2YWx1ZXMgZm9yIHRoZSByYW5kb20gc2VlZCBhbmQgcGFydGl0aW9uaW5nIHBlcmNlbnRhZ2VzIGZvciB0cmFpbmluZyAoNTAlKSwgdmFsaWRhdGlvbiAoMzAlKSwgYW5kIHRlc3QgKDIwJSkgc2V0cy4gRGVzY3JpYmUgdGhlIHJvbGVzIHRoYXQgdGhlc2UgcGFydGl0aW9ucyB3aWxsIHBsYXkgaW4gbW9kZWxpbmcuCmBgYHtyfQpUb3lvdGFDb3JvbGxhJE1vZGVsID0gYXMuY2hhcmFjdGVyKFRveW90YUNvcm9sbGEkTW9kZWwpClRveW90YUNvcm9sbGFEdW1teT1kdW1teS5kYXRhLmZyYW1lKFRveW90YUNvcm9sbGEsZHVtbXkuY2xhc3M9ImZhY3RvciIpClRveW90YUNvcm9sbGFEdW1teT1Ub3lvdGFDb3JvbGxhRHVtbXlbLCFjb2xuYW1lcyhUb3lvdGFDb3JvbGxhRHVtbXkpICVpbiUgIkZ1ZWxfVHlwZUNORyJdClRveW90YUNvcm9sbGFEdW1teT1Ub3lvdGFDb3JvbGxhRHVtbXlbLCFjb2xuYW1lcyhUb3lvdGFDb3JvbGxhRHVtbXkpICVpbiUgIkNvbG9yQmVpZ2UiXQphcy5hcnJheShuYW1lcyhUb3lvdGFDb3JvbGxhRHVtbXkpKQpgYGAKPGI+QW5hbHlzaXM8L2I+PC9icj4KPGZvbnQgY29sb3IgPSAicmVkIj4KYSkgSSB3b3VsZCBjb252ZXJ0IGhlbSBpbnRvIGZhY3RvcnMgdXNpbmcgYXMuZmFjdG9yIGZ1bmN0aW9uLCBjcmVhdGUgZHVtbXkgdmFyaWFsYmVzIHVzaW5nIHRoZSBkdW1teS5kYXRhLmZyYW1lIGZ1bmN0aW9uIGFuZCByZW1vdmUgb25lIG9mIHRoZSBjb2x1bW5zIGZyb20gbXkgZHVtbXkgdmFyaWFibGVzIGFzIHNob3duIGFib3ZlLiA8L2JyPgpiKSB3ZSBwYXJ0aW9uIHRoZSBkYXRhIGR1ZSB0byB0aGUgbmVlZCBmb3IgYnVpbGRpbmcgdGhlIG1vZGVsLCB0ZXN0aW5nIGl0IG9uIGEgdmFsaWRhdGlvbiBzZXQgKHRvIGRldGVybWluZSB0aGUgc3RyZW5ndGggb2YgdGhlIG1vZGVsKSBhbmQgdXNpbmcgb3VyIHRlc3RpbmcgZGF0YSBzZXQgYXMgb3VyIHByZWlkY3Rpb24gc2V0LiAKPC9mb250Pgo8L3NtYWxsPgpgYGB7cn0Kc2V0LnNlZWQoMSkKdHJhaW4ucm93cyA8LSBzYW1wbGUocm93bmFtZXMoVG95b3RhQ29yb2xsYSksIGRpbShUb3lvdGFDb3JvbGxhKVsxXSowLjUpCnNldC5zZWVkKDEpCnZhbGlkLnJvd3MgPC0gc2FtcGxlKHNldGRpZmYocm93bmFtZXMoVG95b3RhQ29yb2xsYSksIHRyYWluLnJvd3MpLGRpbShUb3lvdGFDb3JvbGxhKVsxXSowLjMpCnNldC5zZWVkKDEpCnRlc3Qucm93cyA8LSBzZXRkaWZmKHJvd25hbWVzKFRveW90YUNvcm9sbGEpLCB1bmlvbih0cmFpbi5yb3dzLCB2YWxpZC5yb3dzKSkKCnRyYWluLmRhdGEgPC0gVG95b3RhQ29yb2xsYVt0cmFpbi5yb3dzLCBdCnZhbGlkLmRhdGEgPC0gVG95b3RhQ29yb2xsYVt2YWxpZC5yb3dzLCBdCnRlc3QuZGF0YSA8LSBUb3lvdGFDb3JvbGxhW3Rlc3Qucm93cywgXQpgYGAKCjMuMykgTGFwdG9wIFNhbGVzIGF0IGEgTG9uZG9uIENvbXB1dGVyIENoYWluOiBCYXIgQ2hhcnRzIGFuZCBCb3hwbG90cy4gVGhlIGZpbGUgTGFwdG9wU2FsZXNKYW51YXJ5MjAwOC5jc3YgY29udGFpbnMgZGF0YSBmb3IgYWxsIHNhbGVzIG9mIGxhcHRvcHMgYXQgYSBjb21wdXRlciBjaGFpbiBpbiBMb25kb24gaW4gSmFudWFyeSAyMDA4LiBUaGlzIGlzIGEgc3Vic2V0IG9mIHRoZSBmdWxsIGRhdGFzZXQgdGhhdCBpbmNsdWRlcyBkYXRhIGZvciB0aGUgZW50aXJlIHllYXIuCmEuIENyZWF0ZSBhIGJhciBjaGFydCwgc2hvd2luZyB0aGUgYXZlcmFnZSByZXRhaWwgcHJpY2UgYnkgc3RvcmUuIFdoaWNoIHN0b3JlIGhhcyB0aGUgaGlnaGVzdCBhdmVyYWdlPyBXaGljaCBoYXMgdGhlIGxvd2VzdD8KCmBgYHtyfQoKTGFwdG9wU2FsZXMgPSByZWFkLmNzdigiL1VzZXJzL2theWhhbmJhYmFrYW4vT25lRHJpdmUvTUlUL0RhdGEgTWluaW5nL0RhdGFfZXhwb3J0L0xhcHRvcFNhbGVzSmFudWFyeTIwMDguY3N2IikKc3RyKExhcHRvcFNhbGVzKQpnZ3Bsb3QoTGFwdG9wU2FsZXMpKwogIGdlb21fYmFyKGFlcyhTdG9yZS5Qb3N0Y29kZSxSZXRhaWwuUHJpY2UpLHN0YXQ9InN1bW1hcnkiLGZ1bi55PSJtZWFuIikrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCgphZ2cuZGF0YT1hZ2dyZWdhdGUoZGF0YSA9IExhcHRvcFNhbGVzLFJldGFpbC5QcmljZX5TdG9yZS5Qb3N0Y29kZSxtZWFuKQphZ2cuZGF0YVtvcmRlcihhZ2cuZGF0YSRSZXRhaWwuUHJpY2UpLF0KYGBgCjxzbWFsbD48Zm9udCBjb2xvciA9ICJyZWQiPgo8Yj5BbmFseXNpczwvYj4KPGJyPjx1bD4KPGxpPmxvd2VzdCBhdmVyYWdlIHNhbGVzIHN0b3JlIGluIFBvc3QgQ29kZTogVzQgM1BIPC9saT4KPGxpPmhpZ2hlc3QgYXZlcmFnZSBzYWxlcyBzdG9yZSBQb3N0IENvZGUgc3RvcmU6IE4xNyA2UUE8L2xpPgo8L3VsPgo8L2ZvbnQ+Cjwvc21hbGw+CgoKYi4gVG8gYmV0dGVyIGNvbXBhcmUgcmV0YWlsIHByaWNlcyBhY3Jvc3Mgc3RvcmVzLCBjcmVhdGUgc2lkZS1ieS1zaWRlIGJveHBsb3RzIG9mIHJldGFpbCBwcmljZSBieSBzdG9yZS4gTm93IGNvbXBhcmUgdGhlIHByaWNlcyBpbiB0aGUgdHdvIHN0b3JlcyBmcm9tIChhKS4gRG9lcyB0aGVyZSBzZWVtIHRvIGJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZWlyIHByaWNlIGRpc3RyaWJ1dGlvbnM/CmBgYHtyfQp4PXN1YnNldChMYXB0b3BTYWxlcyxTdG9yZS5Qb3N0Y29kZSAlaW4lIGMoIlc0IDNQSCIsIk4xNyA2UUEiKSkKZ2dwbG90KExhcHRvcFNhbGVzKSsgCiAgZ2VvbV9ib3hwbG90KGFlcyhMYXB0b3BTYWxlcyRTdG9yZS5Qb3N0Y29kZSxMYXB0b3BTYWxlcyRSZXRhaWwuUHJpY2UpKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKCmdncGxvdCh4KSsgCiAgZ2VvbV9ib3hwbG90KGFlcyh4JFN0b3JlLlBvc3Rjb2RlLHgkUmV0YWlsLlByaWNlKSkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCmBgYAo8c21hbGw+PGZvbnQgY29sb3IgPSAicmVkIj4KPGI+QW5hbHlzaXM8L2I+Cjxicj4KdGhlIG1lZGlhbiBzYWxlLCAzcmQgYW5kIDFzdCBxdWFydGlsZXMgb2YgdGhlIGhpZ2hlciBzYWxlcyBzdG9yZSAobGVmdCkgYXJlIHN0cm9uZ2VyLiBBZGRpdGlvbmFsbHksIHN0b3JlIFc0M1BIIGhhcyBhIGZldyBhZGRpdGlvbmFsIG91dGxpZXJzIHdoaWNoIG5lZWQgZnVydGhlciBpbnZlc3RpZ2F0aW9uLgo8L2ZvbnQ+Cjwvc21hbGw+CjwvYnI+CjwvYnI+Cgo0LjEgQnJlYWtmYXN0IENlcmVhbHMuIFVzZSB0aGUgZGF0YSBmb3IgdGhlIGJyZWFrZmFzdCBjZXJlYWxzIGV4YW1wbGUgaW4gU2VjdGlvbiA0LjggdG8gZXhwbG9yZSBhbmQgc3VtbWFyaXplIHRoZSBkYXRhIGFzIGZvbGxvd3M6CmEuIFdoaWNoIHZhcmlhYmxlcyBhcmUgcXVhbnRpdGF0aXZlL251bWVyaWNhbD8gV2hpY2ggYXJlIG9yZGluYWw/IFdoaWNoIGFyZSBub21pbmFsPwpgYGB7cn0KYnJlYWtmYXN0ID0gcmVhZC5jc3YoIi9Vc2Vycy9rYXloYW5iYWJha2FuL09uZURyaXZlL01JVC9EYXRhIE1pbmluZy9EYXRhX2V4cG9ydC9DZXJlYWxzLmNzdiIpCnN0cihicmVha2Zhc3QpCmBgYAo8c21hbGw+PGZvbnQgY29sb3IgPSAicmVkIj4KPGI+T3JkaW5hbCBWYXJpYWJsZXM6PC9iPiBSYXRpbmcsIFNoZWxmPC9icj4KPGI+Tm9taW5hbCBWYXJpYWJsZXM6PC9iPiBNYW51ZmFjdHVyZXIsIFR5cGUsIE5hbWUgPC9icj4KPGI+UXVhbnRpdGF0aXZlL051bWVyaWNhbDogPC9iPkNhbG9yaWVzLCBQcm90ZWluLCBGYXQsIFNvZGl1bSwgRmliZXIsIENhcmJvLCBTdWdhcnMsIFBvdGFzcywgVml0YW1pbnMsIFdlaWdodCwgQ3Vwcwo8L3NtYWxsPjwvZm9udD48L2JyPgo8L2JyPgoKYi4gQ29tcHV0ZSB0aGUgbWVhbiwgbWVkaWFuLCBtaW4sIG1heCwgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgZWFjaCBvZiB0aGUgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcy4gVGhpcyBjYW4gYmUgZG9uZSB0aHJvdWdoIFLigJlzIHNhcHBseSgpIGZ1bmN0aW9uIChlLmcuLCBzYXAtIHBseShkYXRhLCBtZWFuLCBuYS5ybSA9IFRSVUUpKQoKYGBge3J9CmNlcmVhbD1icmVha2Zhc3RbLGMoImNhbG9yaWVzIiwicHJvdGVpbiIsImZhdCIsInNvZGl1bSIsImZpYmVyIiwiY2FyYm8iLCJzdWdhcnMiLCJwb3Rhc3MiLCJ2aXRhbWlucyIsIndlaWdodCIsImN1cHMiKV0KZGF0YS5mcmFtZShtZWFuPXNhcHBseShjZXJlYWwsIG1lYW4sbmEucm09VFJVRSksCiAgICAgICAgICAgbWVkaWFuPXNhcHBseShjZXJlYWwsIG1lZGlhbixuYS5ybT1UUlVFKSwKICAgICAgICAgICBtaW49c2FwcGx5KGNlcmVhbCwgbWluLG5hLnJtPVRSVUUpLAogICAgICAgICAgIG1heD1zYXBwbHkoY2VyZWFsLCBtYXgsbmEucm09VFJVRSksCiAgICAgICAgICAgc3RhbmRhcmRldj1zYXBwbHkoY2VyZWFsLHNkLG5hLnJtPVRSVUUpKQpgYGAKYy4gVXNlIFIgdG8gcGxvdCBhIGhpc3RvZ3JhbSBmb3IgZWFjaCBvZiB0aGUgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcy4gQmFzZWQgb24gdGhlIGhpc3RvZ3JhbXMgYW5kIHN1bW1hcnkgc3RhdGlzdGljcywgYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgpgYGB7cn0KY2VyZWFsICU+JQogIGtlZXAoaXMubnVtZXJpYykgJT4lICAgICAgICAgICAgICAgICAgICAgCiAgZ2F0aGVyKCkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICBnZ3Bsb3QoYWVzKHZhbHVlKSxiaW53aWR0aD01KSArICAgICAgICAgICAgICAgICAgICAgCiAgICBmYWNldF93cmFwKH4ga2V5LCBzY2FsZXMgPSAiZnJlZSIpICsgICAKICAgIGdlb21fZGVuc2l0eSgpCmBgYAoKaS4gV2hpY2ggdmFyaWFibGVzIGhhdmUgdGhlIGxhcmdlc3QgdmFyaWFiaWxpdHk/Cjxmb250IGNvbG9yID0gInJlZCI+PC9icj4KVmFyaWFiaWxlcyAgd2l0aCB0aGUgaGlnaGVzdCB2YXJpYWJpbGl0eSBhcmU6IFN1Z2FycyxTaGVsZiwgYW5kIFNvZGl1bQo8L2ZvbnQ+CmlpLiBXaGljaCB2YXJpYWJsZXMgc2VlbSBza2V3ZWQ/PC9icj4KPGZvbnQgY29sb3IgPSAicmVkIj4gVmFyaWFibGVzIHRoYXQgYXJlIFNrZXdlZDogRmF0LCBGaWJlciwgUG90YXNzLCBWaXRhbWlucwo8L2ZvbnQ+CmlpaS4gQXJlIHRoZXJlIGFueSB2YWx1ZXMgdGhhdCBzZWVtIGV4dHJlbWU/PGZvbnQgY29sb3I9InJlZCI+PC9icj4KRXh0cmVtZSB2YWx1ZXMgYXJlIHZpdGFtaW5zIGF0IDEwMCBnLCBTdWdhcnMgYXQgMzAwIGcsIHByb3RlaW4gYXQgNiBnLCBmaWJlciBhdCAxNWcKPC9mb250Pgo8L2JyPgpkKSBVc2UgUiB0byBwbG90IGEgc2lkZS1ieS1zaWRlIGJveHBsb3QgY29tcGFyaW5nIHRoZSBjYWxvcmllcyBpbiBob3QgdnMuIGNvbGQgY2VyZWFscy5XaGF0IGRvZXMgdGhpcyBwbG90IHNob3cgdXM/CmBgYHtyfQpob3R2Y29sZD1zdWJzZXQoYnJlYWtmYXN0LGJyZWFrZmFzdCR0eXBlICVpbiUgYygiQyIsIkgiKSkKZ2dwbG90KGhvdHZjb2xkKSsgCiAgZ2VvbV9ib3hwbG90KGFlcyhob3R2Y29sZCR0eXBlLGhvdHZjb2xkJGNhbG9yaWVzKSkKYGBgCjxmb250IGNvbG9yID0gInJlZCI+ClRlbGxzIHVzIHRoYXQgdGhlcmUgYXJlIGZldyBIIG9ic2VydmF0aW9ucyAoaG90IGNlcmVhbHMpIGFuZCB0aGV5IGFyZSBhbGwgb2YgdGhlIHNhbWUgY2Fsb3JpZSBjb250ZW50LiBvZiB0aGUgY29sZCBjZXJhbCB0aGUgbWVkaWFuIHZhbHVlIGlzIGF0IHRoZSAzcmQgcXVhcnRpbGUgZHVlIHRvIGEgc2lnbmlmaWNhbnQgYW1vdW50IG9mIGNlcmVhbHMgYmVpbmcgaW4gdGhlIDExMCBjYWxvcmllIHJhbmdlIHRoZSBkYXRhIGlzIGhpZ2hseSBza2V3ZWQgbGVmdC4KPC9mb250PjwvYnI+CgplLiBVc2UgUiB0byBwbG90IGEgc2lkZS1ieS1zaWRlIGJveHBsb3Qgb2YgY29uc3VtZXIgcmF0aW5nIGFzIGEgZnVuY3Rpb24gb2YgdGhlIHNoZWxmIGhlaWdodC4gSWYgd2Ugd2VyZSB0byBwcmVkaWN0IGNvbnN1bWVyIHJhdGluZyBmcm9tIHNoZWxmIGhlaWdodCwgZG9lcyBpdCBhcHBlYXIgdGhhdCB3ZSBuZWVkIHRvIGtlZXAgYWxsIHRocmVlIGNhdGVnb3JpZXMgb2Ygc2hlbGYgaGVpZ2h0PwoKYGBge3J9CmJyZWFrZmFzdCRzaGVsZj1hcy5mYWN0b3IoYnJlYWtmYXN0JHNoZWxmKQpnZ3Bsb3QoYnJlYWtmYXN0KSsgCiAgZ2VvbV9ib3hwbG90KGFlcyhicmVha2Zhc3Qkc2hlbGYsYnJlYWtmYXN0JHJhdGluZykpCmBgYAo8Zm9udCBjb2xvciA9ICJyZWQiPjwvYnI+CmR1ZSB0byB0aGUgc2ltaWxhcml0ZXMgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBzaGVsdmVzIDEvMywgSSBiZWxpZXZlIHdlIGNvdWxkIGdyb3VwIGJvdGggb2YgdGhlbSB0b2dldGhlciBpbnRvIHRoZWlyIG93biBjYXRlZ29yeS4KPC9mb250PjwvYnI+CgpmKSBDb21wdXRlIHRoZSBjb3JyZWxhdGlvbiB0YWJsZSBmb3IgdGhlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZSAoZnVuY3Rpb24gY29yKCkpLiBJbmFkZGl0aW9uLCBnZW5lcmF0ZSBhIG1hdHJpeCBwbG90IGZvciB0aGVzZSB2YXJpYWJsZXMgKGZ1bmN0aW9uIHBsb3QoZGF0YSkpLgpgYGB7cn0Keno9ZGF0YS5mcmFtZShjb3IoY2VyZWFsLCB1c2UgPSAiY29tcGxldGUub2JzIikpCnp6CnBsb3QoenopCmBgYAoKaS4gV2hpY2ggcGFpciBvZiB2YXJpYWJsZXMgaXMgbW9zdCBzdHJvbmdseSBjb3JyZWxhdGVkPwpQb3Rhc3NpdW0gYW5kIEZpYmVyIGhhdmUgdGhlIHN0cm9uZ2VzdCBjb3JyZWxhdGlvbgpgYGB7cn0KZ2dwbG90KGNlcmVhbCxhZXMocG90YXNzLGZpYmVyKSkrCiAgZ2VvbV9wb2ludCgpCmBgYAppaS4gSG93IGNhbiB3ZSByZWR1Y2UgdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgYmFzZWQgb24gdGhlc2UgY29ycmVsYXRpb25zPzwvYnI+Cjxmb250IGNvbG9yPSJyZWQiPldlIGNhbiBwZXJmb3JtIHByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgdG8gcmVkdWNlIHRoZSAjIG9mIGRpbWVuc2lvbnMgdGhyb3VnaCB1bmRlcnN0YW5kaW5nIGhvdyBtdWNoIG9mIHRoZSB2YXJpYW5jZSBpcyBleHBsYWllbmQgYnkgUG90YXNzaXVtIHRvIEZpYmVyCjwvZm9udD4KCmlpaS4gSG93IHdvdWxkIHRoZSBjb3JyZWxhdGlvbnMgY2hhbmdlIGlmIHdlIG5vcm1hbGl6ZWQgdGhlIGRhdGEgZmlyc3Q/PC9icj4KPGZvbnQgY29sb3I9InJlZCI+Tm9ybWFsaXppbmcgdGhlIGRhdGEgZmlyc3Qgd2lsbCBncmVhdGx5IGltcGFjdCB0aGUgUENBIGFzIHRoZSBzY2FsZSBvZiB0aGUgdmFyaWFibGVzIGFyZSBub3QgdGhlIHNhbWUuIE9ubHkgd2hlbiBub3JtYWxpemluZyB0aGUgZGF0YSBhbmQgYnJpbmdpbmcgZXZlcnl0aGluZyB0byBhIGxldmVsIHBsYXlpbmcgZmllbGQgd2l0aCB0aGUgUENBIHdvcmsgY29ycmVjdGx5Lgo8L2ZvbnQ+CgpnLiBDb25zaWRlciB0aGUgZmlyc3QgUEMgb2YgdGhlIGFuYWx5c2lzIG9mIHRoZSAxMyBudW1lcmljYWwgdmFyaWFibGVzIGluIFRhYmxlIDQuMTEuCkRlc2NyaWJlIGJyaWVmbHkgd2hhdCB0aGlzIFBDIHJlcHJlc2VudHMuCjxmb250IGNvbG9yPSJyZWQiPjwvYnI+ClRoZSBQQzEgaXMgZG9taW5hdGVkIGJ5IHRoZSBzYW1vdW50IG9mIHNvZGl1bSBhbmQgaXMgbWVhc3VyaW5nIHRoZSB0b3RhbCBhbW91bnQgb2Ygc29kaXVtIGluIHRoZSBnaXZlbiBjZXJlYWwuPC9mb250Pg==