Videos 2 and 3 Moneyball

VIDEO 2

# Read in data
baseball = read.csv("baseball.csv")
str(baseball)
'data.frame':   1232 obs. of  15 variables:
 $ Team        : chr  "ARI" "ATL" "BAL" "BOS" ...
 $ League      : chr  "NL" "NL" "AL" "AL" ...
 $ Year        : int  2012 2012 2012 2012 2012 2012 2012 2012 2012 2012 ...
 $ RS          : int  734 700 712 734 613 748 669 667 758 726 ...
 $ RA          : int  688 600 705 806 759 676 588 845 890 670 ...
 $ W           : int  81 94 93 69 61 85 97 68 64 88 ...
 $ OBP         : num  0.328 0.32 0.311 0.315 0.302 0.318 0.315 0.324 0.33 0.335 ...
 $ SLG         : num  0.418 0.389 0.417 0.415 0.378 0.422 0.411 0.381 0.436 0.422 ...
 $ BA          : num  0.259 0.247 0.247 0.26 0.24 0.255 0.251 0.251 0.274 0.268 ...
 $ Playoffs    : int  0 1 1 0 0 0 1 0 0 1 ...
 $ RankSeason  : int  NA 4 5 NA NA NA 2 NA NA 6 ...
 $ RankPlayoffs: int  NA 5 4 NA NA NA 4 NA NA 2 ...
 $ G           : int  162 162 162 162 162 162 162 162 162 162 ...
 $ OOBP        : num  0.317 0.306 0.315 0.331 0.335 0.319 0.305 0.336 0.357 0.314 ...
 $ OSLG        : num  0.415 0.378 0.403 0.428 0.424 0.405 0.39 0.43 0.47 0.402 ...
# Subset to only include moneyball years
moneyball = subset(baseball, Year < 2002)
str(moneyball)
'data.frame':   902 obs. of  15 variables:
 $ Team        : chr  "ANA" "ARI" "ATL" "BAL" ...
 $ League      : chr  "AL" "NL" "NL" "AL" ...
 $ Year        : int  2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 ...
 $ RS          : int  691 818 729 687 772 777 798 735 897 923 ...
 $ RA          : int  730 677 643 829 745 701 795 850 821 906 ...
 $ W           : int  75 92 88 63 82 88 83 66 91 73 ...
 $ OBP         : num  0.327 0.341 0.324 0.319 0.334 0.336 0.334 0.324 0.35 0.354 ...
 $ SLG         : num  0.405 0.442 0.412 0.38 0.439 0.43 0.451 0.419 0.458 0.483 ...
 $ BA          : num  0.261 0.267 0.26 0.248 0.266 0.261 0.268 0.262 0.278 0.292 ...
 $ Playoffs    : int  0 1 1 0 0 0 0 0 1 0 ...
 $ RankSeason  : int  NA 5 7 NA NA NA NA NA 6 NA ...
 $ RankPlayoffs: int  NA 1 3 NA NA NA NA NA 4 NA ...
 $ G           : int  162 162 162 162 161 162 162 162 162 162 ...
 $ OOBP        : num  0.331 0.311 0.314 0.337 0.329 0.321 0.334 0.341 0.341 0.35 ...
 $ OSLG        : num  0.412 0.404 0.384 0.439 0.393 0.398 0.427 0.455 0.417 0.48 ...
