ndata <- readRDS("C:/Users/df568923/Desktop/stat/data/ndata.rds")
par_year1234 <- readRDS("C:/Users/df568923/Desktop/stat/data/par_year1234.rds")
Outline
- Questions
- Data
- Result: Analysis and Findings
- Conclusion and Discussion
Questions
- What kind of Broadgames tends to be popular?
- Relation between parameters of broadgame and the rating it gets.
- Using Machine Learning to predict the rating score.
load library
library(ggplot2)
library(readr)
library(dplyr)
library(stringr)
library(gridExtra)
library(ggrepel)
str(ndata)
'data.frame': 976 obs. of 26 variables:
$ id : chr "36235" "197405" "19427" "215613" ...
$ type : chr "boardgame" "boardgame" "boardgame" "boardgame" ...
$ name : chr "The Duke" "Tak" "Gemblo" "Tao Long: The Way of the Dragon" ...
$ yearpublished : int 2013 2017 2003 2017 2016 2017 2012 2015 2013 2019 ...
$ minplayers : int 2 2 2 2 1 2 2 2 2 2 ...
$ maxplayers : int 2 2 6 2 4 4 7 2 2 4 ...
$ playingtime : int 30 60 30 30 30 60 45 45 15 30 ...
$ minplaytime : int 30 20 30 10 30 15 45 30 15 15 ...
$ maxplaytime : int 30 60 30 30 30 60 45 45 15 30 ...
$ minage : int 13 12 6 14 13 12 8 12 0 14 ...
$ users_rated : int 3526 1708 1335 1040 927 534 743 1705 1730 271 ...
$ average_rating : num 7.44 7.73 6.83 7.03 6.8 ...
$ bayes_average_rating: num 6.87 6.63 6.14 6.12 5.98 ...
$ total_owners : int 5864 3329 1478 3239 1948 1252 1218 3607 4785 512 ...
$ total_traders : int 188 41 41 144 168 21 74 191 362 11 ...
$ total_wanters : int 310 199 148 64 45 44 45 88 19 25 ...
$ total_wishers : int 1498 1089 588 492 235 165 191 650 255 105 ...
$ total_comments : num 850 475 466 353 325 154 222 536 736 104 ...
$ total_weights : num 120 46 128 22 24 16 46 51 122 12 ...
$ average_weight : num 2.52 2.46 1.9 2.68 1.96 ...
$ types : chr "boardgame,abstracts" "boardgame,abstracts" "boardgame,abstracts" "boardgame,abstracts" ...
$ categories : chr "Abstract Strategy,Medieval" "Abstract Strategy" "Abstract Strategy" "Abstract Strategy" ...
$ mechanics : chr "Grid Movement,Tile Placement" "Grid Movement,Network and Route Building" "" "Grid Movement,Modular Board,Point to Point Movement" ...
$ family : chr "Crowdfunding: Kickstarter,The Duke,Mensa Select" "5x5 grid,Combinatorial,Connection Games,Crowdfunding: Kickstarter,Fictional Games" "Combinatorial,Crowdfunding: Kickstarter,Gemblo" "Crowdfunding: Kickstarter" ...
$ designers : chr "Jeremy Holcomb,Stephen McLaughlin" "James Ernest,Patrick Rothfuss" "Justin Oh" "Dox Lucchin,Pedro Latro" ...
$ description : chr "Levy. Maneuver. Conquer. The Duke is a dynamic, tile-based strategy game with an old-world, feudal the"| __truncated__ ""My next several hours were spent learning how to play tak. Even if I had not been nearly mad with idlenes"| __truncated__ "Gemblo is an abstract strategy game with translucent, colored pieces, each of which is made up of one to five h"| __truncated__ ""There was something formless and perfect before the Universe was born. For lack of a better name, I call "| __truncated__ ...
#makes options
options(scipen = 999)
mytheme <-
theme(
axis.text.x = element_text(
angle = 90,
size = 8,
vjust = 0.4
),
plot.title = element_text(
size = 12,
vjust = 2,
family = "Georgia",
face = "bold",
margin = margin(b = 20)
),
axis.title.y = element_text(margin = margin(r = 20)),
axis.title.x = element_text(
size = 12,
vjust = -0.35,
margin = margin(t = 20)
),
plot.background = element_rect(fill = "#EDEFF7"),
panel.background = element_rect(fill = "#EDEFF7"),
legend.background = element_rect(fill = "#EDEFF7"),
legend.title = element_text(
size = 10,
family = "Arial",
face = "bold"
),
legend.text = element_text(size = 8, family = "Arial"),
panel.grid.major = element_line(
size = 0.4,
linetype = "solid",
color = "#cccccc"
),
panel.grid.minor = element_line(size = 0),
axis.ticks = element_blank(),
plot.margin = unit(c(0.5, 1, 1, 1), "cm")
)
colors = c(
"#9E0142",
"#D53E4F",
"#F46D43" ,
"#FDAE61",
"#FEE08B",
"#e7fe8b",
"#bcfe8b",
"#8bfeb1",
"#8bc4fe",
"#8b96fe",
"#ad8bfe",
"#d98bfe",
"#fe8bd1",
"#fe8b96",
"#fb6761"
)
treemap of mechanics
library(treemap)
library(viridis)
library(splitstackshape)
ndata$mechanics <- as.character(ndata$mechanics)
tags <-
cSplit(ndata, splitCols = "mechanics", direction = "long")
tags.table <- as.data.frame(table(tags$mechanics))
treemap(
tags.table,
index = "Var1",
vSize = "Freq",
vColor = "#58ACFA",
palette = viridis(6)
)

distribution of weight
options(repr.plot.width = 3, repr.plot.height = 3)
ndata %>% ggplot(aes(x = average_weight)) + geom_density(fill = "#FDAE61", alpha =
0.4) + mytheme + labs(title = "Distribution of weight")

distribution of ages
options(repr.plot.width = 4, repr.plot.height = 4)
ndata %>% ggplot(aes(x = minage)) + geom_histogram(aes(y = ..density..), fill =
"#9E0142", alpha = 0.4) + mytheme + geom_density(col = "#F46D43") + labs(title =
"Distribution of Age")

