Loading data
threep_per_org <- read.csv('../../results/team_data/comb_3pper.csv')
year_range <- threep_per_org$X
threep_per <- subset(threep_per_org, select=-c(X))
threep_attempt_org <- read.csv('../../results/team_data/comb_3pattempt.csv')
year_range <- threep_attempt_org$X
threep_attempt <- subset(threep_attempt_org, select=-c(X))
threep_made_org <- read.csv('../../results/team_data/comb_3pmade.csv')
year_range <- threep_made_org$X
threep_made <- subset(threep_made_org, select=-c(X))
Plotting the mean Long term trend or fad?
avg_threep_per <- rowMeans(threep_per, na.rm=TRUE)
avg_threep_attempt <- rowMeans(threep_attempt, na.rm=TRUE)
means_df <- data.frame('Average 3-pointer percentage'=avg_threep_per, 'Average 3-pointer attempts'=avg_threep_attempt, 'Year'=year_range)
plot1 <- ggplot(data=means_df, aes(Year, Average.3.pointer.percentage)) + geom_line(linetype=2) + geom_point(shape=21, fill="white") + geom_hline(yintercept=0.33, col="red", linetype=3) + ggtitle('3-pointer percentage')
plot2 <- ggplot(data=means_df, aes(Year, Average.3.pointer.attempts)) + geom_line(linetype=2) + geom_point(shape=21, fill="white") + ggtitle('3-pointer attempts')
grid.arrange(plot1, plot2, ncol=2)
After crossing 0.33 percent it has largely saturated. Plot 2-pointers too
The golden state warrior outlier
require(gridExtra)
y1 = as.numeric(threep_per[37,])
y2 = as.numeric(threep_per[27,])
df1 <- data.frame('Season 2016'=y1, 'Season 2006'=y2)
plot1 <- ggplot(data = df1, aes(Season.2016)) + geom_histogram(aes(y=..density..), col="black", fill="grey", bins=6) + geom_density(col="red", lty=2) + ggtitle('Season 2016') + labs(x="3-pointer percentage")
plot2 <- ggplot(data = df1, aes(Season.2006)) + geom_histogram(aes(y=..density..), col="black", fill="grey", bins=8) + geom_density(col="red", lty=2) + ggtitle('Season 2006') + labs(x="3-pointer percentage")
grid.arrange(plot2, plot1, ncol=2)
df2 <- melt(df1, variable_name = 'Season')
ggplot(data = df2, aes(x=Season, y=value, fill=Season)) + geom_boxplot(outlier.colour = "red", outlier.shape = 2, notch = TRUE) + ggtitle('Box plot of 3-pointer percentage') + labs(x='Season', y='3-pointer percentage')
# par(mfrow=c(1,2))
# qqnorm((y1-mean(y1))/sd(y1))
# abline(0,1, col="red")
# qqnorm((y2-mean(y2))/sd(y2))
# abline(0,1, col="red")
But they don’t have as much as big difference in attempts
x1 = as.numeric(threep_attempt[37,])
x2 = as.numeric(threep_attempt[27,])
df1 <- data.frame('Season 2016'=x1, 'Season 2006'=x2)
plot1 <- ggplot(data = df1, aes(Season.2016)) + geom_histogram(aes(y=..density..), col="black", fill="grey", bins=9) + geom_density(col="red", lty=2) + ggtitle('Season 2016') + labs(x="3-pointer attempts")
plot2 <- ggplot(data = df1, aes(Season.2006)) + geom_histogram(aes(y=..density..), col="black", fill="grey", bins=9) + geom_density(col="red", lty=2) + ggtitle('Season 2006') + labs(x="3-pointer attempts")
grid.arrange(plot2, plot1, ncol=2)
df2 <- melt(df1, variable_name = 'Season')
ggplot(data = df2, aes(x=Season, y=value, fill=Season)) + geom_boxplot(outlier.colour = "red", outlier.shape = 2, notch = TRUE) + ggtitle('Box plot of 3-pointer attempts') + labs(x='Season', y='3-pointer attempts')
# par(mfrow=c(1,2))
# qqnorm((x1-mean(x1))/sd(x1))
# abline(0,1, col="red")
# qqnorm((x2-mean(x2))/sd(x2))
# abline(0,1, col="red")
Plotting per team per year data
threep_anal <- function(fname, ind)
{
data <- read.csv(fname)
df <- melt(data, id.vars='X', variable_name = 'teams')
ggplot(df, aes(X,value)) + geom_line(aes(colour = teams))
# Smoothing moving average
col_names <- names(data)
# FIXME: Fudging data for these two years (Interpolation)
if (ind==1)
{
data[24, 'CHA'] <- 0.353
data[25, 'CHA'] <- 0.357
}
if (ind==2)
{
data[24, 'CHA'] <- 11.4
data[25, 'CHA'] <- 11.4
}
smooth_data <- data.frame(time = data["X"])
for (col_name in col_names[2:ncol(data)])
{
smooth_data[col_name] <- SMA(data[col_name], n=3)
}
df2 <- melt(smooth_data, id.vars='X', variable_name = 'teams')
}
threep_per_smooth <- threep_anal('../../results/team_data/comb_3pper.csv', 1)
threep_attempt_smooth <- threep_anal('../../results/team_data/comb_3pattempt.csv', 2)
par(mfrow=c(1,2))
df1 <- melt(threep_per_org, id.vars='X', variable_name = 'teams')
ggplot(df1, aes(X,value)) + geom_line(aes(colour = teams)) + ggtitle('Unsmoothened data') + labs(x='year', y='3-pointer percentage')
ggplot(threep_per_smooth, aes(X,value)) + geom_line(aes(colour = teams)) + ggtitle('Smoothened data') + labs(x='year', y='3-pointer percentage')
par(mfrow=c(1,2))
df2 <- melt(threep_attempt_org, id.vars='X', variable_name = 'teams')
ggplot(df2, aes(X,value)) + geom_line(aes(colour = teams)) + ggtitle('Unsmoothened data') + labs(x='year', y='3-pointer attempts')
ggplot(threep_attempt_smooth, aes(X,value)) + geom_line(aes(colour = teams)) + ggtitle('Smoothened data') + labs(x='year', y='3-pointer attempts')
Looking at statistical significance
t.test(y1,y2)
y3 <- as.numeric(threep_per[17,])
t.test(y1,y3)
Hence threepointer percent looks more or less the same
x1 <- as.numeric(threep_attempt[37,])
x2 <- as.numeric(threep_attempt[27,])
x3 <- as.numeric(threep_attempt[17,])
t.test(x1,x2)
t.test(x1,x3)
Time series analysis HoltWinters predictions
avg_threep_per[16:18] <- c(NA, NA, NA)
avg_threep_per <- na.approx(avg_threep_per)
per_ts <- ts(avg_threep_per, start=head(year_range,n=1))
avg_threep_attempt[16:18] <- c(NA, NA, NA)
avg_threep_attempt <- na.approx(avg_threep_attempt)
attempt_ts <- ts(avg_threep_attempt, start=head(year_range,n=1))
ts_df <- data.frame(Year=year_range, percentage=avg_threep_per, attempts=avg_threep_attempt)
plot1 <- ggplot(data=ts_df, aes(x=Year, y=percentage)) + geom_line() + ggtitle('3-pointer percentage') + labs(x="Year", y="3-pointer percentage") + geom_smooth(col="red", lty=2)
plot2 <- ggplot(data=ts_df, aes(x=Year, y=attempts)) + geom_line() + ggtitle('3-pointer attempts') + labs(x="Year", y="3-pointer attempts") + geom_smooth(col="red", lty=2)
grid.arrange(plot1, plot2, ncol=2)

