Introduction

The aim of the investigation is to find the best fitting trend model to a provided Ozone time series data and to make predictions of yearly changes for the next 5 years. To answer the question, the data was firstly analysed through visualisation. Three trend models that seemed the most appropriate were identified and fitted to the time series. These three models were be further diagnosed to understand how well they fitted the data and if the assumptions of the models were satisfied.

Data

The dataset data1.csv for analysis represents yearly changes in the thickness of Ozone layer from 1927 to 2016 in Dobson units. A negative value in the dataset means a decrease in the thickness and a positive value - an increase.

The following code chunk imports the dataset as well as displays its first observations.

rr data1 <- read_csv(1.csv, col_names = F)

Parsed with column specification:
cols(
  X1 = col_double()
)

rr head(data1)

Checking the class of data1 object showed that the data was read as a data frame, so it was converted to a time series ozone.

rr class(data1)

[1] \tbl_df\     \tbl\        \data.frame\

rr ozone <- ts(as.vector(data1), start = 1927, end = 2016) head(ozone)

[1]  1.3511844  0.7605324 -1.2685573 -1.4636872 -0.9792030  1.5085675

Exploring and Visualising

The plot of Ozone time series shows that there is a general downward trend in the changes of ozone layer thickness over the observed time. There is no seasonality, changing variance in the data is not very obvious, and there can be multiple change points. The series seems to have an autoregressive behaviour, each next point follows the previous one. There is also an oscillation-like pattern in the data.

The observed downward trend in ozone layer thickness changes is explained by the increase in emissions of ozone-depleting substances over the years.

rr plot(ozone, type = , main = series plot for Ozone series, ylab = Units)

For the analysis, it is important to see whether or not consecutive years are related in some way. The following code chunk generates a scatter plot and calculates a correlation coefficient to investigate the relationship between pairs of consecutive changes in ozone layer thickness.

rr y = ozone x = zlag(y) plot(y = y, x = x, main = layer thickness changes vs previous year’s changes, ylab = , xlab = Year DU)

rr index <- 2:length(y) cor(y[index], x[index])

[1] 0.8700381

From a scatter plot we can tell that there is a strong positive linear relationship between two consecutive years’ values, the correlation coefficient (\(r = 0.87\)) confirms that.

Fitting trend models

After visualising the Ozone time series, three trend models were identified: linear, quadratic and a combination of cosine and quadratic trends seemed the most suitable for the investigation. The method used to fit these models was the classical regression approach, estimating unknown parameters in a linear model according to the criterion of least squares.

Fitting a linear trend

The deterministic linear trend model is expressed as follows:

\[\mu_t = \beta_0 + \beta_1t\] The following code chunk generates the constant and slope estimates using the ordinary least squares method.

rr t <- time(ozone) model1 <- lm(ozone~t) summary(model1)


Call:
lm(formula = ozone ~ t)

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 ***
t            -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 estimated model is: \(\mu_t = 213.720155 - 0.110029t\). If the stochastic component in our time series is normally distributed white noise, model summary reports that the constant and slope estimates of linear trend are statistically significant at 5% level. According to coefficient of determination, about 67% of the variation in the Ozone series is explained by a linear time trend.

The following code superimposes the estimated line of best fit to our time series. The plot shows that although the linear model captures the general trend, it is not approximating the data well at all.

rr plot(ozone, type = , main = series plot for Ozone series, ylab = Units) abline(model1, col = )

Residual analysis

If the fitted model is reasonably suitable, the residuals should behave roughly like the true stochastic component, and assumptions behind the stochastic component can be checked by looking at the residuals.

The following code generates standardised residuals for the linear trend model:

rr residuals1 <- rstudent(model1)

Firstly, plotting standardised residuals over time. From looking at the generated plot, it is possible to say that there is major departure from randomness of the residuals, a clear pattern can be observed, so fitted linear model was not successful at capturing the autocorrelation effect in our time series. When we plot standardised residuals against fitted values, we can see that the points are not very evenly distributed, and larger negative residuals associate with larger negative/positive fitted values. There seems to be slight curvilinear relationship between standardised residuals and fitted values.

rr plot(y = residuals1, x = as.vector(time(ozone)), xlab = ‘Time’, ylab = ‘Standardized Residuals’, type = ‘o’) abline(h = 0, col = )

rr plot(y = residuals1, x = fitted(model1), ylab = ‘Standardized Residuals’,xlab = ‘Fitted Trend Line Values’, type = ‘p’)

The following code chunk produces a Q-Q Plot and a Shapiro-Wilk test to test the normality assumption. The straight line pattern is not obvious from a Q-Q Plot, but given the reported test statistics and \(p\)-value = 0.54, we fail to reject the \(H_0\) that the stochastic component of linear model is normally distributed.

rr qqnorm(residuals1) qqline(residuals1, col = 2, lwd = 1, lty = 2)

rr shapiro.test(residuals1)


    Shapiro-Wilk normality test

data:  residuals1
W = 0.98733, p-value = 0.5372

The following code generates the sample autocorrelation function for standardized residuals from the linear trend model of the Ozone series:

rr acf(residuals1, main = for standardised residuals)

The lag 1, lag 7 and lag 8 autocorrelations exceed two standard errors above zero. There is a clear pattern in the sample ACF graph, so we can infer that the stochastic component of the Ozone time series is not white noise.

Fitting a quadratic trend

The deterministic quadratic trend model is expressed as follows:

\[\mu_t = \beta_0 + \beta_1t + \beta_2t^2\] The following code chunck fits a quadratic trend mode to the Ozone data.

rr t2 <- t^2 model2 <- lm(ozone ~ t + t2) summary(model2)


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 estimated model is: \(\mu_t = -5733.23764 + 5.9246t - 0.00153t^2\). According to the adjusted coefficient of determination, about 73% of the variation in the Ozone series is explained by a quadratic time trend.

The following code superimposes the estimated quadratic curve to our time series. The plot shows that the quadratic trend captures the general trend much better than the linear one but still does not do a good job at approximating the data.

rr plot(ts(fitted(model2)), x = as.vector(time(ozone)), ylim = c(min(c(fitted(model2), as.vector(ozone))), max(c(fitted(model2),as.vector(ozone)))), ylab = ‘Dobson Units’, xlab = , main = quadratic curve to Ozone series, type = ,col = ) lines(ozone, type = )

Residual Analysis

From the plot of standardised residuals over time, we observe a very similar picture to the linear trend model. Residuals are not random, quadratic model was not successful at capturing the autocorrelation effect in the series. When we plot standardised residuals against fitted values, we can see that the points are not evenly distributed and tend to gather towards the right side of the rectangle as fitted values approach 0.