category
options(repr.plot.width = 12, repr.plot.height = 20)
category <-
as.data.frame(table(str_trim(unlist(
strsplit(str_trim(as.character(ndata$types)), ", ")
))))
category %>% arrange(desc(Freq)) %>% ggplot(aes(x = Var1, y = Freq, fill =
Var1)) + geom_bar(stat = "identity") + coord_flip() + theme(legend.position = "") +
labs(x = "categories", y = "count", title = "Games Per Category")

distribution of different rating
options(repr.plot.width = 10, repr.plot.height = 4)
g3 <-
ndata %>% ggplot(aes(x = bayes_average_rating)) + geom_density(fill = "#FEE08B", alpha =
0.4) + mytheme + labs(title = "Distribution of Bayes Average Rating")
grid.arrange(g3, nrow = 1, ncol = 1)

options(repr.plot.width = 10, repr.plot.height = 4)
g2 <-
ndata %>% ggplot(aes(x = average_rating)) + geom_density(fill = "#FDAE61", alpha =
0.4) + mytheme + labs(title = "Distribution of Average Rating")
grid.arrange(g2, nrow = 1, ncol = 1)

popular games per average rating
options(repr.plot.width = 10, repr.plot.height = 4)
ndata %>% select(name, average_rating) %>% arrange(desc(average_rating)) %>%
top_n(20) %>% ggplot(aes(x = reorder(name, average_rating), y = average_rating)) +
geom_point(col = "#7f34f3", size = 3) + coord_flip() + geom_segment(aes(
x = name,
xend =
name,
y =
0,
yend =
average_rating
)) + ylim(c(7, 10)) + mytheme + labs(x = "Games", title = "Popular Games per average Rating")
Selecting by average_rating

popular games per bayes average rating
options(repr.plot.width = 10, repr.plot.height = 4)
ndata %>% select(name, bayes_average_rating) %>% arrange(desc(bayes_average_rating)) %>%
top_n(20) %>% ggplot(aes(x = reorder(name, bayes_average_rating), y = bayes_average_rating)) +
geom_point(col = "#7f34f3", size = 3) + coord_flip() + geom_segment(aes(
x = name,
xend =
name,
y =
0,
yend =
bayes_average_rating
)) + ylim(c(7, 10)) + mytheme + labs(x = "Games", title = "Popular Games per bayes average Rating")
Selecting by bayes_average_rating

linear model:
m1. <-
lm(
average_rating ~ types + maxplayers + minage + total_wanters + yearpublished + playingtime + users_rated + average_weight + total_owners,
data = par_year1234
)
summary(m1.)
Call:
lm(formula = average_rating ~ types + maxplayers + minage + total_wanters +
yearpublished + playingtime + users_rated + average_weight +
total_owners, data = par_year1234)
Residuals:
Min 1Q Median 3Q Max
-2.35232 -0.24534 0.01443 0.25114 2.17439
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.87067363 0.11374194 51.614 < 0.0000000000000002 ***
typesboardgame,strategygames 0.03273491 0.05892177 0.556 0.578707
maxplayers 0.01001343 0.00483840 2.070 0.038903 *
minage -0.00623653 0.00839849 -0.743 0.458017
total_wanters 0.00111332 0.00014275 7.799 0.0000000000000263 ***
yearpublished2 0.16490067 0.04966829 3.320 0.000952 ***
yearpublished3 0.33804976 0.05739377 5.890 0.0000000063147203 ***
yearpublished4 0.67470240 0.06218698 10.850 < 0.0000000000000002 ***
playingtime 0.00048708 0.00041633 1.170 0.242478
users_rated -0.00006134 0.00002301 -2.666 0.007869 **
average_weight 0.29092989 0.04547164 6.398 0.0000000003090201 ***
total_owners 0.00003987 0.00001445 2.760 0.005952 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4908 on 624 degrees of freedom
Multiple R-squared: 0.5157, Adjusted R-squared: 0.5072
F-statistic: 60.42 on 11 and 624 DF, p-value: < 0.00000000000000022
par(mfrow = c(2,2))
plot(m1.)

Polynomial regression
quadratic model:
m2s. <-
lm(
average_rating ~ types+ yearpublished+poly(maxplayers, 2) + poly(minage, 2) +
poly(total_wanters, 2)+ poly(playingtime, 2) + poly(users_rated, 2) + poly(average_weight, 2) + poly(total_owners, 2),
data = par_year1234
)
summary(m2s.)
Call:
lm(formula = average_rating ~ types + yearpublished + poly(maxplayers,
2) + poly(minage, 2) + poly(total_wanters, 2) + poly(playingtime,
2) + poly(users_rated, 2) + poly(average_weight, 2) + poly(total_owners,
2), data = par_year1234)
Residuals:
Min 1Q Median 3Q Max
-2.24115 -0.22880 -0.00857 0.23810 2.26954
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 6.78441 0.04968 136.560 < 0.0000000000000002 ***
typesboardgame,strategygames 0.03594 0.05835 0.616 0.538214
yearpublished2 0.17312 0.04772 3.628 0.000310 ***
yearpublished3 0.31212 0.05518 5.657 0.00000002362118310 ***
yearpublished4 0.60649 0.06055 10.016 < 0.0000000000000002 ***
poly(maxplayers, 2)1 1.34974 0.51326 2.630 0.008759 **
poly(maxplayers, 2)2 -0.23954 0.49702 -0.482 0.630013
poly(minage, 2)1 -0.41506 0.53601 -0.774 0.439017
poly(minage, 2)2 -0.54438 0.48860 -1.114 0.265643
poly(total_wanters, 2)1 7.43181 0.91520 8.120 0.00000000000000253 ***
poly(total_wanters, 2)2 -5.17844 0.63806 -8.116 0.00000000000000262 ***
poly(playingtime, 2)1 0.71776 0.72261 0.993 0.320963
poly(playingtime, 2)2 0.24389 0.60269 0.405 0.685867
poly(users_rated, 2)1 -6.36362 2.73241 -2.329 0.020184 *
poly(users_rated, 2)2 4.68346 1.38830 3.374 0.000789 ***
poly(average_weight, 2)1 5.05295 0.96378 5.243 0.00000021752684085 ***
poly(average_weight, 2)2 -0.31244 0.51904 -0.602 0.547426
poly(total_owners, 2)1 5.91401 2.43880 2.425 0.015596 *
poly(total_owners, 2)2 -1.76605 1.35128 -1.307 0.191717
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4671 on 617 degrees of freedom
Multiple R-squared: 0.5664, Adjusted R-squared: 0.5538
F-statistic: 44.78 on 18 and 617 DF, p-value: < 0.00000000000000022
par(mfrow = c(2,2))
plot(m2s.)

