setwd("/Users/patty/Documents/INFOSCI 310")
#read the CSV file into R data frame
player_stats <- read.csv("2022-2023_NBA_player_stats_formatted.csv", header = TRUE, sep = ",")
#view first few rows
head(player_stats)
if (!require("ggplot2")) install.packages("ggplot2")
library(ggplot2)
if (!require("dplyr")) install.packages("dplyr")
library(dplyr)
#simple linear regression on Points per game against field goal percentage
regression_fg <- lm(PTS ~ FG, data = player_stats)
summary(regression_fg)
Call:
lm(formula = PTS ~ FG, data = player_stats)
Residuals:
Min 1Q Median 3Q Max
-3.5268 -0.4084 0.0488 0.3941 5.6626
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.18595 0.05537 -3.358 0.000828 ***
FG 2.78368 0.01379 201.921 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.8481 on 677 degrees of freedom
Multiple R-squared: 0.9837, Adjusted R-squared: 0.9836
F-statistic: 4.077e+04 on 1 and 677 DF, p-value: < 2.2e-16
#Plotting PTS against FG%
ggplot(player_stats, aes(x = FG, y = PTS)) +
geom_point() +
geom_smooth(method = "lm", col = "blue") +
labs(title = "Regression of PTS on FG%", x = "Field Goal Percentage", y = "Points Per Game (PTS")

regression_mp <- lm(PTS ~ MP, data = player_stats)
summary(regression_mp)
Call:
lm(formula = PTS ~ MP, data = player_stats)
Residuals:
Min 1Q Median 3Q Max
-19.1040 -1.7397 -0.0236 1.4267 14.9320
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -3.11156 0.28504 -10.92 <2e-16 ***
MP 0.61501 0.01319 46.65 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 3.233 on 677 degrees of freedom
Multiple R-squared: 0.7627, Adjusted R-squared: 0.7623
F-statistic: 2176 on 1 and 677 DF, p-value: < 2.2e-16
#Plotting PTS against MP
ggplot(player_stats, aes(x = MP, y = PTS)) +
geom_point() +
geom_smooth(method = "lm", col = "red") +
labs(title = "Regression of PTS on MP", x = "Minutes Player per Game (MP)", y = "Points Per Game (PTS)")

