This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Week 8 Data Dive

library(tidyverse)
library(ggplot2)
library(dplyr)
library(tidyverse)
library(ggthemes)
library(ggrepel)
library(effsize)
library(pwrss)
library(tidyverse)
library(ggthemes)
library(ggrepel)
library(AmesHousing)
library(boot)
library(broom)
library(lindia)

# remove scientific notation
options(scipen = 6)

# default theme, unless otherwise noted
theme_set(theme_minimal())

df<- read_delim("/Users/matthewjobe/Downloads/quasi_winshares.csv", delim = ",")
Rows: 98796 Columns: 16── Column specification ───────────────────────────────────
Delimiter: ","
chr (8): name_common, player_ID, team_ID, lg_ID, def_po...
dbl (8): age, year_ID, pct_PT, WAR162, quasi_ws, stint_...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
library(dplyr) #Changing all instances where a player has multiple positions, to "UTL"
library(stringr) #UTL stands for utility player




df |>
  filter(year_ID>2004 & year_ID<2019)|>
  mutate(def_pos = ifelse(str_detect(def_pos, ","), "UTL", def_pos))|>
  group_by(def_pos)|> #Grouping based on defensive position
  summarize(count1=n(),#count of player by year
  mean(WAR162))
df
df <- df |> 
  mutate(def_pos = ifelse(str_detect(def_pos, ","), "UTL", def_pos))

# Check if changes were applied
df |> filter(def_pos == "UTL") |> head()
NA

The two columns I will be looking at this week are the “WAR162” and “def_pos” columns. WAR162 stand Wins Above Replacement per 162 team games. The def-pos column represents what position they player plays. Because some players have multiple positions, I changed the pertaining values to “UTL” (utility player).

WAR162 is the response variable and def_pos is the explanatory variable. I am interested in whether the position played has any effect on WAR162.

Null hypothesis: Average WAR162 is equal across all positions.

df <- df |> drop_na() #getting ride of rows with missing values
df_new <- df |> filter(year_ID > 2004)
df_new |>
  filter(year_ID>2004 )|>
  ggplot() +
  geom_boxplot(mapping = aes(y = WAR162, x = def_pos)) +
  #scale_y_log10(labels = \(x) paste('$', x / 1000, 'K')) +
  annotation_logticks(sides = 'l') +
  labs(x = "Position",
       y = "WAR162")

Above, we can see that some positions typically have higher WAR162 statistics that others. I want to know if the differences are significant enough to challenge the hypothesis that they are all equal.

df_new |> ggplot(aes(x = WAR162)) + 
  geom_histogram(bins = 40, fill = "blue", alpha = 0.5) +
  labs(title = "Histogram of WAR162")

The histogram above shows a WAR162 distribution. It seems be centered at 0, and have a slight right skew. This means most players contribute a neutral value to their ream, and there are more players with very high WAR162 stats than low ones.

m <- aov(WAR162 ~ def_pos, data = df_new)
summary(m)
               Df Sum Sq Mean Sq F value Pr(>F)    
def_pos         9   2822  313.60   159.1 <2e-16 ***
Residuals   21277  41927    1.97                   
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

With the above code we get a very small p-value of essentially zero, which indicates that is unlikely that all of the mean WAR162’s by position are the same and at least one is different.

Because the p-value is so small I reject the null hypothesis that average WAR162 is equal across all positions. This suggests that one or more position has significantly different WAR162 compared to other.

This is interesting as defensive position is associated with their WAR162 statistics. When constructing a team, certain positions may have less value than others. It also ties into salary, as teams may be willing to pay more for a “premium position”.

pairwise.t.test(df_new$WAR162, df_new$def_pos, p.adjust.method = "bonferroni")

    Pairwise comparisons using t tests with pooled SD 

data:  df_new$WAR162 and df_new$def_pos 

    1B      2B      3B      C       CF      LF     
2B  2.7e-05 -       -       -       -       -      
3B  1.8e-14 0.14524 -       -       -       -      
C   < 2e-16 < 2e-16 < 2e-16 -       -       -      
CF  < 2e-16 0.00065 1.00000 < 2e-16 -       -      
LF  1.00000 3.9e-05 1.2e-12 3.8e-11 < 2e-16 -      
P   < 2e-16 < 2e-16 < 2e-16 0.07561 < 2e-16 1.7e-08
RF  0.02550 1.00000 0.01222 < 2e-16 3.8e-05 0.01178
SS  6.6e-16 0.19170 1.00000 < 2e-16 1.00000 2.6e-13
UTL < 2e-16 < 2e-16 < 2e-16 0.00358 < 2e-16 5.9e-07
    P       RF      SS     