rr residuals2 <- rstudent(model2) plot(y = residuals2, x = as.vector(time(ozone)), xlab = ‘Time’, ylab = ‘Standardized Residuals’, type=‘o’) abline(h = 0, col = )

rr plot(y = residuals2, x = fitted(model2), ylab = ‘Standardized Residuals’, xlab = ‘Fitted Trend Line Values’, type = ‘p’)

The following code chunk produces a Q-Q Plot and a Shapiro-Wilk test to check the normality assumption. Given the straight line pattern from a Q-Q Plot and the reported test statistics with \(p\)-value = 0.65, we fail to reject the \(H_0\) that the stochastic component of quadratic model is normally distributed.

rr qqnorm(residuals2) qqline(residuals2, col = 2, lwd = 1, lty = 2)

rr shapiro.test(residuals2)


    Shapiro-Wilk normality test

data:  residuals2
W = 0.98889, p-value = 0.6493

The following code generates the sample autocorrelation function for standardized residuals from the quadratic trend model of the Ozone series:

rr acf(rstudent(model2), main = for standardised residuals)

As in the linear model case, after fitting a quadratic trend, some autocorreation remains in the residuals from this model. Lag 1 and lag 7 autocorrelations exceed two standard errors above zero, while lag 3, 4, 10 - below zero. After examining the residuals, we can infer that the stochastic component in our time series does not behave like white noise.

Forecasting with quadratic trend model

Although non of the fitted trend models are suitable for prediction purposes based on the residual analysis, predictions of yearly changes in the ozone layer thickness for the next 5 years were attempted. The model used for making predictions was the quadratic trend because all the terms were found statistically significant at 5% level unlike the combination trend, and it has an acceptable value of adjusted \(R^2\).

The following code chunk makes predictions for next 5 time points. The last level of the Ozone time series is for year 2016. So we are predicting changes for years 2017-2021.

rr pred <- seq(from = 2017, by = 1, length.out = 5) pred2 <- pred^2 new <- data.frame(t = pred, t2 = pred2) forecasts <- predict(model2, newdata = new, interval = ) forecasts

        fit       lwr       upr
1 -10.34387 -14.13556 -6.552180
2 -10.59469 -14.40282 -6.786548
3 -10.84856 -14.67434 -7.022786
4 -11.10550 -14.95015 -7.260851
5 -11.36550 -15.23030 -7.500701

Adding generated forecasts and their prediction intervals to the time series plot:

rr plot(ozone, xlim = c(1927, 2022), ylim = c(-16, 5)) lines(ts(as.vector(forecasts[,1]), start = 2017), col=, type=) r lines(ts(as.vector(forecasts[,2]), start = 2017), col=, type=) lines(ts(as.vector(forecasts[,3]), start = 2017), col=, type=) r legend(, lty=1, pch=1, col=c(,,), text.width = 22, c(,% forecast limits, ))

Conclusion

To find the best fitting trend model to the Ozone time series, three most promising models were identified. They were: linear, quadratic and a combination of cosine and quadratic trends. All three models were estimated and fitted to the data using ordinary regression approach. The process was followed by analysing the behaviour of standardised residuals from these models. The residuals investigation showed that although all three models managed to capture the general trend in the series, there was always some autocorrelation remaining in the residuals.

The quadratic trend was decided to be the “best fitting” in terms of significance of coefficients and its adjusted \(R^2\) value. It was further used to make predictions of yearly changes in the ozone layer thickness for next 5 years. These forecasts cannot be considered correct and cannot be trusted.

To sum up, fitting a deterministic trend to the Ozone time series did not result into a quality model that can be used for further prediction. Fitting ARIMA models can be the direction for future investigation.



