The Data
The dataset I have chosen to conduct my regression analysis is the (LoL)
League of Legends Ranked Games dataset. This data looks at ranked
League of Legends games played during season 9 in the EUW region. This
dataset was collected using the Riot Games API, which makes it easy to
look up and collect information on a users ranked history and collect
their games.
# Load packages
library(ggplot2)
library(rstanarm)
library(bayesplot)
library(bayesrules)
library(tidyverse)
library(tidybayes)
library(dplyr)
library(broom.mixed)
library(interactions)
To preface this analysis, one must first understand the game of
League of Legends, or LOL for short. In LOL, two 5 person teams fight to
destroy each others nexus and get to choose and ban a champion, each
with a different set of skills and abilities, and 2 summoner spells to
do so. Along the way, the players must both fight each other, destroy
objectives such as towers and inhibitors, and strategize effectively to
reach the opponent’s nexus. There are also several monsters that teams
can defeat to buff them as well, such as Rift Herald, Baron Nashor, and
an assorted set of Dragons.
We will use lol_data
to build various models of League
of Legends gameDuration
. Throughout, we’ll utilize weakly
informative priors and a basic understanding that LOL games usually are
30
minutes but can range from 25-35 minutes. We will asses an array of
different predictors and combinations to determine what can provide us
the best fit for predicting the game duration of a League of Legends
game. A base criteria for these games is there at least needs to be one
tower, one inhibitor, and one champion kill for each game. This is to
mitigate the amount of games that teams may have forfeited due to a
player leaving or trolling.
lol_data <- read.csv("games.csv",
sep=",",
na.strings=c(""," ","NA","N/A")
)
head(lol_data)
Setting Up the Data
Transforming data to fit baseline of at least one kill, tower, and
inhibitor
lol_data <- lol_data[!(lol_data$firstBlood == 0 | lol_data$firstTower == 0 | lol_data$firstInhibitor == 0), ]
nrow(lol_data)
[1] 45214
colnames(lol_data)
[1] "gameId" "creationTime" "gameDuration"
[4] "seasonId" "winner" "firstBlood"
[7] "firstTower" "firstInhibitor" "firstBaron"
[10] "firstDragon" "firstRiftHerald" "t1_champ1id"
[13] "t1_champ1_sum1" "t1_champ1_sum2" "t1_champ2id"
[16] "t1_champ2_sum1" "t1_champ2_sum2" "t1_champ3id"
[19] "t1_champ3_sum1" "t1_champ3_sum2" "t1_champ4id"
[22] "t1_champ4_sum1" "t1_champ4_sum2" "t1_champ5id"
[25] "t1_champ5_sum1" "t1_champ5_sum2" "t1_towerKills"
[28] "t1_inhibitorKills" "t1_baronKills" "t1_dragonKills"
[31] "t1_riftHeraldKills" "t1_ban1" "t1_ban2"
[34] "t1_ban3" "t1_ban4" "t1_ban5"
[37] "t2_champ1id" "t2_champ1_sum1" "t2_champ1_sum2"
[40] "t2_champ2id" "t2_champ2_sum1" "t2_champ2_sum2"
[43] "t2_champ3id" "t2_champ3_sum1" "t2_champ3_sum2"
[46] "t2_champ4id" "t2_champ4_sum1" "t2_champ4_sum2"
[49] "t2_champ5id" "t2_champ5_sum1" "t2_champ5_sum2"
[52] "t2_towerKills" "t2_inhibitorKills" "t2_baronKills"
[55] "t2_dragonKills" "t2_riftHeraldKills" "t2_ban1"
[58] "t2_ban2" "t2_ban3" "t2_ban4"
[61] "t2_ban5"
We can clean up our data by omitting unnecessary columns
lol_data <- subset(lol_data, select = -c(t2_ban1, t2_ban2, t2_ban3, t2_ban4, t2_ban5, t1_ban1, t1_ban2, t1_ban3, t1_ban4, t1_ban5, t1_champ1_sum1, t1_champ2_sum1, t1_champ3_sum1, t1_champ4_sum1, t1_champ5_sum1, t2_champ5_sum1, t2_champ1_sum1, t2_champ2_sum1, t2_champ3_sum1, t2_champ4_sum1, t2_champ5_sum1, t1_champ1_sum2, t1_champ2_sum2, t1_champ3_sum2, t1_champ4_sum2, t1_champ5_sum2, t2_champ1_sum2, t2_champ1_sum2, t2_champ2_sum2, t2_champ3_sum2, t2_champ4_sum2, t2_champ5_sum2, t1_champ1id, t1_champ2id, t1_champ3id, t1_champ4id, t1_champ5id, t2_champ1id, t2_champ2id, t2_champ3id, t2_champ4id, t2_champ5id))
colnames(lol_data)
[1] "gameId" "creationTime" "gameDuration"
[4] "seasonId" "winner" "firstBlood"
[7] "firstTower" "firstInhibitor" "firstBaron"
[10] "firstDragon" "firstRiftHerald" "t1_towerKills"
[13] "t1_inhibitorKills" "t1_baronKills" "t1_dragonKills"
[16] "t1_riftHeraldKills" "t2_towerKills" "t2_inhibitorKills"
[19] "t2_baronKills" "t2_dragonKills" "t2_riftHeraldKills"
We can also covert some of the columns to factors for team 1 and team
2 for ease of visualization and interpretation
lol_data$winner <- as.factor(lol_data$winner)
lol_data$firstBlood <- as.factor(lol_data$firstBlood)
lol_data$firstTower <- as.factor(lol_data$firstTower)
lol_data$firstInhibitor <- as.factor(lol_data$firstInhibitor)
lol_data$firstBaron <- as.factor(lol_data$firstBaron)
lol_data$firstDragon <- as.factor(lol_data$firstDragon)
lol_data$firstRiftHerald <- as.factor(lol_data$firstRiftHerald)
head(lol_data)
Summary Analysis
Here are some visualizations and statistics to help better understand
our data and what we are working with.
summary(lol_data)
gameId creationTime gameDuration seasonId
Min. :3.215e+09 Min. :1.497e+12 Min. : 477 Min. :9
1st Qu.:3.292e+09 1st Qu.:1.502e+12 1st Qu.:1632 1st Qu.:9
Median :3.320e+09 Median :1.504e+12 Median :1895 Median :9
Mean :3.306e+09 Mean :1.503e+12 Mean :1930 Mean :9
3rd Qu.:3.327e+09 3rd Qu.:1.504e+12 3rd Qu.:2196 3rd Qu.:9
Max. :3.332e+09 Max. :1.505e+12 Max. :4728 Max. :9
winner firstBlood firstTower firstInhibitor firstBaron firstDragon
1:22867 1:23151 1:23248 1:23054 0:14617 0: 434
2:22347 2:22063 2:21966 2:22160 1:14469 1:22258
2:16128 2:22522
firstRiftHerald t1_towerKills t1_inhibitorKills t1_baronKills
0:21922 Min. : 0.000 Min. : 0.000 Min. :0.0000
1:11933 1st Qu.: 3.000 1st Qu.: 0.000 1st Qu.:0.0000
2:11359 Median : 7.000 Median : 1.000 Median :0.0000
Mean : 6.173 Mean : 1.159 Mean :0.4173
3rd Qu.:10.000 3rd Qu.: 2.000 3rd Qu.:1.0000
Max. :11.000 Max. :10.000 Max. :5.0000
t1_dragonKills t1_riftHeraldKills t2_towerKills t2_inhibitorKills
Min. :0.000 Min. :0.0000 Min. : 0.000 Min. : 0.000
1st Qu.:0.000 1st Qu.:0.0000 1st Qu.: 2.000 1st Qu.: 0.000
Median :1.000 Median :0.0000 Median : 7.000 Median : 1.000
Mean :1.483 Mean :0.2639 Mean : 6.014 Mean : 1.122
3rd Qu.:2.000 3rd Qu.:1.0000 3rd Qu.:10.000 3rd Qu.: 2.000
Max. :6.000 Max. :1.0000 Max. :11.000 Max. :10.000
t2_baronKills t2_dragonKills t2_riftHeraldKills
Min. :0.0000 Min. :0.000 Min. :0.0000
1st Qu.:0.0000 1st Qu.:0.000 1st Qu.:0.0000
Median :0.0000 Median :1.000 Median :0.0000
Mean :0.4641 Mean :1.506 Mean :0.2512
3rd Qu.:1.0000 3rd Qu.:2.000 3rd Qu.:1.0000
Max. :4.0000 Max. :6.000 Max. :1.0000
Some conclusions we can make here:
The mean game time is around 1930 seconds (roughly 32
minutes)
Game duration lies mostly between 1632 and 2196
Team 1 has won more games, has more first bloods, towers,
inhibitors, and rift heralds
Team 2 has more first barons and dragons.
Team 1’s tower, inhibitor, and herald kills are higher than Team
2’s which is reflected from them getting the first of each more often
than not.
Team 2’s dragon and baron kills are higher than Team 1’s which is
reflected from them getting the first of each more often than
not.
Visualizations
We can use ggplot do visualize some of our findings
Response Distribution
ggplot(lol_data, aes(x = gameDuration)) +
geom_histogram(binwidth = 60, fill = "blue", color = "black") +
labs(x = "Game Duration (seconds)", y = "Frequency", title = "Distribution of Game Duration") +
theme_minimal()

Game duration seems to be a bit right-skewed
First Comparisons
ggplot(lol_data, aes(x = winner, fill = winner)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "Winners")

