Decision Trees

In this section, we answer the research questions defined in the first section of the project using decision tree model. As mentioned in the previous Part, our dataset contains a continues target variable, therefore, the correct predictive regression modeling techniques for Decision Trees is regression trees. Predictors will be selected based on their correlation with target variable specified by the research question with limiting the features to only six highly correlated features. Finally, we will conduct validation and evaluation assessment techniques and find coefficient, r-squared, adjusted rsquare, and standard error for every model.

Pruning technique used to reduce the size of decision trees by removing sections of the tree that are non-critical and redundant in order improves predictive accuracy by the reduction of overfitting . 

The below steps will be conducts for each research question:

Load the dataset, slice attributes, and target attributes related to the research question

Create a Test-Train Split to train, evaluate and validate our model

Build a full Decision Trees and optimize it by pruning using the most optimum CP

Use model evaluation techniques such as RMSE,Rsquared and MAE

Use model validation techniques such as LOOCV, Cross validation and Repeated Cross Validation

First research question

In this section, we create a model for following research question “Which ML model has the best classification metrics to predict percentages that kids might end up family housing with two parents?”, the below highly correlated features are used for the model:

PctIlleg: percentage of kids born to never married

pctWPubAsst: percentage of households with public assistance income in 1989

PctPopUnderPov: percentage of people under the poverty level

medFamInc: median family income (differs from household income for non-family households)

medIncome: median household income

pctWInvInc: percentage of households with investment / rent income in 1989

PctKids2Par: percentage of kids in family housing with two parents

First step, Load the dataset, slice attributes, and target attributes related to the research question

#setwd("D:/Downloads")
#load the data 
data_corr <- read.csv("data_clean.csv",header = T) 
#Slice related attributes into df dataframe 
df <- data_corr[c("PctIlleg","pctWPubAsst","PctPopUnderPov","medFamInc","medIncome","pctWInvInc","PctKids2Par")] 
head(df)

Next, create a Test-Train Split to train, evaluate and validate our model, our test dataset is 20% of our entire dataset. In addition, seed configured to zero in order to replicate the same experiment.

# Test-Train Split 
install.packages('caTools') 
Installing package into 㤼㸱F:/Google Drive/E-book/R/win-library/4.0㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.0/caTools_1.18.1.zip'
Content type 'application/zip' length 317197 bytes (309 KB)
downloaded 309 KB
package ‘caTools’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\a7med\AppData\Local\Temp\Rtmp0QrMLi\downloaded_packages
library(caTools) 
set.seed(0) 
split =sample.split(df,SplitRatio = 0.8) 
train = subset(df,split == TRUE) 
test = subset(df,split == FALSE) 
head(train) 
head(test)

Next, Build a full Decision Trees and optimize it by pruning using the most optimum CP, however, we have to find the most optimum CP for pruning by building full Decision Trees with CP equal to zero.

#install required packages
install.packages('rpart')
Error in install.packages : Updating loaded packages
install.packages('rpart.plot')
Installing package into 㤼㸱F:/Google Drive/E-book/R/win-library/4.0㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.0/rpart.plot_3.0.9.zip'
Content type 'application/zip' length 1033977 bytes (1009 KB)
downloaded 1009 KB
package ‘rpart.plot’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\a7med\AppData\Local\Temp\Rtmp0QrMLi\downloaded_packages
install.packages("rpart")
Installing package into 㤼㸱F:/Google Drive/E-book/R/win-library/4.0㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.0/rpart_4.1-15.zip'
Content type 'application/zip' length 765690 bytes (747 KB)
downloaded 747 KB
package ‘rpart’ successfully unpacked and MD5 sums checked
Warning in install.packages :
  cannot remove prior installation of package ‘rpart’
Warning in install.packages :
  problem copying F:\Google Drive\E-book\R\win-library\4.0\00LOCK\rpart\libs\x64\rpart.dll to F:\Google Drive\E-book\R\win-library\4.0\rpart\libs\x64\rpart.dll: Permission denied
Warning in install.packages :
  restored ‘rpart’

The downloaded binary packages are in
    C:\Users\a7med\AppData\Local\Temp\Rtmp0QrMLi\downloaded_packages
library(rpart)
library(rpart.plot)
#Run regression tree model to find the most optimum cp  
fulltree <- rpart(formula = PctKids2Par~., data = train, control = rpart.control( cp = 0)) 
mincp <- fulltree$cptable[which.min(fulltree$cptable[,"xerror"]),"CP"] 
plotcp(fulltree)

From figure number 1, the most optimum CP is the lowest CP value that have the least relative error and tree size, which is equal to 0.0003, subsequently; we build a full Decision Trees and prune it using the optimum CP as shown in figure number 2.

#Tree Pruning 
prunedtree <- prune(fulltree, cp = mincp) 
rpart.plot(prunedtree, box.palette="RdBu", digits = -3) 

test$pruned <- predict(prunedtree, test, type = "vector") 

Finally, we use model evaluation techniques to find R2, RMSE, MAE and MSE2.

installed.packages('Metrics')
     Package LibPath Version Priority Depends Imports LinkingTo Suggests Enhances License License_is_FOSS
     License_restricts_use OS_type Archs MD5sum NeedsCompilation Built
library(Metrics) 

Attaching package: 㤼㸱Metrics㤼㸲

The following objects are masked from 㤼㸱package:caret㤼㸲:

    precision, recall
performance <- data.frame( R2 = R2(test$pruned, test$PctKids2Par), 
            RMSE = RMSE(test$pruned, test$PctKids2Par), 
            MAE = MAE(test$pruned, test$PctKids2Par), 
            MSE2 = mean((test$pruned - test$PctKids2Par)^2)) 
performance 

Next, we use validation techniques such as LOOCV, Cross validation and Repeated Cross Validation in order.

Leave-One-Out Cross-Validation

library(caret)
cp.grid <- expand.grid(.cp = (0:10)*0.001)  
# Leave one out cross validation - LOOCV 
# Define training control 
train.control.LOOCV <- trainControl(method = "LOOCV") 
# Train the model 
LOOCV <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.LOOCV,tuneGrid = cp.grid) 
# Summarize the results 
print(LOOCV)  
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Leave-One-Out Cross-Validation 
Summary of sample sizes: 1959, 1959, 1959, 1959, 1959, 1959, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.07357167  0.8712806  0.05598688
  0.001  0.07322123  0.8715098  0.05569811
  0.002  0.07672058  0.8588502  0.05876454
  0.003  0.07863310  0.8517203  0.06065240
  0.004  0.07917141  0.8496305  0.06113732
  0.005  0.08017425  0.8457918  0.06238850
  0.006  0.08132025  0.8413248  0.06350218
  0.007  0.08117448  0.8418868  0.06345920
  0.008  0.08318203  0.8339625  0.06545350
  0.009  0.08535404  0.8251825  0.06720654
  0.010  0.08535404  0.8251825  0.06720654

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.001.

K-fold cross-validation

Next, we use K-fold cross-validation, the technique used against a sequence of CP to find the most optimum. Ten folds is configured for technique.

