Introduction
Time series decomposition is a process of splitting a time series
into basic components: trend, seasonality random error. The method
originated a century ago and new developments in the past few
decades.
Seasonal Patterns that repeat for a fixed period.
For example, a website might receive more visits during weekends; this
would produce data with seasonality of 7 days.
Trend: The underlying trend of the metrics. A
website increasing in popularity should show a general trend that goes
up.
Random Error: Also call “noise”, “residual” or
“remainder”. These are the residuals of the original time series after
the seasonal and trend series are removed.
The objective of time series decomposition is to model the trend and
seasonality and estimate the overall time series as a combination of
them. A seasonally adjusted value removes the seasonal effect from a
value so that trends can be seen more clearly.
The following two working data sets were widely used in different
textbooks. We will use them to illustrate some of the concepts.
Australian Beer Production Data
The following data gives quarterly beer production figures in
Australia from 1956 through the 2nd quarter of 2010. The beer production
figure is in megalitres.
ausbeer0=c(284, 213, 227, 308, 262, 228, 236, 320, 272, 233, 237, 313, 261, 227, 250, 314,
286, 227, 260, 311, 295, 233, 257, 339, 279, 250, 270, 346, 294, 255, 278, 363,
313, 273, 300, 370, 331, 288, 306, 386, 335, 288, 308, 402, 353, 316, 325, 405,
393, 319, 327, 442, 383, 332, 361, 446, 387, 357, 374, 466, 410, 370, 379, 487,
419, 378, 393, 506, 458, 387, 427, 565, 465, 445, 450, 556, 500, 452, 435, 554,
510, 433, 453, 548, 486, 453, 457, 566, 515, 464, 431, 588, 503, 443, 448, 555,
513, 427, 473, 526, 548, 440, 469, 575, 493, 433, 480, 576, 475, 405, 435, 535,
453, 430, 417, 552, 464, 417, 423, 554, 459, 428, 429, 534, 481, 416, 440, 538,
474, 440, 447, 598, 467, 439, 446, 567, 485, 441, 429, 599, 464, 424, 436, 574,
443, 410, 420, 532, 433, 421, 410, 512, 449, 381, 423, 531, 426, 408, 416, 520,
409, 398, 398, 507, 432, 398, 406, 526, 428, 397, 403, 517, 435, 383, 424, 521,
421, 402, 414, 500, 451, 380, 416, 492, 428, 408, 406, 506, 435, 380, 421, 490,
435, 390, 412, 454, 416, 403, 408, 482, 438, 386, 405, 491, 427, 383, 394, 473,
420, 390, 410)
This data set records monthly totals of international airline
passengers (1949-1960).
AirPassengers0=c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141,
135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178,
199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209,
191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201,
204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267,
269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374,
413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404,
347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337,
360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419,
461, 472, 535, 622, 606, 508, 461, 390, 432)
Understanding the
Classical Decomposition of Time Series
To understand the structure of additive and multiplication ties
series, we decompose these time series by calculating the trend,
seasonality, and errors manually by writing a basic R script to
gain a technical understanding of decomposing a time series. At the very
end of this section, we introduce the R function
decompose() to extract the three components of additive
and multiplicative time series.
Detect Trend
To detect the underlying trend, we use a smoothing technique called
moving average and it’s variant centered moving
average. For a seasonal time series, the width of the moving
window must be the same as the seasonality. Therefore, to decompose a
time series we need to know the seasonality period: weekly, monthly,
etc.
Example 1: Australian beer production data has an
annual seasonality. Since the data set is quarterly data, the moving
average window should be 4.
trend.beer = ma(ausbeer.ts, order = 12, centre = T) # centre = T => centered moving average
par(mar=c(2,2,2,2))
plot(as.ts(ausbeer.ts), xlab="", ylab="", col="darkred", lwd =2)
title(main = "Extract trend from Australia Beer Production")
lines(trend.beer, lwd =2, col = "blue")
legend("topleft", c("original series", "trend curve"), lwd=rep(2,2),
col=c("darkred", "blue"), bty="n")
Example 2: The airline passenger data were recorded
monthly. It has an annual seasonal pattern. We choose a moving average
window of 12 to extract the trend from this multiplicative time
series.
trend.air = ma(AirPassengers.ts, order = 12, centre = T)
# centre = T => centered moving average
par(mar=c(2,2,2,2))
plot(as.ts(AirPassengers.ts), xlab="", ylab="", col="darkred", lwd =2)
title(main = "Extract trend from Airline Passengers Monthly Data")
lines(trend.air, lwd =2, col = "blue")
legend("topleft", c("original series", "trend curve"), lwd=rep(2,2),
col=c("darkred", "blue"), bty="n")
The moving averages of both time series are recorded
in the above two code chunks and will be used to restore the original
series.
The process of removing the trend from a time series is called
detrending time series.
The way of detrending a time series is dependent on the types of the
time series. The following code shows how to calculate the detrended
time series.
Example 3: We calculate the detrended series using
the Australian Beer data and the Airline Passengers data as an
example.
detrend.beer = ausbeer.ts - trend.beer ## additive model
detrend.air = AirPassengers.ts/trend.air ## multiplicative model
par(mar=c(2,2,2,2))
par(mfrow=c(1,2))
# plot(ausbeer.ts, xlab="", main = "Australia Beer", col="darkred")
# plot(AirPassengers.ts, xlab="", main = "Air Passengers", col="blue")
plot(detrend.beer, xlab="", main = "Australia Beer", col="darkred")
plot(detrend.air, xlab="", main = "Air Passengers", col="blue")
The technique we used in removing the trend from a time series model
is a non-parametric smoothing procedure. There are different techniques
in statistics to estimate a curve for a given set. The moving
average is one of the simplest ones and is widely used in time
series.
Extracting Remainder
Errors
The error term is the random component in the time
series. We learned the of extracting the trend and seasonality from the
original time series. How to extract the “random” noise from a given
time series?
In the additive model, the random error term is
given by \(E_t = y_t - T_t -S_t\). The
random error for a multiplicative model is given by
\(E_t = y_t/(T_t \times S_t)\).
Example 5: Use the above formulas to separate the
random error components in additive and multiplicative models using
Australian beer production and Airline passenger series data.
random.beer = ausbeer.ts - trend.beer - seasonal.beer
random.air = AirPassengers.ts / (trend.air * seasonal.air)
##
par(mfrow=c(2,1), mar=c(3,2,3,2))
plot(random.beer , xlab = "", col="darkred", main="Random errors of Australia beer")
plot(random.air, xlab = "", col = "blue", main="Random errors of air passengers")
Reconstruct the
Original Series / Compose New Series
The original series can be reconstructed by using
the decomposed components. Since the moving average
technique was used in the detrending series, the resulting
reconstructed series with \(T_t\), \(S_t\), and \(E_t\) will generate a few missing values in
the beginning and the end depending on the width of the moving
average window.
Example 6: Reconstruct the
original series of Australian beer data and the airline
passenger data.
recomposed.beer = trend.beer+seasonal.beer+random.beer
recomposed.air = trend.air*seasonal.air*random.air
par(mfrow=c(1,2), mar=c(3,2,3,2))
plot(ausbeer.ts, col="darkred", lty=1)
lines(recomposed.beer, col="blue", lty=2, lwd=2)
legend("topleft", c("original series", "reconstructed series"),
col=c("darkred", "blue"), lty=1:2, lwd=1:2, cex=0.8, bty="n")
title(main="Australian Beer")
##
plot(AirPassengers.ts, col="darkred", lty=1)
lines(recomposed.air, col="blue", lty=2, lwd=2)
legend("topleft", c("original series", "reconstructed series"),
col=c("darkred","blue"), lty=1:2, lwd=1:2, cex=0.8, bty="n")
title(main="Airline Passengers")
Decomposing Time
Series with decompose()
The R library forecast was created by a team led by
a leading expert in the discipline. We’ll use the R function
decompose( ) in library{forecast} as a decomposition
function to decompose a series into seasonal, trend, and random
components. The Australian beer production (additive) and airline
passenger numbers (multiplicative) will still be used to illustrate the
steps.
Example 6: Plot the components of the Australian
beer production data.
decomp.beer = decompose(ausbeer.ts, "additive")
## plot the decomposed components
par(mar=c(2,2,2,2), oma=c(0,2,2,0))
plot(decomp.beer, col="darkred", xlab="")

Example 7: Plot the components of the Airline
Passenger Data.
decomp.air = decompose(AirPassengers.ts, "multiplicative")
## plot the decomposed components
par(mar=c(2,2,2,2), oma=c(0,2,2,0))
plot(decomp.air, col= "navy", xlab="")