2B  -       -       -      
3B  -       -       -      
C   -       -       -      
CF  -       -       -      
LF  -       -       -      
P   -       -       -      
RF  < 2e-16 -       -      
SS  < 2e-16 0.01509 -      
UTL 1.00000 < 2e-16 < 2e-16

P value adjustment method: bonferroni 

Above, a multiple pairwise t-tests to compares each grouping of row and column. It tells us that there are definitely some significant differences such as:

  1. Catcher is significantly different from every other position.

  2. Pitcher is significantly different from all roles except “utility” players and catchers.

  3. Utility players are significantly different from all roles except pitcher.

  4. Left Field is significantly different from all positions except First Base

  5. First Base is significantly different from all positions except Left Field

# we use a "_" so we don't overwrite the original function
boot_ci <- function (v, func = median, conf = 0.95, n_iter = 100) {
  # the function we want to run on each iteration i
  boot_func <- \(x, i) func(x[i])
  
  # the boot instance, running the function on each iteration
  b <- boot(v, boot_func, R = n_iter)
  b <- boot.ci(b, conf = conf, type = "perc")
  
  # return just the lower and upper values
  return(c("lower" = b$percent[4],
           "upper" = b$percent[5]))
}
df_ci <- df_new |>
  group_by(def_pos) |>
  summarise(ci_lower = boot_ci(WAR162, mean)['lower'],
            mean_war = mean(WAR162),
            ci_upper = boot_ci(WAR162, mean)['upper'])

df_ci
df_ci |>
  ggplot() +
  geom_errorbarh(mapping = aes(y = def_pos, 
                               xmin=ci_lower, xmax=ci_upper,
                               color = '95% C.I.'), height = 0.5) +
  geom_point(mapping = aes(x = mean_war, y = def_pos,
                           color = 'Group Mean'),
             shape = '|',
             size = 5) +
  scale_color_manual(values=c('black', 'orange')) +
  labs(title = "WAR162 By Defensive Position",
       x = "WAR162",
       y = "Defensive Position",
       color = '')

The visual above shows us the WAR162’s by position. It makes it much easier to spot some of the differences in WAR162 by position. The visualization supports the statements above:

  1. Catcher is significantly different from every other position.

  2. Pitcher is significantly different from all roles except “utility” players and catchers.

  3. Utility players are significantly different from all roles except pitcher.

  4. Left Field is significantly different from all positions except First Base

  5. First Base is significantly different from all positions except Left Field

LINEAR REGRESSION

Next I will build a linear regression model for the variables share of playing time and “WAR162”. This will estimate a relationship between the two variables, showing how much WAR162 changes with playing time.

df_new |>  
  ggplot(mapping = aes(x = pct_PT, y = WAR162)) +  
  geom_point(size = 2) +  
  geom_smooth(method = "lm", se = FALSE, color = 'darkblue') +  
  labs(title = "Linear Relationship Between Playing Time and WAR162",  
       x = "Percent of Playing Time",  
       y = "WAR162") +  
  theme_minimal()

model <- lm(WAR162 ~ pct_PT, data = df_new)
summary(model)

Call:
lm(formula = WAR162 ~ pct_PT, data = df_new)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.2702 -0.4408  0.0741  0.4078  7.9911 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.443377   0.010095  -43.92   <2e-16 ***
pct_PT       0.543718   0.003525  154.26   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.9963 on 21285 degrees of freedom
Multiple R-squared:  0.5279,    Adjusted R-squared:  0.5278 
F-statistic: 2.38e+04 on 1 and 21285 DF,  p-value: < 2.2e-16

There does appear to be a linear association between share of playing time and WAR162. There is an estimated slope of 0.544, which means that for every 1 percent point in increase in pct_PT, WAR162 increases by 0.544. The small p-value also shows me that pct_PT (playing time) has a statistically significant relationship with WAR162. Additionally, we can see that Multiple R-Squared value is about 0.53. This means that approximately 53% of the variance in WAR162 is explained by pct_PT.