# K-fold cross-validation 
# Define training control 
set.seed(123)  
train.control.cv <- trainControl(method = "cv", number = 10) 
# Train the model 
cv <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.cv,tuneGrid = cp.grid) 
# Summarize the results 
print(cv) 
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 1764, 1763, 1765, 1764, 1764, 1765, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.07458764  0.8682880  0.05583290
  0.001  0.07488059  0.8667450  0.05738251
  0.002  0.07767762  0.8568727  0.05984501
  0.003  0.07873371  0.8528414  0.06086148
  0.004  0.07937136  0.8505033  0.06153656
  0.005  0.08092711  0.8443967  0.06270297
  0.006  0.08191125  0.8404299  0.06376332
  0.007  0.08260000  0.8376132  0.06459001
  0.008  0.08508634  0.8276669  0.06654498
  0.009  0.08554216  0.8259448  0.06698376
  0.010  0.08587788  0.8245843  0.06725568

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.

Repeated K-fold cross-validation

Next, we use Repeated K-fold cross-validation, the technique used against a sequence of CP to find the most optimum. Ten folds with three repeats configured for technique.

# Repeated K-fold cross-validation 
set.seed(123) 
train.control.repeatedcv <- trainControl(method = "repeatedcv", number = 10, repeats = 3) 
# Train the model 
repeatedcv <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.repeatedcv,tuneGrid = cp.grid) 
# Summarize the results 
print(repeatedcv) 
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Cross-Validated (10 fold, repeated 3 times) 
Summary of sample sizes: 1764, 1763, 1765, 1764, 1764, 1765, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.07453701  0.8681612  0.05597149
  0.001  0.07459356  0.8668359  0.05718294
  0.002  0.07711535  0.8576849  0.05950917
  0.003  0.07845355  0.8526869  0.06078661
  0.004  0.07961102  0.8482006  0.06191358
  0.005  0.08093959  0.8430827  0.06304916
  0.006  0.08188199  0.8394141  0.06412822
  0.007  0.08237809  0.8373436  0.06457404
  0.008  0.08444024  0.8292835  0.06622773
  0.009  0.08510176  0.8268375  0.06679961
  0.010  0.08522702  0.8263016  0.06687264

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.

Second research question

In this section, we create a model for following research question “Which ML model has the best classification metrics to predict percentages that someone might depend on public assistance income?”, the below highly correlated features are used for the model:

PctYoungKids2Par: percent of kids 4 and under in two parent households

PctKids2Par: percentage of kids in family housing with two parents

pctWInvInc: percentage of households with investment / rent income in 1989

PctLess9thGrade: percentage of people 25 and over with less than a 9th grade education

PctNotHSGrad: percentage of people 25 and over that are not high school graduates

PctPopUnderPov: percentage of people under the poverty level

pctWPubAsst:percentage of households with public assistance income in 1989

First step, Load the dataset, slice attributes, and target attributes related to the research question

#load the data 
data_corr <- read.csv("data_clean.csv",header = T) 
#Slice related attributes into df dataframe 
df <- data_corr[c("PctYoungKids2Par","PctKids2Par","pctWInvInc","PctLess9thGrade","PctNotHSGrad","PctPopUnderPov","pctWPubAsst")] 
head(df) 

By repeating all the steps mentioned on the previous section, we use model evaluation techniques to find R2, RMSE, MAE and MSE2 and plot the Tree as shown in figure number 3.

#Tree Pruning 
prunedtree <- prune(fulltree, cp = mincp) 
rpart.plot(prunedtree, box.palette="RdBu", digits = -3) 

test$pruned <- predict(prunedtree, test, type = "vector") 
#Model performance metrics 
performance <- data.frame( R2 = R2(test$pruned, test$pctWPubAsst), 
                           RMSE = RMSE(test$pruned, test$pctWPubAsst), 
                           MAE = MAE(test$pruned, test$pctWPubAsst), 
                           MSE2 = mean((test$pruned - test$pctWPubAsst)^2)) 
performance 

Next, we use validation techniques such as LOOCV, Cross validation and Repeated Cross Validation in order. ## Leave-One-Out Cross-Validation

First validation technique is Leave-One-Out Cross-Validation, the technique used against a sequence of CP to find the most optimum.

cp.grid <- expand.grid(.cp = (0:10)*0.001)  
# Leave one out cross validation - LOOCV 
# Define training control 
train.control.LOOCV <- trainControl(method = "LOOCV") 
# Train the model 
LOOCV <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.LOOCV,tuneGrid = cp.grid) 

Repeated K-fold cross-validation

Next, we use Repeated K-fold cross-validation, the technique used against a sequence of CP to find the most optimum. Ten folds with three repeats configured for technique.

# Repeated K-fold cross-validation 
set.seed(123) 
train.control.repeatedcv <- trainControl(method = "repeatedcv", number = 10, repeats = 3) 
# Train the model 
repeatedcv <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.repeatedcv,tuneGrid = cp.grid) 
# Summarize the results 
print(repeatedcv)
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Cross-Validated (10 fold, repeated 3 times) 
Summary of sample sizes: 1764, 1763, 1765, 1764, 1764, 1765, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.07731842  0.8581638  0.05967035
  0.001  0.07555772  0.8634534  0.05878530
  0.002  0.07682919  0.8585964  0.06050429
  0.003  0.07767708  0.8556103  0.06136534
  0.004  0.07928180  0.8495035  0.06241600
  0.005  0.08069363  0.8441580  0.06354659
  0.006  0.08161399  0.8406257  0.06442809
  0.007  0.08187433  0.8395691  0.06466970
  0.008  0.08218811  0.8383946  0.06493020
  0.009  0.08336455  0.8337437  0.06625871
  0.010  0.08403381  0.8310294  0.06686190

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.001.

Third research question

In this section, we create a model for following research question “Which ML model has the best classification metrics to predict violent crimes per population?”, the below highly correlated features are used for the model:

PctKids2Par: percentage of kids in family housing with two parents

PctFam2Par: percentage of families (with kids) that are headed by two parents

PctYoungKids2Par: percent of kids 4 and under in two parent households

TotalPctDiv: percentage of population who are divorced

pctWPubAsst: percentage of households with public assistance income in 1989

PctIlleg: percentage of kids born to never married

ViolentCrimesPerPop: total number of violent crimes per 100K population GOAL attribute

First step, Load the dataset, slice attributes, and target attributes related to the research question

#load the data 
data_corr <- read.csv("data_clean.csv",header = T) 
#Slice related attributes into df dataframe 
df <- data_corr[c("PctKids2Par","PctFam2Par","PctYoungKids2Par","TotalPctDiv","pctWPubAsst","PctIlleg","ViolentCrimesPerPop")] 
head(df)

By repeating all the steps mentioned on the previous section, we use model evaluation techniques to find R2, RMSE, MAE and MSE2 and plot the Tree as shown in figure number 4.

#Tree Pruning 
prunedtree <- prune(fulltree, cp = mincp) 
rpart.plot(prunedtree, box.palette="RdBu", digits = -3) 

test$pruned <- predict(prunedtree, test, type = "vector") 
#Model performance metrics 
performance <- data.frame( #R2 = R2(test$pruned, test$ViolentCrimesPerPop),
                           RMSE = RMSE(test$pruned, test$ViolentCrimesPerPop),
                           MAE = MAE(test$pruned, test$ViolentCrimesPerPop),
                           MSE2 = mean((test$pruned - test$ViolentCrimesPerPop)^2))
performance

Next, we use validation techniques such as LOOCV, Cross validation and Repeated Cross Validation in order. ## Leave-One-Out Cross-Validation

First validation technique is Leave-One-Out Cross-Validation, the technique used against a sequence of CP to find the most optimum.

