Background

In order to put newly acquired data science skills to test, l decided to explore the well-known dataset Ames Housing dataset. The Ames dataset used in this instance documents 2006-2010 data records describing the sale of individual residential property in Ames, Iowa. The Ames Housing Dataset was complied by Dean De Cock for use in data science education and publicly available as a competition hosted on Kaggle.com,in which the goal is to build a model to predict sale prices of houses sold in Ames, Iowa . With 79 explanatory variables describing (almost) every aspect of residential homes in Ames, Iowa, this dataset challenges me to predict the final price of each home.The data set contains 2930 observations and a large number of explanatory variables (23 nominal, 23 ordinal, 14 discrete, and 20 continuous) involved in assessing home values.

Kaggle provides 2 datafiles, one is a training set containing all 81 variables, and the other is a test set, which is missing the SalePrice column.

Required Libraries

Below are required libraries that are employed at various stages throughout the modelling process and also to possibly allow for the running of this notebook.

library('ggplot2')
library('ggthemes')
library('scales')
library('dplyr')
library('mice')
library('randomForest')
library('data.table')
library('gridExtra')
library('corrplot')
library('GGally')
library('e1071')
library('reshape2')
library('lares')
library('gbm')
library('MASS')
library('caret')
library('skimr')

Loading of Dataset

The two data files saved on my computer are loaded into R for the purpose of further analysis.

train = read.csv("train_reg_features-1.csv")
#Train data dimension
dim(train)
[1] 1460   81
test = read.csv("test_reg_features-1.csv")
#test data dimension
dim(test)
[1] 1459   80

Exploratoratory Data Analysis

For the purpose of exploratory analysis , the test and train data set are combined for the pupose of cleaning and analysis. The however allows me to preview the entire(combined) dataset.The combined dataset will be later separated to prevent data leakage and repetition during modelling. The combined datasset contains 2919 observations coupled with 81 variables. The training and testing data reports of 1460 and 1459 observations respectively.

test$SalePrice <-NA 

#Bind the train and test datasets for EDA/cleaning
combine_data <-rbind(train,test)
str(combine_data)
'data.frame':   2919 obs. of  81 variables:
 $ Id           : int  1 2 3 4 5 6 7 8 9 10 ...
 $ MSSubClass   : int  60 20 60 70 60 50 20 60 50 190 ...
 $ MSZoning     : chr  "RL" "RL" "RL" "RL" ...
 $ LotFrontage  : int  65 80 68 60 84 85 75 NA 51 50 ...
 $ LotArea      : int  8450 9600 11250 9550 14260 14115 10084 10382 6120 7420 ...
 $ Street       : chr  "Pave" "Pave" "Pave" "Pave" ...
 $ Alley        : chr  NA NA NA NA ...
 $ LotShape     : chr  "Reg" "Reg" "IR1" "IR1" ...
 $ LandContour  : chr  "Lvl" "Lvl" "Lvl" "Lvl" ...
 $ Utilities    : chr  "AllPub" "AllPub" "AllPub" "AllPub" ...
 $ LotConfig    : chr  "Inside" "FR2" "Inside" "Corner" ...
 $ LandSlope    : chr  "Gtl" "Gtl" "Gtl" "Gtl" ...
 $ Neighborhood : chr  "CollgCr" "Veenker" "CollgCr" "Crawfor" ...
 $ Condition1   : chr  "Norm" "Feedr" "Norm" "Norm" ...
 $ Condition2   : chr  "Norm" "Norm" "Norm" "Norm" ...
 $ BldgType     : chr  "1Fam" "1Fam" "1Fam" "1Fam" ...
 $ HouseStyle   : chr  "2Story" "1Story" "2Story" "2Story" ...
 $ OverallQual  : int  7 6 7 7 8 5 8 7 7 5 ...
 $ OverallCond  : int  5 8 5 5 5 5 5 6 5 6 ...
 $ YearBuilt    : int  2003 1976 2001 1915 2000 1993 2004 1973 1931 1939 ...
 $ YearRemodAdd : int  2003 1976 2002 1970 2000 1995 2005 1973 1950 1950 ...
 $ RoofStyle    : chr  "Gable" "Gable" "Gable" "Gable" ...
 $ RoofMatl     : chr  "CompShg" "CompShg" "CompShg" "CompShg" ...
 $ Exterior1st  : chr  "VinylSd" "MetalSd" "VinylSd" "Wd Sdng" ...
 $ Exterior2nd  : chr  "VinylSd" "MetalSd" "VinylSd" "Wd Shng" ...
 $ MasVnrType   : chr  "BrkFace" "None" "BrkFace" "None" ...
 $ MasVnrArea   : int  196 0 162 0 350 0 186 240 0 0 ...
 $ ExterQual    : chr  "Gd" "TA" "Gd" "TA" ...
 $ ExterCond    : chr  "TA" "TA" "TA" "TA" ...
 $ Foundation   : chr  "PConc" "CBlock" "PConc" "BrkTil" ...
 $ BsmtQual     : chr  "Gd" "Gd" "Gd" "TA" ...
 $ BsmtCond     : chr  "TA" "TA" "TA" "Gd" ...
 $ BsmtExposure : chr  "No" "Gd" "Mn" "No" ...
 $ BsmtFinType1 : chr  "GLQ" "ALQ" "GLQ" "ALQ" ...
 $ BsmtFinSF1   : int  706 978 486 216 655 732 1369 859 0 851 ...
 $ BsmtFinType2 : chr  "Unf" "Unf" "Unf" "Unf" ...
 $ BsmtFinSF2   : int  0 0 0 0 0 0 0 32 0 0 ...
 $ BsmtUnfSF    : int  150 284 434 540 490 64 317 216 952 140 ...
 $ TotalBsmtSF  : int  856 1262 920 756 1145 796 1686 1107 952 991 ...
 $ Heating      : chr  "GasA" "GasA" "GasA" "GasA" ...
 $ HeatingQC    : chr  "Ex" "Ex" "Ex" "Gd" ...
 $ CentralAir   : chr  "Y" "Y" "Y" "Y" ...
 $ Electrical   : chr  "SBrkr" "SBrkr" "SBrkr" "SBrkr" ...
 $ X1stFlrSF    : int  856 1262 920 961 1145 796 1694 1107 1022 1077 ...
 $ X2ndFlrSF    : int  854 0 866 756 1053 566 0 983 752 0 ...
 $ LowQualFinSF : int  0 0 0 0 0 0 0 0 0 0 ...
 $ GrLivArea    : int  1710 1262 1786 1717 2198 1362 1694 2090 1774 1077 ...
 $ BsmtFullBath : int  1 0 1 1 1 1 1 1 0 1 ...
 $ BsmtHalfBath : int  0 1 0 0 0 0 0 0 0 0 ...
 $ FullBath     : int  2 2 2 1 2 1 2 2 2 1 ...
 $ HalfBath     : int  1 0 1 0 1 1 0 1 0 0 ...
 $ BedroomAbvGr : int  3 3 3 3 4 1 3 3 2 2 ...
 $ KitchenAbvGr : int  1 1 1 1 1 1 1 1 2 2 ...
 $ KitchenQual  : chr  "Gd" "TA" "Gd" "Gd" ...
 $ TotRmsAbvGrd : int  8 6 6 7 9 5 7 7 8 5 ...
 $ Functional   : chr  "Typ" "Typ" "Typ" "Typ" ...
 $ Fireplaces   : int  0 1 1 1 1 0 1 2 2 2 ...
 $ FireplaceQu  : chr  NA "TA" "TA" "Gd" ...
 $ GarageType   : chr  "Attchd" "Attchd" "Attchd" "Detchd" ...
 $ GarageYrBlt  : int  2003 1976 2001 1998 2000 1993 2004 1973 1931 1939 ...
 $ GarageFinish : chr  "RFn" "RFn" "RFn" "Unf" ...
 $ GarageCars   : int  2 2 2 3 3 2 2 2 2 1 ...
 $ GarageArea   : int  548 460 608 642 836 480 636 484 468 205 ...
 $ GarageQual   : chr  "TA" "TA" "TA" "TA" ...
 $ GarageCond   : chr  "TA" "TA" "TA" "TA" ...
 $ PavedDrive   : chr  "Y" "Y" "Y" "Y" ...
 $ WoodDeckSF   : int  0 298 0 0 192 40 255 235 90 0 ...
 $ OpenPorchSF  : int  61 0 42 35 84 30 57 204 0 4 ...
 $ EnclosedPorch: int  0 0 0 272 0 0 0 228 205 0 ...
 $ X3SsnPorch   : int  0 0 0 0 0 320 0 0 0 0 ...
 $ ScreenPorch  : int  0 0 0 0 0 0 0 0 0 0 ...
 $ PoolArea     : int  0 0 0 0 0 0 0 0 0 0 ...
 $ PoolQC       : chr  NA NA NA NA ...
 $ Fence        : chr  NA NA NA NA ...
 $ MiscFeature  : chr  NA NA NA NA ...
 $ MiscVal      : int  0 0 0 0 0 700 0 350 0 0 ...
 $ MoSold       : int  2 5 9 2 12 10 8 11 4 1 ...
 $ YrSold       : int  2008 2007 2008 2006 2008 2009 2007 2009 2008 2008 ...
 $ SaleType     : chr  "WD" "WD" "WD" "WD" ...
 $ SaleCondition: chr  "Normal" "Normal" "Normal" "Abnorml" ...
 $ SalePrice    : int  208500 181500 223500 140000 250000 143000 307000 200000 129900 118000 ...

From the above it can be observed that all variables are either class character or integer, as such most of them needs to be recoded as numeric or factor. The project documentation suggest that there are 23 ordinal, 23 nominal, 14 discrete and 20 continuous variables.

table(sapply(combine_data, class))

character   integer 
       43        38 

Target Variable Distribution

Below is a visualization of the target variable, which is demonstrated using a histogram and a density plot.The initial plot of the target variable suggest that it is not normally distributed and hence needs to be corrected.The skewness and kurtosis as reported are 1.879009 and 6.4496789 respectively.

## Summary of Target Variable
summary(combine_data$SalePrice)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  34900  129975  163000  180921  214000  755000    1459 
##checking skewness and kurtosis
skewness(train$SalePrice)
[1] 1.879009
kurtosis(train$SalePrice)
[1] 6.496789
### Visual view of target variable
ggplot(combine_data, mapping = aes(x = SalePrice)) + geom_histogram(color = "black", fill = "lightblue")

Normalization of target variable

Target variable(SalePrice) after performing log transformation, looks much more normal.

combine_data$log_SalePrice <-log(combine_data$SalePrice)

ggplot(data = combine_data, aes(x = log_SalePrice)) +
  geom_histogram(col = "#E1AF00", fill = "#3B9AB2", bins = 50)  + 
  scale_x_continuous(breaks = seq(0, 800000, by = 100000), labels = comma) +
  labs(title = "Housing Data: Log(Sale Price)", x = "Log(Sale Price)")

Checking categorical columns

Below is a check on categorical columns in the combined dataset.


names(combine_data)[sapply(combine_data, typeof) == "character"]
 [1] "MSZoning"      "Street"        "Alley"         "LotShape"      "LandContour"   "Utilities"     "LotConfig"     "LandSlope"     "Neighborhood" 
[10] "Condition1"    "Condition2"    "BldgType"      "HouseStyle"    "RoofStyle"     "RoofMatl"      "Exterior1st"   "Exterior2nd"   "MasVnrType"   
[19] "ExterQual"     "ExterCond"     "Foundation"    "BsmtQual"      "BsmtCond"      "BsmtExposure"  "BsmtFinType1"  "BsmtFinType2"  "Heating"      
[28] "HeatingQC"     "CentralAir"    "Electrical"    "KitchenQual"   "Functional"    "FireplaceQu"   "GarageType"    "GarageFinish"  "GarageQual"   
[37] "GarageCond"    "PavedDrive"    "PoolQC"        "Fence"         "MiscFeature"   "SaleType"      "SaleCondition"
sum(sapply(combine_data[,], typeof) == "character")
[1] 43

Checking numerical columns

Below is a view of all numerical columns found in combined dataset.

names(combine_data)[unlist(lapply(combine_data, is.numeric))]
 [1] "Id"            "MSSubClass"    "LotFrontage"   "LotArea"       "OverallQual"   "OverallCond"   "YearBuilt"     "YearRemodAdd"  "MasVnrArea"   
[10] "BsmtFinSF1"    "BsmtFinSF2"    "BsmtUnfSF"     "TotalBsmtSF"   "X1stFlrSF"     "X2ndFlrSF"     "LowQualFinSF"  "GrLivArea"     "BsmtFullBath" 
[19] "BsmtHalfBath"  "FullBath"      "HalfBath"      "BedroomAbvGr"  "KitchenAbvGr"  "TotRmsAbvGrd"  "Fireplaces"    "GarageYrBlt"   "GarageCars"   
[28] "GarageArea"    "WoodDeckSF"    "OpenPorchSF"   "EnclosedPorch" "X3SsnPorch"    "ScreenPorch"   "PoolArea"      "MiscVal"       "MoSold"       
[37] "YrSold"        "SalePrice"     "log_SalePrice"
sum(sapply(combine_data[,], typeof) != "character")
[1] 39

Distribution Plot of Numerical Variables

#Skewed
#continuous
p1 <-ggplot(data = combine_data, aes(x = LotFrontage)) +
  geom_histogram(fill = "#3B9AB2", bins = 50)  
 

#Definitely needs to be transformed (prob on a log scale)
#continuous
p2 <-ggplot(data = combine_data, aes(x = LotArea)) +
  geom_histogram(fill = "#3B9AB2", bins = 50)  
  
#ordinal
p3<-ggplot(data = combine_data, aes(x = OverallQual)) +
  geom_bar(fill = "#3B9AB2")  


#ordinal
p4<-ggplot(data = combine_data, aes(x = OverallCond)) +
  geom_bar(fill = "#3B9AB2")  


