# Load libraries and read the data
library(dplyr)
library(TSA)
library(magrittr)
Ozone <- read.csv('data1.csv', header =FALSE)
rownames(Ozone) <- seq(from=1927, to=2016)
head(Ozone)
Ozone <- ts(as.vector(Ozone), start = 1927, end=2016)#convert df to a ts object
plot(Ozone,type='o',ylab='Ozone Layer Thickness (DU)',
main="Time series plot of Ozone layer thickness series") #create a time series plot

- Trend : we do see a downward trend in the plot.
- Seasonality : cannot conclude at this stage.
- Behaviour: Appears to be Auto Regressive.
- Intervention: We may want to explore if something major happened around year 1992-93
- Changing Variance: more or less variance remains the same
I. Trying to fit a linear model
model_lm = lm(Ozone ~time(Ozone)) #define the linear regression model
plot(Ozone,type= 'o',ylab='y')
abline(model_lm) #add the fitted least square line to the model

summary(model_lm)
Call:
lm(formula = Ozone ~ time(Ozone))
Residuals:
Min 1Q Median 3Q Max
-4.7165 -1.6687 0.0275 1.4726 4.7940
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 213.720155 16.257158 13.15 <2e-16 ***
time(Ozone) -0.110029 0.008245 -13.34 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 2.032 on 88 degrees of freedom
Multiple R-squared: 0.6693, Adjusted R-squared: 0.6655
F-statistic: 178.1 on 1 and 88 DF, p-value: < 2.2e-16
- The coefficient of both intercept and linear component is statistically significant.
- coefficient of determination R2 appears to be fine at 0.6655, not too high or too low.
Assessing the quality of the linear model
Residual Analysis:
residual_model_lm = rstudent(model_lm) #rstudent() computes standardised residual
plot(y=residual_model_lm, x=as.vector(time(Ozone)),xlab = 'Time', ylab='Standardized Residuals',type = 'o')

- There is somewhat departure from randomness in the above residual plot.
Next, we look at the standardized residuals versus the corresponding trend estimate, or fitted value
plot(y=rstudent(model_lm), x=fitted(model_lm),
xlab ="Fitted Trend Value", ylab ='Standardized Residuals')

- There is no obvious trend in the residuals, however we do see variation with different fitted trend values.
Check the Normality of residuals with a histogram.
hist(rstudent(model_lm), xlab = "Standardized Residuals",
main = "Histogram of Standardized Residuals of Model")

- The plot appears somewhat symmetric and tails off at the low and high end reciprocating the behaviour of a normal distribution.
Check normality assumption with the quantile-quantile (QQ) plot
z = rstudent(model_lm)
qqnorm(z) #produce a qq plot of the residuals
qqline(z , col = 3 , lwd = 1)

- For a normaly distributed data the QQ plot aprrox like a straight line but in the above plot, the line doesnt capture all the points. The straight-line pattern here doesnt fully captures the assumption of normally distributed stochastic component in the model.
Hypothesis test: Shapiro-Wilk test is used to check the normality assumption of the stochastic component
s = rstudent(model_lm)
shapiro.test(s)
Shapiro-Wilk normality test
data: s
W = 0.98733, p-value = 0.5372
- We get the p-value of 0.5372.Hence, we fail to reject the null hypothesis i.e. the stochastic component of this model is normally distributed.
ACF(Autocorrelation function) for analysis of Time Series
##Find the significance autorcorrelation in standardised Residuals
acf(rstudent(model_lm), main="ACF of standardized residuals")

- There is some trend and some autrocorrelation left in the Residuals as deterministic model cannot completely capture it.
II. Trying to fit a Quadratic model
t=time(Ozone) #linear component
t2=t^2 #take square of time for the quadratic component
model_quad = lm(Ozone ~ t+t2) #create a quadratic model
plot(ts(fitted(model_quad)),ylim = c(min(c(fitted(model_quad),as.vector(Ozone))),
max(c(fitted(model_quad),as.vector(Ozone)))),ylab='y' ,
main = "Fitted quadratic curve to Ozone data")
lines(as.vector(Ozone),type='o')

