load library and start h2o
library(h2o)
library(data.table)
library(ggplot2)
h2o.init()
Connection successful!
R is connected to the H2O cluster:
H2O cluster uptime: 2 hours 18 minutes
H2O cluster version: 3.10.5.3
H2O cluster version age: 2 months and 25 days
H2O cluster name: H2O_started_from_R_r631758_qgy865
H2O cluster total nodes: 1
H2O cluster total memory: 3.19 GB
H2O cluster total cores: 8
H2O cluster allowed cores: 8
H2O cluster healthy: TRUE
H2O Connection ip: localhost
H2O Connection port: 54321
H2O Connection proxy: NA
H2O Internal Security: FALSE
R Version: R version 3.4.1 (2017-06-30)
# airlines<-h2o.importFile("C:\\Users\\r631758\\Desktop\\r631758\\R codes\\H2O\\exercise\\allyears2k_headers.csv")
raw <- h2o.importFile(path = "C:\\Users\\r631758\\Desktop\\r631758\\R codes\\H2O\\exercise\\allyears2k_headers.csv", parse=FALSE)
setup <- h2o.parseSetup(raw)
setup$column_types[which(setup$column_names %in% "AirTime")] <- "Numeric"
setup$column_types[which(setup$column_names %in% "AirDelay")] <- "Numeric"
airlines.hex <- h2o.parseRaw(raw, col.types=setup$column_types)
|
| | 0%
|
|=====================================================================================================| 100%
airlines<-fread("C:\\Users\\r631758\\Desktop\\r631758\\R codes\\H2O\\exercise\\allyears2k_headers.csv")
str(airlines)
Classes ‘data.table’ and 'data.frame': 43978 obs. of 31 variables:
$ Year : int 1987 1987 1987 1987 1987 1987 1987 1987 1987 1987 ...
$ Month : int 10 10 10 10 10 10 10 10 10 10 ...
$ DayofMonth : int 14 15 17 18 19 21 22 23 24 25 ...
$ DayOfWeek : int 3 4 6 7 1 3 4 5 6 7 ...
$ DepTime : int 741 729 741 729 749 728 728 731 744 729 ...
$ CRSDepTime : int 730 730 730 730 730 730 730 730 730 730 ...
$ ArrTime : int 912 903 918 847 922 848 852 902 908 851 ...
$ CRSArrTime : int 849 849 849 849 849 849 849 849 849 849 ...
$ UniqueCarrier : chr "PS" "PS" "PS" "PS" ...
$ FlightNum : int 1451 1451 1451 1451 1451 1451 1451 1451 1451 1451 ...
$ TailNum : chr NA NA NA NA ...
$ ActualElapsedTime: int 91 94 97 78 93 80 84 91 84 82 ...
$ CRSElapsedTime : int 79 79 79 79 79 79 79 79 79 79 ...
$ AirTime : int NA NA NA NA NA NA NA NA NA NA ...
$ ArrDelay : int 23 14 29 -2 33 -1 3 13 19 2 ...
$ DepDelay : int 11 -1 11 -1 19 -2 -2 1 14 -1 ...
$ Origin : chr "SAN" "SAN" "SAN" "SAN" ...
$ Dest : chr "SFO" "SFO" "SFO" "SFO" ...
$ Distance : int 447 447 447 447 447 447 447 447 447 447 ...
$ TaxiIn : int NA NA NA NA NA NA NA NA NA NA ...
$ TaxiOut : int NA NA NA NA NA NA NA NA NA NA ...
$ Cancelled : int 0 0 0 0 0 0 0 0 0 0 ...
$ CancellationCode : chr NA NA NA NA ...
$ Diverted : int 0 0 0 0 0 0 0 0 0 0 ...
$ CarrierDelay : int NA NA NA NA NA NA NA NA NA NA ...
$ WeatherDelay : int NA NA NA NA NA NA NA NA NA NA ...
$ NASDelay : int NA NA NA NA NA NA NA NA NA NA ...
$ SecurityDelay : int NA NA NA NA NA NA NA NA NA NA ...
$ LateAircraftDelay: int NA NA NA NA NA NA NA NA NA NA ...
$ IsArrDelayed : chr "YES" "YES" "YES" "NO" ...
$ IsDepDelayed : chr "YES" "NO" "YES" "NO" ...
- attr(*, ".internal.selfref")=<externalptr>
airlines$UniqueCarrier<-as.factor(airlines$UniqueCarrier)
summary(airlines)
Year Month DayofMonth DayOfWeek DepTime CRSDepTime ArrTime
Min. :1987 Min. : 1.000 Min. : 1.0 Min. :1.000 Min. : 1 Min. : 0 Min. : 1
1st Qu.:1992 1st Qu.: 1.000 1st Qu.: 6.0 1st Qu.:2.000 1st Qu.: 929 1st Qu.: 910 1st Qu.:1118
Median :1998 Median : 1.000 Median :14.0 Median :4.000 Median :1330 Median :1320 Median :1527
Mean :1998 Mean : 1.409 Mean :14.6 Mean :3.821 Mean :1346 Mean :1313 Mean :1505
3rd Qu.:2003 3rd Qu.: 1.000 3rd Qu.:23.0 3rd Qu.:5.000 3rd Qu.:1735 3rd Qu.:1720 3rd Qu.:1917
Max. :2008 Max. :10.000 Max. :31.0 Max. :7.000 Max. :2400 Max. :2359 Max. :2400
NA's :1086 NA's :1195
CRSArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime CRSElapsedTime
Min. : 0 US :18729 Min. : 1.0 Length:43978 Min. : 16.0 Min. : 17
1st Qu.:1109 UA : 9434 1st Qu.: 204.0 Class :character 1st Qu.: 71.0 1st Qu.: 71
Median :1516 WN : 6170 Median : 557.0 Mode :character Median :101.0 Median :102
Mean :1485 HP : 3451 Mean : 818.8 Mean :124.8 Mean :125
3rd Qu.:1903 PS : 3212 3rd Qu.:1242.0 3rd Qu.:151.0 3rd Qu.:151
Max. :2359 DL : 935 Max. :3949.0 Max. :475.0 Max. :437
(Other): 2047 NA's :1195 NA's :13
AirTime ArrDelay DepDelay Origin Dest Distance
Min. : 14.0 Min. :-63.000 Min. :-16.00 Length:43978 Length:43978 Min. : 11.0
1st Qu.: 61.0 1st Qu.: -6.000 1st Qu.: -2.00 Class :character Class :character 1st Qu.: 326.0
Median : 91.0 Median : 2.000 Median : 1.00 Mode :character Mode :character Median : 541.0
Mean :114.3 Mean : 9.317 Mean : 10.01 Mean : 730.2
3rd Qu.:140.0 3rd Qu.: 14.000 3rd Qu.: 10.00 3rd Qu.: 920.0
Max. :402.0 Max. :475.000 Max. :473.00 Max. :3365.0
NA's :16649 NA's :1195 NA's :1086 NA's :35
TaxiIn TaxiOut Cancelled CancellationCode Diverted CarrierDelay
Min. : 0.000 Min. : 0.00 Min. :0.00000 Length:43978 Min. :0.000000 Min. : 0.00
1st Qu.: 3.000 1st Qu.: 9.00 1st Qu.:0.00000 Class :character 1st Qu.:0.000000 1st Qu.: 0.00
Median : 5.000 Median : 12.00 Median :0.00000 Mode :character Median :0.000000 Median : 0.00
Mean : 5.381 Mean : 14.17 Mean :0.02469 Mean :0.002478 Mean : 4.05
3rd Qu.: 6.000 3rd Qu.: 16.00 3rd Qu.:0.00000 3rd Qu.:0.000000 3rd Qu.: 0.00
Max. :128.000 Max. :254.00 Max. :1.00000 Max. :1.000000 Max. :369.00
NA's :16026 NA's :16024 NA's :35045
WeatherDelay NASDelay SecurityDelay LateAircraftDelay IsArrDelayed IsDepDelayed
Min. : 0.00 Min. : 0.00 Min. : 0.00 Min. : 0.00 Length:43978 Length:43978
1st Qu.: 0.00 1st Qu.: 0.00 1st Qu.: 0.00 1st Qu.: 0.00 Class :character Class :character
Median : 0.00 Median : 0.00 Median : 0.00 Median : 0.00 Mode :character Mode :character
Mean : 0.29 Mean : 4.86 Mean : 0.02 Mean : 7.62
3rd Qu.: 0.00 3rd Qu.: 0.00 3rd Qu.: 0.00 3rd Qu.: 0.00
Max. :201.00 Max. :323.00 Max. :14.00 Max. :373.00
NA's :35045 NA's :35045 NA's :35045 NA's :35045
ggplot(airlines, aes(x=Year))+geom_histogram()