# Compute Run Difference
moneyball$RD = moneyball$RS - moneyball$RA
str(moneyball)
'data.frame':   902 obs. of  16 variables:
 $ Team        : chr  "ANA" "ARI" "ATL" "BAL" ...
 $ League      : chr  "AL" "NL" "NL" "AL" ...
 $ Year        : int  2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 ...
 $ RS          : int  691 818 729 687 772 777 798 735 897 923 ...
 $ RA          : int  730 677 643 829 745 701 795 850 821 906 ...
 $ W           : int  75 92 88 63 82 88 83 66 91 73 ...
 $ OBP         : num  0.327 0.341 0.324 0.319 0.334 0.336 0.334 0.324 0.35 0.354 ...
 $ SLG         : num  0.405 0.442 0.412 0.38 0.439 0.43 0.451 0.419 0.458 0.483 ...
 $ BA          : num  0.261 0.267 0.26 0.248 0.266 0.261 0.268 0.262 0.278 0.292 ...
 $ Playoffs    : int  0 1 1 0 0 0 0 0 1 0 ...
 $ RankSeason  : int  NA 5 7 NA NA NA NA NA 6 NA ...
 $ RankPlayoffs: int  NA 1 3 NA NA NA NA NA 4 NA ...
 $ G           : int  162 162 162 162 161 162 162 162 162 162 ...
 $ OOBP        : num  0.331 0.311 0.314 0.337 0.329 0.321 0.334 0.341 0.341 0.35 ...
 $ OSLG        : num  0.412 0.404 0.384 0.439 0.393 0.398 0.427 0.455 0.417 0.48 ...
 $ RD          : int  -39 141 86 -142 27 76 3 -115 76 17 ...
# Scatterplot to check for linear relationship
plot(moneyball$RD, moneyball$W)

# Regression model to predict wins
WinsReg = lm(W ~ RD, data=moneyball)
summary(WinsReg)

Call:
lm(formula = W ~ RD, data = moneyball)

Residuals:
     Min       1Q   Median       3Q      Max 
-14.2662  -2.6509   0.1234   2.9364  11.6570 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 80.881375   0.131157  616.67   <2e-16 ***
RD           0.105766   0.001297   81.55   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.939 on 900 degrees of freedom
Multiple R-squared:  0.8808,    Adjusted R-squared:  0.8807 
F-statistic:  6651 on 1 and 900 DF,  p-value: < 2.2e-16

If a baseball team scores 763 runs and allows 614 runs, how many games do we expect the team to win?

Using the linear regression model constructed during the lecture, enter the number of games we expect the team to win:

763-614
[1] 149
wins=80.88+0.105766*(149)
wins
[1] 96.63913

If a baseball team has an RD of 149, we expect the team would win approximately 97 games.

VIDEO 3

str(moneyball)
'data.frame':   902 obs. of  16 variables:
 $ Team        : chr  "ANA" "ARI" "ATL" "BAL" ...
 $ League      : chr  "AL" "NL" "NL" "AL" ...
 $ Year        : int  2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 ...
 $ RS          : int  691 818 729 687 772 777 798 735 897 923 ...
 $ RA          : int  730 677 643 829 745 701 795 850 821 906 ...
 $ W           : int  75 92 88 63 82 88 83 66 91 73 ...
 $ OBP         : num  0.327 0.341 0.324 0.319 0.334 0.336 0.334 0.324 0.35 0.354 ...
 $ SLG         : num  0.405 0.442 0.412 0.38 0.439 0.43 0.451 0.419 0.458 0.483 ...
 $ BA          : num  0.261 0.267 0.26 0.248 0.266 0.261 0.268 0.262 0.278 0.292 ...
 $ Playoffs    : int  0 1 1 0 0 0 0 0 1 0 ...
 $ RankSeason  : int  NA 5 7 NA NA NA NA NA 6 NA ...
 $ RankPlayoffs: int  NA 1 3 NA NA NA NA NA 4 NA ...
 $ G           : int  162 162 162 162 161 162 162 162 162 162 ...
 $ OOBP        : num  0.331 0.311 0.314 0.337 0.329 0.321 0.334 0.341 0.341 0.35 ...
 $ OSLG        : num  0.412 0.404 0.384 0.439 0.393 0.398 0.427 0.455 0.417 0.48 ...
 $ RD          : int  -39 141 86 -142 27 76 3 -115 76 17 ...
# Regression model to predict runs scored
RunsReg = lm(RS ~ OBP + SLG + BA, data=moneyball)
summary(RunsReg)

Call:
lm(formula = RS ~ OBP + SLG + BA, data = moneyball)

Residuals:
    Min      1Q  Median      3Q     Max 