#YearBuilt- negatively skewed, more newer houses (DISCRETE BUT STILL...)
p5<-ggplot(data =combine_data, aes(x = YearBuilt)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#interesting distribution- something weird going on with the 0s here (meaning not remodeled)
#DISCRETE
p6<-ggplot(data = combine_data, aes(x = YearRemodAdd)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#Obviously missing data issue
#continuous
p7<-ggplot(data = combine_data, aes(x = MasVnrArea)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
 

#missing data (0 = no finished basement)
#continuous
p8<-ggplot(data =combine_data, aes(x = BsmtFinSF1)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
  

#same deal w/missing, would need to leave out 0s to see the real dist. here. 
#or do a log transform or whatever. 
#continuous
p9<-ggplot(data = combine_data, aes(x = BsmtFinSF2)) +
  geom_histogram(fill = "#3B9AB2", bins = 30) 


#continuous
p10<-ggplot(data = combine_data, aes(x = BsmtUnfSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
 
#continuous
p11<-ggplot(data = combine_data, aes(x = TotalBsmtSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#continuous
p12<-ggplot(data = combine_data, aes(x = X1stFlrSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#LOTS of missing values here (aka lots of single-story homes)
#continuous
p13<-ggplot(data = combine_data, aes(x = X2ndFlrSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#pointless- on a log scale, or too much missing data
#maybe could set these to not = 0?
#continuous
p14 <-ggplot(data = combine_data, aes(x = LowQualFinSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 10) 


#skewed
#continuous
p15 <-ggplot(data = combine_data, aes(x = GrLivArea)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#discrete
p16<-ggplot(data =combine_data, aes(x = BsmtFullBath)) +
  geom_bar(fill = "#3B9AB2") 


#discrete
p17<-ggplot(data = combine_data, aes(x = BsmtHalfBath)) +
  geom_bar(fill = "#3B9AB2") 


#discrete
p18 <-ggplot(data = combine_data, aes(x = FullBath )) +
  geom_bar(fill = "#3B9AB2") 


#discrete
p19 <-ggplot(data = combine_data, aes(x =HalfBath )) +
  geom_bar(fill = "#3B9AB2") 
 

#discrete
p20 <-ggplot(data = combine_data, aes(x =BedroomAbvGr )) +
  geom_bar(fill = "#3B9AB2") 


#discrete
p21 <-ggplot(data = combine_data, aes(x =KitchenAbvGr )) +
  geom_bar(fill = "#3B9AB2") 
 

#TOTRMSABVGRD
#(discrete)
p22<-ggplot(data = combine_data, aes(x = TotRmsAbvGrd)) +
  geom_bar(fill = "#3B9AB2") 



#FIREPLACES
#(discrete)
p23<-ggplot(data = combine_data, aes(x = Fireplaces)) +
  geom_bar(fill = "#3B9AB2") 


#skewed
#DISCRETE BUT STILL...
p24 <-ggplot(data = combine_data, aes(x = GarageYrBlt)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) + 
  scale_x_continuous(limits = c(1900, 2020))


#(discrete) (this is absurd, clearly should be ordinal??)
p25<-ggplot(data = combine_data, aes(x = GarageCars)) +
  geom_bar(fill = "#3B9AB2") 
 

#0 = no garage
#CONTINUOUS
p26 <-ggplot(data = combine_data, aes(x = GarageArea)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
 

#continuous
p27 <-ggplot(data = combine_data, aes(x = WoodDeckSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
 

#continuous
p28 <-ggplot(data = combine_data, aes(x = OpenPorchSF)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 

 
#continuous
p29 <-ggplot(data = combine_data, aes(x = EnclosedPorch)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
 

#continuous
p30 <-ggplot(data = combine_data, aes(x = X3SsnPorch)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#continuous
p31 <-ggplot(data = combine_data, aes(x = ScreenPorch)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#Continuous
p32 <-ggplot(data = combine_data, aes(x = PoolArea)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 
  

#continuous
p33 <-ggplot(data = combine_data, aes(x = MiscVal)) +
  geom_histogram(fill = "#3B9AB2", bins = 50) 


#MO SOLD?? (DISCRETE) (RECODE)
p34 <-ggplot(data = combine_data, aes(x = MoSold)) +
  geom_bar(fill = "#3B9AB2") 


#YR SOLD (discrete)
p35 <-ggplot(data =combine_data, aes(x = YrSold)) +
  geom_bar(fill = "#3B9AB2") 

grid.arrange(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,
             p12,p13,p14,p15,p16,p17,p18,p19,p20,ncol = 5)

grid.arrange(p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,
             p31,p32,p33,p34,p35,ncol = 4)

From the above plots, it can be noticed that there many numeric variables that are not normally distributed coupled with other variables such as LotFrontage, MasVnrArea and other variables appearing to be skewed due to the presence of outliers.

Distribution Plot of Categorical Variables


b1<-ggplot(data = combine_data, aes(x = MSZoning)) +
  geom_bar(fill = "#3B9AB2") 
 

b2<-ggplot(data = combine_data, aes(x = Street)) +
  geom_bar(fill = "#3B9AB2") 


b3<-ggplot(data = combine_data, aes(x = Alley)) +
  geom_bar(fill = "#3B9AB2") 


b4<-ggplot(data = combine_data, aes(x = LotShape)) +
  geom_bar(fill = "#3B9AB2")  


b5 <-ggplot(data = combine_data, aes(x = LandContour)) +
  geom_bar(fill = "#3B9AB2") 



b6 <-ggplot(data = combine_data, aes(x = Utilities)) +
  geom_bar(fill = "#3B9AB2") #+ 



b7 <-ggplot(data = combine_data, aes(x = LotConfig)) +
  geom_bar(fill = "#3B9AB2") 



b8 <-ggplot(data = combine_data, aes(x = LandSlope)) +
  geom_bar(fill = "#3B9AB2") 



b9<-ggplot(data = combine_data, aes(x = Neighborhood)) +
  geom_bar(fill = "#3B9AB2") + coord_flip() 



b10 <-ggplot(data = combine_data, aes(x = Condition1)) +
  geom_bar(fill = "#3B9AB2") + coord_flip() 


b11 <-ggplot(data = combine_data, aes(x = Condition2)) +
  geom_bar(fill = "#3B9AB2") + coord_flip() 



b12 <-ggplot(data = combine_data, aes(x = BldgType)) +
  geom_bar(fill = "#3B9AB2") 


b13 <-ggplot(data = combine_data, aes(x = HouseStyle)) +
  geom_bar(fill = "#3B9AB2") 



b14 <-ggplot(data = combine_data, aes(x = RoofStyle)) +
  geom_bar(fill = "#3B9AB2") 



b15<-ggplot(data = combine_data, aes(x = RoofMatl)) +
  geom_bar(fill = "#3B9AB2") + coord_flip() 
 


b16 <-ggplot(data = combine_data, aes(x = Exterior1st)) +
  geom_bar(fill = "#3B9AB2") + coord_flip()
  


b17 <-ggplot(data = combine_data, aes(x = Exterior2nd)) +
  geom_bar(fill = "#3B9AB2") + coord_flip() 
 


b18 <-ggplot(data = combine_data, aes(x = MasVnrType)) +
  geom_bar(fill = "#3B9AB2") 



b19 <-ggplot(data = combine_data, aes(x = ExterQual)) +
  geom_bar(fill = "#3B9AB2") 



b20 <-ggplot(data = combine_data, aes(x = ExterCond)) +
  geom_bar(fill = "#3B9AB2") 



b21 <-ggplot(data = combine_data, aes(x = Foundation)) +
  geom_bar(fill = "#3B9AB2") 


b22 <-ggplot(data = combine_data, aes(x = BsmtQual)) +
  geom_bar(fill = "#3B9AB2") 

b23 <-ggplot(data = combine_data, aes(x = BsmtCond)) +
  geom_bar(fill = "#3B9AB2") 
 


b24 <-ggplot(data = combine_data, aes(x = BsmtExposure)) +
  geom_bar(fill = "#3B9AB2") 


b25 <-ggplot(data = combine_data, aes(x = BsmtFinType1)) +
  geom_bar(fill = "#3B9AB2") 
 


b26 <-ggplot(data = combine_data, aes(x = BsmtFinType2)) +
  geom_bar(fill = "#3B9AB2") 
  

b27 <-ggplot(data = combine_data, aes(x = Heating)) +
  geom_bar(fill = "#3B9AB2") 



b28 <-ggplot(data = combine_data, aes(x = HeatingQC)) +
  geom_bar(fill = "#3B9AB2") 


b29 <-ggplot(data =combine_data, aes(x = CentralAir)) +
  geom_bar(fill = "#3B9AB2") 
  


b30 <-ggplot(data = combine_data, aes(x = Electrical)) +
  geom_bar(fill = "#3B9AB2")  


b31 <-ggplot(data = combine_data, aes(x = KitchenQual)) +
  geom_bar(fill = "#3B9AB2") 



b32<-ggplot(data = combine_data, aes(x = Functional)) +
  geom_bar(fill = "#3B9AB2") 



b33<-ggplot(data = combine_data, aes(x = FireplaceQu)) +
  geom_bar(fill = "#3B9AB2") 


b34<-ggplot(data = combine_data, aes(x = GarageType)) +
  geom_bar(fill = "#3B9AB2") 


b35 <-ggplot(data = combine_data, aes(x = GarageFinish)) +
  geom_bar(fill = "#3B9AB2") 



b36 <-ggplot(data = combine_data, aes(x = GarageQual)) +
  geom_bar(fill = "#3B9AB2") 
grid.arrange(b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,ncol = 4)

grid.arrange(b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,ncol = 4)

grid.arrange(b21,b22,b23,b24,b25,b26,b27,b28,b29,b30,b31,b32,b33,b34,b35,b36,ncol = 4)

From the above some categorical variables display evidence of non-normality and (multi)collineraity whiles others variables may be useful features in predicting the target variable. It can also be noted that are significant amount of missing data values.Many of these NA observations are likely to be structurally missing for a logical reason. For instance GarageArea= NA, suggest that the property has no garage. As such missing data will require imputation.

Splitting Data into Numerical and Categorical Variables

For the purpose of visualization, the combined dataset is split into numerical and categorical variables. Also one train dataset with categorical and numeric variable is created

cat_var <- names(combine_data)[which(sapply(combine_data, is.character))]
numeric_var <- names(combine_data)[which(sapply(combine_data, is.numeric))]
train1_cat<-combine_data[cat_var]
train1_num<-combine_data[numeric_var]

Bivariate Plots(numeric)

This section looks at each variable and how they relate to the target variable(salePrice)

# Overall Quality vs Sale Price
# unique(train$OverallQual)
ggplot(train, mapping = aes(x = factor(OverallQual), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

From the above plot, it can be suggested that people are willing to pay more for better quality.

# Living Area vs Sale Price
ggplot(train, mapping = aes(x = GrLivArea, y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

From the above it can be suggested that people are would pay more for living area. However its not reasonable for people to pay less for large area as two data point in the bottom-right of the plot. These two points however needs to be removed.

# Removing outliers manually (The two points in the bottom right)
train = train[train$GrLivArea<=4500,]
ggplot(train, mapping = aes(x = GrLivArea, y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

# Garage Area vs Sale Price
unique(train$GarageCars)
[1] 2 3 1 0 4
ggplot(train, mapping = aes(x = factor(GarageCars), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

The relationship between garagecars and saleprice suggest that 4-car garages result in less sale Price which might be as a result of outliers. These outliers must be removed.

train = train[train$GarageCars < 4, ]
ggplot(train, mapping = aes(x = factor(GarageCars), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

# Garage Area vs Sale Price
ggplot(train, mapping = aes(x = GarageArea , y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

##Again, the two data points at the bottom does not make sense
train = filter(train, GarageArea < 1240)
ggplot(train, mapping = aes(x = GarageArea , y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

# Basement Area vs Sale Price
ggplot(train, mapping = aes(x = TotalBsmtSF , y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

# First Floor Area vs Sale Price
ggplot(train, mapping = aes(x = X1stFlrSF, y = SalePrice)) + geom_point() + geom_smooth(method = "lm",col = "#3B9AB2")

# # ExterQual vs Sale Price
ggplot(train, mapping = aes(x = factor(ExterQual), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

The above plot suggest that, houses with excellent external quality are expensive whereas houses with fair quality material are less expensive.

# ExterQual vs Sale Price
ggplot(train, mapping = aes(x = factor(FullBath), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

From the above plot it is not reasonable that houses with zero full bath are expensive than houses with one full bath.This will be an outlier and must be removed from the data set.

train = train[train$FullBath > 0 , ]
ggplot(train, mapping = aes(x = factor(FullBath), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

#BsmtQual and SalePrice
ggplot(train, mapping = aes(x = factor(BsmtQual), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")

# Total Rooms vs Sale Price
ggplot(train, mapping = aes(x = factor(TotRmsAbvGrd), y = SalePrice)) + geom_boxplot(col = "#3B9AB2")+ scale_y_discrete()

Correlation Matrix

correlations <- cor(na.omit(train1_num[,-1]))
head(correlations, 2)
            MSSubClass LotFrontage    LotArea OverallQual OverallCond  YearBuilt YearRemodAdd MasVnrArea  BsmtFinSF1  BsmtFinSF2  BsmtUnfSF TotalBsmtSF
MSSubClass   1.0000000  -0.3869396 -0.1980955  0.02952186 -0.08785932 0.02579968  0.006645194  0.0402400 -0.07038869 -0.07543900 -0.1455823  -0.2477812
LotFrontage -0.3869396   1.0000000  0.4211841  0.24132232 -0.04631165 0.10972557  0.086413968  0.1899686  0.24135223  0.04930532  0.1153059   0.3876195
             X1stFlrSF X2ndFlrSF LowQualFinSF  GrLivArea BsmtFullBath BsmtHalfBath  FullBath   HalfBath BedroomAbvGr KitchenAbvGr TotRmsAbvGrd  Fireplaces
MSSubClass  -0.2522489 0.3193276   0.02470365 0.08336538   -0.0146813 0.0123095694 0.1312780 0.20397061  -0.03297115  0.266012356   0.04720943 -0.03112223
LotFrontage  0.4510850 0.0750038   0.01114809 0.39630602    0.1180881 0.0004335725 0.1857853 0.04567835   0.27040389 -0.003546472   0.34842111  0.26032083
            GarageYrBlt  GarageCars  GarageArea  WoodDeckSF OpenPorchSF EnclosedPorch  X3SsnPorch ScreenPorch    PoolArea      MiscVal      MoSold
MSSubClass   0.05470137 -0.02741067 -0.09260726 -0.01798842  0.00405397   -0.01778990 -0.03973896 -0.02178934 0.003166468 -0.040688673 -0.02717038
LotFrontage  0.06987812  0.28658681  0.35685094  0.08216563  0.16181512    0.01426101  0.06971577  0.03590598 0.211746117  0.001470738  0.01881453
                 YrSold  SalePrice log_SalePrice
MSSubClass  -0.01244783 -0.0880317   -0.08376839
LotFrontage  0.01326707  0.3442698    0.35361138
melted_correlations = melt(correlations)
head(melted_correlations, 2)


ggplot(data = melted_correlations, aes(x=Var1, y=Var2, fill=value)) +
  geom_tile(color = "white")+
  scale_fill_gradient2(low = "blue", high = "red", mid = "white",
                       midpoint = 0, limit = c(-1,1), space = "Lab",
                       name="Pearson\nCorrelation") +
  theme_minimal()+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.4,
                                   size = 12, hjust = 0.2))+ theme(aspect.ratio = 1) +
  coord_fixed()

The above correlation plot is too clustered, hence lets consider the top 10 correlated variables.

Top 10 correlated variables

corr_cross(train, # name of dataset
           max_pvalue = 0.05, # display only significant correlations (at 5% level)
           top = 10 # display top 10 couples of variables (by correlation coefficient)
)
Returning only the top 10. You may override with the 'top' argument

Top 10 correlated variables with Sale Price

top_10 = corr_var(train, # name of dataset
                  SalePrice, # name of variable to focus on
                  top = 10 # display top 5 correlations
)
top_10

From the above, Blue indicate positive correlation and red indicate negative correlations. ExterQual_TA from the plot negatively correlates with the target variable.

Data Cleaning

Before performing modeling, all variables with missing data are identified and corrected.

test$SalePrice <- NA
train$isTrain <- 1
test$isTrain <- 0
combine_data <-rbind(train,test)
head(combine_data,2)



Missing_indices <- sapply(combine_data,function(x) sum(is.na(x)))/nrow(combine_data)

Missing_Summary <- data.frame(index = names(combine_data),Missing_Values=Missing_indices)

Missing_Summary[order(Missing_Summary$Missing_Values > 0, decreasing = TRUE),]
### percentage of missing cases
sum(is.na(combine_data))/ (dim(combine_data)[1] *dim(combine_data)[2]) *100 
[1] 6.448575
all_data_na = Missing_Summary[order(Missing_Summary$Missing_Values, decreasing = TRUE), ]
all_data_na[1:5, ]

all_data <- combine_data

Inputing Missing Values

From the above variables with missing values are fixed since most of theme are actually not missing.

#Getmode

getmode <- function(v) {
  uniqv <- unique(v)
  uniqv[which.max(tabulate(match(v, uniqv)))]
}
#PoolQC
#Changing NA in PoolQC to None
all_data$PoolQC1 <- as.character(all_data$PoolQC)
all_data$PoolQC1[which(is.na(all_data$PoolQC))] <- "None"
all_data$PoolQC <- as.factor(all_data$PoolQC1)
all_data <- subset(all_data,select = -PoolQC1)
sum(is.na(all_data$PoolQC))
[1] 0
#MiscFeature
all_data$MiscFeature1 <- as.character(all_data$MiscFeature)
all_data$MiscFeature1[which(is.na(all_data$MiscFeature))] <- "None"
all_data$MiscFeature <- as.factor(all_data$MiscFeature1)
all_data <- subset(all_data,select = -MiscFeature1)
sum(is.na(all_data$MiscFeature))
[1] 0
#Alley
all_data$Alley1 <- as.character(all_data$Alley)
all_data$Alley1[which(is.na(all_data$Alley))] <- "None"
all_data$Alley <- as.factor(all_data$Alley1)
all_data <- subset(all_data,select = -Alley1)
sum(is.na(all_data$Alley))
[1] 0
#Fence
all_data$Fence1 <- as.character(all_data$Fence)
all_data$Fence1[which(is.na(all_data$Fence))] <- "None"
all_data$Fence <- as.factor(all_data$Fence1)
all_data <- subset(all_data,select = -Fence1)
sum(is.na(all_data$Fence))
[1] 0
#FireplaceQu
all_data$FireplaceQu1 <- as.character(all_data$FireplaceQu)
all_data$FireplaceQu1[which(is.na(all_data$FireplaceQu))] <- "None"
all_data$FireplaceQu <- as.factor(all_data$FireplaceQu1)
all_data <- subset(all_data,select = -FireplaceQu1)
sum(is.na(all_data$FireplaceQu))
[1] 0
unique(all_data$FireplaceQu)
[1] None TA   Gd   Fa   Ex   Po  
Levels: Ex Fa Gd None Po TA
#LotFrontage
all_data$LotFrontage[which(is.na(all_data$LotFrontage))] <- median(all_data$LotFrontage,na.rm = T)
sum(is.na(all_data$LotFrontage))
[1] 0
#GarageType
all_data$GarageType1 <- as.character(all_data$GarageType)
all_data$GarageType1[which(is.na(all_data$GarageType))] <- "None"
all_data$GarageType <- as.factor(all_data$GarageType1)
all_data <- subset(all_data,select = -GarageType1)
sum(is.na(all_data$GarageType))
[1] 0
#GarageFinish
all_data$GarageFinish1 <- as.character(all_data$GarageFinish)
all_data$GarageFinish1[which(is.na(all_data$GarageFinish))] <- "None"
all_data$GarageFinish <- as.factor(all_data$GarageFinish1)
all_data <- subset(all_data,select = -GarageFinish1)
sum(is.na(all_data$GarageFinish))
[1] 0
#GarageQual
all_data$GarageQual1 <- as.character(all_data$GarageQual)
all_data$GarageQual1[which(is.na(all_data$GarageQual))] <- "None"
all_data$GarageQual <- as.factor(all_data$GarageQual1)
all_data <- subset(all_data,select = -GarageQual1)

#GarageCond
all_data$GarageCond1 <- as.character(all_data$GarageCond)
all_data$GarageCond1[which(is.na(all_data$GarageCond))] <- "None"
all_data$GarageCond <- as.factor(all_data$GarageCond1)
all_data <- subset(all_data,select = -GarageCond1)

unique(all_data$GarageCond)
[1] TA   Fa   None Gd   Po   Ex  
Levels: Ex Fa Gd None Po TA
#GarageYrBlt
all_data$GarageYrBlt[which(is.na(all_data$GarageYrBlt))] <- 0
sum(is.na(all_data$GarageYrBlt))
[1] 0
sum(is.na(all_data$GarageCond))
[1] 0
# head(all_data, 2)
unique(all_data$GarageYrBlt)
  [1] 2003 1976 2001 1998 2000 1993 2004 1973 1931 1939 1965 2005 1962 2006 1960 1991 1970 1967 1958 1930 2002 1968 2007 2008 1957 1920 1966 1959 1995 1954
 [31] 1953    0 1983 1977 1997 1985 1963 1964 1999 1935 1990 1945 1987 1989 1915 1956 1948 1974 2009 1950 1961 1921 1900 1979 1951 1969 1936 1975 1971 1923
 [61] 1984 1926 1955 1981 1986 1988 1916 1932 1972 1918 1980 1924 1996 1940 1949 1994 1910 1978 1982 1992 1925 1941 2010 1927 1947 1937 1942 1938 1952 1928
 [91] 1922 1934 1906 1914 1946 1908 1929 1933 1917 1896 1895 2207 1943 1919
#GarageArea
all_data$GarageArea[which(is.na(all_data$GarageArea))] <- 0
#GarageCars
all_data$GarageCars[which(is.na(all_data$GarageCars))] <- 0
#BsmtFinSF1
all_data$BsmtFinSF1[which(is.na(all_data$BsmtFinSF1))] <- 0
#BsmtFinSF2
all_data$BsmtFinSF2[which(is.na(all_data$BsmtFinSF2))] <- 0
#BsmtUnfSF
all_data$BsmtUnfSF[which(is.na(all_data$BsmtUnfSF))] <- 0
#TotalBsmtSF
all_data$TotalBsmtSF[which(is.na(all_data$TotalBsmtSF))] <- 0
#BsmtFullBath
all_data$BsmtFullBath[which(is.na(all_data$BsmtFullBath))] <- 0
#BsmtHalfBath
all_data$BsmtHalfBath[which(is.na(all_data$BsmtHalfBath))] <- 0
#BsmtQual
all_data$BsmtQual1 <- as.character(all_data$BsmtQual)
all_data$BsmtQual1[which(is.na(all_data$BsmtQual))] <- "None"
all_data$BsmtQual <- as.factor(all_data$BsmtQual1)
all_data <- subset(all_data,select = -BsmtQual1)
#BsmtCond
all_data$BsmtCond1 <- as.character(all_data$BsmtCond)
all_data$BsmtCond1[which(is.na(all_data$BsmtCond))] <- "None"
all_data$BsmtCond <- as.factor(all_data$BsmtCond1)
all_data <- subset(all_data,select = -BsmtCond1)

#BsmtExposure
all_data$BsmtExposure1 <- as.character(all_data$BsmtExposure)
all_data$BsmtExposure1[which(is.na(all_data$BsmtExposure))] <- "None"
all_data$BsmtExposure <- as.factor(all_data$BsmtExposure1)
all_data <- subset(all_data, select = -BsmtExposure1)

#BsmtFinType1
all_data$BsmtFinType11 <- as.character(all_data$BsmtFinType1)
all_data$BsmtFinType11[which(is.na(all_data$BsmtFinType1))] <- "None"
all_data$BsmtFinType1 <- as.factor(all_data$BsmtFinType11)
all_data <- subset(all_data,select = -BsmtFinType11)

#BsmtFinType2
all_data$BsmtFinType21 <- as.character(all_data$BsmtFinType2)
all_data$BsmtFinType21[which(is.na(all_data$BsmtFinType2))] <- "None"
all_data$BsmtFinType2 <- as.factor(all_data$BsmtFinType21)
all_data <- subset(all_data,select = -BsmtFinType21)
#MasVnrType

all_data$MasVnrType1 <- as.character(all_data$MasVnrType)
all_data$MasVnrType1[which(is.na(all_data$MasVnrType))] <- "None"
all_data$MasVnrType <- as.factor(all_data$MasVnrType1)
all_data <- subset(all_data,select = -MasVnrType1)

#MasVnrArea
all_data$MasVnrArea[which(is.na(all_data$MasVnrArea))] <- 0

#MSZoning
all_data$MSZoning1 <- as.character(all_data$MSZoning)
all_data$MSZoning1[which(is.na(all_data$MSZoning))] <- getmode(all_data$MSZoning)
all_data$MSZoning <- as.factor(all_data$MSZoning1)
all_data <- subset(all_data,select = -MSZoning1)


#Utilities We can safely drop this feature since most of the observations are “AllPub”, 1 is “NoSewa”, and 2 “NA”
unique(all_data$Utilities)
[1] "AllPub" "NoSeWa" NA      
## [1] "AllPub" "NoSeWa" NA
table(all_data$Utilities)

AllPub NoSeWa 
  2898      1 
all_data$Utilities = NULL

#Functional
all_data$Functional1 <- as.character(all_data$Functional)
all_data$Functional1[which(is.na(all_data$Functional))] <- "Typ"
all_data$Functional <- as.factor(all_data$Functional1)
all_data <- subset(all_data,select = -Functional1)
#table(all_data$Functional)

#Electrical
all_data$Electrical1 <- as.character(all_data$Electrical)
all_data$Electrical1[which(is.na(all_data$Electrical))] <- getmode(all_data$Electrical)
all_data$Electrical <- as.factor(all_data$Electrical1)
all_data <- subset(all_data,select = -Electrical1)

#KitchenQual
all_data$KitchenQual1 <- as.character(all_data$KitchenQual)
all_data$KitchenQual1[which(is.na(all_data$KitchenQual))] <- getmode(all_data$KitchenQual)
all_data$KitchenQual <- as.factor(all_data$KitchenQual1)
all_data <- subset(all_data,select = -KitchenQual1)

#Exterior1st
all_data$Exterior1st1 <- as.character(all_data$Exterior1st)
all_data$Exterior1st1[which(is.na(all_data$Exterior1st))] <- getmode(all_data$Exterior1st)
all_data$Exterior1st <- as.factor(all_data$Exterior1st1)
all_data <- subset(all_data,select = -Exterior1st1)

#Exterior2nd
all_data$Exterior2nd1 <- as.character(all_data$Exterior2nd)
all_data$Exterior2nd1[which(is.na(all_data$Exterior2nd))] <- getmode(all_data$Exterior2nd)
all_data$Exterior2nd <- as.factor(all_data$Exterior2nd1)
all_data <- subset(all_data,select = -Exterior2nd1)

#SaleType
all_data$SaleType1 <- as.character(all_data$SaleType)
all_data$SaleType1[which(is.na(all_data$SaleType))] <- getmode(all_data$SaleType)
all_data$SaleType <- as.factor(all_data$SaleType1)
all_data <- subset(all_data,select = -SaleType1)
head(all_data,2)

Converting to Factors

all_data$Street = factor(all_data$Street)
all_data$LotShape = factor(all_data$LotShape)
all_data$LandContour = factor(all_data$LandContour)
all_data$LotConfig = factor(all_data$LotConfig)
all_data$LandSlope = factor(all_data$LandSlope)
all_data$Neighborhood = factor(all_data$Neighborhood)
all_data$Condition1 = factor(all_data$Condition1)
all_data$Condition2 = factor(all_data$Condition2)
all_data$BldgType = factor(all_data$BldgType)
all_data$HouseStyle = factor(all_data$HouseStyle)
all_data$OverallQual = factor(all_data$OverallQual)
all_data$OverallCond = factor(all_data$OverallCond)
all_data$YearBuilt = as.character((all_data$YearBuilt))
all_data$GarageYrBlt = as.character((all_data$GarageYrBlt))
all_data$YearRemodAdd = as.character(all_data$YearRemodAdd)
all_data$RoofStyle = factor(all_data$RoofStyle)
all_data$RoofMatl = factor(all_data$RoofMatl)
all_data$ExterQual = factor(all_data$ExterQual)
all_data$ExterCond = factor(all_data$ExterCond)
all_data$MSSubClass = factor(all_data$MSSubClass)
all_data$Foundation = factor(all_data$Foundation)
all_data$Heating = factor(all_data$Heating)
all_data$HeatingQC = factor(all_data$HeatingQC)
all_data$CentralAir = factor(all_data$CentralAir)
all_data$PavedDrive = factor(all_data$PavedDrive)
all_data$MoSold = factor(all_data$MoSold)
all_data$YrSold = factor(all_data$YrSold)
all_data$SaleCondition = factor(all_data$SaleCondition)
all_data$BsmtFullBath = factor(all_data$BsmtFullBath)
all_data$BsmtHalfBath = factor(all_data$BsmtHalfBath)
all_data$FullBath = factor(all_data$FullBath)
all_data$HalfBath = factor(all_data$HalfBath)
head(all_data, 2)
#Determining skew of each numeric variable

Column_classes <- sapply(names(all_data),function(x){class(all_data[[x]])})
numeric_columns <-names(Column_classes[Column_classes != "factor" & Column_classes != "character"])

skew <- sapply(numeric_columns,function(x){skewness(all_data[[x]],na.rm = T)})
# Let us determine a threshold skewness and transform all variables above the treshold.
skew <- skew[skew > 0.75]
# transform excessively skewed features with log(x + 1)
for(x in names(skew))
{
  all_data[[x]] <- log(all_data[[x]] + 1)
}
ggplot(all_data, mapping = aes(x = SalePrice)) + geom_histogram(color = "black", fill = "blue")

Feature Engineering

Here it can be suggested that total basement surface area, 1st floor surface area and 2nd floor surface area can be equated to total surface area. Based on this TotalSF is created.

#linear relationship b/n ground and upper floors
all_data$TotalSF = all_data$TotalBsmtSF + all_data$X1stFlrSF + all_data$X2ndFlrSF

#all_data <-subset(all_data, select = -c(log_SalePrice))
which(colSums(is.na(all_data))>0)
SalePrice 
       80 
dim(all_data)
[1] 2901   82

Data Partition

train_1 <- all_data[all_data$isTrain==1,]
test_1 <- all_data[all_data$isTrain==0,]
dim(train_1)
[1] 1442   82
dim(test_1)
[1] 1459   82
dim(all_data)
[1] 2901   82
train_1 = subset(train_1, select = -c(Id, isTrain))
test_1 = subset(test_1, select = -c(Id, isTrain, SalePrice))
set.seed(100)
partition <- createDataPartition(train_1$SalePrice, p = 0.80, list = FALSE)
train.m <- train_1[partition, ]
test.m <- train_1[-partition, ]

head(train.m, 3)

Modeling

RandomForest Model

###FULL MODEL ###
model1 = randomForest(SalePrice ~ ., data = train.m)
summary(model1)
                Length Class  Mode     
call               3   -none- call     
type               1   -none- character
predicted       1155   -none- numeric  
mse              500   -none- numeric  
rsq              500   -none- numeric  
oob.times       1155   -none- numeric  
importance        79   -none- numeric  
importanceSD       0   -none- NULL     
localImportance    0   -none- NULL     
proximity          0   -none- NULL     
ntree              1   -none- numeric  
mtry               1   -none- numeric  
forest            11   -none- list     
coefs              0   -none- NULL     
y               1155   -none- numeric  
test               0   -none- NULL     
inbag              0   -none- NULL     
terms              3   terms  call     

RF Model Plot

plot(model1)

Variable Importance

imp = importance(model1)
imp
              IncNodePurity
MSSubClass      3.149091652
MSZoning        1.110581653
LotFrontage     0.682229113
LotArea         2.288074115
Street          0.019590196
Alley           0.149008333
LotShape        0.175011443
LandContour     0.157752933
LotConfig       0.126068901
LandSlope       0.159013064
Neighborhood   22.184734180
Condition1      0.132893897
Condition2      0.009086202
BldgType        0.150736037
HouseStyle      0.359474363
OverallQual    40.360696664
OverallCond     0.945470293
YearBuilt       6.505207497
YearRemodAdd    1.142558284
RoofStyle       0.173775477
RoofMatl        0.025706225
Exterior1st     0.896598040
Exterior2nd     0.986840753
MasVnrType      0.121627340
MasVnrArea      0.381078051
ExterQual      11.813144281
ExterCond       0.264751537
Foundation      0.144461509
BsmtQual        3.123396609
BsmtCond        0.163381763
BsmtExposure    0.353701095
BsmtFinType1    0.956226487
BsmtFinSF1      1.773458995
BsmtFinType2    0.207345659
BsmtFinSF2      0.081145774
BsmtUnfSF       0.592320119
TotalBsmtSF     4.056414420
Heating         0.030625280
HeatingQC       0.241954812
CentralAir      0.394723268
Electrical      0.098157843
X1stFlrSF       4.811371727
X2ndFlrSF       1.594500473
LowQualFinSF    0.026265876
GrLivArea      20.177404091
BsmtFullBath    0.185131635
BsmtHalfBath    0.026164667
FullBath        3.595580973
HalfBath        0.187422288
BedroomAbvGr    0.286169709
KitchenAbvGr    0.068327509
KitchenQual     3.086390979
TotRmsAbvGrd    0.850242086
Functional      0.153525048
Fireplaces      0.792973180
FireplaceQu     1.813495808
GarageType      2.373585373
GarageYrBlt     2.228938668
GarageFinish    1.337870492
GarageCars      5.218971747
GarageArea      5.461616387
GarageQual      0.335461870
GarageCond      0.812706770
PavedDrive      0.186963858
WoodDeckSF      0.335663339
OpenPorchSF     0.688378240
EnclosedPorch   0.209572910
X3SsnPorch      0.019876516
ScreenPorch     0.091972942
PoolArea        0.003518593
PoolQC          0.005986523
Fence           0.129436614
MiscFeature     0.021427048
MiscVal         0.030886911
MoSold          1.909772661
YrSold          0.486792859
SaleType        0.113243862
SaleCondition   0.362717834
TotalSF         5.234178681

Plot of Variable Importance

varImpPlot(model1)

# RMSE of full model using log of SalePrice
RMSE(test.m$SalePrice, predict(model1, newdata = test.m))
[1] 0.1617629

Prediction with the full model

pred = predict(model1, newdata = test.m)
df = data.frame(Pred = exp(pred), Test = exp(test.m$SalePrice))

Prediction VS Actual

head(df, 5)

RMSE of the full model using SalePrice

sqrt( mean( (exp(pred)-exp(test.m$SalePrice)) ^2) )
[1] 32233.15

Reduced Model

train.rf = train.m
model.select.rf = randomForest(SalePrice ~ TotalSF + MSZoning + LotArea + LotShape + Neighborhood + Condition1 +Condition2+
                                 BldgType +  OverallQual +OverallCond + YearBuilt + RoofMatl + Exterior1st + ExterCond+
                                 Foundation +BsmtQual+ KitchenQual+FullBath+BsmtExposure+Fireplaces+ SaleCondition+
                                 CentralAir+PavedDrive,data = train.rf)  
summary(model.select.rf)
                Length Class  Mode     
call               3   -none- call     
type               1   -none- character
predicted       1155   -none- numeric  
mse              500   -none- numeric  
rsq              500   -none- numeric  
oob.times       1155   -none- numeric  
importance        23   -none- numeric  
importanceSD       0   -none- NULL     
localImportance    0   -none- NULL     
proximity          0   -none- NULL     
ntree              1   -none- numeric  
mtry               1   -none- numeric  
forest            11   -none- list     
coefs              0   -none- NULL     
y               1155   -none- numeric  
test               0   -none- NULL     
inbag              0   -none- NULL     
terms              3   terms  call     
###model plot
plot(model.select.rf)

variable of importance Reduced Model

imp = importance(model.select.rf)
imp
              IncNodePurity
TotalSF         14.98225966
MSZoning         2.11368832
LotArea         10.07284516
LotShape         0.91405716
Neighborhood    30.33837965
Condition1       0.75819870
Condition2       0.07793706
BldgType         1.09039790
OverallQual     44.97055960
OverallCond      2.69011137
YearBuilt       16.10910241
RoofMatl         0.21277160
Exterior1st      3.69241605
ExterCond        0.71684523
Foundation       2.00885548
BsmtQual         7.51937808
KitchenQual     11.26561590
FullBath        10.38556873
BsmtExposure     1.67606403
Fireplaces       5.93462656
SaleCondition    1.37223695
CentralAir       1.06931075
PavedDrive       0.92066421

Plot of Variable of Importance

varImpPlot(model.select.rf)

RMSE of the Reduced model using log of SalePrice

RMSE(test.m$SalePrice, predict(model.select.rf, newdata = test.m))
[1] 0.1831383

Prediction vs Actual

#####Prediction with the reduced model###
pred = predict(model.select.rf, newdata = test.m)

########
df = data.frame(Pred = exp(pred), Test = exp(test.m$SalePrice))
head(df, 5)

RMSE of the Reduced model using SalePrice

pred = predict(model.select.rf, newdata = test.m)


sqrt( mean( (exp(pred)-exp(test.m$SalePrice)) ^2) )
[1] 39366.59

Given the RMSE of the full model and the Reduce model,it can be suggested that the full model returns a lower RMSE when compared to the reduced model, hence will cost less to deploy.

LS0tDQp0aXRsZTogIkthZ2dsZSBQcm9qZWN0OiBQcmVkaWN0aW5nIEFtZXMgSG91c2UgUHJpY2VzIg0KYXV0aG9yOiAiQ2hhcmxlcyBXaXJlZHUiDQpkYXRlOiAiMjAyMi0xMC0xOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgQmFja2dyb3VuZA0KDQpJbiBvcmRlciB0byBwdXQgbmV3bHkgYWNxdWlyZWQgZGF0YSBzY2llbmNlIHNraWxscyB0byB0ZXN0LCBsIGRlY2lkZWQgdG8gZXhwbG9yZSB0aGUgd2VsbC1rbm93biBkYXRhc2V0IEFtZXMgSG91c2luZyBkYXRhc2V0LiBUaGUgQW1lcyBkYXRhc2V0IHVzZWQgaW4gdGhpcyBpbnN0YW5jZSBkb2N1bWVudHMgMjAwNi0yMDEwIGRhdGEgcmVjb3JkcyBkZXNjcmliaW5nIHRoZSBzYWxlIG9mIGluZGl2aWR1YWwgcmVzaWRlbnRpYWwgcHJvcGVydHkgaW4gQW1lcywgSW93YS4gVGhlIEFtZXMgSG91c2luZyBEYXRhc2V0IHdhcyBjb21wbGllZCBieSBEZWFuIERlIENvY2sgZm9yIHVzZSBpbiBkYXRhIHNjaWVuY2UgZWR1Y2F0aW9uIGFuZCBwdWJsaWNseSBhdmFpbGFibGUgYXMgYSBjb21wZXRpdGlvbiBob3N0ZWQgIG9uIEthZ2dsZS5jb20saW4gd2hpY2ggdGhlIGdvYWwgaXMgdG8gYnVpbGQgYSBtb2RlbCB0byBwcmVkaWN0IHNhbGUgcHJpY2VzIG9mIGhvdXNlcyBzb2xkIGluIEFtZXMsIElvd2EgLiBXaXRoIDc5IGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBkZXNjcmliaW5nIChhbG1vc3QpIGV2ZXJ5IGFzcGVjdCBvZiByZXNpZGVudGlhbCBob21lcyBpbiBBbWVzLCBJb3dhLCB0aGlzIGRhdGFzZXQgY2hhbGxlbmdlcyBtZSB0byBwcmVkaWN0IHRoZSBmaW5hbCBwcmljZSBvZiBlYWNoIGhvbWUuVGhlIGRhdGEgc2V0IGNvbnRhaW5zIDI5MzAgb2JzZXJ2YXRpb25zIGFuZCBhIGxhcmdlIG51bWJlciBvZiBleHBsYW5hdG9yeSB2YXJpYWJsZXMgKDIzIG5vbWluYWwsIDIzIG9yZGluYWwsIDE0IGRpc2NyZXRlLCBhbmQgMjAgY29udGludW91cykgaW52b2x2ZWQgaW4gYXNzZXNzaW5nIGhvbWUgdmFsdWVzLg0KDQpLYWdnbGUgcHJvdmlkZXMgMiBkYXRhZmlsZXMsIG9uZSBpcyBhIHRyYWluaW5nIHNldCBjb250YWluaW5nIGFsbCA4MSB2YXJpYWJsZXMsIGFuZCB0aGUgb3RoZXIgaXMgYSB0ZXN0IHNldCwgd2hpY2ggaXMgbWlzc2luZyB0aGUgU2FsZVByaWNlIGNvbHVtbi4NCg0KIyMgUmVxdWlyZWQgTGlicmFyaWVzDQpCZWxvdyBhcmUgcmVxdWlyZWQgbGlicmFyaWVzIHRoYXQgYXJlIGVtcGxveWVkIGF0IHZhcmlvdXMgc3RhZ2VzIHRocm91Z2hvdXQgdGhlIG1vZGVsbGluZyBwcm9jZXNzIGFuZCBhbHNvICB0byBwb3NzaWJseSBhbGxvdyBmb3IgdGhlIHJ1bm5pbmcgb2YgdGhpcyBub3RlYm9vay4NCmBgYHtyfQ0KbGlicmFyeSgnZ2dwbG90MicpDQpsaWJyYXJ5KCdnZ3RoZW1lcycpDQpsaWJyYXJ5KCdzY2FsZXMnKQ0KbGlicmFyeSgnZHBseXInKQ0KbGlicmFyeSgnbWljZScpDQpsaWJyYXJ5KCdyYW5kb21Gb3Jlc3QnKQ0KbGlicmFyeSgnZGF0YS50YWJsZScpDQpsaWJyYXJ5KCdncmlkRXh0cmEnKQ0KbGlicmFyeSgnY29ycnBsb3QnKQ0KbGlicmFyeSgnR0dhbGx5JykNCmxpYnJhcnkoJ2UxMDcxJykNCmxpYnJhcnkoJ3Jlc2hhcGUyJykNCmxpYnJhcnkoJ2xhcmVzJykNCmxpYnJhcnkoJ2dibScpDQpsaWJyYXJ5KCdNQVNTJykNCmxpYnJhcnkoJ2NhcmV0JykNCmxpYnJhcnkoJ3NraW1yJykNCmBgYA0KDQojIExvYWRpbmcgb2YgRGF0YXNldA0KVGhlIHR3byBkYXRhIGZpbGVzIHNhdmVkIG9uIG15IGNvbXB1dGVyIGFyZSBsb2FkZWQgaW50byBSIGZvciB0aGUgcHVycG9zZSBvZiBmdXJ0aGVyIGFuYWx5c2lzLg0KYGBge3J9DQp0cmFpbiA9IHJlYWQuY3N2KCJ0cmFpbl9yZWdfZmVhdHVyZXMtMS5jc3YiKQ0KI1RyYWluIGRhdGEgZGltZW5zaW9uDQpkaW0odHJhaW4pDQp0ZXN0ID0gcmVhZC5jc3YoInRlc3RfcmVnX2ZlYXR1cmVzLTEuY3N2IikNCiN0ZXN0IGRhdGEgZGltZW5zaW9uDQpkaW0odGVzdCkNCmBgYA0KDQojIEV4cGxvcmF0b3JhdG9yeSBEYXRhIEFuYWx5c2lzDQpGb3IgdGhlIHB1cnBvc2Ugb2YgZXhwbG9yYXRvcnkgYW5hbHlzaXMgLCB0aGUgdGVzdCBhbmQgdHJhaW4gZGF0YSBzZXQgYXJlIGNvbWJpbmVkIGZvciB0aGUgcHVwb3NlIG9mIGNsZWFuaW5nIGFuZCBhbmFseXNpcy4gVGhlIGhvd2V2ZXIgYWxsb3dzIG1lIHRvIHByZXZpZXcgdGhlIGVudGlyZShjb21iaW5lZCkgZGF0YXNldC5UaGUgY29tYmluZWQgZGF0YXNldCB3aWxsIGJlIGxhdGVyIHNlcGFyYXRlZCB0byBwcmV2ZW50IGRhdGEgbGVha2FnZSBhbmQgcmVwZXRpdGlvbiBkdXJpbmcgbW9kZWxsaW5nLiBUaGUgY29tYmluZWQgZGF0YXNzZXQgY29udGFpbnMgMjkxOSBvYnNlcnZhdGlvbnMgY291cGxlZCB3aXRoIDgxIHZhcmlhYmxlcy4gVGhlIHRyYWluaW5nIGFuZCB0ZXN0aW5nIGRhdGEgcmVwb3J0cyBvZiAxNDYwIGFuZCAxNDU5IG9ic2VydmF0aW9ucyByZXNwZWN0aXZlbHkuDQpgYGB7cn0NCnRlc3QkU2FsZVByaWNlIDwtTkEgDQoNCiNCaW5kIHRoZSB0cmFpbiBhbmQgdGVzdCBkYXRhc2V0cyBmb3IgRURBL2NsZWFuaW5nDQpjb21iaW5lX2RhdGEgPC1yYmluZCh0cmFpbix0ZXN0KQ0KYGBgDQoNCmBgYHtyfQ0Kc3RyKGNvbWJpbmVfZGF0YSkNCmBgYA0KDQpGcm9tIHRoZSBhYm92ZSBpdCBjYW4gYmUgb2JzZXJ2ZWQgdGhhdCBhbGwgdmFyaWFibGVzIGFyZSBlaXRoZXIgY2xhc3MgY2hhcmFjdGVyIG9yIGludGVnZXIsIGFzIHN1Y2ggbW9zdCBvZiB0aGVtIG5lZWRzIHRvIGJlIHJlY29kZWQgYXMgbnVtZXJpYyBvciBmYWN0b3IuIFRoZSBwcm9qZWN0IGRvY3VtZW50YXRpb24gc3VnZ2VzdCB0aGF0IHRoZXJlIGFyZSAyMyBvcmRpbmFsLCAyMyBub21pbmFsLCAxNCBkaXNjcmV0ZSBhbmQgMjAgY29udGludW91cyB2YXJpYWJsZXMuDQpgYGB7cn0NCnRhYmxlKHNhcHBseShjb21iaW5lX2RhdGEsIGNsYXNzKSkNCmBgYA0KIyMgVGFyZ2V0IFZhcmlhYmxlIERpc3RyaWJ1dGlvbg0KQmVsb3cgaXMgYSB2aXN1YWxpemF0aW9uIG9mIHRoZSB0YXJnZXQgdmFyaWFibGUsIHdoaWNoIGlzIGRlbW9uc3RyYXRlZCB1c2luZyBhIGhpc3RvZ3JhbSBhbmQgYSBkZW5zaXR5IHBsb3QuVGhlIGluaXRpYWwgcGxvdCBvZiB0aGUgdGFyZ2V0IHZhcmlhYmxlIHN1Z2dlc3QgdGhhdCBpdCBpcyBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIGhlbmNlIG5lZWRzIHRvIGJlIGNvcnJlY3RlZC5UaGUgc2tld25lc3MgYW5kIGt1cnRvc2lzIGFzIHJlcG9ydGVkIGFyZSAxLjg3OTAwOSBhbmQgNi40NDk2Nzg5IHJlc3BlY3RpdmVseS4NCmBgYHtyfQ0KIyMgU3VtbWFyeSBvZiBUYXJnZXQgVmFyaWFibGUNCnN1bW1hcnkoY29tYmluZV9kYXRhJFNhbGVQcmljZSkNCg0KIyNjaGVja2luZyBza2V3bmVzcyBhbmQga3VydG9zaXMNCnNrZXduZXNzKHRyYWluJFNhbGVQcmljZSkNCmt1cnRvc2lzKHRyYWluJFNhbGVQcmljZSkNCmBgYA0KYGBge3J9DQojIyMgVmlzdWFsIHZpZXcgb2YgdGFyZ2V0IHZhcmlhYmxlDQpnZ3Bsb3QoY29tYmluZV9kYXRhLCBtYXBwaW5nID0gYWVzKHggPSBTYWxlUHJpY2UpKSArIGdlb21faGlzdG9ncmFtKGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJsaWdodGJsdWUiKQ0KYGBgDQoNCiMjIE5vcm1hbGl6YXRpb24gb2YgdGFyZ2V0IHZhcmlhYmxlDQpUYXJnZXQgdmFyaWFibGUoU2FsZVByaWNlKSBhZnRlciBwZXJmb3JtaW5nIGxvZyB0cmFuc2Zvcm1hdGlvbiwgbG9va3MgbXVjaCBtb3JlIG5vcm1hbC4NCmBgYHtyfQ0KY29tYmluZV9kYXRhJGxvZ19TYWxlUHJpY2UgPC1sb2coY29tYmluZV9kYXRhJFNhbGVQcmljZSkNCg0KZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gbG9nX1NhbGVQcmljZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sID0gIiNFMUFGMDAiLCBmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApICArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDgwMDAwMCwgYnkgPSAxMDAwMDApLCBsYWJlbHMgPSBjb21tYSkgKw0KICBsYWJzKHRpdGxlID0gIkhvdXNpbmcgRGF0YTogTG9nKFNhbGUgUHJpY2UpIiwgeCA9ICJMb2coU2FsZSBQcmljZSkiKQ0KYGBgDQojIyBDaGVja2luZyBjYXRlZ29yaWNhbCBjb2x1bW5zDQpCZWxvdyBpcyBhIGNoZWNrIG9uIGNhdGVnb3JpY2FsIGNvbHVtbnMgaW4gdGhlIGNvbWJpbmVkIGRhdGFzZXQuDQpgYGB7cn0NCg0KbmFtZXMoY29tYmluZV9kYXRhKVtzYXBwbHkoY29tYmluZV9kYXRhLCB0eXBlb2YpID09ICJjaGFyYWN0ZXIiXQ0Kc3VtKHNhcHBseShjb21iaW5lX2RhdGFbLF0sIHR5cGVvZikgPT0gImNoYXJhY3RlciIpDQoNCmBgYA0KIyMgQ2hlY2tpbmcgbnVtZXJpY2FsIGNvbHVtbnMNCkJlbG93IGlzIGEgdmlldyBvZiBhbGwgbnVtZXJpY2FsIGNvbHVtbnMgZm91bmQgaW4gY29tYmluZWQgZGF0YXNldC4NCmBgYHtyfQ0KbmFtZXMoY29tYmluZV9kYXRhKVt1bmxpc3QobGFwcGx5KGNvbWJpbmVfZGF0YSwgaXMubnVtZXJpYykpXQ0Kc3VtKHNhcHBseShjb21iaW5lX2RhdGFbLF0sIHR5cGVvZikgIT0gImNoYXJhY3RlciIpDQpgYGANCg0KIyMgRGlzdHJpYnV0aW9uIFBsb3Qgb2YgTnVtZXJpY2FsIFZhcmlhYmxlcw0KYGBge3J9DQojU2tld2VkDQojY29udGludW91cw0KcDEgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBMb3RGcm9udGFnZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSAgDQogDQoNCiNEZWZpbml0ZWx5IG5lZWRzIHRvIGJlIHRyYW5zZm9ybWVkIChwcm9iIG9uIGEgbG9nIHNjYWxlKQ0KI2NvbnRpbnVvdXMNCnAyIDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gTG90QXJlYSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSAgDQogIA0KI29yZGluYWwNCnAzPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBPdmVyYWxsUXVhbCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgIA0KDQoNCiNvcmRpbmFsDQpwNDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gT3ZlcmFsbENvbmQpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpICANCg0KDQojWWVhckJ1aWx0LSBuZWdhdGl2ZWx5IHNrZXdlZCwgbW9yZSBuZXdlciBob3VzZXMgKERJU0NSRVRFIEJVVCBTVElMTC4uLikNCnA1PC1nZ3Bsb3QoZGF0YSA9Y29tYmluZV9kYXRhLCBhZXMoeCA9IFllYXJCdWlsdCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCg0KDQojaW50ZXJlc3RpbmcgZGlzdHJpYnV0aW9uLSBzb21ldGhpbmcgd2VpcmQgZ29pbmcgb24gd2l0aCB0aGUgMHMgaGVyZSAobWVhbmluZyBub3QgcmVtb2RlbGVkKQ0KI0RJU0NSRVRFDQpwNjwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gWWVhclJlbW9kQWRkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQoNCiNPYnZpb3VzbHkgbWlzc2luZyBkYXRhIGlzc3VlDQojY29udGludW91cw0KcDc8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IE1hc1ZuckFyZWEpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiIzNCOUFCMiIsIGJpbnMgPSA1MCkgDQogDQoNCiNtaXNzaW5nIGRhdGEgKDAgPSBubyBmaW5pc2hlZCBiYXNlbWVudCkNCiNjb250aW51b3VzDQpwODwtZ2dwbG90KGRhdGEgPWNvbWJpbmVfZGF0YSwgYWVzKHggPSBCc210RmluU0YxKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KICANCg0KI3NhbWUgZGVhbCB3L21pc3NpbmcsIHdvdWxkIG5lZWQgdG8gbGVhdmUgb3V0IDBzIHRvIHNlZSB0aGUgcmVhbCBkaXN0LiBoZXJlLiANCiNvciBkbyBhIGxvZyB0cmFuc2Zvcm0gb3Igd2hhdGV2ZXIuIA0KI2NvbnRpbnVvdXMNCnA5PC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBCc210RmluU0YyKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gMzApIA0KDQoNCiNjb250aW51b3VzDQpwMTA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEJzbXRVbmZTRikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCiANCiNjb250aW51b3VzDQpwMTE8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFRvdGFsQnNtdFNGKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQoNCiNjb250aW51b3VzDQpwMTI8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFgxc3RGbHJTRikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCg0KDQojTE9UUyBvZiBtaXNzaW5nIHZhbHVlcyBoZXJlIChha2EgbG90cyBvZiBzaW5nbGUtc3RvcnkgaG9tZXMpDQojY29udGludW91cw0KcDEzPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBYMm5kRmxyU0YpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiIzNCOUFCMiIsIGJpbnMgPSA1MCkgDQoNCg0KI3BvaW50bGVzcy0gb24gYSBsb2cgc2NhbGUsIG9yIHRvbyBtdWNoIG1pc3NpbmcgZGF0YQ0KI21heWJlIGNvdWxkIHNldCB0aGVzZSB0byBub3QgPSAwPw0KI2NvbnRpbnVvdXMNCnAxNCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IExvd1F1YWxGaW5TRikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDEwKSANCg0KDQojc2tld2VkDQojY29udGludW91cw0KcDE1IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gR3JMaXZBcmVhKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQoNCiNkaXNjcmV0ZQ0KcDE2PC1nZ3Bsb3QoZGF0YSA9Y29tYmluZV9kYXRhLCBhZXMoeCA9IEJzbXRGdWxsQmF0aCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KI2Rpc2NyZXRlDQpwMTc8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEJzbXRIYWxmQmF0aCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KI2Rpc2NyZXRlDQpwMTggPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBGdWxsQmF0aCApKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCiNkaXNjcmV0ZQ0KcDE5IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID1IYWxmQmF0aCApKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KIA0KDQojZGlzY3JldGUNCnAyMCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9QmVkcm9vbUFidkdyICkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KI2Rpc2NyZXRlDQpwMjEgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPUtpdGNoZW5BYnZHciApKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KIA0KDQojVE9UUk1TQUJWR1JEDQojKGRpc2NyZXRlKQ0KcDIyPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBUb3RSbXNBYnZHcmQpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KI0ZJUkVQTEFDRVMNCiMoZGlzY3JldGUpDQpwMjM8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEZpcmVwbGFjZXMpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCiNza2V3ZWQNCiNESVNDUkVURSBCVVQgU1RJTEwuLi4NCnAyNCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEdhcmFnZVlyQmx0KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApICsgDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5MDAsIDIwMjApKQ0KDQoNCiMoZGlzY3JldGUpICh0aGlzIGlzIGFic3VyZCwgY2xlYXJseSBzaG91bGQgYmUgb3JkaW5hbD8/KQ0KcDI1PC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBHYXJhZ2VDYXJzKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCiANCg0KIzAgPSBubyBnYXJhZ2UNCiNDT05USU5VT1VTDQpwMjYgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBHYXJhZ2VBcmVhKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KIA0KDQojY29udGludW91cw0KcDI3IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gV29vZERlY2tTRikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCiANCg0KI2NvbnRpbnVvdXMNCnAyOCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IE9wZW5Qb3JjaFNGKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQogDQojY29udGludW91cw0KcDI5IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gRW5jbG9zZWRQb3JjaCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCiANCg0KI2NvbnRpbnVvdXMNCnAzMCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFgzU3NuUG9yY2gpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiIzNCOUFCMiIsIGJpbnMgPSA1MCkgDQoNCg0KI2NvbnRpbnVvdXMNCnAzMSA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFNjcmVlblBvcmNoKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQoNCiNDb250aW51b3VzDQpwMzIgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBQb29sQXJlYSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICIjM0I5QUIyIiwgYmlucyA9IDUwKSANCiAgDQoNCiNjb250aW51b3VzDQpwMzMgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBNaXNjVmFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMzQjlBQjIiLCBiaW5zID0gNTApIA0KDQoNCiNNTyBTT0xEPz8gKERJU0NSRVRFKSAoUkVDT0RFKQ0KcDM0IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gTW9Tb2xkKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQojWVIgU09MRCAoZGlzY3JldGUpDQpwMzUgPC1nZ3Bsb3QoZGF0YSA9Y29tYmluZV9kYXRhLCBhZXMoeCA9IFlyU29sZCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KYGBgDQoNCmBgYHtyfQ0KDQpncmlkLmFycmFuZ2UocDEscDIscDMscDQscDUscDYscDcscDgscDkscDEwLHAxMSwNCiAgICAgICAgICAgICBwMTIscDEzLHAxNCxwMTUscDE2LHAxNyxwMTgscDE5LHAyMCxuY29sID0gNSkNCmdyaWQuYXJyYW5nZShwMjEscDIyLHAyMyxwMjQscDI1LHAyNixwMjcscDI4LHAyOSxwMzAsDQogICAgICAgICAgICAgcDMxLHAzMixwMzMscDM0LHAzNSxuY29sID0gNCkNCmBgYA0KRnJvbSB0aGUgYWJvdmUgcGxvdHMsIGl0IGNhbiBiZSBub3RpY2VkIHRoYXQgdGhlcmUgbWFueSBudW1lcmljIHZhcmlhYmxlcyB0aGF0IGFyZSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgY291cGxlZCB3aXRoIG90aGVyIHZhcmlhYmxlcyBzdWNoIGFzIExvdEZyb250YWdlLCBNYXNWbnJBcmVhIGFuZCBvdGhlciB2YXJpYWJsZXMgYXBwZWFyaW5nIHRvIGJlIHNrZXdlZCBkdWUgdG8gdGhlIHByZXNlbmNlIG9mIG91dGxpZXJzLg0KDQojIyBEaXN0cmlidXRpb24gUGxvdCBvZiBDYXRlZ29yaWNhbCBWYXJpYWJsZXMNCmBgYHtyfQ0KDQpiMTwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gTVNab25pbmcpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KIA0KDQpiMjwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gU3RyZWV0KSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQpiMzwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gQWxsZXkpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCmI0PC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBMb3RTaGFwZSkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgIA0KDQoNCmI1IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gTGFuZENvbnRvdXIpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjYgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBVdGlsaXRpZXMpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpICMrIA0KDQoNCg0KYjcgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBMb3RDb25maWcpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjggPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBMYW5kU2xvcGUpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjk8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IE5laWdoYm9yaG9vZCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgKyBjb29yZF9mbGlwKCkgDQoNCg0KDQpiMTAgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBDb25kaXRpb24xKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSArIGNvb3JkX2ZsaXAoKSANCg0KDQpiMTEgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBDb25kaXRpb24yKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSArIGNvb3JkX2ZsaXAoKSANCg0KDQoNCmIxMiA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEJsZGdUeXBlKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQpiMTMgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBIb3VzZVN0eWxlKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQoNCmIxNCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFJvb2ZTdHlsZSkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KDQpiMTU8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IFJvb2ZNYXRsKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSArIGNvb3JkX2ZsaXAoKSANCiANCg0KDQpiMTYgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBFeHRlcmlvcjFzdCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgKyBjb29yZF9mbGlwKCkNCiAgDQoNCg0KYjE3IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gRXh0ZXJpb3IybmQpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpICsgY29vcmRfZmxpcCgpIA0KIA0KDQoNCmIxOCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IE1hc1ZuclR5cGUpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjE5IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gRXh0ZXJRdWFsKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQoNCmIyMCA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEV4dGVyQ29uZCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KDQpiMjEgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBGb3VuZGF0aW9uKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQpiMjIgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBCc210UXVhbCkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCmIyMyA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEJzbXRDb25kKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCiANCg0KDQpiMjQgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBCc210RXhwb3N1cmUpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCmIyNSA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEJzbXRGaW5UeXBlMSkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQogDQoNCg0KYjI2IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gQnNtdEZpblR5cGUyKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCiAgDQoNCmIyNyA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEhlYXRpbmcpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjI4IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gSGVhdGluZ1FDKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQpiMjkgPC1nZ3Bsb3QoZGF0YSA9Y29tYmluZV9kYXRhLCBhZXMoeCA9IENlbnRyYWxBaXIpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KICANCg0KDQpiMzAgPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBFbGVjdHJpY2FsKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSAgDQoNCg0KYjMxIDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gS2l0Y2hlblF1YWwpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCg0KYjMyPC1nZ3Bsb3QoZGF0YSA9IGNvbWJpbmVfZGF0YSwgYWVzKHggPSBGdW5jdGlvbmFsKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQoNCmIzMzwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gRmlyZXBsYWNlUXUpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQoNCmIzNDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gR2FyYWdlVHlwZSkpICsNCiAgZ2VvbV9iYXIoZmlsbCA9ICIjM0I5QUIyIikgDQoNCg0KYjM1IDwtZ2dwbG90KGRhdGEgPSBjb21iaW5lX2RhdGEsIGFlcyh4ID0gR2FyYWdlRmluaXNoKSkgKw0KICBnZW9tX2JhcihmaWxsID0gIiMzQjlBQjIiKSANCg0KDQoNCmIzNiA8LWdncGxvdChkYXRhID0gY29tYmluZV9kYXRhLCBhZXMoeCA9IEdhcmFnZVF1YWwpKSArDQogIGdlb21fYmFyKGZpbGwgPSAiIzNCOUFCMiIpIA0KDQpgYGANCg0KYGBge3J9DQpncmlkLmFycmFuZ2UoYjEsYjIsYjMsYjQsYjUsYjYsYjcsYjgsYjksYjEwLG5jb2wgPSA0KQ0KZ3JpZC5hcnJhbmdlKGIxMSxiMTIsYjEzLGIxNCxiMTUsYjE2LGIxNyxiMTgsYjE5LGIyMCxuY29sID0gNCkNCmdyaWQuYXJyYW5nZShiMjEsYjIyLGIyMyxiMjQsYjI1LGIyNixiMjcsYjI4LGIyOSxiMzAsYjMxLGIzMixiMzMsYjM0LGIzNSxiMzYsbmNvbCA9IDQpDQpgYGANCkZyb20gdGhlIGFib3ZlIHNvbWUgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGRpc3BsYXkgZXZpZGVuY2Ugb2Ygbm9uLW5vcm1hbGl0eSBhbmQgKG11bHRpKWNvbGxpbmVyYWl0eSB3aGlsZXMgb3RoZXJzIHZhcmlhYmxlcyBtYXkgYmUgdXNlZnVsIGZlYXR1cmVzIGluIHByZWRpY3RpbmcgdGhlIHRhcmdldCB2YXJpYWJsZS4gSXQgY2FuIGFsc28gYmUgbm90ZWQgdGhhdCBhcmUgc2lnbmlmaWNhbnQgYW1vdW50IG9mIG1pc3NpbmcgZGF0YSB2YWx1ZXMuTWFueSBvZiB0aGVzZSBOQSBvYnNlcnZhdGlvbnMgYXJlIGxpa2VseSB0byBiZSBzdHJ1Y3R1cmFsbHkgbWlzc2luZyBmb3IgYSBsb2dpY2FsIHJlYXNvbi4gRm9yIGluc3RhbmNlIEdhcmFnZUFyZWE9IE5BLCBzdWdnZXN0IHRoYXQgdGhlIHByb3BlcnR5IGhhcyBubyBnYXJhZ2UuIEFzIHN1Y2ggbWlzc2luZyBkYXRhIHdpbGwgcmVxdWlyZSBpbXB1dGF0aW9uLg0KDQojIyBTcGxpdHRpbmcgRGF0YSBpbnRvIE51bWVyaWNhbCBhbmQgQ2F0ZWdvcmljYWwgVmFyaWFibGVzDQpGb3IgdGhlIHB1cnBvc2Ugb2YgdmlzdWFsaXphdGlvbiwgdGhlIGNvbWJpbmVkIGRhdGFzZXQgaXMgc3BsaXQgaW50byBudW1lcmljYWwgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4NCkFsc28gb25lIHRyYWluIGRhdGFzZXQgd2l0aCBjYXRlZ29yaWNhbCBhbmQgbnVtZXJpYyB2YXJpYWJsZSBpcyBjcmVhdGVkIA0KYGBge3J9DQpjYXRfdmFyIDwtIG5hbWVzKGNvbWJpbmVfZGF0YSlbd2hpY2goc2FwcGx5KGNvbWJpbmVfZGF0YSwgaXMuY2hhcmFjdGVyKSldDQpudW1lcmljX3ZhciA8LSBuYW1lcyhjb21iaW5lX2RhdGEpW3doaWNoKHNhcHBseShjb21iaW5lX2RhdGEsIGlzLm51bWVyaWMpKV0NCmBgYA0KDQpgYGB7cn0NCnRyYWluMV9jYXQ8LWNvbWJpbmVfZGF0YVtjYXRfdmFyXQ0KdHJhaW4xX251bTwtY29tYmluZV9kYXRhW251bWVyaWNfdmFyXQ0KYGBgDQoNCiMjICBCaXZhcmlhdGUgUGxvdHMobnVtZXJpYykNClRoaXMgc2VjdGlvbiBsb29rcyBhdCBlYWNoIHZhcmlhYmxlIGFuZCBob3cgdGhleSByZWxhdGUgdG8gdGhlIHRhcmdldCB2YXJpYWJsZShzYWxlUHJpY2UpDQpgYGB7cn0NCiMgT3ZlcmFsbCBRdWFsaXR5IHZzIFNhbGUgUHJpY2UNCiMgdW5pcXVlKHRyYWluJE92ZXJhbGxRdWFsKQ0KZ2dwbG90KHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IoT3ZlcmFsbFF1YWwpLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX2JveHBsb3QoY29sID0gIiMzQjlBQjIiKQ0KYGBgDQpGcm9tIHRoZSBhYm92ZSBwbG90LCBpdCBjYW4gYmUgc3VnZ2VzdGVkIHRoYXQgcGVvcGxlIGFyZSB3aWxsaW5nIHRvIHBheSBtb3JlIGZvciBiZXR0ZXIgcXVhbGl0eS4NCmBgYHtyfQ0KIyBMaXZpbmcgQXJlYSB2cyBTYWxlIFByaWNlDQpnZ3Bsb3QodHJhaW4sIG1hcHBpbmcgPSBhZXMoeCA9IEdyTGl2QXJlYSwgeSA9IFNhbGVQcmljZSkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIixjb2wgPSAiIzNCOUFCMiIpDQpgYGANCkZyb20gdGhlIGFib3ZlIGl0IGNhbiBiZSBzdWdnZXN0ZWQgdGhhdCBwZW9wbGUgYXJlIHdvdWxkIHBheSBtb3JlIGZvciBsaXZpbmcgYXJlYS4gSG93ZXZlciBpdHMgbm90IHJlYXNvbmFibGUgZm9yIHBlb3BsZSB0byBwYXkgbGVzcyBmb3IgbGFyZ2UgYXJlYSBhcyB0d28gZGF0YSBwb2ludCBpbiB0aGUgYm90dG9tLXJpZ2h0IG9mIHRoZSBwbG90LiBUaGVzZSB0d28gcG9pbnRzIGhvd2V2ZXIgbmVlZHMgdG8gYmUgcmVtb3ZlZC4NCmBgYHtyfQ0KIyBSZW1vdmluZyBvdXRsaWVycyBtYW51YWxseSAoVGhlIHR3byBwb2ludHMgaW4gdGhlIGJvdHRvbSByaWdodCkNCnRyYWluID0gdHJhaW5bdHJhaW4kR3JMaXZBcmVhPD00NTAwLF0NCmdncGxvdCh0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gR3JMaXZBcmVhLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLGNvbCA9ICIjM0I5QUIyIikNCmBgYA0KDQpgYGB7cn0NCiMgR2FyYWdlIEFyZWEgdnMgU2FsZSBQcmljZQ0KdW5pcXVlKHRyYWluJEdhcmFnZUNhcnMpDQpnZ3Bsb3QodHJhaW4sIG1hcHBpbmcgPSBhZXMoeCA9IGZhY3RvcihHYXJhZ2VDYXJzKSwgeSA9IFNhbGVQcmljZSkpICsgZ2VvbV9ib3hwbG90KGNvbCA9ICIjM0I5QUIyIikNCg0KYGBgDQpUaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZ2FyYWdlY2FycyBhbmQgc2FsZXByaWNlIHN1Z2dlc3QgdGhhdCA0LWNhciBnYXJhZ2VzIHJlc3VsdCBpbiBsZXNzIHNhbGUgUHJpY2Ugd2hpY2ggbWlnaHQgYmUgYXMgYSByZXN1bHQgb2Ygb3V0bGllcnMuIFRoZXNlIG91dGxpZXJzIG11c3QgYmUgcmVtb3ZlZC4NCmBgYHtyfQ0KdHJhaW4gPSB0cmFpblt0cmFpbiRHYXJhZ2VDYXJzIDwgNCwgXQ0KZ2dwbG90KHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IoR2FyYWdlQ2FycyksIHkgPSBTYWxlUHJpY2UpKSArIGdlb21fYm94cGxvdChjb2wgPSAiIzNCOUFCMiIpDQpgYGANCg0KYGBge3J9DQojIEdhcmFnZSBBcmVhIHZzIFNhbGUgUHJpY2UNCmdncGxvdCh0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gR2FyYWdlQXJlYSAsIHkgPSBTYWxlUHJpY2UpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsY29sID0gIiMzQjlBQjIiKQ0KYGBgDQpgYGB7cn0NCiMjQWdhaW4sIHRoZSB0d28gZGF0YSBwb2ludHMgYXQgdGhlIGJvdHRvbSBkb2VzIG5vdCBtYWtlIHNlbnNlDQp0cmFpbiA9IGZpbHRlcih0cmFpbiwgR2FyYWdlQXJlYSA8IDEyNDApDQpnZ3Bsb3QodHJhaW4sIG1hcHBpbmcgPSBhZXMoeCA9IEdhcmFnZUFyZWEgLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLGNvbCA9ICIjM0I5QUIyIikNCmBgYA0KYGBge3J9DQojIEJhc2VtZW50IEFyZWEgdnMgU2FsZSBQcmljZQ0KZ2dwbG90KHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBUb3RhbEJzbXRTRiAsIHkgPSBTYWxlUHJpY2UpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsY29sID0gIiMzQjlBQjIiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBGaXJzdCBGbG9vciBBcmVhIHZzIFNhbGUgUHJpY2UNCmdncGxvdCh0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gWDFzdEZsclNGLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLGNvbCA9ICIjM0I5QUIyIikNCmBgYA0KYGBge3J9DQojICMgRXh0ZXJRdWFsIHZzIFNhbGUgUHJpY2UNCmdncGxvdCh0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gZmFjdG9yKEV4dGVyUXVhbCksIHkgPSBTYWxlUHJpY2UpKSArIGdlb21fYm94cGxvdChjb2wgPSAiIzNCOUFCMiIpDQpgYGANClRoZSBhYm92ZSBwbG90IHN1Z2dlc3QgdGhhdCwgaG91c2VzIHdpdGggZXhjZWxsZW50IGV4dGVybmFsIHF1YWxpdHkgYXJlIGV4cGVuc2l2ZSB3aGVyZWFzIGhvdXNlcyB3aXRoIGZhaXIgcXVhbGl0eSBtYXRlcmlhbCBhcmUgbGVzcyBleHBlbnNpdmUuDQoNCmBgYHtyfQ0KIyBFeHRlclF1YWwgdnMgU2FsZSBQcmljZQ0KZ2dwbG90KHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IoRnVsbEJhdGgpLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX2JveHBsb3QoY29sID0gIiMzQjlBQjIiKQ0KDQpgYGANCkZyb20gdGhlIGFib3ZlIHBsb3QgaXQgaXMgbm90IHJlYXNvbmFibGUgdGhhdCBob3VzZXMgd2l0aCB6ZXJvIGZ1bGwgYmF0aCBhcmUgZXhwZW5zaXZlIHRoYW4gaG91c2VzIHdpdGggb25lIGZ1bGwgYmF0aC5UaGlzIHdpbGwgYmUgYW4gb3V0bGllciBhbmQgbXVzdCBiZSByZW1vdmVkIGZyb20gdGhlIGRhdGEgc2V0Lg0KYGBge3J9DQp0cmFpbiA9IHRyYWluW3RyYWluJEZ1bGxCYXRoID4gMCAsIF0NCmdncGxvdCh0cmFpbiwgbWFwcGluZyA9IGFlcyh4ID0gZmFjdG9yKEZ1bGxCYXRoKSwgeSA9IFNhbGVQcmljZSkpICsgZ2VvbV9ib3hwbG90KGNvbCA9ICIjM0I5QUIyIikNCmBgYA0KYGBge3J9DQojQnNtdFF1YWwgYW5kIFNhbGVQcmljZQ0KZ2dwbG90KHRyYWluLCBtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IoQnNtdFF1YWwpLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX2JveHBsb3QoY29sID0gIiMzQjlBQjIiKQ0KDQpgYGANCmBgYHtyfQ0KIyBUb3RhbCBSb29tcyB2cyBTYWxlIFByaWNlDQpnZ3Bsb3QodHJhaW4sIG1hcHBpbmcgPSBhZXMoeCA9IGZhY3RvcihUb3RSbXNBYnZHcmQpLCB5ID0gU2FsZVByaWNlKSkgKyBnZW9tX2JveHBsb3QoY29sID0gIiMzQjlBQjIiKSsgc2NhbGVfeV9kaXNjcmV0ZSgpDQpgYGANCg0KIyMgQ29ycmVsYXRpb24gTWF0cml4DQpgYGB7cn0NCmNvcnJlbGF0aW9ucyA8LSBjb3IobmEub21pdCh0cmFpbjFfbnVtWywtMV0pKQ0KaGVhZChjb3JyZWxhdGlvbnMsIDIpDQpgYGANCmBgYHtyfQ0KbWVsdGVkX2NvcnJlbGF0aW9ucyA9IG1lbHQoY29ycmVsYXRpb25zKQ0KaGVhZChtZWx0ZWRfY29ycmVsYXRpb25zLCAyKQ0KDQoNCmdncGxvdChkYXRhID0gbWVsdGVkX2NvcnJlbGF0aW9ucywgYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPXZhbHVlKSkgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIsIG1pZCA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwgbGltaXQgPSBjKC0xLDEpLCBzcGFjZSA9ICJMYWIiLA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lPSJQZWFyc29uXG5Db3JyZWxhdGlvbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuMikpKyB0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArDQogIGNvb3JkX2ZpeGVkKCkNCmBgYA0KVGhlIGFib3ZlIGNvcnJlbGF0aW9uIHBsb3QgaXMgdG9vIGNsdXN0ZXJlZCwgaGVuY2UgbGV0cyBjb25zaWRlciB0aGUgdG9wIDEwIGNvcnJlbGF0ZWQgdmFyaWFibGVzLg0KDQojIyMgVG9wIDEwIGNvcnJlbGF0ZWQgdmFyaWFibGVzDQpgYGB7cn0NCmNvcnJfY3Jvc3ModHJhaW4sICMgbmFtZSBvZiBkYXRhc2V0DQogICAgICAgICAgIG1heF9wdmFsdWUgPSAwLjA1LCAjIGRpc3BsYXkgb25seSBzaWduaWZpY2FudCBjb3JyZWxhdGlvbnMgKGF0IDUlIGxldmVsKQ0KICAgICAgICAgICB0b3AgPSAxMCAjIGRpc3BsYXkgdG9wIDEwIGNvdXBsZXMgb2YgdmFyaWFibGVzIChieSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCkNCikNCmBgYA0KDQoNCiMjIyBUb3AgMTAgY29ycmVsYXRlZCB2YXJpYWJsZXMgd2l0aCBTYWxlIFByaWNlDQpgYGB7cn0NCnRvcF8xMCA9IGNvcnJfdmFyKHRyYWluLCAjIG5hbWUgb2YgZGF0YXNldA0KICAgICAgICAgICAgICAgICAgU2FsZVByaWNlLCAjIG5hbWUgb2YgdmFyaWFibGUgdG8gZm9jdXMgb24NCiAgICAgICAgICAgICAgICAgIHRvcCA9IDEwICMgZGlzcGxheSB0b3AgNSBjb3JyZWxhdGlvbnMNCikNCnRvcF8xMA0KDQpgYGANCkZyb20gdGhlIGFib3ZlLCBCbHVlIGluZGljYXRlIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGFuZCByZWQgaW5kaWNhdGUgbmVnYXRpdmUgY29ycmVsYXRpb25zLiBFeHRlclF1YWxfVEEgZnJvbSB0aGUgcGxvdCBuZWdhdGl2ZWx5IGNvcnJlbGF0ZXMgd2l0aCB0aGUgdGFyZ2V0IHZhcmlhYmxlLg0KDQoNCg0KIyBEYXRhIENsZWFuaW5nDQpCZWZvcmUgcGVyZm9ybWluZyBtb2RlbGluZywgYWxsIHZhcmlhYmxlcyB3aXRoIG1pc3NpbmcgZGF0YSBhcmUgaWRlbnRpZmllZCBhbmQgY29ycmVjdGVkLg0KYGBge3J9DQp0ZXN0JFNhbGVQcmljZSA8LSBOQQ0KdHJhaW4kaXNUcmFpbiA8LSAxDQp0ZXN0JGlzVHJhaW4gPC0gMA0KY29tYmluZV9kYXRhIDwtcmJpbmQodHJhaW4sdGVzdCkNCmhlYWQoY29tYmluZV9kYXRhLDIpDQoNCg0KDQpNaXNzaW5nX2luZGljZXMgPC0gc2FwcGx5KGNvbWJpbmVfZGF0YSxmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKS9ucm93KGNvbWJpbmVfZGF0YSkNCg0KTWlzc2luZ19TdW1tYXJ5IDwtIGRhdGEuZnJhbWUoaW5kZXggPSBuYW1lcyhjb21iaW5lX2RhdGEpLE1pc3NpbmdfVmFsdWVzPU1pc3NpbmdfaW5kaWNlcykNCg0KTWlzc2luZ19TdW1tYXJ5W29yZGVyKE1pc3NpbmdfU3VtbWFyeSRNaXNzaW5nX1ZhbHVlcyA+IDAsIGRlY3JlYXNpbmcgPSBUUlVFKSxdDQpgYGANCg0KDQoNCg0KYGBge3J9DQojIyMgcGVyY2VudGFnZSBvZiBtaXNzaW5nIGNhc2VzDQpzdW0oaXMubmEoY29tYmluZV9kYXRhKSkvIChkaW0oY29tYmluZV9kYXRhKVsxXSAqZGltKGNvbWJpbmVfZGF0YSlbMl0pICoxMDAgDQoNCmFsbF9kYXRhX25hID0gTWlzc2luZ19TdW1tYXJ5W29yZGVyKE1pc3NpbmdfU3VtbWFyeSRNaXNzaW5nX1ZhbHVlcywgZGVjcmVhc2luZyA9IFRSVUUpLCBdDQphbGxfZGF0YV9uYVsxOjUsIF0NCg0KYWxsX2RhdGEgPC0gY29tYmluZV9kYXRhDQoNCmBgYA0KIyMgSW5wdXRpbmcgTWlzc2luZyBWYWx1ZXMNCkZyb20gdGhlIGFib3ZlIHZhcmlhYmxlcyB3aXRoIG1pc3NpbmcgdmFsdWVzIGFyZSBmaXhlZCBzaW5jZSBtb3N0IG9mIHRoZW1lIGFyZSBhY3R1YWxseSBub3QgbWlzc2luZy4NCmBgYHtyfQ0KI0dldG1vZGUNCg0KZ2V0bW9kZSA8LSBmdW5jdGlvbih2KSB7DQogIHVuaXF2IDwtIHVuaXF1ZSh2KQ0KICB1bmlxdlt3aGljaC5tYXgodGFidWxhdGUobWF0Y2godiwgdW5pcXYpKSldDQp9DQojUG9vbFFDDQojQ2hhbmdpbmcgTkEgaW4gUG9vbFFDIHRvIE5vbmUNCmFsbF9kYXRhJFBvb2xRQzEgPC0gYXMuY2hhcmFjdGVyKGFsbF9kYXRhJFBvb2xRQykNCmFsbF9kYXRhJFBvb2xRQzFbd2hpY2goaXMubmEoYWxsX2RhdGEkUG9vbFFDKSldIDwtICJOb25lIg0KYWxsX2RhdGEkUG9vbFFDIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRQb29sUUMxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1Qb29sUUMxKQ0Kc3VtKGlzLm5hKGFsbF9kYXRhJFBvb2xRQykpDQoNCiNNaXNjRmVhdHVyZQ0KYWxsX2RhdGEkTWlzY0ZlYXR1cmUxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRNaXNjRmVhdHVyZSkNCmFsbF9kYXRhJE1pc2NGZWF0dXJlMVt3aGljaChpcy5uYShhbGxfZGF0YSRNaXNjRmVhdHVyZSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJE1pc2NGZWF0dXJlIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRNaXNjRmVhdHVyZTEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLU1pc2NGZWF0dXJlMSkNCnN1bShpcy5uYShhbGxfZGF0YSRNaXNjRmVhdHVyZSkpDQoNCiNBbGxleQ0KYWxsX2RhdGEkQWxsZXkxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRBbGxleSkNCmFsbF9kYXRhJEFsbGV5MVt3aGljaChpcy5uYShhbGxfZGF0YSRBbGxleSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEFsbGV5IDwtIGFzLmZhY3RvcihhbGxfZGF0YSRBbGxleTEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUFsbGV5MSkNCnN1bShpcy5uYShhbGxfZGF0YSRBbGxleSkpDQoNCiNGZW5jZQ0KYWxsX2RhdGEkRmVuY2UxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRGZW5jZSkNCmFsbF9kYXRhJEZlbmNlMVt3aGljaChpcy5uYShhbGxfZGF0YSRGZW5jZSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEZlbmNlIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRGZW5jZTEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUZlbmNlMSkNCnN1bShpcy5uYShhbGxfZGF0YSRGZW5jZSkpDQoNCiNGaXJlcGxhY2VRdQ0KYWxsX2RhdGEkRmlyZXBsYWNlUXUxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRGaXJlcGxhY2VRdSkNCmFsbF9kYXRhJEZpcmVwbGFjZVF1MVt3aGljaChpcy5uYShhbGxfZGF0YSRGaXJlcGxhY2VRdSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEZpcmVwbGFjZVF1IDwtIGFzLmZhY3RvcihhbGxfZGF0YSRGaXJlcGxhY2VRdTEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUZpcmVwbGFjZVF1MSkNCnN1bShpcy5uYShhbGxfZGF0YSRGaXJlcGxhY2VRdSkpDQoNCnVuaXF1ZShhbGxfZGF0YSRGaXJlcGxhY2VRdSkNCg0KI0xvdEZyb250YWdlDQphbGxfZGF0YSRMb3RGcm9udGFnZVt3aGljaChpcy5uYShhbGxfZGF0YSRMb3RGcm9udGFnZSkpXSA8LSBtZWRpYW4oYWxsX2RhdGEkTG90RnJvbnRhZ2UsbmEucm0gPSBUKQ0Kc3VtKGlzLm5hKGFsbF9kYXRhJExvdEZyb250YWdlKSkNCg0KI0dhcmFnZVR5cGUNCmFsbF9kYXRhJEdhcmFnZVR5cGUxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRHYXJhZ2VUeXBlKQ0KYWxsX2RhdGEkR2FyYWdlVHlwZTFbd2hpY2goaXMubmEoYWxsX2RhdGEkR2FyYWdlVHlwZSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEdhcmFnZVR5cGUgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEdhcmFnZVR5cGUxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1HYXJhZ2VUeXBlMSkNCnN1bShpcy5uYShhbGxfZGF0YSRHYXJhZ2VUeXBlKSkNCg0KI0dhcmFnZUZpbmlzaA0KYWxsX2RhdGEkR2FyYWdlRmluaXNoMSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2RhdGEkR2FyYWdlRmluaXNoKQ0KYWxsX2RhdGEkR2FyYWdlRmluaXNoMVt3aGljaChpcy5uYShhbGxfZGF0YSRHYXJhZ2VGaW5pc2gpKV0gPC0gIk5vbmUiDQphbGxfZGF0YSRHYXJhZ2VGaW5pc2ggPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEdhcmFnZUZpbmlzaDEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUdhcmFnZUZpbmlzaDEpDQpzdW0oaXMubmEoYWxsX2RhdGEkR2FyYWdlRmluaXNoKSkNCg0KI0dhcmFnZVF1YWwNCmFsbF9kYXRhJEdhcmFnZVF1YWwxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRHYXJhZ2VRdWFsKQ0KYWxsX2RhdGEkR2FyYWdlUXVhbDFbd2hpY2goaXMubmEoYWxsX2RhdGEkR2FyYWdlUXVhbCkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEdhcmFnZVF1YWwgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEdhcmFnZVF1YWwxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1HYXJhZ2VRdWFsMSkNCg0KI0dhcmFnZUNvbmQNCmFsbF9kYXRhJEdhcmFnZUNvbmQxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRHYXJhZ2VDb25kKQ0KYWxsX2RhdGEkR2FyYWdlQ29uZDFbd2hpY2goaXMubmEoYWxsX2RhdGEkR2FyYWdlQ29uZCkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEdhcmFnZUNvbmQgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEdhcmFnZUNvbmQxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1HYXJhZ2VDb25kMSkNCg0KdW5pcXVlKGFsbF9kYXRhJEdhcmFnZUNvbmQpDQoNCiNHYXJhZ2VZckJsdA0KYWxsX2RhdGEkR2FyYWdlWXJCbHRbd2hpY2goaXMubmEoYWxsX2RhdGEkR2FyYWdlWXJCbHQpKV0gPC0gMA0Kc3VtKGlzLm5hKGFsbF9kYXRhJEdhcmFnZVlyQmx0KSkNCnN1bShpcy5uYShhbGxfZGF0YSRHYXJhZ2VDb25kKSkNCg0KIyBoZWFkKGFsbF9kYXRhLCAyKQ0KdW5pcXVlKGFsbF9kYXRhJEdhcmFnZVlyQmx0KQ0KDQojR2FyYWdlQXJlYQ0KYWxsX2RhdGEkR2FyYWdlQXJlYVt3aGljaChpcy5uYShhbGxfZGF0YSRHYXJhZ2VBcmVhKSldIDwtIDANCiNHYXJhZ2VDYXJzDQphbGxfZGF0YSRHYXJhZ2VDYXJzW3doaWNoKGlzLm5hKGFsbF9kYXRhJEdhcmFnZUNhcnMpKV0gPC0gMA0KI0JzbXRGaW5TRjENCmFsbF9kYXRhJEJzbXRGaW5TRjFbd2hpY2goaXMubmEoYWxsX2RhdGEkQnNtdEZpblNGMSkpXSA8LSAwDQojQnNtdEZpblNGMg0KYWxsX2RhdGEkQnNtdEZpblNGMlt3aGljaChpcy5uYShhbGxfZGF0YSRCc210RmluU0YyKSldIDwtIDANCiNCc210VW5mU0YNCmFsbF9kYXRhJEJzbXRVbmZTRlt3aGljaChpcy5uYShhbGxfZGF0YSRCc210VW5mU0YpKV0gPC0gMA0KI1RvdGFsQnNtdFNGDQphbGxfZGF0YSRUb3RhbEJzbXRTRlt3aGljaChpcy5uYShhbGxfZGF0YSRUb3RhbEJzbXRTRikpXSA8LSAwDQojQnNtdEZ1bGxCYXRoDQphbGxfZGF0YSRCc210RnVsbEJhdGhbd2hpY2goaXMubmEoYWxsX2RhdGEkQnNtdEZ1bGxCYXRoKSldIDwtIDANCiNCc210SGFsZkJhdGgNCmFsbF9kYXRhJEJzbXRIYWxmQmF0aFt3aGljaChpcy5uYShhbGxfZGF0YSRCc210SGFsZkJhdGgpKV0gPC0gMA0KI0JzbXRRdWFsDQphbGxfZGF0YSRCc210UXVhbDEgPC0gYXMuY2hhcmFjdGVyKGFsbF9kYXRhJEJzbXRRdWFsKQ0KYWxsX2RhdGEkQnNtdFF1YWwxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEJzbXRRdWFsKSldIDwtICJOb25lIg0KYWxsX2RhdGEkQnNtdFF1YWwgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEJzbXRRdWFsMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSxzZWxlY3QgPSAtQnNtdFF1YWwxKQ0KI0JzbXRDb25kDQphbGxfZGF0YSRCc210Q29uZDEgPC0gYXMuY2hhcmFjdGVyKGFsbF9kYXRhJEJzbXRDb25kKQ0KYWxsX2RhdGEkQnNtdENvbmQxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEJzbXRDb25kKSldIDwtICJOb25lIg0KYWxsX2RhdGEkQnNtdENvbmQgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEJzbXRDb25kMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSxzZWxlY3QgPSAtQnNtdENvbmQxKQ0KDQojQnNtdEV4cG9zdXJlDQphbGxfZGF0YSRCc210RXhwb3N1cmUxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRCc210RXhwb3N1cmUpDQphbGxfZGF0YSRCc210RXhwb3N1cmUxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEJzbXRFeHBvc3VyZSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEJzbXRFeHBvc3VyZSA8LSBhcy5mYWN0b3IoYWxsX2RhdGEkQnNtdEV4cG9zdXJlMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSwgc2VsZWN0ID0gLUJzbXRFeHBvc3VyZTEpDQoNCiNCc210RmluVHlwZTENCmFsbF9kYXRhJEJzbXRGaW5UeXBlMTEgPC0gYXMuY2hhcmFjdGVyKGFsbF9kYXRhJEJzbXRGaW5UeXBlMSkNCmFsbF9kYXRhJEJzbXRGaW5UeXBlMTFbd2hpY2goaXMubmEoYWxsX2RhdGEkQnNtdEZpblR5cGUxKSldIDwtICJOb25lIg0KYWxsX2RhdGEkQnNtdEZpblR5cGUxIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRCc210RmluVHlwZTExKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1Cc210RmluVHlwZTExKQ0KDQojQnNtdEZpblR5cGUyDQphbGxfZGF0YSRCc210RmluVHlwZTIxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRCc210RmluVHlwZTIpDQphbGxfZGF0YSRCc210RmluVHlwZTIxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEJzbXRGaW5UeXBlMikpXSA8LSAiTm9uZSINCmFsbF9kYXRhJEJzbXRGaW5UeXBlMiA8LSBhcy5mYWN0b3IoYWxsX2RhdGEkQnNtdEZpblR5cGUyMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSxzZWxlY3QgPSAtQnNtdEZpblR5cGUyMSkNCiNNYXNWbnJUeXBlDQoNCmFsbF9kYXRhJE1hc1ZuclR5cGUxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRNYXNWbnJUeXBlKQ0KYWxsX2RhdGEkTWFzVm5yVHlwZTFbd2hpY2goaXMubmEoYWxsX2RhdGEkTWFzVm5yVHlwZSkpXSA8LSAiTm9uZSINCmFsbF9kYXRhJE1hc1ZuclR5cGUgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJE1hc1ZuclR5cGUxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1NYXNWbnJUeXBlMSkNCg0KI01hc1ZuckFyZWENCmFsbF9kYXRhJE1hc1ZuckFyZWFbd2hpY2goaXMubmEoYWxsX2RhdGEkTWFzVm5yQXJlYSkpXSA8LSAwDQoNCiNNU1pvbmluZw0KYWxsX2RhdGEkTVNab25pbmcxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRNU1pvbmluZykNCmFsbF9kYXRhJE1TWm9uaW5nMVt3aGljaChpcy5uYShhbGxfZGF0YSRNU1pvbmluZykpXSA8LSBnZXRtb2RlKGFsbF9kYXRhJE1TWm9uaW5nKQ0KYWxsX2RhdGEkTVNab25pbmcgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJE1TWm9uaW5nMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSxzZWxlY3QgPSAtTVNab25pbmcxKQ0KDQoNCiNVdGlsaXRpZXMgV2UgY2FuIHNhZmVseSBkcm9wIHRoaXMgZmVhdHVyZSBzaW5jZSBtb3N0IG9mIHRoZSBvYnNlcnZhdGlvbnMgYXJlIOKAnEFsbFB1YuKAnSwgMSBpcyDigJxOb1Nld2HigJ0sIGFuZCAyIOKAnE5B4oCdDQp1bmlxdWUoYWxsX2RhdGEkVXRpbGl0aWVzKQ0KDQojIyBbMV0gIkFsbFB1YiIgIk5vU2VXYSIgTkENCnRhYmxlKGFsbF9kYXRhJFV0aWxpdGllcykNCmFsbF9kYXRhJFV0aWxpdGllcyA9IE5VTEwNCg0KI0Z1bmN0aW9uYWwNCmFsbF9kYXRhJEZ1bmN0aW9uYWwxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRGdW5jdGlvbmFsKQ0KYWxsX2RhdGEkRnVuY3Rpb25hbDFbd2hpY2goaXMubmEoYWxsX2RhdGEkRnVuY3Rpb25hbCkpXSA8LSAiVHlwIg0KYWxsX2RhdGEkRnVuY3Rpb25hbCA8LSBhcy5mYWN0b3IoYWxsX2RhdGEkRnVuY3Rpb25hbDEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUZ1bmN0aW9uYWwxKQ0KI3RhYmxlKGFsbF9kYXRhJEZ1bmN0aW9uYWwpDQoNCiNFbGVjdHJpY2FsDQphbGxfZGF0YSRFbGVjdHJpY2FsMSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2RhdGEkRWxlY3RyaWNhbCkNCmFsbF9kYXRhJEVsZWN0cmljYWwxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEVsZWN0cmljYWwpKV0gPC0gZ2V0bW9kZShhbGxfZGF0YSRFbGVjdHJpY2FsKQ0KYWxsX2RhdGEkRWxlY3RyaWNhbCA8LSBhcy5mYWN0b3IoYWxsX2RhdGEkRWxlY3RyaWNhbDEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUVsZWN0cmljYWwxKQ0KDQojS2l0Y2hlblF1YWwNCmFsbF9kYXRhJEtpdGNoZW5RdWFsMSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2RhdGEkS2l0Y2hlblF1YWwpDQphbGxfZGF0YSRLaXRjaGVuUXVhbDFbd2hpY2goaXMubmEoYWxsX2RhdGEkS2l0Y2hlblF1YWwpKV0gPC0gZ2V0bW9kZShhbGxfZGF0YSRLaXRjaGVuUXVhbCkNCmFsbF9kYXRhJEtpdGNoZW5RdWFsIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRLaXRjaGVuUXVhbDEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLUtpdGNoZW5RdWFsMSkNCg0KI0V4dGVyaW9yMXN0DQphbGxfZGF0YSRFeHRlcmlvcjFzdDEgPC0gYXMuY2hhcmFjdGVyKGFsbF9kYXRhJEV4dGVyaW9yMXN0KQ0KYWxsX2RhdGEkRXh0ZXJpb3Ixc3QxW3doaWNoKGlzLm5hKGFsbF9kYXRhJEV4dGVyaW9yMXN0KSldIDwtIGdldG1vZGUoYWxsX2RhdGEkRXh0ZXJpb3Ixc3QpDQphbGxfZGF0YSRFeHRlcmlvcjFzdCA8LSBhcy5mYWN0b3IoYWxsX2RhdGEkRXh0ZXJpb3Ixc3QxKQ0KYWxsX2RhdGEgPC0gc3Vic2V0KGFsbF9kYXRhLHNlbGVjdCA9IC1FeHRlcmlvcjFzdDEpDQoNCiNFeHRlcmlvcjJuZA0KYWxsX2RhdGEkRXh0ZXJpb3IybmQxIDwtIGFzLmNoYXJhY3RlcihhbGxfZGF0YSRFeHRlcmlvcjJuZCkNCmFsbF9kYXRhJEV4dGVyaW9yMm5kMVt3aGljaChpcy5uYShhbGxfZGF0YSRFeHRlcmlvcjJuZCkpXSA8LSBnZXRtb2RlKGFsbF9kYXRhJEV4dGVyaW9yMm5kKQ0KYWxsX2RhdGEkRXh0ZXJpb3IybmQgPC0gYXMuZmFjdG9yKGFsbF9kYXRhJEV4dGVyaW9yMm5kMSkNCmFsbF9kYXRhIDwtIHN1YnNldChhbGxfZGF0YSxzZWxlY3QgPSAtRXh0ZXJpb3IybmQxKQ0KDQojU2FsZVR5cGUNCmFsbF9kYXRhJFNhbGVUeXBlMSA8LSBhcy5jaGFyYWN0ZXIoYWxsX2RhdGEkU2FsZVR5cGUpDQphbGxfZGF0YSRTYWxlVHlwZTFbd2hpY2goaXMubmEoYWxsX2RhdGEkU2FsZVR5cGUpKV0gPC0gZ2V0bW9kZShhbGxfZGF0YSRTYWxlVHlwZSkNCmFsbF9kYXRhJFNhbGVUeXBlIDwtIGFzLmZhY3RvcihhbGxfZGF0YSRTYWxlVHlwZTEpDQphbGxfZGF0YSA8LSBzdWJzZXQoYWxsX2RhdGEsc2VsZWN0ID0gLVNhbGVUeXBlMSkNCmhlYWQoYWxsX2RhdGEsMikNCmBgYA0KIyMgQ29udmVydGluZyB0byBGYWN0b3JzDQpgYGB7cn0NCmFsbF9kYXRhJFN0cmVldCA9IGZhY3RvcihhbGxfZGF0YSRTdHJlZXQpDQphbGxfZGF0YSRMb3RTaGFwZSA9IGZhY3RvcihhbGxfZGF0YSRMb3RTaGFwZSkNCmFsbF9kYXRhJExhbmRDb250b3VyID0gZmFjdG9yKGFsbF9kYXRhJExhbmRDb250b3VyKQ0KYWxsX2RhdGEkTG90Q29uZmlnID0gZmFjdG9yKGFsbF9kYXRhJExvdENvbmZpZykNCmFsbF9kYXRhJExhbmRTbG9wZSA9IGZhY3RvcihhbGxfZGF0YSRMYW5kU2xvcGUpDQphbGxfZGF0YSROZWlnaGJvcmhvb2QgPSBmYWN0b3IoYWxsX2RhdGEkTmVpZ2hib3Job29kKQ0KYWxsX2RhdGEkQ29uZGl0aW9uMSA9IGZhY3RvcihhbGxfZGF0YSRDb25kaXRpb24xKQ0KYWxsX2RhdGEkQ29uZGl0aW9uMiA9IGZhY3RvcihhbGxfZGF0YSRDb25kaXRpb24yKQ0KYWxsX2RhdGEkQmxkZ1R5cGUgPSBmYWN0b3IoYWxsX2RhdGEkQmxkZ1R5cGUpDQphbGxfZGF0YSRIb3VzZVN0eWxlID0gZmFjdG9yKGFsbF9kYXRhJEhvdXNlU3R5bGUpDQphbGxfZGF0YSRPdmVyYWxsUXVhbCA9IGZhY3RvcihhbGxfZGF0YSRPdmVyYWxsUXVhbCkNCmFsbF9kYXRhJE92ZXJhbGxDb25kID0gZmFjdG9yKGFsbF9kYXRhJE92ZXJhbGxDb25kKQ0KYWxsX2RhdGEkWWVhckJ1aWx0ID0gYXMuY2hhcmFjdGVyKChhbGxfZGF0YSRZZWFyQnVpbHQpKQ0KYWxsX2RhdGEkR2FyYWdlWXJCbHQgPSBhcy5jaGFyYWN0ZXIoKGFsbF9kYXRhJEdhcmFnZVlyQmx0KSkNCmFsbF9kYXRhJFllYXJSZW1vZEFkZCA9IGFzLmNoYXJhY3RlcihhbGxfZGF0YSRZZWFyUmVtb2RBZGQpDQphbGxfZGF0YSRSb29mU3R5bGUgPSBmYWN0b3IoYWxsX2RhdGEkUm9vZlN0eWxlKQ0KYWxsX2RhdGEkUm9vZk1hdGwgPSBmYWN0b3IoYWxsX2RhdGEkUm9vZk1hdGwpDQphbGxfZGF0YSRFeHRlclF1YWwgPSBmYWN0b3IoYWxsX2RhdGEkRXh0ZXJRdWFsKQ0KYWxsX2RhdGEkRXh0ZXJDb25kID0gZmFjdG9yKGFsbF9kYXRhJEV4dGVyQ29uZCkNCmFsbF9kYXRhJE1TU3ViQ2xhc3MgPSBmYWN0b3IoYWxsX2RhdGEkTVNTdWJDbGFzcykNCmFsbF9kYXRhJEZvdW5kYXRpb24gPSBmYWN0b3IoYWxsX2RhdGEkRm91bmRhdGlvbikNCmFsbF9kYXRhJEhlYXRpbmcgPSBmYWN0b3IoYWxsX2RhdGEkSGVhdGluZykNCmFsbF9kYXRhJEhlYXRpbmdRQyA9IGZhY3RvcihhbGxfZGF0YSRIZWF0aW5nUUMpDQphbGxfZGF0YSRDZW50cmFsQWlyID0gZmFjdG9yKGFsbF9kYXRhJENlbnRyYWxBaXIpDQphbGxfZGF0YSRQYXZlZERyaXZlID0gZmFjdG9yKGFsbF9kYXRhJFBhdmVkRHJpdmUpDQphbGxfZGF0YSRNb1NvbGQgPSBmYWN0b3IoYWxsX2RhdGEkTW9Tb2xkKQ0KYWxsX2RhdGEkWXJTb2xkID0gZmFjdG9yKGFsbF9kYXRhJFlyU29sZCkNCmFsbF9kYXRhJFNhbGVDb25kaXRpb24gPSBmYWN0b3IoYWxsX2RhdGEkU2FsZUNvbmRpdGlvbikNCmFsbF9kYXRhJEJzbXRGdWxsQmF0aCA9IGZhY3RvcihhbGxfZGF0YSRCc210RnVsbEJhdGgpDQphbGxfZGF0YSRCc210SGFsZkJhdGggPSBmYWN0b3IoYWxsX2RhdGEkQnNtdEhhbGZCYXRoKQ0KYWxsX2RhdGEkRnVsbEJhdGggPSBmYWN0b3IoYWxsX2RhdGEkRnVsbEJhdGgpDQphbGxfZGF0YSRIYWxmQmF0aCA9IGZhY3RvcihhbGxfZGF0YSRIYWxmQmF0aCkNCmBgYA0KDQpgYGB7cn0NCmhlYWQoYWxsX2RhdGEsIDIpDQojRGV0ZXJtaW5pbmcgc2tldyBvZiBlYWNoIG51bWVyaWMgdmFyaWFibGUNCg0KQ29sdW1uX2NsYXNzZXMgPC0gc2FwcGx5KG5hbWVzKGFsbF9kYXRhKSxmdW5jdGlvbih4KXtjbGFzcyhhbGxfZGF0YVtbeF1dKX0pDQpudW1lcmljX2NvbHVtbnMgPC1uYW1lcyhDb2x1bW5fY2xhc3Nlc1tDb2x1bW5fY2xhc3NlcyAhPSAiZmFjdG9yIiAmIENvbHVtbl9jbGFzc2VzICE9ICJjaGFyYWN0ZXIiXSkNCg0Kc2tldyA8LSBzYXBwbHkobnVtZXJpY19jb2x1bW5zLGZ1bmN0aW9uKHgpe3NrZXduZXNzKGFsbF9kYXRhW1t4XV0sbmEucm0gPSBUKX0pDQojIExldCB1cyBkZXRlcm1pbmUgYSB0aHJlc2hvbGQgc2tld25lc3MgYW5kIHRyYW5zZm9ybSBhbGwgdmFyaWFibGVzIGFib3ZlIHRoZSB0cmVzaG9sZC4NCnNrZXcgPC0gc2tld1tza2V3ID4gMC43NV0NCiMgdHJhbnNmb3JtIGV4Y2Vzc2l2ZWx5IHNrZXdlZCBmZWF0dXJlcyB3aXRoIGxvZyh4ICsgMSkNCmZvcih4IGluIG5hbWVzKHNrZXcpKQ0Kew0KICBhbGxfZGF0YVtbeF1dIDwtIGxvZyhhbGxfZGF0YVtbeF1dICsgMSkNCn0NCmdncGxvdChhbGxfZGF0YSwgbWFwcGluZyA9IGFlcyh4ID0gU2FsZVByaWNlKSkgKyBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiYmx1ZSIpDQoNCmBgYA0KDQojIyBGZWF0dXJlIEVuZ2luZWVyaW5nDQpIZXJlIGl0IGNhbiBiZSBzdWdnZXN0ZWQgdGhhdCB0b3RhbCBiYXNlbWVudCBzdXJmYWNlIGFyZWEsIDFzdCBmbG9vciBzdXJmYWNlIGFyZWEgYW5kIDJuZCBmbG9vciBzdXJmYWNlIGFyZWEgY2FuIGJlIGVxdWF0ZWQgdG8gdG90YWwgc3VyZmFjZSBhcmVhLiBCYXNlZCBvbiB0aGlzIFRvdGFsU0YgaXMgY3JlYXRlZC4NCmBgYHtyfQ0KI2xpbmVhciByZWxhdGlvbnNoaXAgYi9uIGdyb3VuZCBhbmQgdXBwZXIgZmxvb3JzDQphbGxfZGF0YSRUb3RhbFNGID0gYWxsX2RhdGEkVG90YWxCc210U0YgKyBhbGxfZGF0YSRYMXN0RmxyU0YgKyBhbGxfZGF0YSRYMm5kRmxyU0YNCg0KI2FsbF9kYXRhIDwtc3Vic2V0KGFsbF9kYXRhLCBzZWxlY3QgPSAtYyhsb2dfU2FsZVByaWNlKSkNCndoaWNoKGNvbFN1bXMoaXMubmEoYWxsX2RhdGEpKT4wKQ0KZGltKGFsbF9kYXRhKQ0KYGBgDQoNCiMjIERhdGEgUGFydGl0aW9uDQpgYGB7cn0NCnRyYWluXzEgPC0gYWxsX2RhdGFbYWxsX2RhdGEkaXNUcmFpbj09MSxdDQp0ZXN0XzEgPC0gYWxsX2RhdGFbYWxsX2RhdGEkaXNUcmFpbj09MCxdDQpkaW0odHJhaW5fMSkNCmRpbSh0ZXN0XzEpDQpkaW0oYWxsX2RhdGEpDQpgYGANCg0KDQpgYGB7cn0NCnRyYWluXzEgPSBzdWJzZXQodHJhaW5fMSwgc2VsZWN0ID0gLWMoSWQsIGlzVHJhaW4pKQ0KdGVzdF8xID0gc3Vic2V0KHRlc3RfMSwgc2VsZWN0ID0gLWMoSWQsIGlzVHJhaW4sIFNhbGVQcmljZSkpDQpzZXQuc2VlZCgxMDApDQpwYXJ0aXRpb24gPC0gY3JlYXRlRGF0YVBhcnRpdGlvbih0cmFpbl8xJFNhbGVQcmljZSwgcCA9IDAuODAsIGxpc3QgPSBGQUxTRSkNCnRyYWluLm0gPC0gdHJhaW5fMVtwYXJ0aXRpb24sIF0NCnRlc3QubSA8LSB0cmFpbl8xWy1wYXJ0aXRpb24sIF0NCg0KaGVhZCh0cmFpbi5tLCAzKQ0KYGBgDQoNCg0KIyBNb2RlbGluZw0KIyMgUmFuZG9tRm9yZXN0IE1vZGVsDQpgYGB7cn0NCiMjI0ZVTEwgTU9ERUwgIyMjDQptb2RlbDEgPSByYW5kb21Gb3Jlc3QoU2FsZVByaWNlIH4gLiwgZGF0YSA9IHRyYWluLm0pDQpzdW1tYXJ5KG1vZGVsMSkNCmBgYA0KIyMgUkYgTW9kZWwgUGxvdA0KYGBge3J9DQpwbG90KG1vZGVsMSkNCmBgYA0KIyMgVmFyaWFibGUgSW1wb3J0YW5jZQ0KYGBge3J9DQppbXAgPSBpbXBvcnRhbmNlKG1vZGVsMSkNCmltcA0KYGBgDQoNCiMjIyBQbG90IG9mIFZhcmlhYmxlIEltcG9ydGFuY2UNCmBgYHtyfQ0KdmFySW1wUGxvdChtb2RlbDEpDQpgYGANCmBgYHtyfQ0KIyBSTVNFIG9mIGZ1bGwgbW9kZWwgdXNpbmcgbG9nIG9mIFNhbGVQcmljZQ0KUk1TRSh0ZXN0Lm0kU2FsZVByaWNlLCBwcmVkaWN0KG1vZGVsMSwgbmV3ZGF0YSA9IHRlc3QubSkpDQpgYGANCg0KDQoNCiMjIFByZWRpY3Rpb24gd2l0aCB0aGUgZnVsbCBtb2RlbA0KDQpgYGB7cn0NCnByZWQgPSBwcmVkaWN0KG1vZGVsMSwgbmV3ZGF0YSA9IHRlc3QubSkNCmRmID0gZGF0YS5mcmFtZShQcmVkID0gZXhwKHByZWQpLCBUZXN0ID0gZXhwKHRlc3QubSRTYWxlUHJpY2UpKQ0KDQpgYGANCg0KIyMjIFByZWRpY3Rpb24gVlMgQWN0dWFsDQoNCmBgYHtyfQ0KaGVhZChkZiwgNSkNCmBgYA0KIyMjIFJNU0Ugb2YgdGhlIGZ1bGwgbW9kZWwgdXNpbmcgU2FsZVByaWNlIA0KYGBge3J9DQpzcXJ0KCBtZWFuKCAoZXhwKHByZWQpLWV4cCh0ZXN0Lm0kU2FsZVByaWNlKSkgXjIpICkNCmBgYA0KIyMgUmVkdWNlZCBNb2RlbA0KYGBge3J9DQp0cmFpbi5yZiA9IHRyYWluLm0NCm1vZGVsLnNlbGVjdC5yZiA9IHJhbmRvbUZvcmVzdChTYWxlUHJpY2UgfiBUb3RhbFNGICsgTVNab25pbmcgKyBMb3RBcmVhICsgTG90U2hhcGUgKyBOZWlnaGJvcmhvb2QgKyBDb25kaXRpb24xICtDb25kaXRpb24yKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxkZ1R5cGUgKyAgT3ZlcmFsbFF1YWwgK092ZXJhbGxDb25kICsgWWVhckJ1aWx0ICsgUm9vZk1hdGwgKyBFeHRlcmlvcjFzdCArIEV4dGVyQ29uZCsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZvdW5kYXRpb24gK0JzbXRRdWFsKyBLaXRjaGVuUXVhbCtGdWxsQmF0aCtCc210RXhwb3N1cmUrRmlyZXBsYWNlcysgU2FsZUNvbmRpdGlvbisNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENlbnRyYWxBaXIrUGF2ZWREcml2ZSxkYXRhID0gdHJhaW4ucmYpICANCnN1bW1hcnkobW9kZWwuc2VsZWN0LnJmKQ0KDQoNCiMjI21vZGVsIHBsb3QNCnBsb3QobW9kZWwuc2VsZWN0LnJmKQ0KDQpgYGANCiMjIyB2YXJpYWJsZSBvZiBpbXBvcnRhbmNlIFJlZHVjZWQgTW9kZWwNCmBgYHtyfQ0KaW1wID0gaW1wb3J0YW5jZShtb2RlbC5zZWxlY3QucmYpDQppbXANCmBgYA0KIyMjIFBsb3Qgb2YgVmFyaWFibGUgb2YgSW1wb3J0YW5jZQ0KYGBge3J9DQp2YXJJbXBQbG90KG1vZGVsLnNlbGVjdC5yZikNCmBgYA0KIyMjIFJNU0Ugb2YgdGhlIFJlZHVjZWQgbW9kZWwgdXNpbmcgbG9nIG9mIFNhbGVQcmljZQ0KYGBge3J9DQpSTVNFKHRlc3QubSRTYWxlUHJpY2UsIHByZWRpY3QobW9kZWwuc2VsZWN0LnJmLCBuZXdkYXRhID0gdGVzdC5tKSkNCmBgYA0KIyMjIFByZWRpY3Rpb24gdnMgQWN0dWFsIA0KYGBge3J9DQojIyMjI1ByZWRpY3Rpb24gd2l0aCB0aGUgcmVkdWNlZCBtb2RlbCMjIw0KcHJlZCA9IHByZWRpY3QobW9kZWwuc2VsZWN0LnJmLCBuZXdkYXRhID0gdGVzdC5tKQ0KDQojIyMjIyMjIw0KZGYgPSBkYXRhLmZyYW1lKFByZWQgPSBleHAocHJlZCksIFRlc3QgPSBleHAodGVzdC5tJFNhbGVQcmljZSkpDQpoZWFkKGRmLCA1KQ0KYGBgDQoNCg0KIyMjIFJNU0Ugb2YgdGhlIFJlZHVjZWQgbW9kZWwgdXNpbmcgU2FsZVByaWNlDQpgYGB7cn0NCnByZWQgPSBwcmVkaWN0KG1vZGVsLnNlbGVjdC5yZiwgbmV3ZGF0YSA9IHRlc3QubSkNCg0KDQpzcXJ0KCBtZWFuKCAoZXhwKHByZWQpLWV4cCh0ZXN0Lm0kU2FsZVByaWNlKSkgXjIpICkNCmBgYA0KR2l2ZW4gdGhlIFJNU0Ugb2YgdGhlIGZ1bGwgbW9kZWwgYW5kIHRoZSBSZWR1Y2UgbW9kZWwsaXQgY2FuIGJlIHN1Z2dlc3RlZCB0aGF0IHRoZSBmdWxsIG1vZGVsIHJldHVybnMgIGEgbG93ZXIgUk1TRSB3aGVuIGNvbXBhcmVkIHRvIHRoZSByZWR1Y2VkIG1vZGVsLCBoZW5jZSAgd2lsbCBjb3N0IGxlc3MgdG8gZGVwbG95Lg==