# Running the regression analyses
regression_fg <- lm(PTS ~ FG, data = player_stats)
regression_mp <- lm(PTS ~ MP, data = player_stats)
# Assuming we have the summaries stored
summary_fg <- summary(regression_fg)
summary_mp <- summary(regression_mp)
# Interpretation for Field Goal Percentage
cat("\nInterpretation for Field Goal Percentage (FG%):\n")
Interpretation for Field Goal Percentage (FG%):
cat("Slope (Coefficient for FG%):", summary_fg$coefficients["FG", "Estimate"], "\n")
Slope (Coefficient for FG%): 2.783681
cat("This slope indicates that for each one percent increase in FG%, a player's points per game is expected to change by",
summary_fg$coefficients["FG", "Estimate"], "points.\n")
This slope indicates that for each one percent increase in FG%, a player's points per game is expected to change by 2.783681 points.
cat("R-squared:", summary_fg$r.squared, "\n")
R-squared: 0.9836668
cat("This R-squared value suggests that", round(summary_fg$r.squared * 100), "% of the variability in PTS can be explained by FG%.\n")
This R-squared value suggests that 98 % of the variability in PTS can be explained by FG%.
cat("p-value for FG%:", summary_fg$coefficients["FG", "Pr(>|t|)"], "\n")
p-value for FG%: 0
if (summary_fg$coefficients["FG", "Pr(>|t|)"] < 0.05) {
cat("This p-value is statistically significant, indicating a strong evidence that FG% has an effect on PTS.\n")
} else {
cat("This p-value is not statistically significant, which suggests that the relationship between FG% and PTS may be due to chance.\n")
}
This p-value is statistically significant, indicating a strong evidence that FG% has an effect on PTS.
# Interpretation for Minutes Played
cat("\nInterpretation for Minutes Played (MP):\n")
Interpretation for Minutes Played (MP):
cat("Slope (Coefficient for MP):", summary_mp$coefficients["MP", "Estimate"], "\n")
Slope (Coefficient for MP): 0.6150149
cat("This slope indicates that for each additional minute played, a player's points per game is expected to change by",
summary_mp$coefficients["MP", "Estimate"], "points.\n")
This slope indicates that for each additional minute played, a player's points per game is expected to change by 0.6150149 points.
cat("R-squared:", summary_mp$r.squared, "\n")
R-squared: 0.7626856
cat("This R-squared value suggests that", round(summary_mp$r.squared * 100), "% of the variability in PTS can be explained by MP.\n")
This R-squared value suggests that 76 % of the variability in PTS can be explained by MP.
cat("p-value for MP:", summary_mp$coefficients["MP", "Pr(>|t|)"], "\n")
p-value for MP: 1.236772e-213
if (summary_mp$coefficients["MP", "Pr(>|t|)"] < 0.05) {
cat("This p-value is statistically significant, which provides strong evidence that MP has an effect on PTS.\n")
} else {
cat("This p-value is not statistically significant, suggesting that the relationship between MP and PTS may be due to chance.\n")
}
This p-value is statistically significant, which provides strong evidence that MP has an effect on PTS.
#Calc correlation between FG% and MP
correlation <- cor(player_stats$FG, player_stats$MP, use = "complete.obs")
#output corr
cat("Correlation between FG and MP is: ", correlation, "\n")
Correlation between FG and MP is: 0.8757879
#Decide whether to perform multiple regression
if(abs(correlation) > 0.7) {
cat("The correlation is high, indicating potential collinearity. It may be more appropriate to use multiple regression with caution, ensuring to check for multicollinearity. \n")
} else{
cat("The correlation is not high, indicating that simple linear regression may sufficient. However, multiple regression could still be beneficial to understand the combined effect of both variables on Points Per Game. \n")
}
The correlation is high, indicating potential collinearity. It may be more appropriate to use multiple regression with caution, ensuring to check for multicollinearity.
#Multiple Regression model
mrm <- lm(PTS ~ FG + MP, data = player_stats)
#summary
summary(mrm)
Call:
lm(formula = PTS ~ FG + MP, data = player_stats)
Residuals:
Min 1Q Median 3Q Max
-3.4563 -0.4077 0.0409 0.3854 5.7385
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.30164 0.08016 -3.763 0.000182 ***
FG 2.73396 0.02850 95.936 < 2e-16 ***
MP 0.01424 0.00715 1.992 0.046772 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.8463 on 676 degrees of freedom
Multiple R-squared: 0.9838, Adjusted R-squared: 0.9837
F-statistic: 2.048e+04 on 2 and 676 DF, p-value: < 2.2e-16
# Assuming the multiple regression model is stored in multiple_regression_model variable
# Get the summary of the model
model_summary <- summary(mrm)
#coefficients and their significance
cat("Coefficients and Significance:\n")
Coefficients and Significance:
if (model_summary$coefficients["FG", "Pr(>|t|)"] < 0.05) {
cat("FG% is statistically significant with a p-value of", model_summary$coefficients["FG", "Pr(>|t|)"], "\n")
} else {
cat("FG% is not statistically significant with a p-value of", model_summary$coefficients["FG", "Pr(>|t|)"], "\n")
}
FG% is statistically significant with a p-value of 0
if (model_summary$coefficients["MP", "Pr(>|t|)"] < 0.05) {
cat("MP is statistically significant with a p-value of", model_summary$coefficients["MP", "Pr(>|t|)"], "\n")
} else {
cat("MP is not statistically significant with a p-value of", model_summary$coefficients["MP", "Pr(>|t|)"], "\n")
}
MP is statistically significant with a p-value of 0.04677218
#model fit
cat("\nModel Fit:\n")
Model Fit:
cat("The R-squared value is", model_summary$r.squared, "which means that", round(model_summary$r.squared * 100), "% of the variability in PTS is explained by the model.\n")
The R-squared value is 0.9837621 which means that 98 % of the variability in PTS is explained by the model.
cat("The adjusted R-squared value is", model_summary$adj.r.squared, "which adjusts for the number of predictors in the model.\n")
The adjusted R-squared value is 0.983714 which adjusts for the number of predictors in the model.
#Residual Error
cat("\nResidual Error:\n")
Residual Error:
cat("The Residual Standard Error (RSE) is", sigma(mrm), "points. This value indicates the typical size of the residuals.\n")
The Residual Standard Error (RSE) is 0.8462535 points. This value indicates the typical size of the residuals.
# Insights R-squared
cat("\nInsights from R-squared:\n")
Insights from R-squared:
cat("A higher R-squared value would suggest a better fit of the model to the data. However, it does not indicate whether the model is appropriate or whether every predictor is significant.\n")
A higher R-squared value would suggest a better fit of the model to the data. However, it does not indicate whether the model is appropriate or whether every predictor is significant.
# Residual error difference between different models
cat("\nResidual Error Difference Between Different Models:\n")
Residual Error Difference Between Different Models:
cat("The RSE for the FG% model is", sigma(regression_fg), "and for the MP model is", sigma(regression_mp), ".\n")
The RSE for the FG% model is 0.8481066 and for the MP model is 3.232782 .
cat("Comparing these with the RSE for the multiple regression model may give insights into whether combining the variables improves the prediction accuracy.\n")
Comparing these with the RSE for the multiple regression model may give insights into whether combining the variables improves the prediction accuracy.
cat("In conclusion, the multiple regression model because it offers a more complex and informative picture of how FG% and MP interact to influecne points per game. This apprach is in line with our project motivation to delve deeper into the dynamics of scoring in the NBA and provides actionable insights that can influence player training, game strategty, and team performance analysis.")
In conclusion, the multiple regression model because it offers a more complex and informative picture of how FG% and MP interact to influecne points per game. This apprach is in line with our project motivation to delve deeper into the dynamics of scoring in the NBA and provides actionable insights that can influence player training, game strategty, and team performance analysis.
#install packages
if (!require("Metrics")) install.packages("Metrics")
library(Metrics)
#set a seed for reproducibility
set.seed(123)
#Randomly sample indices for the training set
train_indicies <- sample(1:nrow(player_stats), size = 0.8 * nrow(player_stats))
#create the training set
train_data <- player_stats[train_indicies, ]
#Create the test by excluding
test_data <- player_stats[-train_indicies, ]
#Check the number of rows in each set
cat("Training set rows:", nrow(train_data), "\n")
Training set rows: 543
cat("Test set rows:", nrow(test_data), "\n")
Test set rows: 136
predictors <- setdiff(names(train_data), c("Player", "Tm", "PTS"))
#create the formula for the model by pasting all predictor variables
formula <- as.formula(paste("PTS ~", paste(predictors, collapse = " + ")))
#Fit the multiple linear regression model
model <- lm(formula, data = train_data)
summary(model)
Call:
lm(formula = formula, data = train_data)
Residuals:
Min 1Q Median 3Q Max
-0.203475 -0.058444 0.002787 0.037992 0.205385
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2.228e-02 3.169e-02 -0.703 0.482325
Rk -1.913e-05 2.073e-05 -0.923 0.356400
PosPF 8.829e-03 1.208e-02 0.731 0.465076
PosPF-SF 5.028e-02 5.326e-02 0.944 0.345674
PosPG -1.057e-02 1.553e-02 -0.680 0.496571
PosSF -5.241e-04 1.384e-02 -0.038 0.969802
PosSG -3.328e-03 1.420e-02 -0.234 0.814778
Age 1.875e-04 7.722e-04 0.243 0.808252
G 3.872e-04 1.809e-04 2.140 0.032824 *
GS -9.585e-06 2.330e-04 -0.041 0.967200
MP -1.300e-03 1.271e-03 -1.023 0.306921
FG 1.761e+00 7.324e-02 24.039 < 2e-16 ***
FGA 9.667e-02 6.551e-02 1.476 0.140678
FG.1 9.460e-02 1.590e-01 0.595 0.552131
X3P 1.191e+00 7.417e-02 16.058 < 2e-16 ***
X3PA -7.491e-02 6.624e-02 -1.131 0.258595
X3P. 2.227e-02 3.270e-02 0.681 0.496176
X2P 2.537e-01 7.437e-02 3.411 0.000697 ***
X2PA -1.027e-01 6.544e-02 -1.570 0.117053
X2P. -1.138e-01 4.561e-02 -2.495 0.012925 *
eFG. 4.342e-02 1.464e-01 0.297 0.766887
FT 9.739e-01 1.523e-02 63.934 < 2e-16 ***
FTA 1.875e-02 1.274e-02 1.472 0.141654
FT. -3.179e-03 1.826e-02 -0.174 0.861855
ORB -2.910e-02 6.399e-02 -0.455 0.649433
DRB -2.599e-02 6.418e-02 -0.405 0.685676
TRB 2.424e-02 6.395e-02 0.379 0.704846
AST -1.956e-03 3.936e-03 -0.497 0.619553
STL 9.901e-03 1.280e-02 0.774 0.439581
BLK 1.521e-02 1.315e-02 1.156 0.248118
TOV 1.140e-02 1.019e-02 1.119 0.263619
PF -7.280e-03 7.578e-03 -0.961 0.337167
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.07187 on 511 degrees of freedom
Multiple R-squared: 0.9999, Adjusted R-squared: 0.9999
F-statistic: 1.577e+05 on 31 and 511 DF, p-value: < 2.2e-16
#predicting on the test set
test_predictons <- predict(model, newdata = test_data)
#computing residuals
residuals <- test_data$PTS - test_predictons
#Computing RSE
rse <- sqrt(mean(residuals^2))
#Computing R squared
sst <- sum((test_data$PTS - mean(test_data$PTS))^2)
ssr <- sum(residuals^2)
r_squared <- 1 - (ssr / sst)
#output
cat("Performance on the Test Data:\n")
Performance on the Test Data:
cat("Residual Standard Error (RSE):", rse, "\n")
Residual Standard Error (RSE): 0.07540592
cat("R-squared:", r_squared, "\n")
R-squared: 0.9998292
#Evaluate
#predict on training set
train_predictions <- predict(model, newdata = train_data)
#compute residuals for training set
train_residuals <- train_data$PTS - train_predictions
#compute RSE for training set
train_rse <- sqrt(mean(train_residuals^2))
#compute r squared for the training set
train_sst <- sum((train_data$PTS - mean(train_data$PTS))^2)
train_ssr <- sum(train_residuals^2)
train_r_squared <- 1 - (train_ssr / train_sst)
#compare with test set metrics
cat("Training Data Performance:\n")
Training Data Performance:
cat("R-squared:", train_r_squared, "\n")
R-squared: 0.9998955
cat("Residual Standard Error (RSE):", train_rse, "\n")
Residual Standard Error (RSE): 0.06971688
cat("\nTest Data Performance:\n")
Test Data Performance:
cat("R-squared:", r_squared, "\n")
R-squared: 0.9998292
cat("Residual Standard Error (RSE):", rse, "\n")
Residual Standard Error (RSE): 0.07540592
cat("\nBoth the training and test data show high r-squared values, indicating that the model is highly accurage in explaining the variance of the dependent variable.\n")
Both the training and test data show high r-squared values, indicating that the model is highly accurage in explaining the variance of the dependent variable.
cat("\nThe consistency of high R-squared and low RSE values between training and test datasets suggest that the model is generalizing well to unseen data. which implies there is no significant overfitting.\n")
The consistency of high R-squared and low RSE values between training and test datasets suggest that the model is generalizing well to unseen data. which implies there is no significant overfitting.
cat("\nR-squared values this high are quite unusual and might indicate overfitting. Which cna happen when the model captures noise in the training set as if it were a part of the underlying pattern.\n")
R-squared values this high are quite unusual and might indicate overfitting. Which cna happen when the model captures noise in the training set as if it were a part of the underlying pattern.
cat("\nIn summary, the model appears to perform extraordinarily well on both sets. While this is a generally postive outcome, its important to critically asses the models complexity, the quality of the data and the potential for overfitting.\n")
In summary, the model appears to perform extraordinarily well on both sets. While this is a generally postive outcome, its important to critically asses the models complexity, the quality of the data and the potential for overfitting.
LS0tDQp0aXRsZTogIkhXNCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KYGBge3J9DQpzZXR3ZCgiL1VzZXJzL3BhdHR5L0RvY3VtZW50cy9JTkZPU0NJIDMxMCIpDQoNCiNyZWFkIHRoZSBDU1YgZmlsZSBpbnRvIFIgZGF0YSBmcmFtZQ0KcGxheWVyX3N0YXRzIDwtIHJlYWQuY3N2KCIyMDIyLTIwMjNfTkJBX3BsYXllcl9zdGF0c19mb3JtYXR0ZWQuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiKQ0KDQojdmlldyBmaXJzdCBmZXcgcm93cw0KaGVhZChwbGF5ZXJfc3RhdHMpDQpgYGANCmBgYHtyfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQppZiAoIXJlcXVpcmUoImRwbHlyIikpIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KYGBge3J9DQojc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG9uIFBvaW50cyBwZXIgZ2FtZSBhZ2FpbnN0IGZpZWxkIGdvYWwgcGVyY2VudGFnZQ0KDQpyZWdyZXNzaW9uX2ZnIDwtIGxtKFBUUyB+IEZHLCBkYXRhID0gcGxheWVyX3N0YXRzKQ0KDQpzdW1tYXJ5KHJlZ3Jlc3Npb25fZmcpDQoNCiNQbG90dGluZyBQVFMgYWdhaW5zdCBGRyUNCmdncGxvdChwbGF5ZXJfc3RhdHMsIGFlcyh4ID0gRkcsIHkgPSBQVFMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJibHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlJlZ3Jlc3Npb24gb2YgUFRTIG9uIEZHJSIsIHggPSAiRmllbGQgR29hbCBQZXJjZW50YWdlIiwgeSA9ICJQb2ludHMgUGVyIEdhbWUgKFBUUyIpDQpgYGANCg0KDQpgYGB7cn0NCnJlZ3Jlc3Npb25fbXAgPC0gbG0oUFRTIH4gTVAsIGRhdGEgPSBwbGF5ZXJfc3RhdHMpDQpzdW1tYXJ5KHJlZ3Jlc3Npb25fbXApDQoNCiNQbG90dGluZyBQVFMgYWdhaW5zdCBNUA0KZ2dwbG90KHBsYXllcl9zdGF0cywgYWVzKHggPSBNUCwgeSA9IFBUUykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJSZWdyZXNzaW9uIG9mIFBUUyBvbiBNUCIsIHggPSAiTWludXRlcyBQbGF5ZXIgcGVyIEdhbWUgKE1QKSIsIHkgPSAiUG9pbnRzIFBlciBHYW1lIChQVFMpIikNCmBgYA0KDQpgYGB7cn0NCiMgUnVubmluZyB0aGUgcmVncmVzc2lvbiBhbmFseXNlcw0KcmVncmVzc2lvbl9mZyA8LSBsbShQVFMgfiBGRywgZGF0YSA9IHBsYXllcl9zdGF0cykNCnJlZ3Jlc3Npb25fbXAgPC0gbG0oUFRTIH4gTVAsIGRhdGEgPSBwbGF5ZXJfc3RhdHMpDQoNCiMgQXNzdW1pbmcgd2UgaGF2ZSB0aGUgc3VtbWFyaWVzIHN0b3JlZA0Kc3VtbWFyeV9mZyA8LSBzdW1tYXJ5KHJlZ3Jlc3Npb25fZmcpDQpzdW1tYXJ5X21wIDwtIHN1bW1hcnkocmVncmVzc2lvbl9tcCkNCg0KIyBJbnRlcnByZXRhdGlvbiBmb3IgRmllbGQgR29hbCBQZXJjZW50YWdlDQpjYXQoIlxuSW50ZXJwcmV0YXRpb24gZm9yIEZpZWxkIEdvYWwgUGVyY2VudGFnZSAoRkclKTpcbiIpDQoNCmNhdCgiU2xvcGUgKENvZWZmaWNpZW50IGZvciBGRyUpOiIsIHN1bW1hcnlfZmckY29lZmZpY2llbnRzWyJGRyIsICJFc3RpbWF0ZSJdLCAiXG4iKQ0KDQpjYXQoIlRoaXMgc2xvcGUgaW5kaWNhdGVzIHRoYXQgZm9yIGVhY2ggb25lIHBlcmNlbnQgaW5jcmVhc2UgaW4gRkclLCBhIHBsYXllcidzIHBvaW50cyBwZXIgZ2FtZSBpcyBleHBlY3RlZCB0byBjaGFuZ2UgYnkiLA0KICAgIHN1bW1hcnlfZmckY29lZmZpY2llbnRzWyJGRyIsICJFc3RpbWF0ZSJdLCAicG9pbnRzLlxuIikNCg0KY2F0KCJSLXNxdWFyZWQ6Iiwgc3VtbWFyeV9mZyRyLnNxdWFyZWQsICJcbiIpDQoNCmNhdCgiVGhpcyBSLXNxdWFyZWQgdmFsdWUgc3VnZ2VzdHMgdGhhdCIsIHJvdW5kKHN1bW1hcnlfZmckci5zcXVhcmVkICogMTAwKSwgIiUgb2YgdGhlIHZhcmlhYmlsaXR5IGluIFBUUyBjYW4gYmUgZXhwbGFpbmVkIGJ5IEZHJS5cbiIpDQoNCmNhdCgicC12YWx1ZSBmb3IgRkclOiIsIHN1bW1hcnlfZmckY29lZmZpY2llbnRzWyJGRyIsICJQcig+fHR8KSJdLCAiXG4iKQ0KaWYgKHN1bW1hcnlfZmckY29lZmZpY2llbnRzWyJGRyIsICJQcig+fHR8KSJdIDwgMC4wNSkgew0KICBjYXQoIlRoaXMgcC12YWx1ZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBpbmRpY2F0aW5nIGEgc3Ryb25nIGV2aWRlbmNlIHRoYXQgRkclIGhhcyBhbiBlZmZlY3Qgb24gUFRTLlxuIikNCn0gZWxzZSB7DQogIGNhdCgiVGhpcyBwLXZhbHVlIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCB3aGljaCBzdWdnZXN0cyB0aGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBGRyUgYW5kIFBUUyBtYXkgYmUgZHVlIHRvIGNoYW5jZS5cbiIpDQp9DQoNCiMgSW50ZXJwcmV0YXRpb24gZm9yIE1pbnV0ZXMgUGxheWVkDQpjYXQoIlxuSW50ZXJwcmV0YXRpb24gZm9yIE1pbnV0ZXMgUGxheWVkIChNUCk6XG4iKQ0KDQpjYXQoIlNsb3BlIChDb2VmZmljaWVudCBmb3IgTVApOiIsIHN1bW1hcnlfbXAkY29lZmZpY2llbnRzWyJNUCIsICJFc3RpbWF0ZSJdLCAiXG4iKQ0KDQpjYXQoIlRoaXMgc2xvcGUgaW5kaWNhdGVzIHRoYXQgZm9yIGVhY2ggYWRkaXRpb25hbCBtaW51dGUgcGxheWVkLCBhIHBsYXllcidzIHBvaW50cyBwZXIgZ2FtZSBpcyBleHBlY3RlZCB0byBjaGFuZ2UgYnkiLA0KICAgIHN1bW1hcnlfbXAkY29lZmZpY2llbnRzWyJNUCIsICJFc3RpbWF0ZSJdLCAicG9pbnRzLlxuIikNCg0KY2F0KCJSLXNxdWFyZWQ6Iiwgc3VtbWFyeV9tcCRyLnNxdWFyZWQsICJcbiIpDQoNCmNhdCgiVGhpcyBSLXNxdWFyZWQgdmFsdWUgc3VnZ2VzdHMgdGhhdCIsIHJvdW5kKHN1bW1hcnlfbXAkci5zcXVhcmVkICogMTAwKSwgIiUgb2YgdGhlIHZhcmlhYmlsaXR5IGluIFBUUyBjYW4gYmUgZXhwbGFpbmVkIGJ5IE1QLlxuIikNCg0KY2F0KCJwLXZhbHVlIGZvciBNUDoiLCBzdW1tYXJ5X21wJGNvZWZmaWNpZW50c1siTVAiLCAiUHIoPnx0fCkiXSwgIlxuIikNCmlmIChzdW1tYXJ5X21wJGNvZWZmaWNpZW50c1siTVAiLCAiUHIoPnx0fCkiXSA8IDAuMDUpIHsNCiAgY2F0KCJUaGlzIHAtdmFsdWUgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgd2hpY2ggcHJvdmlkZXMgc3Ryb25nIGV2aWRlbmNlIHRoYXQgTVAgaGFzIGFuIGVmZmVjdCBvbiBQVFMuXG4iKQ0KfSBlbHNlIHsNCiAgY2F0KCJUaGlzIHAtdmFsdWUgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gTVAgYW5kIFBUUyBtYXkgYmUgZHVlIHRvIGNoYW5jZS5cbiIpDQp9DQoNCmBgYA0KYGBge3J9DQojQ2FsYyBjb3JyZWxhdGlvbiBiZXR3ZWVuIEZHJSBhbmQgTVANCg0KY29ycmVsYXRpb24gPC0gY29yKHBsYXllcl9zdGF0cyRGRywgcGxheWVyX3N0YXRzJE1QLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KI291dHB1dCBjb3JyDQpjYXQoIkNvcnJlbGF0aW9uIGJldHdlZW4gRkcgYW5kIE1QIGlzOiAiLCBjb3JyZWxhdGlvbiwgIlxuIikNCg0KI0RlY2lkZSB3aGV0aGVyIHRvIHBlcmZvcm0gbXVsdGlwbGUgcmVncmVzc2lvbg0KaWYoYWJzKGNvcnJlbGF0aW9uKSA+IDAuNykgew0KICBjYXQoIlRoZSBjb3JyZWxhdGlvbiBpcyBoaWdoLCBpbmRpY2F0aW5nIHBvdGVudGlhbCBjb2xsaW5lYXJpdHkuIEl0IG1heSBiZSBtb3JlIGFwcHJvcHJpYXRlIHRvIHVzZSBtdWx0aXBsZSByZWdyZXNzaW9uIHdpdGggY2F1dGlvbiwgZW5zdXJpbmcgdG8gY2hlY2sgZm9yIG11bHRpY29sbGluZWFyaXR5LiBcbiIpDQp9IGVsc2V7DQogIGNhdCgiVGhlIGNvcnJlbGF0aW9uIGlzIG5vdCBoaWdoLCBpbmRpY2F0aW5nIHRoYXQgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG1heSBzdWZmaWNpZW50LiBIb3dldmVyLCBtdWx0aXBsZSByZWdyZXNzaW9uIGNvdWxkIHN0aWxsIGJlIGJlbmVmaWNpYWwgdG8gdW5kZXJzdGFuZCB0aGUgY29tYmluZWQgZWZmZWN0IG9mIGJvdGggdmFyaWFibGVzIG9uIFBvaW50cyBQZXIgR2FtZS4gXG4iKQ0KfQ0KYGBgDQpgYGB7cn0NCiNNdWx0aXBsZSBSZWdyZXNzaW9uIG1vZGVsDQptcm0gPC0gbG0oUFRTIH4gRkcgKyBNUCwgZGF0YSA9IHBsYXllcl9zdGF0cykNCg0KI3N1bW1hcnkNCnN1bW1hcnkobXJtKQ0KYGBgDQoNCmBgYHtyfQ0KIyBBc3N1bWluZyB0aGUgbXVsdGlwbGUgcmVncmVzc2lvbiBtb2RlbCBpcyBzdG9yZWQgaW4gbXVsdGlwbGVfcmVncmVzc2lvbl9tb2RlbCB2YXJpYWJsZQ0KDQojIEdldCB0aGUgc3VtbWFyeSBvZiB0aGUgbW9kZWwNCm1vZGVsX3N1bW1hcnkgPC0gc3VtbWFyeShtcm0pDQoNCg0KI2NvZWZmaWNpZW50cyBhbmQgdGhlaXIgc2lnbmlmaWNhbmNlDQpjYXQoIkNvZWZmaWNpZW50cyBhbmQgU2lnbmlmaWNhbmNlOlxuIikNCmlmIChtb2RlbF9zdW1tYXJ5JGNvZWZmaWNpZW50c1siRkciLCAiUHIoPnx0fCkiXSA8IDAuMDUpIHsNCiAgY2F0KCJGRyUgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB3aXRoIGEgcC12YWx1ZSBvZiIsIG1vZGVsX3N1bW1hcnkkY29lZmZpY2llbnRzWyJGRyIsICJQcig+fHR8KSJdLCAiXG4iKQ0KfSBlbHNlIHsNCiAgY2F0KCJGRyUgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgd2l0aCBhIHAtdmFsdWUgb2YiLCBtb2RlbF9zdW1tYXJ5JGNvZWZmaWNpZW50c1siRkciLCAiUHIoPnx0fCkiXSwgIlxuIikNCn0NCg0KDQppZiAobW9kZWxfc3VtbWFyeSRjb2VmZmljaWVudHNbIk1QIiwgIlByKD58dHwpIl0gPCAwLjA1KSB7DQogIGNhdCgiTVAgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB3aXRoIGEgcC12YWx1ZSBvZiIsIG1vZGVsX3N1bW1hcnkkY29lZmZpY2llbnRzWyJNUCIsICJQcig+fHR8KSJdLCAiXG4iKQ0KfSBlbHNlIHsNCiAgY2F0KCJNUCBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB3aXRoIGEgcC12YWx1ZSBvZiIsIG1vZGVsX3N1bW1hcnkkY29lZmZpY2llbnRzWyJNUCIsICJQcig+fHR8KSJdLCAiXG4iKQ0KfQ0KDQojbW9kZWwgZml0DQpjYXQoIlxuTW9kZWwgRml0OlxuIikNCmNhdCgiVGhlIFItc3F1YXJlZCB2YWx1ZSBpcyIsIG1vZGVsX3N1bW1hcnkkci5zcXVhcmVkLCAid2hpY2ggbWVhbnMgdGhhdCIsIHJvdW5kKG1vZGVsX3N1bW1hcnkkci5zcXVhcmVkICogMTAwKSwgIiUgb2YgdGhlIHZhcmlhYmlsaXR5IGluIFBUUyBpcyBleHBsYWluZWQgYnkgdGhlIG1vZGVsLlxuIikNCmNhdCgiVGhlIGFkanVzdGVkIFItc3F1YXJlZCB2YWx1ZSBpcyIsIG1vZGVsX3N1bW1hcnkkYWRqLnIuc3F1YXJlZCwgIndoaWNoIGFkanVzdHMgZm9yIHRoZSBudW1iZXIgb2YgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwuXG4iKQ0KDQojUmVzaWR1YWwgRXJyb3INCmNhdCgiXG5SZXNpZHVhbCBFcnJvcjpcbiIpDQpjYXQoIlRoZSBSZXNpZHVhbCBTdGFuZGFyZCBFcnJvciAoUlNFKSBpcyIsIHNpZ21hKG1ybSksICJwb2ludHMuIFRoaXMgdmFsdWUgaW5kaWNhdGVzIHRoZSB0eXBpY2FsIHNpemUgb2YgdGhlIHJlc2lkdWFscy5cbiIpDQoNCiMgSW5zaWdodHMgUi1zcXVhcmVkDQpjYXQoIlxuSW5zaWdodHMgZnJvbSBSLXNxdWFyZWQ6XG4iKQ0KY2F0KCJBIGhpZ2hlciBSLXNxdWFyZWQgdmFsdWUgd291bGQgc3VnZ2VzdCBhIGJldHRlciBmaXQgb2YgdGhlIG1vZGVsIHRvIHRoZSBkYXRhLiBIb3dldmVyLCBpdCBkb2VzIG5vdCBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBtb2RlbCBpcyBhcHByb3ByaWF0ZSBvciB3aGV0aGVyIGV2ZXJ5IHByZWRpY3RvciBpcyBzaWduaWZpY2FudC5cbiIpDQoNCiMgUmVzaWR1YWwgZXJyb3IgZGlmZmVyZW5jZSBiZXR3ZWVuIGRpZmZlcmVudCBtb2RlbHMNCg0KY2F0KCJcblJlc2lkdWFsIEVycm9yIERpZmZlcmVuY2UgQmV0d2VlbiBEaWZmZXJlbnQgTW9kZWxzOlxuIikNCmNhdCgiVGhlIFJTRSBmb3IgdGhlIEZHJSBtb2RlbCBpcyIsIHNpZ21hKHJlZ3Jlc3Npb25fZmcpLCAiYW5kIGZvciB0aGUgTVAgbW9kZWwgaXMiLCBzaWdtYShyZWdyZXNzaW9uX21wKSwgIi5cbiIpDQpjYXQoIkNvbXBhcmluZyB0aGVzZSB3aXRoIHRoZSBSU0UgZm9yIHRoZSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIG1heSBnaXZlIGluc2lnaHRzIGludG8gd2hldGhlciBjb21iaW5pbmcgdGhlIHZhcmlhYmxlcyBpbXByb3ZlcyB0aGUgcHJlZGljdGlvbiBhY2N1cmFjeS5cbiIpDQoNCmBgYA0KDQpgYGB7cn0NCmNhdCgiSW4gY29uY2x1c2lvbiwgdGhlIG11bHRpcGxlIHJlZ3Jlc3Npb24gbW9kZWwgYmVjYXVzZSBpdCBvZmZlcnMgYSBtb3JlIGNvbXBsZXggYW5kIGluZm9ybWF0aXZlIHBpY3R1cmUgb2YgaG93IEZHJSBhbmQgTVAgaW50ZXJhY3QgdG8gaW5mbHVlY25lIHBvaW50cyBwZXIgZ2FtZS4gVGhpcyBhcHByYWNoIGlzIGluIGxpbmUgd2l0aCBvdXIgcHJvamVjdCBtb3RpdmF0aW9uIHRvIGRlbHZlIGRlZXBlciBpbnRvIHRoZSBkeW5hbWljcyBvZiBzY29yaW5nIGluIHRoZSBOQkEgYW5kIHByb3ZpZGVzIGFjdGlvbmFibGUgaW5zaWdodHMgdGhhdCBjYW4gaW5mbHVlbmNlIHBsYXllciB0cmFpbmluZywgZ2FtZSBzdHJhdGVndHksIGFuZCB0ZWFtIHBlcmZvcm1hbmNlIGFuYWx5c2lzLiIpDQpgYGANCmBgYHtyfQ0KI2luc3RhbGwgcGFja2FnZXMNCmlmICghcmVxdWlyZSgiTWV0cmljcyIpKSBpbnN0YWxsLnBhY2thZ2VzKCJNZXRyaWNzIikNCmxpYnJhcnkoTWV0cmljcykNCg0KYGBgDQoNCmBgYHtyfQ0KI3NldCBhIHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0Kc2V0LnNlZWQoMTIzKQ0KDQojUmFuZG9tbHkgc2FtcGxlIGluZGljZXMgZm9yIHRoZSB0cmFpbmluZyBzZXQNCnRyYWluX2luZGljaWVzIDwtIHNhbXBsZSgxOm5yb3cocGxheWVyX3N0YXRzKSwgc2l6ZSA9IDAuOCAqIG5yb3cocGxheWVyX3N0YXRzKSkNCg0KI2NyZWF0ZSB0aGUgdHJhaW5pbmcgc2V0DQp0cmFpbl9kYXRhIDwtIHBsYXllcl9zdGF0c1t0cmFpbl9pbmRpY2llcywgXQ0KDQojQ3JlYXRlIHRoZSB0ZXN0IGJ5IGV4Y2x1ZGluZw0KdGVzdF9kYXRhIDwtIHBsYXllcl9zdGF0c1stdHJhaW5faW5kaWNpZXMsIF0NCg0KI0NoZWNrIHRoZSBudW1iZXIgb2Ygcm93cyBpbiBlYWNoIHNldA0KY2F0KCJUcmFpbmluZyBzZXQgcm93czoiLCBucm93KHRyYWluX2RhdGEpLCAiXG4iKQ0KY2F0KCJUZXN0IHNldCByb3dzOiIsIG5yb3codGVzdF9kYXRhKSwgIlxuIikNCg0KYGBgDQpgYGB7cn0NCnByZWRpY3RvcnMgPC0gc2V0ZGlmZihuYW1lcyh0cmFpbl9kYXRhKSwgYygiUGxheWVyIiwgIlRtIiwgIlBUUyIpKQ0KDQojY3JlYXRlIHRoZSBmb3JtdWxhIGZvciB0aGUgbW9kZWwgYnkgcGFzdGluZyBhbGwgcHJlZGljdG9yIHZhcmlhYmxlcw0KZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJQVFMgfiIsIHBhc3RlKHByZWRpY3RvcnMsIGNvbGxhcHNlID0gIiArICIpKSkNCg0KI0ZpdCB0aGUgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwNCm1vZGVsIDwtIGxtKGZvcm11bGEsIGRhdGEgPSB0cmFpbl9kYXRhKQ0KDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQpgYGB7cn0NCiNwcmVkaWN0aW5nIG9uIHRoZSB0ZXN0IHNldA0KdGVzdF9wcmVkaWN0b25zIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEpDQoNCiNjb21wdXRpbmcgcmVzaWR1YWxzDQpyZXNpZHVhbHMgPC0gdGVzdF9kYXRhJFBUUyAtIHRlc3RfcHJlZGljdG9ucw0KDQojQ29tcHV0aW5nIFJTRQ0KcnNlIDwtIHNxcnQobWVhbihyZXNpZHVhbHNeMikpDQoNCiNDb21wdXRpbmcgUiBzcXVhcmVkDQpzc3QgPC0gc3VtKCh0ZXN0X2RhdGEkUFRTIC0gbWVhbih0ZXN0X2RhdGEkUFRTKSleMikNCnNzciA8LSBzdW0ocmVzaWR1YWxzXjIpDQpyX3NxdWFyZWQgPC0gMSAtIChzc3IgLyBzc3QpDQoNCiNvdXRwdXQNCmNhdCgiUGVyZm9ybWFuY2Ugb24gdGhlIFRlc3QgRGF0YTpcbiIpDQpjYXQoIlJlc2lkdWFsIFN0YW5kYXJkIEVycm9yIChSU0UpOiIsIHJzZSwgIlxuIikNCmNhdCgiUi1zcXVhcmVkOiIsIHJfc3F1YXJlZCwgIlxuIikNCg0KYGBgDQpgYGB7cn0NCiNFdmFsdWF0ZQ0KDQojcHJlZGljdCBvbiB0cmFpbmluZyBzZXQNCnRyYWluX3ByZWRpY3Rpb25zIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0cmFpbl9kYXRhKQ0KDQojY29tcHV0ZSByZXNpZHVhbHMgZm9yIHRyYWluaW5nIHNldA0KdHJhaW5fcmVzaWR1YWxzIDwtIHRyYWluX2RhdGEkUFRTIC0gdHJhaW5fcHJlZGljdGlvbnMNCg0KI2NvbXB1dGUgUlNFIGZvciB0cmFpbmluZyBzZXQNCnRyYWluX3JzZSA8LSBzcXJ0KG1lYW4odHJhaW5fcmVzaWR1YWxzXjIpKQ0KDQojY29tcHV0ZSByIHNxdWFyZWQgZm9yIHRoZSB0cmFpbmluZyBzZXQNCnRyYWluX3NzdCA8LSBzdW0oKHRyYWluX2RhdGEkUFRTIC0gbWVhbih0cmFpbl9kYXRhJFBUUykpXjIpDQoNCnRyYWluX3NzciA8LSBzdW0odHJhaW5fcmVzaWR1YWxzXjIpDQoNCnRyYWluX3Jfc3F1YXJlZCA8LSAxIC0gKHRyYWluX3NzciAvIHRyYWluX3NzdCkNCg0KI2NvbXBhcmUgd2l0aCB0ZXN0IHNldCBtZXRyaWNzDQpjYXQoIlRyYWluaW5nIERhdGEgUGVyZm9ybWFuY2U6XG4iKQ0KY2F0KCJSLXNxdWFyZWQ6IiwgdHJhaW5fcl9zcXVhcmVkLCAiXG4iKQ0KY2F0KCJSZXNpZHVhbCBTdGFuZGFyZCBFcnJvciAoUlNFKToiLCB0cmFpbl9yc2UsICJcbiIpDQoNCmNhdCgiXG5UZXN0IERhdGEgUGVyZm9ybWFuY2U6XG4iKQ0KDQpjYXQoIlItc3F1YXJlZDoiLCByX3NxdWFyZWQsICJcbiIpDQpjYXQoIlJlc2lkdWFsIFN0YW5kYXJkIEVycm9yIChSU0UpOiIsIHJzZSwgIlxuIikNCg0KYGBgDQpgYGB7cn0NCmNhdCgiXG5Cb3RoIHRoZSB0cmFpbmluZyBhbmQgdGVzdCBkYXRhIHNob3cgaGlnaCByLXNxdWFyZWQgdmFsdWVzLCBpbmRpY2F0aW5nIHRoYXQgdGhlIG1vZGVsIGlzIGhpZ2hseSBhY2N1cmFnZSBpbiBleHBsYWluaW5nIHRoZSB2YXJpYW5jZSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLlxuIikNCg0KY2F0KCJcblRoZSBjb25zaXN0ZW5jeSBvZiBoaWdoIFItc3F1YXJlZCBhbmQgbG93IFJTRSB2YWx1ZXMgYmV0d2VlbiB0cmFpbmluZyBhbmQgdGVzdCBkYXRhc2V0cyBzdWdnZXN0IHRoYXQgdGhlIG1vZGVsIGlzIGdlbmVyYWxpemluZyB3ZWxsIHRvIHVuc2VlbiBkYXRhLiB3aGljaCBpbXBsaWVzIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IG92ZXJmaXR0aW5nLlxuIikNCg0KY2F0KCJcblItc3F1YXJlZCB2YWx1ZXMgdGhpcyBoaWdoIGFyZSBxdWl0ZSB1bnVzdWFsIGFuZCBtaWdodCBpbmRpY2F0ZSBvdmVyZml0dGluZy4gV2hpY2ggY25hIGhhcHBlbiB3aGVuIHRoZSBtb2RlbCBjYXB0dXJlcyBub2lzZSBpbiB0aGUgdHJhaW5pbmcgc2V0IGFzIGlmIGl0IHdlcmUgYSBwYXJ0IG9mIHRoZSB1bmRlcmx5aW5nIHBhdHRlcm4uXG4iKQ0KDQpjYXQoIlxuSW4gc3VtbWFyeSwgdGhlIG1vZGVsIGFwcGVhcnMgdG8gcGVyZm9ybSBleHRyYW9yZGluYXJpbHkgd2VsbCBvbiBib3RoIHNldHMuIFdoaWxlIHRoaXMgaXMgYSBnZW5lcmFsbHkgcG9zdGl2ZSBvdXRjb21lLCBpdHMgaW1wb3J0YW50IHRvIGNyaXRpY2FsbHkgYXNzZXMgdGhlIG1vZGVscyBjb21wbGV4aXR5LCB0aGUgcXVhbGl0eSBvZiB0aGUgZGF0YSBhbmQgdGhlIHBvdGVudGlhbCBmb3Igb3ZlcmZpdHRpbmcuXG4iKQ0KDQpgYGANCg0K