Th R function decompose() can be used to extract the
individual components from a given additive and multiplicative model
using the following code.
Example 8: Decomposing Australian beer production
data using decompose().
decomp.beer = decompose(ausbeer.ts, "additive")
# the four components can be extracted by
seasonal.beer = decomp.beer$seasonal
trend.beer = decomp.beer$trend
error.beer = decomp.beer$random
Example 9: Decomposing airline passengers data using
decompose().
decomp.air = decompose(AirPassengers.ts, "multiplicative")
# the four components can be extracted by
seasonal.air = decomp.air$seasonal
trend.air = decomp.air$trend
error.air = decomp.air$random
Concluding Remark: There are other decomposition
methods. among them, X11 is commonly used in
econometrics. The recently developed method STL() that
used LOESS algorithm to estimate the trend can also be used to extract
components from more general time series. We will outline this
decomposition method to forecast future values.
Forecasting with
Decomposing
Several benchmark forecasting methods were introduced in the previous
module. Next, we use these benchmark methods to forecast the
deseasonalized series. Since the seasonality of a time series is a
scalar, we can forecast the deseasonalized series
through decomposition and then adjust the forecasted values.
Forecasting Additive
Models with Decomposing
Since the multiplicative models can be converted to an additive model
by
\[
\log(y_t) = \log(S_t) + \log(T_t) + \log(E_t).
\]
So we only restrict our discussion in this module to additive models.
Assuming an additive decomposition, the decomposed time series can be
written as
\[y_t = \hat{S}_t + \hat{A}_t\]
where \(\hat{A}_t = \hat{T} +
\hat{E}_t\) is the seasonally adjusted component. We can forecast
the future values based on \(\hat{A}_t\).
Example 10: Forecasting based on the seasonally
adjusted series with Australian beer production data. We introduced four
benchmark forecasting methods in the previous module. For a time series
with a trend, naive, seasonal naive, and drift method is more accurate
than the moving average. The issue is that none of the benchmark methods
forecast the trend. As an illustrative example, we use the naive method
to forecast the deseasonalized series and then add the seasonal
adjustment to the forecast values.
decomp.beer = decompose(ausbeer.ts, "additive")
# the four components can be extracted by
seasonal.beer = decomp.beer$seasonal
trend.beer = decomp.beer$trend
error.beer = decomp.beer$random
seasonal.adj = trend.beer + error.beer
deseasonalized.pred = as.data.frame(rwf(na.omit(seasonal.adj), h = 6))
seasonality = matrix(rep(seasonal.beer[3:8],5), nco=5, byrow=F)
seasonal.adj.pred <- deseasonalized.pred + seasonality
kable(seasonal.adj.pred, caption = "Forecasting with decomposing - drift method")
Forecasting with decomposing - drift method
| 1973 Q3 |
404.7167 |
386.3725 |
423.0608 |
376.6617 |
432.7717 |
| 1973 Q4 |
486.6167 |
460.6741 |
512.5593 |
446.9409 |
526.2924 |
| 1974 Q1 |
437.1500 |
405.3769 |
468.9231 |
388.5573 |
485.7427 |
| 1974 Q2 |
387.0000 |
350.3116 |
423.6884 |
330.8900 |
443.1100 |
| 1974 Q3 |
404.7167 |
363.6978 |
445.7355 |
341.9838 |
467.4496 |
| 1974 Q4 |
486.6167 |
441.6828 |
531.5505 |
417.8962 |
555.3371 |
Since the deseasonalized series has two missing values in the
beginning and two in the end. we remove the missing values before using
the drift methods to forecast the next 6 periods (qtr3, 1973 - qtr 4,
1874). The forecast values are given in the above table.
par(mar=c(2,2,2,2))
plot(1:62, as.vector(ausbeer.ts)[-c(63,64)], type="l", xlim=c(1,70), ylim=c(200, 570),
xlab="", ylab="Beer Production", main="Forecast with classical decomposing")
lines(62:64, as.vector(ausbeer.ts)[c(62,63,64)], col="red")
points(62:64, as.vector(ausbeer.ts)[c(62,63,64)], col="red", pch=21)
lines(63:68,seasonal.adj.pred[,1], col="blue")
points(63:68,seasonal.adj.pred[,1], col="blue", pch = 16)
The plot of the forecast values and the original values. The red plot
represented quarters 3-4 of 1973 and forecast values in quarters 3 -
quarters 4, 1974, are plotted in blue. We can see
that
Concepts of Seasonal
and Trend Decomposition Using Loess (STL)
Seasonal and Trend decomposition using LOESS (STL) combines the
classical time series decomposition and the modern
locally estimated scatterplot smoothing (LOESS). The LOESS has developed
about 40 years ago and is a modern computational algorithm. The seasonal
trend in a time series is a fixed pattern. The real
benefit of STL is to use the LOESS to estimate the nonlinear trend more
accurately. We will not discuss the technical development of the STL.
Instead, we will use its R implementation to decompose time series and
use it to forecast future values.
stl.beer = stl(ausbeer.ts, "periodic")
seasonal.stl.beer <- stl.beer$time.series[,1]
trend.stl.beer <- stl.beer$time.series[,2]
random.stl.beer <- stl.beer$time.series[,3]
###
par(mfrow=c(4,1), mar=c(2,2,2,2))
plot(ausbeer.ts)
plot(as.ts(seasonal.stl.beer))
plot(trend.stl.beer)
plot(random.stl.beer)
We can also plot the above-decomposed components in a single step as
follows with the STL model.
plot(stl.beer)
Forecast with STL
decomposing
For the additive model, we can use the R function
stl() to decompose the series into three components. It
uses a more robust non-parametric smoothing method (LOESS) to estimate
the nonlinear trend.
fit <- stl(ausbeer.ts,s.window="periodic")
par(mar=c(2,2,2,2))
plot(forecast(fit,h=6, method="rwdrift"))
Length of Time
Series
The length of the time series impacts the performance of the
forecasting. In general, a very long time series (for example, more than
200 observations) usually does not work well for most of the existing
models partly because the existing models were not built for
very long series. Intuitively, future values are
dependent on recent historical values. If including too old observations
that have no predictive power in the model will bring bias and noise to
the underlying model and, hence, negative impacts on the performance of
the model.
There are a lot of discussions in literature and practice about the
minimum size required for building a good time series model. It seems
that 60 is the suggested minimum size. The actual minimum size depends
on the situation and the level of accuracy.
In this class, we recommend the sample size be between 60 and 200.
Therefore, in the assignment, if the original time series data has more
than 200 observations, we can use only 150-200 most recent data values
for analysis.
Case Study
Data description
and
The time series used in this case study is chosen from https://datahub.io/search: 10-year
nominal yields on US government bonds from the Federal Reserve. The
10-year government bond yield is considered a standard indicator of
long-term interest rates. The data contains monthly rates. There are 808
months of data between April 1943 and July 2020. We only use look at
monthly data between January 2008 and July 2020.
us.bond=read.csv("https://datahub.io/core/bond-yields-us-10y/r/monthly.csv")
n.row = dim(us.bond)[1]
data.us.bond = us.bond[(n.row-150):n.row, ]
Define time series
object
Since this is monthly data, frequency =12 will be used the define the
time series object.
usbond.ts = ts(data.us.bond[,2], frequency = 12, start = c(2008, 1))
par(mar=c(2,2,2,2))
plot(usbond.ts, main="US Bond Rates Between Jan, 2008 and July, 2020", ylab="Monthly Rate", xlab="")
Forecasting with
Decomposing
Notice that the classical decomposition method does not work as well
as the STL method due to the robustness of the LOESS component. The
following visual representations show the different behaviors of the two
methods of decomposition.
cls.decomp = decompose(usbond.ts)
par(mar=c(2,2,2,2))
plot(cls.decomp, xlab="")
stl.decomp=stl(usbond.ts, s.window = 12)
par(mar=c(2,2,2,2))
plot(stl.decomp)
Training and Testing Data
We hold up the last 7 periods of data for testing.
The rest of the historical data will be used to train the forecast
model.
To evaluate the effect of different sizes in training the time
series, We define different training data sets with different sizes.
Three training set sizes used in this example are 144, 109, 73, and 48.
The same test set with size 7 will be used to calculate the prediction
error.
ini.data = data.us.bond[,2]
n0 = length(ini.data)
##
train.data01 = data.us.bond[1:(n0-7), 2]
train.data02 = data.us.bond[37:(n0-7), 2]
train.data03 = data.us.bond[73:(n0-7), 2]
train.data04 = data.us.bond[97:(n0-7), 2]
## last 7 observations
test.data = data.us.bond[(n0-6):n0,2]
##
train01.ts = ts(train.data01, frequency = 12, start = c(2008, 1))
train02.ts = ts(train.data02, frequency = 12, start = c(2011, 1))
train03.ts = ts(train.data03, frequency = 12, start = c(2014, 1))
train04.ts = ts(train.data04, frequency = 12, start = c(2016, 1))
##
stl01 = stl(train01.ts, s.window = 12)
stl02 = stl(train02.ts, s.window = 12)
stl03 = stl(train03.ts, s.window = 12)
stl04 = stl(train04.ts, s.window = 12)
## Forecast with decomposing
fcst01 = forecast(stl01,h=7, method="naive")
fcst02 = forecast(stl02,h=7, method="naive")
fcst03 = forecast(stl03,h=7, method="naive")
fcst04 = forecast(stl04,h=7, method="naive")
We next perform error analysis.
## To compare different errors, we will not use the percentage for MAPE
PE01=(test.data-fcst01$mean)/fcst01$mean
PE02=(test.data-fcst02$mean)/fcst02$mean
PE03=(test.data-fcst03$mean)/fcst03$mean
PE04=(test.data-fcst04$mean)/fcst04$mean
###
MAPE1 = mean(abs(PE01))
MAPE2 = mean(abs(PE02))
MAPE3 = mean(abs(PE03))
MAPE4 = mean(abs(PE04))
###
E1=test.data-fcst01$mean
E2=test.data-fcst02$mean
E3=test.data-fcst03$mean
E4=test.data-fcst04$mean
##
MSE1=mean(E1^2)
MSE2=mean(E2^2)
MSE3=mean(E3^2)
MSE4=mean(E4^2)
###
MSE=c(MSE1, MSE2, MSE3, MSE4)
MAPE=c(MAPE1, MAPE2, MAPE3, MAPE4)
accuracy=cbind(MSE=MSE, MAPE=MAPE)
row.names(accuracy)=c("n.144", "n.109", "n. 73", "n. 48")
kable(accuracy, caption="Error comparison between forecast results with different sample sizes")
Error comparison between forecast results with different sample
sizes
| n.144 |
0.0275199 |
0.0519051 |
| n.109 |
0.0287952 |
0.0543882 |
| n. 73 |
0.0279627 |
0.0550278 |
| n. 48 |
0.0368680 |
0.0637425 |
par(mfrow=c(1,2))
plot(1:4, MSE, type="b", col="darkred", ylab="Error", xlab="",
#ylim=c(0.4,.85),xlim = c(0.5,4.5),
main="MSE", axes=FALSE)
labs=c("n=144", "n=109", "n=73", "n=48")
axis(1, at=1:4, label=labs)
axis(2)
#lines(1:4, MAPE, type="b", col="blue")
text(1:4, MAPE+0.03, as.character(round(MAPE,4)), col="blue", cex=0.7)
text(1:4, MSE-0.03, as.character(round(MSE,4)), col="darkred", cex=0.7)
legend(1.5, 0.63, c("MSE", "MAPE"), col=c("darkred","blue"), lty=1, bty="n", cex=0.7)
###
#```{r fig.align='center', fig.cap= "Comparing forecast errors", fig.width=5, fig.height=3.5}
plot(1:4, MAPE, type="b", col="darkred", ylab="Error", xlab="",
#ylim=c(0.4,.85),xlim = c(0.5,4.5),
main="MAPE", axes=FALSE)
labs=c("n=144", "n=109", "n=73", "n=48")
axis(1, at=1:4, label=labs)
axis(2)
We trained the same algorithm with different sample sizes and
compared the resulting accuracy measures. Among four training sizes 144,
109, 73, and 48. training data size 73 yields the best performance.
As anticipated, forecasting with STL smoothing does not yield decent
results. However, our case study still accomplishes the main learning
goals. To be more specific, we have learned how to
decompose a time series
distinguish the graphical patterns of additive and multiplicative
time series models
use the non-parametric smoothing LOESS method in time series
forecasting;
use the technique of machine learning to tune the training size
to identify the optimal training size to achieve the best accuracy. In
this case, the training size is considered a tuning parameter
(hyper-parameter).
We will start building actual and practical forecasting models in the
next module - exponential smoothing models.
LS0tDQp0aXRsZTogJ1dlZWsgIzEyOiBUaW1lIFNlcmllcyBEZWNvbXBvc2l0aW9uJw0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ193aWR0aDogNg0KICAgIGZpZ19oZWlnaHQ6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgICBkZl9wcmludDoga2FibGUNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDUNCiAgICBmaWdfaGVpZ2h0OiA0DQotLS0NCg0KYGBgez1odG1sfQ0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KZGl2I1RPQyBsaSB7DQogICAgbGlzdC1zdHlsZTpub25lOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNXB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCjwvc3R5bGU+DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgiSVN3UiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJJU3dSIikNCiAgIGxpYnJhcnkoSVN3UikNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgiZm9yZWNhc3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQ0KICAgbGlicmFyeShmb3JlY2FzdCkNCn0NCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ249J2NlbnRlcicsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5wb3MgPSAnaHQnKQ0KYGBgDQoNCg0KDQpcDQoNCiMgSW50cm9kdWN0aW9uDQoNClRpbWUgc2VyaWVzIGRlY29tcG9zaXRpb24gaXMgYSBwcm9jZXNzIG9mIHNwbGl0dGluZyBhIHRpbWUgc2VyaWVzIGludG8gYmFzaWMgY29tcG9uZW50czogdHJlbmQsIHNlYXNvbmFsaXR5IHJhbmRvbSBlcnJvci4gVGhlIG1ldGhvZCBvcmlnaW5hdGVkIGEgY2VudHVyeSBhZ28gYW5kIG5ldyBkZXZlbG9wbWVudHMgaW4gdGhlIHBhc3QgZmV3IGRlY2FkZXMuDQoNCioqU2Vhc29uYWwgUGF0dGVybnMqKiB0aGF0IHJlcGVhdCBmb3IgYSBmaXhlZCBwZXJpb2QuIEZvciBleGFtcGxlLCBhIHdlYnNpdGUgbWlnaHQgcmVjZWl2ZSBtb3JlIHZpc2l0cyBkdXJpbmcgd2Vla2VuZHM7IHRoaXMgd291bGQgcHJvZHVjZSBkYXRhIHdpdGggc2Vhc29uYWxpdHkgb2YgNyBkYXlzLg0KDQoqKlRyZW5kKio6IFRoZSB1bmRlcmx5aW5nIHRyZW5kIG9mIHRoZSBtZXRyaWNzLiBBIHdlYnNpdGUgaW5jcmVhc2luZyBpbiBwb3B1bGFyaXR5IHNob3VsZCBzaG93IGEgZ2VuZXJhbCB0cmVuZCB0aGF0IGdvZXMgdXAuDQoNCioqUmFuZG9tIEVycm9yKio6IEFsc28gY2FsbCDigJxub2lzZeKAnSwg4oCccmVzaWR1YWzigJ0gb3Ig4oCccmVtYWluZGVy4oCdLiBUaGVzZSBhcmUgdGhlIHJlc2lkdWFscyBvZiB0aGUgb3JpZ2luYWwgdGltZSBzZXJpZXMgYWZ0ZXIgdGhlIHNlYXNvbmFsIGFuZCB0cmVuZCBzZXJpZXMgYXJlIHJlbW92ZWQuDQoNCg0KVGhlIG9iamVjdGl2ZSBvZiB0aW1lIHNlcmllcyBkZWNvbXBvc2l0aW9uIGlzIHRvIG1vZGVsIHRoZSB0cmVuZCBhbmQgc2Vhc29uYWxpdHkgYW5kIGVzdGltYXRlIHRoZSBvdmVyYWxsIHRpbWUgc2VyaWVzIGFzIGEgY29tYmluYXRpb24gb2YgdGhlbS4gQSBzZWFzb25hbGx5IGFkanVzdGVkIHZhbHVlIHJlbW92ZXMgdGhlIHNlYXNvbmFsIGVmZmVjdCBmcm9tIGEgdmFsdWUgc28gdGhhdCB0cmVuZHMgY2FuIGJlIHNlZW4gbW9yZSBjbGVhcmx5LiANCg0KVGhlIGZvbGxvd2luZyB0d28gd29ya2luZyBkYXRhIHNldHMgd2VyZSB3aWRlbHkgdXNlZCBpbiBkaWZmZXJlbnQgdGV4dGJvb2tzLiBXZSB3aWxsIHVzZSB0aGVtIHRvIGlsbHVzdHJhdGUgc29tZSBvZiB0aGUgY29uY2VwdHMuDQoNCioqQXVzdHJhbGlhbiBCZWVyIFByb2R1Y3Rpb24gRGF0YSoqIA0KDQpUaGUgZm9sbG93aW5nIGRhdGEgZ2l2ZXMgcXVhcnRlcmx5IGJlZXIgcHJvZHVjdGlvbiBmaWd1cmVzIGluIEF1c3RyYWxpYSBmcm9tIDE5NTYgdGhyb3VnaCB0aGUgMm5kIHF1YXJ0ZXIgb2YgMjAxMC4gVGhlIGJlZXIgcHJvZHVjdGlvbiBmaWd1cmUgaXMgaW4gbWVnYWxpdHJlcy4gDQoNCmBgYHtyfQ0KYXVzYmVlcjA9YygyODQsIDIxMywgMjI3LCAzMDgsIDI2MiwgMjI4LCAyMzYsIDMyMCwgMjcyLCAyMzMsIDIzNywgMzEzLCAyNjEsIDIyNywgMjUwLCAzMTQsIA0KICAgICAgICAgIDI4NiwgMjI3LCAyNjAsIDMxMSwgMjk1LCAyMzMsIDI1NywgMzM5LCAyNzksIDI1MCwgMjcwLCAzNDYsIDI5NCwgMjU1LCAyNzgsIDM2MywgDQogICAgICAgICAgMzEzLCAyNzMsIDMwMCwgMzcwLCAzMzEsIDI4OCwgMzA2LCAzODYsIDMzNSwgMjg4LCAzMDgsIDQwMiwgMzUzLCAzMTYsIDMyNSwgNDA1LCANCiAgICAgICAgICAzOTMsIDMxOSwgMzI3LCA0NDIsIDM4MywgMzMyLCAzNjEsIDQ0NiwgMzg3LCAzNTcsIDM3NCwgNDY2LCA0MTAsIDM3MCwgMzc5LCA0ODcsIA0KICAgICAgICAgIDQxOSwgMzc4LCAzOTMsIDUwNiwgNDU4LCAzODcsIDQyNywgNTY1LCA0NjUsIDQ0NSwgNDUwLCA1NTYsIDUwMCwgNDUyLCA0MzUsIDU1NCwgDQogICAgICAgICAgNTEwLCA0MzMsIDQ1MywgNTQ4LCA0ODYsIDQ1MywgNDU3LCA1NjYsIDUxNSwgNDY0LCA0MzEsIDU4OCwgNTAzLCA0NDMsIDQ0OCwgNTU1LCANCiAgICAgICAgICA1MTMsIDQyNywgNDczLCA1MjYsIDU0OCwgNDQwLCA0NjksIDU3NSwgNDkzLCA0MzMsIDQ4MCwgNTc2LCA0NzUsIDQwNSwgNDM1LCA1MzUsIA0KICAgICAgICAgIDQ1MywgNDMwLCA0MTcsIDU1MiwgNDY0LCA0MTcsIDQyMywgNTU0LCA0NTksIDQyOCwgNDI5LCA1MzQsIDQ4MSwgNDE2LCA0NDAsIDUzOCwgDQogICAgICAgICAgNDc0LCA0NDAsIDQ0NywgNTk4LCA0NjcsIDQzOSwgNDQ2LCA1NjcsIDQ4NSwgNDQxLCA0MjksIDU5OSwgNDY0LCA0MjQsIDQzNiwgNTc0LCANCiAgICAgICAgICA0NDMsIDQxMCwgNDIwLCA1MzIsIDQzMywgNDIxLCA0MTAsIDUxMiwgNDQ5LCAzODEsIDQyMywgNTMxLCA0MjYsIDQwOCwgNDE2LCA1MjAsIA0KICAgICAgICAgIDQwOSwgMzk4LCAzOTgsIDUwNywgNDMyLCAzOTgsIDQwNiwgNTI2LCA0MjgsIDM5NywgNDAzLCA1MTcsIDQzNSwgMzgzLCA0MjQsIDUyMSwgDQogICAgICAgICAgNDIxLCA0MDIsIDQxNCwgNTAwLCA0NTEsIDM4MCwgNDE2LCA0OTIsIDQyOCwgNDA4LCA0MDYsIDUwNiwgNDM1LCAzODAsIDQyMSwgNDkwLCANCiAgICAgICAgICA0MzUsIDM5MCwgNDEyLCA0NTQsIDQxNiwgNDAzLCA0MDgsIDQ4MiwgNDM4LCAzODYsIDQwNSwgNDkxLCA0MjcsIDM4MywgMzk0LCA0NzMsIA0KICAgICAgICAgIDQyMCwgMzkwLCA0MTApDQpgYGANCg0KKiAqKkFpcmxpbmUgUGFzc2VuZ2VycyBEYXRhKioNCg0KVGhpcyBkYXRhIHNldCByZWNvcmRzIG1vbnRobHkgdG90YWxzIG9mIGludGVybmF0aW9uYWwgYWlybGluZSBwYXNzZW5nZXJzICgxOTQ5LTE5NjApLg0KDQpgYGB7cn0NCkFpclBhc3NlbmdlcnMwPWMoMTEyLCAxMTgsIDEzMiwgMTI5LCAxMjEsIDEzNSwgMTQ4LCAxNDgsIDEzNiwgMTE5LCAxMDQsIDExOCwgMTE1LCAxMjYsIDE0MSwgDQogICAgICAgICAgICAgICAgMTM1LCAxMjUsIDE0OSwgMTcwLCAxNzAsIDE1OCwgMTMzLCAxMTQsIDE0MCwgMTQ1LCAxNTAsIDE3OCwgMTYzLCAxNzIsIDE3OCwgDQogICAgICAgICAgICAgICAgMTk5LCAxOTksIDE4NCwgMTYyLCAxNDYsIDE2NiwgMTcxLCAxODAsIDE5MywgMTgxLCAxODMsIDIxOCwgMjMwLCAyNDIsIDIwOSwgDQogICAgICAgICAgICAgICAgMTkxLCAxNzIsIDE5NCwgMTk2LCAxOTYsIDIzNiwgMjM1LCAyMjksIDI0MywgMjY0LCAyNzIsIDIzNywgMjExLCAxODAsIDIwMSwgDQogICAgICAgICAgICAgICAgMjA0LCAxODgsIDIzNSwgMjI3LCAyMzQsIDI2NCwgMzAyLCAyOTMsIDI1OSwgMjI5LCAyMDMsIDIyOSwgMjQyLCAyMzMsIDI2NywgDQogICAgICAgICAgICAgICAgMjY5LCAyNzAsIDMxNSwgMzY0LCAzNDcsIDMxMiwgMjc0LCAyMzcsIDI3OCwgMjg0LCAyNzcsIDMxNywgMzEzLCAzMTgsIDM3NCwgDQogICAgICAgICAgICAgICAgNDEzLCA0MDUsIDM1NSwgMzA2LCAyNzEsIDMwNiwgMzE1LCAzMDEsIDM1NiwgMzQ4LCAzNTUsIDQyMiwgNDY1LCA0NjcsIDQwNCwgDQogICAgICAgICAgICAgICAgMzQ3LCAzMDUsIDMzNiwgMzQwLCAzMTgsIDM2MiwgMzQ4LCAzNjMsIDQzNSwgNDkxLCA1MDUsIDQwNCwgMzU5LCAzMTAsIDMzNywgDQogICAgICAgICAgICAgICAgMzYwLCAzNDIsIDQwNiwgMzk2LCA0MjAsIDQ3MiwgNTQ4LCA1NTksIDQ2MywgNDA3LCAzNjIsIDQwNSwgNDE3LCAzOTEsIDQxOSwNCiAgICAgICAgICAgICAgICA0NjEsIDQ3MiwgNTM1LCA2MjIsIDYwNiwgNTA4LCA0NjEsIDM5MCwgNDMyKQ0KYGBgDQoNCg0KIyBDbGFzc2ljYWwgRGVjb21wb3NpdGlvbnMNCg0KQ2xhc3NpY2FsIGRlY29tcG9zaXRpb24gd2FzIGRldmVsb3BlZCBhYm91dCBhIGNlbnR1cnkgYWdvIGFuZCBpcyBzdGlsbCB3aWRlbHkgdXNlZCBub3dhZGF5cy4gRGVwZW5kaW5nIG9uIHRoZSB0eXBlcyBvZiB0aW1lIHNlcmllcyBtb2RlbHMsIHRoZXJlIGFyZSB0d28gYmFzaWMgbWV0aG9kcyBvZiBkZWNvbXBvc2l0aW9uOiBhZGRpdGl2ZSBhbmQgbXVsdGlwbGljYXRpdmUuDQoNClRoZSBmb2xsb3dpbmcgdHdvIHRpbWUgc2VyaWVzIHJlcHJlc2VudCB0aGUgYWJvdmUgdHdvIGJhc2ljIHR5cGVzIG9mIHRpbWVzIHNlcmllcyBtb2RlbHMuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zLGZpZy5jYXA9InRpbWUgc2VyaWVzIHBsb3RzIG9mIGFkZGl0aXZlIGFuZCBtdWx0aXBsaWNhdGl2ZSBzZXJpZXMifQ0KYXVzYmVlci50cyA9IHRzKGF1c2JlZXIwWzk6NzJdLCBmcmVxdWVuY3kgPSA0LCBzdGFydCA9IGMoMTk1OCwgMSkpDQpBaXJQYXNzZW5nZXJzLnRzID0gdHMoQWlyUGFzc2VuZ2VyczAsIGZyZXF1ZW5jeSA9IDQsIHN0YXJ0ID0gYygxOTQ5LCAxKSkNCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDIsMiwyLDIpKQ0KcGxvdChhdXNiZWVyLnRzLCB4bGFiPSIiLCB5bGFiPSIiLCBtYWluID0gIkFkZGl0aXZlIE1vZGVsIikNCnBsb3QoQWlyUGFzc2VuZ2Vycy50cywgeGxhYj0iIiwgeWxhYj0iIiwgbWFpbiA9ICJNdWx0aXBsaWNhdGl2ZSBNb2RlbCIpDQpgYGANCg0KRGVub3RlICRUID0gdHJlbmQkLCAkUyA9IHNlYXNvbmFsaXR5JCwgYW5kICRFID0gZXJyb3IkLiBXaXRoIHRoZXNlIG5vdGF0aW9ucywgd2UgY2FuIGNoYXJhY3Rlcml6ZSB0aGUgc3RydWN0dXJlIG9mICoqYWRkaXRpdmUgYW5kIG11bHRpcGxpY2F0aXZlKiogdGltZSBzZXJpZXMuDQoNCkluIGEgKiptdWx0aXBsaWNhdGl2ZSB0aW1lIHNlcmllcyoqLCB0aGUgY29tcG9uZW50cyBtdWx0aXBseSB0b2dldGhlciB0byBtYWtlIHRoZSB0aW1lIHNlcmllcy4gQXMgdGhlIHRpbWUgc2VyaWVzIGluY3JlYXNlcyBpbiBtYWduaXR1ZGUsIHRoZSAqKnNlYXNvbmFsIHZhcmlhdGlvbioqIGluY3JlYXNlcyBhcyB3ZWxsLiBUaGUgc3RydWN0dXJlIG9mIGEgbXVsdGlwbGUgdGltZSBzZXJpZXMgaGFzIHRoZSBmb2xsb3dpbmcgZm9ybS4NCg0KJCQNCnlfdCA9IFRfdCBcdGltZXMgU190IFx0aW1lcyBFX3QuDQokJA0KDQpJbiBhbiAqKmFkZGl0aXZlIHRpbWUgc2VyaWVzKiosIHRoZSBjb21wb25lbnRzIGFkZCB0b2dldGhlciB0byBtYWtlIHRoZSB0aW1lIHNlcmllcy4gSWYgeW91IGhhdmUgYW4gaW5jcmVhc2luZyB0cmVuZCwgeW91IHN0aWxsIHNlZSByb3VnaGx5IHRoZSBzYW1lIHNpemUgcGVha3MgYW5kIHRyb3VnaHMgdGhyb3VnaG91dCB0aGUgdGltZSBzZXJpZXMuIFRoaXMgaXMgb2Z0ZW4gc2VlbiBpbiBpbmRleGVkIHRpbWUgc2VyaWVzIHdoZXJlIHRoZSBhYnNvbHV0ZSB2YWx1ZSBpcyBncm93aW5nIGJ1dCBjaGFuZ2VzIHN0YXkgcmVsYXRpdmUuIFRoZSBzdHJ1Y3R1cmUgb2YgYW4gYWRkaXRpdmUgdGltZSBzZXJpZXMgaGFzIHRoZSBmb2xsb3dpbmcgZm9ybQ0KDQokJA0KeV90ID0gVF90ICsgU190ICsgRV90Lg0KJCQNCg0KRm9yIGFuICoqYWRkaXRpdmUgdGltZSBzZXJpZXMqKiwgdGhlIGRldHJlbmRlZCBhZGRpdGl2ZSBzZXJpZXMgaGFzIGZvciAkRF90ID0geV90IC0gVF90JC4gRm9yIHRoZSBtdWx0aXBsaWNhdGl2ZSB0aW1lIHNlcmllcywgdGhlIGRldHJlbmRlZCB0aW1lIHNlcmllcyBpcyBjYWxjdWxhdGVkIGJ5ICREX3QgPSB5X3QvVF90JA0KDQoNCiMgVW5kZXJzdGFuZGluZyB0aGUgQ2xhc3NpY2FsIERlY29tcG9zaXRpb24gb2YgVGltZSBTZXJpZXMNCg0KVG8gdW5kZXJzdGFuZCB0aGUgc3RydWN0dXJlIG9mIGFkZGl0aXZlIGFuZCBtdWx0aXBsaWNhdGlvbiB0aWVzIHNlcmllcywgd2UgZGVjb21wb3NlIHRoZXNlIHRpbWUgc2VyaWVzIGJ5IGNhbGN1bGF0aW5nIHRoZSB0cmVuZCwgc2Vhc29uYWxpdHksIGFuZCBlcnJvcnMgKm1hbnVhbGx5KiBieSB3cml0aW5nIGEgYmFzaWMgUiBzY3JpcHQgdG8gZ2FpbiBhIHRlY2huaWNhbCB1bmRlcnN0YW5kaW5nIG9mIGRlY29tcG9zaW5nIGEgdGltZSBzZXJpZXMuIEF0IHRoZSB2ZXJ5IGVuZCBvZiB0aGlzIHNlY3Rpb24sIHdlIGludHJvZHVjZSB0aGUgUiBmdW5jdGlvbiAqKmRlY29tcG9zZSgpKiogdG8gZXh0cmFjdCB0aGUgdGhyZWUgY29tcG9uZW50cyBvZiBhZGRpdGl2ZSBhbmQgbXVsdGlwbGljYXRpdmUgdGltZSBzZXJpZXMuDQoNCg0KIyMgRGV0ZWN0IFRyZW5kDQoNClRvIGRldGVjdCB0aGUgdW5kZXJseWluZyB0cmVuZCwgd2UgdXNlIGEgc21vb3RoaW5nIHRlY2huaXF1ZSBjYWxsZWQgKiptb3ZpbmcgYXZlcmFnZSoqIGFuZCBpdCdzIHZhcmlhbnQgKipjZW50ZXJlZCBtb3ZpbmcgYXZlcmFnZSoqLiBGb3IgYSBzZWFzb25hbCB0aW1lIHNlcmllcywgdGhlIHdpZHRoIG9mIHRoZSBtb3Zpbmcgd2luZG93IG11c3QgYmUgdGhlIHNhbWUgYXMgdGhlIHNlYXNvbmFsaXR5LiBUaGVyZWZvcmUsIHRvIGRlY29tcG9zZSBhIHRpbWUgc2VyaWVzIHdlIG5lZWQgdG8ga25vdyB0aGUgc2Vhc29uYWxpdHkgcGVyaW9kOiB3ZWVrbHksIG1vbnRobHksIGV0Yy4NCg0KKipFeGFtcGxlIDEqKjogQXVzdHJhbGlhbiBiZWVyIHByb2R1Y3Rpb24gZGF0YSBoYXMgYW4gYW5udWFsIHNlYXNvbmFsaXR5LiBTaW5jZSB0aGUgZGF0YSBzZXQgaXMgcXVhcnRlcmx5IGRhdGEsIHRoZSBtb3ZpbmcgYXZlcmFnZSB3aW5kb3cgc2hvdWxkIGJlIDQuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9Mi42LCBmaWcuY2FwPSJTZXJpcmVzIHBsb3Qgd2l0aCB0cmVuZCBjdXJ2ZSJ9DQp0cmVuZC5iZWVyID0gbWEoYXVzYmVlci50cywgb3JkZXIgPSAxMiwgY2VudHJlID0gVCkgICAgICMgY2VudHJlID0gVCA9PiBjZW50ZXJlZCBtb3ZpbmcgYXZlcmFnZQ0KcGFyKG1hcj1jKDIsMiwyLDIpKQ0KcGxvdChhcy50cyhhdXNiZWVyLnRzKSwgeGxhYj0iIiwgeWxhYj0iIiwgY29sPSJkYXJrcmVkIiwgbHdkID0yKQ0KdGl0bGUobWFpbiA9ICJFeHRyYWN0IHRyZW5kIGZyb20gQXVzdHJhbGlhIEJlZXIgUHJvZHVjdGlvbiIpDQpsaW5lcyh0cmVuZC5iZWVyLCBsd2QgPTIsIGNvbCA9ICJibHVlIikNCmxlZ2VuZCgidG9wbGVmdCIsIGMoIm9yaWdpbmFsIHNlcmllcyIsICJ0cmVuZCBjdXJ2ZSIpLCBsd2Q9cmVwKDIsMiksDQogICAgICAgY29sPWMoImRhcmtyZWQiLCAiYmx1ZSIpLCBidHk9Im4iKQ0KYGBgDQoNCg0KKipFeGFtcGxlIDIqKjogVGhlIGFpcmxpbmUgcGFzc2VuZ2VyIGRhdGEgd2VyZSByZWNvcmRlZCBtb250aGx5LiBJdCBoYXMgYW4gYW5udWFsIHNlYXNvbmFsIHBhdHRlcm4uIFdlIGNob29zZSBhIG1vdmluZyBhdmVyYWdlIHdpbmRvdyBvZiAxMiB0byBleHRyYWN0IHRoZSB0cmVuZCBmcm9tIHRoaXMgbXVsdGlwbGljYXRpdmUgdGltZSBzZXJpZXMuDQoNCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0yLjYsIGZpZy5jYXA9InNlcmllcyBwbG90IHdpdGggY3VydmUgdHJlbmQifQ0KdHJlbmQuYWlyID0gbWEoQWlyUGFzc2VuZ2Vycy50cywgb3JkZXIgPSAxMiwgY2VudHJlID0gVCkgIA0KICAjIGNlbnRyZSA9IFQgPT4gY2VudGVyZWQgbW92aW5nIGF2ZXJhZ2UNCnBhcihtYXI9YygyLDIsMiwyKSkNCnBsb3QoYXMudHMoQWlyUGFzc2VuZ2Vycy50cyksIHhsYWI9IiIsIHlsYWI9IiIsIGNvbD0iZGFya3JlZCIsIGx3ZCA9MikNCnRpdGxlKG1haW4gPSAiRXh0cmFjdCB0cmVuZCBmcm9tIEFpcmxpbmUgUGFzc2VuZ2VycyBNb250aGx5IERhdGEiKQ0KbGluZXModHJlbmQuYWlyLCBsd2QgPTIsIGNvbCA9ICJibHVlIikNCmxlZ2VuZCgidG9wbGVmdCIsIGMoIm9yaWdpbmFsIHNlcmllcyIsICJ0cmVuZCBjdXJ2ZSIpLCBsd2Q9cmVwKDIsMiksDQogICAgICAgY29sPWMoImRhcmtyZWQiLCAiYmx1ZSIpLCBidHk9Im4iKQ0KYGBgDQoNClRoZSAqKm1vdmluZyBhdmVyYWdlcyoqIG9mIGJvdGggdGltZSBzZXJpZXMgYXJlIHJlY29yZGVkIGluIHRoZSBhYm92ZSB0d28gY29kZSBjaHVua3MgYW5kIHdpbGwgYmUgdXNlZCB0byByZXN0b3JlIHRoZSBvcmlnaW5hbCBzZXJpZXMuDQoNClRoZSBwcm9jZXNzIG9mIHJlbW92aW5nIHRoZSB0cmVuZCBmcm9tIGEgdGltZSBzZXJpZXMgaXMgY2FsbGVkICoqZGV0cmVuZGluZyoqIHRpbWUgc2VyaWVzLiANCg0KVGhlIHdheSBvZiBkZXRyZW5kaW5nIGEgdGltZSBzZXJpZXMgaXMgZGVwZW5kZW50IG9uIHRoZSB0eXBlcyBvZiB0aGUgdGltZSBzZXJpZXMuIFRoZSBmb2xsb3dpbmcgY29kZSBzaG93cyBob3cgdG8gY2FsY3VsYXRlIHRoZSBkZXRyZW5kZWQgdGltZSBzZXJpZXMuDQoNCg0KKipFeGFtcGxlIDMqKjogIFdlIGNhbGN1bGF0ZSB0aGUgZGV0cmVuZGVkIHNlcmllcyB1c2luZyB0aGUgQXVzdHJhbGlhbiBCZWVyIGRhdGEgYW5kIHRoZSBBaXJsaW5lIFBhc3NlbmdlcnMgZGF0YSBhcyBhbiBleGFtcGxlLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMsIGZpZy5jYXA9IkRldHJlbmRlZCBzZXJpZXMifQ0KZGV0cmVuZC5iZWVyID0gYXVzYmVlci50cyAtIHRyZW5kLmJlZXIgICAgICMjIGFkZGl0aXZlIG1vZGVsDQpkZXRyZW5kLmFpciA9IEFpclBhc3NlbmdlcnMudHMvdHJlbmQuYWlyICAgIyMgbXVsdGlwbGljYXRpdmUgbW9kZWwNCnBhcihtYXI9YygyLDIsMiwyKSkNCnBhcihtZnJvdz1jKDEsMikpDQojIHBsb3QoYXVzYmVlci50cywgeGxhYj0iIiwgbWFpbiA9ICJBdXN0cmFsaWEgQmVlciIsIGNvbD0iZGFya3JlZCIpDQojIHBsb3QoQWlyUGFzc2VuZ2Vycy50cywgeGxhYj0iIiwgbWFpbiA9ICJBaXIgUGFzc2VuZ2VycyIsIGNvbD0iYmx1ZSIpDQpwbG90KGRldHJlbmQuYmVlciwgeGxhYj0iIiwgbWFpbiA9ICJBdXN0cmFsaWEgQmVlciIsIGNvbD0iZGFya3JlZCIpDQpwbG90KGRldHJlbmQuYWlyLCB4bGFiPSIiLCBtYWluID0gIkFpciBQYXNzZW5nZXJzIiwgY29sPSJibHVlIikNCmBgYA0KDQoNClRoZSB0ZWNobmlxdWUgd2UgdXNlZCBpbiByZW1vdmluZyB0aGUgdHJlbmQgZnJvbSBhIHRpbWUgc2VyaWVzIG1vZGVsIGlzIGEgbm9uLXBhcmFtZXRyaWMgc21vb3RoaW5nIHByb2NlZHVyZS4gVGhlcmUgYXJlIGRpZmZlcmVudCB0ZWNobmlxdWVzIGluIHN0YXRpc3RpY3MgdG8gZXN0aW1hdGUgYSBjdXJ2ZSBmb3IgYSBnaXZlbiBzZXQuIFRoZSAqKm1vdmluZyBhdmVyYWdlKiogaXMgb25lIG9mIHRoZSBzaW1wbGVzdCBvbmVzIGFuZCBpcyB3aWRlbHkgdXNlZCBpbiB0aW1lIHNlcmllcy4NCg0KDQojIyBFeHRyYWN0aW5nIHRoZSBTZWFzb25hbGl0eQ0KDQpTaW1pbGFyIHRvIHRoZSB0cmVuZCBpbiBhIHRpbWUgc2VyaWVzLCB0aGUgc2Vhc29uYWxpdHkgb2YgYSB0aW1lIHNlcmllcyBpcyBhbHNvIGEgbm9uLXJhbmRvbSBzdHJ1Y3R1cmFsIHBhdHRlcm4uIFdlIGNhbiBleHRyYWN0IHRoZSBzZWFzb25hbGl0eSBmcm9tIHRoZSBkZXRyZW5kZWQgdGltZSBzZXJpZXMuIA0KDQpUaGUgaWRlYSBpcyB0byByZWRlZmluZSBhICoqc2Vhc29uYWwgc2VyaWVzKiogYmFzZWQgb24gdGhlIGRldHJlbmRlZCBzZXJpZXMgYnkgcmVwbGFjaW5nIGFsbCBvYnNlcnZhdGlvbnMgdGFrZW4gZnJvbSB0aGUgc2FtZSBzZWFzb25hbCBwZXJpb2Qgd2l0aCB0aGUgYXZlcmFnZSBvZiB0aGVzZSBvYnNlcnZhdGlvbnMuIFRoaXMgcHJvY2VzcyBpcyBjYWxsZWQgKiphdmVyYWdpbmcgc2Vhc29uYWxpdHkqKi4gVGhpcyBpZGVhIGlzIGltcGxlbWVudGVkIGluIFIuIEhlcmUgaXMgaG93IHRvIGRvIGl0IGluIFIuDQoNCioqRXhhbXBsZSA0Kio6IFVzZSB0aGUgKipBdXN0cmFsaWFuIEJlZXIgUHJvZHVjdGlvbiBEYXRhKiogYW5kIHRoZSAqKkFpcmxpbmUgUGFzc2VuZ2VyIERhdGEqKiBhZnRlciB0aGVpciB0cmVuZHMgd2VyZSByZW1vdmVkLiBUaGUgZm9sbG93aW5nIGNvZGUgaWxsdXN0cmF0ZXMgaG93IHRvIGNhbGN1bGF0ZSBhbmQgZ3JhcGggdGhlIHNlYXNvbmFsaXR5IG9mIGJvdGggc2VyaWVzLg0KDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0iU2Vhc29uYWwgc2VyaWVzIn0NCnBhcihtZnJvdz1jKDIsMSksIG1hcj1jKDMsMiwzLDIpKQ0KIyMgQXVzdHJhbGlhIEJlZXINCm10cnguYmVlciA9IHQobWF0cml4KGRhdGEgPSBkZXRyZW5kLmJlZXIsIG5yb3cgPSA0KSkgICMjIHF1YXJ0ZXJseSBiZWVyIGRhdGEgDQpzZWFzb25hbC5iZWVyID0gY29sTWVhbnMobXRyeC5iZWVyLCBuYS5ybSA9IFQpDQpzZWFzb25hbC5iZWVyLnRzID0gYXMudHMocmVwKHNlYXNvbmFsLmJlZXIsMTYpKQ0KcGxvdChzZWFzb25hbC5iZWVyLnRzLCB4bGFiID0gIiIsIGNvbD0iZGFya3JlZCIsIG1haW49IlNlYXNvbmFsIHNlcmllcyBvZiBBdXN0cmFsaWEgYmVlciIpDQojIw0KbXRyeC5haXIgPSB0KG1hdHJpeChkYXRhID0gZGV0cmVuZC5haXIsIG5yb3cgPSAxMikpICAjIyBhbm51YWwgZGF0YQ0Kc2Vhc29uYWwuYWlyID0gY29sTWVhbnMobXRyeC5haXIsIG5hLnJtID0gVCkNCnNlYXNvbmFsLmFpci50cyA9IGFzLnRzKHJlcChzZWFzb25hbC5haXIsMTYpKQ0KcGxvdChzZWFzb25hbC5haXIudHMsIHhsYWIgPSAiIiwgY29sID0gImJsdWUiLCBtYWluPSJTZWFzb25hbCBzZXJpZXMgb2YgYWlyIHBhc3NlbmdlcnMiKQ0KYGBgDQoNCiMjIEV4dHJhY3RpbmcgUmVtYWluZGVyIEVycm9ycw0KDQpUaGUgKiplcnJvciB0ZXJtKiogaXMgdGhlIHJhbmRvbSBjb21wb25lbnQgaW4gdGhlIHRpbWUgc2VyaWVzLiBXZSBsZWFybmVkIHRoZSBvZiBleHRyYWN0aW5nIHRoZSB0cmVuZCBhbmQgc2Vhc29uYWxpdHkgZnJvbSB0aGUgb3JpZ2luYWwgdGltZSBzZXJpZXMuIEhvdyB0byBleHRyYWN0IHRoZSDigJxyYW5kb23igJ0gbm9pc2UgZnJvbSBhIGdpdmVuIHRpbWUgc2VyaWVzPw0KDQpJbiB0aGUgYWRkaXRpdmUgbW9kZWwsIHRoZSByYW5kb20gKiplcnJvciB0ZXJtKiogaXMgZ2l2ZW4gYnkgJEVfdCA9IHlfdCAtIFRfdCAtU190JC4gVGhlICoqcmFuZG9tIGVycm9yKiogZm9yIGEgbXVsdGlwbGljYXRpdmUgbW9kZWwgaXMgZ2l2ZW4gYnkgJEVfdCA9IHlfdC8oVF90IFx0aW1lcyBTX3QpJC4NCg0KKipFeGFtcGxlIDUqKjogVXNlIHRoZSBhYm92ZSBmb3JtdWxhcyB0byBzZXBhcmF0ZSB0aGUgcmFuZG9tIGVycm9yIGNvbXBvbmVudHMgaW4gYWRkaXRpdmUgYW5kIG11bHRpcGxpY2F0aXZlIG1vZGVscyB1c2luZyBBdXN0cmFsaWFuIGJlZXIgcHJvZHVjdGlvbiBhbmQgQWlybGluZSBwYXNzZW5nZXIgc2VyaWVzIGRhdGEuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0iUmFuZG9tIGVycm9yIGNvbXBvbmVudHMifQ0KcmFuZG9tLmJlZXIgPSBhdXNiZWVyLnRzIC0gdHJlbmQuYmVlciAtIHNlYXNvbmFsLmJlZXINCnJhbmRvbS5haXIgPSBBaXJQYXNzZW5nZXJzLnRzIC8gKHRyZW5kLmFpciAqIHNlYXNvbmFsLmFpcikNCiMjDQpwYXIobWZyb3c9YygyLDEpLCBtYXI9YygzLDIsMywyKSkNCnBsb3QocmFuZG9tLmJlZXIgLCB4bGFiID0gIiIsIGNvbD0iZGFya3JlZCIsIG1haW49IlJhbmRvbSBlcnJvcnMgb2YgQXVzdHJhbGlhIGJlZXIiKQ0KcGxvdChyYW5kb20uYWlyLCB4bGFiID0gIiIsIGNvbCA9ICJibHVlIiwgbWFpbj0iUmFuZG9tIGVycm9ycyBvZiBhaXIgcGFzc2VuZ2VycyIpDQpgYGANCg0KIyMgUmVjb25zdHJ1Y3QgdGhlIE9yaWdpbmFsIFNlcmllcyAvIENvbXBvc2UgTmV3IFNlcmllcw0KDQpUaGUgb3JpZ2luYWwgc2VyaWVzIGNhbiBiZSAqKnJlY29uc3RydWN0ZWQqKiBieSB1c2luZyB0aGUgZGVjb21wb3NlZCBjb21wb25lbnRzLiBTaW5jZSB0aGUgKiptb3ZpbmcgYXZlcmFnZSB0ZWNobmlxdWUqKiB3YXMgdXNlZCBpbiB0aGUgZGV0cmVuZGluZyBzZXJpZXMsIHRoZSByZXN1bHRpbmcgKipyZWNvbnN0cnVjdGVkKiogc2VyaWVzIHdpdGggJFRfdCQsICRTX3QkLCBhbmQgJEVfdCQgd2lsbCBnZW5lcmF0ZSBhIGZldyBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgYmVnaW5uaW5nIGFuZCB0aGUgZW5kIGRlcGVuZGluZyBvbiB0aGUgd2lkdGggb2YgdGhlICoqbW92aW5nIGF2ZXJhZ2Ugd2luZG93KiouDQoNCioqRXhhbXBsZSA2Kio6ICAqKlJlY29uc3RydWN0KiogdGhlICoqb3JpZ2luYWwqKiBzZXJpZXMgb2YgQXVzdHJhbGlhbiBiZWVyIGRhdGEgYW5kIHRoZSBhaXJsaW5lIHBhc3NlbmdlciBkYXRhLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTMsIGZpZy5jYXA9IkFkZGluZyB0cmVuZCBzZXJpZXMgdG8gdGhlIG9yaWdpbmFsIHNlcmllcyJ9DQpyZWNvbXBvc2VkLmJlZXIgPSB0cmVuZC5iZWVyK3NlYXNvbmFsLmJlZXIrcmFuZG9tLmJlZXINCnJlY29tcG9zZWQuYWlyID0gdHJlbmQuYWlyKnNlYXNvbmFsLmFpcipyYW5kb20uYWlyDQpwYXIobWZyb3c9YygxLDIpLCBtYXI9YygzLDIsMywyKSkNCnBsb3QoYXVzYmVlci50cywgY29sPSJkYXJrcmVkIiwgbHR5PTEpDQpsaW5lcyhyZWNvbXBvc2VkLmJlZXIsIGNvbD0iYmx1ZSIsIGx0eT0yLCBsd2Q9MikNCmxlZ2VuZCgidG9wbGVmdCIsIGMoIm9yaWdpbmFsIHNlcmllcyIsICJyZWNvbnN0cnVjdGVkIHNlcmllcyIpLCANCiAgICAgICBjb2w9YygiZGFya3JlZCIsICJibHVlIiksIGx0eT0xOjIsIGx3ZD0xOjIsIGNleD0wLjgsIGJ0eT0ibiIpDQp0aXRsZShtYWluPSJBdXN0cmFsaWFuIEJlZXIiKQ0KIyMNCnBsb3QoQWlyUGFzc2VuZ2Vycy50cywgY29sPSJkYXJrcmVkIiwgbHR5PTEpDQpsaW5lcyhyZWNvbXBvc2VkLmFpciwgY29sPSJibHVlIiwgbHR5PTIsIGx3ZD0yKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgYygib3JpZ2luYWwgc2VyaWVzIiwgInJlY29uc3RydWN0ZWQgc2VyaWVzIiksIA0KICAgICAgIGNvbD1jKCJkYXJrcmVkIiwiYmx1ZSIpLCBsdHk9MToyLCBsd2Q9MToyLCBjZXg9MC44LCBidHk9Im4iKQ0KdGl0bGUobWFpbj0iQWlybGluZSBQYXNzZW5nZXJzIikNCmBgYA0KDQojIyBEZWNvbXBvc2luZyBUaW1lIFNlcmllcyB3aXRoICoqZGVjb21wb3NlKCkqKg0KDQoNClRoZSBSIGxpYnJhcnkgKipmb3JlY2FzdCoqIHdhcyBjcmVhdGVkIGJ5IGEgdGVhbSBsZWQgYnkgYSBsZWFkaW5nIGV4cGVydCBpbiB0aGUgZGlzY2lwbGluZS4gV2XigJlsbCB1c2UgdGhlIFIgZnVuY3Rpb24gKipkZWNvbXBvc2UoICkqKiBpbiBsaWJyYXJ5e2ZvcmVjYXN0fSBhcyBhIGRlY29tcG9zaXRpb24gZnVuY3Rpb24gdG8gZGVjb21wb3NlIGEgc2VyaWVzIGludG8gc2Vhc29uYWwsIHRyZW5kLCBhbmQgcmFuZG9tIGNvbXBvbmVudHMuIFRoZSBBdXN0cmFsaWFuIGJlZXIgcHJvZHVjdGlvbiAoYWRkaXRpdmUpIGFuZCBhaXJsaW5lIHBhc3NlbmdlciBudW1iZXJzIChtdWx0aXBsaWNhdGl2ZSkgd2lsbCBzdGlsbCBiZSB1c2VkIHRvIGlsbHVzdHJhdGUgdGhlIHN0ZXBzLg0KDQoqKkV4YW1wbGUgNioqOiBQbG90IHRoZSBjb21wb25lbnRzIG9mIHRoZSBBdXN0cmFsaWFuIGJlZXIgcHJvZHVjdGlvbiBkYXRhLg0KDQoNCmBgYHtyICBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTMuOH0NCmRlY29tcC5iZWVyID0gZGVjb21wb3NlKGF1c2JlZXIudHMsICJhZGRpdGl2ZSIpDQojIyBwbG90IHRoZSBkZWNvbXBvc2VkIGNvbXBvbmVudHMNCnBhcihtYXI9YygyLDIsMiwyKSwgb21hPWMoMCwyLDIsMCkpDQpwbG90KGRlY29tcC5iZWVyLCBjb2w9ImRhcmtyZWQiLCB4bGFiPSIiKQ0KYGBgDQoNCioqRXhhbXBsZSA3Kio6IFBsb3QgdGhlIGNvbXBvbmVudHMgb2YgdGhlIEFpcmxpbmUgUGFzc2VuZ2VyIERhdGEuDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9My44fQ0KZGVjb21wLmFpciA9IGRlY29tcG9zZShBaXJQYXNzZW5nZXJzLnRzLCAibXVsdGlwbGljYXRpdmUiKQ0KIyMgcGxvdCB0aGUgZGVjb21wb3NlZCBjb21wb25lbnRzDQpwYXIobWFyPWMoMiwyLDIsMiksIG9tYT1jKDAsMiwyLDApKQ0KcGxvdChkZWNvbXAuYWlyLCBjb2w9ICJuYXZ5IiwgeGxhYj0iIikNCmBgYA0KDQpUaCBSIGZ1bmN0aW9uICoqZGVjb21wb3NlKCkqKiBjYW4gYmUgdXNlZCB0byBleHRyYWN0IHRoZSBpbmRpdmlkdWFsIGNvbXBvbmVudHMgZnJvbSBhIGdpdmVuIGFkZGl0aXZlIGFuZCBtdWx0aXBsaWNhdGl2ZSBtb2RlbCB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGUuDQoNCg0KKipFeGFtcGxlIDgqKjogRGVjb21wb3NpbmcgQXVzdHJhbGlhbiBiZWVyIHByb2R1Y3Rpb24gZGF0YSB1c2luZyAqKmRlY29tcG9zZSgpKiouDQoNCmBgYHtyfQ0KZGVjb21wLmJlZXIgPSBkZWNvbXBvc2UoYXVzYmVlci50cywgImFkZGl0aXZlIikNCiMgdGhlIGZvdXIgY29tcG9uZW50cyBjYW4gYmUgZXh0cmFjdGVkIGJ5DQpzZWFzb25hbC5iZWVyID0gZGVjb21wLmJlZXIkc2Vhc29uYWwNCnRyZW5kLmJlZXIgPSBkZWNvbXAuYmVlciR0cmVuZA0KZXJyb3IuYmVlciA9IGRlY29tcC5iZWVyJHJhbmRvbQ0KYGBgDQoNCioqRXhhbXBsZSA5Kio6IERlY29tcG9zaW5nIGFpcmxpbmUgcGFzc2VuZ2VycyBkYXRhIHVzaW5nICoqZGVjb21wb3NlKCkqKi4NCg0KDQpgYGB7cn0NCmRlY29tcC5haXIgPSBkZWNvbXBvc2UoQWlyUGFzc2VuZ2Vycy50cywgIm11bHRpcGxpY2F0aXZlIikNCiMgdGhlIGZvdXIgY29tcG9uZW50cyBjYW4gYmUgZXh0cmFjdGVkIGJ5DQpzZWFzb25hbC5haXIgPSBkZWNvbXAuYWlyJHNlYXNvbmFsDQp0cmVuZC5haXIgPSBkZWNvbXAuYWlyJHRyZW5kDQplcnJvci5haXIgPSBkZWNvbXAuYWlyJHJhbmRvbQ0KYGBgDQoNCioqQ29uY2x1ZGluZyBSZW1hcmsqKjogIFRoZXJlIGFyZSBvdGhlciBkZWNvbXBvc2l0aW9uIG1ldGhvZHMuIGFtb25nIHRoZW0sICoqWDExKiogaXMgY29tbW9ubHkgdXNlZCBpbiBlY29ub21ldHJpY3MuIFRoZSByZWNlbnRseSBkZXZlbG9wZWQgbWV0aG9kICoqU1RMKCkqKiB0aGF0IHVzZWQgTE9FU1MgYWxnb3JpdGhtIHRvIGVzdGltYXRlIHRoZSB0cmVuZCBjYW4gYWxzbyBiZSB1c2VkIHRvIGV4dHJhY3QgY29tcG9uZW50cyBmcm9tIG1vcmUgZ2VuZXJhbCB0aW1lIHNlcmllcy4gV2Ugd2lsbCBvdXRsaW5lIHRoaXMgZGVjb21wb3NpdGlvbiBtZXRob2QgdG8gZm9yZWNhc3QgZnV0dXJlIHZhbHVlcy4NCg0KDQoNCiMgRm9yZWNhc3Rpbmcgd2l0aCBEZWNvbXBvc2luZw0KDQpTZXZlcmFsIGJlbmNobWFyayBmb3JlY2FzdGluZyBtZXRob2RzIHdlcmUgaW50cm9kdWNlZCBpbiB0aGUgcHJldmlvdXMgbW9kdWxlLiBOZXh0LCB3ZSB1c2UgdGhlc2UgYmVuY2htYXJrIG1ldGhvZHMgdG8gZm9yZWNhc3QgdGhlIGRlc2Vhc29uYWxpemVkIHNlcmllcy4gU2luY2UgdGhlIHNlYXNvbmFsaXR5IG9mIGEgdGltZSBzZXJpZXMgaXMgYSAqKnNjYWxhcioqLCB3ZSBjYW4gZm9yZWNhc3QgdGhlIGRlc2Vhc29uYWxpemVkIHNlcmllcyB0aHJvdWdoIGRlY29tcG9zaXRpb24gYW5kIHRoZW4gYWRqdXN0IHRoZSBmb3JlY2FzdGVkIHZhbHVlcy4NCg0KDQojIyBGb3JlY2FzdGluZyBBZGRpdGl2ZSBNb2RlbHMgd2l0aCBEZWNvbXBvc2luZw0KDQpTaW5jZSB0aGUgbXVsdGlwbGljYXRpdmUgbW9kZWxzIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYW4gYWRkaXRpdmUgbW9kZWwgYnkNCg0KJCQNClxsb2coeV90KSA9IFxsb2coU190KSArIFxsb2coVF90KSArIFxsb2coRV90KS4NCiQkDQoNClNvIHdlIG9ubHkgcmVzdHJpY3Qgb3VyIGRpc2N1c3Npb24gaW4gdGhpcyBtb2R1bGUgdG8gYWRkaXRpdmUgbW9kZWxzLiBBc3N1bWluZyBhbiBhZGRpdGl2ZSBkZWNvbXBvc2l0aW9uLCB0aGUgZGVjb21wb3NlZCB0aW1lIHNlcmllcyBjYW4gYmUgd3JpdHRlbiBhcw0KDQokJHlfdCA9IFxoYXR7U31fdCArIFxoYXR7QX1fdCQkDQoNCndoZXJlICAkXGhhdHtBfV90ID0gXGhhdHtUfSArIFxoYXR7RX1fdCQgaXMgdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgY29tcG9uZW50LiBXZSBjYW4gZm9yZWNhc3QgdGhlIGZ1dHVyZSB2YWx1ZXMgYmFzZWQgb24gICRcaGF0e0F9X3QkLg0KDQoqKkV4YW1wbGUgMTAqKjogRm9yZWNhc3RpbmcgYmFzZWQgb24gdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgc2VyaWVzIHdpdGggQXVzdHJhbGlhbiBiZWVyIHByb2R1Y3Rpb24gZGF0YS4gV2UgaW50cm9kdWNlZCBmb3VyIGJlbmNobWFyayBmb3JlY2FzdGluZyBtZXRob2RzIGluIHRoZSBwcmV2aW91cyBtb2R1bGUuIEZvciBhIHRpbWUgc2VyaWVzIHdpdGggYSB0cmVuZCwgbmFpdmUsIHNlYXNvbmFsIG5haXZlLCBhbmQgZHJpZnQgbWV0aG9kIGlzIG1vcmUgYWNjdXJhdGUgdGhhbiB0aGUgbW92aW5nIGF2ZXJhZ2UuIFRoZSBpc3N1ZSBpcyB0aGF0IG5vbmUgb2YgdGhlIGJlbmNobWFyayBtZXRob2RzIGZvcmVjYXN0IHRoZSB0cmVuZC4gQXMgYW4gaWxsdXN0cmF0aXZlIGV4YW1wbGUsIHdlIHVzZSB0aGUgbmFpdmUgbWV0aG9kIHRvIGZvcmVjYXN0IHRoZSBkZXNlYXNvbmFsaXplZCBzZXJpZXMgYW5kIHRoZW4gYWRkIHRoZSBzZWFzb25hbCBhZGp1c3RtZW50IHRvIHRoZSBmb3JlY2FzdCB2YWx1ZXMuDQoNCg0KYGBge3J9DQpkZWNvbXAuYmVlciA9IGRlY29tcG9zZShhdXNiZWVyLnRzLCAiYWRkaXRpdmUiKQ0KIyB0aGUgZm91ciBjb21wb25lbnRzIGNhbiBiZSBleHRyYWN0ZWQgYnkNCnNlYXNvbmFsLmJlZXIgPSBkZWNvbXAuYmVlciRzZWFzb25hbA0KdHJlbmQuYmVlciA9IGRlY29tcC5iZWVyJHRyZW5kDQplcnJvci5iZWVyID0gZGVjb21wLmJlZXIkcmFuZG9tDQpzZWFzb25hbC5hZGogPSB0cmVuZC5iZWVyICsgZXJyb3IuYmVlcg0KZGVzZWFzb25hbGl6ZWQucHJlZCA9IGFzLmRhdGEuZnJhbWUocndmKG5hLm9taXQoc2Vhc29uYWwuYWRqKSwgaCA9IDYpKSANCnNlYXNvbmFsaXR5ID0gIG1hdHJpeChyZXAoc2Vhc29uYWwuYmVlclszOjhdLDUpLCBuY289NSwgYnlyb3c9RikgICAgICAgICAgICAgICAgICAgICAgDQpzZWFzb25hbC5hZGoucHJlZCA8LSBkZXNlYXNvbmFsaXplZC5wcmVkICArIHNlYXNvbmFsaXR5DQprYWJsZShzZWFzb25hbC5hZGoucHJlZCwgY2FwdGlvbiA9ICJGb3JlY2FzdGluZyB3aXRoIGRlY29tcG9zaW5nIC0gZHJpZnQgbWV0aG9kIikNCmBgYA0KDQpTaW5jZSB0aGUgZGVzZWFzb25hbGl6ZWQgc2VyaWVzIGhhcyB0d28gbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGJlZ2lubmluZyBhbmQgdHdvIGluIHRoZSBlbmQuIHdlIHJlbW92ZSB0aGUgbWlzc2luZyB2YWx1ZXMgYmVmb3JlIHVzaW5nIHRoZSBkcmlmdCBtZXRob2RzIHRvIGZvcmVjYXN0IHRoZSBuZXh0IDYgcGVyaW9kcyAocXRyMywgMTk3MyAtIHF0ciA0LCAxODc0KS4gVGhlIGZvcmVjYXN0IHZhbHVlcyBhcmUgZ2l2ZW4gaW4gdGhlIGFib3ZlIHRhYmxlLg0KDQoNCmBgYHtyICBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTQsIGZpZy5jYXA9ImZvcmVjYXN0aW5nIHdpdGggY2xhc3NpY2FsIGRlY29tcG9zaW5nIn0NCnBhcihtYXI9YygyLDIsMiwyKSkNCnBsb3QoMTo2MiwgYXMudmVjdG9yKGF1c2JlZXIudHMpWy1jKDYzLDY0KV0sIHR5cGU9ImwiLCB4bGltPWMoMSw3MCksIHlsaW09YygyMDAsIDU3MCksDQogICAgIHhsYWI9IiIsIHlsYWI9IkJlZXIgUHJvZHVjdGlvbiIsIG1haW49IkZvcmVjYXN0IHdpdGggY2xhc3NpY2FsIGRlY29tcG9zaW5nIikNCmxpbmVzKDYyOjY0LCAgYXMudmVjdG9yKGF1c2JlZXIudHMpW2MoNjIsNjMsNjQpXSwgY29sPSJyZWQiKQ0KcG9pbnRzKDYyOjY0LCAgYXMudmVjdG9yKGF1c2JlZXIudHMpW2MoNjIsNjMsNjQpXSwgY29sPSJyZWQiLCBwY2g9MjEpDQpsaW5lcyg2Mzo2OCxzZWFzb25hbC5hZGoucHJlZFssMV0sIGNvbD0iYmx1ZSIpDQpwb2ludHMoNjM6Njgsc2Vhc29uYWwuYWRqLnByZWRbLDFdLCBjb2w9ImJsdWUiLCBwY2ggPSAxNikNCmBgYA0KDQpUaGUgcGxvdCBvZiB0aGUgZm9yZWNhc3QgdmFsdWVzIGFuZCB0aGUgb3JpZ2luYWwgdmFsdWVzLiBUaGUgcmVkIHBsb3QgcmVwcmVzZW50ZWQgcXVhcnRlcnMgMy00IG9mIDE5NzMgYW5kIGZvcmVjYXN0IHZhbHVlcyBpbiBxdWFydGVycyAzIC0gcXVhcnRlcnMgNCwgMTk3NCwgYXJlIHBsb3R0ZWQgaW4gKipibHVlKiouIFdlIGNhbiBzZWUgdGhhdA0KDQoNCiMjIENvbmNlcHRzIG9mIFNlYXNvbmFsIGFuZCBUcmVuZCBEZWNvbXBvc2l0aW9uIFVzaW5nIExvZXNzIChTVEwpDQoNClNlYXNvbmFsIGFuZCBUcmVuZCBkZWNvbXBvc2l0aW9uIHVzaW5nIExPRVNTIChTVEwpIGNvbWJpbmVzIHRoZSBjbGFzc2ljYWwgdGltZSBzZXJpZXMgZGVjb21wb3NpdGlvbiBhbmQgdGhlICoqbW9kZXJuKiogbG9jYWxseSBlc3RpbWF0ZWQgc2NhdHRlcnBsb3Qgc21vb3RoaW5nIChMT0VTUykuIFRoZSBMT0VTUyBoYXMgZGV2ZWxvcGVkIGFib3V0IDQwIHllYXJzIGFnbyBhbmQgaXMgYSBtb2Rlcm4gY29tcHV0YXRpb25hbCBhbGdvcml0aG0uIFRoZSBzZWFzb25hbCB0cmVuZCBpbiBhIHRpbWUgc2VyaWVzIGlzIGEgKipmaXhlZCoqIHBhdHRlcm4uIFRoZSByZWFsIGJlbmVmaXQgb2YgU1RMIGlzIHRvIHVzZSB0aGUgTE9FU1MgdG8gZXN0aW1hdGUgdGhlIG5vbmxpbmVhciB0cmVuZCBtb3JlIGFjY3VyYXRlbHkuIFdlIHdpbGwgbm90IGRpc2N1c3MgdGhlIHRlY2huaWNhbCBkZXZlbG9wbWVudCBvZiB0aGUgU1RMLiBJbnN0ZWFkLCB3ZSB3aWxsIHVzZSBpdHMgUiBpbXBsZW1lbnRhdGlvbiB0byBkZWNvbXBvc2UgdGltZSBzZXJpZXMgYW5kIHVzZSBpdCB0byBmb3JlY2FzdCBmdXR1cmUgdmFsdWVzLg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9IkRlY29tcG9zaW5nIHdpdGggU1RMIGFwcHJvYWNoIn0NCnN0bC5iZWVyID0gc3RsKGF1c2JlZXIudHMsICJwZXJpb2RpYyIpDQpzZWFzb25hbC5zdGwuYmVlciAgIDwtIHN0bC5iZWVyJHRpbWUuc2VyaWVzWywxXQ0KdHJlbmQuc3RsLmJlZXIgICAgIDwtIHN0bC5iZWVyJHRpbWUuc2VyaWVzWywyXQ0KcmFuZG9tLnN0bC5iZWVyICA8LSBzdGwuYmVlciR0aW1lLnNlcmllc1ssM10NCiMjIw0KcGFyKG1mcm93PWMoNCwxKSwgbWFyPWMoMiwyLDIsMikpDQpwbG90KGF1c2JlZXIudHMpDQpwbG90KGFzLnRzKHNlYXNvbmFsLnN0bC5iZWVyKSkNCnBsb3QodHJlbmQuc3RsLmJlZXIpDQpwbG90KHJhbmRvbS5zdGwuYmVlcikNCmBgYA0KDQpXZSBjYW4gYWxzbyBwbG90IHRoZSBhYm92ZS1kZWNvbXBvc2VkIGNvbXBvbmVudHMgaW4gYSBzaW5nbGUgc3RlcCBhcyBmb2xsb3dzIHdpdGggdGhlIFNUTCBtb2RlbC4NCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9InBsb3QgY29tcG9uZW50IHBhbmVsIHdpdGggU1RMIG9iamVjdCJ9DQpwbG90KHN0bC5iZWVyKQ0KYGBgDQoNCiMjIEZvcmVjYXN0IHdpdGggU1RMIGRlY29tcG9zaW5nDQoNCkZvciB0aGUgYWRkaXRpdmUgbW9kZWwsIHdlIGNhbiB1c2UgdGhlIFIgZnVuY3Rpb24gKipzdGwoKSoqIHRvIGRlY29tcG9zZSB0aGUgc2VyaWVzIGludG8gdGhyZWUgY29tcG9uZW50cy4gSXQgdXNlcyBhIG1vcmUgcm9idXN0IG5vbi1wYXJhbWV0cmljIHNtb290aGluZyBtZXRob2QgKExPRVNTKSB0byBlc3RpbWF0ZSB0aGUgbm9ubGluZWFyIHRyZW5kLiANCg0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMuNSwgZmlnLmNhcD0iRm9yZWNhcyB3aXRoIFNUTCBkZWNvbXBvc2luZyJ9DQpmaXQgPC0gc3RsKGF1c2JlZXIudHMscy53aW5kb3c9InBlcmlvZGljIikNCnBhcihtYXI9YygyLDIsMiwyKSkNCnBsb3QoZm9yZWNhc3QoZml0LGg9NiwgbWV0aG9kPSJyd2RyaWZ0IikpDQpgYGANCg0KIyMgTGVuZ3RoIG9mIFRpbWUgU2VyaWVzDQoNClRoZSBsZW5ndGggb2YgdGhlIHRpbWUgc2VyaWVzIGltcGFjdHMgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBmb3JlY2FzdGluZy4gSW4gZ2VuZXJhbCwgYSB2ZXJ5IGxvbmcgdGltZSBzZXJpZXMgKGZvciBleGFtcGxlLCBtb3JlIHRoYW4gMjAwIG9ic2VydmF0aW9ucykgdXN1YWxseSBkb2VzIG5vdCB3b3JrIHdlbGwgZm9yIG1vc3Qgb2YgdGhlIGV4aXN0aW5nIG1vZGVscyBwYXJ0bHkgYmVjYXVzZSB0aGUgZXhpc3RpbmcgbW9kZWxzIHdlcmUgbm90IGJ1aWx0IGZvciAqKnZlcnkgbG9uZyoqIHNlcmllcy4gSW50dWl0aXZlbHksIGZ1dHVyZSB2YWx1ZXMgYXJlIGRlcGVuZGVudCBvbiByZWNlbnQgaGlzdG9yaWNhbCB2YWx1ZXMuIElmIGluY2x1ZGluZyB0b28gb2xkIG9ic2VydmF0aW9ucyB0aGF0IGhhdmUgbm8gcHJlZGljdGl2ZSBwb3dlciBpbiB0aGUgbW9kZWwgd2lsbCBicmluZyBiaWFzIGFuZCBub2lzZSB0byB0aGUgdW5kZXJseWluZyBtb2RlbCBhbmQsIGhlbmNlLCBuZWdhdGl2ZSBpbXBhY3RzIG9uIHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgbW9kZWwuDQoNClRoZXJlIGFyZSBhIGxvdCBvZiBkaXNjdXNzaW9ucyBpbiBsaXRlcmF0dXJlIGFuZCBwcmFjdGljZSBhYm91dCB0aGUgbWluaW11bSBzaXplIHJlcXVpcmVkIGZvciBidWlsZGluZyBhIGdvb2QgdGltZSBzZXJpZXMgbW9kZWwuIEl0IHNlZW1zIHRoYXQgNjAgaXMgdGhlIHN1Z2dlc3RlZCBtaW5pbXVtIHNpemUuIFRoZSBhY3R1YWwgbWluaW11bSBzaXplIGRlcGVuZHMgb24gdGhlIHNpdHVhdGlvbiBhbmQgdGhlIGxldmVsIG9mIGFjY3VyYWN5Lg0KDQpJbiB0aGlzIGNsYXNzLCB3ZSByZWNvbW1lbmQgdGhlIHNhbXBsZSBzaXplIGJlIGJldHdlZW4gNjAgYW5kIDIwMC4gVGhlcmVmb3JlLCBpbiB0aGUgYXNzaWdubWVudCwgaWYgdGhlIG9yaWdpbmFsIHRpbWUgc2VyaWVzIGRhdGEgaGFzIG1vcmUgdGhhbiAyMDAgb2JzZXJ2YXRpb25zLCB3ZSBjYW4gdXNlIG9ubHkgMTUwLTIwMCBtb3N0IHJlY2VudCBkYXRhIHZhbHVlcyBmb3IgYW5hbHlzaXMuIA0KDQoNCiMgQ2FzZSBTdHVkeQ0KIA0KIyMgRGF0YSBkZXNjcmlwdGlvbiBhbmQgDQoNClRoZSB0aW1lIHNlcmllcyB1c2VkIGluIHRoaXMgY2FzZSBzdHVkeSBpcyBjaG9zZW4gZnJvbSBbaHR0cHM6Ly9kYXRhaHViLmlvL3NlYXJjaF0oaHR0cHM6Ly9kYXRhaHViLmlvL3NlYXJjaCk6IDEwLXllYXIgbm9taW5hbCB5aWVsZHMgb24gVVMgZ292ZXJubWVudCBib25kcyBmcm9tIHRoZSBGZWRlcmFsIFJlc2VydmUuIFRoZSAxMC15ZWFyIGdvdmVybm1lbnQgYm9uZCB5aWVsZCBpcyBjb25zaWRlcmVkIGEgc3RhbmRhcmQgaW5kaWNhdG9yIG9mIGxvbmctdGVybSBpbnRlcmVzdCByYXRlcy4gVGhlIGRhdGEgY29udGFpbnMgbW9udGhseSByYXRlcy4gVGhlcmUgYXJlIDgwOCBtb250aHMgb2YgZGF0YSBiZXR3ZWVuIEFwcmlsIDE5NDMgYW5kIEp1bHkgMjAyMC4gV2Ugb25seSB1c2UgbG9vayBhdCBtb250aGx5IGRhdGEgYmV0d2VlbiBKYW51YXJ5IDIwMDggYW5kIEp1bHkgMjAyMC4gDQoNCmBgYHtyfQ0KdXMuYm9uZD1yZWFkLmNzdigiaHR0cHM6Ly9kYXRhaHViLmlvL2NvcmUvYm9uZC15aWVsZHMtdXMtMTB5L3IvbW9udGhseS5jc3YiKQ0Kbi5yb3cgPSBkaW0odXMuYm9uZClbMV0NCmRhdGEudXMuYm9uZCA9IHVzLmJvbmRbKG4ucm93LTE1MCk6bi5yb3csIF0NCmBgYA0KDQojIyBEZWZpbmUgdGltZSBzZXJpZXMgb2JqZWN0DQoNClNpbmNlIHRoaXMgaXMgbW9udGhseSBkYXRhLCBmcmVxdWVuY3kgPTEyIHdpbGwgYmUgdXNlZCB0aGUgZGVmaW5lIHRoZSB0aW1lIHNlcmllcyBvYmplY3QuDQoNCmBgYHtyICBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PSAzLCBmaWcuY2FwPSJVUyBib25kIG1vbnRobHkgcmF0ZXMifQ0KdXNib25kLnRzID0gdHMoZGF0YS51cy5ib25kWywyXSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDA4LCAxKSkNCnBhcihtYXI9YygyLDIsMiwyKSkNCnBsb3QodXNib25kLnRzLCBtYWluPSJVUyBCb25kIFJhdGVzIEJldHdlZW4gSmFuLCAyMDA4IGFuZCBKdWx5LCAyMDIwIiwgeWxhYj0iTW9udGhseSBSYXRlIiwgeGxhYj0iIikNCmBgYA0KDQojIyBGb3JlY2FzdGluZyB3aXRoIERlY29tcG9zaW5nDQoNCk5vdGljZSB0aGF0IHRoZSBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbiBtZXRob2QgZG9lcyBub3Qgd29yayBhcyB3ZWxsIGFzIHRoZSBTVEwgbWV0aG9kIGR1ZSB0byB0aGUgcm9idXN0bmVzcyBvZiB0aGUgTE9FU1MgY29tcG9uZW50LiBUaGUgZm9sbG93aW5nIHZpc3VhbCByZXByZXNlbnRhdGlvbnMgc2hvdyB0aGUgZGlmZmVyZW50IGJlaGF2aW9ycyBvZiB0aGUgdHdvIG1ldGhvZHMgb2YgZGVjb21wb3NpdGlvbi4NCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSAiQ2xhc3NpY2FsIGRlY29tcG9zaXRpb24gb2YgYWRkaXRpdmUgdGltZSBzZXJpZXMiLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00fQ0KY2xzLmRlY29tcCA9IGRlY29tcG9zZSh1c2JvbmQudHMpDQpwYXIobWFyPWMoMiwyLDIsMikpDQpwbG90KGNscy5kZWNvbXAsIHhsYWI9IiIpDQpgYGANCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSAiU1RMIGRlY29tcG9zaXRpb24gb2YgYWRkaXRpdmUgdGltZSBzZXJpZXMiLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQ0Kc3RsLmRlY29tcD1zdGwodXNib25kLnRzLCBzLndpbmRvdyA9IDEyKQ0KcGFyKG1hcj1jKDIsMiwyLDIpKQ0KcGxvdChzdGwuZGVjb21wKQ0KYGBgDQoNCioqVHJhaW5pbmcgYW5kIFRlc3RpbmcgRGF0YSoqDQoNCldlIGhvbGQgdXAgdGhlICoqbGFzdCA3IHBlcmlvZHMqKiBvZiBkYXRhIGZvciB0ZXN0aW5nLiBUaGUgcmVzdCBvZiB0aGUgaGlzdG9yaWNhbCBkYXRhIHdpbGwgYmUgdXNlZCB0byB0cmFpbiB0aGUgZm9yZWNhc3QgbW9kZWwuIA0KDQpUbyBldmFsdWF0ZSB0aGUgZWZmZWN0IG9mIGRpZmZlcmVudCBzaXplcyBpbiB0cmFpbmluZyB0aGUgdGltZSBzZXJpZXMsIFdlIGRlZmluZSBkaWZmZXJlbnQgdHJhaW5pbmcgZGF0YSBzZXRzIHdpdGggZGlmZmVyZW50IHNpemVzLiBUaHJlZSB0cmFpbmluZyBzZXQgc2l6ZXMgdXNlZCBpbiB0aGlzIGV4YW1wbGUgYXJlIDE0NCwgMTA5LCA3MywgYW5kIDQ4LiBUaGUgc2FtZSB0ZXN0IHNldCB3aXRoIHNpemUgNyB3aWxsIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwcmVkaWN0aW9uIGVycm9yLg0KDQoNCmBgYHtyfQ0KaW5pLmRhdGEgPSBkYXRhLnVzLmJvbmRbLDJdDQpuMCA9IGxlbmd0aChpbmkuZGF0YSkNCiMjDQp0cmFpbi5kYXRhMDEgPSBkYXRhLnVzLmJvbmRbMToobjAtNyksIDJdDQp0cmFpbi5kYXRhMDIgPSBkYXRhLnVzLmJvbmRbMzc6KG4wLTcpLCAyXQ0KdHJhaW4uZGF0YTAzID0gZGF0YS51cy5ib25kWzczOihuMC03KSwgMl0NCnRyYWluLmRhdGEwNCA9IGRhdGEudXMuYm9uZFs5NzoobjAtNyksIDJdDQojIyBsYXN0IDcgb2JzZXJ2YXRpb25zDQp0ZXN0LmRhdGEgPSBkYXRhLnVzLmJvbmRbKG4wLTYpOm4wLDJdDQojIw0KdHJhaW4wMS50cyA9IHRzKHRyYWluLmRhdGEwMSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDA4LCAxKSkNCnRyYWluMDIudHMgPSB0cyh0cmFpbi5kYXRhMDIsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxMSwgMSkpDQp0cmFpbjAzLnRzID0gdHModHJhaW4uZGF0YTAzLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTQsIDEpKQ0KdHJhaW4wNC50cyA9IHRzKHRyYWluLmRhdGEwNCwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDE2LCAxKSkNCiMjDQpzdGwwMSA9IHN0bCh0cmFpbjAxLnRzLCBzLndpbmRvdyA9IDEyKQ0Kc3RsMDIgPSBzdGwodHJhaW4wMi50cywgcy53aW5kb3cgPSAxMikNCnN0bDAzID0gc3RsKHRyYWluMDMudHMsIHMud2luZG93ID0gMTIpDQpzdGwwNCA9IHN0bCh0cmFpbjA0LnRzLCBzLndpbmRvdyA9IDEyKQ0KIyMgRm9yZWNhc3Qgd2l0aCBkZWNvbXBvc2luZw0KZmNzdDAxID0gZm9yZWNhc3Qoc3RsMDEsaD03LCBtZXRob2Q9Im5haXZlIikNCmZjc3QwMiA9IGZvcmVjYXN0KHN0bDAyLGg9NywgbWV0aG9kPSJuYWl2ZSIpDQpmY3N0MDMgPSBmb3JlY2FzdChzdGwwMyxoPTcsIG1ldGhvZD0ibmFpdmUiKQ0KZmNzdDA0ID0gZm9yZWNhc3Qoc3RsMDQsaD03LCBtZXRob2Q9Im5haXZlIikNCmBgYA0KDQpXZSBuZXh0IHBlcmZvcm0gZXJyb3IgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KIyMgVG8gY29tcGFyZSBkaWZmZXJlbnQgZXJyb3JzLCB3ZSB3aWxsIG5vdCB1c2UgdGhlIHBlcmNlbnRhZ2UgZm9yIE1BUEUNClBFMDE9KHRlc3QuZGF0YS1mY3N0MDEkbWVhbikvZmNzdDAxJG1lYW4NClBFMDI9KHRlc3QuZGF0YS1mY3N0MDIkbWVhbikvZmNzdDAyJG1lYW4NClBFMDM9KHRlc3QuZGF0YS1mY3N0MDMkbWVhbikvZmNzdDAzJG1lYW4NClBFMDQ9KHRlc3QuZGF0YS1mY3N0MDQkbWVhbikvZmNzdDA0JG1lYW4NCiMjIw0KTUFQRTEgPSBtZWFuKGFicyhQRTAxKSkNCk1BUEUyID0gbWVhbihhYnMoUEUwMikpDQpNQVBFMyA9IG1lYW4oYWJzKFBFMDMpKQ0KTUFQRTQgPSBtZWFuKGFicyhQRTA0KSkNCiMjIw0KRTE9dGVzdC5kYXRhLWZjc3QwMSRtZWFuDQpFMj10ZXN0LmRhdGEtZmNzdDAyJG1lYW4NCkUzPXRlc3QuZGF0YS1mY3N0MDMkbWVhbg0KRTQ9dGVzdC5kYXRhLWZjc3QwNCRtZWFuDQojIw0KTVNFMT1tZWFuKEUxXjIpDQpNU0UyPW1lYW4oRTJeMikNCk1TRTM9bWVhbihFM14yKQ0KTVNFND1tZWFuKEU0XjIpDQojIyMNCk1TRT1jKE1TRTEsIE1TRTIsIE1TRTMsIE1TRTQpDQpNQVBFPWMoTUFQRTEsIE1BUEUyLCBNQVBFMywgTUFQRTQpDQphY2N1cmFjeT1jYmluZChNU0U9TVNFLCBNQVBFPU1BUEUpDQpyb3cubmFtZXMoYWNjdXJhY3kpPWMoIm4uMTQ0IiwgIm4uMTA5IiwgIm4uIDczIiwgIm4uIDQ4IikNCmthYmxlKGFjY3VyYWN5LCBjYXB0aW9uPSJFcnJvciBjb21wYXJpc29uIGJldHdlZW4gZm9yZWNhc3QgcmVzdWx0cyB3aXRoIGRpZmZlcmVudCBzYW1wbGUgc2l6ZXMiKQ0KYGBgDQoNClxuZXdwYWdlDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0gIkNvbXBhcmluZyBmb3JlY2FzdCBlcnJvcnMiLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQ0KcGFyKG1mcm93PWMoMSwyKSkNCnBsb3QoMTo0LCBNU0UsIHR5cGU9ImIiLCBjb2w9ImRhcmtyZWQiLCB5bGFiPSJFcnJvciIsIHhsYWI9IiIsDQogICAgICN5bGltPWMoMC40LC44NSkseGxpbSA9IGMoMC41LDQuNSksIA0KICAgICBtYWluPSJNU0UiLCBheGVzPUZBTFNFKQ0KbGFicz1jKCJuPTE0NCIsICJuPTEwOSIsICJuPTczIiwgIm49NDgiKQ0KYXhpcygxLCBhdD0xOjQsIGxhYmVsPWxhYnMpDQpheGlzKDIpDQojbGluZXMoMTo0LCBNQVBFLCB0eXBlPSJiIiwgY29sPSJibHVlIikNCnRleHQoMTo0LCBNQVBFKzAuMDMsIGFzLmNoYXJhY3Rlcihyb3VuZChNQVBFLDQpKSwgY29sPSJibHVlIiwgY2V4PTAuNykNCnRleHQoMTo0LCBNU0UtMC4wMywgYXMuY2hhcmFjdGVyKHJvdW5kKE1TRSw0KSksIGNvbD0iZGFya3JlZCIsIGNleD0wLjcpDQpsZWdlbmQoMS41LCAwLjYzLCBjKCJNU0UiLCAiTUFQRSIpLCBjb2w9YygiZGFya3JlZCIsImJsdWUiKSwgbHR5PTEsIGJ0eT0ibiIsIGNleD0wLjcpDQojIyMNCiNgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9ICJDb21wYXJpbmcgZm9yZWNhc3QgZXJyb3JzIiwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9My41fQ0KcGxvdCgxOjQsIE1BUEUsIHR5cGU9ImIiLCBjb2w9ImRhcmtyZWQiLCB5bGFiPSJFcnJvciIsIHhsYWI9IiIsDQogICAgICN5bGltPWMoMC40LC44NSkseGxpbSA9IGMoMC41LDQuNSksIA0KICAgICBtYWluPSJNQVBFIiwgYXhlcz1GQUxTRSkNCmxhYnM9Yygibj0xNDQiLCAibj0xMDkiLCAibj03MyIsICJuPTQ4IikNCmF4aXMoMSwgYXQ9MTo0LCBsYWJlbD1sYWJzKQ0KYXhpcygyKQ0KYGBgDQoNCldlIHRyYWluZWQgdGhlIHNhbWUgYWxnb3JpdGhtIHdpdGggZGlmZmVyZW50IHNhbXBsZSBzaXplcyBhbmQgY29tcGFyZWQgdGhlIHJlc3VsdGluZyBhY2N1cmFjeSBtZWFzdXJlcy4gQW1vbmcgZm91ciB0cmFpbmluZyBzaXplcyAxNDQsIDEwOSwgNzMsIGFuZCA0OC4gdHJhaW5pbmcgZGF0YSBzaXplIDczIHlpZWxkcyB0aGUgYmVzdCBwZXJmb3JtYW5jZS4NCg0KDQpBcyBhbnRpY2lwYXRlZCwgZm9yZWNhc3Rpbmcgd2l0aCBTVEwgc21vb3RoaW5nIGRvZXMgbm90IHlpZWxkIGRlY2VudCByZXN1bHRzLiBIb3dldmVyLCBvdXIgY2FzZSBzdHVkeSBzdGlsbCBhY2NvbXBsaXNoZXMgdGhlIG1haW4gbGVhcm5pbmcgZ29hbHMuIFRvIGJlIG1vcmUgc3BlY2lmaWMsIHdlIGhhdmUgbGVhcm5lZCBob3cgdG8NCg0KKiBkZWNvbXBvc2UgYSB0aW1lIHNlcmllcyANCg0KKiBkaXN0aW5ndWlzaCB0aGUgZ3JhcGhpY2FsIHBhdHRlcm5zIG9mIGFkZGl0aXZlIGFuZCBtdWx0aXBsaWNhdGl2ZSB0aW1lIHNlcmllcyBtb2RlbHMNCg0KKiB1c2UgdGhlIG5vbi1wYXJhbWV0cmljIHNtb290aGluZyBMT0VTUyBtZXRob2QgaW4gdGltZSBzZXJpZXMgZm9yZWNhc3Rpbmc7DQoNCiogdXNlIHRoZSB0ZWNobmlxdWUgb2YgbWFjaGluZSBsZWFybmluZyB0byB0dW5lIHRoZSB0cmFpbmluZyBzaXplIHRvIGlkZW50aWZ5IHRoZSBvcHRpbWFsIHRyYWluaW5nIHNpemUgdG8gYWNoaWV2ZSB0aGUgYmVzdCBhY2N1cmFjeS4gSW4gdGhpcyBjYXNlLCB0aGUgdHJhaW5pbmcgc2l6ZSBpcyBjb25zaWRlcmVkIGEgdHVuaW5nIHBhcmFtZXRlciAoaHlwZXItcGFyYW1ldGVyKS4NCg0KDQpXZSB3aWxsIHN0YXJ0IGJ1aWxkaW5nIGFjdHVhbCBhbmQgcHJhY3RpY2FsIGZvcmVjYXN0aW5nIG1vZGVscyBpbiB0aGUgbmV4dCBtb2R1bGUgLSBleHBvbmVudGlhbCBzbW9vdGhpbmcgbW9kZWxzLg0KDQoNCg0KDQoNCg0KDQo=