-70.941 -17.247  -0.621  16.754  90.998 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -788.46      19.70 -40.029  < 2e-16 ***
OBP          2917.42     110.47  26.410  < 2e-16 ***
SLG          1637.93      45.99  35.612  < 2e-16 ***
BA           -368.97     130.58  -2.826  0.00482 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.69 on 898 degrees of freedom
Multiple R-squared:  0.9302,    Adjusted R-squared:   0.93 
F-statistic:  3989 on 3 and 898 DF,  p-value: < 2.2e-16

Exercise 1 If a baseball team’s OBP is 0.361, SLG is 0.409, and BA is 0.257, how many runs do we expect the team to score? Using the linear regression model constructed during the lecture (the one that uses OBP, SLG, and BA as independent variables), find the number of runs we expect the team to score:

RunsScored=-788.46+2917.42*(0.361)+1637.93*(0.409)-368.97*(0.257)
RunsScored
[1] 839.8167

The number of runs we expect the team to score is approximately 840

# Regression model to predict runs allowed
RunsReg = lm(RA ~ OOBP + OSLG, data=moneyball)
summary(RunsReg)

Call:
lm(formula = RA ~ OOBP + OSLG, data = moneyball)

Residuals:
    Min      1Q  Median      3Q     Max 
-82.397 -15.178  -0.129  17.679  60.955 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -837.38      60.26 -13.897  < 2e-16 ***
OOBP         2913.60     291.97   9.979 4.46e-16 ***
OSLG         1514.29     175.43   8.632 2.55e-13 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 25.67 on 87 degrees of freedom
  (812 observations deleted due to missingness)
Multiple R-squared:  0.9073,    Adjusted R-squared:  0.9052 
F-statistic: 425.8 on 2 and 87 DF,  p-value: < 2.2e-16

Exercise 2

If a baseball team’s opponents OBP (OOBP) is 0.267 and opponents SLG (OSLG) is 0.392, how many runs do we expect the team to allow? Using the linear regression model discussed during the lecture (the one on the last slide of the previous video), find the number of runs we expect the team to allow.

RunsScored1=-837.38+2913.60*(0.267)+1514.29*(0.392)
RunsScored1
[1] 534.1529

The number of runs we expect the team to allow is 534

baseball
cor(baseball$RA, baseball$OBP)
[1] 0.3263595
cor(baseball$RA, baseball$SLG)
[1] 0.436527
cor(baseball$RS, baseball$OBP)
[1] 0.9004922
cor(baseball$RS, baseball$SLG)
[1] 0.91874
cor(baseball$RA, baseball$W)
[1] -0.5323938
cor(baseball$RS, baseball$W)
[1] 0.5117447
# Regression model to predict runs allowed
RunsReg = lm(RS ~ OBP + SLG, data=moneyball)
summary(RunsReg)

Call:
lm(formula = RS ~ OBP + SLG, data = moneyball)

Residuals:
    Min      1Q  Median      3Q     Max 
-70.838 -17.174  -1.108  16.770  90.036 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -804.63      18.92  -42.53   <2e-16 ***
OBP          2737.77      90.68   30.19   <2e-16 ***
SLG          1584.91      42.16   37.60   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.79 on 899 degrees of freedom
Multiple R-squared:  0.9296,    Adjusted R-squared:  0.9294 
F-statistic:  5934 on 2 and 899 DF,  p-value: < 2.2e-16

Suppose you are the General Manager of a baseball team, and you are selecting two players for your team. You have a budget of $10,500,000, and you have the choice between the following players:

Player Name OBP SLG Salary
Yandy Diaz 0.403 0.511 $8,000,000
Joey Meneses 0.320 0.366 $723,600
Jose Abreu 0.292 0.358 $19,500,000
Ryan Noda 0.384 0.400 $720,000
Nate Lowe 0.365 0.426 $4,050,000

Given your budget and the player statistics, which two players would you select?