# the line estimated above
lm_ <- \(x) (1 / 2) * x + 3

df_new |>
  ggplot(mapping = aes(x = pct_PT, y = WAR162)) +
  geom_point(size = 2) +
  geom_segment(mapping = aes(xend = pct_PT, y = WAR162, yend = lm_(WAR162), 
                             color = 'error'), linewidth = 1) +
  geom_smooth(method = "lm", se = FALSE, color = 'red', linewidth = 0.5) + 
  scale_color_manual(values = c('darkblue')) +
  labs(color = '')

There does appear to be quite a bit of error in the visualization above.

beta_0 <- 3
beta_1 <- 1/2

lm_ <- \(x) beta_1 * x + beta_0

df_new |>
  ggplot() +
  geom_point(mapping = aes(x = pct_PT, y = WAR162), size = 2) +
  geom_smooth(mapping = aes(x = pct_PT, y = WAR162), method = "lm", se = FALSE, color = 'red', linewidth = 0.5) + 
  geom_rect(mapping = aes(xmin = pct_PT, 
                          xmax = pct_PT + abs(WAR162 - lm_(pct_PT)),
                          ymin = lm_(pct_PT), 
                          ymax = WAR162), 
            fill = NA, color = 'darkblue') +
  labs(color = '')

There are so many data points which makes it very hard to understand the two visualizations above.

model <- lm(WAR162 ~ pct_PT, df_new)
model$coefficients
(Intercept)      pct_PT 
 -0.4433769   0.5437183 

From this output, we see that the expected WAR162, when the share of playing time is zero, is -0.44. For every 1 percent point in increase in pct_PT, WAR162 increases by 0.544.

I believe this is a good fit because the slope of 0.544 indicates a meaning relationship. Additionally, there was a very small p-value which shows that the predictor (pct_PT) is statistically significant.

However, the multiple R-squared value of 0.53 tells us that pct_PT explains 53% of the variance in WAR162. This leaves the rest of the variance unexplained, and there could be other factors influencing WAR162.