three-dimensional models:
m3s. <-
lm(
average_rating ~ types + yearpublished +poly(maxplayers, 3) +
poly(minage, 3) + poly(total_wanters, 3) + poly(playingtime, 3) + poly(users_rated, 3) + poly(average_weight, 3) + poly(total_owners, 3),
data = par_year1234
)
summary(m3s.)
Call:
lm(formula = average_rating ~ types + yearpublished + poly(maxplayers,
3) + poly(minage, 3) + poly(total_wanters, 3) + poly(playingtime,
3) + poly(users_rated, 3) + poly(average_weight, 3) + poly(total_owners,
3), data = par_year1234)
Residuals:
Min 1Q Median 3Q Max
-2.13758 -0.21537 0.00214 0.23257 2.30184
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 6.78748 0.04916 138.063 < 0.0000000000000002 ***
typesboardgame,strategygames 0.03956 0.05934 0.667 0.505293
yearpublished2 0.17642 0.04682 3.768 0.000181 ***
yearpublished3 0.31182 0.05424 5.749 0.0000000142 ***
yearpublished4 0.56972 0.06006 9.486 < 0.0000000000000002 ***
poly(maxplayers, 3)1 1.43614 0.50578 2.839 0.004670 **
poly(maxplayers, 3)2 -0.25292 0.48733 -0.519 0.603950
poly(maxplayers, 3)3 -0.45076 0.47532 -0.948 0.343342
poly(minage, 3)1 -0.17062 0.53241 -0.320 0.748717
poly(minage, 3)2 -0.52461 0.49185 -1.067 0.286571
poly(minage, 3)3 -0.40435 0.50265 -0.804 0.421452
poly(total_wanters, 3)1 9.29756 1.01430 9.166 < 0.0000000000000002 ***
poly(total_wanters, 3)2 -3.60053 0.72168 -4.989 0.0000007921 ***
poly(total_wanters, 3)3 3.74396 0.74363 5.035 0.0000006310 ***
poly(playingtime, 3)1 0.57211 0.72082 0.794 0.427682
poly(playingtime, 3)2 0.45521 0.61624 0.739 0.460384
poly(playingtime, 3)3 -1.53273 0.52647 -2.911 0.003730 **
poly(users_rated, 3)1 -7.20371 2.78451 -2.587 0.009910 **
poly(users_rated, 3)2 2.11544 1.75839 1.203 0.229422
poly(users_rated, 3)3 -4.47925 1.16471 -3.846 0.000133 ***
poly(average_weight, 3)1 4.73463 0.97591 4.851 0.0000015578 ***
poly(average_weight, 3)2 -0.68095 0.54516 -1.249 0.212109
poly(average_weight, 3)3 0.19682 0.50824 0.387 0.698706
poly(total_owners, 3)1 4.74592 2.45059 1.937 0.053250 .
poly(total_owners, 3)2 -1.90774 1.49979 -1.272 0.203857
poly(total_owners, 3)3 2.00152 1.09931 1.821 0.069142 .
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4545 on 610 degrees of freedom
Multiple R-squared: 0.5942, Adjusted R-squared: 0.5775
F-statistic: 35.72 on 25 and 610 DF, p-value: < 0.00000000000000022
par(mfrow = c(2,2))
plot(m3s.)

machine learning:
ndata$average_rating.high <- ndata$average_rating > 7
ndata$average_rating.high <- 1 * (ndata$average_rating.high)
dataset <- ndata
library(caret)
library(lattice)
library(ggplot2)
set.seed(509) # Set random seed
# Shuffle rows
rows <- sample(nrow(dataset))
dataset <- dataset[rows, ]
# create a list of 80% of the rows in the original dataset we can use for training
train_index <-
createDataPartition(dataset$average_rating.high, p = 0.80, list = FALSE)
# Randomly select 80% of data as the training data set
data_tr <- dataset[train_index, ]
# Assign the remaining 20% of as the validation data set
data_va <- dataset[-train_index, ]
head(data_tr, 3)
# scatterplot matrix
library(ellipse) # package ellipse is required
data_tr$types <- as.character(data_tr$types)
data_tr$average_rating.high <-
as.factor(data_tr$average_rating.high)
x <- c(4:7,10:20)
featurePlot(
x = data_tr[, x],
y = data_tr$average_rating.high,
plot = "ellipse",
## Add a key at the top
auto.key = list(columns = 2)
)