# Create a data frame with player statistics
players <- data.frame(
  name = c("Yandy Diaz", "Joey Meneses", "Jose Abreu", "Ryan Noda", "Nate Lowe"),
  OBP = c(0.403, 0.320, 0.292, 0.384, 0.365),
  SLG = c(0.511, 0.366, 0.358, 0.400, 0.426),
  salary = c(8000000, 723600, 19500000, 720000, 4050000)
)
# Calculate expected runs for each player using the regression model
players$expected_runs <- predict(RunsReg, newdata = players)
# Filter players within budget
players <- players[players$salary <= 10500000, ]
# Calculate all combinations of 2 players
combinations <- combn(nrow(players), 2)
# Initialize variables to store the best combination
max_runs <- 0
best_combination <- NULL
# Loop through each combination
for (i in 1:ncol(combinations)) {
  # Get the indices of the players in this combination
  indices <- combinations[, i]
  
  # Calculate the total salary and expected runs for this combination
  total_salary <- sum(players$salary[indices])
  total_runs <- sum(players$expected_runs[indices])
  
  # If this combination is within budget and has a higher expected runs than the current best, update the best combination
  if (total_salary <= 10500000 && total_runs > max_runs) {
    max_runs <- total_runs
    best_combination <- indices
  }
}
# Print the best combination
best_players <- players[best_combination, ]
print(best_players)
NA