gamma=False means non-seasonal
par(mfrow=c(1,2))
per_forecasts <- HoltWinters(per_ts, gamma=FALSE)
plot(per_forecasts, xlab="Year", ylab="3-pointer percentage")
per_forecasts$SSE
[1] 0.006259325
per_future <- forecast.HoltWinters(per_forecasts, h=5)
attempt_forecasts <- HoltWinters(attempt_ts, gamma=FALSE)
plot(attempt_forecasts, xlab="Year", ylab="3-pointer attempts")

attempt_forecasts$SSE
[1] 12.33629
attempt_future <- forecast.HoltWinters(attempt_forecasts, h=5)
plot.forecast(per_future, xlab="Year", ylab="3-pointer percentage")
plot.forecast(attempt_future, xlab="Year", ylab="3-pointer attempts")

tsdisplay(diff(per_ts), main="diff 3-pointer percentage", xlab="Year", ylab="percentage")

tsdisplay(diff(attempt_ts), main="diff 3-pointer attempts", xlab="Year", ylab="attempts")

# plot(diff(per_ts))
# plot(diff(attempt_ts))
The first order differences look largely stationary. This and the auto.arima giving 0,1,0 implies that the trend is mostly a random walk.
Arima models
par(mfrow=c(1,2))
acf(per_ts)
pacf(per_ts)

per_fit <- auto.arima(per_ts, seasonal = FALSE)
acf(attempt_ts)
pacf(attempt_ts)