# table(airlines$Year)
ggplot(airlines, aes(x=Month))+geom_histogram()

# table(airlines$Month)
hist(airlines$Year)

hist(airlines$Month)

airlines.h2o<-as.h2o(airlines)
|
| | 0%
|
|=====================================================================================================| 100%
Create scatter plots by taking a random sample into R to plot and graphing linear fit
scatter_plot<-function(data,x,y,max_points=1000, fit=T){
if(fit){
lr<-h2o.glm(x=x,y=y,training_frame = data,family="gaussian")
coeff<-lr@model$coefficients_table$coefficients
}
df<-data[,c(x,y)]
runif<-h2o.runif(df)
df.subset<-df[runif < max_points/nrow(data),]
df.R<-as.data.frame(df.subset)
h2o.rm(df.subset)
if (fit) h2o.rm(lr@model_id)
plot(x=df.R[,x],y=df.R[,y], col="blue", xlab=x, ylab=y)
if (fit) abline(coef=coeff,col="black")
}
scatter_plot(data=airlines.h2o,x="Distance", y="AirTime", fit=T)
|
| | 0%
|
|=====================================================================================================| 100%

# lr<-h2o.glm(x="Distance",y="AirTime",training_frame = airlines.h2o,family="gaussian")
scatter_plot(data = airlines.h2o, x = "UniqueCarrier", y = "ArrDelay", max_points = 5000, fit = F)