We can see that Yandy Diaz and Ryan Noda are the best picks given our budget and our model predicting Runs Scored from a players on base percentage and slugging percentage. It makes sense that it would that these two players are the recommendation since they fairly have the top sums of OBP and SLG. Noda is particularly Inexpensive of a player.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayAtIE1vbmV5YmFsbCBBY3Rpdml0aWVzIDcsIDgsIDkiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgVmlkZW9zIDIgYW5kIDMgTW9uZXliYWxsCiMjIFZJREVPIDIKCmBgYHtyfQojIFJlYWQgaW4gZGF0YQpiYXNlYmFsbCA9IHJlYWQuY3N2KCJiYXNlYmFsbC5jc3YiKQpzdHIoYmFzZWJhbGwpCmBgYAoKCmBgYHtyfQojIFN1YnNldCB0byBvbmx5IGluY2x1ZGUgbW9uZXliYWxsIHllYXJzCm1vbmV5YmFsbCA9IHN1YnNldChiYXNlYmFsbCwgWWVhciA8IDIwMDIpCnN0cihtb25leWJhbGwpCmBgYAoKYGBge3J9CiMgQ29tcHV0ZSBSdW4gRGlmZmVyZW5jZQptb25leWJhbGwkUkQgPSBtb25leWJhbGwkUlMgLSBtb25leWJhbGwkUkEKc3RyKG1vbmV5YmFsbCkKYGBgCgoKCmBgYHtyfQojIFNjYXR0ZXJwbG90IHRvIGNoZWNrIGZvciBsaW5lYXIgcmVsYXRpb25zaGlwCnBsb3QobW9uZXliYWxsJFJELCBtb25leWJhbGwkVykKCmBgYAoKYGBge3J9CiMgUmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHdpbnMKV2luc1JlZyA9IGxtKFcgfiBSRCwgZGF0YT1tb25leWJhbGwpCnN1bW1hcnkoV2luc1JlZykKYGBgCklmIGEgYmFzZWJhbGwgdGVhbSBzY29yZXMgNzYzIHJ1bnMgYW5kIGFsbG93cyA2MTQgcnVucywgaG93IG1hbnkgZ2FtZXMgZG8gd2UgZXhwZWN0IHRoZSB0ZWFtIHRvIHdpbj8KClVzaW5nIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBjb25zdHJ1Y3RlZCBkdXJpbmcgdGhlIGxlY3R1cmUsIGVudGVyIHRoZSBudW1iZXIgb2YgZ2FtZXMgd2UgZXhwZWN0IHRoZSB0ZWFtIHRvIHdpbjoKCmBgYHtyfQo3NjMtNjE0CmBgYApgYGB7cn0Kd2lucz04MC44OCswLjEwNTc2NiooMTQ5KQp3aW5zCmBgYAoKSWYgYSBiYXNlYmFsbCB0ZWFtIGhhcyBhbiBSRCBvZiAxNDksIHdlIGV4cGVjdCB0aGUgdGVhbSB3b3VsZCB3aW4gYXBwcm94aW1hdGVseSA5NyBnYW1lcy4gCgojIFZJREVPIDMKCmBgYHtyfQpzdHIobW9uZXliYWxsKQoKYGBgCgoKYGBge3J9CiMgUmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHJ1bnMgc2NvcmVkClJ1bnNSZWcgPSBsbShSUyB+IE9CUCArIFNMRyArIEJBLCBkYXRhPW1vbmV5YmFsbCkKc3VtbWFyeShSdW5zUmVnKQpgYGAKCgpFeGVyY2lzZSAxCklmIGEgYmFzZWJhbGwgdGVhbeKAmXMgT0JQIGlzIDAuMzYxLCBTTEcgaXMgMC40MDksIGFuZCBCQSBpcyAwLjI1NywgaG93IG1hbnkgcnVucyBkbyB3ZSBleHBlY3QgdGhlIHRlYW0gdG8gc2NvcmU/ClVzaW5nIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBjb25zdHJ1Y3RlZCBkdXJpbmcgdGhlIGxlY3R1cmUgKHRoZSBvbmUgdGhhdCB1c2VzIE9CUCwgU0xHLCBhbmQgQkEgYXMgaW5kZXBlbmRlbnQgdmFyaWFibGVzKSwgZmluZCB0aGUgbnVtYmVyIG9mIHJ1bnMgd2UgZXhwZWN0IHRoZSB0ZWFtIHRvIHNjb3JlOgoKCmBgYHtyfQpSdW5zU2NvcmVkPS03ODguNDYrMjkxNy40MiooMC4zNjEpKzE2MzcuOTMqKDAuNDA5KS0zNjguOTcqKDAuMjU3KQpSdW5zU2NvcmVkCmBgYAoKIFRoZSBudW1iZXIgb2YgcnVucyB3ZSBleHBlY3QgdGhlIHRlYW0gdG8gc2NvcmUgaXMgYXBwcm94aW1hdGVseSA4NDAKCgoKYGBge3J9CiMgUmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHJ1bnMgYWxsb3dlZApSdW5zUmVnID0gbG0oUkEgfiBPT0JQICsgT1NMRywgZGF0YT1tb25leWJhbGwpCnN1bW1hcnkoUnVuc1JlZykKYGBgCgoKCgogRXhlcmNpc2UgMgoKCklmIGEgYmFzZWJhbGwgdGVhbeKAmXMgb3Bwb25lbnRzIE9CUCAoT09CUCkgaXMgMC4yNjcgYW5kIG9wcG9uZW50cyBTTEcgKE9TTEcpIGlzIDAuMzkyLCBob3cgbWFueSBydW5zIGRvIHdlIGV4cGVjdCB0aGUgdGVhbSB0byBhbGxvdz8KVXNpbmcgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGRpc2N1c3NlZCBkdXJpbmcgdGhlIGxlY3R1cmUgKHRoZSBvbmUgb24gdGhlIGxhc3Qgc2xpZGUgb2YgdGhlIHByZXZpb3VzIHZpZGVvKSwgZmluZCB0aGUgbnVtYmVyIG9mIHJ1bnMgd2UgZXhwZWN0IHRoZSB0ZWFtIHRvIGFsbG93LiAKCgoKYGBge3J9ClJ1bnNTY29yZWQxPS04MzcuMzgrMjkxMy42MCooMC4yNjcpKzE1MTQuMjkqKDAuMzkyKQpSdW5zU2NvcmVkMQpgYGAKVGhlIG51bWJlciBvZiBydW5zIHdlIGV4cGVjdCB0aGUgdGVhbSB0byBhbGxvdyBpcyA1MzQKCmBgYHtyfQpiYXNlYmFsbApgYGAKCmBgYHtyfQpjb3IoYmFzZWJhbGwkUkEsIGJhc2ViYWxsJE9CUCkKY29yKGJhc2ViYWxsJFJBLCBiYXNlYmFsbCRTTEcpCmNvcihiYXNlYmFsbCRSUywgYmFzZWJhbGwkT0JQKQpjb3IoYmFzZWJhbGwkUlMsIGJhc2ViYWxsJFNMRykKY29yKGJhc2ViYWxsJFJBLCBiYXNlYmFsbCRXKQpjb3IoYmFzZWJhbGwkUlMsIGJhc2ViYWxsJFcpCgpgYGAKCmBgYHtyfQojIFJlZ3Jlc3Npb24gbW9kZWwgdG8gcHJlZGljdCBydW5zIGFsbG93ZWQKUnVuc1JlZyA9IGxtKFJTIH4gT0JQICsgU0xHLCBkYXRhPW1vbmV5YmFsbCkKc3VtbWFyeShSdW5zUmVnKQpgYGAKCgoKU3VwcG9zZSB5b3UgYXJlIHRoZSBHZW5lcmFsIE1hbmFnZXIgb2YgYSBiYXNlYmFsbCB0ZWFtLCBhbmQgeW91IGFyZSBzZWxlY3RpbmcgdHdvIHBsYXllcnMgZm9yIHlvdXIgdGVhbS4gWW91IGhhdmUgYSBidWRnZXQgb2YgJDEwLDUwMCwwMDAsIGFuZCB5b3UgaGF2ZSB0aGUgY2hvaWNlIGJldHdlZW4gdGhlIGZvbGxvd2luZyBwbGF5ZXJzOgoKfCBQbGF5ZXIgTmFtZSAgfCBPQlAgICB8IFNMRyAgIHwgU2FsYXJ5ICAgICAgfAp8LS0tLS0tLS0tLS0tLS18LS0tLS0tLXwtLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgWWFuZHkgRGlheiAgIHwgMC40MDMgfCAwLjUxMSB8ICQ4LDAwMCwwMDAgIHwKfCBKb2V5IE1lbmVzZXMgfCAwLjMyMCB8IDAuMzY2IHwgJDcyMyw2MDAgICAgfAp8IEpvc2UgQWJyZXUgICB8IDAuMjkyIHwgMC4zNTggfCAkMTksNTAwLDAwMCB8CnwgUnlhbiBOb2RhICAgIHwgMC4zODQgfCAwLjQwMCB8ICQ3MjAsMDAwICAgIHwKfCBOYXRlIExvd2UgICAgfCAwLjM2NSB8IDAuNDI2IHwgJDQsMDUwLDAwMCAgfAoKR2l2ZW4geW91ciBidWRnZXQgYW5kIHRoZSBwbGF5ZXIgc3RhdGlzdGljcywgd2hpY2ggdHdvIHBsYXllcnMgd291bGQgeW91IHNlbGVjdD8KCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCBwbGF5ZXIgc3RhdGlzdGljcwpwbGF5ZXJzIDwtIGRhdGEuZnJhbWUoCiAgbmFtZSA9IGMoIllhbmR5IERpYXoiLCAiSm9leSBNZW5lc2VzIiwgIkpvc2UgQWJyZXUiLCAiUnlhbiBOb2RhIiwgIk5hdGUgTG93ZSIpLAogIE9CUCA9IGMoMC40MDMsIDAuMzIwLCAwLjI5MiwgMC4zODQsIDAuMzY1KSwKICBTTEcgPSBjKDAuNTExLCAwLjM2NiwgMC4zNTgsIDAuNDAwLCAwLjQyNiksCiAgc2FsYXJ5ID0gYyg4MDAwMDAwLCA3MjM2MDAsIDE5NTAwMDAwLCA3MjAwMDAsIDQwNTAwMDApCikKYGBgCgpgYGB7cn0KIyBDYWxjdWxhdGUgZXhwZWN0ZWQgcnVucyBmb3IgZWFjaCBwbGF5ZXIgdXNpbmcgdGhlIHJlZ3Jlc3Npb24gbW9kZWwKcGxheWVycyRleHBlY3RlZF9ydW5zIDwtIHByZWRpY3QoUnVuc1JlZywgbmV3ZGF0YSA9IHBsYXllcnMpCgpgYGAKCmBgYHtyfQojIEZpbHRlciBwbGF5ZXJzIHdpdGhpbiBidWRnZXQKcGxheWVycyA8LSBwbGF5ZXJzW3BsYXllcnMkc2FsYXJ5IDw9IDEwNTAwMDAwLCBdCgpgYGAKCmBgYHtyfQojIENhbGN1bGF0ZSBhbGwgY29tYmluYXRpb25zIG9mIDIgcGxheWVycwpjb21iaW5hdGlvbnMgPC0gY29tYm4obnJvdyhwbGF5ZXJzKSwgMikKCmBgYAoKCmBgYHtyfQojIEluaXRpYWxpemUgdmFyaWFibGVzIHRvIHN0b3JlIHRoZSBiZXN0IGNvbWJpbmF0aW9uCm1heF9ydW5zIDwtIDAKYmVzdF9jb21iaW5hdGlvbiA8LSBOVUxMCmBgYAoKCmBgYHtyfQojIExvb3AgdGhyb3VnaCBlYWNoIGNvbWJpbmF0aW9uCmZvciAoaSBpbiAxOm5jb2woY29tYmluYXRpb25zKSkgewogICMgR2V0IHRoZSBpbmRpY2VzIG9mIHRoZSBwbGF5ZXJzIGluIHRoaXMgY29tYmluYXRpb24KICBpbmRpY2VzIDwtIGNvbWJpbmF0aW9uc1ssIGldCiAgCiAgIyBDYWxjdWxhdGUgdGhlIHRvdGFsIHNhbGFyeSBhbmQgZXhwZWN0ZWQgcnVucyBmb3IgdGhpcyBjb21iaW5hdGlvbgogIHRvdGFsX3NhbGFyeSA8LSBzdW0ocGxheWVycyRzYWxhcnlbaW5kaWNlc10pCiAgdG90YWxfcnVucyA8LSBzdW0ocGxheWVycyRleHBlY3RlZF9ydW5zW2luZGljZXNdKQogIAogICMgSWYgdGhpcyBjb21iaW5hdGlvbiBpcyB3aXRoaW4gYnVkZ2V0IGFuZCBoYXMgYSBoaWdoZXIgZXhwZWN0ZWQgcnVucyB0aGFuIHRoZSBjdXJyZW50IGJlc3QsIHVwZGF0ZSB0aGUgYmVzdCBjb21iaW5hdGlvbgogIGlmICh0b3RhbF9zYWxhcnkgPD0gMTA1MDAwMDAgJiYgdG90YWxfcnVucyA+IG1heF9ydW5zKSB7CiAgICBtYXhfcnVucyA8LSB0b3RhbF9ydW5zCiAgICBiZXN0X2NvbWJpbmF0aW9uIDwtIGluZGljZXMKICB9Cn0KYGBgCgpgYGB7cn0KIyBQcmludCB0aGUgYmVzdCBjb21iaW5hdGlvbgpiZXN0X3BsYXllcnMgPC0gcGxheWVyc1tiZXN0X2NvbWJpbmF0aW9uLCBdCnByaW50KGJlc3RfcGxheWVycykKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IFlhbmR5IERpYXogYW5kIFJ5YW4gTm9kYSBhcmUgdGhlIGJlc3QgcGlja3MgZ2l2ZW4gb3VyIGJ1ZGdldCBhbmQgb3VyIG1vZGVsIHByZWRpY3RpbmcgUnVucyBTY29yZWQgZnJvbSBhIHBsYXllcnMgb24gYmFzZSBwZXJjZW50YWdlIGFuZCBzbHVnZ2luZyBwZXJjZW50YWdlLiBJdCBtYWtlcyBzZW5zZSB0aGF0IGl0IHdvdWxkIHRoYXQgdGhlc2UgdHdvIHBsYXllcnMgYXJlIHRoZSByZWNvbW1lbmRhdGlvbiBzaW5jZSB0aGV5IGZhaXJseSBoYXZlIHRoZSB0b3Agc3VtcyBvZiBPQlAgYW5kIFNMRy4gTm9kYSBpcyBwYXJ0aWN1bGFybHkgSW5leHBlbnNpdmUgb2YgYSBwbGF5ZXIuIAoKCgoKCgo=