attempt_fit <- auto.arima(attempt_ts, seasonal = FALSE)
plot(forecast(per_fit, h=5), main="Forecasts from ARIMA", xlab="Year", ylab="3-pointer percentage")
plot(forecast(attempt_fit, h=5), main="Forecasts from ARIMA", xlab="Year", ylab="3-pointer attempts")

ARIMA stands for Autoregressive Integrated Moving Average models. Univariate (single vector) ARIMA is a forecasting technique that projects the future values of a series based entirely on its own inertia. Its main application is in the area of short term forecasting requiring at least 40 historical data points. It works best when your data exhibits a stable or consistent pattern over time with a minimum amount of outliers. Sometimes called Box-Jenkins (after the original authors), ARIMA is usually superior to exponential smoothing techniques when the data is reasonably long and the correlation between past observations is stable. If the data is short or highly volatile, then some smoothing method may perform better. If you do not have at least 38 data points, you should consider some other method than ARIMA.
From all these analyses we can say that 3-pointer shooting is not a fad due to one team but rather a long term trend that one team just capitalized on because they excelled at it.
LS0tCnRpdGxlOiAiVGhyZWUgcG9pbnRlciB0aW1lLXNlcmllcyBhbmFseXNpcyIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpyZXF1aXJlKHJlc2hhcGUpCmxpYnJhcnkoVFRSKQpsaWJyYXJ5KGZvcmVjYXN0KQpgYGAKCipMb2FkaW5nIGRhdGEqCmBgYHtyfQp0aHJlZXBfcGVyX29yZyA8LSByZWFkLmNzdignLi4vLi4vcmVzdWx0cy90ZWFtX2RhdGEvY29tYl8zcHBlci5jc3YnKQp5ZWFyX3JhbmdlIDwtIHRocmVlcF9wZXJfb3JnJFgKdGhyZWVwX3BlciA8LSBzdWJzZXQodGhyZWVwX3Blcl9vcmcsIHNlbGVjdD0tYyhYKSkKdGhyZWVwX2F0dGVtcHRfb3JnIDwtIHJlYWQuY3N2KCcuLi8uLi9yZXN1bHRzL3RlYW1fZGF0YS9jb21iXzNwYXR0ZW1wdC5jc3YnKQp5ZWFyX3JhbmdlIDwtIHRocmVlcF9hdHRlbXB0X29yZyRYCnRocmVlcF9hdHRlbXB0IDwtIHN1YnNldCh0aHJlZXBfYXR0ZW1wdF9vcmcsIHNlbGVjdD0tYyhYKSkKdGhyZWVwX21hZGVfb3JnIDwtIHJlYWQuY3N2KCcuLi8uLi9yZXN1bHRzL3RlYW1fZGF0YS9jb21iXzNwbWFkZS5jc3YnKQp5ZWFyX3JhbmdlIDwtIHRocmVlcF9tYWRlX29yZyRYCnRocmVlcF9tYWRlIDwtIHN1YnNldCh0aHJlZXBfbWFkZV9vcmcsIHNlbGVjdD0tYyhYKSkKYGBgCgoqUGxvdHRpbmcgdGhlIG1lYW4qIExvbmcgdGVybSB0cmVuZCBvciBmYWQ/CmBgYHtyfQphdmdfdGhyZWVwX3BlciA8LSByb3dNZWFucyh0aHJlZXBfcGVyLCBuYS5ybT1UUlVFKQphdmdfdGhyZWVwX2F0dGVtcHQgPC0gcm93TWVhbnModGhyZWVwX2F0dGVtcHQsIG5hLnJtPVRSVUUpCm1lYW5zX2RmIDwtIGRhdGEuZnJhbWUoJ0F2ZXJhZ2UgMy1wb2ludGVyIHBlcmNlbnRhZ2UnPWF2Z190aHJlZXBfcGVyLCAnQXZlcmFnZSAzLXBvaW50ZXIgYXR0ZW1wdHMnPWF2Z190aHJlZXBfYXR0ZW1wdCwgJ1llYXInPXllYXJfcmFuZ2UpCnBsb3QxIDwtIGdncGxvdChkYXRhPW1lYW5zX2RmLCBhZXMoWWVhciwgQXZlcmFnZS4zLnBvaW50ZXIucGVyY2VudGFnZSkpICsgZ2VvbV9saW5lKGxpbmV0eXBlPTIpICsgZ2VvbV9wb2ludChzaGFwZT0yMSwgZmlsbD0id2hpdGUiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0wLjMzLCBjb2w9InJlZCIsIGxpbmV0eXBlPTMpICsgZ2d0aXRsZSgnMy1wb2ludGVyIHBlcmNlbnRhZ2UnKQpwbG90MiA8LSBnZ3Bsb3QoZGF0YT1tZWFuc19kZiwgYWVzKFllYXIsIEF2ZXJhZ2UuMy5wb2ludGVyLmF0dGVtcHRzKSkgKyBnZW9tX2xpbmUobGluZXR5cGU9MikgKyBnZW9tX3BvaW50KHNoYXBlPTIxLCBmaWxsPSJ3aGl0ZSIpICsgZ2d0aXRsZSgnMy1wb2ludGVyIGF0dGVtcHRzJykKZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbD0yKQpgYGAKQWZ0ZXIgY3Jvc3NpbmcgMC4zMyBwZXJjZW50IGl0IGhhcyBsYXJnZWx5IHNhdHVyYXRlZC4gUGxvdCAyLXBvaW50ZXJzIHRvbwoKVGhlIGdvbGRlbiBzdGF0ZSB3YXJyaW9yIG91dGxpZXIKYGBge3J9CnJlcXVpcmUoZ3JpZEV4dHJhKQp5MSA9IGFzLm51bWVyaWModGhyZWVwX3BlclszNyxdKQp5MiA9IGFzLm51bWVyaWModGhyZWVwX3BlclsyNyxdKQpkZjEgPC0gZGF0YS5mcmFtZSgnU2Vhc29uIDIwMTYnPXkxLCAnU2Vhc29uIDIwMDYnPXkyKQpwbG90MSA8LSBnZ3Bsb3QoZGF0YSA9IGRmMSwgYWVzKFNlYXNvbi4yMDE2KSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJncmV5IiwgYmlucz02KSArIGdlb21fZGVuc2l0eShjb2w9InJlZCIsIGx0eT0yKSArIGdndGl0bGUoJ1NlYXNvbiAyMDE2JykgKyBsYWJzKHg9IjMtcG9pbnRlciBwZXJjZW50YWdlIikKcGxvdDIgPC0gZ2dwbG90KGRhdGEgPSBkZjEsIGFlcyhTZWFzb24uMjAwNikpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iZ3JleSIsIGJpbnM9OCkgKyBnZW9tX2RlbnNpdHkoY29sPSJyZWQiLCBsdHk9MikgKyBnZ3RpdGxlKCdTZWFzb24gMjAwNicpICsgbGFicyh4PSIzLXBvaW50ZXIgcGVyY2VudGFnZSIpCmdyaWQuYXJyYW5nZShwbG90MiwgcGxvdDEsIG5jb2w9MikKZGYyIDwtIG1lbHQoZGYxLCB2YXJpYWJsZV9uYW1lID0gJ1NlYXNvbicpCmdncGxvdChkYXRhID0gZGYyLCBhZXMoeD1TZWFzb24sIHk9dmFsdWUsIGZpbGw9U2Vhc29uKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXIgPSAicmVkIiwgb3V0bGllci5zaGFwZSA9IDIsIG5vdGNoID0gVFJVRSkgKyBnZ3RpdGxlKCdCb3ggcGxvdCBvZiAzLXBvaW50ZXIgcGVyY2VudGFnZScpICsgbGFicyh4PSdTZWFzb24nLCB5PSczLXBvaW50ZXIgcGVyY2VudGFnZScpCiMgcGFyKG1mcm93PWMoMSwyKSkKIyBxcW5vcm0oKHkxLW1lYW4oeTEpKS9zZCh5MSkpCiMgYWJsaW5lKDAsMSwgY29sPSJyZWQiKQojIHFxbm9ybSgoeTItbWVhbih5MikpL3NkKHkyKSkKIyBhYmxpbmUoMCwxLCBjb2w9InJlZCIpCmBgYApCdXQgdGhleSBkb24ndCBoYXZlIGFzIG11Y2ggYXMgYmlnIGRpZmZlcmVuY2UgaW4gYXR0ZW1wdHMKYGBge3J9CngxID0gYXMubnVtZXJpYyh0aHJlZXBfYXR0ZW1wdFszNyxdKQp4MiA9IGFzLm51bWVyaWModGhyZWVwX2F0dGVtcHRbMjcsXSkKZGYxIDwtIGRhdGEuZnJhbWUoJ1NlYXNvbiAyMDE2Jz14MSwgJ1NlYXNvbiAyMDA2Jz14MikKcGxvdDEgPC0gZ2dwbG90KGRhdGEgPSBkZjEsIGFlcyhTZWFzb24uMjAxNikpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2w9ImJsYWNrIiwgZmlsbD0iZ3JleSIsIGJpbnM9OSkgKyBnZW9tX2RlbnNpdHkoY29sPSJyZWQiLCBsdHk9MikgKyBnZ3RpdGxlKCdTZWFzb24gMjAxNicpICsgbGFicyh4PSIzLXBvaW50ZXIgYXR0ZW1wdHMiKQpwbG90MiA8LSBnZ3Bsb3QoZGF0YSA9IGRmMSwgYWVzKFNlYXNvbi4yMDA2KSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbD0iYmxhY2siLCBmaWxsPSJncmV5IiwgYmlucz05KSArIGdlb21fZGVuc2l0eShjb2w9InJlZCIsIGx0eT0yKSArIGdndGl0bGUoJ1NlYXNvbiAyMDA2JykgKyBsYWJzKHg9IjMtcG9pbnRlciBhdHRlbXB0cyIpCmdyaWQuYXJyYW5nZShwbG90MiwgcGxvdDEsIG5jb2w9MikKZGYyIDwtIG1lbHQoZGYxLCB2YXJpYWJsZV9uYW1lID0gJ1NlYXNvbicpCmdncGxvdChkYXRhID0gZGYyLCBhZXMoeD1TZWFzb24sIHk9dmFsdWUsIGZpbGw9U2Vhc29uKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXIgPSAicmVkIiwgb3V0bGllci5zaGFwZSA9IDIsIG5vdGNoID0gVFJVRSkgKyBnZ3RpdGxlKCdCb3ggcGxvdCBvZiAzLXBvaW50ZXIgYXR0ZW1wdHMnKSArIGxhYnMoeD0nU2Vhc29uJywgeT0nMy1wb2ludGVyIGF0dGVtcHRzJykKIyBwYXIobWZyb3c9YygxLDIpKQojIHFxbm9ybSgoeDEtbWVhbih4MSkpL3NkKHgxKSkKIyBhYmxpbmUoMCwxLCBjb2w9InJlZCIpCiMgcXFub3JtKCh4Mi1tZWFuKHgyKSkvc2QoeDIpKQojIGFibGluZSgwLDEsIGNvbD0icmVkIikKYGBgCgoqUGxvdHRpbmcgcGVyIHRlYW0gcGVyIHllYXIgZGF0YSoKYGBge3J9CnRocmVlcF9hbmFsIDwtIGZ1bmN0aW9uKGZuYW1lLCBpbmQpCnsKICAgIGRhdGEgPC0gcmVhZC5jc3YoZm5hbWUpCiAgICBkZiA8LSBtZWx0KGRhdGEsIGlkLnZhcnM9J1gnLCB2YXJpYWJsZV9uYW1lID0gJ3RlYW1zJykKICAgIGdncGxvdChkZiwgYWVzKFgsdmFsdWUpKSArIGdlb21fbGluZShhZXMoY29sb3VyID0gdGVhbXMpKQogICAgIyBTbW9vdGhpbmcgbW92aW5nIGF2ZXJhZ2UKICAgIGNvbF9uYW1lcyA8LSBuYW1lcyhkYXRhKQogICAgIyBGSVhNRTogRnVkZ2luZyBkYXRhIGZvciB0aGVzZSB0d28geWVhcnMgKEludGVycG9sYXRpb24pCiAgICBpZiAoaW5kPT0xKQogICAgewogICAgICBkYXRhWzI0LCAnQ0hBJ10gPC0gMC4zNTMKICAgICAgZGF0YVsyNSwgJ0NIQSddIDwtIDAuMzU3CiAgICB9CiAgICBpZiAoaW5kPT0yKQogICAgewogICAgICBkYXRhWzI0LCAnQ0hBJ10gPC0gMTEuNAogICAgICBkYXRhWzI1LCAnQ0hBJ10gPC0gMTEuNAogICAgfQogICAgc21vb3RoX2RhdGEgPC0gZGF0YS5mcmFtZSh0aW1lID0gZGF0YVsiWCJdKQogICAgZm9yIChjb2xfbmFtZSBpbiBjb2xfbmFtZXNbMjpuY29sKGRhdGEpXSkKICAgIHsKICAgICAgICBzbW9vdGhfZGF0YVtjb2xfbmFtZV0gPC0gU01BKGRhdGFbY29sX25hbWVdLCBuPTMpCiAgICB9CiAgICBkZjIgPC0gbWVsdChzbW9vdGhfZGF0YSwgaWQudmFycz0nWCcsIHZhcmlhYmxlX25hbWUgPSAndGVhbXMnKQoKfQoKdGhyZWVwX3Blcl9zbW9vdGggPC0gdGhyZWVwX2FuYWwoJy4uLy4uL3Jlc3VsdHMvdGVhbV9kYXRhL2NvbWJfM3BwZXIuY3N2JywgMSkKdGhyZWVwX2F0dGVtcHRfc21vb3RoIDwtIHRocmVlcF9hbmFsKCcuLi8uLi9yZXN1bHRzL3RlYW1fZGF0YS9jb21iXzNwYXR0ZW1wdC5jc3YnLCAyKQpwYXIobWZyb3c9YygxLDIpKQpkZjEgPC0gbWVsdCh0aHJlZXBfcGVyX29yZywgaWQudmFycz0nWCcsIHZhcmlhYmxlX25hbWUgPSAndGVhbXMnKQpnZ3Bsb3QoZGYxLCBhZXMoWCx2YWx1ZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvdXIgPSB0ZWFtcykpICsgZ2d0aXRsZSgnVW5zbW9vdGhlbmVkIGRhdGEnKSArIGxhYnMoeD0neWVhcicsIHk9JzMtcG9pbnRlciBwZXJjZW50YWdlJykKZ2dwbG90KHRocmVlcF9wZXJfc21vb3RoLCBhZXMoWCx2YWx1ZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvdXIgPSB0ZWFtcykpICsgZ2d0aXRsZSgnU21vb3RoZW5lZCBkYXRhJykgKyBsYWJzKHg9J3llYXInLCB5PSczLXBvaW50ZXIgcGVyY2VudGFnZScpCnBhcihtZnJvdz1jKDEsMikpCmRmMiA8LSBtZWx0KHRocmVlcF9hdHRlbXB0X29yZywgaWQudmFycz0nWCcsIHZhcmlhYmxlX25hbWUgPSAndGVhbXMnKQpnZ3Bsb3QoZGYyLCBhZXMoWCx2YWx1ZSkpICsgZ2VvbV9saW5lKGFlcyhjb2xvdXIgPSB0ZWFtcykpICsgZ2d0aXRsZSgnVW5zbW9vdGhlbmVkIGRhdGEnKSArIGxhYnMoeD0neWVhcicsIHk9JzMtcG9pbnRlciBhdHRlbXB0cycpCmdncGxvdCh0aHJlZXBfYXR0ZW1wdF9zbW9vdGgsIGFlcyhYLHZhbHVlKSkgKyBnZW9tX2xpbmUoYWVzKGNvbG91ciA9IHRlYW1zKSkgKyBnZ3RpdGxlKCdTbW9vdGhlbmVkIGRhdGEnKSArIGxhYnMoeD0neWVhcicsIHk9JzMtcG9pbnRlciBhdHRlbXB0cycpCmBgYAoKKkxvb2tpbmcgYXQgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlKgpgYGB7cn0KdC50ZXN0KHkxLHkyKQp5MyA8LSBhcy5udW1lcmljKHRocmVlcF9wZXJbMTcsXSkKdC50ZXN0KHkxLHkzKQpgYGAKSGVuY2UgdGhyZWVwb2ludGVyIHBlcmNlbnQgbG9va3MgbW9yZSBvciBsZXNzIHRoZSBzYW1lCgpgYGB7cn0KeDEgPC0gYXMubnVtZXJpYyh0aHJlZXBfYXR0ZW1wdFszNyxdKQp4MiA8LSBhcy5udW1lcmljKHRocmVlcF9hdHRlbXB0WzI3LF0pCngzIDwtIGFzLm51bWVyaWModGhyZWVwX2F0dGVtcHRbMTcsXSkKdC50ZXN0KHgxLHgyKQp0LnRlc3QoeDEseDMpCmBgYAoKKlRpbWUgc2VyaWVzIGFuYWx5c2lzKgpIb2x0V2ludGVycyBwcmVkaWN0aW9ucwpgYGB7cn0KYXZnX3RocmVlcF9wZXJbMTY6MThdIDwtIGMoTkEsIE5BLCBOQSkKYXZnX3RocmVlcF9wZXIgPC0gbmEuYXBwcm94KGF2Z190aHJlZXBfcGVyKQpwZXJfdHMgPC0gdHMoYXZnX3RocmVlcF9wZXIsIHN0YXJ0PWhlYWQoeWVhcl9yYW5nZSxuPTEpKQphdmdfdGhyZWVwX2F0dGVtcHRbMTY6MThdIDwtIGMoTkEsIE5BLCBOQSkKYXZnX3RocmVlcF9hdHRlbXB0IDwtIG5hLmFwcHJveChhdmdfdGhyZWVwX2F0dGVtcHQpCmF0dGVtcHRfdHMgPC0gdHMoYXZnX3RocmVlcF9hdHRlbXB0LCBzdGFydD1oZWFkKHllYXJfcmFuZ2Usbj0xKSkKdHNfZGYgPC0gZGF0YS5mcmFtZShZZWFyPXllYXJfcmFuZ2UsIHBlcmNlbnRhZ2U9YXZnX3RocmVlcF9wZXIsIGF0dGVtcHRzPWF2Z190aHJlZXBfYXR0ZW1wdCkKcGxvdDEgPC0gZ2dwbG90KGRhdGE9dHNfZGYsIGFlcyh4PVllYXIsIHk9cGVyY2VudGFnZSkpICsgZ2VvbV9saW5lKCkgKyBnZ3RpdGxlKCczLXBvaW50ZXIgcGVyY2VudGFnZScpICsgbGFicyh4PSJZZWFyIiwgeT0iMy1wb2ludGVyIHBlcmNlbnRhZ2UiKSArIGdlb21fc21vb3RoKGNvbD0icmVkIiwgbHR5PTIpCnBsb3QyIDwtIGdncGxvdChkYXRhPXRzX2RmLCBhZXMoeD1ZZWFyLCB5PWF0dGVtcHRzKSkgKyBnZW9tX2xpbmUoKSArIGdndGl0bGUoJzMtcG9pbnRlciBhdHRlbXB0cycpICsgbGFicyh4PSJZZWFyIiwgeT0iMy1wb2ludGVyIGF0dGVtcHRzIikgKyBnZW9tX3Ntb290aChjb2w9InJlZCIsIGx0eT0yKQpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBuY29sPTIpCmBgYApnYW1tYT1GYWxzZSBtZWFucyBub24tc2Vhc29uYWwKYGBge3J9CnBhcihtZnJvdz1jKDEsMikpCnBlcl9mb3JlY2FzdHMgPC0gSG9sdFdpbnRlcnMocGVyX3RzLCBnYW1tYT1GQUxTRSkKcGxvdChwZXJfZm9yZWNhc3RzLCB4bGFiPSJZZWFyIiwgeWxhYj0iMy1wb2ludGVyIHBlcmNlbnRhZ2UiKQpwZXJfZm9yZWNhc3RzJFNTRQpwZXJfZnV0dXJlIDwtIGZvcmVjYXN0LkhvbHRXaW50ZXJzKHBlcl9mb3JlY2FzdHMsIGg9NSkKYXR0ZW1wdF9mb3JlY2FzdHMgPC0gSG9sdFdpbnRlcnMoYXR0ZW1wdF90cywgZ2FtbWE9RkFMU0UpCnBsb3QoYXR0ZW1wdF9mb3JlY2FzdHMsIHhsYWI9IlllYXIiLCB5bGFiPSIzLXBvaW50ZXIgYXR0ZW1wdHMiKQphdHRlbXB0X2ZvcmVjYXN0cyRTU0UKYXR0ZW1wdF9mdXR1cmUgPC0gZm9yZWNhc3QuSG9sdFdpbnRlcnMoYXR0ZW1wdF9mb3JlY2FzdHMsIGg9NSkKcGxvdC5mb3JlY2FzdChwZXJfZnV0dXJlLCB4bGFiPSJZZWFyIiwgeWxhYj0iMy1wb2ludGVyIHBlcmNlbnRhZ2UiKQpwbG90LmZvcmVjYXN0KGF0dGVtcHRfZnV0dXJlLCB4bGFiPSJZZWFyIiwgeWxhYj0iMy1wb2ludGVyIGF0dGVtcHRzIikKYGBgCmBgYHtyfQp0c2Rpc3BsYXkoZGlmZihwZXJfdHMpLCBtYWluPSJkaWZmIDMtcG9pbnRlciBwZXJjZW50YWdlIiwgeGxhYj0iWWVhciIsIHlsYWI9InBlcmNlbnRhZ2UiKQp0c2Rpc3BsYXkoZGlmZihhdHRlbXB0X3RzKSwgbWFpbj0iZGlmZiAzLXBvaW50ZXIgYXR0ZW1wdHMiLCB4bGFiPSJZZWFyIiwgeWxhYj0iYXR0ZW1wdHMiKQojIHBsb3QoZGlmZihwZXJfdHMpKQojIHBsb3QoZGlmZihhdHRlbXB0X3RzKSkKYGBgClRoZSBmaXJzdCBvcmRlciBkaWZmZXJlbmNlcyBsb29rIGxhcmdlbHkgc3RhdGlvbmFyeS4gVGhpcyBhbmQgdGhlIGF1dG8uYXJpbWEgZ2l2aW5nIDAsMSwwIGltcGxpZXMgdGhhdCB0aGUgdHJlbmQgaXMgbW9zdGx5IGEgcmFuZG9tIHdhbGsuCgpBcmltYSBtb2RlbHMKYGBge3J9CnBhcihtZnJvdz1jKDEsMikpCmFjZihwZXJfdHMpCnBhY2YocGVyX3RzKQpwZXJfZml0IDwtIGF1dG8uYXJpbWEocGVyX3RzLCBzZWFzb25hbCA9IEZBTFNFKQphY2YoYXR0ZW1wdF90cykKcGFjZihhdHRlbXB0X3RzKQphdHRlbXB0X2ZpdCA8LSBhdXRvLmFyaW1hKGF0dGVtcHRfdHMsIHNlYXNvbmFsID0gRkFMU0UpCnBhcihtZnJvdz1jKDEsMikpCnBsb3QoZm9yZWNhc3QocGVyX2ZpdCwgaD01KSwgbWFpbj0iRm9yZWNhc3RzIGZyb20gQVJJTUEiLCB4bGFiPSJZZWFyIiwgeWxhYj0iMy1wb2ludGVyIHBlcmNlbnRhZ2UiKQpwbG90KGZvcmVjYXN0KGF0dGVtcHRfZml0LCBoPTUpLCBtYWluPSJGb3JlY2FzdHMgZnJvbSBBUklNQSIsIHhsYWI9IlllYXIiLCB5bGFiPSIzLXBvaW50ZXIgYXR0ZW1wdHMiKQpgYGAKQVJJTUEgc3RhbmRzIGZvciBBdXRvcmVncmVzc2l2ZSBJbnRlZ3JhdGVkIE1vdmluZyBBdmVyYWdlIG1vZGVscy4gVW5pdmFyaWF0ZSAoc2luZ2xlIHZlY3RvcikgQVJJTUEgaXMgYSBmb3JlY2FzdGluZyB0ZWNobmlxdWUgdGhhdCBwcm9qZWN0cyB0aGUgZnV0dXJlIHZhbHVlcyBvZiBhIHNlcmllcyBiYXNlZCBlbnRpcmVseSBvbiBpdHMgb3duIGluZXJ0aWEuIEl0cyBtYWluIGFwcGxpY2F0aW9uIGlzIGluIHRoZSBhcmVhIG9mIHNob3J0IHRlcm0gZm9yZWNhc3RpbmcgcmVxdWlyaW5nIGF0IGxlYXN0IDQwIGhpc3RvcmljYWwgZGF0YSBwb2ludHMuIEl0IHdvcmtzIGJlc3Qgd2hlbiB5b3VyIGRhdGEgZXhoaWJpdHMgYSBzdGFibGUgb3IgY29uc2lzdGVudCBwYXR0ZXJuIG92ZXIgdGltZSB3aXRoIGEgbWluaW11bSBhbW91bnQgb2Ygb3V0bGllcnMuIFNvbWV0aW1lcyBjYWxsZWQgQm94LUplbmtpbnMgKGFmdGVyIHRoZSBvcmlnaW5hbCBhdXRob3JzKSwgQVJJTUEgaXMgdXN1YWxseSBzdXBlcmlvciB0byBleHBvbmVudGlhbCBzbW9vdGhpbmcgdGVjaG5pcXVlcyB3aGVuIHRoZSBkYXRhIGlzIHJlYXNvbmFibHkgbG9uZyBhbmQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gcGFzdCBvYnNlcnZhdGlvbnMgaXMgc3RhYmxlLiBJZiB0aGUgZGF0YSBpcyBzaG9ydCBvciBoaWdobHkgdm9sYXRpbGUsIHRoZW4gc29tZSBzbW9vdGhpbmcgbWV0aG9kIG1heSBwZXJmb3JtIGJldHRlci4gSWYgeW91IGRvIG5vdCBoYXZlIGF0IGxlYXN0IDM4IGRhdGEgcG9pbnRzLCB5b3Ugc2hvdWxkIGNvbnNpZGVyIHNvbWUgb3RoZXIgbWV0aG9kIHRoYW4gQVJJTUEuCgoKRnJvbSBhbGwgdGhlc2UgYW5hbHlzZXMgd2UgY2FuIHNheSB0aGF0IDMtcG9pbnRlciBzaG9vdGluZyBpcyBub3QgYSBmYWQgZHVlIHRvIG9uZSB0ZWFtIGJ1dCByYXRoZXIgYSBsb25nIHRlcm0gdHJlbmQgdGhhdCBvbmUgdGVhbSBqdXN0IGNhcGl0YWxpemVkIG9uIGJlY2F1c2UgdGhleSBleGNlbGxlZCBhdCBpdC4K