ggplot(lol_data, aes(x = firstBlood, fill = firstBlood)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Bloods")

ggplot(lol_data, aes(x = firstTower, fill = firstTower)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Towers")

ggplot(lol_data, aes(x = firstInhibitor, fill = firstInhibitor)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Inhibitors")

ggplot(lol_data, aes(x = firstDragon, fill = firstDragon)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Dragons")

ggplot(lol_data, aes(x = firstRiftHerald, fill = firstRiftHerald)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Rift Heralds")

ggplot(lol_data, aes(x = firstBaron, fill = firstBaron)) +
geom_bar() +
theme(text = element_text(size=9)) +
labs(y = "First Barons")

These all are consistent with our previous summary findings about
first categories
Total Objectives Comparisons
ggplot(lol_data, aes(x = t1_towerKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

ggplot(lol_data, aes(x = t2_towerKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

tower_kills <- data.frame(Team = c("T1", "T2"),
Kills = c(sum(lol_data$t1_towerKills, na.rm = TRUE),
sum(lol_data$t2_towerKills, na.rm = TRUE)))
ggplot(tower_kills, aes(x = Team, y = Kills, fill = Team)) +
geom_bar(stat = "identity") +
labs(x = "Team", y = "Total Tower Kills", title = "Comparison of Tower Kills between T1 and T2")

More often than not, both teams tend to kill >6 towers per
game
ggplot(lol_data, aes(x = t1_inhibitorKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

ggplot(lol_data, aes(x = t2_inhibitorKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

# Calculate the total number of inhibitor kills for each team
inhibitor_kills <- data.frame(Team = c("T1", "T2"),
Kills = c(sum(lol_data$t1_inhibitorKills, na.rm = TRUE),
sum(lol_data$t2_inhibitorKills, na.rm = TRUE)))
ggplot(inhibitor_kills, aes(x = Team, y = Kills, fill = Team)) +
geom_bar(stat = "identity") +
labs(x = "Team", y = "Total Inhibitor Kills", title = "Comparison of Inhibitor Kills between T1 and T2")

Games usually end with 0 to 2 inhibitors being destroyed, likely due
to late game forfeits or steam rolls (which is often the case in many
games)
ggplot(lol_data, aes(x = t1_dragonKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

ggplot(lol_data, aes(x = t2_dragonKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

# Calculate the total number of dragon kills for each team
dragon_kills <- data.frame(Team = c("T1", "T2"),
Kills = c(sum(lol_data$t1_dragonKills, na.rm = TRUE),
sum(lol_data$t2_dragonKills, na.rm = TRUE)))
ggplot(dragon_kills, aes(x = Team, y = Kills, fill = Team)) +
geom_bar(stat = "identity") +
labs(x = "Team", y = "Total Dragon Kills", title = "Comparison of Dragon Kills between T1 and T2")

Dragon kills comfortably lie within the 0-2 range
ggplot(lol_data, aes(x = t1_riftHeraldKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

ggplot(lol_data, aes(x = t2_riftHeraldKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

# Calculate the total number of rift herald kills for each team
riftHerald_kills <- data.frame(Team = c("T1", "T2"),
Kills = c(sum(lol_data$t1_riftHeraldKills, na.rm = TRUE),
sum(lol_data$t2_riftHeraldKills, na.rm = TRUE)))
ggplot(riftHerald_kills, aes(x = Team, y = Kills, fill = Team)) +
geom_bar(stat = "identity") +
labs(x = "Team", y = "Total Rift Herald Kills", title = "Comparison of Rift Herald Kills between T1 and T2")

Rift herald only spawns from 9:50 - 19:45 during the game and is most
often only taken once if at all
ggplot(lol_data, aes(x = t1_baronKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

ggplot(lol_data, aes(x = t2_baronKills)) +
geom_bar() +
theme(text = element_text(size=10)) +
labs(y = "Count")

# Calculate the total number of baron kills for each team
baron_kills <- data.frame(Team = c("T1", "T2"),
Kills = c(sum(lol_data$t1_baronKills, na.rm = TRUE),
sum(lol_data$t2_baronKills, na.rm = TRUE)))
ggplot(baron_kills, aes(x = Team, y = Kills, fill = Team)) +
geom_bar(stat = "identity") +
labs(x = "Team", y = "Total Baron Kills", title = "Comparison of Baron Kills between T1 and T2")

Baron spawns after the rift herald and usually is game over if taken
and used properly, hence why the amount taken is usually 0 or 1 as
sometimes games end before it can be taken
Base Model and Prior Modeling
Lets start off with a base model to see if we can get insight from
just the winner of the match
base <- stan_glm(gameDuration ~ winner,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 8e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.8 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 0.248 seconds (Warm-up)
Chain 1: 13.035 seconds (Sampling)
Chain 1: 13.283 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.6e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 0.227 seconds (Warm-up)
Chain 2: 13.029 seconds (Sampling)
Chain 2: 13.256 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 2.2e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.22 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 0.239 seconds (Warm-up)
Chain 3: 13.007 seconds (Sampling)
Chain 3: 13.246 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.6e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 0.239 seconds (Warm-up)
Chain 4: 12.989 seconds (Sampling)
Chain 4: 13.228 seconds (Total)
Chain 4:
prior_summary(base)
Priors for model 'base'
------
Intercept (after predictors centered)
Specified prior:
~ normal(location = 1800, scale = 150)
Adjusted prior:
~ normal(location = 1800, scale = 64093)
Coefficients
Specified prior:
~ normal(location = 0, scale = 2.5)
Adjusted prior:
~ normal(location = 0, scale = 2137)
Auxiliary (sigma)
Specified prior:
~ exponential(rate = 1)
Adjusted prior:
~ exponential(rate = 0.0023)
------
See help('prior_summary.stanreg') for more details
A prior predictive check can be used to see what we can potentially
expect from the data alone and what the stan model viewed as appropriate
for our predictions
base_priors <- update(base, prior_PD = TRUE)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1.2e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 4.083 seconds (Warm-up)
Chain 1: 0.161 seconds (Sampling)
Chain 1: 4.244 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.7e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 2.508 seconds (Warm-up)
Chain 2: 0.148 seconds (Sampling)
Chain 2: 2.656 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 1.2e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 4.038 seconds (Warm-up)
Chain 3: 0.161 seconds (Sampling)
Chain 3: 4.199 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.2e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.12 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 4.794 seconds (Warm-up)
Chain 4: 0.159 seconds (Sampling)
Chain 4: 4.953 seconds (Total)
Chain 4:
# 200 prior model lines
lol_data %>%
add_fitted_draws(base, n = 200) %>%
ggplot(aes(x = winner, y = gameDuration)) +
geom_line(aes(y = .value, group = .draw), alpha = 0.05)
Warning: `fitted_draws` and `add_fitted_draws` are deprecated as their names were confusing.
- Use [add_]epred_draws() to get the expectation of the posterior predictive.
- Use [add_]linpred_draws() to get the distribution of the linear predictor.
- For example, you used [add_]fitted_draws(..., scale = "response"), which
means you most likely want [add_]epred_draws(...).
NOTE: When updating to the new functions, note that the `model` parameter is now
named `object` and the `n` parameter is now named `ndraws`.

# 4 prior simulated datasets
set.seed(3)
lol_data %>%
add_predicted_draws(base, n = 4) %>%
ggplot(aes(x = winner, y = gameDuration)) +
geom_point(aes(y = .prediction, group = .draw)) +
facet_wrap(~ .draw)
Warning:
In add_predicted_draws(): The `n` argument is a deprecated alias for `ndraws`.
Use the `ndraws` argument instead.
See help("tidybayes-deprecated").

Prior distribution expects the games to range from 1910 - 1945
seconds as expected
Game duration lies between 500-3500 seconds which falls in line with
our summary
Prior distribution expects games to last longer if team 2 wins as
compared to team 1
mcmc_trace(base, size = .1)

Plots look fast mixing and consistent
rhat(base)
(Intercept) winner2 sigma
0.9998587 0.9999295 0.9999225
Rhat close to 1 and not >1.05, good
neff_ratio(base)
(Intercept) winner2 sigma
0.92220 0.95970 0.95575
neff ratio is a little high but still acceptable, >.10 which is
good
tidy(base, effects = c("fixed", "aux"),
conf.int = TRUE, conf.level = 0.95)
Overall the model could work, but more investigation should be done
to improve what we have
Interaction Investigation
Lets see if there are some interactions we can expect
Speaking from experience in playing the game myself, I predict the
dragon and baron kills will have a big impact on the game duration due
to the buffs they give each member of the team being crucial to
winning
int <- stan_glm(gameDuration ~ t1_dragonKills:t2_dragonKills,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 2.4e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.24 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 0.266 seconds (Warm-up)
Chain 1: 13.025 seconds (Sampling)
Chain 1: 13.291 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.6e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 0.259 seconds (Warm-up)
Chain 2: 13.003 seconds (Sampling)
Chain 2: 13.262 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 1.7e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 0.251 seconds (Warm-up)
Chain 3: 12.961 seconds (Sampling)
Chain 3: 13.212 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.7e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 0.234 seconds (Warm-up)
Chain 4: 13.145 seconds (Sampling)
Chain 4: 13.379 seconds (Total)
Chain 4:
int2 <- stan_glm(gameDuration ~ t1_baronKills:t2_baronKills,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1.8e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 0.256 seconds (Warm-up)
Chain 1: 13.03 seconds (Sampling)
Chain 1: 13.286 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.7e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 0.241 seconds (Warm-up)
Chain 2: 12.952 seconds (Sampling)
Chain 2: 13.193 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 1.8e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 0.26 seconds (Warm-up)
Chain 3: 13.004 seconds (Sampling)
Chain 3: 13.264 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.6e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 0.233 seconds (Warm-up)
Chain 4: 12.956 seconds (Sampling)
Chain 4: 13.189 seconds (Total)
Chain 4:
summary(int)
Model Info:
function: stan_glm
family: gaussian [identity]
formula: gameDuration ~ t1_dragonKills:t2_dragonKills
algorithm: sampling
sample: 20000 (posterior sample size)
priors: see help('prior_summary')
observations: 45214
predictors: 2
Estimates:
mean sd 10% 50% 90%
(Intercept) 1728.5 2.0 1725.9 1728.5 1731.1
t1_dragonKills:t2_dragonKills 147.5 0.9 146.3 147.5 148.6
sigma 340.5 1.1 339.0 340.5 341.9
Fit Diagnostics:
mean sd 10% 50% 90%
mean_PPD 1929.8 2.3 1926.9 1929.8 1932.7
The mean_ppd is the sample average posterior predictive distribution of the outcome variable (for details see help('summary.stanreg')).
MCMC diagnostics
mcse Rhat n_eff
(Intercept) 0.0 1.0 18279
t1_dragonKills:t2_dragonKills 0.0 1.0 21144
sigma 0.0 1.0 18662
mean_PPD 0.0 1.0 18790
log-posterior 0.0 1.0 9402
For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
summary(int2)
Model Info:
function: stan_glm
family: gaussian [identity]
formula: gameDuration ~ t1_baronKills:t2_baronKills
algorithm: sampling
sample: 20000 (posterior sample size)
priors: see help('prior_summary')
observations: 45214
predictors: 2
Estimates:
mean sd 10% 50% 90%
(Intercept) 1884.0 1.9 1881.6 1884.0 1886.4
t1_baronKills:t2_baronKills 466.7 4.8 460.4 466.6 472.8
sigma 390.0 1.3 388.4 390.0 391.7
Fit Diagnostics:
mean sd 10% 50% 90%
mean_PPD 1929.8 2.6 1926.5 1929.8 1933.1
The mean_ppd is the sample average posterior predictive distribution of the outcome variable (for details see help('summary.stanreg')).
MCMC diagnostics
mcse Rhat n_eff
(Intercept) 0.0 1.0 17022
t1_baronKills:t2_baronKills 0.0 1.0 20014
sigma 0.0 1.0 18691
mean_PPD 0.0 1.0 18228
log-posterior 0.0 1.0 9914
For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and Rhat is the potential scale reduction factor on split chains (at convergence Rhat=1).
Summary stats look promising with both values not containing 0 for
their 95% CI showing they are significant and can be useful
# Extract the posterior samples
posterior_samples <- as.matrix(int)
posterior_samples2 <- as.matrix(int2)
# Plot the posterior distribution of the interaction term
mcmc_hist(posterior_samples, pars = c("t1_dragonKills:t2_dragonKills"))

mcmc_hist(posterior_samples2, pars = c("t1_baronKills:t2_baronKills"))

The predictors don’t look skewed either, looks good.
We can canclude that there may be a potential interaction between
dragon kills and baron kills for each team
We can utilize this info later on upon building a better model
Main Model
Let’s assess how much getting a jump start in the game does for
determining the length of the game
main <- stan_glm(gameDuration ~ winner + firstBlood + firstTower + firstDragon + firstBaron,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1.8e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 1.141 seconds (Warm-up)
Chain 1: 14.816 seconds (Sampling)
Chain 1: 15.957 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 2e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.2 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 1.289 seconds (Warm-up)
Chain 2: 14.216 seconds (Sampling)
Chain 2: 15.505 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 1.8e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 1.089 seconds (Warm-up)
Chain 3: 14.186 seconds (Sampling)
Chain 3: 15.275 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.8e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 1.117 seconds (Warm-up)
Chain 4: 14.54 seconds (Sampling)
Chain 4: 15.657 seconds (Total)
Chain 4:
prior_summary(main)
Priors for model 'main'
------
Intercept (after predictors centered)
Specified prior:
~ normal(location = 1800, scale = 150)
Adjusted prior:
~ normal(location = 1800, scale = 64093)
Coefficients
Specified prior:
~ normal(location = [0,0,0,...], scale = [2.5,2.5,2.5,...])
Adjusted prior:
~ normal(location = [0,0,0,...], scale = [2136.54,2137.02,2137.26,...])
Auxiliary (sigma)
Specified prior:
~ exponential(rate = 1)
Adjusted prior:
~ exponential(rate = 0.0023)
------
See help('prior_summary.stanreg') for more details
mcmc_trace(main, size = .1)

Chains look normal
rhat(main)
(Intercept) winner2 firstBlood2 firstTower2 firstDragon1
1.0001252 1.0000866 0.9999479 0.9999554 1.0000860
firstDragon2 firstBaron1 firstBaron2 sigma
1.0001157 1.0000559 0.9999221 1.0000304
neff_ratio(main)
(Intercept) winner2 firstBlood2 firstTower2 firstDragon1
0.56465 1.06070 1.40485 1.23750 0.54275
firstDragon2 firstBaron1 firstBaron2 sigma
0.54175 1.05630 1.05235 1.12255
Rhat looks good, some of the neff ratio values are still high but
acceptable for now
tidy(main, effects = c("fixed", "aux"),
conf.int = TRUE, conf.level = 0.95)
From the tidy output, it looks like winner, firstBlood, and
firstTower lose their significance when adding other predictors since
their 95% CI range includes 0. We’ll use this info later for refining
our model
newdata <- data.frame(winner = factor(1, levels = levels(lol_data$winner)),
firstBlood = factor(2, levels = levels(lol_data$firstBlood)),
firstTower = factor(2, levels = levels(lol_data$firstTower)),
firstDragon = factor(2, levels = levels(lol_data$firstDragon)),
firstBaron = factor(2, levels = levels(lol_data$firstBaron)))
main_predict <- posterior_predict(
main,
newdata = newdata)
mcmc_areas(main_predict) + xlab("Game Duration") +
ggtitle('Predictive distribution of a League of Legends game where first blood, tower, dragon, baron was team 2 and team 1 won') +
theme(plot.title = element_text(size = 7))

Here’s an example output of where a game duration may lie if team 1
wins despite being behind from the start. The game is a little later
than normal, but to be expected as the team would need time to make the
comeback in the first place. However, I believe this is undershooting
the true time we could expect from this scenario. We’ll verify if this
is true after refining our model
More Predictors
We can add some numerical variables to see how much adding the amount
of each objective a team has taken to see how it affects the game
duration
ext_main <- stan_glm(gameDuration ~ winner + firstBlood + firstTower + firstDragon + firstBaron + t1_towerKills + t1_inhibitorKills + t1_baronKills + t1_dragonKills + t2_towerKills + t2_inhibitorKills + t2_baronKills + t2_dragonKills,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1.9e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.19 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 1.543 seconds (Warm-up)
Chain 1: 14.226 seconds (Sampling)
Chain 1: 15.769 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.9e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.19 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 1.671 seconds (Warm-up)
Chain 2: 14.491 seconds (Sampling)
Chain 2: 16.162 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 2.1e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.21 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 1.822 seconds (Warm-up)
Chain 3: 14.543 seconds (Sampling)
Chain 3: 16.365 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.6e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 1.593 seconds (Warm-up)
Chain 4: 14.438 seconds (Sampling)
Chain 4: 16.031 seconds (Total)
Chain 4:
prior_summary(ext_main)
Priors for model 'ext_main'
------
Intercept (after predictors centered)
Specified prior:
~ normal(location = 1800, scale = 150)
Adjusted prior:
~ normal(location = 1800, scale = 64093)
Coefficients
Specified prior:
~ normal(location = [0,0,0,...], scale = [2.5,2.5,2.5,...])
Adjusted prior:
~ normal(location = [0,0,0,...], scale = [2136.54,2137.02,2137.26,...])
Auxiliary (sigma)
Specified prior:
~ exponential(rate = 1)
Adjusted prior:
~ exponential(rate = 0.0023)
------
See help('prior_summary.stanreg') for more details
mcmc_trace(ext_main, size = .1)

Traces look good
rhat(ext_main)
(Intercept) winner2 firstBlood2 firstTower2
0.9999612 0.9999395 0.9999895 0.9998515
firstDragon1 firstDragon2 firstBaron1 firstBaron2
1.0000056 1.0000145 1.0001244 1.0001247
t1_towerKills t1_inhibitorKills t1_baronKills t1_dragonKills
0.9999698 1.0000633 1.0001761 0.9998990
t2_towerKills t2_inhibitorKills t2_baronKills t2_dragonKills
0.9998515 0.9999585 1.0003134 0.9999253
sigma
0.9998820
neff_ratio(ext_main)
(Intercept) winner2 firstBlood2 firstTower2
0.58290 0.79920 2.05680 1.44595
firstDragon1 firstDragon2 firstBaron1 firstBaron2
0.48310 0.48375 0.66920 0.65460
t1_towerKills t1_inhibitorKills t1_baronKills t1_dragonKills
0.71785 1.02960 0.65910 0.94240
t2_towerKills t2_inhibitorKills t2_baronKills t2_dragonKills
0.74235 1.01930 0.65770 0.91395
sigma
1.16840
Rhat looks good, some neff ratios (i.e. firstBlood, firstTower) are
now too high to keep and will need to be handled later
tidy(ext_main, effects = c("fixed", "aux"),
conf.int = TRUE, conf.level = 0.95)
Here, the predictors winner, firstBlood, and firstTower are not
significant due to their 95% CI including 0
# dataframe with the specified values
newdata_ext <- data.frame(
winner = factor(1, levels = levels(lol_data$winner)),
firstBlood = factor(2, levels = levels(lol_data$firstBlood)),
firstTower = factor(2, levels = levels(lol_data$firstTower)),
firstDragon = factor(2, levels = levels(lol_data$firstDragon)),
firstBaron = factor(2, levels = levels(lol_data$firstBaron)),
t1_towerKills = 7,
t1_inhibitorKills = 2,
t1_baronKills = 2,
t1_dragonKills = 2,
t2_towerKills = 3,
t2_inhibitorKills = 2,
t2_baronKills = 1,
t2_dragonKills = 3
)
ext_main_predict <- posterior_predict(ext_main, newdata = newdata_ext)
mcmc_areas(ext_main_predict) +
xlab("Game Duration") +
ggtitle('Predictive distribution of a League of Legends game where first blood, tower, dragon, baron was team 2 and team 1 won, with additional predictors') +
theme(plot.title = element_text(size = 8))

After adding a few more variables into play we can see the game gets
longer (and expectedly so). Team 1 comes from behind but ends up getting
2 barons and 7 towers making us believe this game will have to go on for
a while for the comeback to truly be complete
Refined Model
Let’s now remove the high neff ratio terms from the extended model
(i.e. > 1) and include the interaction terms we deemed useful
beforehand
ext_main_int <- stan_glm(gameDuration ~ firstDragon + firstBaron + t1_baronKills + t1_dragonKills + t2_baronKills + t2_dragonKills + t1_baronKills:t2_baronKills + t1_dragonKills:t2_dragonKills,
data = lol_data, family = gaussian,
prior_intercept = normal(1800, 150, autoscale = TRUE),
prior = normal(0, 2.5, autoscale = TRUE),
prior_aux = exponential(1, autoscale = TRUE),
chains = 4, iter = 5000*2, seed = 84735)
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 1.7e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.17 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 1: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 1: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 1: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 1: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 1: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 1: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 1: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 1: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 1: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 1: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 1: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 1.363 seconds (Warm-up)
Chain 1: 14.396 seconds (Sampling)
Chain 1: 15.759 seconds (Total)
Chain 1:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 1.6e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.16 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 2: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 2: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 2: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 2: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 2: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 2: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 2: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 2: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 2: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 2: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 2: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 1.365 seconds (Warm-up)
Chain 2: 14.24 seconds (Sampling)
Chain 2: 15.605 seconds (Total)
Chain 2:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 3).
Chain 3:
Chain 3: Gradient evaluation took 1.4e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.14 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 3: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 3: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 3: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 3: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 3: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 3: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 3: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 3: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 3: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 3: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 3: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 3: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 3:
Chain 3: Elapsed Time: 1.761 seconds (Warm-up)
Chain 3: 14.227 seconds (Sampling)
Chain 3: 15.988 seconds (Total)
Chain 3:
SAMPLING FOR MODEL 'continuous' NOW (CHAIN 4).
Chain 4:
Chain 4: Gradient evaluation took 1.8e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.18 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 4: Iteration: 1 / 10000 [ 0%] (Warmup)
Chain 4: Iteration: 1000 / 10000 [ 10%] (Warmup)
Chain 4: Iteration: 2000 / 10000 [ 20%] (Warmup)
Chain 4: Iteration: 3000 / 10000 [ 30%] (Warmup)
Chain 4: Iteration: 4000 / 10000 [ 40%] (Warmup)
Chain 4: Iteration: 5000 / 10000 [ 50%] (Warmup)
Chain 4: Iteration: 5001 / 10000 [ 50%] (Sampling)
Chain 4: Iteration: 6000 / 10000 [ 60%] (Sampling)
Chain 4: Iteration: 7000 / 10000 [ 70%] (Sampling)
Chain 4: Iteration: 8000 / 10000 [ 80%] (Sampling)
Chain 4: Iteration: 9000 / 10000 [ 90%] (Sampling)
Chain 4: Iteration: 10000 / 10000 [100%] (Sampling)
Chain 4:
Chain 4: Elapsed Time: 1.409 seconds (Warm-up)
Chain 4: 14.229 seconds (Sampling)
Chain 4: 15.638 seconds (Total)
Chain 4:
prior_summary(ext_main_int)
Priors for model 'ext_main_int'
------
Intercept (after predictors centered)
Specified prior:
~ normal(location = 1800, scale = 150)
Adjusted prior:
~ normal(location = 1800, scale = 64093)
Coefficients
Specified prior:
~ normal(location = [0,0,0,...], scale = [2.5,2.5,2.5,...])
Adjusted prior:
~ normal(location = [0,0,0,...], scale = [2136.66,2136.42,2289.92,...])
Auxiliary (sigma)
Specified prior:
~ exponential(rate = 1)
Adjusted prior:
~ exponential(rate = 0.0023)
------
See help('prior_summary.stanreg') for more details
mcmc_trace(ext_main_int, size = .1)

So far so good
rhat(ext_main_int)
(Intercept) firstDragon1
1.0003440 1.0003428
firstDragon2 firstBaron1
1.0003775 1.0000760
firstBaron2 t1_baronKills
1.0002465 1.0000761
t1_dragonKills t2_baronKills
0.9998796 1.0002153
t2_dragonKills t1_baronKills:t2_baronKills
0.9999051 1.0002525
t1_dragonKills:t2_dragonKills sigma
1.0000077 1.0000297
Rhat looks satisfactory for all predictors
neff_ratio(ext_main_int)
(Intercept) firstDragon1
0.58795 0.50540
firstDragon2 firstBaron1
0.50105 0.56190
firstBaron2 t1_baronKills
0.53910 0.53865
t1_dragonKills t2_baronKills
0.67185 0.53005
t2_dragonKills t1_baronKills:t2_baronKills
0.67705 0.66965
t1_dragonKills:t2_dragonKills sigma
0.82210 1.12835
Neff ratios are much more reasonable now and a big improvement from
prior models with no value being > .90
tidy(ext_main_int, effects = c("fixed", "aux"),
conf.int = TRUE, conf.level = 0.95)
Every value looks significant from the 95% CI (even the interaction
terms!!) due to none of them including 0.
# dataframe with the specified values
newdata_ext_int <- data.frame(
firstDragon = factor(2, levels = levels(lol_data$firstDragon)),
firstBaron = factor(2, levels = levels(lol_data$firstBaron)),
t1_baronKills = 2,
t1_dragonKills = 2,
t2_baronKills = 1,
t2_dragonKills = 3
)
ext_main_int_predict <- posterior_predict(ext_main_int, newdata = newdata_ext_int)
mcmc_areas(ext_main_int_predict) +
xlab("Game Duration") +
ggtitle('Predictive distribution of a League of Legends game where first dragon, baron was team 2 and team 1 had more baron kills with interaction') +
theme(plot.title = element_text(size = 8))

The games seem to drag on even longer with this new model. This is
expected since the dragon and baron respawn times are quite long so, as
said before, the comeback would realistically take longer than
average.
Lets do some model comparisons to verify which model is best
Model Comparisons
PP Check
pp_check(main, nreps = 50) + xlab("Game Duration") +
ggtitle('Main effects model')

The main model gets a decent amount of area, yet it starts moving too
far right and undershoots at the peak
pp_check(ext_main, nreps = 50) + xlab("Game Duration") +
ggtitle('Extended Main effects model')

The extended model is objectively better than the main model, but
still undershoots area at the peak
pp_check(ext_main_int, nreps = 50) + xlab("Game Duration") +
ggtitle('Refined Interaction effects model')

The interaction model is very similar to the extended model which is
better than the main model.
The ppchecks show most of the are being covered for the last 2 models
with the interaction model doing better around the peak by a small
margin
10 Fold Cross-Validations
test_sample <- lol_data %>% head(10000)
nrow(test_sample)
[1] 10000
set.seed(84735)
p_main <- prediction_summary(model = main, data = test_sample)
p_ext_main <- prediction_summary(model = ext_main, data = test_sample)
p_ext_main_int <- prediction_summary(model = ext_main_int, data = test_sample)
rbind(p_main, p_ext_main, p_ext_main_int)
These are the raw MAE values based on a sample of 10000 observations
from the data, we can use these to determine the behavior and bias of
each model based on their cross-validation results
set.seed(84735)
cv_main <- prediction_summary_cv(
model = main, data = lol_data, k = 10)
rbind(cv_main$cv, cv_extend$cv, cv_interact$cv)
Loo Diagnostics
set.seed(34521)
main_elpd <- loo(main)
ext_main_elpd <- loo(ext_main)
ext_main_interact_elpd <- loo(ext_main_int)
main_elpd$estimates
Estimate SE
elpd_loo -3.323804e+05 174.6839030
p_loo 9.093789e+00 0.1196568
looic 6.647608e+05 349.3678059
ext_main_elpd$estimates
Estimate SE
elpd_loo -309859.5959 173.9985196
p_loo 19.2336 0.2843918
looic 619719.1918 347.9970392
ext_main_interact_elpd$estimates
Estimate SE
elpd_loo -314197.32595 179.0596124
p_loo 13.56236 0.2282117
looic 628394.65191 358.1192249
c(main_elpd$estimates[1], ext_main_elpd$estimates[1], ext_main_interact_elpd$estimates[1])
[1] -332380.4 -309859.6 -314197.3
loo_compare(main_elpd, ext_main_elpd, ext_main_interact_elpd)
elpd_diff se_diff
ext_main 0.0 0.0
ext_main_int -4337.7 96.8
main -22520.8 178.3
The extended model fairs better than the interaction model when
comparing their ELPD and MAE. The interaction model does 4337.6 points
“worse” for ELPD and is around 16 points higher in its MAE. However,
something to consider here is the idea of overfitting
and how more predictors and affect the model overall and skew our
metrics.
Despite the interaction model covering more area, the MAE and ELPD are
both worse. This may be due to these values being inflated by the larger
number of predictors in the extended model. Furthermore, the extended
model contains numerous values with higher than normal Neff Ratios which
is a cause
for concern about the validity of the model along with predictors
that were not significant.
Despite having less predictors, the interaction model garners more
area in its predictive posterior distribution while having a similar MAE
and good ELPD score too (-309859.7 vs 314197.3) which is a minor (~1%)
difference given the size of these values. However, these interaction
terms could also be having an adverse effect on the model leading to
these greater errors.
Overfitting
rbind(p_main, p_ext_main, p_ext_main_int)
rbind(cv_main$cv, cv_extend$cv, cv_interact$cv)
Based on the difference between the raw MAE values and the
cross-validation MAE values, overfitting does not seem to pose a threat
to these models, however we can only truly know this if we are given new
data entirely to test the models. Furthermore, the extended model does
have a larger (though mostly negligible due to how small it is)
difference from the cross-validation MAE compared to the other
models.
What is undoubtedly clear is that adding numerical predictors to the
model does help the predictions overall and is shown with both the
extended and interaction model fairing better than the main model in
every aspect.
Regression Inference
Let’s see how the 2 best models fair when conducting a quick
hypothesis test to see the Posterior probability of a game around 40
minutes long
We’ll use the predictive posterior models we created and visualized
earlier to conduct the tests
\[
H_0: \pi \geq 2500
\]
\[
H_a: \pi < 2500
\]
# Extract the posterior samples
posterior_samples <- ext_main_int_predict
p_H0 <- mean(posterior_samples >= 2500)
p_Ha <- mean(posterior_samples < 2500)
# Print the results
cat("Posterior probability of H0 (π ≥ 2500):", p_H0)
Posterior probability of H0 (π ≥ 2500): 0.9364
cat("Posterior probability of Ha (π < 2500):", p_Ha)
Posterior probability of Ha (π < 2500): 0.0636
# Extract the posterior samples
posterior_samples <- ext_main_predict
p_H0 <- mean(posterior_samples >= 2500)
p_Ha <- mean(posterior_samples < 2500)
# Print the results
cat("Posterior probability of H0 (π ≥ 2500):", p_H0)
Posterior probability of H0 (π ≥ 2500): 0.42085
cat("Posterior probability of Ha (π < 2500):", p_Ha)
Posterior probability of Ha (π < 2500): 0.57915
Though the two models seemingly predict the actual distribution of
the data well, the 2 models have very different outcomes when conducting
the test.
The extended model favors the alternate hypothesis while the
interaction model clearly favors the null hypothesis. This both
coincides with what we saw before from the visualizations and tells us
that the extended model favors games that are shorter while the
interaction model expects games like this to take longer.
This is also something one should consider when choosing the model.
Whether or not the predictions themselves seem realistic given the
scenario/circumstances.
To back up what I’m saying, Baron Nashor spawns at 20 minutes and
respawns every 6 minutes. Since 3 Barons are killed in both scenarios,
the game would have to be at least 38 minutes and only if the teams kill
the Baron IMMEDIATELY (which is usually never the case). Therefore, one
would expect majority of the area to lie within the ~40 minute range at
the very least for when the game would end.
Conclusion
In conclusion, it is a choice between whether one wants to take the
chance of playing with a model that may be susceptible to overfitting
for the sake of potentially less error or a slightly higher error model
that has interactions but would be less likely to be susceptible to
overfitting.
Personally, I say that the refined interaction model is the best
model to use for predicting the game duration of a LOL match given our
data due to its comparable MAE along with better posterior predictive
abilities and lack of evidence for overfitting. Furthermore, based on my
experience and game rules, the predictive values it comes up with end up
being much more realistic in the grand scheme of things and with other
factors such as respawn time considered.
Honor Pledge
On my honor, I have neither received nor given any unauthorized
assistance on this project
Signed: Thomas Christo (tjc260)
LS0tDQp0aXRsZTogIkZpbmFsIFByb2plY3QgTE9MIg0KZGF0ZTogIkR1ZTogV2VkbmVzZGF5IDEyLzE5IGF0IDExOjU5YW0sIENhbnZhcyBzdWJtaXNzaW9uIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMgVGhlIERhdGENCg0KVGhlIGRhdGFzZXQgSSBoYXZlIGNob3NlbiB0byBjb25kdWN0IG15IHJlZ3Jlc3Npb24gYW5hbHlzaXMgaXMgdGhlIFsoTG9MKSBMZWFndWUgb2YgTGVnZW5kcyBSYW5rZWQgR2FtZXMgZGF0YXNldF0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9kYXRhc25hZWsvbGVhZ3VlLW9mLWxlZ2VuZHMvP3NlbGVjdD1nYW1lcy5jc3YpLiBUaGlzIGRhdGEgbG9va3MgYXQgcmFua2VkIExlYWd1ZSBvZiBMZWdlbmRzIGdhbWVzIHBsYXllZCBkdXJpbmcgc2Vhc29uIDkgaW4gdGhlIEVVVyByZWdpb24uIFRoaXMgZGF0YXNldCB3YXMgY29sbGVjdGVkIHVzaW5nIHRoZSBSaW90IEdhbWVzIEFQSSwgd2hpY2ggbWFrZXMgaXQgZWFzeSB0byBsb29rIHVwIGFuZCBjb2xsZWN0IGluZm9ybWF0aW9uIG9uIGEgdXNlcnMgcmFua2VkIGhpc3RvcnkgYW5kIGNvbGxlY3QgdGhlaXIgZ2FtZXMuDQoNCmBgYHtyIHNldHVwLCByZXN1bHRzPUYsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBMb2FkIHBhY2thZ2VzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJzdGFuYXJtKQ0KbGlicmFyeShiYXllc3Bsb3QpDQpsaWJyYXJ5KGJheWVzcnVsZXMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodGlkeWJheWVzKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoYnJvb20ubWl4ZWQpDQpsaWJyYXJ5KGludGVyYWN0aW9ucykNCmBgYA0KDQpUbyBwcmVmYWNlIHRoaXMgYW5hbHlzaXMsIG9uZSBtdXN0IGZpcnN0IHVuZGVyc3RhbmQgdGhlIGdhbWUgb2YgTGVhZ3VlIG9mIExlZ2VuZHMsIG9yIExPTCBmb3Igc2hvcnQuIEluIExPTCwgdHdvIDUgcGVyc29uIHRlYW1zIGZpZ2h0IHRvIGRlc3Ryb3kgZWFjaCBvdGhlcnMgbmV4dXMgYW5kIGdldCB0byBjaG9vc2UgYW5kIGJhbiBhIGNoYW1waW9uLCBlYWNoIHdpdGggYSBkaWZmZXJlbnQgc2V0IG9mIHNraWxscyBhbmQgYWJpbGl0aWVzLCBhbmQgMiBzdW1tb25lciBzcGVsbHMgdG8gZG8gc28uIEFsb25nIHRoZSB3YXksIHRoZSBwbGF5ZXJzIG11c3QgYm90aCBmaWdodCBlYWNoIG90aGVyLCBkZXN0cm95IG9iamVjdGl2ZXMgc3VjaCBhcyB0b3dlcnMgYW5kIGluaGliaXRvcnMsIGFuZCBzdHJhdGVnaXplIGVmZmVjdGl2ZWx5IHRvIHJlYWNoIHRoZSBvcHBvbmVudCdzIG5leHVzLiBUaGVyZSBhcmUgYWxzbyBzZXZlcmFsIG1vbnN0ZXJzIHRoYXQgdGVhbXMgY2FuIGRlZmVhdCB0byBidWZmIHRoZW0gYXMgd2VsbCwgc3VjaCBhcyBSaWZ0IEhlcmFsZCwgQmFyb24gTmFzaG9yLCBhbmQgYW4gYXNzb3J0ZWQgc2V0IG9mIERyYWdvbnMuDQoNCldlIHdpbGwgdXNlIGBsb2xfZGF0YWAgdG8gYnVpbGQgdmFyaW91cyBtb2RlbHMgb2YgTGVhZ3VlIG9mIExlZ2VuZHMgYGdhbWVEdXJhdGlvbmAuIFRocm91Z2hvdXQsIHdlJ2xsIHV0aWxpemUgd2Vha2x5IGluZm9ybWF0aXZlIHByaW9ycyBhbmQgYSBiYXNpYyB1bmRlcnN0YW5kaW5nIHRoYXQgTE9MIGdhbWVzIHVzdWFsbHkgYXJlIFszMCBtaW51dGVzXShodHRwczovL3d3dy5sZWFndWVvZmdyYXBocy5jb20vc3RhdHMvZ2FtZS1kdXJhdGlvbnMpIGJ1dCBjYW4gcmFuZ2UgZnJvbSAyNS0zNSBtaW51dGVzLiBXZSB3aWxsIGFzc2VzIGFuIGFycmF5IG9mIGRpZmZlcmVudCBwcmVkaWN0b3JzIGFuZCBjb21iaW5hdGlvbnMgdG8gZGV0ZXJtaW5lIHdoYXQgY2FuIHByb3ZpZGUgdXMgdGhlIGJlc3QgZml0IGZvciBwcmVkaWN0aW5nIHRoZSBnYW1lIGR1cmF0aW9uIG9mIGEgTGVhZ3VlIG9mIExlZ2VuZHMgZ2FtZS4gQSBiYXNlIGNyaXRlcmlhIGZvciB0aGVzZSBnYW1lcyBpcyB0aGVyZSBhdCBsZWFzdCBuZWVkcyB0byBiZSBvbmUgdG93ZXIsIG9uZSBpbmhpYml0b3IsIGFuZCBvbmUgY2hhbXBpb24ga2lsbCBmb3IgZWFjaCBnYW1lLiBUaGlzIGlzIHRvIG1pdGlnYXRlIHRoZSBhbW91bnQgb2YgZ2FtZXMgdGhhdCB0ZWFtcyBtYXkgaGF2ZSBmb3JmZWl0ZWQgZHVlIHRvIGEgcGxheWVyIGxlYXZpbmcgb3IgdHJvbGxpbmcuDQoNCmBgYHtyfQ0KbG9sX2RhdGEgPC0gcmVhZC5jc3YoImdhbWVzLmNzdiIsDQogICAgICAgICAgICAgICAgICAgIHNlcD0iLCIsDQogICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3M9YygiIiwiICIsIk5BIiwiTi9BIikNCikNCmhlYWQobG9sX2RhdGEpDQpgYGANCg0KIyMgU2V0dGluZyBVcCB0aGUgRGF0YQ0KDQpUcmFuc2Zvcm1pbmcgZGF0YSB0byBmaXQgYmFzZWxpbmUgb2YgYXQgbGVhc3Qgb25lIGtpbGwsIHRvd2VyLCBhbmQgaW5oaWJpdG9yDQoNCmBgYHtyfQ0KbG9sX2RhdGEgPC0gbG9sX2RhdGFbIShsb2xfZGF0YSRmaXJzdEJsb29kID09IDAgfCBsb2xfZGF0YSRmaXJzdFRvd2VyID09IDAgfCBsb2xfZGF0YSRmaXJzdEluaGliaXRvciA9PSAwKSwgXQ0KYGBgDQoNCmBgYHtyfQ0KbnJvdyhsb2xfZGF0YSkNCmBgYA0KDQpgYGB7cn0NCmNvbG5hbWVzKGxvbF9kYXRhKQ0KYGBgDQoNCldlIGNhbiBjbGVhbiB1cCBvdXIgZGF0YSBieSBvbWl0dGluZyB1bm5lY2Vzc2FyeSBjb2x1bW5zDQoNCmBgYHtyfQ0KbG9sX2RhdGEgPC0gc3Vic2V0KGxvbF9kYXRhLCBzZWxlY3QgPSAtYyh0Ml9iYW4xLCB0Ml9iYW4yLCB0Ml9iYW4zLCB0Ml9iYW40LCB0Ml9iYW41LCB0MV9iYW4xLCB0MV9iYW4yLCB0MV9iYW4zLCB0MV9iYW40LCB0MV9iYW41LCB0MV9jaGFtcDFfc3VtMSwgdDFfY2hhbXAyX3N1bTEsIHQxX2NoYW1wM19zdW0xLCB0MV9jaGFtcDRfc3VtMSwgdDFfY2hhbXA1X3N1bTEsIHQyX2NoYW1wNV9zdW0xLCB0Ml9jaGFtcDFfc3VtMSwgdDJfY2hhbXAyX3N1bTEsIHQyX2NoYW1wM19zdW0xLCB0Ml9jaGFtcDRfc3VtMSwgdDJfY2hhbXA1X3N1bTEsIHQxX2NoYW1wMV9zdW0yLCB0MV9jaGFtcDJfc3VtMiwgdDFfY2hhbXAzX3N1bTIsIHQxX2NoYW1wNF9zdW0yLCB0MV9jaGFtcDVfc3VtMiwgdDJfY2hhbXAxX3N1bTIsIHQyX2NoYW1wMV9zdW0yLCB0Ml9jaGFtcDJfc3VtMiwgdDJfY2hhbXAzX3N1bTIsIHQyX2NoYW1wNF9zdW0yLCB0Ml9jaGFtcDVfc3VtMiwgdDFfY2hhbXAxaWQsIHQxX2NoYW1wMmlkLCB0MV9jaGFtcDNpZCwgdDFfY2hhbXA0aWQsIHQxX2NoYW1wNWlkLCB0Ml9jaGFtcDFpZCwgdDJfY2hhbXAyaWQsIHQyX2NoYW1wM2lkLCB0Ml9jaGFtcDRpZCwgdDJfY2hhbXA1aWQpKQ0KDQpjb2xuYW1lcyhsb2xfZGF0YSkNCmBgYA0KDQpXZSBjYW4gYWxzbyBjb3ZlcnQgc29tZSBvZiB0aGUgY29sdW1ucyB0byBmYWN0b3JzIGZvciB0ZWFtIDEgYW5kIHRlYW0gMiBmb3IgZWFzZSBvZiB2aXN1YWxpemF0aW9uIGFuZCBpbnRlcnByZXRhdGlvbg0KDQpgYGB7cn0NCmxvbF9kYXRhJHdpbm5lciA8LSBhcy5mYWN0b3IobG9sX2RhdGEkd2lubmVyKQ0KbG9sX2RhdGEkZmlyc3RCbG9vZCA8LSBhcy5mYWN0b3IobG9sX2RhdGEkZmlyc3RCbG9vZCkNCmxvbF9kYXRhJGZpcnN0VG93ZXIgPC0gYXMuZmFjdG9yKGxvbF9kYXRhJGZpcnN0VG93ZXIpDQpsb2xfZGF0YSRmaXJzdEluaGliaXRvciA8LSBhcy5mYWN0b3IobG9sX2RhdGEkZmlyc3RJbmhpYml0b3IpDQpsb2xfZGF0YSRmaXJzdEJhcm9uIDwtIGFzLmZhY3Rvcihsb2xfZGF0YSRmaXJzdEJhcm9uKQ0KbG9sX2RhdGEkZmlyc3REcmFnb24gPC0gYXMuZmFjdG9yKGxvbF9kYXRhJGZpcnN0RHJhZ29uKQ0KbG9sX2RhdGEkZmlyc3RSaWZ0SGVyYWxkIDwtIGFzLmZhY3Rvcihsb2xfZGF0YSRmaXJzdFJpZnRIZXJhbGQpDQpgYGANCg0KYGBge3J9DQpoZWFkKGxvbF9kYXRhKQ0KYGBgDQoNCiMjIFN1bW1hcnkgQW5hbHlzaXMNCg0KSGVyZSBhcmUgc29tZSB2aXN1YWxpemF0aW9ucyBhbmQgc3RhdGlzdGljcyB0byBoZWxwIGJldHRlciB1bmRlcnN0YW5kIG91ciBkYXRhIGFuZCB3aGF0IHdlIGFyZSB3b3JraW5nIHdpdGguDQoNCmBgYHtyfQ0Kc3VtbWFyeShsb2xfZGF0YSkNCmBgYA0KDQpTb21lIGNvbmNsdXNpb25zIHdlIGNhbiBtYWtlIGhlcmU6DQoNCi0gICBUaGUgbWVhbiBnYW1lIHRpbWUgaXMgYXJvdW5kIDE5MzAgc2Vjb25kcyAocm91Z2hseSAzMiBtaW51dGVzKQ0KDQotICAgR2FtZSBkdXJhdGlvbiBsaWVzIG1vc3RseSBiZXR3ZWVuIDE2MzIgYW5kIDIxOTYNCg0KLSAgIFRlYW0gMSBoYXMgd29uIG1vcmUgZ2FtZXMsIGhhcyBtb3JlIGZpcnN0IGJsb29kcywgdG93ZXJzLCBpbmhpYml0b3JzLCBhbmQgcmlmdCBoZXJhbGRzDQoNCi0gICBUZWFtIDIgaGFzIG1vcmUgZmlyc3QgYmFyb25zIGFuZCBkcmFnb25zLg0KDQotICAgVGVhbSAxJ3MgdG93ZXIsIGluaGliaXRvciwgYW5kIGhlcmFsZCBraWxscyBhcmUgaGlnaGVyIHRoYW4gVGVhbSAyJ3Mgd2hpY2ggaXMgcmVmbGVjdGVkIGZyb20gdGhlbSBnZXR0aW5nIHRoZSBmaXJzdCBvZiBlYWNoIG1vcmUgb2Z0ZW4gdGhhbiBub3QuDQoNCi0gICBUZWFtIDIncyBkcmFnb24gYW5kIGJhcm9uIGtpbGxzIGFyZSBoaWdoZXIgdGhhbiBUZWFtIDEncyB3aGljaCBpcyByZWZsZWN0ZWQgZnJvbSB0aGVtIGdldHRpbmcgdGhlIGZpcnN0IG9mIGVhY2ggbW9yZSBvZnRlbiB0aGFuIG5vdC4NCg0KIyMgVmlzdWFsaXphdGlvbnMNCg0KV2UgY2FuIHVzZSBnZ3Bsb3QgZG8gdmlzdWFsaXplIHNvbWUgb2Ygb3VyIGZpbmRpbmdzDQoNCiMjIyBSZXNwb25zZSBEaXN0cmlidXRpb24NCg0KYGBge3J9DQpnZ3Bsb3QobG9sX2RhdGEsIGFlcyh4ID0gZ2FtZUR1cmF0aW9uKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDYwLCBmaWxsID0gImJsdWUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgbGFicyh4ID0gIkdhbWUgRHVyYXRpb24gKHNlY29uZHMpIiwgeSA9ICJGcmVxdWVuY3kiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgR2FtZSBEdXJhdGlvbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KR2FtZSBkdXJhdGlvbiBzZWVtcyB0byBiZSBhIGJpdCByaWdodC1za2V3ZWQNCg0KIyMjIEZpcnN0IENvbXBhcmlzb25zDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IHdpbm5lciwgZmlsbCA9IHdpbm5lcikpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OSkpICsNCiAgICAgIGxhYnMoeSA9ICJXaW5uZXJzIikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChsb2xfZGF0YSwgYWVzKHggPSBmaXJzdEJsb29kLCBmaWxsID0gZmlyc3RCbG9vZCkpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OSkpICsNCiAgICAgIGxhYnMoeSA9ICJGaXJzdCBCbG9vZHMiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IGZpcnN0VG93ZXIsIGZpbGwgPSBmaXJzdFRvd2VyKSkgKyANCiAgICAgIGdlb21fYmFyKCkgKyANCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT05KSkgKw0KICAgICAgbGFicyh5ID0gIkZpcnN0IFRvd2VycyIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobG9sX2RhdGEsIGFlcyh4ID0gZmlyc3RJbmhpYml0b3IsIGZpbGwgPSBmaXJzdEluaGliaXRvcikpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OSkpICsNCiAgICAgIGxhYnMoeSA9ICJGaXJzdCBJbmhpYml0b3JzIikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChsb2xfZGF0YSwgYWVzKHggPSBmaXJzdERyYWdvbiwgZmlsbCA9IGZpcnN0RHJhZ29uKSkgKyANCiAgICAgIGdlb21fYmFyKCkgKyANCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT05KSkgKw0KICAgICAgbGFicyh5ID0gIkZpcnN0IERyYWdvbnMiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IGZpcnN0UmlmdEhlcmFsZCwgZmlsbCA9IGZpcnN0UmlmdEhlcmFsZCkpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OSkpICsNCiAgICAgIGxhYnMoeSA9ICJGaXJzdCBSaWZ0IEhlcmFsZHMiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IGZpcnN0QmFyb24sIGZpbGwgPSBmaXJzdEJhcm9uKSkgKyANCiAgICAgIGdlb21fYmFyKCkgKyANCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT05KSkgKw0KICAgICAgbGFicyh5ID0gIkZpcnN0IEJhcm9ucyIpDQpgYGANCg0KVGhlc2UgYWxsIGFyZSBjb25zaXN0ZW50IHdpdGggb3VyIHByZXZpb3VzIHN1bW1hcnkgZmluZGluZ3MgYWJvdXQgZmlyc3QgY2F0ZWdvcmllcw0KDQojIyMgVG90YWwgT2JqZWN0aXZlcyBDb21wYXJpc29ucw0KDQpgYGB7cn0NCmdncGxvdChsb2xfZGF0YSwgYWVzKHggPSB0MV90b3dlcktpbGxzKSkgKyANCiAgICAgIGdlb21fYmFyKCkgKyANCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsNCiAgICAgIGxhYnMoeSA9ICJDb3VudCIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobG9sX2RhdGEsIGFlcyh4ID0gdDJfdG93ZXJLaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KdG93ZXJfa2lsbHMgPC0gZGF0YS5mcmFtZShUZWFtID0gYygiVDEiLCAiVDIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgS2lsbHMgPSBjKHN1bShsb2xfZGF0YSR0MV90b3dlcktpbGxzLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bShsb2xfZGF0YSR0Ml90b3dlcktpbGxzLCBuYS5ybSA9IFRSVUUpKSkNCg0KZ2dwbG90KHRvd2VyX2tpbGxzLCBhZXMoeCA9IFRlYW0sIHkgPSBLaWxscywgZmlsbCA9IFRlYW0pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeCA9ICJUZWFtIiwgeSA9ICJUb3RhbCBUb3dlciBLaWxscyIsIHRpdGxlID0gIkNvbXBhcmlzb24gb2YgVG93ZXIgS2lsbHMgYmV0d2VlbiBUMSBhbmQgVDIiKQ0KYGBgDQoNCk1vcmUgb2Z0ZW4gdGhhbiBub3QsIGJvdGggdGVhbXMgdGVuZCB0byBraWxsIFw+NiB0b3dlcnMgcGVyIGdhbWUNCg0KYGBge3J9DQpnZ3Bsb3QobG9sX2RhdGEsIGFlcyh4ID0gdDFfaW5oaWJpdG9yS2lsbHMpKSArIA0KICAgICAgZ2VvbV9iYXIoKSArIA0KICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKw0KICAgICAgbGFicyh5ID0gIkNvdW50IikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChsb2xfZGF0YSwgYWVzKHggPSB0Ml9pbmhpYml0b3JLaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiBpbmhpYml0b3Iga2lsbHMgZm9yIGVhY2ggdGVhbQ0KaW5oaWJpdG9yX2tpbGxzIDwtIGRhdGEuZnJhbWUoVGVhbSA9IGMoIlQxIiwgIlQyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLaWxscyA9IGMoc3VtKGxvbF9kYXRhJHQxX2luaGliaXRvcktpbGxzLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0obG9sX2RhdGEkdDJfaW5oaWJpdG9yS2lsbHMsIG5hLnJtID0gVFJVRSkpKQ0KDQpnZ3Bsb3QoaW5oaWJpdG9yX2tpbGxzLCBhZXMoeCA9IFRlYW0sIHkgPSBLaWxscywgZmlsbCA9IFRlYW0pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeCA9ICJUZWFtIiwgeSA9ICJUb3RhbCBJbmhpYml0b3IgS2lsbHMiLCB0aXRsZSA9ICJDb21wYXJpc29uIG9mIEluaGliaXRvciBLaWxscyBiZXR3ZWVuIFQxIGFuZCBUMiIpDQpgYGANCg0KR2FtZXMgdXN1YWxseSBlbmQgd2l0aCAwIHRvIDIgaW5oaWJpdG9ycyBiZWluZyBkZXN0cm95ZWQsIGxpa2VseSBkdWUgdG8gbGF0ZSBnYW1lIGZvcmZlaXRzIG9yIHN0ZWFtIHJvbGxzICh3aGljaCBpcyBvZnRlbiB0aGUgY2FzZSBpbiBtYW55IGdhbWVzKQ0KDQpgYGB7cn0NCmdncGxvdChsb2xfZGF0YSwgYWVzKHggPSB0MV9kcmFnb25LaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IHQyX2RyYWdvbktpbGxzKSkgKyANCiAgICAgIGdlb21fYmFyKCkgKyANCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsNCiAgICAgIGxhYnMoeSA9ICJDb3VudCIpDQpgYGANCg0KYGBge3J9DQojIENhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIGRyYWdvbiBraWxscyBmb3IgZWFjaCB0ZWFtDQpkcmFnb25fa2lsbHMgPC0gZGF0YS5mcmFtZShUZWFtID0gYygiVDEiLCAiVDIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEtpbGxzID0gYyhzdW0obG9sX2RhdGEkdDFfZHJhZ29uS2lsbHMsIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bShsb2xfZGF0YSR0Ml9kcmFnb25LaWxscywgbmEucm0gPSBUUlVFKSkpDQoNCmdncGxvdChkcmFnb25fa2lsbHMsIGFlcyh4ID0gVGVhbSwgeSA9IEtpbGxzLCBmaWxsID0gVGVhbSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh4ID0gIlRlYW0iLCB5ID0gIlRvdGFsIERyYWdvbiBLaWxscyIsIHRpdGxlID0gIkNvbXBhcmlzb24gb2YgRHJhZ29uIEtpbGxzIGJldHdlZW4gVDEgYW5kIFQyIikNCmBgYA0KDQpEcmFnb24ga2lsbHMgY29tZm9ydGFibHkgbGllIHdpdGhpbiB0aGUgMC0yIHJhbmdlDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IHQxX3JpZnRIZXJhbGRLaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IHQyX3JpZnRIZXJhbGRLaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiByaWZ0IGhlcmFsZCBraWxscyBmb3IgZWFjaCB0ZWFtDQpyaWZ0SGVyYWxkX2tpbGxzIDwtIGRhdGEuZnJhbWUoVGVhbSA9IGMoIlQxIiwgIlQyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgS2lsbHMgPSBjKHN1bShsb2xfZGF0YSR0MV9yaWZ0SGVyYWxkS2lsbHMsIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW0obG9sX2RhdGEkdDJfcmlmdEhlcmFsZEtpbGxzLCBuYS5ybSA9IFRSVUUpKSkNCg0KZ2dwbG90KHJpZnRIZXJhbGRfa2lsbHMsIGFlcyh4ID0gVGVhbSwgeSA9IEtpbGxzLCBmaWxsID0gVGVhbSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh4ID0gIlRlYW0iLCB5ID0gIlRvdGFsIFJpZnQgSGVyYWxkIEtpbGxzIiwgdGl0bGUgPSAiQ29tcGFyaXNvbiBvZiBSaWZ0IEhlcmFsZCBLaWxscyBiZXR3ZWVuIFQxIGFuZCBUMiIpDQpgYGANCg0KUmlmdCBoZXJhbGQgb25seSBzcGF3bnMgZnJvbSA5OjUwIC0gMTk6NDUgZHVyaW5nIHRoZSBnYW1lIGFuZCBpcyBtb3N0IG9mdGVuIG9ubHkgdGFrZW4gb25jZSBpZiBhdCBhbGwNCg0KYGBge3J9DQpnZ3Bsb3QobG9sX2RhdGEsIGFlcyh4ID0gdDFfYmFyb25LaWxscykpICsgDQogICAgICBnZW9tX2JhcigpICsgDQogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArDQogICAgICBsYWJzKHkgPSAiQ291bnQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGxvbF9kYXRhLCBhZXMoeCA9IHQyX2Jhcm9uS2lsbHMpKSArIA0KICAgICAgZ2VvbV9iYXIoKSArIA0KICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKw0KICAgICAgbGFicyh5ID0gIkNvdW50IikNCmBgYA0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRoZSB0b3RhbCBudW1iZXIgb2YgYmFyb24ga2lsbHMgZm9yIGVhY2ggdGVhbQ0KYmFyb25fa2lsbHMgPC0gZGF0YS5mcmFtZShUZWFtID0gYygiVDEiLCAiVDIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgS2lsbHMgPSBjKHN1bShsb2xfZGF0YSR0MV9iYXJvbktpbGxzLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bShsb2xfZGF0YSR0Ml9iYXJvbktpbGxzLCBuYS5ybSA9IFRSVUUpKSkNCg0KZ2dwbG90KGJhcm9uX2tpbGxzLCBhZXMoeCA9IFRlYW0sIHkgPSBLaWxscywgZmlsbCA9IFRlYW0pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeCA9ICJUZWFtIiwgeSA9ICJUb3RhbCBCYXJvbiBLaWxscyIsIHRpdGxlID0gIkNvbXBhcmlzb24gb2YgQmFyb24gS2lsbHMgYmV0d2VlbiBUMSBhbmQgVDIiKQ0KYGBgDQoNCkJhcm9uIHNwYXducyBhZnRlciB0aGUgcmlmdCBoZXJhbGQgYW5kIHVzdWFsbHkgaXMgZ2FtZSBvdmVyIGlmIHRha2VuIGFuZCB1c2VkIHByb3Blcmx5LCBoZW5jZSB3aHkgdGhlIGFtb3VudCB0YWtlbiBpcyB1c3VhbGx5IDAgb3IgMSBhcyBzb21ldGltZXMgZ2FtZXMgZW5kIGJlZm9yZSBpdCBjYW4gYmUgdGFrZW4NCg0KIyMgQmFzZSBNb2RlbCBhbmQgUHJpb3IgTW9kZWxpbmcNCg0KTGV0cyBzdGFydCBvZmYgd2l0aCBhIGJhc2UgbW9kZWwgdG8gc2VlIGlmIHdlIGNhbiBnZXQgaW5zaWdodCBmcm9tIGp1c3QgdGhlIHdpbm5lciBvZiB0aGUgbWF0Y2gNCg0KYGBge3J9DQpiYXNlIDwtIHN0YW5fZ2xtKGdhbWVEdXJhdGlvbiB+IHdpbm5lciwNCiAgZGF0YSA9IGxvbF9kYXRhLCBmYW1pbHkgPSBnYXVzc2lhbiwgDQogIHByaW9yX2ludGVyY2VwdCA9IG5vcm1hbCgxODAwLCAxNTAsIGF1dG9zY2FsZSA9IFRSVUUpLA0KICBwcmlvciA9IG5vcm1hbCgwLCAyLjUsIGF1dG9zY2FsZSA9IFRSVUUpLCANCiAgcHJpb3JfYXV4ID0gZXhwb25lbnRpYWwoMSwgYXV0b3NjYWxlID0gVFJVRSksDQogIGNoYWlucyA9IDQsIGl0ZXIgPSA1MDAwKjIsIHNlZWQgPSA4NDczNSkNCmBgYA0KDQpgYGB7cn0NCnByaW9yX3N1bW1hcnkoYmFzZSkgDQpgYGANCg0KQSBwcmlvciBwcmVkaWN0aXZlIGNoZWNrIGNhbiBiZSB1c2VkIHRvIHNlZSB3aGF0IHdlIGNhbiBwb3RlbnRpYWxseSBleHBlY3QgZnJvbSB0aGUgZGF0YSBhbG9uZSBhbmQgd2hhdCB0aGUgc3RhbiBtb2RlbCB2aWV3ZWQgYXMgYXBwcm9wcmlhdGUgZm9yIG91ciBwcmVkaWN0aW9ucw0KDQpgYGB7cn0NCmJhc2VfcHJpb3JzIDwtIHVwZGF0ZShiYXNlLCBwcmlvcl9QRCA9IFRSVUUpDQojIDIwMCBwcmlvciBtb2RlbCBsaW5lcw0KbG9sX2RhdGEgJT4lDQogIGFkZF9maXR0ZWRfZHJhd3MoYmFzZSwgbiA9IDIwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IHdpbm5lciwgeSA9IGdhbWVEdXJhdGlvbikpICsNCiAgICBnZW9tX2xpbmUoYWVzKHkgPSAudmFsdWUsIGdyb3VwID0gLmRyYXcpLCBhbHBoYSA9IDAuMDUpDQoNCiMgNCBwcmlvciBzaW11bGF0ZWQgZGF0YXNldHMNCnNldC5zZWVkKDMpDQpsb2xfZGF0YSAlPiUNCiAgYWRkX3ByZWRpY3RlZF9kcmF3cyhiYXNlLCBuID0gNCkgJT4lDQogIGdncGxvdChhZXMoeCA9IHdpbm5lciwgeSA9IGdhbWVEdXJhdGlvbikpICsNCiAgICBnZW9tX3BvaW50KGFlcyh5ID0gLnByZWRpY3Rpb24sIGdyb3VwID0gLmRyYXcpKSArIA0KICAgIGZhY2V0X3dyYXAofiAuZHJhdykNCmBgYA0KDQpQcmlvciBkaXN0cmlidXRpb24gZXhwZWN0cyB0aGUgZ2FtZXMgdG8gcmFuZ2UgZnJvbSAxOTEwIC0gMTk0NSBzZWNvbmRzIGFzIGV4cGVjdGVkDQoNCkdhbWUgZHVyYXRpb24gbGllcyBiZXR3ZWVuIDUwMC0zNTAwIHNlY29uZHMgd2hpY2ggZmFsbHMgaW4gbGluZSB3aXRoIG91ciBzdW1tYXJ5DQoNClByaW9yIGRpc3RyaWJ1dGlvbiBleHBlY3RzIGdhbWVzIHRvIGxhc3QgbG9uZ2VyIGlmIHRlYW0gMiB3aW5zIGFzIGNvbXBhcmVkIHRvIHRlYW0gMQ0KDQpgYGB7cn0NCm1jbWNfdHJhY2UoYmFzZSwgc2l6ZSA9IC4xKQ0KYGBgDQoNClBsb3RzIGxvb2sgZmFzdCBtaXhpbmcgYW5kIGNvbnNpc3RlbnQNCg0KYGBge3J9DQpyaGF0KGJhc2UpDQpgYGANCg0KUmhhdCBjbG9zZSB0byAxIGFuZCBub3QgXD4xLjA1LCBnb29kDQoNCmBgYHtyfQ0KbmVmZl9yYXRpbyhiYXNlKQ0KYGBgDQoNCm5lZmYgcmF0aW8gaXMgYSBsaXR0bGUgaGlnaCBidXQgc3RpbGwgYWNjZXB0YWJsZSwgXD4uMTAgd2hpY2ggaXMgZ29vZA0KDQpgYGB7cn0NCnRpZHkoYmFzZSwgZWZmZWN0cyA9IGMoImZpeGVkIiwgImF1eCIpLA0KICAgICBjb25mLmludCA9IFRSVUUsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCk92ZXJhbGwgdGhlIG1vZGVsIGNvdWxkIHdvcmssIGJ1dCBtb3JlIGludmVzdGlnYXRpb24gc2hvdWxkIGJlIGRvbmUgdG8gaW1wcm92ZSB3aGF0IHdlIGhhdmUNCg0KIyMgSW50ZXJhY3Rpb24gSW52ZXN0aWdhdGlvbg0KDQpMZXRzIHNlZSBpZiB0aGVyZSBhcmUgc29tZSBpbnRlcmFjdGlvbnMgd2UgY2FuIGV4cGVjdA0KDQpTcGVha2luZyBmcm9tIGV4cGVyaWVuY2UgaW4gcGxheWluZyB0aGUgZ2FtZSBteXNlbGYsIEkgcHJlZGljdCB0aGUgZHJhZ29uIGFuZCBiYXJvbiBraWxscyB3aWxsIGhhdmUgYSBiaWcgaW1wYWN0IG9uIHRoZSBnYW1lIGR1cmF0aW9uIGR1ZSB0byB0aGUgYnVmZnMgdGhleSBnaXZlIGVhY2ggbWVtYmVyIG9mIHRoZSB0ZWFtIGJlaW5nIGNydWNpYWwgdG8gd2lubmluZw0KDQpgYGB7cn0NCmludCA8LSBzdGFuX2dsbShnYW1lRHVyYXRpb24gfiB0MV9kcmFnb25LaWxsczp0Ml9kcmFnb25LaWxscywNCiAgZGF0YSA9IGxvbF9kYXRhLCBmYW1pbHkgPSBnYXVzc2lhbiwgDQogIHByaW9yX2ludGVyY2VwdCA9IG5vcm1hbCgxODAwLCAxNTAsIGF1dG9zY2FsZSA9IFRSVUUpLA0KICBwcmlvciA9IG5vcm1hbCgwLCAyLjUsIGF1dG9zY2FsZSA9IFRSVUUpLCANCiAgcHJpb3JfYXV4ID0gZXhwb25lbnRpYWwoMSwgYXV0b3NjYWxlID0gVFJVRSksDQogIGNoYWlucyA9IDQsIGl0ZXIgPSA1MDAwKjIsIHNlZWQgPSA4NDczNSkNCmBgYA0KDQpgYGB7cn0NCmludDIgPC0gc3Rhbl9nbG0oZ2FtZUR1cmF0aW9uIH4gdDFfYmFyb25LaWxsczp0Ml9iYXJvbktpbGxzLA0KICBkYXRhID0gbG9sX2RhdGEsIGZhbWlseSA9IGdhdXNzaWFuLCANCiAgcHJpb3JfaW50ZXJjZXB0ID0gbm9ybWFsKDE4MDAsIDE1MCwgYXV0b3NjYWxlID0gVFJVRSksDQogIHByaW9yID0gbm9ybWFsKDAsIDIuNSwgYXV0b3NjYWxlID0gVFJVRSksIA0KICBwcmlvcl9hdXggPSBleHBvbmVudGlhbCgxLCBhdXRvc2NhbGUgPSBUUlVFKSwNCiAgY2hhaW5zID0gNCwgaXRlciA9IDUwMDAqMiwgc2VlZCA9IDg0NzM1KQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShpbnQpDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGludDIpDQpgYGANCg0KU3VtbWFyeSBzdGF0cyBsb29rIHByb21pc2luZyB3aXRoIGJvdGggdmFsdWVzIG5vdCBjb250YWluaW5nIDAgZm9yIHRoZWlyIDk1JSBDSSBzaG93aW5nIHRoZXkgYXJlIHNpZ25pZmljYW50IGFuZCBjYW4gYmUgdXNlZnVsDQoNCmBgYHtyfQ0KIyBFeHRyYWN0IHRoZSBwb3N0ZXJpb3Igc2FtcGxlcw0KcG9zdGVyaW9yX3NhbXBsZXMgPC0gYXMubWF0cml4KGludCkNCnBvc3Rlcmlvcl9zYW1wbGVzMiA8LSBhcy5tYXRyaXgoaW50MikNCg0KIyBQbG90IHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIG9mIHRoZSBpbnRlcmFjdGlvbiB0ZXJtDQptY21jX2hpc3QocG9zdGVyaW9yX3NhbXBsZXMsIHBhcnMgPSBjKCJ0MV9kcmFnb25LaWxsczp0Ml9kcmFnb25LaWxscyIpKQ0KDQptY21jX2hpc3QocG9zdGVyaW9yX3NhbXBsZXMyLCBwYXJzID0gYygidDFfYmFyb25LaWxsczp0Ml9iYXJvbktpbGxzIikpDQpgYGANCg0KVGhlIHByZWRpY3RvcnMgZG9uJ3QgbG9vayBza2V3ZWQgZWl0aGVyLCBsb29rcyBnb29kLg0KDQpXZSBjYW4gY2FuY2x1ZGUgdGhhdCB0aGVyZSBtYXkgYmUgYSBwb3RlbnRpYWwgaW50ZXJhY3Rpb24gYmV0d2VlbiBkcmFnb24ga2lsbHMgYW5kIGJhcm9uIGtpbGxzIGZvciBlYWNoIHRlYW0NCg0KV2UgY2FuIHV0aWxpemUgdGhpcyBpbmZvIGxhdGVyIG9uIHVwb24gYnVpbGRpbmcgYSBiZXR0ZXIgbW9kZWwNCg0KIyMgTWFpbiBNb2RlbA0KDQpMZXQncyBhc3Nlc3MgaG93IG11Y2ggZ2V0dGluZyBhIGp1bXAgc3RhcnQgaW4gdGhlIGdhbWUgZG9lcyBmb3IgZGV0ZXJtaW5pbmcgdGhlIGxlbmd0aCBvZiB0aGUgZ2FtZQ0KDQpgYGB7cn0NCm1haW4gPC0gc3Rhbl9nbG0oZ2FtZUR1cmF0aW9uIH4gd2lubmVyICsgZmlyc3RCbG9vZCArIGZpcnN0VG93ZXIgKyBmaXJzdERyYWdvbiArIGZpcnN0QmFyb24sDQogIGRhdGEgPSBsb2xfZGF0YSwgZmFtaWx5ID0gZ2F1c3NpYW4sIA0KICBwcmlvcl9pbnRlcmNlcHQgPSBub3JtYWwoMTgwMCwgMTUwLCBhdXRvc2NhbGUgPSBUUlVFKSwNCiAgcHJpb3IgPSBub3JtYWwoMCwgMi41LCBhdXRvc2NhbGUgPSBUUlVFKSwgDQogIHByaW9yX2F1eCA9IGV4cG9uZW50aWFsKDEsIGF1dG9zY2FsZSA9IFRSVUUpLA0KICBjaGFpbnMgPSA0LCBpdGVyID0gNTAwMCoyLCBzZWVkID0gODQ3MzUpDQpgYGANCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KG1haW4pIA0KYGBgDQoNCmBgYHtyfQ0KbWNtY190cmFjZShtYWluLCBzaXplID0gLjEpDQpgYGANCg0KQ2hhaW5zIGxvb2sgbm9ybWFsDQoNCmBgYHtyfQ0KcmhhdChtYWluKQ0KYGBgDQoNCmBgYHtyfQ0KbmVmZl9yYXRpbyhtYWluKQ0KYGBgDQoNClJoYXQgbG9va3MgZ29vZCwgc29tZSBvZiB0aGUgbmVmZiByYXRpbyB2YWx1ZXMgYXJlIHN0aWxsIGhpZ2ggYnV0IGFjY2VwdGFibGUgZm9yIG5vdw0KDQpgYGB7cn0NCnRpZHkobWFpbiwgZWZmZWN0cyA9IGMoImZpeGVkIiwgImF1eCIpLA0KICAgICBjb25mLmludCA9IFRSVUUsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCkZyb20gdGhlIHRpZHkgb3V0cHV0LCBpdCBsb29rcyBsaWtlIHdpbm5lciwgZmlyc3RCbG9vZCwgYW5kIGZpcnN0VG93ZXIgbG9zZSB0aGVpciBzaWduaWZpY2FuY2Ugd2hlbiBhZGRpbmcgb3RoZXIgcHJlZGljdG9ycyBzaW5jZSB0aGVpciA5NSUgQ0kgcmFuZ2UgaW5jbHVkZXMgMC4gV2UnbGwgdXNlIHRoaXMgaW5mbyBsYXRlciBmb3IgcmVmaW5pbmcgb3VyIG1vZGVsDQoNCmBgYHtyfQ0KbmV3ZGF0YSA8LSBkYXRhLmZyYW1lKHdpbm5lciA9IGZhY3RvcigxLCBsZXZlbHMgPSBsZXZlbHMobG9sX2RhdGEkd2lubmVyKSksDQogICAgICAgICAgICAgICAgICAgICAgZmlyc3RCbG9vZCA9IGZhY3RvcigyLCBsZXZlbHMgPSBsZXZlbHMobG9sX2RhdGEkZmlyc3RCbG9vZCkpLA0KICAgICAgICAgICAgICAgICAgICAgIGZpcnN0VG93ZXIgPSBmYWN0b3IoMiwgbGV2ZWxzID0gbGV2ZWxzKGxvbF9kYXRhJGZpcnN0VG93ZXIpKSwNCiAgICAgICAgICAgICAgICAgICAgICBmaXJzdERyYWdvbiA9IGZhY3RvcigyLCBsZXZlbHMgPSBsZXZlbHMobG9sX2RhdGEkZmlyc3REcmFnb24pKSwNCiAgICAgICAgICAgICAgICAgICAgICBmaXJzdEJhcm9uID0gZmFjdG9yKDIsIGxldmVscyA9IGxldmVscyhsb2xfZGF0YSRmaXJzdEJhcm9uKSkpDQoNCm1haW5fcHJlZGljdCA8LSBwb3N0ZXJpb3JfcHJlZGljdCgNCiAgbWFpbiwgDQogIG5ld2RhdGEgPSBuZXdkYXRhKQ0KbWNtY19hcmVhcyhtYWluX3ByZWRpY3QpICsgIHhsYWIoIkdhbWUgRHVyYXRpb24iKSArDQogIGdndGl0bGUoJ1ByZWRpY3RpdmUgZGlzdHJpYnV0aW9uIG9mIGEgTGVhZ3VlIG9mIExlZ2VuZHMgZ2FtZSB3aGVyZSBmaXJzdCBibG9vZCwgdG93ZXIsIGRyYWdvbiwgYmFyb24gd2FzIHRlYW0gMiBhbmQgdGVhbSAxIHdvbicpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpDQpgYGANCg0KSGVyZSdzIGFuIGV4YW1wbGUgb3V0cHV0IG9mIHdoZXJlIGEgZ2FtZSBkdXJhdGlvbiBtYXkgbGllIGlmIHRlYW0gMSB3aW5zIGRlc3BpdGUgYmVpbmcgYmVoaW5kIGZyb20gdGhlIHN0YXJ0LiBUaGUgZ2FtZSBpcyBhIGxpdHRsZSBsYXRlciB0aGFuIG5vcm1hbCwgYnV0IHRvIGJlIGV4cGVjdGVkIGFzIHRoZSB0ZWFtIHdvdWxkIG5lZWQgdGltZSB0byBtYWtlIHRoZSBjb21lYmFjayBpbiB0aGUgZmlyc3QgcGxhY2UuIEhvd2V2ZXIsIEkgYmVsaWV2ZSB0aGlzIGlzIHVuZGVyc2hvb3RpbmcgdGhlIHRydWUgdGltZSB3ZSBjb3VsZCBleHBlY3QgZnJvbSB0aGlzIHNjZW5hcmlvLiBXZSdsbCB2ZXJpZnkgaWYgdGhpcyBpcyB0cnVlIGFmdGVyIHJlZmluaW5nIG91ciBtb2RlbA0KDQojIyBNb3JlIFByZWRpY3RvcnMNCg0KV2UgY2FuIGFkZCBzb21lIG51bWVyaWNhbCB2YXJpYWJsZXMgdG8gc2VlIGhvdyBtdWNoIGFkZGluZyB0aGUgYW1vdW50IG9mIGVhY2ggb2JqZWN0aXZlIGEgdGVhbSBoYXMgdGFrZW4gdG8gc2VlIGhvdyBpdCBhZmZlY3RzIHRoZSBnYW1lIGR1cmF0aW9uDQoNCmBgYHtyfQ0KZXh0X21haW4gPC0gc3Rhbl9nbG0oZ2FtZUR1cmF0aW9uIH4gd2lubmVyICsgZmlyc3RCbG9vZCArIGZpcnN0VG93ZXIgKyBmaXJzdERyYWdvbiArIGZpcnN0QmFyb24gKyB0MV90b3dlcktpbGxzICsgdDFfaW5oaWJpdG9yS2lsbHMgKyB0MV9iYXJvbktpbGxzICsgdDFfZHJhZ29uS2lsbHMgKyB0Ml90b3dlcktpbGxzICsgdDJfaW5oaWJpdG9yS2lsbHMgKyB0Ml9iYXJvbktpbGxzICsgdDJfZHJhZ29uS2lsbHMsDQogIGRhdGEgPSBsb2xfZGF0YSwgZmFtaWx5ID0gZ2F1c3NpYW4sIA0KICBwcmlvcl9pbnRlcmNlcHQgPSBub3JtYWwoMTgwMCwgMTUwLCBhdXRvc2NhbGUgPSBUUlVFKSwNCiAgcHJpb3IgPSBub3JtYWwoMCwgMi41LCBhdXRvc2NhbGUgPSBUUlVFKSwgDQogIHByaW9yX2F1eCA9IGV4cG9uZW50aWFsKDEsIGF1dG9zY2FsZSA9IFRSVUUpLA0KICBjaGFpbnMgPSA0LCBpdGVyID0gNTAwMCoyLCBzZWVkID0gODQ3MzUpDQpgYGANCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KGV4dF9tYWluKSANCmBgYA0KDQpgYGB7cn0NCm1jbWNfdHJhY2UoZXh0X21haW4sIHNpemUgPSAuMSkNCmBgYA0KDQpUcmFjZXMgbG9vayBnb29kDQoNCmBgYHtyfQ0KcmhhdChleHRfbWFpbikNCmBgYA0KDQpgYGB7cn0NCm5lZmZfcmF0aW8oZXh0X21haW4pDQpgYGANCg0KUmhhdCBsb29rcyBnb29kLCBzb21lIG5lZmYgcmF0aW9zIChpLmUuIGZpcnN0Qmxvb2QsIGZpcnN0VG93ZXIpIGFyZSBub3cgdG9vIGhpZ2ggdG8ga2VlcCBhbmQgd2lsbCBuZWVkIHRvIGJlIGhhbmRsZWQgbGF0ZXINCg0KYGBge3J9DQp0aWR5KGV4dF9tYWluLCBlZmZlY3RzID0gYygiZml4ZWQiLCAiYXV4IiksDQogICAgIGNvbmYuaW50ID0gVFJVRSwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCg0KSGVyZSwgdGhlIHByZWRpY3RvcnMgd2lubmVyLCBmaXJzdEJsb29kLCBhbmQgZmlyc3RUb3dlciBhcmUgbm90IHNpZ25pZmljYW50IGR1ZSB0byB0aGVpciA5NSUgQ0kgaW5jbHVkaW5nIDANCg0KYGBge3J9DQojIGRhdGFmcmFtZSB3aXRoIHRoZSBzcGVjaWZpZWQgdmFsdWVzDQpuZXdkYXRhX2V4dCA8LSBkYXRhLmZyYW1lKA0KICB3aW5uZXIgPSBmYWN0b3IoMSwgbGV2ZWxzID0gbGV2ZWxzKGxvbF9kYXRhJHdpbm5lcikpLA0KICBmaXJzdEJsb29kID0gZmFjdG9yKDIsIGxldmVscyA9IGxldmVscyhsb2xfZGF0YSRmaXJzdEJsb29kKSksDQogIGZpcnN0VG93ZXIgPSBmYWN0b3IoMiwgbGV2ZWxzID0gbGV2ZWxzKGxvbF9kYXRhJGZpcnN0VG93ZXIpKSwNCiAgZmlyc3REcmFnb24gPSBmYWN0b3IoMiwgbGV2ZWxzID0gbGV2ZWxzKGxvbF9kYXRhJGZpcnN0RHJhZ29uKSksDQogIGZpcnN0QmFyb24gPSBmYWN0b3IoMiwgbGV2ZWxzID0gbGV2ZWxzKGxvbF9kYXRhJGZpcnN0QmFyb24pKSwNCiAgdDFfdG93ZXJLaWxscyA9IDcsDQogIHQxX2luaGliaXRvcktpbGxzID0gMiwNCiAgdDFfYmFyb25LaWxscyA9IDIsDQogIHQxX2RyYWdvbktpbGxzID0gMiwNCiAgdDJfdG93ZXJLaWxscyA9IDMsDQogIHQyX2luaGliaXRvcktpbGxzID0gMiwNCiAgdDJfYmFyb25LaWxscyA9IDEsDQogIHQyX2RyYWdvbktpbGxzID0gMw0KKQ0KDQpleHRfbWFpbl9wcmVkaWN0IDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGV4dF9tYWluLCBuZXdkYXRhID0gbmV3ZGF0YV9leHQpDQoNCm1jbWNfYXJlYXMoZXh0X21haW5fcHJlZGljdCkgKyAgDQogIHhsYWIoIkdhbWUgRHVyYXRpb24iKSArDQogIGdndGl0bGUoJ1ByZWRpY3RpdmUgZGlzdHJpYnV0aW9uIG9mIGEgTGVhZ3VlIG9mIExlZ2VuZHMgZ2FtZSB3aGVyZSBmaXJzdCBibG9vZCwgdG93ZXIsIGRyYWdvbiwgYmFyb24gd2FzIHRlYW0gMiBhbmQgdGVhbSAxIHdvbiwgd2l0aCBhZGRpdGlvbmFsIHByZWRpY3RvcnMnKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQ0KYGBgDQoNCkFmdGVyIGFkZGluZyBhIGZldyBtb3JlIHZhcmlhYmxlcyBpbnRvIHBsYXkgd2UgY2FuIHNlZSB0aGUgZ2FtZSBnZXRzIGxvbmdlciAoYW5kIGV4cGVjdGVkbHkgc28pLiBUZWFtIDEgY29tZXMgZnJvbSBiZWhpbmQgYnV0IGVuZHMgdXAgZ2V0dGluZyAyIGJhcm9ucyBhbmQgNyB0b3dlcnMgbWFraW5nIHVzIGJlbGlldmUgdGhpcyBnYW1lIHdpbGwgaGF2ZSB0byBnbyBvbiBmb3IgYSB3aGlsZSBmb3IgdGhlIGNvbWViYWNrIHRvIHRydWx5IGJlIGNvbXBsZXRlDQoNCiMjIFJlZmluZWQgTW9kZWwNCg0KTGV0J3Mgbm93IHJlbW92ZSB0aGUgaGlnaCBuZWZmIHJhdGlvIHRlcm1zIGZyb20gdGhlIGV4dGVuZGVkIG1vZGVsIChpLmUuIFw+IDEpIGFuZCBpbmNsdWRlIHRoZSBpbnRlcmFjdGlvbiB0ZXJtcyB3ZSBkZWVtZWQgdXNlZnVsIGJlZm9yZWhhbmQNCg0KYGBge3J9DQpleHRfbWFpbl9pbnQgPC0gc3Rhbl9nbG0oZ2FtZUR1cmF0aW9uIH4gZmlyc3REcmFnb24gKyBmaXJzdEJhcm9uICsgdDFfYmFyb25LaWxscyArIHQxX2RyYWdvbktpbGxzICsgdDJfYmFyb25LaWxscyArIHQyX2RyYWdvbktpbGxzICsgdDFfYmFyb25LaWxsczp0Ml9iYXJvbktpbGxzICsgdDFfZHJhZ29uS2lsbHM6dDJfZHJhZ29uS2lsbHMsDQogIGRhdGEgPSBsb2xfZGF0YSwgZmFtaWx5ID0gZ2F1c3NpYW4sIA0KICBwcmlvcl9pbnRlcmNlcHQgPSBub3JtYWwoMTgwMCwgMTUwLCBhdXRvc2NhbGUgPSBUUlVFKSwNCiAgcHJpb3IgPSBub3JtYWwoMCwgMi41LCBhdXRvc2NhbGUgPSBUUlVFKSwgDQogIHByaW9yX2F1eCA9IGV4cG9uZW50aWFsKDEsIGF1dG9zY2FsZSA9IFRSVUUpLA0KICBjaGFpbnMgPSA0LCBpdGVyID0gNTAwMCoyLCBzZWVkID0gODQ3MzUpDQpgYGANCg0KYGBge3J9DQpwcmlvcl9zdW1tYXJ5KGV4dF9tYWluX2ludCkNCmBgYA0KDQpgYGB7cn0NCm1jbWNfdHJhY2UoZXh0X21haW5faW50LCBzaXplID0gLjEpDQpgYGANCg0KU28gZmFyIHNvIGdvb2QNCg0KYGBge3J9DQpyaGF0KGV4dF9tYWluX2ludCkNCmBgYA0KDQpSaGF0IGxvb2tzIHNhdGlzZmFjdG9yeSBmb3IgYWxsIHByZWRpY3RvcnMNCg0KYGBge3J9DQpuZWZmX3JhdGlvKGV4dF9tYWluX2ludCkNCmBgYA0KDQpOZWZmIHJhdGlvcyBhcmUgbXVjaCBtb3JlIHJlYXNvbmFibGUgbm93IGFuZCBhIGJpZyBpbXByb3ZlbWVudCBmcm9tIHByaW9yIG1vZGVscyB3aXRoIG5vIHZhbHVlIGJlaW5nIFw+IC45MA0KDQpgYGB7cn0NCnRpZHkoZXh0X21haW5faW50LCBlZmZlY3RzID0gYygiZml4ZWQiLCAiYXV4IiksDQogICAgIGNvbmYuaW50ID0gVFJVRSwgY29uZi5sZXZlbCA9IDAuOTUpDQpgYGANCg0KRXZlcnkgdmFsdWUgbG9va3Mgc2lnbmlmaWNhbnQgZnJvbSB0aGUgOTUlIENJIChldmVuIHRoZSBpbnRlcmFjdGlvbiB0ZXJtcyEhKSBkdWUgdG8gbm9uZSBvZiB0aGVtIGluY2x1ZGluZyAwLg0KDQpgYGB7cn0NCiMgZGF0YWZyYW1lIHdpdGggdGhlIHNwZWNpZmllZCB2YWx1ZXMNCm5ld2RhdGFfZXh0X2ludCA8LSBkYXRhLmZyYW1lKA0KICBmaXJzdERyYWdvbiA9IGZhY3RvcigyLCBsZXZlbHMgPSBsZXZlbHMobG9sX2RhdGEkZmlyc3REcmFnb24pKSwNCiAgZmlyc3RCYXJvbiA9IGZhY3RvcigyLCBsZXZlbHMgPSBsZXZlbHMobG9sX2RhdGEkZmlyc3RCYXJvbikpLA0KICB0MV9iYXJvbktpbGxzID0gMiwNCiAgdDFfZHJhZ29uS2lsbHMgPSAyLA0KICB0Ml9iYXJvbktpbGxzID0gMSwNCiAgdDJfZHJhZ29uS2lsbHMgPSAzDQopDQoNCmV4dF9tYWluX2ludF9wcmVkaWN0IDwtIHBvc3Rlcmlvcl9wcmVkaWN0KGV4dF9tYWluX2ludCwgbmV3ZGF0YSA9IG5ld2RhdGFfZXh0X2ludCkNCg0KbWNtY19hcmVhcyhleHRfbWFpbl9pbnRfcHJlZGljdCkgKyAgDQogIHhsYWIoIkdhbWUgRHVyYXRpb24iKSArDQogIGdndGl0bGUoJ1ByZWRpY3RpdmUgZGlzdHJpYnV0aW9uIG9mIGEgTGVhZ3VlIG9mIExlZ2VuZHMgZ2FtZSB3aGVyZSBmaXJzdCBkcmFnb24sIGJhcm9uIHdhcyB0ZWFtIDIgYW5kIHRlYW0gMSBoYWQgbW9yZSBiYXJvbiBraWxscyB3aXRoIGludGVyYWN0aW9uJykgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkNCmBgYA0KDQpUaGUgZ2FtZXMgc2VlbSB0byBkcmFnIG9uIGV2ZW4gbG9uZ2VyIHdpdGggdGhpcyBuZXcgbW9kZWwuIFRoaXMgaXMgZXhwZWN0ZWQgc2luY2UgdGhlIGRyYWdvbiBhbmQgYmFyb24gcmVzcGF3biB0aW1lcyBhcmUgcXVpdGUgbG9uZyBzbywgYXMgc2FpZCBiZWZvcmUsIHRoZSBjb21lYmFjayB3b3VsZCByZWFsaXN0aWNhbGx5IHRha2UgbG9uZ2VyIHRoYW4gYXZlcmFnZS4NCg0KTGV0cyBkbyBzb21lIG1vZGVsIGNvbXBhcmlzb25zIHRvIHZlcmlmeSB3aGljaCBtb2RlbCBpcyBiZXN0DQoNCiMjIE1vZGVsIENvbXBhcmlzb25zDQoNCiMjIyBQUCBDaGVjaw0KDQpgYGB7cn0NCnBwX2NoZWNrKG1haW4sIG5yZXBzID0gNTApICsgeGxhYigiR2FtZSBEdXJhdGlvbiIpICsNCiAgZ2d0aXRsZSgnTWFpbiBlZmZlY3RzIG1vZGVsJykNCmBgYA0KDQpUaGUgbWFpbiBtb2RlbCBnZXRzIGEgZGVjZW50IGFtb3VudCBvZiBhcmVhLCB5ZXQgaXQgc3RhcnRzIG1vdmluZyB0b28gZmFyIHJpZ2h0IGFuZCB1bmRlcnNob290cyBhdCB0aGUgcGVhaw0KDQpgYGB7cn0NCnBwX2NoZWNrKGV4dF9tYWluLCBucmVwcyA9IDUwKSArIHhsYWIoIkdhbWUgRHVyYXRpb24iKSArDQogIGdndGl0bGUoJ0V4dGVuZGVkIE1haW4gZWZmZWN0cyBtb2RlbCcpDQpgYGANCg0KVGhlIGV4dGVuZGVkIG1vZGVsIGlzIG9iamVjdGl2ZWx5IGJldHRlciB0aGFuIHRoZSBtYWluIG1vZGVsLCBidXQgc3RpbGwgdW5kZXJzaG9vdHMgYXJlYSBhdCB0aGUgcGVhaw0KDQpgYGB7cn0NCnBwX2NoZWNrKGV4dF9tYWluX2ludCwgbnJlcHMgPSA1MCkgKyB4bGFiKCJHYW1lIER1cmF0aW9uIikgKw0KICBnZ3RpdGxlKCdSZWZpbmVkIEludGVyYWN0aW9uIGVmZmVjdHMgbW9kZWwnKQ0KYGBgDQoNClRoZSBpbnRlcmFjdGlvbiBtb2RlbCBpcyB2ZXJ5IHNpbWlsYXIgdG8gdGhlIGV4dGVuZGVkIG1vZGVsIHdoaWNoIGlzIGJldHRlciB0aGFuIHRoZSBtYWluIG1vZGVsLg0KDQpUaGUgcHBjaGVja3Mgc2hvdyBtb3N0IG9mIHRoZSBhcmUgYmVpbmcgY292ZXJlZCBmb3IgdGhlIGxhc3QgMiBtb2RlbHMgd2l0aCB0aGUgaW50ZXJhY3Rpb24gbW9kZWwgZG9pbmcgYmV0dGVyIGFyb3VuZCB0aGUgcGVhayBieSBhIHNtYWxsIG1hcmdpbg0KDQojIyMgMTAgRm9sZCBDcm9zcy1WYWxpZGF0aW9ucw0KDQpgYGB7cn0NCnRlc3Rfc2FtcGxlIDwtIGxvbF9kYXRhICU+JSBoZWFkKDEwMDAwKQ0KbnJvdyh0ZXN0X3NhbXBsZSkNCmBgYA0KDQpgYGB7cn0NCnNldC5zZWVkKDg0NzM1KQ0KDQpwX21haW4gPC0gcHJlZGljdGlvbl9zdW1tYXJ5KG1vZGVsID0gbWFpbiwgZGF0YSA9IHRlc3Rfc2FtcGxlKQ0KcF9leHRfbWFpbiA8LSBwcmVkaWN0aW9uX3N1bW1hcnkobW9kZWwgPSBleHRfbWFpbiwgZGF0YSA9IHRlc3Rfc2FtcGxlKQ0KcF9leHRfbWFpbl9pbnQgPC0gcHJlZGljdGlvbl9zdW1tYXJ5KG1vZGVsID0gZXh0X21haW5faW50LCBkYXRhID0gdGVzdF9zYW1wbGUpDQpgYGANCg0KYGBge3J9DQpyYmluZChwX21haW4sIHBfZXh0X21haW4sIHBfZXh0X21haW5faW50KQ0KYGBgDQoNClRoZXNlIGFyZSB0aGUgcmF3IE1BRSB2YWx1ZXMgYmFzZWQgb24gYSBzYW1wbGUgb2YgMTAwMDAgb2JzZXJ2YXRpb25zIGZyb20gdGhlIGRhdGEsIHdlIGNhbiB1c2UgdGhlc2UgdG8gZGV0ZXJtaW5lIHRoZSBiZWhhdmlvciBhbmQgYmlhcyBvZiBlYWNoIG1vZGVsIGJhc2VkIG9uIHRoZWlyIGNyb3NzLXZhbGlkYXRpb24gcmVzdWx0cw0KDQpgYGB7cn0NCnNldC5zZWVkKDg0NzM1KQ0KDQpjdl9tYWluIDwtIHByZWRpY3Rpb25fc3VtbWFyeV9jdigNCiAgbW9kZWwgPSBtYWluLCBkYXRhID0gbG9sX2RhdGEsIGsgPSAxMCkNCg0KY3ZfZXh0ZW5kIDwtIHByZWRpY3Rpb25fc3VtbWFyeV9jdigNCiAgbW9kZWwgPSBleHRfbWFpbiwgZGF0YSA9IGxvbF9kYXRhLCBrID0gMTApDQoNCmN2X2ludGVyYWN0IDwtIHByZWRpY3Rpb25fc3VtbWFyeV9jdigNCiAgbW9kZWwgPSBleHRfbWFpbl9pbnQsIGRhdGEgPSBsb2xfZGF0YSwgayA9IDEwKQ0KYGBgDQoNCmBgYHtyfQ0KcmJpbmQoY3ZfbWFpbiRjdiwgY3ZfZXh0ZW5kJGN2LCBjdl9pbnRlcmFjdCRjdikNCmBgYA0KDQojIyMgTG9vIERpYWdub3N0aWNzDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMzQ1MjEpDQptYWluX2VscGQgPC0gbG9vKG1haW4pDQpleHRfbWFpbl9lbHBkIDwtIGxvbyhleHRfbWFpbikNCmV4dF9tYWluX2ludGVyYWN0X2VscGQgPC0gbG9vKGV4dF9tYWluX2ludCkNCg0KbWFpbl9lbHBkJGVzdGltYXRlcw0KZXh0X21haW5fZWxwZCRlc3RpbWF0ZXMNCmV4dF9tYWluX2ludGVyYWN0X2VscGQkZXN0aW1hdGVzDQpgYGANCg0KYGBge3J9DQpjKG1haW5fZWxwZCRlc3RpbWF0ZXNbMV0sIGV4dF9tYWluX2VscGQkZXN0aW1hdGVzWzFdLCBleHRfbWFpbl9pbnRlcmFjdF9lbHBkJGVzdGltYXRlc1sxXSkNCg0KbG9vX2NvbXBhcmUobWFpbl9lbHBkLCBleHRfbWFpbl9lbHBkLCBleHRfbWFpbl9pbnRlcmFjdF9lbHBkKQ0KYGBgDQoNClRoZSBleHRlbmRlZCBtb2RlbCBmYWlycyBiZXR0ZXIgdGhhbiB0aGUgaW50ZXJhY3Rpb24gbW9kZWwgd2hlbiBjb21wYXJpbmcgdGhlaXIgRUxQRCBhbmQgTUFFLiBUaGUgaW50ZXJhY3Rpb24gbW9kZWwgZG9lcyA0MzM3LjYgcG9pbnRzICJ3b3JzZSIgZm9yIEVMUEQgYW5kIGlzIGFyb3VuZCAxNiBwb2ludHMgaGlnaGVyIGluIGl0cyBNQUUuIEhvd2V2ZXIsIHNvbWV0aGluZyB0byBjb25zaWRlciBoZXJlIGlzIHRoZSBpZGVhIG9mIFtvdmVyZml0dGluZ10oaHR0cHM6Ly9zdGF0aXN0aWNzYnlqaW0uY29tL3JlZ3Jlc3Npb24vb3ZlcmZpdHRpbmctcmVncmVzc2lvbi1tb2RlbHMvKSBhbmQgaG93IG1vcmUgcHJlZGljdG9ycyBhbmQgYWZmZWN0IHRoZSBtb2RlbCBvdmVyYWxsIGFuZCBza2V3IG91ciBtZXRyaWNzLg0KDQpEZXNwaXRlIHRoZSBpbnRlcmFjdGlvbiBtb2RlbCBjb3ZlcmluZyBtb3JlIGFyZWEsIHRoZSBbTUFFXShodHRwczovL3N0ZXBoZW5hbGx3cmlnaHQuY29tL2dvb2QtbWFlLXNjb3JlLykgYW5kIEVMUEQgYXJlIGJvdGggd29yc2UuIFRoaXMgbWF5IGJlIGR1ZSB0byB0aGVzZSB2YWx1ZXMgYmVpbmcgaW5mbGF0ZWQgYnkgdGhlIGxhcmdlciBudW1iZXIgb2YgcHJlZGljdG9ycyBpbiB0aGUgZXh0ZW5kZWQgbW9kZWwuIEZ1cnRoZXJtb3JlLCB0aGUgZXh0ZW5kZWQgbW9kZWwgY29udGFpbnMgbnVtZXJvdXMgdmFsdWVzIHdpdGggaGlnaGVyIHRoYW4gbm9ybWFsIE5lZmYgUmF0aW9zIHdoaWNoIGlzIGEgW2NhdXNlIGZvciBjb25jZXJuXShodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8yOTYwNTkvZWZmZWN0aXZlLXNhbXBsZS1zaXplLWdyZWF0ZXItdGhhbi1hY3R1YWwtc2FtcGxlLXNpemUpIGFib3V0IHRoZSB2YWxpZGl0eSBvZiB0aGUgbW9kZWwgYWxvbmcgd2l0aCBwcmVkaWN0b3JzIHRoYXQgd2VyZSBub3Qgc2lnbmlmaWNhbnQuDQoNCkRlc3BpdGUgaGF2aW5nIGxlc3MgcHJlZGljdG9ycywgdGhlIGludGVyYWN0aW9uIG1vZGVsIGdhcm5lcnMgbW9yZSBhcmVhIGluIGl0cyBwcmVkaWN0aXZlIHBvc3RlcmlvciBkaXN0cmlidXRpb24gd2hpbGUgaGF2aW5nIGEgc2ltaWxhciBNQUUgYW5kIGdvb2QgRUxQRCBzY29yZSB0b28gKC0zMDk4NTkuNyB2cyAzMTQxOTcuMykgd2hpY2ggaXMgYSBtaW5vciAoXH4xJSkgZGlmZmVyZW5jZSBnaXZlbiB0aGUgc2l6ZSBvZiB0aGVzZSB2YWx1ZXMuIEhvd2V2ZXIsIHRoZXNlIGludGVyYWN0aW9uIHRlcm1zIGNvdWxkIGFsc28gYmUgaGF2aW5nIGFuIGFkdmVyc2UgZWZmZWN0IG9uIHRoZSBtb2RlbCBsZWFkaW5nIHRvIHRoZXNlIGdyZWF0ZXIgZXJyb3JzLg0KDQojIyMgT3ZlcmZpdHRpbmcNCg0KYGBge3J9DQpyYmluZChwX21haW4sIHBfZXh0X21haW4sIHBfZXh0X21haW5faW50KSANCnJiaW5kKGN2X21haW4kY3YsIGN2X2V4dGVuZCRjdiwgY3ZfaW50ZXJhY3QkY3YpDQpgYGANCg0KQmFzZWQgb24gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcmF3IE1BRSB2YWx1ZXMgYW5kIHRoZSBjcm9zcy12YWxpZGF0aW9uIE1BRSB2YWx1ZXMsIG92ZXJmaXR0aW5nIGRvZXMgbm90IHNlZW0gdG8gcG9zZSBhIHRocmVhdCB0byB0aGVzZSBtb2RlbHMsIGhvd2V2ZXIgd2UgY2FuIG9ubHkgdHJ1bHkga25vdyB0aGlzIGlmIHdlIGFyZSBnaXZlbiBuZXcgZGF0YSBlbnRpcmVseSB0byB0ZXN0IHRoZSBtb2RlbHMuIEZ1cnRoZXJtb3JlLCB0aGUgZXh0ZW5kZWQgbW9kZWwgZG9lcyBoYXZlIGEgbGFyZ2VyICh0aG91Z2ggbW9zdGx5IG5lZ2xpZ2libGUgZHVlIHRvIGhvdyBzbWFsbCBpdCBpcykgZGlmZmVyZW5jZSBmcm9tIHRoZSBjcm9zcy12YWxpZGF0aW9uIE1BRSBjb21wYXJlZCB0byB0aGUgb3RoZXIgbW9kZWxzLg0KDQpXaGF0IGlzIHVuZG91YnRlZGx5IGNsZWFyIGlzIHRoYXQgYWRkaW5nIG51bWVyaWNhbCBwcmVkaWN0b3JzIHRvIHRoZSBtb2RlbCBkb2VzIGhlbHAgdGhlIHByZWRpY3Rpb25zIG92ZXJhbGwgYW5kIGlzIHNob3duIHdpdGggYm90aCB0aGUgZXh0ZW5kZWQgYW5kIGludGVyYWN0aW9uIG1vZGVsIGZhaXJpbmcgYmV0dGVyIHRoYW4gdGhlIG1haW4gbW9kZWwgaW4gZXZlcnkgYXNwZWN0Lg0KDQojIyBSZWdyZXNzaW9uIEluZmVyZW5jZQ0KDQpMZXQncyBzZWUgaG93IHRoZSAyIGJlc3QgbW9kZWxzIGZhaXIgd2hlbiBjb25kdWN0aW5nIGEgcXVpY2sgaHlwb3RoZXNpcyB0ZXN0IHRvIHNlZSB0aGUgUG9zdGVyaW9yIHByb2JhYmlsaXR5IG9mIGEgZ2FtZSBhcm91bmQgNDAgbWludXRlcyBsb25nDQoNCldlJ2xsIHVzZSB0aGUgcHJlZGljdGl2ZSBwb3N0ZXJpb3IgbW9kZWxzIHdlIGNyZWF0ZWQgYW5kIHZpc3VhbGl6ZWQgZWFybGllciB0byBjb25kdWN0IHRoZSB0ZXN0cw0KDQokJA0KSF8wOiBccGkgXGdlcSAyNTAwDQokJA0KDQokJA0KSF9hOiBccGkgPCAyNTAwDQokJA0KDQpgYGB7cn0NCiMgRXh0cmFjdCB0aGUgcG9zdGVyaW9yIHNhbXBsZXMNCnBvc3Rlcmlvcl9zYW1wbGVzIDwtIGV4dF9tYWluX2ludF9wcmVkaWN0DQoNCnBfSDAgPC0gbWVhbihwb3N0ZXJpb3Jfc2FtcGxlcyA+PSAyNTAwKQ0KDQpwX0hhIDwtIG1lYW4ocG9zdGVyaW9yX3NhbXBsZXMgPCAyNTAwKQ0KDQojIFByaW50IHRoZSByZXN1bHRzDQpjYXQoIlBvc3RlcmlvciBwcm9iYWJpbGl0eSBvZiBIMCAoz4Ag4omlIDI1MDApOiIsIHBfSDApDQpjYXQoIlBvc3RlcmlvciBwcm9iYWJpbGl0eSBvZiBIYSAoz4AgPCAyNTAwKToiLCBwX0hhKQ0KYGBgDQoNCmBgYHtyfQ0KIyBFeHRyYWN0IHRoZSBwb3N0ZXJpb3Igc2FtcGxlcw0KcG9zdGVyaW9yX3NhbXBsZXMgPC0gZXh0X21haW5fcHJlZGljdA0KDQpwX0gwIDwtIG1lYW4ocG9zdGVyaW9yX3NhbXBsZXMgPj0gMjUwMCkNCg0KcF9IYSA8LSBtZWFuKHBvc3Rlcmlvcl9zYW1wbGVzIDwgMjUwMCkNCg0KIyBQcmludCB0aGUgcmVzdWx0cw0KY2F0KCJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgb2YgSDAgKM+AIOKJpSAyNTAwKToiLCBwX0gwKQ0KY2F0KCJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgb2YgSGEgKM+AIDwgMjUwMCk6IiwgcF9IYSkNCmBgYA0KDQpUaG91Z2ggdGhlIHR3byBtb2RlbHMgc2VlbWluZ2x5IHByZWRpY3QgdGhlIGFjdHVhbCBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGEgd2VsbCwgdGhlIDIgbW9kZWxzIGhhdmUgdmVyeSBkaWZmZXJlbnQgb3V0Y29tZXMgd2hlbiBjb25kdWN0aW5nIHRoZSB0ZXN0Lg0KDQpUaGUgZXh0ZW5kZWQgbW9kZWwgZmF2b3JzIHRoZSBhbHRlcm5hdGUgaHlwb3RoZXNpcyB3aGlsZSB0aGUgaW50ZXJhY3Rpb24gbW9kZWwgY2xlYXJseSBmYXZvcnMgdGhlIG51bGwgaHlwb3RoZXNpcy4gVGhpcyBib3RoIGNvaW5jaWRlcyB3aXRoIHdoYXQgd2Ugc2F3IGJlZm9yZSBmcm9tIHRoZSB2aXN1YWxpemF0aW9ucyBhbmQgdGVsbHMgdXMgdGhhdCB0aGUgZXh0ZW5kZWQgbW9kZWwgZmF2b3JzIGdhbWVzIHRoYXQgYXJlIHNob3J0ZXIgd2hpbGUgdGhlIGludGVyYWN0aW9uIG1vZGVsIGV4cGVjdHMgZ2FtZXMgbGlrZSB0aGlzIHRvIHRha2UgbG9uZ2VyLg0KDQpUaGlzIGlzIGFsc28gc29tZXRoaW5nIG9uZSBzaG91bGQgY29uc2lkZXIgd2hlbiBjaG9vc2luZyB0aGUgbW9kZWwuIFdoZXRoZXIgb3Igbm90IHRoZSBwcmVkaWN0aW9ucyB0aGVtc2VsdmVzIHNlZW0gcmVhbGlzdGljIGdpdmVuIHRoZSBzY2VuYXJpby9jaXJjdW1zdGFuY2VzLg0KDQpUbyBiYWNrIHVwIHdoYXQgSSdtIHNheWluZywgQmFyb24gTmFzaG9yIHNwYXducyBhdCAyMCBtaW51dGVzIGFuZCByZXNwYXducyBldmVyeSA2IG1pbnV0ZXMuIFNpbmNlIDMgQmFyb25zIGFyZSBraWxsZWQgaW4gYm90aCBzY2VuYXJpb3MsIHRoZSBnYW1lIHdvdWxkIGhhdmUgdG8gYmUgYXQgbGVhc3QgMzggbWludXRlcyBhbmQgb25seSBpZiB0aGUgdGVhbXMga2lsbCB0aGUgQmFyb24gSU1NRURJQVRFTFkgKHdoaWNoIGlzIHVzdWFsbHkgbmV2ZXIgdGhlIGNhc2UpLiBUaGVyZWZvcmUsIG9uZSB3b3VsZCBleHBlY3QgbWFqb3JpdHkgb2YgdGhlIGFyZWEgdG8gbGllIHdpdGhpbiB0aGUgXH40MCBtaW51dGUgcmFuZ2UgYXQgdGhlIHZlcnkgbGVhc3QgZm9yIHdoZW4gdGhlIGdhbWUgd291bGQgZW5kLg0KDQojIyBDb25jbHVzaW9uDQoNCkluIGNvbmNsdXNpb24sIGl0IGlzIGEgY2hvaWNlIGJldHdlZW4gd2hldGhlciBvbmUgd2FudHMgdG8gdGFrZSB0aGUgY2hhbmNlIG9mIHBsYXlpbmcgd2l0aCBhIG1vZGVsIHRoYXQgbWF5IGJlIHN1c2NlcHRpYmxlIHRvIG92ZXJmaXR0aW5nIGZvciB0aGUgc2FrZSBvZiBwb3RlbnRpYWxseSBsZXNzIGVycm9yIG9yIGEgc2xpZ2h0bHkgaGlnaGVyIGVycm9yIG1vZGVsIHRoYXQgaGFzIGludGVyYWN0aW9ucyBidXQgd291bGQgYmUgbGVzcyBsaWtlbHkgdG8gYmUgc3VzY2VwdGlibGUgdG8gb3ZlcmZpdHRpbmcuDQoNClBlcnNvbmFsbHksIEkgc2F5IHRoYXQgdGhlIHJlZmluZWQgaW50ZXJhY3Rpb24gbW9kZWwgaXMgdGhlIGJlc3QgbW9kZWwgdG8gdXNlIGZvciBwcmVkaWN0aW5nIHRoZSBnYW1lIGR1cmF0aW9uIG9mIGEgTE9MIG1hdGNoIGdpdmVuIG91ciBkYXRhIGR1ZSB0byBpdHMgY29tcGFyYWJsZSBNQUUgYWxvbmcgd2l0aCBiZXR0ZXIgcG9zdGVyaW9yIHByZWRpY3RpdmUgYWJpbGl0aWVzIGFuZCBsYWNrIG9mIGV2aWRlbmNlIGZvciBvdmVyZml0dGluZy4gRnVydGhlcm1vcmUsIGJhc2VkIG9uIG15IGV4cGVyaWVuY2UgYW5kIGdhbWUgcnVsZXMsIHRoZSBwcmVkaWN0aXZlIHZhbHVlcyBpdCBjb21lcyB1cCB3aXRoIGVuZCB1cCBiZWluZyBtdWNoIG1vcmUgcmVhbGlzdGljIGluIHRoZSBncmFuZCBzY2hlbWUgb2YgdGhpbmdzIGFuZCB3aXRoIG90aGVyIGZhY3RvcnMgc3VjaCBhcyByZXNwYXduIHRpbWUgY29uc2lkZXJlZC4NCg0KIyMgUmVmZXJlbmNlcw0KDQotICAgPGh0dHBzOi8vd3d3LmJheWVzcnVsZXNib29rLmNvbS8+DQoNCi0gICA8aHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMjk2MDU5L2VmZmVjdGl2ZS1zYW1wbGUtc2l6ZS1ncmVhdGVyLXRoYW4tYWN0dWFsLXNhbXBsZS1zaXplPg0KDQotICAgPGh0dHBzOi8vc3RlcGhlbmFsbHdyaWdodC5jb20vZ29vZC1tYWUtc2NvcmUvPg0KDQotICAgPGh0dHBzOi8vZGlzY291cnNlLm1jLXN0YW4ub3JnL3QvdW5kZXJzdGFuZGluZy1sb29pYy8xMzQwOS82Pg0KDQotICAgPGh0dHBzOi8vZGlzY291cnNlLm1jLXN0YW4ub3JnL3QvcHJvanByZWQtZWxwZC1nb2VzLWRvd24tYW5kLXJtc2UtZ29lcy11cC1hZnRlci14LXZhcmlhYmxlcy8xMzE1Mz4NCg0KLSAgIDxodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8zMTM1NjQvaG93LWRvZXMtYmF5ZXNpYW4tYW5hbHlzaXMtbWFrZS1hY2N1cmF0ZS1wcmVkaWN0aW9ucy11c2luZy1zdWJqZWN0aXZlbHktY2hvc2VuLXA+DQoNCi0gICBbaHR0cHM6Ly9tZWRpdW0uY29tL1xAb29lbW1hODMvaW50ZXJwcmV0YXRpb24tb2YtZXZhbHVhdGlvbi1tZXRyaWNzLWZvci1yZWdyZXNzaW9uLWFuYWx5c2lzLW1hZS1tc2Utcm1zZS1tYXBlLXItc3F1YXJlZC1hbmQtNTY5M2I2MWE5ODMzXShodHRwczovL21lZGl1bS5jb20vQG9vZW1tYTgzL2ludGVycHJldGF0aW9uLW9mLWV2YWx1YXRpb24tbWV0cmljcy1mb3ItcmVncmVzc2lvbi1hbmFseXNpcy1tYWUtbXNlLXJtc2UtbWFwZS1yLXNxdWFyZWQtYW5kLTU2OTNiNjFhOTgzMyl7LnVyaX0NCg0KLSAgIDxodHRwczovL3N0YXRpc3RpY3NieWppbS5jb20vcmVncmVzc2lvbi9vdmVyZml0dGluZy1yZWdyZXNzaW9uLW1vZGVscy8+DQoNCi0gICA8aHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvOTA1My9ob3ctZG9lcy1jcm9zcy12YWxpZGF0aW9uLW92ZXJjb21lLXRoZS1vdmVyZml0dGluZy1wcm9ibGVtPg0KDQojIyBIb25vciBQbGVkZ2UNCg0KT24gbXkgaG9ub3IsIEkgaGF2ZSBuZWl0aGVyIHJlY2VpdmVkIG5vciBnaXZlbiBhbnkgdW5hdXRob3JpemVkIGFzc2lzdGFuY2Ugb24gdGhpcyBwcm9qZWN0DQoNClNpZ25lZDogVGhvbWFzIENocmlzdG8gKHRqYzI2MCkNCg==