# lr<-h2o.glm(x="UniqueCarrier",y="ArrDelay",training_frame = airlines.h2o,family="gaussian")
# lr<-h2o.glm(x="Distance",y="AirTime",training_frame =airlines.h2o,family="gaussian")
Flight by Month calculated using H2O’s fast groupby
print("Splitting data into group of 12 month and aggregating on two columns...")
[1] "Splitting data into group of 12 month and aggregating on two columns..."
flightBymonth<-h2o.group_by(data=airlines.h2o,by="Month", nrow("Month"), sum("Cancelled"))
flightBymonth.R<-as.data.frame(flightBymonth)
Set Column Type for Enumerator or Factor Columns
airlines.h2o$Year<-as.factor(airlines.h2o$Year)
airlines.h2o$Month<-as.factor(airlines.h2o$Month)
airlines.h2o$DayOfWeek<-as.factor(airlines.h2o$DayOfWeek)
airlines.h2o$Cancelled<-as.factor(airlines.h2o$Cancelled)
airlines.h2o$FlightNum<-as.factor(airlines.h2o$FlightNum)
airlines.h2o$Origin<-as.factor(airlines.h2o$Origin)
airlines.h2o$Dest<-as.factor(airlines.h2o$Dest)
airlines.h2o$IsDepDelayed<-as.factor(airlines.h2o$IsDepDelayed)
Parameter Creation
hour1<-airlines.h2o$CRSArrTime %/% 100
mins1<-airlines.h2o$CRSArrTime %% 100
arrTime<-hour1*60+mins1
hour2 <- airlines.h2o$CRSDepTime %/% 100
mins2 <- airlines.h2o$CRSDepTime %% 100
depTime <- hour2*60+mins2
travelTime <- ifelse(arrTime - depTime > 0, arrTime - depTime, NA)
airlines.h2o$TravelTime <- travelTime
scatter_plot(airlines.h2o, "Distance", "TravelTime")
|
| | 0%
|
|=====================================================================================================| 100%

imputation: You can also choose to impute missing value by taking the mean of subsets
h2o.impute(data=airlines.h2o, column="Distance", by=c("Origin", "Dest"))
Origin Dest mean_Distance
1 ABE CLT 481
2 ABE PIT 253
3 ABQ AMA 277
4 ABQ BWI 1670
5 ABQ DAL 580
6 ABQ DEN 349
[1517 rows x 3 columns]
scatter_plot(airlines.h2o, "Distance", "TravelTime")
|
| | 0%
|
|=====================================================================================================| 100%