LS0tCnRpdGxlOiAiTUFUSDEzMTggQXNzaWdubWVudCAxIgphdXRob3I6ICJBbm5hIEtyaW5vY2hraW5hIHMzNzEyNzYxIgpzdWJ0aXRsZTogRml0dGluZyB0cmVuZCBtb2RlbHMgdG8gcHJlZGljdCB5ZWFybHkgY2hhbmdlcyBvZiBPem9uZSBsYXllciB0aGlja25lc3MKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIyBJbnRyb2R1Y3Rpb24KClRoZSBhaW0gb2YgdGhlIGludmVzdGlnYXRpb24gaXMgdG8gZmluZCB0aGUgYmVzdCBmaXR0aW5nIHRyZW5kIG1vZGVsIHRvIGEgcHJvdmlkZWQgT3pvbmUgdGltZSBzZXJpZXMgZGF0YSBhbmQgdG8gbWFrZSBwcmVkaWN0aW9ucyBvZiB5ZWFybHkgY2hhbmdlcyBmb3IgdGhlIG5leHQgNSB5ZWFycy4gVG8gYW5zd2VyIHRoZSBxdWVzdGlvbiwgdGhlIGRhdGEgd2FzIGZpcnN0bHkgYW5hbHlzZWQgdGhyb3VnaCB2aXN1YWxpc2F0aW9uLiBUaHJlZSB0cmVuZCBtb2RlbHMgdGhhdCBzZWVtZWQgdGhlIG1vc3QgYXBwcm9wcmlhdGUgd2VyZSBpZGVudGlmaWVkIGFuZCBmaXR0ZWQgdG8gdGhlIHRpbWUgc2VyaWVzLiBUaGVzZSB0aHJlZSBtb2RlbHMgd2VyZSBiZSBmdXJ0aGVyIGRpYWdub3NlZCB0byB1bmRlcnN0YW5kIGhvdyB3ZWxsIHRoZXkgZml0dGVkIHRoZSBkYXRhIGFuZCBpZiB0aGUgYXNzdW1wdGlvbnMgb2YgdGhlIG1vZGVscyB3ZXJlIHNhdGlzZmllZC4gCgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShyZWFkcikKaW5zdGFsbC5wYWNrYWdlcygiRlNBZGF0YSIpCmxpYnJhcnkoRlNBZGF0YSkKYGBgCgojIyBEYXRhIAoKVGhlIGRhdGFzZXQgYGRhdGExLmNzdmAgZm9yIGFuYWx5c2lzIHJlcHJlc2VudHMgeWVhcmx5IGNoYW5nZXMgaW4gdGhlIHRoaWNrbmVzcyBvZiBPem9uZSBsYXllciBmcm9tIDE5MjcgdG8gMjAxNiBpbiBEb2Jzb24gdW5pdHMuIEEgbmVnYXRpdmUgdmFsdWUgaW4gdGhlIGRhdGFzZXQgbWVhbnMgYSBkZWNyZWFzZSBpbiB0aGUgdGhpY2tuZXNzIGFuZCBhIHBvc2l0aXZlIHZhbHVlIC0gYW4gaW5jcmVhc2UuCgpUaGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgaW1wb3J0cyB0aGUgZGF0YXNldCBhcyB3ZWxsIGFzIGRpc3BsYXlzIGl0cyBmaXJzdCBvYnNlcnZhdGlvbnMuCgpgYGB7cn0KZGF0YTEgPC0gcmVhZF9jc3YoImRhdGExLmNzdiIsIGNvbF9uYW1lcyA9IEYpCmhlYWQoZGF0YTEpCmBgYAogCkNoZWNraW5nIHRoZSBjbGFzcyBvZiBgZGF0YTFgIG9iamVjdCBzaG93ZWQgdGhhdCB0aGUgZGF0YSB3YXMgcmVhZCBhcyBhIGRhdGEgZnJhbWUsIHNvIGl0IHdhcyBjb252ZXJ0ZWQgdG8gYSB0aW1lIHNlcmllcyBgb3pvbmVgLgoKYGBge3J9CmNsYXNzKGRhdGExKQpvem9uZSA8LSB0cyhhcy52ZWN0b3IoZGF0YTEpLCBzdGFydCA9IDE5MjcsIGVuZCA9IDIwMTYpCmhlYWQob3pvbmUpCmBgYAoKIyMgRXhwbG9yaW5nIGFuZCBWaXN1YWxpc2luZwoKVGhlIHBsb3Qgb2YgT3pvbmUgdGltZSBzZXJpZXMgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIGdlbmVyYWwgZG93bndhcmQgdHJlbmQgaW4gdGhlIGNoYW5nZXMgb2Ygb3pvbmUgbGF5ZXIgdGhpY2tuZXNzIG92ZXIgdGhlIG9ic2VydmVkIHRpbWUuIFRoZXJlIGlzIG5vIHNlYXNvbmFsaXR5LCBjaGFuZ2luZyB2YXJpYW5jZSBpbiB0aGUgZGF0YSBpcyBub3QgdmVyeSBvYnZpb3VzLCBhbmQgdGhlcmUgY2FuIGJlIG11bHRpcGxlIGNoYW5nZSBwb2ludHMuIFRoZSBzZXJpZXMgc2VlbXMgdG8gaGF2ZSBhbiBhdXRvcmVncmVzc2l2ZSBiZWhhdmlvdXIsIGVhY2ggbmV4dCBwb2ludCBmb2xsb3dzIHRoZSBwcmV2aW91cyBvbmUuIFRoZXJlIGlzIGFsc28gYW4gb3NjaWxsYXRpb24tbGlrZSBwYXR0ZXJuIGluIHRoZSBkYXRhLgoKVGhlIG9ic2VydmVkIGRvd253YXJkIHRyZW5kIGluIG96b25lIGxheWVyIHRoaWNrbmVzcyBjaGFuZ2VzIGlzIGV4cGxhaW5lZCBieSB0aGUgaW5jcmVhc2UgaW4gZW1pc3Npb25zIG9mIG96b25lLWRlcGxldGluZyBzdWJzdGFuY2VzIG92ZXIgdGhlIHllYXJzLiAKCmBgYHtyfQpwbG90KG96b25lLCB0eXBlID0gIm8iLCBtYWluID0gIlRpbWUgc2VyaWVzIHBsb3QgZm9yIE96b25lIHNlcmllcyIsIHlsYWIgPSAiRG9ic29uIFVuaXRzIikKYGBgCgpGb3IgdGhlIGFuYWx5c2lzLCBpdCBpcyBpbXBvcnRhbnQgdG8gc2VlIHdoZXRoZXIgb3Igbm90IGNvbnNlY3V0aXZlIHllYXJzIGFyZSByZWxhdGVkIGluIHNvbWUgd2F5LiBUaGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgZ2VuZXJhdGVzIGEgc2NhdHRlciBwbG90IGFuZCBjYWxjdWxhdGVzIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgdG8gaW52ZXN0aWdhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBhaXJzIG9mIGNvbnNlY3V0aXZlIGNoYW5nZXMgaW4gb3pvbmUgbGF5ZXIgdGhpY2tuZXNzLgoKYGBge3J9CnkgPSBvem9uZQp4ID0gemxhZyh5KQpwbG90KHkgPSB5LCB4ID0geCwgbWFpbiA9ICJPem9uZSBsYXllciB0aGlja25lc3MgY2hhbmdlcyB2cyBwcmV2aW91cyB5ZWFyJ3MgY2hhbmdlcyIsIHlsYWIgPSAiRFUiLCB4bGFiID0gIlByZXZpb3VzIFllYXIgRFUiKQppbmRleCA8LSAyOmxlbmd0aCh5KQpjb3IoeVtpbmRleF0sIHhbaW5kZXhdKQpgYGAKCkZyb20gYSBzY2F0dGVyIHBsb3Qgd2UgY2FuIHRlbGwgdGhhdCB0aGVyZSBpcyBhIHN0cm9uZyBwb3NpdGl2ZSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIGNvbnNlY3V0aXZlIHllYXJzJyB2YWx1ZXMsIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCAoJHIgPSAwLjg3JCkgY29uZmlybXMgdGhhdC4KCiMjIEZpdHRpbmcgdHJlbmQgbW9kZWxzCgpBZnRlciB2aXN1YWxpc2luZyB0aGUgT3pvbmUgdGltZSBzZXJpZXMsIHRocmVlIHRyZW5kIG1vZGVscyB3ZXJlIGlkZW50aWZpZWQ6IGxpbmVhciwgcXVhZHJhdGljIGFuZCBhIGNvbWJpbmF0aW9uIG9mIGNvc2luZSBhbmQgcXVhZHJhdGljIHRyZW5kcyBzZWVtZWQgdGhlIG1vc3Qgc3VpdGFibGUgZm9yIHRoZSBpbnZlc3RpZ2F0aW9uLiBUaGUgbWV0aG9kIHVzZWQgdG8gZml0IHRoZXNlIG1vZGVscyB3YXMgdGhlIGNsYXNzaWNhbCByZWdyZXNzaW9uIGFwcHJvYWNoLCBlc3RpbWF0aW5nIHVua25vd24gcGFyYW1ldGVycyBpbiBhIGxpbmVhciBtb2RlbCBhY2NvcmRpbmcgdG8gdGhlIGNyaXRlcmlvbiBvZiBsZWFzdCBzcXVhcmVzLiAKCiMjIyBGaXR0aW5nIGEgbGluZWFyIHRyZW5kCgpUaGUgZGV0ZXJtaW5pc3RpYyBsaW5lYXIgdHJlbmQgbW9kZWwgaXMgZXhwcmVzc2VkIGFzIGZvbGxvd3M6CgokJFxtdV90ID0gXGJldGFfMCArIFxiZXRhXzF0JCQKVGhlIGZvbGxvd2luZyBjb2RlIGNodW5rIGdlbmVyYXRlcyB0aGUgY29uc3RhbnQgYW5kIHNsb3BlIGVzdGltYXRlcyB1c2luZyB0aGUgb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyBtZXRob2QuCgpgYGB7cn0KdCA8LSB0aW1lKG96b25lKQptb2RlbDEgPC0gbG0ob3pvbmV+dCkKc3VtbWFyeShtb2RlbDEpCmBgYAoKVGhlIGVzdGltYXRlZCBtb2RlbCBpczogJFxtdV90ID0gMjEzLjcyMDE1NSAtIDAuMTEwMDI5dCQuIElmIHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCBpbiBvdXIgdGltZSBzZXJpZXMgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2hpdGUgbm9pc2UsIG1vZGVsIHN1bW1hcnkgcmVwb3J0cyB0aGF0IHRoZSBjb25zdGFudCBhbmQgc2xvcGUgZXN0aW1hdGVzIG9mIGxpbmVhciB0cmVuZCBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhdCA1JSBsZXZlbC4gQWNjb3JkaW5nIHRvIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24sIGFib3V0IDY3JSBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBPem9uZSBzZXJpZXMgaXMgZXhwbGFpbmVkIGJ5IGEgbGluZWFyIHRpbWUgdHJlbmQuIAoKVGhlIGZvbGxvd2luZyBjb2RlIHN1cGVyaW1wb3NlcyB0aGUgZXN0aW1hdGVkIGxpbmUgb2YgYmVzdCBmaXQgdG8gb3VyIHRpbWUgc2VyaWVzLiBUaGUgcGxvdCBzaG93cyB0aGF0IGFsdGhvdWdoIHRoZSBsaW5lYXIgbW9kZWwgY2FwdHVyZXMgdGhlIGdlbmVyYWwgdHJlbmQsIGl0IGlzIG5vdCBhcHByb3hpbWF0aW5nIHRoZSBkYXRhIHdlbGwgYXQgYWxsLgoKYGBge3J9CnBsb3Qob3pvbmUsIHR5cGUgPSAibyIsIG1haW4gPSAiVGltZSBzZXJpZXMgcGxvdCBmb3IgT3pvbmUgc2VyaWVzIiwgeWxhYiA9ICJEb2Jzb24gVW5pdHMiKQphYmxpbmUobW9kZWwxLCBjb2wgPSAicmVkIikKYGBgCgojIyMjIFJlc2lkdWFsIGFuYWx5c2lzCgpJZiB0aGUgZml0dGVkIG1vZGVsIGlzIHJlYXNvbmFibHkgc3VpdGFibGUsIHRoZSByZXNpZHVhbHMgc2hvdWxkIGJlaGF2ZSByb3VnaGx5IGxpa2UgdGhlIHRydWUgc3RvY2hhc3RpYyBjb21wb25lbnQsIGFuZCBhc3N1bXB0aW9ucyBiZWhpbmQgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IGNhbiBiZSBjaGVja2VkIGJ5IGxvb2tpbmcgYXQgdGhlIHJlc2lkdWFscy4KClRoZSBmb2xsb3dpbmcgY29kZSBnZW5lcmF0ZXMgc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBmb3IgdGhlIGxpbmVhciB0cmVuZCBtb2RlbDoKCmBgYHtyfQpyZXNpZHVhbHMxIDwtIHJzdHVkZW50KG1vZGVsMSkKYGBgCgpGaXJzdGx5LCBwbG90dGluZyBzdGFuZGFyZGlzZWQgcmVzaWR1YWxzIG92ZXIgdGltZS4gRnJvbSBsb29raW5nIGF0IHRoZSBnZW5lcmF0ZWQgcGxvdCwgaXQgaXMgcG9zc2libGUgdG8gc2F5IHRoYXQgdGhlcmUgaXMgbWFqb3IgZGVwYXJ0dXJlIGZyb20gcmFuZG9tbmVzcyBvZiB0aGUgcmVzaWR1YWxzLCBhIGNsZWFyIHBhdHRlcm4gY2FuIGJlIG9ic2VydmVkLCBzbyBmaXR0ZWQgbGluZWFyIG1vZGVsIHdhcyBub3Qgc3VjY2Vzc2Z1bCBhdCBjYXB0dXJpbmcgdGhlIGF1dG9jb3JyZWxhdGlvbiBlZmZlY3QgaW4gb3VyIHRpbWUgc2VyaWVzLiBXaGVuIHdlIHBsb3Qgc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBhZ2FpbnN0IGZpdHRlZCB2YWx1ZXMsIHdlIGNhbiBzZWUgdGhhdCB0aGUgcG9pbnRzIGFyZSBub3QgdmVyeSBldmVubHkgZGlzdHJpYnV0ZWQsIGFuZCBsYXJnZXIgbmVnYXRpdmUgcmVzaWR1YWxzIGFzc29jaWF0ZSB3aXRoIGxhcmdlciBuZWdhdGl2ZS9wb3NpdGl2ZSBmaXR0ZWQgdmFsdWVzLiBUaGVyZSBzZWVtcyB0byBiZSBzbGlnaHQgY3VydmlsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBhbmQgZml0dGVkIHZhbHVlcy4KCmBgYHtyfQpwbG90KHkgPSByZXNpZHVhbHMxLCB4ID0gYXMudmVjdG9yKHRpbWUob3pvbmUpKSwgeGxhYiA9ICdUaW1lJywgeWxhYiA9ICdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgdHlwZSA9ICdvJykKYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIikKcGxvdCh5ID0gcmVzaWR1YWxzMSwgeCA9IGZpdHRlZChtb2RlbDEpLCB5bGFiID0gJ1N0YW5kYXJkaXplZCBSZXNpZHVhbHMnLHhsYWIgPSAnRml0dGVkIFRyZW5kIExpbmUgVmFsdWVzJywgdHlwZSA9ICdwJykKYGBgCgpUaGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgcHJvZHVjZXMgYSBRLVEgUGxvdCBhbmQgYSBTaGFwaXJvLVdpbGsgdGVzdCB0byB0ZXN0IHRoZSBub3JtYWxpdHkgYXNzdW1wdGlvbi4gVGhlIHN0cmFpZ2h0IGxpbmUgcGF0dGVybiBpcyBub3Qgb2J2aW91cyBmcm9tIGEgUS1RIFBsb3QsIGJ1dCBnaXZlbiB0aGUgcmVwb3J0ZWQgdGVzdCBzdGF0aXN0aWNzIGFuZCAkcCQtdmFsdWUgPSAwLjU0LCB3ZSBmYWlsIHRvIHJlamVjdCB0aGUgJEhfMCQgdGhhdCB0aGUgc3RvY2hhc3RpYyBjb21wb25lbnQgb2YgbGluZWFyIG1vZGVsIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKYGBge3J9CnFxbm9ybShyZXNpZHVhbHMxKQpxcWxpbmUocmVzaWR1YWxzMSwgY29sID0gMiwgbHdkID0gMSwgbHR5ID0gMikKc2hhcGlyby50ZXN0KHJlc2lkdWFsczEpCmBgYAoKVGhlIGZvbGxvd2luZyBjb2RlIGdlbmVyYXRlcyB0aGUgc2FtcGxlIGF1dG9jb3JyZWxhdGlvbiBmdW5jdGlvbiBmb3Igc3RhbmRhcmRpemVkIHJlc2lkdWFscyBmcm9tIHRoZSBsaW5lYXIgdHJlbmQgbW9kZWwgb2YgdGhlIE96b25lIHNlcmllczoKCmBgYHtyfQphY2YocmVzaWR1YWxzMSwgbWFpbiA9ICJBQ0YgZm9yIHN0YW5kYXJkaXNlZCByZXNpZHVhbHMiKQpgYGAKClRoZSBsYWcgMSwgbGFnIDcgYW5kIGxhZyA4IGF1dG9jb3JyZWxhdGlvbnMgZXhjZWVkIHR3byBzdGFuZGFyZCBlcnJvcnMgYWJvdmUgemVyby4gVGhlcmUgaXMgYSBjbGVhciBwYXR0ZXJuIGluIHRoZSBzYW1wbGUgQUNGIGdyYXBoLCBzbyB3ZSBjYW4gaW5mZXIgdGhhdCB0aGUgc3RvY2hhc3RpYyBjb21wb25lbnQgb2YgdGhlIE96b25lIHRpbWUgc2VyaWVzIGlzIG5vdCB3aGl0ZSBub2lzZS4KCiMjIyBGaXR0aW5nIGEgcXVhZHJhdGljIHRyZW5kCgpUaGUgZGV0ZXJtaW5pc3RpYyBxdWFkcmF0aWMgdHJlbmQgbW9kZWwgaXMgZXhwcmVzc2VkIGFzIGZvbGxvd3M6CgokJFxtdV90ID0gXGJldGFfMCArIFxiZXRhXzF0ICsgXGJldGFfMnReMiQkClRoZSBmb2xsb3dpbmcgY29kZSBjaHVuY2sgZml0cyBhIHF1YWRyYXRpYyB0cmVuZCBtb2RlIHRvIHRoZSBPem9uZSBkYXRhLgoKYGBge3J9CnQyIDwtIHReMgptb2RlbDIgPC0gbG0ob3pvbmUgfiB0ICsgdDIpCnN1bW1hcnkobW9kZWwyKQpgYGAKClRoZSBlc3RpbWF0ZWQgbW9kZWwgaXM6ICRcbXVfdCA9IC01NzMzLjIzNzY0ICsgNS45MjQ2dCAtIDAuMDAxNTN0XjIkLiBBY2NvcmRpbmcgdG8gdGhlIGFkanVzdGVkIGNvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24sIGFib3V0IDczJSBvZiB0aGUgdmFyaWF0aW9uIGluIHRoZSBPem9uZSBzZXJpZXMgaXMgZXhwbGFpbmVkIGJ5IGEgcXVhZHJhdGljIHRpbWUgdHJlbmQuIAoKVGhlIGZvbGxvd2luZyBjb2RlIHN1cGVyaW1wb3NlcyB0aGUgZXN0aW1hdGVkIHF1YWRyYXRpYyBjdXJ2ZSB0byBvdXIgdGltZSBzZXJpZXMuIFRoZSBwbG90IHNob3dzIHRoYXQgdGhlIHF1YWRyYXRpYyB0cmVuZCBjYXB0dXJlcyB0aGUgZ2VuZXJhbCB0cmVuZCBtdWNoIGJldHRlciB0aGFuIHRoZSBsaW5lYXIgb25lIGJ1dCBzdGlsbCBkb2VzIG5vdCBkbyBhIGdvb2Qgam9iIGF0IGFwcHJveGltYXRpbmcgdGhlIGRhdGEuCgpgYGB7cn0KcGxvdCh0cyhmaXR0ZWQobW9kZWwyKSksIHggPSBhcy52ZWN0b3IodGltZShvem9uZSkpLCB5bGltID0gYyhtaW4oYyhmaXR0ZWQobW9kZWwyKSwgYXMudmVjdG9yKG96b25lKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChjKGZpdHRlZChtb2RlbDIpLGFzLnZlY3Rvcihvem9uZSkpKSksCiAgICAgeWxhYiA9ICdEb2Jzb24gVW5pdHMnLCB4bGFiID0gIlRpbWUiLCBtYWluID0gIkZpdHRlZCBxdWFkcmF0aWMgY3VydmUgdG8gT3pvbmUgc2VyaWVzIiwgdHlwZSA9ICJsIixjb2wgPSAicmVkIikKbGluZXMob3pvbmUsIHR5cGUgPSAibyIpCmBgYAoKIyMjIyBSZXNpZHVhbCBBbmFseXNpcwoKRnJvbSB0aGUgcGxvdCBvZiBzdGFuZGFyZGlzZWQgcmVzaWR1YWxzIG92ZXIgdGltZSwgd2Ugb2JzZXJ2ZSBhIHZlcnkgc2ltaWxhciBwaWN0dXJlIHRvIHRoZSBsaW5lYXIgdHJlbmQgbW9kZWwuIFJlc2lkdWFscyBhcmUgbm90IHJhbmRvbSwgcXVhZHJhdGljIG1vZGVsIHdhcyBub3Qgc3VjY2Vzc2Z1bCBhdCBjYXB0dXJpbmcgdGhlIGF1dG9jb3JyZWxhdGlvbiBlZmZlY3QgaW4gdGhlIHNlcmllcy4gV2hlbiB3ZSBwbG90IHN0YW5kYXJkaXNlZCByZXNpZHVhbHMgYWdhaW5zdCBmaXR0ZWQgdmFsdWVzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHBvaW50cyBhcmUgbm90IGV2ZW5seSBkaXN0cmlidXRlZCBhbmQgdGVuZCB0byBnYXRoZXIgdG93YXJkcyB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgcmVjdGFuZ2xlIGFzIGZpdHRlZCB2YWx1ZXMgYXBwcm9hY2ggMC4KCmBgYHtyfQpyZXNpZHVhbHMyIDwtIHJzdHVkZW50KG1vZGVsMikKcGxvdCh5ID0gcmVzaWR1YWxzMiwgeCA9IGFzLnZlY3Rvcih0aW1lKG96b25lKSksIHhsYWIgPSAnVGltZScsIHlsYWIgPSAnU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHR5cGU9J28nKQphYmxpbmUoaCA9IDAsIGNvbCA9ICJyZWQiKQpwbG90KHkgPSByZXNpZHVhbHMyLCB4ID0gZml0dGVkKG1vZGVsMiksIHlsYWIgPSAnU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHhsYWIgPSAnRml0dGVkIFRyZW5kIExpbmUgVmFsdWVzJywgdHlwZSA9ICdwJykKYGBgCgpUaGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgcHJvZHVjZXMgYSBRLVEgUGxvdCBhbmQgYSBTaGFwaXJvLVdpbGsgdGVzdCB0byBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24uIEdpdmVuIHRoZSBzdHJhaWdodCBsaW5lIHBhdHRlcm4gZnJvbSBhIFEtUSBQbG90IGFuZCB0aGUgcmVwb3J0ZWQgdGVzdCBzdGF0aXN0aWNzIHdpdGggJHAkLXZhbHVlID0gMC42NSwgd2UgZmFpbCB0byByZWplY3QgdGhlICRIXzAkIHRoYXQgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IG9mIHF1YWRyYXRpYyBtb2RlbCBpcyBub3JtYWxseSBkaXN0cmlidXRlZC4KCmBgYHtyfQpxcW5vcm0ocmVzaWR1YWxzMikKcXFsaW5lKHJlc2lkdWFsczIsIGNvbCA9IDIsIGx3ZCA9IDEsIGx0eSA9IDIpCnNoYXBpcm8udGVzdChyZXNpZHVhbHMyKQpgYGAKClRoZSBmb2xsb3dpbmcgY29kZSBnZW5lcmF0ZXMgdGhlIHNhbXBsZSBhdXRvY29ycmVsYXRpb24gZnVuY3Rpb24gZm9yIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgZnJvbSB0aGUgcXVhZHJhdGljIHRyZW5kIG1vZGVsIG9mIHRoZSBPem9uZSBzZXJpZXM6CgpgYGB7cn0KYWNmKHJzdHVkZW50KG1vZGVsMiksIG1haW4gPSAiQUNGIGZvciBzdGFuZGFyZGlzZWQgcmVzaWR1YWxzIikKYGBgCgpBcyBpbiB0aGUgbGluZWFyIG1vZGVsIGNhc2UsIGFmdGVyIGZpdHRpbmcgYSBxdWFkcmF0aWMgdHJlbmQsIHNvbWUgYXV0b2NvcnJlYXRpb24gcmVtYWlucyBpbiB0aGUgcmVzaWR1YWxzIGZyb20gdGhpcyBtb2RlbC4gTGFnIDEgYW5kIGxhZyA3IGF1dG9jb3JyZWxhdGlvbnMgZXhjZWVkIHR3byBzdGFuZGFyZCBlcnJvcnMgYWJvdmUgemVybywgd2hpbGUgbGFnIDMsIDQsIDEwIC0gYmVsb3cgemVyby4gQWZ0ZXIgZXhhbWluaW5nIHRoZSByZXNpZHVhbHMsIHdlIGNhbiBpbmZlciB0aGF0IHRoZSBzdG9jaGFzdGljIGNvbXBvbmVudCBpbiBvdXIgdGltZSBzZXJpZXMgZG9lcyBub3QgYmVoYXZlIGxpa2Ugd2hpdGUgbm9pc2UuCgojIyMgRml0dGluZyBhIGxpbmVhciBjb21iaW5hdGlvbiBvZiB0cmVuZHMKClRoZSBjb21iaW5hdGlvbiBvZiBjb3NpbmUgYW5kIHF1YWRyYXRpYyB0cmVuZHMgd2FzIGF0dGVtcHRlZCB0byBmaXQgdGhlIE96b25lIHRpbWUgc2VyaWVzLiBUbyBmaXQgYSBoYXJtb25pYyBjb21wb25lbnQgb2YgdGhlIG1vZGVsIHRvIHRoZSBPem9uZSB0aW1lIHNlcmllcywgYSBuZXcgdGltZSBzZXJpZXMgYG96b25lX25ld2Agd2FzIGNyZWF0ZWQuIFRoZSBmcmVxdWVuY3kgd2FzIHJvdWdobHkgZGV0ZXJtaW5lZCBieSBsb29raW5nIGF0IHRoZSB0aW1lIHNlcmllcyBwbG90IG9mIHRoZSBkYXRhLiBFeHBlcmltZW50aW5nIHdpdGggZGlmZmVyZW50IHZhbHVlcyBzaG93ZWQgdGhhdCBmcmVxdWVuY3kgb2YgOCBnYXZlIHRoZSBiZXN0IHJlc3VsdHMgaW4gdGVybXMgb2YgJFJeMiQuIAoKYGBge3J9Cm96b25lX25ldyA8LSB0cyhhcy52ZWN0b3IoZGF0YTEpLCBmcmVxdWVuY3kgPSA4KQp0X25ldyA8LSB0aW1lKG96b25lX25ldykKdDJfbmV3IDwtIHRfbmV3XjIKaGFyIDwtIGhhcm1vbmljKG96b25lX25ldywgMSkKbW9kZWwzIDwtIGxtKG96b25lX25ldyB+IGhhciArIHRfbmV3ICsgdDJfbmV3KQpzdW1tYXJ5KG1vZGVsMykKYGBgCgpUaGUgZXN0aW1hdGVkIG1vZGVsIGlzOiAkXG11X3QgPSAtMC40ODkxNiAtMC4yNzE3N2NvcygyXHBpIHQpIC0gMC41ODY5NzJzaW4oMlxwaSB0KSArIDAuMzY3Nzd0IC0gMC4wOTU0NHReMiQuIE1vZGVsIHN1bW1hcnkgcmVwb3J0cyB0aGF0IG9ubHkgdGhlIHNpbmUgYW5kIHF1YWRyYXRpYyB0ZXJtcyBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhdCA1JSBsZXZlbC4gQWNjb3JkaW5nIHRvIHRoZSByZXBvcnRlZCBhZGp1c3RlZCAkUl4yJCwgYWJvdXQgNzQuNSUgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgT3pvbmUgc2VyaWVzIGlzIGV4cGxhaW5lZCBieSBhIGNvbWJpbmF0aW9uIG9mIGNvc2luZSBhbmQgcXVhZHJhdGljIHRpbWUgdHJlbmRzLiAKClRoZSBmb2xsb3dpbmcgY29kZSBzdXBlcmltcG9zZXMgdGhlIGVzdGltYXRlZCBjdXJ2ZSB0byBvdXIgdGltZSBzZXJpZXMuIFRoZSBwbG90IHNob3dzIHRoYXQgdGhpcyBtb2RlbCBjYXB0dXJlcyB0aGUgZ2VuZXJhbCB0cmVuZCBhcyB3ZWxsIGFzIHRyaWVzIHRvIHJvdWdobHkgYXBwcm94aW1hdGUgdGhlIGRhdGEuCgpgYGB7cn0KcGxvdCh0cyhmaXR0ZWQobW9kZWwzKSwgc3RhcnQgPSAxOTI3LCBlbmQgPSAyMDE2KSwgeWxpbSA9IHJhbmdlKGMoZml0dGVkKG1vZGVsMyksIG96b25lKSksIHlsYWI9J0RvYnNvbiBVbml0cycsIHhsYWIgPSAiVGltZSIsIAogICAgIG1haW4gPSAiRml0dGVkIGN1cnZlIHRvIE96b25lIHNlcmllcyIsIHR5cGUgPSAibCIsY29sID0gInJlZCIpCmxpbmVzKG96b25lLHR5cGU9Im8iKQpgYGAKCiMjIyMgUmVzaWR1YWwgYW5hbHlzaXMKCkFsdGhvdWdoIG5vdCBhbGwgY29lZmZpY2llbnRzIG9mIHRoZSBjb21iaW5hdGlvbiB0cmVuZCB3ZXJlIGZvdW5kIHNpZ25pZmljYW50LCB3ZSBzdGlsbCB3aWxsIHByb2NlZWQgdG8gYW5hbHlzZSB0aGUgc3RhbmRhcmRpc2VkIHJlc2lkdWFscyB0byBoYXZlIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcuIEZyb20gdGhlIHBsb3Qgb2Ygc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBvdmVyIHRpbWUsIHdlIG9ic2VydmUgYSB2ZXJ5IHNpbWlsYXIgcGljdHVyZSB0byB0aGUgcHJldmlvdXMgdHdvIG1vZGVscy4gUmVzaWR1YWxzIGFyZSBub3QgcmFuZG9tLiBXaGVuIHdlIHBsb3Qgc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBhZ2FpbnN0IGZpdHRlZCB2YWx1ZXMsIHdlIGNhbiBzZWUgdGhhdCB0aGUgcG9pbnRzIGFyZSBub3QgZXZlbmx5IGRpc3RyaWJ1dGVkIGluIHRoZSByZWN0YW5nbGUsIHRob3VnaCBjaGFuZ2luZyB2YXJpYW5jZSBpcyBub3Qgb2J2aW91cy4KCmBgYHtyfQpyZXNpZHVhbHMzIDwtIHJzdHVkZW50KG1vZGVsMykKcGxvdCh5ID0gcmVzaWR1YWxzMywgeCA9IGFzLnZlY3Rvcih0aW1lKG96b25lKSksIHhsYWIgPSAnVGltZScsIHlsYWIgPSAnU3RhbmRhcmRpemVkIFJlc2lkdWFscycsIHR5cGUgPSAnbycpCmFibGluZShoID0gMCwgY29sID0gInJlZCIpCnBsb3QoeSA9IHJlc2lkdWFsczMsIHggPSBmaXR0ZWQobW9kZWwzKSwgeWxhYiA9ICdTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzJywgeGxhYiA9ICdGaXR0ZWQgVHJlbmQgTGluZSBWYWx1ZXMnLCB0eXBlID0gJ3AnKQpgYGAKClRoZSBmb2xsb3dpbmcgY29kZSBjaHVuayBnZW5lcmF0ZXMgYSBRLVEgUGxvdCBhbmQgYSBTaGFwaXJvLVdpbGsgdGVzdCB0byBjaGVjayB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24uIEdpdmVuIHRoZSBzdHJhaWdodCBsaW5lIHBhdHRlcm4gZnJvbSBhIFEtUSBQbG90IGFuZCB0aGUgcmVwb3J0ZWQgdGVzdCBzdGF0aXN0aWNzIHdpdGggJHAkLXZhbHVlID0gMC40OSwgd2UgZmFpbCB0byByZWplY3QgdGhlICRIXzAkIHRoYXQgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IG9mIGEgY29tYmluYXRpb24gbW9kZWwgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuCgpgYGB7cn0KcXFub3JtKHJlc2lkdWFsczMpCnFxbGluZShyZXNpZHVhbHMzLCBjb2wgPSAyLCBsd2QgPSAxLCBsdHkgPSAyKQpzaGFwaXJvLnRlc3QocmVzaWR1YWxzMykKYGBgCgpBcyBpbiB0d28gcHJldmlvdXMgY2FzZXMsIGFmdGVyIGZpdHRpbmcgYSBjb21iaW5hdGlvbiB0cmVuZCwgc29tZSBhdXRvY29ycmVhdGlvbiBzdGlsbCByZW1haW5zIGluIHRoZSByZXNpZHVhbHMgZnJvbSB0aGlzIG1vZGVsLiBXZSBoYXZlIGNvcnJlbGF0aW9uIHZhbHVlcyBoaWdoZXIgdGhhbiB0aGUgY29uZmlkZW5jZSBib3VuZHMgYXQgc2V2ZXJhbCBsYWdzLiBBZnRlciBhbmFseXNpbmcgdmFyaW91cyByZXNpZHVhbCBwbG90cywgd2UgY2FuIGluZmVyIHRoYXQgdGhlIHN0b2NoYXN0aWMgY29tcG9uZW50IGluIG91ciB0aW1lIHNlcmllcyBkb2VzIG5vdCBiZWhhdmUgbGlrZSB3aGl0ZSBub2lzZS4KCmBgYHtyfQphY2YocnN0dWRlbnQobW9kZWwzKSwgbWFpbiA9ICJBQ0YgZm9yIHN0YW5kYXJkaXNlZCByZXNpZHVhbHMiKQpgYGAKCiMjIEZvcmVjYXN0aW5nIHdpdGggcXVhZHJhdGljIHRyZW5kIG1vZGVsCgpBbHRob3VnaCBub24gb2YgdGhlIGZpdHRlZCB0cmVuZCBtb2RlbHMgYXJlIHN1aXRhYmxlIGZvciBwcmVkaWN0aW9uIHB1cnBvc2VzIGJhc2VkIG9uIHRoZSByZXNpZHVhbCBhbmFseXNpcywgcHJlZGljdGlvbnMgb2YgeWVhcmx5IGNoYW5nZXMgaW4gdGhlIG96b25lIGxheWVyIHRoaWNrbmVzcyBmb3IgdGhlIG5leHQgNSB5ZWFycyB3ZXJlIGF0dGVtcHRlZC4gVGhlIG1vZGVsIHVzZWQgZm9yIG1ha2luZyBwcmVkaWN0aW9ucyB3YXMgdGhlIHF1YWRyYXRpYyB0cmVuZCBiZWNhdXNlIGFsbCB0aGUgdGVybXMgd2VyZSBmb3VuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGF0IDUlIGxldmVsIHVubGlrZSB0aGUgY29tYmluYXRpb24gdHJlbmQsIGFuZCBpdCBoYXMgYW4gYWNjZXB0YWJsZSB2YWx1ZSBvZiBhZGp1c3RlZCAkUl4yJC4KClRoZSBmb2xsb3dpbmcgY29kZSBjaHVuayBtYWtlcyBwcmVkaWN0aW9ucyBmb3IgbmV4dCA1IHRpbWUgcG9pbnRzLiBUaGUgbGFzdCBsZXZlbCBvZiB0aGUgT3pvbmUgdGltZSBzZXJpZXMgaXMgZm9yIHllYXIgMjAxNi4gU28gd2UgYXJlIHByZWRpY3RpbmcgY2hhbmdlcyBmb3IgeWVhcnMgMjAxNy0yMDIxLgoKYGBge3J9CnByZWQgPC0gc2VxKGZyb20gPSAyMDE3LCBieSA9IDEsIGxlbmd0aC5vdXQgPSA1KSAKcHJlZDIgPC0gcHJlZF4yCm5ldyA8LSBkYXRhLmZyYW1lKHQgPSBwcmVkLCB0MiA9IHByZWQyKQpmb3JlY2FzdHMgPC0gcHJlZGljdChtb2RlbDIsIG5ld2RhdGEgPSBuZXcsIGludGVydmFsID0gInByZWRpY3Rpb24iKQpmb3JlY2FzdHMKYGBgCgpBZGRpbmcgZ2VuZXJhdGVkIGZvcmVjYXN0cyBhbmQgdGhlaXIgcHJlZGljdGlvbiBpbnRlcnZhbHMgdG8gdGhlIHRpbWUgc2VyaWVzIHBsb3Q6CgpgYGB7cn0KcGxvdChvem9uZSwgeGxpbSA9IGMoMTkyNywgMjAyMiksIHlsaW0gPSBjKC0xNiwgNSkpCmxpbmVzKHRzKGFzLnZlY3Rvcihmb3JlY2FzdHNbLDFdKSwgc3RhcnQgPSAyMDE3KSwgY29sPSJyZWQiLCB0eXBlPSJsIikKbGluZXModHMoYXMudmVjdG9yKGZvcmVjYXN0c1ssMl0pLCBzdGFydCA9IDIwMTcpLCBjb2w9ImJsdWUiLCB0eXBlPSJsIikKbGluZXModHMoYXMudmVjdG9yKGZvcmVjYXN0c1ssM10pLCBzdGFydCA9IDIwMTcpLCBjb2w9ImJsdWUiLCB0eXBlPSJsIikKbGVnZW5kKCJ0b3ByaWdodCIsIGx0eT0xLCBwY2g9MSwgY29sPWMoImJsYWNrIiwiYmx1ZSIsInJlZCIpLCB0ZXh0LndpZHRoID0gMjIsIGMoIkRhdGEiLCI1JSBmb3JlY2FzdCBsaW1pdHMiLCAiRm9yZWNhc3RzIikpCmBgYAoKIyMgQ29uY2x1c2lvbgoKVG8gZmluZCB0aGUgYmVzdCBmaXR0aW5nIHRyZW5kIG1vZGVsIHRvIHRoZSBPem9uZSB0aW1lIHNlcmllcywgdGhyZWUgbW9zdCBwcm9taXNpbmcgbW9kZWxzIHdlcmUgaWRlbnRpZmllZC4gVGhleSB3ZXJlOiBsaW5lYXIsIHF1YWRyYXRpYyBhbmQgYSBjb21iaW5hdGlvbiBvZiBjb3NpbmUgYW5kIHF1YWRyYXRpYyB0cmVuZHMuIEFsbCB0aHJlZSBtb2RlbHMgd2VyZSBlc3RpbWF0ZWQgYW5kIGZpdHRlZCB0byB0aGUgZGF0YSB1c2luZyBvcmRpbmFyeSByZWdyZXNzaW9uIGFwcHJvYWNoLiBUaGUgcHJvY2VzcyB3YXMgZm9sbG93ZWQgYnkgYW5hbHlzaW5nIHRoZSBiZWhhdmlvdXIgb2Ygc3RhbmRhcmRpc2VkIHJlc2lkdWFscyBmcm9tIHRoZXNlIG1vZGVscy4gVGhlIHJlc2lkdWFscyBpbnZlc3RpZ2F0aW9uIHNob3dlZCB0aGF0IGFsdGhvdWdoIGFsbCB0aHJlZSBtb2RlbHMgbWFuYWdlZCB0byBjYXB0dXJlIHRoZSBnZW5lcmFsIHRyZW5kIGluIHRoZSBzZXJpZXMsIHRoZXJlIHdhcyBhbHdheXMgc29tZSBhdXRvY29ycmVsYXRpb24gcmVtYWluaW5nIGluIHRoZSByZXNpZHVhbHMuIAoKVGhlIHF1YWRyYXRpYyB0cmVuZCB3YXMgZGVjaWRlZCB0byBiZSB0aGUgImJlc3QgZml0dGluZyIgaW4gdGVybXMgb2Ygc2lnbmlmaWNhbmNlIG9mIGNvZWZmaWNpZW50cyBhbmQgaXRzIGFkanVzdGVkICRSXjIkIHZhbHVlLiBJdCB3YXMgZnVydGhlciB1c2VkIHRvIG1ha2UgcHJlZGljdGlvbnMgb2YgeWVhcmx5IGNoYW5nZXMgaW4gdGhlIG96b25lIGxheWVyIHRoaWNrbmVzcyBmb3IgbmV4dCA1IHllYXJzLiBUaGVzZSBmb3JlY2FzdHMgY2Fubm90IGJlIGNvbnNpZGVyZWQgY29ycmVjdCBhbmQgY2Fubm90IGJlIHRydXN0ZWQuCgpUbyBzdW0gdXAsIGZpdHRpbmcgYSBkZXRlcm1pbmlzdGljIHRyZW5kIHRvIHRoZSBPem9uZSB0aW1lIHNlcmllcyBkaWQgbm90IHJlc3VsdCBpbnRvIGEgcXVhbGl0eSBtb2RlbCB0aGF0IGNhbiBiZSB1c2VkIGZvciBmdXJ0aGVyIHByZWRpY3Rpb24uIEZpdHRpbmcgQVJJTUEgbW9kZWxzIGNhbiBiZSB0aGUgZGlyZWN0aW9uIGZvciBmdXR1cmUgaW52ZXN0aWdhdGlvbi4KCgoKPGJyPgo8YnI+