cp.grid <- expand.grid(.cp = (0:10)*0.001)  
# Leave one out cross validation - LOOCV 
# Define training control 
train.control.LOOCV <- trainControl(method = "LOOCV") 
# Train the model 
LOOCV <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.LOOCV,tuneGrid = cp.grid) 
# Summarize the results 
print(LOOCV) 
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Leave-One-Out Cross-Validation 
Summary of sample sizes: 1959, 1959, 1959, 1959, 1959, 1959, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.03418075  0.9720116  0.02637377
  0.001  0.03681265  0.9674737  0.02872839
  0.002  0.04196478  0.9577414  0.03340132
  0.003  0.04480233  0.9518414  0.03588543
  0.004  0.04707172  0.9468375  0.03737454
  0.005  0.04911222  0.9421246  0.03915869
  0.006  0.04920138  0.9419135  0.03924957
  0.007  0.04920138  0.9419135  0.03924957
  0.008  0.04920138  0.9419135  0.03924957
  0.009  0.04920138  0.9419135  0.03924957
  0.010  0.04920138  0.9419135  0.03924957

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.

K-fold cross-validation

Next, we use K-fold cross-validation, the technique used against a sequence of CP to find the most optimum. Ten folds is configured for technique.

# K-fold cross-validation 
# Define training control 
set.seed(123)  
train.control.cv <- trainControl(method = "cv", number = 10) 
# Train the model 
cv <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.cv,tuneGrid = cp.grid) 
# Summarize the results 
print(cv) 
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 1764, 1763, 1765, 1764, 1764, 1765, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.03384649  0.9725788  0.02632753
  0.001  0.03751814  0.9660019  0.02944487
  0.002  0.04191489  0.9576327  0.03341077
  0.003  0.04444036  0.9522942  0.03565194
  0.004  0.04670451  0.9475621  0.03722992
  0.005  0.04891898  0.9426378  0.03920383
  0.006  0.04897554  0.9425108  0.03920224
  0.007  0.04897554  0.9425108  0.03920224
  0.008  0.04897554  0.9425108  0.03920224
  0.009  0.04897554  0.9425108  0.03920224
  0.010  0.04897554  0.9425108  0.03920224

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.

Repeated K-fold cross-validation

Next, we use Repeated K-fold cross-validation, the technique used against a sequence of CP to find the most optimum. Ten folds with three repeats configured for technique.

# Repeated K-fold cross-validation 
set.seed(123) 
train.control.repeatedcv <- trainControl(method = "repeatedcv", number = 10, repeats = 3) 
# Train the model 
repeatedcv <- train(PctKids2Par~., data = df, method = "rpart",trControl = train.control.repeatedcv,tuneGrid = cp.grid) 
# Summarize the results 
print(repeatedcv) 
CART 

1960 samples
   6 predictor

No pre-processing
Resampling: Cross-Validated (10 fold, repeated 3 times) 
Summary of sample sizes: 1764, 1763, 1765, 1764, 1764, 1765, ... 
Resampling results across tuning parameters:

  cp     RMSE        Rsquared   MAE       
  0.000  0.03372565  0.9727262  0.02628385
  0.001  0.03743549  0.9662402  0.02943846
  0.002  0.04167924  0.9582385  0.03324330
  0.003  0.04434660  0.9526983  0.03545597
  0.004  0.04679384  0.9475879  0.03727969
  0.005  0.04855650  0.9435567  0.03881583
  0.006  0.04877678  0.9430230  0.03899143
  0.007  0.04877678  0.9430230  0.03899143
  0.008  0.04877678  0.9430230  0.03899143
  0.009  0.04877678  0.9430230  0.03899143
  0.010  0.04877678  0.9430230  0.03899143

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.

Conclusion

From the previous sections, we list down all our findings divided into two tables, validation and evaluation tables as shown in table number 1 and number 2, we can conclude the below:

Question 1: Leave-One-Out Cross Validation has the highest R2 and the lowest RMSE and MAE so it is suitable for first research question

Question 2: Leave-One-Out Cross Validation has the highest R2 and the lowest RMSE and MAE so it is suitable for first research question

Question 3: Repeated K-fold cross-validation has the highest R2 and the lowest RMSE and MAE so it is suitable for first research question