summary(model_quad)
Call:
lm(formula = Ozone ~ t + t2)
Residuals:
Min 1Q Median 3Q Max
-5.1062 -1.2846 -0.0055 1.3379 4.2325
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -5.733e+03 1.232e+03 -4.654 1.16e-05 ***
t 5.924e+00 1.250e+00 4.739 8.30e-06 ***
t2 -1.530e-03 3.170e-04 -4.827 5.87e-06 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.815 on 87 degrees of freedom
Multiple R-squared: 0.7391, Adjusted R-squared: 0.7331
F-statistic: 123.3 on 2 and 87 DF, p-value: < 2.2e-16
- The coefficient of quadratic component is statistically significant.
- coefficient of determination R2 (0.7331) is better than that of the linear model(0.6655).
Assessing the quality of the Quadratic model
Residual Analysis:
residual_model_qd = rstudent(model_quad)
plot(y=residual_model_qd, x=as.vector(time(Ozone)),xlab = 'Time', ylab='Standardized Residuals',type='o')

- There is departure from randomness in the above residual plot. The plot is smooth at multiple place, so it cant be concluded as a white noise.
Next, we look at the standardized residuals versus the corresponding trend estimate, or fitted value
plot(y=rstudent(model_quad), x=fitted(model_quad),
xlab ="Fitted Trend Value", ylab ='Standardized Residuals')

- We do see variation with different fitted trend values.
Check the Normality of residuals with a histogram
hist(rstudent(model_quad), xlab = "Standardized Residuals",
main = "Histogram of Standardized Residuals of Model")

- The plot is not symmetric and so the residuals doesnt fulfill the normality assumption.
Check normality assumption with the quantile-quantile (QQ) plot
q = rstudent(model_quad)
qqnorm(q)
qqline(q , col = 2 , lwd = 1)

- For a normaly distributed data the QQ plot aprrox like a straight line. In the above plot, the line almost captures all the points, better than a linear model. The straight-line pattern here does supports the assumption of normally distributed stochastic component in the model.
Hypothesis test: Shapiro-Wilk test is used to check the normality assumption of the stochastic component
s=rstudent(model_quad)
shapiro.test(s)
Shapiro-Wilk normality test
data: s
W = 0.98889, p-value = 0.6493
- We get the p-value of 0.6493. Hence, we fail to reject the null hypothesis i.e. the stochastic component of this model is normally distributed.
ACF(Autocorrelation function) for analysis of Time Series
##Find the significance autorcorrelation in standardised Residuals
acf(rstudent(model_quad), main="ACF of standardized residuals")

Forecasting
t = c(2017,2018,2019,2020,2021) # create a time vector for next five years
t2 = t^2
new = data.frame(t,t2) #create a new data frame with t and t2
forecasts = predict(model_quad,new, interval = "prediction")
plot(Ozone,ylab= "Ozone Layer Thickness(DU)",ylim = c(-15,3),xlim=c(1927,2021),main="Time series plot of Ozone layer thickness series")
# convert forecasts to time series object starting from the first
# time steps-ahead to be able to use plot function
lines(ts(as.vector(forecasts[,1]), start = 2016), col="red", type="l",lwd=2)
lines(ts(as.vector(forecasts[,2]), start = 2016), col="blue", type="l",lwd=2)
lines(ts(as.vector(forecasts[,3]), start = 2016), col="blue", type="l",lwd=2)
legend("bottomleft", lty=1, pch=1,bty = "n", col=c("black","blue","red"), text.width = 18,
c("Data","5% forecast limit", "Forecasts"))

