# 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

  1. Trend : we do see a downward trend in the plot.
  2. Seasonality : cannot conclude at this stage.
  3. Behaviour: Appears to be Auto Regressive.
  4. Intervention: We may want to explore if something major happened around year 1992-93
  5. 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
  1. The coefficient of both intercept and linear component is statistically significant.
  2. 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
  1. The coefficient of quadratic component is statistically significant.
  2. 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")

  • We have correlation values higher than the confidence bound at several lags. This doesnt appear to be a white noise.

  • Conclusion:
    • Neither linear or quadratic models seems to be the best fit for the given data as it appears to be a stochastic trend.
    • Based on the model fitting and R2 values quadratic model seems to be a better fit for forecasting for the given data.

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.
End of report



LS0tCnRpdGxlOiAiTUFUSDEzMTggU2VtZXN0ZXIgMSwgMjAxOSIKYXV0aG9yOiAiQWhtYWQgSGFzbmFpbihTMzcxMjUzOCkiCnN1YnRpdGxlOiBGb3JlY2FzdGluZyBPem9uZSBMYXllciB0aGlja25lcyBiYXNlZCBvbiBkYXRhIGZyb20gMTkyNyB0byAyMDE2Cm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9CiMgTG9hZCBsaWJyYXJpZXMgYW5kIHJlYWQgdGhlIGRhdGEgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoVFNBKQpsaWJyYXJ5KG1hZ3JpdHRyKQpPem9uZSA8LSByZWFkLmNzdignZGF0YTEuY3N2JywgaGVhZGVyID1GQUxTRSkKcm93bmFtZXMoT3pvbmUpIDwtIHNlcShmcm9tPTE5MjcsIHRvPTIwMTYpCmhlYWQoT3pvbmUpCk96b25lIDwtIHRzKGFzLnZlY3RvcihPem9uZSksIHN0YXJ0ID0gMTkyNywgZW5kPTIwMTYpI2NvbnZlcnQgZGYgdG8gYSB0cyBvYmplY3QKcGxvdChPem9uZSx0eXBlPSdvJyx5bGFiPSdPem9uZSBMYXllciBUaGlja25lc3MgKERVKScsCm1haW49IlRpbWUgc2VyaWVzIHBsb3Qgb2YgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIHNlcmllcyIpICNjcmVhdGUgYSB0aW1lIHNlcmllcyBwbG90CgpgYGAKCiogIE9ic2VydmF0aW9uczoKMS4gVHJlbmQgOiAgd2UgZG8gc2VlIGEgZG93bndhcmQgdHJlbmQgaW4gdGhlIHBsb3QuIAoyLiBTZWFzb25hbGl0eSA6ICBjYW5ub3QgY29uY2x1ZGUgYXQgdGhpcyBzdGFnZS4KMy4gQmVoYXZpb3VyOiBBcHBlYXJzIHRvIGJlIEF1dG8gUmVncmVzc2l2ZS4gCjQuIEludGVydmVudGlvbjogV2UgbWF5IHdhbnQgdG8gZXhwbG9yZSBpZiBzb21ldGhpbmcgbWFqb3IgaGFwcGVuZWQgYXJvdW5kIHllYXIgMTk5Mi05Mwo1LiBDaGFuZ2luZyBWYXJpYW5jZTogbW9yZSBvciBsZXNzIHZhcmlhbmNlIHJlbWFpbnMgdGhlIHNhbWUgCgojIyBJLiBUcnlpbmcgdG8gZml0IGEgbGluZWFyIG1vZGVsCmBgYHtyfQptb2RlbF9sbSA9IGxtKE96b25lIH50aW1lKE96b25lKSkgI2RlZmluZSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwKcGxvdChPem9uZSx0eXBlPSAnbycseWxhYj0neScpCmFibGluZShtb2RlbF9sbSkgI2FkZCB0aGUgZml0dGVkIGxlYXN0IHNxdWFyZSBsaW5lIHRvIHRoZSBtb2RlbApzdW1tYXJ5KG1vZGVsX2xtKSAKYGBgCiogT2JzZXJ2YXRpb25zOgoxLiBUaGUgY29lZmZpY2llbnQgb2YgYm90aCBpbnRlcmNlcHQgYW5kIGxpbmVhciBjb21wb25lbnQgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KMi4gKmNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24qIFJeMl4gYXBwZWFycyB0byBiZSBmaW5lIGF0IDAuNjY1NSwgbm90IHRvbyBoaWdoIG9yIHRvbyBsb3cuIAoKIyMjIEFzc2Vzc2luZyB0aGUgcXVhbGl0eSBvZiB0aGUgbGluZWFyIG1vZGVsIAojIyMjIyBSZXNpZHVhbCBBbmFseXNpczogCgpgYGB7cn0KcmVzaWR1YWxfbW9kZWxfbG0gPSByc3R1ZGVudChtb2RlbF9sbSkgI3JzdHVkZW50KCkgY29tcHV0ZXMgc3RhbmRhcmRpc2VkIHJlc2lkdWFsCnBsb3QoeT1yZXNpZHVhbF9tb2RlbF9sbSwgeD1hcy52ZWN0b3IodGltZShPem9uZSkpLHhsYWIgPSAnVGltZScsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLHR5cGUgPSAnbycpCmBgYAoqIFRoZXJlIGlzIHNvbWV3aGF0IGRlcGFydHVyZSBmcm9tIHJhbmRvbW5lc3MgaW4gdGhlIGFib3ZlIHJlc2lkdWFsIHBsb3QuIAoKIyMjIyMgTmV4dCwgd2UgbG9vayBhdCB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscyB2ZXJzdXMgdGhlIGNvcnJlc3BvbmRpbmcgdHJlbmQgZXN0aW1hdGUsIG9yIGZpdHRlZCB2YWx1ZSAKCmBgYHtyfQpwbG90KHk9cnN0dWRlbnQobW9kZWxfbG0pLCB4PWZpdHRlZChtb2RlbF9sbSksCnhsYWIgPSJGaXR0ZWQgVHJlbmQgVmFsdWUiLCB5bGFiID0nU3RhbmRhcmRpemVkIFJlc2lkdWFscycpCmBgYAoKKiBUaGVyZSBpcyBubyBvYnZpb3VzIHRyZW5kIGluIHRoZSByZXNpZHVhbHMsIGhvd2V2ZXIgd2UgZG8gc2VlIHZhcmlhdGlvbiB3aXRoIGRpZmZlcmVudCBmaXR0ZWQgdHJlbmQgdmFsdWVzLiAKCiMjIyBDaGVjayB0aGUgTm9ybWFsaXR5IG9mIHJlc2lkdWFscyB3aXRoIGEgaGlzdG9ncmFtLgoKYGBge3J9Cmhpc3QocnN0dWRlbnQobW9kZWxfbG0pLCB4bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCAKbWFpbiA9ICJIaXN0b2dyYW0gb2YgU3RhbmRhcmRpemVkIFJlc2lkdWFscyBvZiBNb2RlbCIpCmBgYAoqIFRoZSBwbG90IGFwcGVhcnMgc29tZXdoYXQgc3ltbWV0cmljIGFuZCB0YWlscyBvZmYgYXQgdGhlIGxvdyBhbmQgaGlnaCBlbmQgcmVjaXByb2NhdGluZyB0aGUgYmVoYXZpb3VyIG9mIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gIAoKIyMjIENoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHdpdGggdGhlIHF1YW50aWxlLXF1YW50aWxlIChRUSkgcGxvdAoKYGBge3J9CnogPSByc3R1ZGVudChtb2RlbF9sbSkKcXFub3JtKHopICNwcm9kdWNlIGEgcXEgcGxvdCBvZiB0aGUgcmVzaWR1YWxzIApxcWxpbmUoeiAsIGNvbCA9IDMgLCBsd2QgPSAxKSAKYGBgCgoqIEZvciBhIG5vcm1hbHkgZGlzdHJpYnV0ZWQgZGF0YSB0aGUgUVEgcGxvdCBhcHJyb3ggbGlrZSBhIHN0cmFpZ2h0IGxpbmUgYnV0IGluIHRoZSBhYm92ZSBwbG90LCB0aGUgbGluZSBkb2VzbnQgY2FwdHVyZSBhbGwgdGhlIHBvaW50cy4gVGhlIHN0cmFpZ2h0LWxpbmUgcGF0dGVybiBoZXJlIGRvZXNudCBmdWxseSBjYXB0dXJlcyB0aGUgYXNzdW1wdGlvbiBvZiBub3JtYWxseSBkaXN0cmlidXRlZCBzdG9jaGFzdGljIGNvbXBvbmVudCBpbiB0aGUgbW9kZWwuIAoKCiMjIyBIeXBvdGhlc2lzIHRlc3Q6ICpTaGFwaXJvLVdpbGsqIHRlc3QgaXMgdXNlZCB0byBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gb2YgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IAoKYGBge3J9CnMgPSByc3R1ZGVudChtb2RlbF9sbSkKc2hhcGlyby50ZXN0KHMpCmBgYAoqIFdlIGdldCB0aGUgcC12YWx1ZSBvZiAwLjUzNzIuSGVuY2UsIHdlIGZhaWwgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgaS5lLgp0aGUgc3RvY2hhc3RpYyBjb21wb25lbnQgb2YgdGhpcyBtb2RlbCBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4KCiMjIyBBQ0YoQXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9uKSBmb3IgYW5hbHlzaXMgb2YgVGltZSBTZXJpZXMKYGBge3J9CiMjRmluZCB0aGUgc2lnbmlmaWNhbmNlIGF1dG9yY29ycmVsYXRpb24gaW4gc3RhbmRhcmRpc2VkIFJlc2lkdWFscwphY2YocnN0dWRlbnQobW9kZWxfbG0pLCBtYWluPSJBQ0Ygb2Ygc3RhbmRhcmRpemVkIHJlc2lkdWFscyIpCmBgYAoqIFRoZXJlIGlzIHNvbWUgdHJlbmQgYW5kIHNvbWUgYXV0cm9jb3JyZWxhdGlvbiBsZWZ0IGluIHRoZSBSZXNpZHVhbHMgYXMgZGV0ZXJtaW5pc3RpYyBtb2RlbCBjYW5ub3QgY29tcGxldGVseSBjYXB0dXJlIGl0LgoKIyMgSUkuIFRyeWluZyB0byBmaXQgYSBRdWFkcmF0aWMgbW9kZWwKCmBgYHtyfQp0PXRpbWUoT3pvbmUpICNsaW5lYXIgY29tcG9uZW50IAp0Mj10XjIgI3Rha2Ugc3F1YXJlIG9mIHRpbWUgZm9yIHRoZSBxdWFkcmF0aWMgY29tcG9uZW50IAptb2RlbF9xdWFkID0gbG0oT3pvbmUgfiB0K3QyKSAjY3JlYXRlIGEgcXVhZHJhdGljIG1vZGVsIAoKcGxvdCh0cyhmaXR0ZWQobW9kZWxfcXVhZCkpLHlsaW0gPSBjKG1pbihjKGZpdHRlZChtb2RlbF9xdWFkKSxhcy52ZWN0b3IoT3pvbmUpKSksCm1heChjKGZpdHRlZChtb2RlbF9xdWFkKSxhcy52ZWN0b3IoT3pvbmUpKSkpLHlsYWI9J3knICwKbWFpbiA9ICJGaXR0ZWQgcXVhZHJhdGljIGN1cnZlIHRvIE96b25lIGRhdGEiKQpsaW5lcyhhcy52ZWN0b3IoT3pvbmUpLHR5cGU9J28nKQoKc3VtbWFyeShtb2RlbF9xdWFkKQpgYGAKKiBPYnNlcnZhdGlvbnM6CjEuIFRoZSBjb2VmZmljaWVudCBvZiBxdWFkcmF0aWMgY29tcG9uZW50IGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuCjIuICpjb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uKiBSXjJeICgwLjczMzEpIGlzIGJldHRlciB0aGFuIHRoYXQgb2YgdGhlIGxpbmVhciBtb2RlbCgwLjY2NTUpLgoKIyMjIEFzc2Vzc2luZyB0aGUgcXVhbGl0eSBvZiB0aGUgUXVhZHJhdGljIG1vZGVsIAojIyMjIyBSZXNpZHVhbCBBbmFseXNpczogCmBgYHtyfQpyZXNpZHVhbF9tb2RlbF9xZCA9IHJzdHVkZW50KG1vZGVsX3F1YWQpCnBsb3QoeT1yZXNpZHVhbF9tb2RlbF9xZCwgeD1hcy52ZWN0b3IodGltZShPem9uZSkpLHhsYWIgPSAnVGltZScsIHlsYWI9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLHR5cGU9J28nKQpgYGAKKiBUaGVyZSBpcyBkZXBhcnR1cmUgZnJvbSByYW5kb21uZXNzIGluIHRoZSBhYm92ZSByZXNpZHVhbCBwbG90LiBUaGUgcGxvdCBpcyBzbW9vdGggYXQgbXVsdGlwbGUgcGxhY2UsIHNvIGl0IGNhbnQgYmUgY29uY2x1ZGVkIGFzIGEgd2hpdGUgbm9pc2UuIAoKIyMjIyMgTmV4dCwgd2UgbG9vayBhdCB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscyB2ZXJzdXMgdGhlIGNvcnJlc3BvbmRpbmcgdHJlbmQgZXN0aW1hdGUsIG9yIGZpdHRlZCB2YWx1ZSAKCmBgYHtyfQpwbG90KHk9cnN0dWRlbnQobW9kZWxfcXVhZCksIHg9Zml0dGVkKG1vZGVsX3F1YWQpLAp4bGFiID0iRml0dGVkIFRyZW5kIFZhbHVlIiwgeWxhYiA9J1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnKQpgYGAKKiAgV2UgZG8gc2VlIHZhcmlhdGlvbiB3aXRoIGRpZmZlcmVudCBmaXR0ZWQgdHJlbmQgdmFsdWVzLiAKCiMjIyBDaGVjayB0aGUgTm9ybWFsaXR5IG9mIHJlc2lkdWFscyB3aXRoIGEgaGlzdG9ncmFtCgpgYGB7cn0KaGlzdChyc3R1ZGVudChtb2RlbF9xdWFkKSwgeGxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgCm1haW4gPSAiSGlzdG9ncmFtIG9mIFN0YW5kYXJkaXplZCBSZXNpZHVhbHMgb2YgTW9kZWwiKQpgYGAKCiogVGhlIHBsb3QgaXMgbm90IHN5bW1ldHJpYyBhbmQgc28gdGhlIHJlc2lkdWFscyBkb2VzbnQgZnVsZmlsbCB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24uCgoKIyMjIENoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHdpdGggdGhlIHF1YW50aWxlLXF1YW50aWxlIChRUSkgcGxvdApgYGB7cn0KcSA9IHJzdHVkZW50KG1vZGVsX3F1YWQpCnFxbm9ybShxKQpxcWxpbmUocSAsIGNvbCA9IDIgLCBsd2QgPSAxKQpgYGAKKiBGb3IgYSBub3JtYWx5IGRpc3RyaWJ1dGVkIGRhdGEgdGhlIFFRIHBsb3QgYXBycm94IGxpa2UgYSBzdHJhaWdodCBsaW5lLiBJbiB0aGUgYWJvdmUgcGxvdCwgdGhlIGxpbmUgYWxtb3N0IGNhcHR1cmVzIGFsbCB0aGUgcG9pbnRzLCBiZXR0ZXIgdGhhbiBhIGxpbmVhciBtb2RlbC4gVGhlIHN0cmFpZ2h0LWxpbmUgcGF0dGVybiBoZXJlIGRvZXMgc3VwcG9ydHMgdGhlIGFzc3VtcHRpb24gb2Ygbm9ybWFsbHkgZGlzdHJpYnV0ZWQgc3RvY2hhc3RpYyBjb21wb25lbnQgaW4gdGhlIG1vZGVsLiAKCgojIyMgSHlwb3RoZXNpcyB0ZXN0OiAqU2hhcGlyby1XaWxrKiB0ZXN0IGlzIHVzZWQgdG8gY2hlY2sgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uIG9mIHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCAKCmBgYHtyfQpzPXJzdHVkZW50KG1vZGVsX3F1YWQpCnNoYXBpcm8udGVzdChzKQpgYGAKKiBXZSBnZXQgdGhlIHAtdmFsdWUgb2YgMC42NDkzLiBIZW5jZSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpLmUuIHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCBvZiB0aGlzIG1vZGVsIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMjIEFDRihBdXRvY29ycmVsYXRpb24gZnVuY3Rpb24pIGZvciBhbmFseXNpcyBvZiBUaW1lIFNlcmllcwpgYGB7cn0KIyNGaW5kIHRoZSBzaWduaWZpY2FuY2UgYXV0b3Jjb3JyZWxhdGlvbiBpbiBzdGFuZGFyZGlzZWQgUmVzaWR1YWxzCmFjZihyc3R1ZGVudChtb2RlbF9xdWFkKSwgbWFpbj0iQUNGIG9mIHN0YW5kYXJkaXplZCByZXNpZHVhbHMiKQpgYGAKKiBXZSBoYXZlIGNvcnJlbGF0aW9uIHZhbHVlcyBoaWdoZXIgdGhhbiB0aGUgY29uZmlkZW5jZSBib3VuZCBhdCBzZXZlcmFsIGxhZ3MuIFRoaXMgZG9lc250IGFwcGVhciB0byBiZSBhIHdoaXRlIG5vaXNlLiAKCiogX19Db25jbHVzaW9uX186IAogICAgKyBOZWl0aGVyIGxpbmVhciBvciBxdWFkcmF0aWMgbW9kZWxzIHNlZW1zIHRvIGJlIHRoZSBiZXN0IGZpdCBmb3IgdGhlIGdpdmVuICAgZGF0YSBhcyBpdCBhcHBlYXJzIHRvIGJlIGEgc3RvY2hhc3RpYyB0cmVuZC4gCiAgICArIEJhc2VkIG9uIHRoZSBtb2RlbCBmaXR0aW5nIGFuZCBSXjJeIHZhbHVlcyBxdWFkcmF0aWMgbW9kZWwgc2VlbXMgdG8gYmUgYSBiZXR0ZXIgZml0IGZvciBmb3JlY2FzdGluZyBmb3IgdGhlIGdpdmVuIGRhdGEuIAoKIyMjRm9yZWNhc3RpbmcgCgpgYGB7cn0KdCA9IGMoMjAxNywyMDE4LDIwMTksMjAyMCwyMDIxKSAjIGNyZWF0ZSBhIHRpbWUgdmVjdG9yIGZvciBuZXh0IGZpdmUgeWVhcnMgCnQyID0gdF4yIApuZXcgPSBkYXRhLmZyYW1lKHQsdDIpICNjcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIHQgYW5kIHQyIApmb3JlY2FzdHMgPSBwcmVkaWN0KG1vZGVsX3F1YWQsbmV3LCBpbnRlcnZhbCA9ICJwcmVkaWN0aW9uIikKcGxvdChPem9uZSx5bGFiPSAiT3pvbmUgTGF5ZXIgVGhpY2tuZXNzKERVKSIseWxpbSA9IGMoLTE1LDMpLHhsaW09YygxOTI3LDIwMjEpLG1haW49IlRpbWUgc2VyaWVzIHBsb3Qgb2YgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIHNlcmllcyIpCiMgY29udmVydCBmb3JlY2FzdHMgdG8gdGltZSBzZXJpZXMgb2JqZWN0IHN0YXJ0aW5nIGZyb20gdGhlIGZpcnN0IAojIHRpbWUgc3RlcHMtYWhlYWQgdG8gYmUgYWJsZSB0byB1c2UgcGxvdCBmdW5jdGlvbgpsaW5lcyh0cyhhcy52ZWN0b3IoZm9yZWNhc3RzWywxXSksIHN0YXJ0ID0gMjAxNiksIGNvbD0icmVkIiwgdHlwZT0ibCIsbHdkPTIpCmxpbmVzKHRzKGFzLnZlY3Rvcihmb3JlY2FzdHNbLDJdKSwgc3RhcnQgPSAyMDE2KSwgY29sPSJibHVlIiwgdHlwZT0ibCIsbHdkPTIpCmxpbmVzKHRzKGFzLnZlY3Rvcihmb3JlY2FzdHNbLDNdKSwgc3RhcnQgPSAyMDE2KSwgY29sPSJibHVlIiwgdHlwZT0ibCIsbHdkPTIpCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGx0eT0xLCBwY2g9MSxidHkgPSAibiIsIGNvbD1jKCJibGFjayIsImJsdWUiLCJyZWQiKSwgdGV4dC53aWR0aCA9IDE4LAogICAgICAgYygiRGF0YSIsIjUlIGZvcmVjYXN0IGxpbWl0IiwgIkZvcmVjYXN0cyIpKQpgYGAKKiBUaGUgcXVhZHJhdGljIG1vZGVsIGZpdHRlZCB0byBvcmlnaW5hbCBvem9uZSBsYXllciB0aGlja25lc3Mgc2VyaWVzIHNob3dpbmcgZm9yZWNhc3QgZm9yIGFub3RoZXIgZml2ZSB5ZWFycygyMDE3IHRvIDIwMjEpLgoKIyMjQ29uY2x1c2lvbgoKLSBBIGxpbmVhciBhbmQgcXVkcmF0aWMgbW9kZWwgd2FzIGFuYWx5c2VkIGZvciBzdWl0YWJpbGl0eSBmb3IgdGhlIHByb3ZpZGVkIGRhdGEgc2V0LiAKLSBOZWl0aGVyIG1vZGVscyBhcHBlYXJzIHRvIGJlIHRoZSBiZXN0IGZpdCBmb3IgdGhlIGdpdmVuIHN0b2NoYXN0aWMgdHJlbmQuIAotIEFjY29yZGluZyB0byBtdWx0aXBsZSAgUl4yXiA3NCUgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgT3pvbmUgbGF5ZXIgdGhpY2tuZXNzIGRhdGEgaXMgZXhwbGFpbmVkIGJ5IHRoZSBxdWFkcmF0aWMgbW9kZWwgYWdhaW5zdCA2NyUgYnkgdGhlIGxpbmVhciBtb2RlbC4gCi0gQWxzbywgbW9kZWwgZml0dGluZyB1c2luZyB0aGUgcXVhZHJhdGljIG1vZGVsIGNhcHR1cmVkIHRoZSB0cmVuZCBiZXR0ZXIgdGhhbiB0aGUgbGluZWFyIG1vZGVsLiAKLSBIZW5jZSwgcXVhZHJhdGljIG1vZGVsIHdhcyBzZWxlY3RlZCBhbmQgdXNlZCBmb3IgZm9yZWNhc3RpbmcuIAoKCiMjIyMjIyBFbmQgb2YgcmVwb3J0IAo8YnI+Cjxicj4K