I think that using multiple explanatory variables would have be an optimal way of building this model. Other factors such as team and age could also influence WAR162. Originally I was going to look at the relationship with age and WAR162, but it was not linear. As players get older, their WAR162 stats start to become lower.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4KCiMjIFdlZWsgOCBEYXRhIERpdmUKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGVmZnNpemUpCmxpYnJhcnkocHdyc3MpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoQW1lc0hvdXNpbmcpCmxpYnJhcnkoYm9vdCkKbGlicmFyeShicm9vbSkKbGlicmFyeShsaW5kaWEpCgojIHJlbW92ZSBzY2llbnRpZmljIG5vdGF0aW9uCm9wdGlvbnMoc2NpcGVuID0gNikKCiMgZGVmYXVsdCB0aGVtZSwgdW5sZXNzIG90aGVyd2lzZSBub3RlZAp0aGVtZV9zZXQodGhlbWVfbWluaW1hbCgpKQoKZGY8LSByZWFkX2RlbGltKCIvVXNlcnMvbWF0dGhld2pvYmUvRG93bmxvYWRzL3F1YXNpX3dpbnNoYXJlcy5jc3YiLCBkZWxpbSA9ICIsIikKYGBgCgpgYGB7cn0KbGlicmFyeShkcGx5cikgI0NoYW5naW5nIGFsbCBpbnN0YW5jZXMgd2hlcmUgYSBwbGF5ZXIgaGFzIG11bHRpcGxlIHBvc2l0aW9ucywgdG8gIlVUTCIKbGlicmFyeShzdHJpbmdyKSAjVVRMIHN0YW5kcyBmb3IgdXRpbGl0eSBwbGF5ZXIKCgoKCmRmIHw+CiAgZmlsdGVyKHllYXJfSUQ+MjAwNCAmIHllYXJfSUQ8MjAxOSl8PgogIG11dGF0ZShkZWZfcG9zID0gaWZlbHNlKHN0cl9kZXRlY3QoZGVmX3BvcywgIiwiKSwgIlVUTCIsIGRlZl9wb3MpKXw+CiAgZ3JvdXBfYnkoZGVmX3Bvcyl8PiAjR3JvdXBpbmcgYmFzZWQgb24gZGVmZW5zaXZlIHBvc2l0aW9uCiAgc3VtbWFyaXplKGNvdW50MT1uKCksI2NvdW50IG9mIHBsYXllciBieSB5ZWFyCiAgbWVhbihXQVIxNjIpKQpkZgpgYGAKCmBgYHtyfQpkZiA8LSBkZiB8PiAKICBtdXRhdGUoZGVmX3BvcyA9IGlmZWxzZShzdHJfZGV0ZWN0KGRlZl9wb3MsICIsIiksICJVVEwiLCBkZWZfcG9zKSkKCiMgQ2hlY2sgaWYgY2hhbmdlcyB3ZXJlIGFwcGxpZWQKZGYgfD4gZmlsdGVyKGRlZl9wb3MgPT0gIlVUTCIpIHw+IGhlYWQoKQoKYGBgCgpUaGUgdHdvIGNvbHVtbnMgSSB3aWxsIGJlIGxvb2tpbmcgYXQgdGhpcyB3ZWVrIGFyZSB0aGUgIldBUjE2MiIgYW5kICJkZWZfcG9zIiBjb2x1bW5zLiBXQVIxNjIgc3RhbmQgV2lucyBBYm92ZSBSZXBsYWNlbWVudCBwZXIgMTYyIHRlYW0gZ2FtZXMuIFRoZSBkZWYtcG9zIGNvbHVtbiByZXByZXNlbnRzIHdoYXQgcG9zaXRpb24gdGhleSBwbGF5ZXIgcGxheXMuIEJlY2F1c2Ugc29tZSBwbGF5ZXJzIGhhdmUgbXVsdGlwbGUgcG9zaXRpb25zLCBJIGNoYW5nZWQgdGhlIHBlcnRhaW5pbmcgdmFsdWVzIHRvICJVVEwiICh1dGlsaXR5IHBsYXllcikuCgpXQVIxNjIgaXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIGFuZCBkZWZfcG9zIGlzIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZS4gSSBhbSBpbnRlcmVzdGVkIGluIHdoZXRoZXIgdGhlIHBvc2l0aW9uIHBsYXllZCBoYXMgYW55IGVmZmVjdCBvbiBXQVIxNjIuCgpOdWxsIGh5cG90aGVzaXM6IEF2ZXJhZ2UgV0FSMTYyIGlzIGVxdWFsIGFjcm9zcyBhbGwgcG9zaXRpb25zLgoKYGBge3J9CmRmIDwtIGRmIHw+IGRyb3BfbmEoKSAjZ2V0dGluZyByaWRlIG9mIHJvd3Mgd2l0aCBtaXNzaW5nIHZhbHVlcwpkZl9uZXcgPC0gZGYgfD4gZmlsdGVyKHllYXJfSUQgPiAyMDA0KQoKYGBgCgpgYGB7cn0KZGZfbmV3IHw+CiAgZmlsdGVyKHllYXJfSUQ+MjAwNCApfD4KICBnZ3Bsb3QoKSArCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoeSA9IFdBUjE2MiwgeCA9IGRlZl9wb3MpKSArCiAgI3NjYWxlX3lfbG9nMTAobGFiZWxzID0gXCh4KSBwYXN0ZSgnJCcsIHggLyAxMDAwLCAnSycpKSArCiAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzaWRlcyA9ICdsJykgKwogIGxhYnMoeCA9ICJQb3NpdGlvbiIsCiAgICAgICB5ID0gIldBUjE2MiIpCmBgYAoKQWJvdmUsIHdlIGNhbiBzZWUgdGhhdCBzb21lIHBvc2l0aW9ucyB0eXBpY2FsbHkgaGF2ZSBoaWdoZXIgV0FSMTYyIHN0YXRpc3RpY3MgdGhhdCBvdGhlcnMuIEkgd2FudCB0byBrbm93IGlmIHRoZSBkaWZmZXJlbmNlcyBhcmUgc2lnbmlmaWNhbnQgZW5vdWdoIHRvIGNoYWxsZW5nZSB0aGUgaHlwb3RoZXNpcyB0aGF0IHRoZXkgYXJlIGFsbCBlcXVhbC4KCmBgYHtyfQpkZl9uZXcgfD4gZ2dwbG90KGFlcyh4ID0gV0FSMTYyKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNDAsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgV0FSMTYyIikKYGBgCgpUaGUgaGlzdG9ncmFtIGFib3ZlIHNob3dzIGEgV0FSMTYyIGRpc3RyaWJ1dGlvbi4gSXQgc2VlbXMgYmUgY2VudGVyZWQgYXQgMCwgYW5kIGhhdmUgYSBzbGlnaHQgcmlnaHQgc2tldy4gVGhpcyBtZWFucyBtb3N0IHBsYXllcnMgY29udHJpYnV0ZSBhIG5ldXRyYWwgdmFsdWUgdG8gdGhlaXIgcmVhbSwgYW5kIHRoZXJlIGFyZSBtb3JlIHBsYXllcnMgd2l0aCB2ZXJ5IGhpZ2ggV0FSMTYyIHN0YXRzIHRoYW4gbG93IG9uZXMuCgpgYGB7cn0KbSA8LSBhb3YoV0FSMTYyIH4gZGVmX3BvcywgZGF0YSA9IGRmX25ldykKc3VtbWFyeShtKQpgYGAKCldpdGggdGhlIGFib3ZlIGNvZGUgd2UgZ2V0IGEgdmVyeSBzbWFsbCBwLXZhbHVlIG9mIGVzc2VudGlhbGx5IHplcm8sIHdoaWNoIGluZGljYXRlcyB0aGF0IGlzIHVubGlrZWx5IHRoYXQgYWxsIG9mIHRoZSBtZWFuIFdBUjE2MidzIGJ5IHBvc2l0aW9uIGFyZSB0aGUgc2FtZSBhbmQgYXQgbGVhc3Qgb25lIGlzIGRpZmZlcmVudC4KCkJlY2F1c2UgdGhlIHAtdmFsdWUgaXMgc28gc21hbGwgSSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IGF2ZXJhZ2UgV0FSMTYyIGlzIGVxdWFsIGFjcm9zcyBhbGwgcG9zaXRpb25zLiBUaGlzIHN1Z2dlc3RzIHRoYXQgb25lIG9yIG1vcmUgcG9zaXRpb24gaGFzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IFdBUjE2MiBjb21wYXJlZCB0byBvdGhlci4KClRoaXMgaXMgaW50ZXJlc3RpbmcgYXMgZGVmZW5zaXZlIHBvc2l0aW9uIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGVpciBXQVIxNjIgc3RhdGlzdGljcy4gV2hlbiBjb25zdHJ1Y3RpbmcgYSB0ZWFtLCBjZXJ0YWluIHBvc2l0aW9ucyBtYXkgaGF2ZSBsZXNzIHZhbHVlIHRoYW4gb3RoZXJzLiBJdCBhbHNvIHRpZXMgaW50byBzYWxhcnksIGFzIHRlYW1zIG1heSBiZSB3aWxsaW5nIHRvIHBheSBtb3JlIGZvciBhICJwcmVtaXVtIHBvc2l0aW9uIi4KCmBgYHtyfQpwYWlyd2lzZS50LnRlc3QoZGZfbmV3JFdBUjE2MiwgZGZfbmV3JGRlZl9wb3MsIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIikKYGBgCgpBYm92ZSwgYSBtdWx0aXBsZSBwYWlyd2lzZSB0LXRlc3RzIHRvIGNvbXBhcmVzIGVhY2ggZ3JvdXBpbmcgb2Ygcm93IGFuZCBjb2x1bW4uIEl0IHRlbGxzIHVzIHRoYXQgdGhlcmUgYXJlIGRlZmluaXRlbHkgc29tZSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBzdWNoIGFzOgoKMSkgIENhdGNoZXIgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBldmVyeSBvdGhlciBwb3NpdGlvbi4KCjIpICBQaXRjaGVyIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYWxsIHJvbGVzIGV4Y2VwdCAidXRpbGl0eSIgcGxheWVycyBhbmQgY2F0Y2hlcnMuCgozKSAgVXRpbGl0eSBwbGF5ZXJzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGFsbCByb2xlcyBleGNlcHQgcGl0Y2hlci4KCjQpICBMZWZ0IEZpZWxkIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYWxsIHBvc2l0aW9ucyBleGNlcHQgRmlyc3QgQmFzZQoKNSkgIEZpcnN0IEJhc2UgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBhbGwgcG9zaXRpb25zIGV4Y2VwdCBMZWZ0IEZpZWxkCgpgYGB7cn0KIyB3ZSB1c2UgYSAiXyIgc28gd2UgZG9uJ3Qgb3ZlcndyaXRlIHRoZSBvcmlnaW5hbCBmdW5jdGlvbgpib290X2NpIDwtIGZ1bmN0aW9uICh2LCBmdW5jID0gbWVkaWFuLCBjb25mID0gMC45NSwgbl9pdGVyID0gMTAwKSB7CiAgIyB0aGUgZnVuY3Rpb24gd2Ugd2FudCB0byBydW4gb24gZWFjaCBpdGVyYXRpb24gaQogIGJvb3RfZnVuYyA8LSBcKHgsIGkpIGZ1bmMoeFtpXSkKICAKICAjIHRoZSBib290IGluc3RhbmNlLCBydW5uaW5nIHRoZSBmdW5jdGlvbiBvbiBlYWNoIGl0ZXJhdGlvbgogIGIgPC0gYm9vdCh2LCBib290X2Z1bmMsIFIgPSBuX2l0ZXIpCiAgYiA8LSBib290LmNpKGIsIGNvbmYgPSBjb25mLCB0eXBlID0gInBlcmMiKQogIAogICMgcmV0dXJuIGp1c3QgdGhlIGxvd2VyIGFuZCB1cHBlciB2YWx1ZXMKICByZXR1cm4oYygibG93ZXIiID0gYiRwZXJjZW50WzRdLAogICAgICAgICAgICJ1cHBlciIgPSBiJHBlcmNlbnRbNV0pKQp9CmBgYAoKYGBge3J9CmRmX2NpIDwtIGRmX25ldyB8PgogIGdyb3VwX2J5KGRlZl9wb3MpIHw+CiAgc3VtbWFyaXNlKGNpX2xvd2VyID0gYm9vdF9jaShXQVIxNjIsIG1lYW4pWydsb3dlciddLAogICAgICAgICAgICBtZWFuX3dhciA9IG1lYW4oV0FSMTYyKSwKICAgICAgICAgICAgY2lfdXBwZXIgPSBib290X2NpKFdBUjE2MiwgbWVhbilbJ3VwcGVyJ10pCgpkZl9jaQpgYGAKCmBgYHtyfQpkZl9jaSB8PgogIGdncGxvdCgpICsKICBnZW9tX2Vycm9yYmFyaChtYXBwaW5nID0gYWVzKHkgPSBkZWZfcG9zLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhtaW49Y2lfbG93ZXIsIHhtYXg9Y2lfdXBwZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICc5NSUgQy5JLicpLCBoZWlnaHQgPSAwLjUpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IG1lYW5fd2FyLCB5ID0gZGVmX3BvcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAnR3JvdXAgTWVhbicpLAogICAgICAgICAgICAgc2hhcGUgPSAnfCcsCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnYmxhY2snLCAnb3JhbmdlJykpICsKICBsYWJzKHRpdGxlID0gIldBUjE2MiBCeSBEZWZlbnNpdmUgUG9zaXRpb24iLAogICAgICAgeCA9ICJXQVIxNjIiLAogICAgICAgeSA9ICJEZWZlbnNpdmUgUG9zaXRpb24iLAogICAgICAgY29sb3IgPSAnJykKYGBgCgpUaGUgdmlzdWFsIGFib3ZlIHNob3dzIHVzIHRoZSBXQVIxNjIncyBieSBwb3NpdGlvbi4gSXQgbWFrZXMgaXQgbXVjaCBlYXNpZXIgdG8gc3BvdCBzb21lIG9mIHRoZSBkaWZmZXJlbmNlcyBpbiBXQVIxNjIgYnkgcG9zaXRpb24uIFRoZSB2aXN1YWxpemF0aW9uIHN1cHBvcnRzIHRoZSBzdGF0ZW1lbnRzIGFib3ZlOgoKMSkgIENhdGNoZXIgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBldmVyeSBvdGhlciBwb3NpdGlvbi4KCjIpICBQaXRjaGVyIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYWxsIHJvbGVzIGV4Y2VwdCAidXRpbGl0eSIgcGxheWVycyBhbmQgY2F0Y2hlcnMuCgozKSAgVXRpbGl0eSBwbGF5ZXJzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGFsbCByb2xlcyBleGNlcHQgcGl0Y2hlci4KCjQpICBMZWZ0IEZpZWxkIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYWxsIHBvc2l0aW9ucyBleGNlcHQgRmlyc3QgQmFzZQoKNSkgIEZpcnN0IEJhc2UgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBhbGwgcG9zaXRpb25zIGV4Y2VwdCBMZWZ0IEZpZWxkCgojIyBMSU5FQVIgUkVHUkVTU0lPTgoKTmV4dCBJIHdpbGwgYnVpbGQgYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIHZhcmlhYmxlcyBzaGFyZSBvZiBwbGF5aW5nIHRpbWUgYW5kICJXQVIxNjIiLiBUaGlzIHdpbGwgZXN0aW1hdGUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcywgc2hvd2luZyBob3cgbXVjaCBXQVIxNjIgY2hhbmdlcyB3aXRoIHBsYXlpbmcgdGltZS4KCmBgYHtyfQpkZl9uZXcgfD4gIAogIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBwY3RfUFQsIHkgPSBXQVIxNjIpKSArICAKICBnZW9tX3BvaW50KHNpemUgPSAyKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICdkYXJrYmx1ZScpICsgIAogIGxhYnModGl0bGUgPSAiTGluZWFyIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIFBsYXlpbmcgVGltZSBhbmQgV0FSMTYyIiwgIAogICAgICAgeCA9ICJQZXJjZW50IG9mIFBsYXlpbmcgVGltZSIsICAKICAgICAgIHkgPSAiV0FSMTYyIikgKyAgCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9Cm1vZGVsIDwtIGxtKFdBUjE2MiB+IHBjdF9QVCwgZGF0YSA9IGRmX25ldykKc3VtbWFyeShtb2RlbCkKYGBgCgpUaGVyZSBkb2VzIGFwcGVhciB0byBiZSBhIGxpbmVhciBhc3NvY2lhdGlvbiBiZXR3ZWVuIHNoYXJlIG9mIHBsYXlpbmcgdGltZSBhbmQgV0FSMTYyLiBUaGVyZSBpcyBhbiBlc3RpbWF0ZWQgc2xvcGUgb2YgMC41NDQsIHdoaWNoIG1lYW5zIHRoYXQgZm9yIGV2ZXJ5IDEgcGVyY2VudCBwb2ludCBpbiBpbmNyZWFzZSBpbiBwY3RfUFQsIFdBUjE2MiBpbmNyZWFzZXMgYnkgMC41NDQuIFRoZSBzbWFsbCBwLXZhbHVlIGFsc28gc2hvd3MgbWUgdGhhdCBwY3RfUFQgKHBsYXlpbmcgdGltZSkgaGFzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgd2l0aCBXQVIxNjIuIEFkZGl0aW9uYWxseSwgd2UgY2FuIHNlZSB0aGF0IE11bHRpcGxlIFItU3F1YXJlZCB2YWx1ZSBpcyBhYm91dCAwLjUzLiBUaGlzIG1lYW5zIHRoYXQgYXBwcm94aW1hdGVseSA1MyUgb2YgdGhlIHZhcmlhbmNlIGluIFdBUjE2MiBpcyBleHBsYWluZWQgYnkgcGN0X1BULgoKYGBge3J9CiMgdGhlIGxpbmUgZXN0aW1hdGVkIGFib3ZlCmxtXyA8LSBcKHgpICgxIC8gMikgKiB4ICsgMwoKZGZfbmV3IHw+CiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IHBjdF9QVCwgeSA9IFdBUjE2MikpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgZ2VvbV9zZWdtZW50KG1hcHBpbmcgPSBhZXMoeGVuZCA9IHBjdF9QVCwgeSA9IFdBUjE2MiwgeWVuZCA9IGxtXyhXQVIxNjIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICdlcnJvcicpLCBsaW5ld2lkdGggPSAxKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAncmVkJywgbGluZXdpZHRoID0gMC41KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCdkYXJrYmx1ZScpKSArCiAgbGFicyhjb2xvciA9ICcnKQpgYGAKClRoZXJlIGRvZXMgYXBwZWFyIHRvIGJlIHF1aXRlIGEgYml0IG9mIGVycm9yIGluIHRoZSB2aXN1YWxpemF0aW9uIGFib3ZlLgoKYGBge3J9CmJldGFfMCA8LSAzCmJldGFfMSA8LSAxLzIKCmxtXyA8LSBcKHgpIGJldGFfMSAqIHggKyBiZXRhXzAKCmRmX25ldyB8PgogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHBjdF9QVCwgeSA9IFdBUjE2MiksIHNpemUgPSAyKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gcGN0X1BULCB5ID0gV0FSMTYyKSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAncmVkJywgbGluZXdpZHRoID0gMC41KSArIAogIGdlb21fcmVjdChtYXBwaW5nID0gYWVzKHhtaW4gPSBwY3RfUFQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHhtYXggPSBwY3RfUFQgKyBhYnMoV0FSMTYyIC0gbG1fKHBjdF9QVCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHltaW4gPSBsbV8ocGN0X1BUKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heCA9IFdBUjE2MiksIAogICAgICAgICAgICBmaWxsID0gTkEsIGNvbG9yID0gJ2RhcmtibHVlJykgKwogIGxhYnMoY29sb3IgPSAnJykKYGBgCgpUaGVyZSBhcmUgc28gbWFueSBkYXRhIHBvaW50cyB3aGljaCBtYWtlcyBpdCB2ZXJ5IGhhcmQgdG8gdW5kZXJzdGFuZCB0aGUgdHdvIHZpc3VhbGl6YXRpb25zIGFib3ZlLgoKYGBge3J9Cm1vZGVsIDwtIGxtKFdBUjE2MiB+IHBjdF9QVCwgZGZfbmV3KQptb2RlbCRjb2VmZmljaWVudHMKYGBgCgpGcm9tIHRoaXMgb3V0cHV0LCB3ZSBzZWUgdGhhdCB0aGUgZXhwZWN0ZWQgV0FSMTYyLCB3aGVuIHRoZSBzaGFyZSBvZiBwbGF5aW5nIHRpbWUgaXMgemVybywgaXMgLTAuNDQuIEZvciBldmVyeSAxIHBlcmNlbnQgcG9pbnQgaW4gaW5jcmVhc2UgaW4gcGN0X1BULCBXQVIxNjIgaW5jcmVhc2VzIGJ5IDAuNTQ0LgoKSSBiZWxpZXZlIHRoaXMgaXMgYSBnb29kIGZpdCBiZWNhdXNlIHRoZSBzbG9wZSBvZiAwLjU0NCBpbmRpY2F0ZXMgYSBtZWFuaW5nIHJlbGF0aW9uc2hpcC4gQWRkaXRpb25hbGx5LCB0aGVyZSB3YXMgYSB2ZXJ5IHNtYWxsIHAtdmFsdWUgd2hpY2ggc2hvd3MgdGhhdCB0aGUgcHJlZGljdG9yIChwY3RfUFQpIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuCgpIb3dldmVyLCB0aGUgbXVsdGlwbGUgUi1zcXVhcmVkIHZhbHVlIG9mIDAuNTMgdGVsbHMgdXMgdGhhdCBwY3RfUFQgZXhwbGFpbnMgNTMlIG9mIHRoZSB2YXJpYW5jZSBpbiBXQVIxNjIuIFRoaXMgbGVhdmVzIHRoZSByZXN0IG9mIHRoZSB2YXJpYW5jZSB1bmV4cGxhaW5lZCwgYW5kIHRoZXJlIGNvdWxkIGJlIG90aGVyIGZhY3RvcnMgaW5mbHVlbmNpbmcgV0FSMTYyLgoKSSB0aGluayB0aGF0IHVzaW5nIG11bHRpcGxlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB3b3VsZCBoYXZlIGJlIGFuIG9wdGltYWwgd2F5IG9mIGJ1aWxkaW5nIHRoaXMgbW9kZWwuIE90aGVyIGZhY3RvcnMgc3VjaCBhcyB0ZWFtIGFuZCBhZ2UgY291bGQgYWxzbyBpbmZsdWVuY2UgV0FSMTYyLiBPcmlnaW5hbGx5IEkgd2FzIGdvaW5nIHRvIGxvb2sgYXQgdGhlIHJlbGF0aW9uc2hpcCB3aXRoIGFnZSBhbmQgV0FSMTYyLCBidXQgaXQgd2FzIG5vdCBsaW5lYXIuIEFzIHBsYXllcnMgZ2V0IG9sZGVyLCB0aGVpciBXQVIxNjIgc3RhdHMgc3RhcnQgdG8gYmVjb21lIGxvd2VyLgo=