- The quadratic model fitted to original ozone layer thickness series showing forecast for another five years(2017 to 2021).
Conclusion
- A linear and qudratic model was analysed for suitability for the provided data set.
- Neither models appears to be the best fit for the given stochastic trend.
- According to multiple R2 74% of the variation in the Ozone layer thickness data is explained by the quadratic model against 67% by the linear model.
- Also, model fitting using the quadratic model captured the trend better than the linear model.
- Hence, quadratic model was selected and used for forecasting.
LS0tCnRpdGxlOiAiTUFUSDEzMTggU2VtZXN0ZXIgMSwgMjAxOSIKYXV0aG9yOiAiQWhtYWQgSGFzbmFpbihTMzcxMjUzOCkiCnN1YnRpdGxlOiBGb3JlY2FzdGluZyBPem9uZSBMYXllciB0aGlja25lcyBiYXNlZCBvbiBkYXRhIGZyb20gMTkyNyB0byAyMDE2Cm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9CiMgTG9hZCBsaWJyYXJpZXMgYW5kIHJlYWQgdGhlIGRhdGEgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoVFNBKQpsaWJyYXJ5KG1hZ3JpdHRyKQpPem9uZSA8LSByZWFkLmNzdignZGF0YTEuY3N2JywgaGVhZGVyID1GQUxTRSkKcm93bmFtZXMoT3pvbmUpIDwtIHNlcShmcm9tPTE5MjcsIHRvPTIwMTYpCmhlYWQoT3pvbmUpCk96b25lIDwtIHRzKGFzLnZlY3RvcihPem9uZSksIHN0YXJ0ID0gMTkyNywgZW5kPTIwMTYpI2NvbnZlcnQgZGYgdG8gYSB0cyBvYmplY3QKcGxvdChPem9uZSx0eXBlPSdvJyx5bGFiPSdPem9uZSBMYXllciBUaGlja25lc3MgKERVKScsCm1haW49IlRpbWUgc2VyaWVzIHBsb3Qgb2YgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIHNlcmllcyIpICNjcmVhdGUgYSB0aW1lIHNlcmllcyBwbG90CgpgYGAKCiogIE9ic2VydmF0aW9uczoKMS4gVHJlbmQgOiAgd2UgZG8gc2VlIGEgZG93bndhcmQgdHJlbmQgaW4gdGhlIHBsb3QuIAoyLiBTZWFzb25hbGl0eSA6ICBjYW5ub3QgY29uY2x1ZGUgYXQgdGhpcyBzdGFnZS4KMy4gQmVoYXZpb3VyOiBBcHBlYXJzIHRvIGJlIEF1dG8gUmVncmVzc2l2ZS4gCjQuIEludGVydmVudGlvbjogV2UgbWF5IHdhbnQgdG8gZXhwbG9yZSBpZiBzb21ldGhpbmcgbWFqb3IgaGFwcGVuZWQgYXJvdW5kIHllYXIgMTk5Mi05Mwo1LiBDaGFuZ2luZyBWYXJpYW5jZTogbW9yZSBvciBsZXNzIHZhcmlhbmNlIHJlbWFpbnMgdGhlIHNhbWUgCgojIyBJLiBUcnlpbmcgdG8gZml0IGEgbGluZWFyIG1vZGVsCmBgYHtyfQptb2RlbF9sbSA9IGxtKE96b25lIH50aW1lKE96b25lKSkgI2RlZmluZSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwKcGxvdChPem9uZSx0eXBlPSAnbycseWxhYj0neScpCmFibGluZShtb2RlbF9sbSkgI2FkZCB0aGUgZml0dGVkIGxlYXN0IHNxdWFyZSBsaW5lIHRvIHRoZSBtb2RlbApzdW1tYXJ5KG1vZGVsX2xtKSAKYGBgCiogT2JzZXJ2YXRpb25zOgoxLiBUaGUgY29lZmZpY2llbnQgb2YgYm90aCBpbnRlcmNlcHQgYW5kIGxpbmVhciBjb21wb25lbnQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KMi4gKmNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24qIFJeMl4gYXBwZWFycyB0byBiZSBmaW5lIGF0IDAuNjY1NSwgbm90IHRvbyBoaWdoIG9yIHRvbyBsb3cuIAoKIyMjIEFzc2Vzc2luZyB0aGUgcXVhbGl0eSBvZiB0aGUgbGluZWFyIG1vZGVsIAojIyMjIyBSZXNpZHVhbCBBbmFseXNpczogCgpgYGB7cn0KcmVzaWR1YWxfbW9kZWxfbG0gPSByc3R1ZGVudChtb2RlbF9sbSkgI3JzdHVkZW50KCkgY29tcHV0ZXMgc3RhbmRhcmRpc2VkIHJlc2lkdWFsCnBsb3QoeT1yZXNpZHVhbF9tb2RlbF9sbSwgeD1hcy52ZWN0b3IodGltZShPem9uZSkpLHhsYWIgPSAnVGltZScsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLHR5cGUgPSAnbycpCmBgYAoqIFRoZXJlIGlzIHNvbWV3aGF0IGRlcGFydHVyZSBmcm9tIHJhbmRvbW5lc3MgaW4gdGhlIGFib3ZlIHJlc2lkdWFsIHBsb3QuIAoKIyMjIyMgTmV4dCwgd2UgbG9vayBhdCB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscyB2ZXJzdXMgdGhlIGNvcnJlc3BvbmRpbmcgdHJlbmQgZXN0aW1hdGUsIG9yIGZpdHRlZCB2YWx1ZSAKCmBgYHtyfQpwbG90KHk9cnN0dWRlbnQobW9kZWxfbG0pLCB4PWZpdHRlZChtb2RlbF9sbSksCnhsYWIgPSJGaXR0ZWQgVHJlbmQgVmFsdWUiLCB5bGFiID0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycpCmBgYAoKKiBUaGVyZSBpcyBubyBvYnZpb3VzIHRyZW5kIGluIHRoZSByZXNpZHVhbHMsIGhvd2V2ZXIgd2UgZG8gc2VlIHZhcmlhdGlvbiB3aXRoIGRpZmZlcmVudCBmaXR0ZWQgdHJlbmQgdmFsdWVzLiAKCiMjIyBDaGVjayB0aGUgTm9ybWFsaXR5IG9mIHJlc2lkdWFscyB3aXRoIGEgaGlzdG9ncmFtLgoKYGBge3J9Cmhpc3QocnN0dWRlbnQobW9kZWxfbG0pLCB4bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCAKbWFpbiA9ICJIaXN0b2dyYW0gb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFscyBvZiBNb2RlbCIpCmBgYAoqIFRoZSBwbG90IGFwcGVhcnMgc29tZXdoYXQgc3ltbWV0cmljIGFuZCB0YWlscyBvZmYgYXQgdGhlIGxvdyBhbmQgaGlnaCBlbmQgcmVjaXByb2NhdGluZyB0aGUgYmVoYXZpb3VyIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gIAoKIyMjIENoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHdpdGggdGhlIHF1YW50aWxlLXF1YW50aWxlIChRUSkgcGxvdAoKYGBge3J9CnogPSByc3R1ZGVudChtb2RlbF9sbSkKcXFub3JtKHopICNwcm9kdWNlIGEgcXEgcGxvdCBvZiB0aGUgcmVzaWR1YWxzIApxcWxpbmUoeiAsIGNvbCA9IDMgLCBsd2QgPSAxKSAKYGBgCgoqIEZvciBhIG5vcm1hbHkgZGlzdHJpYnV0ZWQgZGF0YSB0aGUgUVEgcGxvdCBhcHJyb3ggbGlrZSBhIHN0cmFpZ2h0IGxpbmUgYnV0IGluIHRoZSBhYm92ZSBwbG90LCB0aGUgbGluZSBkb2VzbnQgY2FwdHVyZSBhbGwgdGhlIHBvaW50cy4gVGhlIHN0cmFpZ2h0LWxpbmUgcGF0dGVybiBoZXJlIGRvZXNudCBmdWxseSBjYXB0dXJlcyB0aGUgYXNzdW1wdGlvbiBvZiBub3JtYWxseSBkaXN0cmlidXRlZCBzdG9jaGFzdGljIGNvbXBvbmVudCBpbiB0aGUgbW9kZWwuIAoKCiMjIyBIeXBvdGhlc2lzIHRlc3Q6ICpTaGFwaXJvLVdpbGsqIHRlc3QgaXMgdXNlZCB0byBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gb2YgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IAoKYGBge3J9CnMgPSByc3R1ZGVudChtb2RlbF9sbSkKc2hhcGlyby50ZXN0KHMpCmBgYAoqIFdlIGdldCB0aGUgcC12YWx1ZSBvZiAwLjUzNzIuSGVuY2UsIHdlIGZhaWwgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgaS5lLgp0aGUgc3RvY2hhc3RpYyBjb21wb25lbnQgb2YgdGhpcyBtb2RlbCBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4KCiMjIyBBQ0YoQXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9uKSBmb3IgYW5hbHlzaXMgb2YgVGltZSBTZXJpZXMKYGBge3J9CiMjRmluZCB0aGUgc2lnbmlmaWNhbmNlIGF1dG9yY29ycmVsYXRpb24gaW4gc3RhbmRhcmRpc2VkIFJlc2lkdWFscwphY2YocnN0dWRlbnQobW9kZWxfbG0pLCBtYWluPSJBQ0Ygb2Ygc3RhbmRhcmRpemVkIHJlc2lkdWFscyIpCmBgYAoqIFRoZXJlIGlzIHNvbWUgdHJlbmQgYW5kIHNvbWUgYXV0cm9jb3JyZWxhdGlvbiBsZWZ0IGluIHRoZSBSZXNpZHVhbHMgYXMgZGV0ZXJtaW5pc3RpYyBtb2RlbCBjYW5ub3QgY29tcGxldGVseSBjYXB0dXJlIGl0LgoKIyMgSUkuIFRyeWluZyB0byBmaXQgYSBRdWFkcmF0aWMgbW9kZWwKCmBgYHtyfQp0PXRpbWUoT3pvbmUpICNsaW5lYXIgY29tcG9uZW50IAp0Mj10XjIgI3Rha2Ugc3F1YXJlIG9mIHRpbWUgZm9yIHRoZSBxdWFkcmF0aWMgY29tcG9uZW50IAptb2RlbF9xdWFkID0gbG0oT3pvbmUgfiB0K3QyKSAjY3JlYXRlIGEgcXVhZHJhdGljIG1vZGVsIAoKcGxvdCh0cyhmaXR0ZWQobW9kZWxfcXVhZCkpLHlsaW0gPSBjKG1pbihjKGZpdHRlZChtb2RlbF9xdWFkKSxhcy52ZWN0b3IoT3pvbmUpKSksCm1heChjKGZpdHRlZChtb2RlbF9xdWFkKSxhcy52ZWN0b3IoT3pvbmUpKSkpLHlsYWI9J3knICwKbWFpbiA9ICJGaXR0ZWQgcXVhZHJhdGljIGN1cnZlIHRvIE96b25lIGRhdGEiKQpsaW5lcyhhcy52ZWN0b3IoT3pvbmUpLHR5cGU9J28nKQoKc3VtbWFyeShtb2RlbF9xdWFkKQpgYGAKKiBPYnNlcnZhdGlvbnM6CjEuIFRoZSBjb2VmZmljaWVudCBvZiBxdWFkcmF0aWMgY29tcG9uZW50IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuCjIuICpjb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKiBSXjJeICgwLjczMzEpIGlzIGJldHRlciB0aGFuIHRoYXQgb2YgdGhlIGxpbmVhciBtb2RlbCgwLjY2NTUpLgoKIyMjIEFzc2Vzc2luZyB0aGUgcXVhbGl0eSBvZiB0aGUgUXVhZHJhdGljIG1vZGVsIAojIyMjIyBSZXNpZHVhbCBBbmFseXNpczogCmBgYHtyfQpyZXNpZHVhbF9tb2RlbF9xZCA9IHJzdHVkZW50KG1vZGVsX3F1YWQpCnBsb3QoeT1yZXNpZHVhbF9tb2RlbF9xZCwgeD1hcy52ZWN0b3IodGltZShPem9uZSkpLHhsYWIgPSAnVGltZScsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLHR5cGU9J28nKQpgYGAKKiBUaGVyZSBpcyBkZXBhcnR1cmUgZnJvbSByYW5kb21uZXNzIGluIHRoZSBhYm92ZSByZXNpZHVhbCBwbG90LiBUaGUgcGxvdCBpcyBzbW9vdGggYXQgbXVsdGlwbGUgcGxhY2UsIHNvIGl0IGNhbnQgYmUgY29uY2x1ZGVkIGFzIGEgd2hpdGUgbm9pc2UuIAoKIyMjIyMgTmV4dCwgd2UgbG9vayBhdCB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscyB2ZXJzdXMgdGhlIGNvcnJlc3BvbmRpbmcgdHJlbmQgZXN0aW1hdGUsIG9yIGZpdHRlZCB2YWx1ZSAKCmBgYHtyfQpwbG90KHk9cnN0dWRlbnQobW9kZWxfcXVhZCksIHg9Zml0dGVkKG1vZGVsX3F1YWQpLAp4bGFiID0iRml0dGVkIFRyZW5kIFZhbHVlIiwgeWxhYiA9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnKQpgYGAKKiAgV2UgZG8gc2VlIHZhcmlhdGlvbiB3aXRoIGRpZmZlcmVudCBmaXR0ZWQgdHJlbmQgdmFsdWVzLiAKCiMjIyBDaGVjayB0aGUgTm9ybWFsaXR5IG9mIHJlc2lkdWFscyB3aXRoIGEgaGlzdG9ncmFtCgpgYGB7cn0KaGlzdChyc3R1ZGVudChtb2RlbF9xdWFkKSwgeGxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgCm1haW4gPSAiSGlzdG9ncmFtIG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbHMgb2YgTW9kZWwiKQpgYGAKCiogVGhlIHBsb3QgaXMgbm90IHN5bW1ldHJpYyBhbmQgc28gdGhlIHJlc2lkdWFscyBkb2VzbnQgZnVsZmlsbCB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24uCgoKIyMjIENoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHdpdGggdGhlIHF1YW50aWxlLXF1YW50aWxlIChRUSkgcGxvdApgYGB7cn0KcSA9IHJzdHVkZW50KG1vZGVsX3F1YWQpCnFxbm9ybShxKQpxcWxpbmUocSAsIGNvbCA9IDIgLCBsd2QgPSAxKQpgYGAKKiBGb3IgYSBub3JtYWx5IGRpc3RyaWJ1dGVkIGRhdGEgdGhlIFFRIHBsb3QgYXBycm94IGxpa2UgYSBzdHJhaWdodCBsaW5lLiBJbiB0aGUgYWJvdmUgcGxvdCwgdGhlIGxpbmUgYWxtb3N0IGNhcHR1cmVzIGFsbCB0aGUgcG9pbnRzLCBiZXR0ZXIgdGhhbiBhIGxpbmVhciBtb2RlbC4gVGhlIHN0cmFpZ2h0LWxpbmUgcGF0dGVybiBoZXJlIGRvZXMgc3VwcG9ydHMgdGhlIGFzc3VtcHRpb24gb2Ygbm9ybWFsbHkgZGlzdHJpYnV0ZWQgc3RvY2hhc3RpYyBjb21wb25lbnQgaW4gdGhlIG1vZGVsLiAKCgojIyMgSHlwb3RoZXNpcyB0ZXN0OiAqU2hhcGlyby1XaWxrKiB0ZXN0IGlzIHVzZWQgdG8gY2hlY2sgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uIG9mIHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCAKCmBgYHtyfQpzPXJzdHVkZW50KG1vZGVsX3F1YWQpCnNoYXBpcm8udGVzdChzKQpgYGAKKiBXZSBnZXQgdGhlIHAtdmFsdWUgb2YgMC42NDkzLiBIZW5jZSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpLmUuIHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCBvZiB0aGlzIG1vZGVsIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMjIEFDRihBdXRvY29ycmVsYXRpb24gZnVuY3Rpb24pIGZvciBhbmFseXNpcyBvZiBUaW1lIFNlcmllcwpgYGB7cn0KIyNGaW5kIHRoZSBzaWduaWZpY2FuY2UgYXV0b3Jjb3JyZWxhdGlvbiBpbiBzdGFuZGFyZGlzZWQgUmVzaWR1YWxzCmFjZihyc3R1ZGVudChtb2RlbF9xdWFkKSwgbWFpbj0iQUNGIG9mIHN0YW5kYXJkaXplZCByZXNpZHVhbHMiKQpgYGAKKiBXZSBoYXZlIGNvcnJlbGF0aW9uIHZhbHVlcyBoaWdoZXIgdGhhbiB0aGUgY29uZmlkZW5jZSBib3VuZCBhdCBzZXZlcmFsIGxhZ3MuIFRoaXMgZG9lc250IGFwcGVhciB0byBiZSBhIHdoaXRlIG5vaXNlLiAKCiogX19Db25jbHVzaW9uX186IAogICAgKyBOZWl0aGVyIGxpbmVhciBvciBxdWFkcmF0aWMgbW9kZWxzIHNlZW1zIHRvIGJlIHRoZSBiZXN0IGZpdCBmb3IgdGhlIGdpdmVuICAgZGF0YSBhcyBpdCBhcHBlYXJzIHRvIGJlIGEgc3RvY2hhc3RpYyB0cmVuZC4gCiAgICArIEJhc2VkIG9uIHRoZSBtb2RlbCBmaXR0aW5nIGFuZCBSXjJeIHZhbHVlcyBxdWFkcmF0aWMgbW9kZWwgc2VlbXMgdG8gYmUgYSBiZXR0ZXIgZml0IGZvciBmb3JlY2FzdGluZyBmb3IgdGhlIGdpdmVuIGRhdGEuIAoKIyMjRm9yZWNhc3RpbmcgCgpgYGB7cn0KdCA9IGMoMjAxNywyMDE4LDIwMTksMjAyMCwyMDIxKSAjIGNyZWF0ZSBhIHRpbWUgdmVjdG9yIGZvciBuZXh0IGZpdmUgeWVhcnMgCnQyID0gdF4yIApuZXcgPSBkYXRhLmZyYW1lKHQsdDIpICNjcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIHQgYW5kIHQyIApmb3JlY2FzdHMgPSBwcmVkaWN0KG1vZGVsX3F1YWQsbmV3LCBpbnRlcnZhbCA9ICJwcmVkaWN0aW9uIikKcGxvdChPem9uZSx5bGFiPSAiT3pvbmUgTGF5ZXIgVGhpY2tuZXNzKERVKSIseWxpbSA9IGMoLTE1LDMpLHhsaW09YygxOTI3LDIwMjEpLG1haW49IlRpbWUgc2VyaWVzIHBsb3Qgb2YgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIHNlcmllcyIpCiMgY29udmVydCBmb3JlY2FzdHMgdG8gdGltZSBzZXJpZXMgb2JqZWN0IHN0YXJ0aW5nIGZyb20gdGhlIGZpcnN0IAojIHRpbWUgc3RlcHMtYWhlYWQgdG8gYmUgYWJsZSB0byB1c2UgcGxvdCBmdW5jdGlvbgpsaW5lcyh0cyhhcy52ZWN0b3IoZm9yZWNhc3RzWywxXSksIHN0YXJ0ID0gMjAxNiksIGNvbD0icmVkIiwgdHlwZT0ibCIsbHdkPTIpCmxpbmVzKHRzKGFzLnZlY3Rvcihmb3JlY2FzdHNbLDJdKSwgc3RhcnQgPSAyMDE2KSwgY29sPSJibHVlIiwgdHlwZT0ibCIsbHdkPTIpCmxpbmVzKHRzKGFzLnZlY3Rvcihmb3JlY2FzdHNbLDNdKSwgc3RhcnQgPSAyMDE2KSwgY29sPSJibHVlIiwgdHlwZT0ibCIsbHdkPTIpCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGx0eT0xLCBwY2g9MSxidHkgPSAibiIsIGNvbD1jKCJibGFjayIsImJsdWUiLCJyZWQiKSwgdGV4dC53aWR0aCA9IDE4LAogICAgICAgYygiRGF0YSIsIjUlIGZvcmVjYXN0IGxpbWl0IiwgIkZvcmVjYXN0cyIpKQpgYGAKKiBUaGUgcXVhZHJhdGljIG1vZGVsIGZpdHRlZCB0byBvcmlnaW5hbCBvem9uZSBsYXllciB0aGlja25lc3Mgc2VyaWVzIHNob3dpbmcgZm9yZWNhc3QgZm9yIGFub3RoZXIgZml2ZSB5ZWFycygyMDE3IHRvIDIwMjEpLgoKIyMjQ29uY2x1c2lvbgoKLSBBIGxpbmVhciBhbmQgcXVkcmF0aWMgbW9kZWwgd2FzIGFuYWx5c2VkIGZvciBzdWl0YWJpbGl0eSBmb3IgdGhlIHByb3ZpZGVkIGRhdGEgc2V0LiAKLSBOZWl0aGVyIG1vZGVscyBhcHBlYXJzIHRvIGJlIHRoZSBiZXN0IGZpdCBmb3IgdGhlIGdpdmVuIHN0b2NoYXN0aWMgdHJlbmQuIAotIEFjY29yZGluZyB0byBtdWx0aXBsZSAgUl4yXiA3NCUgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIGRhdGEgaXMgZXhwbGFpbmVkIGJ5IHRoZSBxdWFkcmF0aWMgbW9kZWwgYWdhaW5zdCA2NyUgYnkgdGhlIGxpbmVhciBtb2RlbC4gCi0gQWxzbywgbW9kZWwgZml0dGluZyB1c2luZyB0aGUgcXVhZHJhdGljIG1vZGVsIGNhcHR1cmVkIHRoZSB0cmVuZCBiZXR0ZXIgdGhhbiB0aGUgbGluZWFyIG1vZGVsLiAKLSBIZW5jZSwgcXVhZHJhdGljIG1vZGVsIHdhcyBzZWxlY3RlZCBhbmQgdXNlZCBmb3IgZm9yZWNhc3RpbmcuIAoKCiMjIyMjIyBFbmQgb2YgcmVwb3J0IAo8YnI+Cjxicj4K