LS0tDQp0aXRsZTogIlJlZ3Jlc3Npb24gVHJlZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBEZWNpc2lvbiBUcmVlcw0KDQpJbiB0aGlzIHNlY3Rpb24sIHdlIGFuc3dlciB0aGUgcmVzZWFyY2ggcXVlc3Rpb25zIGRlZmluZWQgaW4gdGhlIGZpcnN0IHNlY3Rpb24gb2YgdGhlIHByb2plY3QgdXNpbmcgZGVjaXNpb24gdHJlZSBtb2RlbC4gQXMgbWVudGlvbmVkIGluIHRoZSBwcmV2aW91cyBQYXJ0LCBvdXIgZGF0YXNldCBjb250YWlucyBhIGNvbnRpbnVlcyB0YXJnZXQgdmFyaWFibGUsIHRoZXJlZm9yZSwgdGhlIGNvcnJlY3QgcHJlZGljdGl2ZSByZWdyZXNzaW9uIG1vZGVsaW5nIHRlY2huaXF1ZXMgZm9yIERlY2lzaW9uIFRyZWVzIGlzIHJlZ3Jlc3Npb24gdHJlZXMuIFByZWRpY3RvcnMgd2lsbCBiZSBzZWxlY3RlZCBiYXNlZCBvbiB0aGVpciBjb3JyZWxhdGlvbiB3aXRoIHRhcmdldCB2YXJpYWJsZSBzcGVjaWZpZWQgYnkgdGhlIHJlc2VhcmNoIHF1ZXN0aW9uIHdpdGggbGltaXRpbmcgdGhlIGZlYXR1cmVzIHRvIG9ubHkgc2l4IGhpZ2hseSBjb3JyZWxhdGVkIGZlYXR1cmVzLiBGaW5hbGx5LCB3ZSB3aWxsIGNvbmR1Y3QgdmFsaWRhdGlvbiBhbmQgZXZhbHVhdGlvbiBhc3Nlc3NtZW50IHRlY2huaXF1ZXMgYW5kIGZpbmQgY29lZmZpY2llbnQsIHItc3F1YXJlZCwgYWRqdXN0ZWQgcnNxdWFyZSwgYW5kIHN0YW5kYXJkIGVycm9yIGZvciBldmVyeSBtb2RlbC4gDQoNClBydW5pbmfigK90ZWNobmlxdWUgdXNlZCB0byByZWR1Y2UgdGhlIHNpemUgb2bigK9kZWNpc2lvbiB0cmVlc+KAr2J5IHJlbW92aW5nIHNlY3Rpb25zIG9mIHRoZSB0cmVlIHRoYXQgYXJlIG5vbi1jcml0aWNhbCBhbmQgcmVkdW5kYW50IGluIG9yZGVyIGltcHJvdmVzIHByZWRpY3RpdmXigK9hY2N1cmFjeeKAr2J5IHRoZSByZWR1Y3Rpb24gb2Ygb3ZlcmZpdHRpbmcgLuKAryANCg0KVGhlIGJlbG93IHN0ZXBzIHdpbGwgYmUgY29uZHVjdHMgZm9yIGVhY2ggcmVzZWFyY2ggcXVlc3Rpb246IA0KDQpMb2FkIHRoZSBkYXRhc2V0LCBzbGljZSBhdHRyaWJ1dGVzLCBhbmQgdGFyZ2V0IGF0dHJpYnV0ZXMgcmVsYXRlZCB0byB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gIA0KDQpDcmVhdGUgYSBUZXN0LVRyYWluIFNwbGl0IHRvIHRyYWluLCBldmFsdWF0ZSBhbmQgdmFsaWRhdGUgb3VyIG1vZGVsIA0KDQpCdWlsZCBhIGZ1bGwgRGVjaXNpb24gVHJlZXMgYW5kIG9wdGltaXplIGl0IGJ5IHBydW5pbmcgdXNpbmcgdGhlIG1vc3Qgb3B0aW11bSBDUCANCg0KVXNlIG1vZGVsIGV2YWx1YXRpb24gdGVjaG5pcXVlcyBzdWNoIGFzIFJNU0UsUnNxdWFyZWQgYW5kIE1BRSANCg0KVXNlIG1vZGVsIHZhbGlkYXRpb24gdGVjaG5pcXVlcyBzdWNoIGFzIExPT0NWLCBDcm9zcyB2YWxpZGF0aW9uIGFuZCBSZXBlYXRlZCBDcm9zcyBWYWxpZGF0aW9uIA0KDQpGaXJzdCByZXNlYXJjaCBxdWVzdGlvbiANCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBjcmVhdGUgYSBtb2RlbCBmb3IgZm9sbG93aW5nIHJlc2VhcmNoIHF1ZXN0aW9uIOKAnFdoaWNoIE1MIG1vZGVsIGhhcyB0aGUgYmVzdCBjbGFzc2lmaWNhdGlvbiBtZXRyaWNzIHRvIHByZWRpY3QgcGVyY2VudGFnZXMgdGhhdCBraWRzIG1pZ2h0IGVuZCB1cCBmYW1pbHkgaG91c2luZyB3aXRoIHR3byBwYXJlbnRzP+KAnSwgdGhlIGJlbG93IGhpZ2hseSBjb3JyZWxhdGVkIGZlYXR1cmVzIGFyZSB1c2VkIGZvciB0aGUgbW9kZWw6IA0KDQpQY3RJbGxlZzogcGVyY2VudGFnZSBvZiBraWRzIGJvcm4gdG8gbmV2ZXIgbWFycmllZCAgDQoNCnBjdFdQdWJBc3N0OiBwZXJjZW50YWdlIG9mIGhvdXNlaG9sZHMgd2l0aCBwdWJsaWMgYXNzaXN0YW5jZSBpbmNvbWUgaW4gMTk4OSAgDQoNClBjdFBvcFVuZGVyUG92OiBwZXJjZW50YWdlIG9mIHBlb3BsZSB1bmRlciB0aGUgcG92ZXJ0eSBsZXZlbCANCg0KbWVkRmFtSW5jOiBtZWRpYW4gZmFtaWx5IGluY29tZSAoZGlmZmVycyBmcm9tIGhvdXNlaG9sZCBpbmNvbWUgZm9yIG5vbi1mYW1pbHkgaG91c2Vob2xkcykgIA0KDQptZWRJbmNvbWU6IG1lZGlhbiBob3VzZWhvbGQgaW5jb21lICANCg0KcGN0V0ludkluYzogcGVyY2VudGFnZSBvZiBob3VzZWhvbGRzIHdpdGggaW52ZXN0bWVudCAvIHJlbnQgaW5jb21lIGluIDE5ODkgDQoNClBjdEtpZHMyUGFyOiBwZXJjZW50YWdlIG9mIGtpZHMgaW4gZmFtaWx5IGhvdXNpbmcgd2l0aCB0d28gcGFyZW50cyANCg0KRmlyc3Qgc3RlcCwgTG9hZCB0aGUgZGF0YXNldCwgc2xpY2UgYXR0cmlidXRlcywgYW5kIHRhcmdldCBhdHRyaWJ1dGVzIHJlbGF0ZWQgdG8gdGhlIHJlc2VhcmNoIHF1ZXN0aW9uIA0KDQoNCmBgYHtyfQ0KI3NldHdkKCJEOi9Eb3dubG9hZHMiKQ0KI2xvYWQgdGhlIGRhdGEgDQpkYXRhX2NvcnIgPC0gcmVhZC5jc3YoImRhdGFfY2xlYW4uY3N2IixoZWFkZXIgPSBUKSANCiNTbGljZSByZWxhdGVkIGF0dHJpYnV0ZXMgaW50byBkZiBkYXRhZnJhbWUgDQpkZiA8LSBkYXRhX2NvcnJbYygiUGN0SWxsZWciLCJwY3RXUHViQXNzdCIsIlBjdFBvcFVuZGVyUG92IiwibWVkRmFtSW5jIiwibWVkSW5jb21lIiwicGN0V0ludkluYyIsIlBjdEtpZHMyUGFyIildIA0KaGVhZChkZikNCmBgYA0KDQpOZXh0LCBjcmVhdGUgYSBUZXN0LVRyYWluIFNwbGl0IHRvIHRyYWluLCBldmFsdWF0ZSBhbmQgdmFsaWRhdGUgb3VyIG1vZGVsLCBvdXIgdGVzdCBkYXRhc2V0IGlzIDIwJSBvZiBvdXIgZW50aXJlIGRhdGFzZXQuIEluIGFkZGl0aW9uLCBzZWVkIGNvbmZpZ3VyZWQgdG8gemVybyBpbiBvcmRlciB0byByZXBsaWNhdGUgdGhlIHNhbWUgZXhwZXJpbWVudC4gDQoNCmBgYHtyfQ0KIyBUZXN0LVRyYWluIFNwbGl0IA0KaW5zdGFsbC5wYWNrYWdlcygnY2FUb29scycpIA0KbGlicmFyeShjYVRvb2xzKSANCnNldC5zZWVkKDApIA0Kc3BsaXQgPXNhbXBsZS5zcGxpdChkZixTcGxpdFJhdGlvID0gMC44KSANCnRyYWluID0gc3Vic2V0KGRmLHNwbGl0ID09IFRSVUUpIA0KdGVzdCA9IHN1YnNldChkZixzcGxpdCA9PSBGQUxTRSkgDQpoZWFkKHRyYWluKSANCmhlYWQodGVzdCkNCmBgYA0KDQpOZXh0LCBCdWlsZCBhIGZ1bGwgRGVjaXNpb24gVHJlZXMgYW5kIG9wdGltaXplIGl0IGJ5IHBydW5pbmcgdXNpbmcgdGhlIG1vc3Qgb3B0aW11bSBDUCwgaG93ZXZlciwgd2UgaGF2ZSB0byBmaW5kIHRoZSBtb3N0IG9wdGltdW0gQ1AgZm9yIHBydW5pbmcgYnkgYnVpbGRpbmcgZnVsbCBEZWNpc2lvbiBUcmVlcyB3aXRoIENQIGVxdWFsIHRvIHplcm8uIA0KDQpgYGB7cn0NCiNpbnN0YWxsIHJlcXVpcmVkIHBhY2thZ2VzDQppbnN0YWxsLnBhY2thZ2VzKCdycGFydCcpDQppbnN0YWxsLnBhY2thZ2VzKCdycGFydC5wbG90JykNCmluc3RhbGwucGFja2FnZXMoJ2NhcmV0JykNCmxpYnJhcnkocnBhcnQpDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQpsaWJyYXJ5KGNhcmV0KQ0KI1J1biByZWdyZXNzaW9uIHRyZWUgbW9kZWwgdG8gZmluZCB0aGUgbW9zdCBvcHRpbXVtIGNwICANCmZ1bGx0cmVlIDwtIHJwYXJ0KGZvcm11bGEgPSBQY3RLaWRzMlBhcn4uLCBkYXRhID0gdHJhaW4sIGNvbnRyb2wgPSBycGFydC5jb250cm9sKCBjcCA9IDApKSANCm1pbmNwIDwtIGZ1bGx0cmVlJGNwdGFibGVbd2hpY2gubWluKGZ1bGx0cmVlJGNwdGFibGVbLCJ4ZXJyb3IiXSksIkNQIl0gDQpwbG90Y3AoZnVsbHRyZWUpDQpgYGANCkZyb20gZmlndXJlIG51bWJlciAxLCB0aGUgbW9zdCBvcHRpbXVtIENQIGlzIHRoZSBsb3dlc3QgQ1AgdmFsdWUgdGhhdCBoYXZlIHRoZSBsZWFzdCByZWxhdGl2ZSBlcnJvciBhbmQgdHJlZSBzaXplLCB3aGljaCBpcyBlcXVhbCB0byAwLjAwMDMsIHN1YnNlcXVlbnRseTsgd2UgYnVpbGQgYSBmdWxsIERlY2lzaW9uIFRyZWVzIGFuZCBwcnVuZSBpdCB1c2luZyB0aGUgb3B0aW11bSBDUCBhcyBzaG93biBpbiBmaWd1cmUgbnVtYmVyIDIuIA0KDQpgYGB7cn0NCiNUcmVlIFBydW5pbmcgDQpwcnVuZWR0cmVlIDwtIHBydW5lKGZ1bGx0cmVlLCBjcCA9IG1pbmNwKSANCnJwYXJ0LnBsb3QocHJ1bmVkdHJlZSwgYm94LnBhbGV0dGU9IlJkQnUiLCBkaWdpdHMgPSAtMykgDQp0ZXN0JHBydW5lZCA8LSBwcmVkaWN0KHBydW5lZHRyZWUsIHRlc3QsIHR5cGUgPSAidmVjdG9yIikgDQpgYGANCkZpbmFsbHksIHdlIHVzZSBtb2RlbCBldmFsdWF0aW9uIHRlY2huaXF1ZXMgdG8gZmluZCBSMiwgUk1TRSwgTUFFIGFuZCBNU0UyLiANCg0KYGBge3J9DQppbnN0YWxsZWQucGFja2FnZXMoJ01ldHJpY3MnKQ0KbGlicmFyeShNZXRyaWNzKSANCnBlcmZvcm1hbmNlIDwtIGRhdGEuZnJhbWUoIFIyID0gUjIodGVzdCRwcnVuZWQsIHRlc3QkUGN0S2lkczJQYXIpLCANCiAgICAgICAgICAgIFJNU0UgPSBSTVNFKHRlc3QkcHJ1bmVkLCB0ZXN0JFBjdEtpZHMyUGFyKSwgDQogICAgICAgICAgICBNQUUgPSBNQUUodGVzdCRwcnVuZWQsIHRlc3QkUGN0S2lkczJQYXIpLCANCiAgICAgICAgICAgIE1TRTIgPSBtZWFuKCh0ZXN0JHBydW5lZCAtIHRlc3QkUGN0S2lkczJQYXIpXjIpKSANCnBlcmZvcm1hbmNlIA0KYGBgDQpOZXh0LCB3ZSB1c2UgdmFsaWRhdGlvbiB0ZWNobmlxdWVzIHN1Y2ggYXMgTE9PQ1YsIENyb3NzIHZhbGlkYXRpb24gYW5kIFJlcGVhdGVkIENyb3NzIFZhbGlkYXRpb24gaW4gb3JkZXIuIA0KDQojIyBMZWF2ZS1PbmUtT3V0IENyb3NzLVZhbGlkYXRpb24NCg0KYGBge3J9DQpsaWJyYXJ5KGNhcmV0KQ0KY3AuZ3JpZCA8LSBleHBhbmQuZ3JpZCguY3AgPSAoMDoxMCkqMC4wMDEpICANCiMgTGVhdmUgb25lIG91dCBjcm9zcyB2YWxpZGF0aW9uIC0gTE9PQ1YgDQojIERlZmluZSB0cmFpbmluZyBjb250cm9sIA0KdHJhaW4uY29udHJvbC5MT09DViA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gIkxPT0NWIikgDQojIFRyYWluIHRoZSBtb2RlbCANCkxPT0NWIDwtIHRyYWluKFBjdEtpZHMyUGFyfi4sIGRhdGEgPSBkZiwgbWV0aG9kID0gInJwYXJ0Iix0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sLkxPT0NWLHR1bmVHcmlkID0gY3AuZ3JpZCkgDQojIFN1bW1hcml6ZSB0aGUgcmVzdWx0cyANCnByaW50KExPT0NWKSAgDQpgYGANCiMjIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uIA0KDQpOZXh0LCB3ZSB1c2UgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24sIHRoZSB0ZWNobmlxdWUgdXNlZCBhZ2FpbnN0IGEgc2VxdWVuY2Ugb2YgQ1AgdG8gZmluZCB0aGUgbW9zdCBvcHRpbXVtLiBUZW4gZm9sZHMgaXMgY29uZmlndXJlZCBmb3IgdGVjaG5pcXVlLiANCg0KYGBge3J9DQojIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uIA0KIyBEZWZpbmUgdHJhaW5pbmcgY29udHJvbCANCnNldC5zZWVkKDEyMykgIA0KdHJhaW4uY29udHJvbC5jdiA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gMTApIA0KIyBUcmFpbiB0aGUgbW9kZWwgDQpjdiA8LSB0cmFpbihQY3RLaWRzMlBhcn4uLCBkYXRhID0gZGYsIG1ldGhvZCA9ICJycGFydCIsdHJDb250cm9sID0gdHJhaW4uY29udHJvbC5jdix0dW5lR3JpZCA9IGNwLmdyaWQpIA0KIyBTdW1tYXJpemUgdGhlIHJlc3VsdHMgDQpwcmludChjdikgDQpgYGANCiMjIFJlcGVhdGVkIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uIA0KDQpOZXh0LCB3ZSB1c2UgUmVwZWF0ZWQgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24sIHRoZSB0ZWNobmlxdWUgdXNlZCBhZ2FpbnN0IGEgc2VxdWVuY2Ugb2YgQ1AgdG8gZmluZCB0aGUgbW9zdCBvcHRpbXVtLiBUZW4gZm9sZHMgd2l0aCB0aHJlZSByZXBlYXRzIGNvbmZpZ3VyZWQgZm9yIHRlY2huaXF1ZS4gDQpgYGB7cn0NCiMgUmVwZWF0ZWQgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24gDQpzZXQuc2VlZCgxMjMpIA0KdHJhaW4uY29udHJvbC5yZXBlYXRlZGN2IDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAicmVwZWF0ZWRjdiIsIG51bWJlciA9IDEwLCByZXBlYXRzID0gMykgDQojIFRyYWluIHRoZSBtb2RlbCANCnJlcGVhdGVkY3YgPC0gdHJhaW4oUGN0S2lkczJQYXJ+LiwgZGF0YSA9IGRmLCBtZXRob2QgPSAicnBhcnQiLHRyQ29udHJvbCA9IHRyYWluLmNvbnRyb2wucmVwZWF0ZWRjdix0dW5lR3JpZCA9IGNwLmdyaWQpIA0KIyBTdW1tYXJpemUgdGhlIHJlc3VsdHMgDQpwcmludChyZXBlYXRlZGN2KSANCmBgYA0KIyMgU2Vjb25kIHJlc2VhcmNoIHF1ZXN0aW9uIA0KDQpJbiB0aGlzIHNlY3Rpb24sIHdlIGNyZWF0ZSBhIG1vZGVsIGZvciBmb2xsb3dpbmcgcmVzZWFyY2ggcXVlc3Rpb24g4oCcV2hpY2ggTUwgbW9kZWwgaGFzIHRoZSBiZXN0IGNsYXNzaWZpY2F0aW9uIG1ldHJpY3MgdG8gcHJlZGljdCBwZXJjZW50YWdlcyB0aGF0IHNvbWVvbmUgbWlnaHQgZGVwZW5kIG9uIHB1YmxpYyBhc3Npc3RhbmNlIGluY29tZT/igJ0sIHRoZSBiZWxvdyBoaWdobHkgY29ycmVsYXRlZCBmZWF0dXJlcyBhcmUgdXNlZCBmb3IgdGhlIG1vZGVsOiANCg0KUGN0WW91bmdLaWRzMlBhcjogcGVyY2VudCBvZiBraWRzIDQgYW5kIHVuZGVyIGluIHR3byBwYXJlbnQgaG91c2Vob2xkcyAgDQoNClBjdEtpZHMyUGFyOiBwZXJjZW50YWdlIG9mIGtpZHMgaW4gZmFtaWx5IGhvdXNpbmcgd2l0aCB0d28gcGFyZW50cyAgDQoNCnBjdFdJbnZJbmM6IHBlcmNlbnRhZ2Ugb2YgaG91c2Vob2xkcyB3aXRoIGludmVzdG1lbnQgLyByZW50IGluY29tZSBpbiAxOTg5IA0KDQpQY3RMZXNzOXRoR3JhZGU6IHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIDI1IGFuZCBvdmVyIHdpdGggbGVzcyB0aGFuIGEgOXRoIGdyYWRlIGVkdWNhdGlvbiAgDQoNClBjdE5vdEhTR3JhZDogcGVyY2VudGFnZSBvZiBwZW9wbGUgMjUgYW5kIG92ZXIgdGhhdCBhcmUgbm90IGhpZ2ggc2Nob29sIGdyYWR1YXRlcyAgDQoNClBjdFBvcFVuZGVyUG92OiBwZXJjZW50YWdlIG9mIHBlb3BsZSB1bmRlciB0aGUgcG92ZXJ0eSBsZXZlbCAgDQoNCnBjdFdQdWJBc3N0OnBlcmNlbnRhZ2Ugb2YgaG91c2Vob2xkcyB3aXRoIHB1YmxpYyBhc3Npc3RhbmNlIGluY29tZSBpbiAxOTg5IA0KDQpGaXJzdCBzdGVwLCBMb2FkIHRoZSBkYXRhc2V0LCBzbGljZSBhdHRyaWJ1dGVzLCBhbmQgdGFyZ2V0IGF0dHJpYnV0ZXMgcmVsYXRlZCB0byB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gDQpgYGB7cn0NCiNsb2FkIHRoZSBkYXRhIA0KZGF0YV9jb3JyIDwtIHJlYWQuY3N2KCJkYXRhX2NsZWFuLmNzdiIsaGVhZGVyID0gVCkgDQojU2xpY2UgcmVsYXRlZCBhdHRyaWJ1dGVzIGludG8gZGYgZGF0YWZyYW1lIA0KZGYgPC0gZGF0YV9jb3JyW2MoIlBjdFlvdW5nS2lkczJQYXIiLCJQY3RLaWRzMlBhciIsInBjdFdJbnZJbmMiLCJQY3RMZXNzOXRoR3JhZGUiLCJQY3ROb3RIU0dyYWQiLCJQY3RQb3BVbmRlclBvdiIsInBjdFdQdWJBc3N0IildIA0KaGVhZChkZikgDQpgYGANCkJ5IHJlcGVhdGluZyBhbGwgdGhlIHN0ZXBzIG1lbnRpb25lZCBvbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgd2UgdXNlIG1vZGVsIGV2YWx1YXRpb24gdGVjaG5pcXVlcyB0byBmaW5kIFIyLCBSTVNFLCBNQUUgYW5kIE1TRTIgYW5kIHBsb3QgdGhlIFRyZWUgYXMgc2hvd24gaW4gZmlndXJlIG51bWJlciAzLg0KDQpgYGB7cn0NCiNUcmVlIFBydW5pbmcgDQpwcnVuZWR0cmVlIDwtIHBydW5lKGZ1bGx0cmVlLCBjcCA9IG1pbmNwKSANCnJwYXJ0LnBsb3QocHJ1bmVkdHJlZSwgYm94LnBhbGV0dGU9IlJkQnUiLCBkaWdpdHMgPSAtMykgDQp0ZXN0JHBydW5lZCA8LSBwcmVkaWN0KHBydW5lZHRyZWUsIHRlc3QsIHR5cGUgPSAidmVjdG9yIikgDQpgYGANCmBgYHtyfQ0KI01vZGVsIHBlcmZvcm1hbmNlIG1ldHJpY3MgDQpwZXJmb3JtYW5jZSA8LSBkYXRhLmZyYW1lKCBSMiA9IFIyKHRlc3QkcHJ1bmVkLCB0ZXN0JHBjdFdQdWJBc3N0KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBSTVNFID0gUk1TRSh0ZXN0JHBydW5lZCwgdGVzdCRwY3RXUHViQXNzdCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgTUFFID0gTUFFKHRlc3QkcHJ1bmVkLCB0ZXN0JHBjdFdQdWJBc3N0KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBNU0UyID0gbWVhbigodGVzdCRwcnVuZWQgLSB0ZXN0JHBjdFdQdWJBc3N0KV4yKSkgDQpwZXJmb3JtYW5jZSANCmBgYA0KTmV4dCwgd2UgdXNlIHZhbGlkYXRpb24gdGVjaG5pcXVlcyBzdWNoIGFzIExPT0NWLCBDcm9zcyB2YWxpZGF0aW9uIGFuZCBSZXBlYXRlZCBDcm9zcyBWYWxpZGF0aW9uIGluIG9yZGVyLiANCiMjIExlYXZlLU9uZS1PdXQgQ3Jvc3MtVmFsaWRhdGlvbiANCg0KRmlyc3QgdmFsaWRhdGlvbiB0ZWNobmlxdWUgaXMgTGVhdmUtT25lLU91dCBDcm9zcy1WYWxpZGF0aW9uLCB0aGUgdGVjaG5pcXVlIHVzZWQgYWdhaW5zdCBhIHNlcXVlbmNlIG9mIENQIHRvIGZpbmQgdGhlIG1vc3Qgb3B0aW11bS4gDQoNCmBgYHtyfQ0KY3AuZ3JpZCA8LSBleHBhbmQuZ3JpZCguY3AgPSAoMDoxMCkqMC4wMDEpICANCiMgTGVhdmUgb25lIG91dCBjcm9zcyB2YWxpZGF0aW9uIC0gTE9PQ1YgDQojIERlZmluZSB0cmFpbmluZyBjb250cm9sIA0KdHJhaW4uY29udHJvbC5MT09DViA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gIkxPT0NWIikgDQojIFRyYWluIHRoZSBtb2RlbCANCkxPT0NWIDwtIHRyYWluKFBjdEtpZHMyUGFyfi4sIGRhdGEgPSBkZiwgbWV0aG9kID0gInJwYXJ0Iix0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sLkxPT0NWLHR1bmVHcmlkID0gY3AuZ3JpZCkgDQojIFN1bW1hcml6ZSB0aGUgcmVzdWx0cyANCnByaW50KExPT0NWKSAgDQpgYGANCg0KIyMgUmVwZWF0ZWQgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24NCg0KTmV4dCwgd2UgdXNlIFJlcGVhdGVkIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uLCB0aGUgdGVjaG5pcXVlIHVzZWQgYWdhaW5zdCBhIHNlcXVlbmNlIG9mIENQIHRvIGZpbmQgdGhlIG1vc3Qgb3B0aW11bS4gVGVuIGZvbGRzIHdpdGggdGhyZWUgcmVwZWF0cyBjb25maWd1cmVkIGZvciB0ZWNobmlxdWUuIA0KDQpgYGB7cn0NCiMgUmVwZWF0ZWQgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24gDQpzZXQuc2VlZCgxMjMpIA0KdHJhaW4uY29udHJvbC5yZXBlYXRlZGN2IDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAicmVwZWF0ZWRjdiIsIG51bWJlciA9IDEwLCByZXBlYXRzID0gMykgDQojIFRyYWluIHRoZSBtb2RlbCANCnJlcGVhdGVkY3YgPC0gdHJhaW4oUGN0S2lkczJQYXJ+LiwgZGF0YSA9IGRmLCBtZXRob2QgPSAicnBhcnQiLHRyQ29udHJvbCA9IHRyYWluLmNvbnRyb2wucmVwZWF0ZWRjdix0dW5lR3JpZCA9IGNwLmdyaWQpIA0KIyBTdW1tYXJpemUgdGhlIHJlc3VsdHMgDQpwcmludChyZXBlYXRlZGN2KQ0KYGBgDQojIyBUaGlyZCByZXNlYXJjaCBxdWVzdGlvbg0KDQpJbiB0aGlzIHNlY3Rpb24sIHdlIGNyZWF0ZSBhIG1vZGVsIGZvciBmb2xsb3dpbmcgcmVzZWFyY2ggcXVlc3Rpb24g4oCcV2hpY2ggTUwgbW9kZWwgaGFzIHRoZSBiZXN0IGNsYXNzaWZpY2F0aW9uIG1ldHJpY3MgdG8gcHJlZGljdCB2aW9sZW50IGNyaW1lcyBwZXIgcG9wdWxhdGlvbj/igJ0sIHRoZSBiZWxvdyBoaWdobHkgY29ycmVsYXRlZCBmZWF0dXJlcyBhcmUgdXNlZCBmb3IgdGhlIG1vZGVsOiANCg0KUGN0S2lkczJQYXI6IHBlcmNlbnRhZ2Ugb2Yga2lkcyBpbiBmYW1pbHkgaG91c2luZyB3aXRoIHR3byBwYXJlbnRzICANCg0KUGN0RmFtMlBhcjogcGVyY2VudGFnZSBvZiBmYW1pbGllcyAod2l0aCBraWRzKSB0aGF0IGFyZSBoZWFkZWQgYnkgdHdvIHBhcmVudHMgIA0KDQpQY3RZb3VuZ0tpZHMyUGFyOiBwZXJjZW50IG9mIGtpZHMgNCBhbmQgdW5kZXIgaW4gdHdvIHBhcmVudCBob3VzZWhvbGRzICANCg0KVG90YWxQY3REaXY6IHBlcmNlbnRhZ2Ugb2YgcG9wdWxhdGlvbiB3aG8gYXJlIGRpdm9yY2VkICANCg0KcGN0V1B1YkFzc3Q6IHBlcmNlbnRhZ2Ugb2YgaG91c2Vob2xkcyB3aXRoIHB1YmxpYyBhc3Npc3RhbmNlIGluY29tZSBpbiAxOTg5ICANCg0KUGN0SWxsZWc6IHBlcmNlbnRhZ2Ugb2Yga2lkcyBib3JuIHRvIG5ldmVyIG1hcnJpZWQgDQoNClZpb2xlbnRDcmltZXNQZXJQb3A6IHRvdGFsIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgMTAwSyBwb3B1bGF0aW9uIEdPQUwgYXR0cmlidXRlIA0KDQpGaXJzdCBzdGVwLCBMb2FkIHRoZSBkYXRhc2V0LCBzbGljZSBhdHRyaWJ1dGVzLCBhbmQgdGFyZ2V0IGF0dHJpYnV0ZXMgcmVsYXRlZCB0byB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gDQoNCmBgYHtyfQ0KI2xvYWQgdGhlIGRhdGEgDQpkYXRhX2NvcnIgPC0gcmVhZC5jc3YoImRhdGFfY2xlYW4uY3N2IixoZWFkZXIgPSBUKSANCiNTbGljZSByZWxhdGVkIGF0dHJpYnV0ZXMgaW50byBkZiBkYXRhZnJhbWUgDQpkZiA8LSBkYXRhX2NvcnJbYygiUGN0S2lkczJQYXIiLCJQY3RGYW0yUGFyIiwiUGN0WW91bmdLaWRzMlBhciIsIlRvdGFsUGN0RGl2IiwicGN0V1B1YkFzc3QiLCJQY3RJbGxlZyIsIlZpb2xlbnRDcmltZXNQZXJQb3AiKV0gDQpoZWFkKGRmKQ0KYGBgDQpCeSByZXBlYXRpbmcgYWxsIHRoZSBzdGVwcyBtZW50aW9uZWQgb24gdGhlIHByZXZpb3VzIHNlY3Rpb24sIHdlIHVzZSBtb2RlbCBldmFsdWF0aW9uIHRlY2huaXF1ZXMgdG8gZmluZCBSMiwgUk1TRSwgTUFFIGFuZCBNU0UyIGFuZCBwbG90IHRoZSBUcmVlIGFzIHNob3duIGluIGZpZ3VyZSBudW1iZXIgNC4gDQoNCmBgYHtyfQ0KI1RyZWUgUHJ1bmluZyANCnBydW5lZHRyZWUgPC0gcHJ1bmUoZnVsbHRyZWUsIGNwID0gbWluY3ApIA0KcnBhcnQucGxvdChwcnVuZWR0cmVlLCBib3gucGFsZXR0ZT0iUmRCdSIsIGRpZ2l0cyA9IC0zKSANCnRlc3QkcHJ1bmVkIDwtIHByZWRpY3QocHJ1bmVkdHJlZSwgdGVzdCwgdHlwZSA9ICJ2ZWN0b3IiKSANCmBgYA0KYGBge3J9DQojTW9kZWwgcGVyZm9ybWFuY2UgbWV0cmljcyANCnBlcmZvcm1hbmNlIDwtIGRhdGEuZnJhbWUoICNSMiA9IFIyKHRlc3QkcHJ1bmVkLCB0ZXN0JFZpb2xlbnRDcmltZXNQZXJQb3ApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgUk1TRSA9IFJNU0UodGVzdCRwcnVuZWQsIHRlc3QkVmlvbGVudENyaW1lc1BlclBvcCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBNQUUgPSBNQUUodGVzdCRwcnVuZWQsIHRlc3QkVmlvbGVudENyaW1lc1BlclBvcCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBNU0UyID0gbWVhbigodGVzdCRwcnVuZWQgLSB0ZXN0JFZpb2xlbnRDcmltZXNQZXJQb3ApXjIpKQ0KcGVyZm9ybWFuY2UNCmBgYA0KTmV4dCwgd2UgdXNlIHZhbGlkYXRpb24gdGVjaG5pcXVlcyBzdWNoIGFzIExPT0NWLCBDcm9zcyB2YWxpZGF0aW9uIGFuZCBSZXBlYXRlZCBDcm9zcyBWYWxpZGF0aW9uIGluIG9yZGVyLg0KIyMgTGVhdmUtT25lLU91dCBDcm9zcy1WYWxpZGF0aW9uIA0KDQpGaXJzdCB2YWxpZGF0aW9uIHRlY2huaXF1ZSBpcyBMZWF2ZS1PbmUtT3V0IENyb3NzLVZhbGlkYXRpb24sIHRoZSB0ZWNobmlxdWUgdXNlZCBhZ2FpbnN0IGEgc2VxdWVuY2Ugb2YgQ1AgdG8gZmluZCB0aGUgbW9zdCBvcHRpbXVtLiANCmBgYHtyfQ0KY3AuZ3JpZCA8LSBleHBhbmQuZ3JpZCguY3AgPSAoMDoxMCkqMC4wMDEpICANCiMgTGVhdmUgb25lIG91dCBjcm9zcyB2YWxpZGF0aW9uIC0gTE9PQ1YgDQojIERlZmluZSB0cmFpbmluZyBjb250cm9sIA0KdHJhaW4uY29udHJvbC5MT09DViA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gIkxPT0NWIikgDQojIFRyYWluIHRoZSBtb2RlbCANCkxPT0NWIDwtIHRyYWluKFBjdEtpZHMyUGFyfi4sIGRhdGEgPSBkZiwgbWV0aG9kID0gInJwYXJ0Iix0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sLkxPT0NWLHR1bmVHcmlkID0gY3AuZ3JpZCkgDQojIFN1bW1hcml6ZSB0aGUgcmVzdWx0cyANCnByaW50KExPT0NWKSANCmBgYA0KIyMgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24gDQoNCk5leHQsIHdlIHVzZSBLLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiwgdGhlIHRlY2huaXF1ZSB1c2VkIGFnYWluc3QgYSBzZXF1ZW5jZSBvZiBDUCB0byBmaW5kIHRoZSBtb3N0IG9wdGltdW0uIFRlbiBmb2xkcyBpcyBjb25maWd1cmVkIGZvciB0ZWNobmlxdWUuIA0KYGBge3J9DQojIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uIA0KIyBEZWZpbmUgdHJhaW5pbmcgY29udHJvbCANCnNldC5zZWVkKDEyMykgIA0KdHJhaW4uY29udHJvbC5jdiA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gMTApIA0KIyBUcmFpbiB0aGUgbW9kZWwgDQpjdiA8LSB0cmFpbihQY3RLaWRzMlBhcn4uLCBkYXRhID0gZGYsIG1ldGhvZCA9ICJycGFydCIsdHJDb250cm9sID0gdHJhaW4uY29udHJvbC5jdix0dW5lR3JpZCA9IGNwLmdyaWQpIA0KIyBTdW1tYXJpemUgdGhlIHJlc3VsdHMgDQpwcmludChjdikgDQpgYGANCiMjIFJlcGVhdGVkIEstZm9sZCBjcm9zcy12YWxpZGF0aW9uIA0KDQpOZXh0LCB3ZSB1c2UgUmVwZWF0ZWQgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24sIHRoZSB0ZWNobmlxdWUgdXNlZCBhZ2FpbnN0IGEgc2VxdWVuY2Ugb2YgQ1AgdG8gZmluZCB0aGUgbW9zdCBvcHRpbXVtLiBUZW4gZm9sZHMgd2l0aCB0aHJlZSByZXBlYXRzIGNvbmZpZ3VyZWQgZm9yIHRlY2huaXF1ZS4gDQoNCmBgYHtyfQ0KIyBSZXBlYXRlZCBLLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiANCnNldC5zZWVkKDEyMykgDQp0cmFpbi5jb250cm9sLnJlcGVhdGVkY3YgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgbnVtYmVyID0gMTAsIHJlcGVhdHMgPSAzKSANCiMgVHJhaW4gdGhlIG1vZGVsIA0KcmVwZWF0ZWRjdiA8LSB0cmFpbihQY3RLaWRzMlBhcn4uLCBkYXRhID0gZGYsIG1ldGhvZCA9ICJycGFydCIsdHJDb250cm9sID0gdHJhaW4uY29udHJvbC5yZXBlYXRlZGN2LHR1bmVHcmlkID0gY3AuZ3JpZCkgDQojIFN1bW1hcml6ZSB0aGUgcmVzdWx0cyANCnByaW50KHJlcGVhdGVkY3YpIA0KYGBgDQojIyBDb25jbHVzaW9uIA0KDQpGcm9tIHRoZSBwcmV2aW91cyBzZWN0aW9ucywgd2UgbGlzdCBkb3duIGFsbCBvdXIgZmluZGluZ3MgZGl2aWRlZCBpbnRvIHR3byB0YWJsZXMsIHZhbGlkYXRpb24gYW5kIGV2YWx1YXRpb24gdGFibGVzIGFzIHNob3duIGluIHRhYmxlIG51bWJlciAxIGFuZCBudW1iZXIgMiwgd2UgY2FuIGNvbmNsdWRlIHRoZSBiZWxvdzogDQoNClF1ZXN0aW9uIDE6IExlYXZlLU9uZS1PdXQgQ3Jvc3MgVmFsaWRhdGlvbiBoYXMgdGhlIGhpZ2hlc3QgUjIgYW5kIHRoZSBsb3dlc3QgUk1TRSBhbmQgTUFFIHNvIGl0IGlzIHN1aXRhYmxlIGZvciBmaXJzdCByZXNlYXJjaCBxdWVzdGlvbiANCg0KUXVlc3Rpb24gMjogTGVhdmUtT25lLU91dCBDcm9zcyBWYWxpZGF0aW9uIGhhcyB0aGUgaGlnaGVzdCBSMiBhbmQgdGhlIGxvd2VzdCBSTVNFIGFuZCBNQUUgc28gaXQgaXMgc3VpdGFibGUgZm9yIGZpcnN0IHJlc2VhcmNoIHF1ZXN0aW9uIA0KDQpRdWVzdGlvbiAzOiBSZXBlYXRlZCBLLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiBoYXMgdGhlIGhpZ2hlc3QgUjIgYW5kIHRoZSBsb3dlc3QgUk1TRSBhbmQgTUFFIHNvIGl0IGlzIHN1aXRhYmxlIGZvciBmaXJzdCByZXNlYXJjaCBxdWVzdGlvbiANCg0K