create test/train split
data.split<-h2o.splitFrame(data=airlines.h2o,ratio=0.8)
data.train<-data.split[[1]]
data.test<-data.split[[2]]
set the predictor names and the response column name
Build GLM
start<-Sys.time()
data.glm<-h2o.glm(y=response,x=predictors,training_frame = data.train, validation_frame = data.test, family="binomial", standardize = T, model_id = "glm_model", alpha=0.5, lambda=1e-05)
|
| | 0%
|
|== | 2%
|
|=====================================================================================================| 100%
glm_time<-Sys.time()-start
print(paste("Took", round(glm_time, digits=2), units(glm_time), "to build logistic regression model."))
[1] "Took 1.62 secs to build logistic regression model."
Build GBM model
predictors=c("Year", "UniqueCarrier","DayOfWeek","Month","Distance")
start<-Sys.time()
#for balance classes https://h2o-release.s3.amazonaws.com/h2o/rel-ueno/2/docs-website/h2o-docs/data-science/algo-params/balance_classes.html
data.gbm<-h2o.gbm(y=response, x=predictors, balance_classes=T,training_frame = data.train, validation_frame = data.test, ntrees=100, max_depth=5, model_id="gbm_model", distribution="bernoulli", learn_rate = .1, min_rows=2)
|
| | 0%
|
|= | 1%
|
|=============== | 15%
|
|===================== | 21%
|
|========================= | 25%
|
|===================================== | 37%
|
|=====================================================================================================| 100%
gbm_time<-Sys.time()-start
print(paste("Took", round(gbm_time, digits = 2), units(gbm_time), "to build a GBM model."))
[1] "Took 6.97 secs to build a GBM model."
Build random forest mdoel
predictors=c("Year", "UniqueCarrier","DayOfWeek","Month","Distance")
start<-Sys.time()
data.drf<-h2o.randomForest(y=response, x=predictors, training_frame = data.train, validation_frame = data.test, ntrees=1500, max_depth=5, model_id="drf_model", balance_classes = T)
|
| | 0%
|
|= | 1%
|
|== | 2%
|
|================== | 17%
|
|================================== | 34%
|
|================================================== | 50%
|
|============================================================= | 60%
|
|========================================================================== | 74%
|
|=========================================================================================== | 90%
|
|=====================================================================================================| 100%
drf_time <- Sys.time() - start
print(paste("Took", round(drf_time, digits = 2), units(drf_time), "to build a Random Forest model."))
[1] "Took 29.27 secs to build a Random Forest model."
comparing running tiem with randoforest package
cannot handle predictors more than 53 categories
library(randomForest)
library(caret)
trainIndex=createDataPartition(airlines$IsDepDelayed,p=0.7, list=FALSE, times=1)
#https://www.rdocumentation.org/packages/caret/versions/6.0-76/topics/createDataPartition
airlines$Year<-as.factor(airlines$Year)
airlines$Month<-as.factor(airlines$Month)
airlines$DayOfWeek<-as.factor(airlines$DayOfWeek)
airlines$Cancelled<-as.factor(airlines$Cancelled)
airlines$FlightNum<-as.factor(airlines$FlightNum)
airlines$Origin<-as.factor(airlines$Origin)
airlines$Dest<-as.factor(airlines$Dest)
airlines$IsDepDelayed<-as.factor(airlines$IsDepDelayed)
training<-airlines[trainIndex,]
testing<-airlines[-trainIndex,]
training<-as.data.frame(training)
testing<-as.data.frame(testing)
start<-Sys.time()
fit <- randomForest(IsDepDelayed ~ Year+UniqueCarrier+DayOfWeek+Month+Distance,
data=training,
importance=TRUE,
ntree=1500, na.action=na.omit)
drf_time <- Sys.time() - start
print(paste("Took", round(drf_time, digits = 2), units(drf_time), "to build a Random Forest model under randomForest package."))
[1] "Took 44.74 secs to build a Random Forest model under randomForest package."
build deep learning model
start <- Sys.time()
data.dl<-h2o.deeplearning(y=response, x=predictors, training_frame = data.train, validation_frame = data.test, hidden=c(10,10), epochs = 5, balance_classes=T, loss="Automatic", variable_importances=T)
dl_time <- Sys.time() - start
print(paste("Took", round(dl_time, digits = 2), units(dl_time), "to build a Deep Learning model."))
Variable Importance - For feature selection and rerunning a model build
print("GLM: Sorted Standardized Coefficient Magnitudes To Find Nonzero Coefficients")
data.glm@model$standardized_coefficient_magnitudes
print("GBM: Variable Importance")
data.gbm@model$variable_importances
print("Random Forest: Variable Importance")
data.drf@model$variable_importances
print("Deep Learning: Variable Importance")
data.dl@model$variable_importances
LS0tDQp0aXRsZTogImFpcmxpbmUgZGVsYXkgcHJlZGljdGlvbiBhbmFseXNpcyBieSBIMm8iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCiNsb2FkIGxpYnJhcnkgYW5kIHN0YXJ0IGgybw0KYGBge3J9DQpsaWJyYXJ5KGgybykNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmxpYnJhcnkoZ2dwbG90MikNCmgyby5pbml0KCkNCmBgYA0KDQpgYGB7cn0NCiMgYWlybGluZXM8LWgyby5pbXBvcnRGaWxlKCJDOlxcVXNlcnNcXHI2MzE3NThcXERlc2t0b3BcXHI2MzE3NThcXFIgY29kZXNcXEgyT1xcZXhlcmNpc2VcXGFsbHllYXJzMmtfaGVhZGVycy5jc3YiKQ0KDQoNCnJhdyA8LSBoMm8uaW1wb3J0RmlsZShwYXRoID0gIkM6XFxVc2Vyc1xccjYzMTc1OFxcRGVza3RvcFxccjYzMTc1OFxcUiBjb2Rlc1xcSDJPXFxleGVyY2lzZVxcYWxseWVhcnMya19oZWFkZXJzLmNzdiIsIHBhcnNlPUZBTFNFKQ0Kc2V0dXAgPC0gaDJvLnBhcnNlU2V0dXAocmF3KQ0Kc2V0dXAkY29sdW1uX3R5cGVzW3doaWNoKHNldHVwJGNvbHVtbl9uYW1lcyAlaW4lICJBaXJUaW1lIildICA8LSAiTnVtZXJpYyINCnNldHVwJGNvbHVtbl90eXBlc1t3aGljaChzZXR1cCRjb2x1bW5fbmFtZXMgJWluJSAiQWlyRGVsYXkiKV0gPC0gIk51bWVyaWMiDQphaXJsaW5lcy5oZXggPC0gaDJvLnBhcnNlUmF3KHJhdywgY29sLnR5cGVzPXNldHVwJGNvbHVtbl90eXBlcykNCg0KDQphaXJsaW5lczwtZnJlYWQoIkM6XFxVc2Vyc1xccjYzMTc1OFxcRGVza3RvcFxccjYzMTc1OFxcUiBjb2Rlc1xcSDJPXFxleGVyY2lzZVxcYWxseWVhcnMya19oZWFkZXJzLmNzdiIpDQpzdHIoYWlybGluZXMpDQoNCg0KYWlybGluZXMkVW5pcXVlQ2FycmllcjwtYXMuZmFjdG9yKGFpcmxpbmVzJFVuaXF1ZUNhcnJpZXIpDQpzdW1tYXJ5KGFpcmxpbmVzKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmdncGxvdChhaXJsaW5lcywgYWVzKHg9WWVhcikpK2dlb21faGlzdG9ncmFtKCkNCiMgdGFibGUoYWlybGluZXMkWWVhcikNCmdncGxvdChhaXJsaW5lcywgYWVzKHg9TW9udGgpKStnZW9tX2hpc3RvZ3JhbSgpDQojIHRhYmxlKGFpcmxpbmVzJE1vbnRoKQ0KaGlzdChhaXJsaW5lcyRZZWFyKQ0KaGlzdChhaXJsaW5lcyRNb250aCkNCg0KYWlybGluZXMuaDJvPC1hcy5oMm8oYWlybGluZXMpDQpgYGANCg0KI0NyZWF0ZSBzY2F0dGVyIHBsb3RzIGJ5IHRha2luZyBhIHJhbmRvbSBzYW1wbGUgaW50byBSIHRvIHBsb3QgYW5kIGdyYXBoaW5nIGxpbmVhciBmaXQNCmBgYHtyfQ0Kc2NhdHRlcl9wbG90PC1mdW5jdGlvbihkYXRhLHgseSxtYXhfcG9pbnRzPTEwMDAsIGZpdD1UKXsNCiAgaWYoZml0KXsNCiAgICBscjwtaDJvLmdsbSh4PXgseT15LHRyYWluaW5nX2ZyYW1lID0gZGF0YSxmYW1pbHk9ImdhdXNzaWFuIikNCiAgICAgIGNvZWZmPC1sckBtb2RlbCRjb2VmZmljaWVudHNfdGFibGUkY29lZmZpY2llbnRzDQogIH0NCiAgZGY8LWRhdGFbLGMoeCx5KV0NCiAgcnVuaWY8LWgyby5ydW5pZihkZikNCiAgZGYuc3Vic2V0PC1kZltydW5pZiA8IG1heF9wb2ludHMvbnJvdyhkYXRhKSxdDQogIGRmLlI8LWFzLmRhdGEuZnJhbWUoZGYuc3Vic2V0KQ0KICBoMm8ucm0oZGYuc3Vic2V0KQ0KICBpZiAoZml0KSBoMm8ucm0obHJAbW9kZWxfaWQpDQogIA0KICBwbG90KHg9ZGYuUlsseF0seT1kZi5SWyx5XSwgY29sPSJibHVlIiwgeGxhYj14LCB5bGFiPXkpDQogIGlmIChmaXQpIGFibGluZShjb2VmPWNvZWZmLGNvbD0iYmxhY2siKQ0KfQ0KDQpzY2F0dGVyX3Bsb3QoZGF0YT1haXJsaW5lcy5oMm8seD0iRGlzdGFuY2UiLCB5PSJBaXJUaW1lIiwgZml0PVQpDQojIGxyPC1oMm8uZ2xtKHg9IkRpc3RhbmNlIix5PSJBaXJUaW1lIix0cmFpbmluZ19mcmFtZSA9IGFpcmxpbmVzLmgybyxmYW1pbHk9ImdhdXNzaWFuIikNCg0KDQpzY2F0dGVyX3Bsb3QoZGF0YSA9IGFpcmxpbmVzLmgybywgeCA9ICJVbmlxdWVDYXJyaWVyIiwgeSA9ICJBcnJEZWxheSIsIG1heF9wb2ludHMgPSA1MDAwLCBmaXQgPSBGKQ0KIyBscjwtaDJvLmdsbSh4PSJVbmlxdWVDYXJyaWVyIix5PSJBcnJEZWxheSIsdHJhaW5pbmdfZnJhbWUgPSBhaXJsaW5lcy5oMm8sZmFtaWx5PSJnYXVzc2lhbiIpDQojIGxyPC1oMm8uZ2xtKHg9IkRpc3RhbmNlIix5PSJBaXJUaW1lIix0cmFpbmluZ19mcmFtZSA9YWlybGluZXMuaDJvLGZhbWlseT0iZ2F1c3NpYW4iKQ0KDQpgYGANCg0KIyMgRmxpZ2h0IGJ5IE1vbnRoIGNhbGN1bGF0ZWQgdXNpbmcgSDJPJ3MgZmFzdCBncm91cGJ5DQpgYGB7cn0NCnByaW50KCJTcGxpdHRpbmcgZGF0YSBpbnRvIGdyb3VwIG9mIDEyIG1vbnRoIGFuZCBhZ2dyZWdhdGluZyBvbiB0d28gY29sdW1ucy4uLiIpDQpmbGlnaHRCeW1vbnRoPC1oMm8uZ3JvdXBfYnkoZGF0YT1haXJsaW5lcy5oMm8sYnk9Ik1vbnRoIiwgbnJvdygiTW9udGgiKSwgc3VtKCJDYW5jZWxsZWQiKSkNCmZsaWdodEJ5bW9udGguUjwtYXMuZGF0YS5mcmFtZShmbGlnaHRCeW1vbnRoKQ0KYGBgDQoNCiNTZXQgQ29sdW1uIFR5cGUgZm9yIEVudW1lcmF0b3Igb3IgRmFjdG9yIENvbHVtbnMNCmBgYHtyfQ0KYWlybGluZXMuaDJvJFllYXI8LWFzLmZhY3RvcihhaXJsaW5lcy5oMm8kWWVhcikNCmFpcmxpbmVzLmgybyRNb250aDwtYXMuZmFjdG9yKGFpcmxpbmVzLmgybyRNb250aCkNCmFpcmxpbmVzLmgybyREYXlPZldlZWs8LWFzLmZhY3RvcihhaXJsaW5lcy5oMm8kRGF5T2ZXZWVrKQ0KYWlybGluZXMuaDJvJENhbmNlbGxlZDwtYXMuZmFjdG9yKGFpcmxpbmVzLmgybyRDYW5jZWxsZWQpDQphaXJsaW5lcy5oMm8kRmxpZ2h0TnVtPC1hcy5mYWN0b3IoYWlybGluZXMuaDJvJEZsaWdodE51bSkNCmFpcmxpbmVzLmgybyRPcmlnaW48LWFzLmZhY3RvcihhaXJsaW5lcy5oMm8kT3JpZ2luKQ0KYWlybGluZXMuaDJvJERlc3Q8LWFzLmZhY3RvcihhaXJsaW5lcy5oMm8kRGVzdCkNCmFpcmxpbmVzLmgybyRJc0RlcERlbGF5ZWQ8LWFzLmZhY3RvcihhaXJsaW5lcy5oMm8kSXNEZXBEZWxheWVkKQ0KYGBgDQojUGFyYW1ldGVyIENyZWF0aW9uDQpgYGB7cn0NCmhvdXIxPC1haXJsaW5lcy5oMm8kQ1JTQXJyVGltZSAlLyUgMTAwDQptaW5zMTwtYWlybGluZXMuaDJvJENSU0FyclRpbWUgJSUgMTAwDQphcnJUaW1lPC1ob3VyMSo2MCttaW5zMQ0KDQpob3VyMiA8LSBhaXJsaW5lcy5oMm8kQ1JTRGVwVGltZSAlLyUgMTAwDQptaW5zMiA8LSBhaXJsaW5lcy5oMm8kQ1JTRGVwVGltZSAlJSAxMDANCmRlcFRpbWUgPC0gaG91cjIqNjArbWluczINCg0KdHJhdmVsVGltZSA8LSBpZmVsc2UoYXJyVGltZSAtIGRlcFRpbWUgPiAwLCBhcnJUaW1lIC0gZGVwVGltZSwgTkEpDQphaXJsaW5lcy5oMm8kVHJhdmVsVGltZSA8LSB0cmF2ZWxUaW1lDQpzY2F0dGVyX3Bsb3QoYWlybGluZXMuaDJvLCAiRGlzdGFuY2UiLCAiVHJhdmVsVGltZSIpDQoNCmBgYA0KDQojaW1wdXRhdGlvbjogWW91IGNhbiBhbHNvIGNob29zZSB0byBpbXB1dGUgbWlzc2luZyB2YWx1ZSBieSB0YWtpbmcgdGhlIG1lYW4gb2Ygc3Vic2V0cw0KYGBge3J9DQpoMm8uaW1wdXRlKGRhdGE9YWlybGluZXMuaDJvLCBjb2x1bW49IkRpc3RhbmNlIiwgYnk9YygiT3JpZ2luIiwgIkRlc3QiKSkNCnNjYXR0ZXJfcGxvdChhaXJsaW5lcy5oMm8sICJEaXN0YW5jZSIsICJUcmF2ZWxUaW1lIikNCmBgYA0KDQojY3JlYXRlIHRlc3QvdHJhaW4gc3BsaXQNCmBgYHtyfQ0KZGF0YS5zcGxpdDwtaDJvLnNwbGl0RnJhbWUoZGF0YT1haXJsaW5lcy5oMm8scmF0aW89MC44KQ0KZGF0YS50cmFpbjwtZGF0YS5zcGxpdFtbMV1dDQpkYXRhLnRlc3Q8LWRhdGEuc3BsaXRbWzJdXQ0KYGBgDQoNCiNzZXQgdGhlIHByZWRpY3RvciBuYW1lcyBhbmQgdGhlIHJlc3BvbnNlIGNvbHVtbiBuYW1lDQpgYGB7cn0NCnByZWRpY3RvcnM9YygiT3JpZ2luIiwiRGVzdCIsIlllYXIiLCAiVW5pcXVlQ2FycmllciIsIkRheU9mV2VlayIsIk1vbnRoIiwiRGlzdGFuY2UiLCJGbGlnaHROdW0iKQ0KcmVzcG9uc2U9IklzRGVwRGVsYXllZCINCg0KYGBgDQoNCiNCdWlsZCBHTE0NCmBgYHtyfQ0Kc3RhcnQ8LVN5cy50aW1lKCkNCmRhdGEuZ2xtPC1oMm8uZ2xtKHk9cmVzcG9uc2UseD1wcmVkaWN0b3JzLHRyYWluaW5nX2ZyYW1lID0gZGF0YS50cmFpbiwgdmFsaWRhdGlvbl9mcmFtZSA9IGRhdGEudGVzdCwgZmFtaWx5PSJiaW5vbWlhbCIsIHN0YW5kYXJkaXplID0gVCwgbW9kZWxfaWQgPSAiZ2xtX21vZGVsIiwgYWxwaGE9MC41LCBsYW1iZGE9MWUtMDUpDQpnbG1fdGltZTwtU3lzLnRpbWUoKS1zdGFydA0KcHJpbnQocGFzdGUoIlRvb2siLCByb3VuZChnbG1fdGltZSwgZGlnaXRzPTIpLCB1bml0cyhnbG1fdGltZSksICJ0byBidWlsZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiIpKQ0KYGBgDQoNCiNCdWlsZCBHQk0gbW9kZWwNCmBgYHtyfQ0KDQpzdGFydDwtU3lzLnRpbWUoKQ0KI2ZvciBiYWxhbmNlIGNsYXNzZXMgaHR0cHM6Ly9oMm8tcmVsZWFzZS5zMy5hbWF6b25hd3MuY29tL2gyby9yZWwtdWVuby8yL2RvY3Mtd2Vic2l0ZS9oMm8tZG9jcy9kYXRhLXNjaWVuY2UvYWxnby1wYXJhbXMvYmFsYW5jZV9jbGFzc2VzLmh0bWwNCg0KZGF0YS5nYm08LWgyby5nYm0oeT1yZXNwb25zZSwgeD1wcmVkaWN0b3JzLCBiYWxhbmNlX2NsYXNzZXM9VCx0cmFpbmluZ19mcmFtZSA9IGRhdGEudHJhaW4sIHZhbGlkYXRpb25fZnJhbWUgPSBkYXRhLnRlc3QsIG50cmVlcz0xMDAsIG1heF9kZXB0aD01LCBtb2RlbF9pZD0iZ2JtX21vZGVsIiwgZGlzdHJpYnV0aW9uPSJiZXJub3VsbGkiLCBsZWFybl9yYXRlID0gLjEsIG1pbl9yb3dzPTIpDQpnYm1fdGltZTwtU3lzLnRpbWUoKS1zdGFydA0KcHJpbnQocGFzdGUoIlRvb2siLCByb3VuZChnYm1fdGltZSwgZGlnaXRzID0gMiksIHVuaXRzKGdibV90aW1lKSwgInRvIGJ1aWxkIGEgR0JNIG1vZGVsLiIpKSANCg0KYGBgDQojQnVpbGQgcmFuZG9tIGZvcmVzdCBtZG9lbA0KYGBge3J9DQojcHJlZGljdG9ycz1jKCJZZWFyIiwgIlVuaXF1ZUNhcnJpZXIiLCJEYXlPZldlZWsiLCJNb250aCIsIkRpc3RhbmNlIikNCnN0YXJ0PC1TeXMudGltZSgpDQpkYXRhLmRyZjwtaDJvLnJhbmRvbUZvcmVzdCh5PXJlc3BvbnNlLCB4PXByZWRpY3RvcnMsIHRyYWluaW5nX2ZyYW1lID0gZGF0YS50cmFpbiwgdmFsaWRhdGlvbl9mcmFtZSA9IGRhdGEudGVzdCwgbnRyZWVzPTE1MDAsIG1heF9kZXB0aD01LCBtb2RlbF9pZD0iZHJmX21vZGVsIiwgYmFsYW5jZV9jbGFzc2VzID0gVCkNCmRyZl90aW1lIDwtIFN5cy50aW1lKCkgLSBzdGFydA0KcHJpbnQocGFzdGUoIlRvb2siLCByb3VuZChkcmZfdGltZSwgZGlnaXRzID0gMiksIHVuaXRzKGRyZl90aW1lKSwgInRvIGJ1aWxkIGEgUmFuZG9tIEZvcmVzdCBtb2RlbC4iKSkNCmBgYA0KDQojY29tcGFyaW5nIHJ1bm5pbmcgdGllbSB3aXRoIHJhbmRvZm9yZXN0IHBhY2thZ2UNCiNjYW5ub3QgaGFuZGxlIHByZWRpY3RvcnMgbW9yZSB0aGFuIDUzIGNhdGVnb3JpZXMNCmBgYHtyfQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGNhcmV0KQ0KDQp0cmFpbkluZGV4PWNyZWF0ZURhdGFQYXJ0aXRpb24oYWlybGluZXMkSXNEZXBEZWxheWVkLHA9MC43LCBsaXN0PUZBTFNFLCB0aW1lcz0xKQ0KI2h0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9jYXJldC92ZXJzaW9ucy82LjAtNzYvdG9waWNzL2NyZWF0ZURhdGFQYXJ0aXRpb24NCmFpcmxpbmVzJFllYXI8LWFzLmZhY3RvcihhaXJsaW5lcyRZZWFyKQ0KYWlybGluZXMkTW9udGg8LWFzLmZhY3RvcihhaXJsaW5lcyRNb250aCkNCmFpcmxpbmVzJERheU9mV2VlazwtYXMuZmFjdG9yKGFpcmxpbmVzJERheU9mV2VlaykNCmFpcmxpbmVzJENhbmNlbGxlZDwtYXMuZmFjdG9yKGFpcmxpbmVzJENhbmNlbGxlZCkNCmFpcmxpbmVzJEZsaWdodE51bTwtYXMuZmFjdG9yKGFpcmxpbmVzJEZsaWdodE51bSkNCmFpcmxpbmVzJE9yaWdpbjwtYXMuZmFjdG9yKGFpcmxpbmVzJE9yaWdpbikNCmFpcmxpbmVzJERlc3Q8LWFzLmZhY3RvcihhaXJsaW5lcyREZXN0KQ0KYWlybGluZXMkSXNEZXBEZWxheWVkPC1hcy5mYWN0b3IoYWlybGluZXMkSXNEZXBEZWxheWVkKQ0KDQp0cmFpbmluZzwtYWlybGluZXNbdHJhaW5JbmRleCxdDQp0ZXN0aW5nPC1haXJsaW5lc1stdHJhaW5JbmRleCxdDQp0cmFpbmluZzwtYXMuZGF0YS5mcmFtZSh0cmFpbmluZykNCnRlc3Rpbmc8LWFzLmRhdGEuZnJhbWUodGVzdGluZykNCnN0YXJ0PC1TeXMudGltZSgpDQpmaXQgPC0gcmFuZG9tRm9yZXN0KElzRGVwRGVsYXllZCB+IFllYXIrVW5pcXVlQ2FycmllcitEYXlPZldlZWsrTW9udGgrRGlzdGFuY2UsDQogICAgICAgICAgICAgICAgICAgICAgZGF0YT10cmFpbmluZywgDQogICAgICAgICAgICAgICAgICAgICAgaW1wb3J0YW5jZT1UUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICBudHJlZT0xNTAwLCBuYS5hY3Rpb249bmEub21pdCkNCmRyZl90aW1lIDwtIFN5cy50aW1lKCkgLSBzdGFydA0KcHJpbnQocGFzdGUoIlRvb2siLCByb3VuZChkcmZfdGltZSwgZGlnaXRzID0gMiksIHVuaXRzKGRyZl90aW1lKSwgInRvIGJ1aWxkIGEgUmFuZG9tIEZvcmVzdCBtb2RlbCB1bmRlciByYW5kb21Gb3Jlc3QgcGFja2FnZS4iKSkNCmBgYA0KDQojYnVpbGQgZGVlcCBsZWFybmluZyBtb2RlbA0KYGBge3J9DQpzdGFydCAgIDwtIFN5cy50aW1lKCkNCmRhdGEuZGw8LWgyby5kZWVwbGVhcm5pbmcoeT1yZXNwb25zZSwgeD1wcmVkaWN0b3JzLCB0cmFpbmluZ19mcmFtZSA9IGRhdGEudHJhaW4sIHZhbGlkYXRpb25fZnJhbWUgPSBkYXRhLnRlc3QsIGhpZGRlbj1jKDEwLDEwKSwgZXBvY2hzID0gNSwgYmFsYW5jZV9jbGFzc2VzPVQsIGxvc3M9IkF1dG9tYXRpYyIsIHZhcmlhYmxlX2ltcG9ydGFuY2VzPVQpDQpkbF90aW1lIDwtIFN5cy50aW1lKCkgLSBzdGFydA0KcHJpbnQocGFzdGUoIlRvb2siLCByb3VuZChkbF90aW1lLCBkaWdpdHMgPSAyKSwgdW5pdHMoZGxfdGltZSksICJ0byBidWlsZCBhIERlZXAgTGVhcm5pbmcgbW9kZWwuIikpDQpgYGANCg0KIyMgVmFyaWFibGUgSW1wb3J0YW5jZSAtIEZvciBmZWF0dXJlIHNlbGVjdGlvbiBhbmQgcmVydW5uaW5nIGEgbW9kZWwgYnVpbGQNCmBgYHtyfQ0KcHJpbnQoIkdMTTogU29ydGVkIFN0YW5kYXJkaXplZCBDb2VmZmljaWVudCBNYWduaXR1ZGVzIFRvIEZpbmQgTm9uemVybyBDb2VmZmljaWVudHMiKQ0KZGF0YS5nbG1AbW9kZWwkc3RhbmRhcmRpemVkX2NvZWZmaWNpZW50X21hZ25pdHVkZXMNCnByaW50KCJHQk06IFZhcmlhYmxlIEltcG9ydGFuY2UiKQ0KZGF0YS5nYm1AbW9kZWwkdmFyaWFibGVfaW1wb3J0YW5jZXMNCnByaW50KCJSYW5kb20gRm9yZXN0OiBWYXJpYWJsZSBJbXBvcnRhbmNlIikNCmRhdGEuZHJmQG1vZGVsJHZhcmlhYmxlX2ltcG9ydGFuY2VzDQpwcmludCgiRGVlcCBMZWFybmluZzogVmFyaWFibGUgSW1wb3J0YW5jZSIpDQpkYXRhLmRsQG1vZGVsJHZhcmlhYmxlX2ltcG9ydGFuY2VzDQpgYGANCg0K