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: Source

https://boardgamegeek.com/boardgame/174430/gloomhaven bgg

Data

head(ndata,1)

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.&#10;&#10;The Duke is a dynamic, tile-based strategy game with an old-world, feudal the"| __truncated__ "&quot;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__ "&quot;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)

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