# summarize the class distribution
table.class <- table(data_tr$average_rating.high)
percentage <- prop.table(table.class) * 100
print(cbind(counts = table.class, percentage = percentage))
counts percentage
0 340 43.53393
1 441 56.46607
# Run algorithms using 10-fold cross validation
control <- trainControl(method = "cv", number = 10)
metric <- "Accuracy"
dataset$average_rating.high <-
as.factor(dataset$average_rating.high)
# a) linear algorithms
set.seed(7)
fit.lda <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "lda",
metric = metric,
trControl = control
)
# b) nonlinear algorithms
# CART
set.seed(7)
fit.cart <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "rpart",
metric = metric,
trControl = control
)
# kNN
set.seed(7)
fit.knn <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "knn",
metric = metric,
trControl = control
)
# c) advanced algorithms
# SVM
set.seed(7)
fit.svm <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "svmRadial",
metric = metric,
trControl = control
)
# Random Forest
set.seed(7)
fit.rf <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "rf",
metric = metric,
trControl = control
)
# d) Special guests
# XGBoost: LightGBM, etc. Friend in high places :)
set.seed(7)
fit.xgb <-
train(
average_rating.high ~ yearpublished + minplayers + maxplayers + playingtime + minage + users_rated + total_owners + total_traders + total_wanters + total_wishers + total_comments + total_weights + average_weight,
data = dataset,
method = "xgbTree",
metric = metric,
trControl = control
)
# summarize accuracy of models
results <- resamples(list(lda=fit.lda, cart=fit.cart, knn=fit.knn, svm=fit.svm, rf=fit.rf, xgb=fit.xgb))
summary(results)
Call:
summary.resamples(object = results)
Models: lda, cart, knn, svm, rf, xgb
Number of resamples: 10
Accuracy
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
lda 0.6836735 0.7397959 0.7845571 0.7706186 0.8020724 0.8247423 0
cart 0.6428571 0.7500000 0.7704082 0.7582790 0.7815064 0.8041237 0
knn 0.7142857 0.7216495 0.7487376 0.7612666 0.7959184 0.8453608 0
svm 0.7755102 0.8067010 0.8265306 0.8310120 0.8509363 0.9175258 0
rf 0.8163265 0.8380234 0.8564065 0.8545550 0.8673469 0.8969072 0
xgb 0.8265306 0.8392857 0.8564065 0.8597307 0.8740532 0.9175258 0
Kappa
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
lda 0.3560831 0.4729190 0.5571063 0.5334978 0.5972336 0.6440751 0
cart 0.2910294 0.4866880 0.5210937 0.5015601 0.5593714 0.5907173 0
knn 0.4198732 0.4372251 0.4939052 0.5163414 0.5866723 0.6787370 0
svm 0.5418615 0.6060157 0.6495024 0.6563757 0.6970886 0.8320346 0
rf 0.6308079 0.6760997 0.7081475 0.7056573 0.7320100 0.7900433 0
xgb 0.6468843 0.6718148 0.7078990 0.7149074 0.7442114 0.8310840 0
Conclusion and Discussion
- users_rated, average_weight, total_owners have significant effects.
- SVM, Random forest, XG bloost are good for predicting the rating score.
LS0tDQp0aXRsZTogIkJyb2FkR2FtZXMgQW5hbHlzaXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCm5kYXRhIDwtIHJlYWRSRFMoIkM6L1VzZXJzL2RmNTY4OTIzL0Rlc2t0b3Avc3RhdC9kYXRhL25kYXRhLnJkcyIpDQpwYXJfeWVhcjEyMzQgPC0gcmVhZFJEUygiQzovVXNlcnMvZGY1Njg5MjMvRGVza3RvcC9zdGF0L2RhdGEvcGFyX3llYXIxMjM0LnJkcyIpDQpgYGANCiMjIE91dGxpbmUNCiogUXVlc3Rpb25zDQoqIERhdGENCiogUmVzdWx0OiBBbmFseXNpcyBhbmQgRmluZGluZ3MNCiogQ29uY2x1c2lvbiBhbmQgRGlzY3Vzc2lvbg0KDQoNCiMjIFF1ZXN0aW9ucw0KLSBXaGF0IGtpbmQgb2YgQnJvYWRnYW1lcyB0ZW5kcyB0byBiZSBwb3B1bGFyPw0KLSBSZWxhdGlvbiBiZXR3ZWVuIHBhcmFtZXRlcnMgb2YgYnJvYWRnYW1lIGFuZCB0aGUgcmF0aW5nIGl0IGdldHMuDQotIFVzaW5nIE1hY2hpbmUgTGVhcm5pbmcgdG8gcHJlZGljdCB0aGUgcmF0aW5nIHNjb3JlLiANCg0KIyMgRGF0YTogU291cmNlDQpodHRwczovL2JvYXJkZ2FtZWdlZWsuY29tL2JvYXJkZ2FtZS8xNzQ0MzAvZ2xvb21oYXZlbg0KIVtiZ2ddKEM6L1VzZXJzL2RmNTY4OTIzL0Rlc2t0b3Avc3RhdC9SIG5vdGVib29rL2JnZy5wbmcpe3dpZHRoPTkwJX0NCg0KI0RhdGENCmBgYHtyfQ0KaGVhZChuZGF0YSwxKQ0KYGBgDQoNCg0KI2xvYWQgbGlicmFyeQ0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShnZ3JlcGVsKQ0KDQpzdHIobmRhdGEpDQoNCiNtYWtlcyBvcHRpb25zDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkNCm15dGhlbWUgPC0NCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoDQogICAgICBhbmdsZSA9IDkwLA0KICAgICAgc2l6ZSA9IDgsDQogICAgICB2anVzdCA9IDAuNA0KICAgICksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMiwNCiAgICAgIHZqdXN0ID0gMiwNCiAgICAgIGZhbWlseSA9ICJHZW9yZ2lhIiwNCiAgICAgIGZhY2UgPSAiYm9sZCIsDQogICAgICBtYXJnaW4gPSBtYXJnaW4oYiA9IDIwKQ0KICAgICksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMjApKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTIsDQogICAgICB2anVzdCA9IC0wLjM1LA0KICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSAyMCkNCiAgICApLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFREVGRjciKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0VERUZGNyIpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0VERUZGNyIpLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMCwNCiAgICAgIGZhbWlseSA9ICJBcmlhbCIsDQogICAgICBmYWNlID0gImJvbGQiDQogICAgKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgZmFtaWx5ID0gIkFyaWFsIiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZSgNCiAgICAgIHNpemUgPSAwLjQsDQogICAgICBsaW5ldHlwZSA9ICJzb2xpZCIsDQogICAgICBjb2xvciA9ICIjY2NjY2NjIg0KICAgICksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShzaXplID0gMCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjUsIDEsIDEsIDEpLCAiY20iKQ0KICApDQpjb2xvcnMgPSBjKA0KICAiIzlFMDE0MiIsDQogICIjRDUzRTRGIiwNCiAgIiNGNDZENDMiICwNCiAgIiNGREFFNjEiLA0KICAiI0ZFRTA4QiIsDQogICIjZTdmZThiIiwNCiAgIiNiY2ZlOGIiLA0KICAiIzhiZmViMSIsDQogICIjOGJjNGZlIiwNCiAgIiM4Yjk2ZmUiLA0KICAiI2FkOGJmZSIsDQogICIjZDk4YmZlIiwNCiAgIiNmZThiZDEiLA0KICAiI2ZlOGI5NiIsDQogICIjZmI2NzYxIg0KKQ0KYGBgDQoNCiN0cmVlbWFwIG9mIG1lY2hhbmljcw0KYGBge3J9DQpsaWJyYXJ5KHRyZWVtYXApDQpsaWJyYXJ5KHZpcmlkaXMpDQpsaWJyYXJ5KHNwbGl0c3RhY2tzaGFwZSkNCm5kYXRhJG1lY2hhbmljcyA8LSBhcy5jaGFyYWN0ZXIobmRhdGEkbWVjaGFuaWNzKQ0KdGFncyA8LQ0KICBjU3BsaXQobmRhdGEsIHNwbGl0Q29scyA9ICJtZWNoYW5pY3MiLCBkaXJlY3Rpb24gPSAibG9uZyIpDQp0YWdzLnRhYmxlIDwtIGFzLmRhdGEuZnJhbWUodGFibGUodGFncyRtZWNoYW5pY3MpKQ0KDQp0cmVlbWFwKA0KICB0YWdzLnRhYmxlLA0KICBpbmRleCA9ICJWYXIxIiwNCiAgdlNpemUgPSAiRnJlcSIsDQogIHZDb2xvciA9ICIjNThBQ0ZBIiwNCiAgcGFsZXR0ZSA9IHZpcmlkaXMoNikNCikNCmBgYA0KDQoNCg0KI2Rpc3RyaWJ1dGlvbiBvZiB3ZWlnaHQNCmBgYHtyfQ0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAzLCByZXByLnBsb3QuaGVpZ2h0ID0gMykNCm5kYXRhICU+JSBnZ3Bsb3QoYWVzKHggPSBhdmVyYWdlX3dlaWdodCkpICsgZ2VvbV9kZW5zaXR5KGZpbGwgPSAiI0ZEQUU2MSIsIGFscGhhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjQpICsgbXl0aGVtZSArIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHdlaWdodCIpDQpgYGANCg0KI2Rpc3RyaWJ1dGlvbiBvZiBhZ2VzDQpgYGB7cn0NCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gNCwgcmVwci5wbG90LmhlaWdodCA9IDQpDQpuZGF0YSAlPiUgZ2dwbG90KGFlcyh4ID0gbWluYWdlKSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgZmlsbCA9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM5RTAxNDIiLCBhbHBoYSA9IDAuNCkgKyBteXRoZW1lICsgZ2VvbV9kZW5zaXR5KGNvbCA9ICIjRjQ2RDQzIikgKyBsYWJzKHRpdGxlID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzdHJpYnV0aW9uIG9mIEFnZSIpDQpgYGANCg0KI2NhdGVnb3J5DQpgYGB7cn0NCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTIsIHJlcHIucGxvdC5oZWlnaHQgPSAyMCkNCmNhdGVnb3J5IDwtDQogIGFzLmRhdGEuZnJhbWUodGFibGUoc3RyX3RyaW0odW5saXN0KA0KICAgIHN0cnNwbGl0KHN0cl90cmltKGFzLmNoYXJhY3RlcihuZGF0YSR0eXBlcykpLCAiLCAiKQ0KICApKSkpDQpjYXRlZ29yeSAlPiUgYXJyYW5nZShkZXNjKEZyZXEpKSAlPiUgZ2dwbG90KGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEsIGZpbGwgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWYXIxKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiIikgKw0KICBsYWJzKHggPSAiY2F0ZWdvcmllcyIsIHkgPSAiY291bnQiLCB0aXRsZSA9ICJHYW1lcyBQZXIgQ2F0ZWdvcnkiKQ0KYGBgDQoNCg0KIyNkaXN0cmlidXRpb24gb2YgZGlmZmVyZW50IHJhdGluZw0KYGBge3J9DQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDEwLCByZXByLnBsb3QuaGVpZ2h0ID0gNCkNCg0KZzMgPC0NCiAgbmRhdGEgJT4lIGdncGxvdChhZXMoeCA9IGJheWVzX2F2ZXJhZ2VfcmF0aW5nKSkgKyBnZW9tX2RlbnNpdHkoZmlsbCA9ICIjRkVFMDhCIiwgYWxwaGEgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC40KSArIG15dGhlbWUgKyBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCYXllcyBBdmVyYWdlIFJhdGluZyIpDQoNCmdyaWQuYXJyYW5nZShnMywgbnJvdyA9IDEsIG5jb2wgPSAxKQ0KDQoNCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTAsIHJlcHIucGxvdC5oZWlnaHQgPSA0KQ0KZzIgPC0NCiAgbmRhdGEgJT4lIGdncGxvdChhZXMoeCA9IGF2ZXJhZ2VfcmF0aW5nKSkgKyBnZW9tX2RlbnNpdHkoZmlsbCA9ICIjRkRBRTYxIiwgYWxwaGEgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC40KSArIG15dGhlbWUgKyBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBBdmVyYWdlIFJhdGluZyIpDQpncmlkLmFycmFuZ2UoZzIsIG5yb3cgPSAxLCBuY29sID0gMSkNCmBgYA0KDQoNCiNwb3B1bGFyIGdhbWVzIHBlciBhdmVyYWdlIHJhdGluZw0KYGBge3J9DQpvcHRpb25zKHJlcHIucGxvdC53aWR0aCA9IDEwLCByZXByLnBsb3QuaGVpZ2h0ID0gNCkNCm5kYXRhICU+JSBzZWxlY3QobmFtZSwgYXZlcmFnZV9yYXRpbmcpICU+JSBhcnJhbmdlKGRlc2MoYXZlcmFnZV9yYXRpbmcpKSAlPiUNCiAgdG9wX24oMjApICU+JSBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKG5hbWUsIGF2ZXJhZ2VfcmF0aW5nKSwgeSA9IGF2ZXJhZ2VfcmF0aW5nKSkgKw0KICBnZW9tX3BvaW50KGNvbCA9ICIjN2YzNGYzIiwgc2l6ZSA9IDMpICsgY29vcmRfZmxpcCgpICsgZ2VvbV9zZWdtZW50KGFlcygNCiAgICB4ID0gbmFtZSwNCiAgICB4ZW5kID0NCiAgICAgIG5hbWUsDQogICAgeSA9DQogICAgICAwLA0KICAgIHllbmQgPQ0KICAgICAgYXZlcmFnZV9yYXRpbmcNCiAgKSkgKyB5bGltKGMoNywgMTApKSArIG15dGhlbWUgKyBsYWJzKHggPSAiR2FtZXMiLCB0aXRsZSA9ICJQb3B1bGFyIEdhbWVzIHBlciBhdmVyYWdlIFJhdGluZyIpDQpgYGANCg0KI3BvcHVsYXIgZ2FtZXMgcGVyIGJheWVzIGF2ZXJhZ2UgcmF0aW5nDQpgYGB7cn0NCm9wdGlvbnMocmVwci5wbG90LndpZHRoID0gMTAsIHJlcHIucGxvdC5oZWlnaHQgPSA0KQ0KbmRhdGEgJT4lIHNlbGVjdChuYW1lLCBiYXllc19hdmVyYWdlX3JhdGluZykgJT4lIGFycmFuZ2UoZGVzYyhiYXllc19hdmVyYWdlX3JhdGluZykpICU+JQ0KICB0b3BfbigyMCkgJT4lIGdncGxvdChhZXMoeCA9IHJlb3JkZXIobmFtZSwgYmF5ZXNfYXZlcmFnZV9yYXRpbmcpLCB5ID0gYmF5ZXNfYXZlcmFnZV9yYXRpbmcpKSArDQogIGdlb21fcG9pbnQoY29sID0gIiM3ZjM0ZjMiLCBzaXplID0gMykgKyBjb29yZF9mbGlwKCkgKyBnZW9tX3NlZ21lbnQoYWVzKA0KICAgIHggPSBuYW1lLA0KICAgIHhlbmQgPQ0KICAgICAgbmFtZSwNCiAgICB5ID0NCiAgICAgIDAsDQogICAgeWVuZCA9DQogICAgICBiYXllc19hdmVyYWdlX3JhdGluZw0KICApKSArIHlsaW0oYyg3LCAxMCkpICsgbXl0aGVtZSArIGxhYnMoeCA9ICJHYW1lcyIsIHRpdGxlID0gIlBvcHVsYXIgR2FtZXMgcGVyIGJheWVzIGF2ZXJhZ2UgUmF0aW5nIikNCmBgYA0KDQoNCg0KI2xpbmVhciBtb2RlbDoNCmBgYHtyfQ0KbTEuIDwtDQogIGxtKA0KICAgIGF2ZXJhZ2VfcmF0aW5nIH4gdHlwZXMgKyBtYXhwbGF5ZXJzICsgbWluYWdlICsgdG90YWxfd2FudGVycyArIHllYXJwdWJsaXNoZWQgKyBwbGF5aW5ndGltZSArIHVzZXJzX3JhdGVkICsgYXZlcmFnZV93ZWlnaHQgKyB0b3RhbF9vd25lcnMsDQogICAgZGF0YSA9IHBhcl95ZWFyMTIzNA0KICApDQpzdW1tYXJ5KG0xLikNCnBhcihtZnJvdyA9IGMoMiwyKSkNCnBsb3QobTEuKQ0KYGBgDQoNCiNQb2x5bm9taWFsIHJlZ3Jlc3Npb24NCiNxdWFkcmF0aWMgbW9kZWw6DQpgYGB7cn0NCm0ycy4gPC0NCiAgbG0oDQogICAgYXZlcmFnZV9yYXRpbmcgfiB0eXBlcysgeWVhcnB1Ymxpc2hlZCtwb2x5KG1heHBsYXllcnMsIDIpICsgcG9seShtaW5hZ2UsIDIpICsNCiAgICAgIHBvbHkodG90YWxfd2FudGVycywgMikrIHBvbHkocGxheWluZ3RpbWUsIDIpICsgcG9seSh1c2Vyc19yYXRlZCwgMikgKyBwb2x5KGF2ZXJhZ2Vfd2VpZ2h0LCAyKSArIHBvbHkodG90YWxfb3duZXJzLCAyKSwNCiAgICBkYXRhID0gcGFyX3llYXIxMjM0DQogICkNCnN1bW1hcnkobTJzLikNCnBhcihtZnJvdyA9IGMoMiwyKSkNCnBsb3QobTJzLikNCmBgYA0KDQoNCiN0aHJlZS1kaW1lbnNpb25hbCBtb2RlbHM6DQpgYGB7cn0NCm0zcy4gPC0NCiAgbG0oDQogICAgYXZlcmFnZV9yYXRpbmcgfiB0eXBlcyAgKyB5ZWFycHVibGlzaGVkICtwb2x5KG1heHBsYXllcnMsIDMpICArDQogICAgICBwb2x5KG1pbmFnZSwgMykgKyBwb2x5KHRvdGFsX3dhbnRlcnMsIDMpICsgcG9seShwbGF5aW5ndGltZSwgMykgKyBwb2x5KHVzZXJzX3JhdGVkLCAzKSArIHBvbHkoYXZlcmFnZV93ZWlnaHQsIDMpICsgcG9seSh0b3RhbF9vd25lcnMsIDMpLA0KICAgIGRhdGEgPSBwYXJfeWVhcjEyMzQNCiAgKQ0Kc3VtbWFyeShtM3MuKQ0KcGFyKG1mcm93ID0gYygyLDIpKQ0KcGxvdChtM3MuKQ0KYGBgDQoNCg0KI21hY2hpbmUgbGVhcm5pbmc6DQpgYGB7cn0NCm5kYXRhJGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggPC0gbmRhdGEkYXZlcmFnZV9yYXRpbmcgPiA3DQpuZGF0YSRhdmVyYWdlX3JhdGluZy5oaWdoIDwtICAxICogKG5kYXRhJGF2ZXJhZ2VfcmF0aW5nLmhpZ2gpDQoNCg0KDQpkYXRhc2V0IDwtIG5kYXRhDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShsYXR0aWNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpzZXQuc2VlZCg1MDkpICAgIyBTZXQgcmFuZG9tIHNlZWQNCiMgU2h1ZmZsZSByb3dzDQpyb3dzIDwtIHNhbXBsZShucm93KGRhdGFzZXQpKQ0KZGF0YXNldCA8LSBkYXRhc2V0W3Jvd3MsIF0NCg0KIyBjcmVhdGUgYSBsaXN0IG9mIDgwJSBvZiB0aGUgcm93cyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldCB3ZSBjYW4gdXNlIGZvciB0cmFpbmluZw0KdHJhaW5faW5kZXggPC0NCiAgY3JlYXRlRGF0YVBhcnRpdGlvbihkYXRhc2V0JGF2ZXJhZ2VfcmF0aW5nLmhpZ2gsIHAgPSAwLjgwLCBsaXN0ID0gRkFMU0UpDQojIFJhbmRvbWx5IHNlbGVjdCA4MCUgb2YgZGF0YSBhcyB0aGUgdHJhaW5pbmcgZGF0YSBzZXQNCmRhdGFfdHIgPC0gZGF0YXNldFt0cmFpbl9pbmRleCwgXQ0KIyBBc3NpZ24gdGhlIHJlbWFpbmluZyAyMCUgb2YgYXMgdGhlIHZhbGlkYXRpb24gZGF0YSBzZXQNCmRhdGFfdmEgPC0gZGF0YXNldFstdHJhaW5faW5kZXgsIF0NCg0KaGVhZChkYXRhX3RyLCAzKQ0KYGBgDQoNCmBgYHtyfQ0KIyBzY2F0dGVycGxvdCBtYXRyaXgNCmxpYnJhcnkoZWxsaXBzZSkgICAgIyBwYWNrYWdlIGVsbGlwc2UgaXMgcmVxdWlyZWQNCmRhdGFfdHIkdHlwZXMgPC0gYXMuY2hhcmFjdGVyKGRhdGFfdHIkdHlwZXMpDQpkYXRhX3RyJGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggPC0NCiAgYXMuZmFjdG9yKGRhdGFfdHIkYXZlcmFnZV9yYXRpbmcuaGlnaCkNCnggPC0gYyg0OjcsMTA6MjApDQpmZWF0dXJlUGxvdCgNCiAgeCA9IGRhdGFfdHJbLCB4XSwNCiAgeSA9IGRhdGFfdHIkYXZlcmFnZV9yYXRpbmcuaGlnaCwNCiAgcGxvdCA9ICJlbGxpcHNlIiwNCiAgIyMgQWRkIGEga2V5IGF0IHRoZSB0b3ANCiAgYXV0by5rZXkgPSBsaXN0KGNvbHVtbnMgPSAyKQ0KKQ0KDQojIHN1bW1hcml6ZSB0aGUgY2xhc3MgZGlzdHJpYnV0aW9uDQp0YWJsZS5jbGFzcyA8LSB0YWJsZShkYXRhX3RyJGF2ZXJhZ2VfcmF0aW5nLmhpZ2gpDQpwZXJjZW50YWdlIDwtIHByb3AudGFibGUodGFibGUuY2xhc3MpICogMTAwDQpwcmludChjYmluZChjb3VudHMgPSB0YWJsZS5jbGFzcywgcGVyY2VudGFnZSA9IHBlcmNlbnRhZ2UpKQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KIyBSdW4gYWxnb3JpdGhtcyB1c2luZyAxMC1mb2xkIGNyb3NzIHZhbGlkYXRpb24NCmNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQ0KbWV0cmljIDwtICJBY2N1cmFjeSINCg0KDQpkYXRhc2V0JGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggPC0NCiAgYXMuZmFjdG9yKGRhdGFzZXQkYXZlcmFnZV9yYXRpbmcuaGlnaCkNCiMgYSkgbGluZWFyIGFsZ29yaXRobXMNCnNldC5zZWVkKDcpDQpmaXQubGRhIDwtDQogIHRyYWluKA0KICAgIGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggfiB5ZWFycHVibGlzaGVkICsgbWlucGxheWVycyArIG1heHBsYXllcnMgKyBwbGF5aW5ndGltZSArIG1pbmFnZSArIHVzZXJzX3JhdGVkICsgdG90YWxfb3duZXJzICsgdG90YWxfdHJhZGVycyArIHRvdGFsX3dhbnRlcnMgKyB0b3RhbF93aXNoZXJzICsgdG90YWxfY29tbWVudHMgKyB0b3RhbF93ZWlnaHRzICsgYXZlcmFnZV93ZWlnaHQsDQogICAgZGF0YSA9IGRhdGFzZXQsDQogICAgbWV0aG9kID0gImxkYSIsDQogICAgbWV0cmljID0gbWV0cmljLA0KICAgIHRyQ29udHJvbCA9IGNvbnRyb2wNCiAgKQ0KDQojIGIpIG5vbmxpbmVhciBhbGdvcml0aG1zDQojIENBUlQNCnNldC5zZWVkKDcpDQpmaXQuY2FydCA8LQ0KICB0cmFpbigNCiAgICBhdmVyYWdlX3JhdGluZy5oaWdoIH4geWVhcnB1Ymxpc2hlZCArIG1pbnBsYXllcnMgKyBtYXhwbGF5ZXJzICsgcGxheWluZ3RpbWUgKyBtaW5hZ2UgKyB1c2Vyc19yYXRlZCArIHRvdGFsX293bmVycyArIHRvdGFsX3RyYWRlcnMgKyB0b3RhbF93YW50ZXJzICsgdG90YWxfd2lzaGVycyArIHRvdGFsX2NvbW1lbnRzICsgdG90YWxfd2VpZ2h0cyArIGF2ZXJhZ2Vfd2VpZ2h0LA0KICAgIGRhdGEgPSBkYXRhc2V0LA0KICAgIG1ldGhvZCA9ICJycGFydCIsDQogICAgbWV0cmljID0gbWV0cmljLA0KICAgIHRyQ29udHJvbCA9IGNvbnRyb2wNCiAgKQ0KDQojIGtOTg0Kc2V0LnNlZWQoNykNCmZpdC5rbm4gPC0NCiAgdHJhaW4oDQogICAgYXZlcmFnZV9yYXRpbmcuaGlnaCB+IHllYXJwdWJsaXNoZWQgKyBtaW5wbGF5ZXJzICsgbWF4cGxheWVycyArIHBsYXlpbmd0aW1lICsgbWluYWdlICsgdXNlcnNfcmF0ZWQgKyB0b3RhbF9vd25lcnMgKyB0b3RhbF90cmFkZXJzICsgdG90YWxfd2FudGVycyArIHRvdGFsX3dpc2hlcnMgKyB0b3RhbF9jb21tZW50cyArIHRvdGFsX3dlaWdodHMgKyBhdmVyYWdlX3dlaWdodCwNCiAgICBkYXRhID0gZGF0YXNldCwNCiAgICBtZXRob2QgPSAia25uIiwNCiAgICBtZXRyaWMgPSBtZXRyaWMsDQogICAgdHJDb250cm9sID0gY29udHJvbA0KICApDQoNCiMgYykgYWR2YW5jZWQgYWxnb3JpdGhtcw0KIyBTVk0NCnNldC5zZWVkKDcpDQpmaXQuc3ZtIDwtDQogIHRyYWluKA0KICAgIGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggfiB5ZWFycHVibGlzaGVkICsgbWlucGxheWVycyArIG1heHBsYXllcnMgKyBwbGF5aW5ndGltZSArIG1pbmFnZSArIHVzZXJzX3JhdGVkICsgdG90YWxfb3duZXJzICsgdG90YWxfdHJhZGVycyArIHRvdGFsX3dhbnRlcnMgKyB0b3RhbF93aXNoZXJzICsgdG90YWxfY29tbWVudHMgKyB0b3RhbF93ZWlnaHRzICsgYXZlcmFnZV93ZWlnaHQsDQogICAgZGF0YSA9IGRhdGFzZXQsDQogICAgbWV0aG9kID0gInN2bVJhZGlhbCIsDQogICAgbWV0cmljID0gbWV0cmljLA0KICAgIHRyQ29udHJvbCA9IGNvbnRyb2wNCiAgKQ0KDQojIFJhbmRvbSBGb3Jlc3QNCnNldC5zZWVkKDcpDQpmaXQucmYgPC0NCiAgdHJhaW4oDQogICAgYXZlcmFnZV9yYXRpbmcuaGlnaCB+IHllYXJwdWJsaXNoZWQgKyBtaW5wbGF5ZXJzICsgbWF4cGxheWVycyArIHBsYXlpbmd0aW1lICsgbWluYWdlICsgdXNlcnNfcmF0ZWQgKyB0b3RhbF9vd25lcnMgKyB0b3RhbF90cmFkZXJzICsgdG90YWxfd2FudGVycyArIHRvdGFsX3dpc2hlcnMgKyB0b3RhbF9jb21tZW50cyArIHRvdGFsX3dlaWdodHMgKyBhdmVyYWdlX3dlaWdodCwNCiAgICBkYXRhID0gZGF0YXNldCwNCiAgICBtZXRob2QgPSAicmYiLA0KICAgIG1ldHJpYyA9IG1ldHJpYywNCiAgICB0ckNvbnRyb2wgPSBjb250cm9sDQogICkNCg0KIyBkKSBTcGVjaWFsIGd1ZXN0cw0KIyBYR0Jvb3N0OiBMaWdodEdCTSwgZXRjLiBGcmllbmQgaW4gaGlnaCBwbGFjZXMgOikNCnNldC5zZWVkKDcpDQpmaXQueGdiIDwtDQogIHRyYWluKA0KICAgIGF2ZXJhZ2VfcmF0aW5nLmhpZ2ggfiB5ZWFycHVibGlzaGVkICsgbWlucGxheWVycyArIG1heHBsYXllcnMgKyBwbGF5aW5ndGltZSArIG1pbmFnZSArIHVzZXJzX3JhdGVkICsgdG90YWxfb3duZXJzICsgdG90YWxfdHJhZGVycyArIHRvdGFsX3dhbnRlcnMgKyB0b3RhbF93aXNoZXJzICsgdG90YWxfY29tbWVudHMgKyB0b3RhbF93ZWlnaHRzICsgYXZlcmFnZV93ZWlnaHQsDQogICAgZGF0YSA9IGRhdGFzZXQsDQogICAgbWV0aG9kID0gInhnYlRyZWUiLA0KICAgIG1ldHJpYyA9IG1ldHJpYywNCiAgICB0ckNvbnRyb2wgPSBjb250cm9sDQogICkNCg0KIyBzdW1tYXJpemUgYWNjdXJhY3kgb2YgbW9kZWxzDQpyZXN1bHRzIDwtIHJlc2FtcGxlcyhsaXN0KGxkYT1maXQubGRhLCBjYXJ0PWZpdC5jYXJ0LCBrbm49Zml0Lmtubiwgc3ZtPWZpdC5zdm0sIHJmPWZpdC5yZiwgeGdiPWZpdC54Z2IpKQ0Kc3VtbWFyeShyZXN1bHRzKQ0KYGBgDQoNCg0KIyMgQ29uY2x1c2lvbiBhbmQgRGlzY3Vzc2lvbg0KDQotICB1c2Vyc19yYXRlZCwgYXZlcmFnZV93ZWlnaHQsIHRvdGFsX293bmVycyBoYXZlIHNpZ25pZmljYW50IGVmZmVjdHMuICANCi0gIFNWTSwgUmFuZG9tIGZvcmVzdCwgWEcgYmxvb3N0IGFyZSBnb29kIGZvciBwcmVkaWN0aW5nIHRoZSByYXRpbmcgc2NvcmUuDQoNCiMjIyBSZWZlcmVuY2VzDQotaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kZXZpc2FuZ2VldGhhL2luc2lnaHRzLWdlZWstYm9hcmQtZ2FtZSAgDQotaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9tYXhwaGlsaXBwL2JvYXJkLWdhbWVzLW1lY2hhbmljcw0KDQoNCg0KDQoNCg0K