Introduction and
Background
The dataset in use today originally stems from the extremely popular
real estate website, Zillow. It is a compilation of Zillow’s home value
index rankings broken down in a month-by-month and state-by-state
manner, beginning in January of 2000 and being most recently updated in
September of 2025.
Technically speaking, the dataset’s structure is fairly
straightforward. There are 51 variables, with the first day of each
month acting as a date object within R in YYYY-MM-DD format, and every
state in the nation’s home value index getting its own variable, stored
as a double (units are $USD). There are 228 missing
values across the dataset, with the vast majority of them coming from
North Dakota, Montana, Wyoming and New Mexico.
For my analysis, I will be specifically focusing on the typical home
values in the state of New York, and constraining my study to the 15
year time window of January 2010 to January of 2025. I will not be
primarily concerned with associative and external exploration as to
why the changes in home prices have occurred in the manner
which they have. Rather I will be applying a longitudinal perspective
and developing a number of time series models with the hope of creating
a model that can reliably, based on the historical data at hand, predict
future New York home values.
Plot of the Data
Below we see a plot of the standard New York home’s value over the
past 15 years. From this plot, there is one obvious takeaway that
instantly comes to the viewer’s mind. That being, there is a clear,
noticeable and approximately consistent increase in home values
throughout the duration between January of 2010 and January of 2025. To
quantify; the home value index for New York in January of 2025 was about
$496,846 per home, while in January of 2010 that same metric was only
$267,153. This is a staggering increase of about 85.98%.
Time_Series = ts(TS_Data$NY, frequency = 12, start = c(2010,1))
# frequency set to 12 since our dataset is composed of years, which are 12-month periods
# keyword start ensures that the axes on graph below will be accurate, that ts function recognizes that the first observation is the first of 12 of value 2010
# using xaxt = "n" will override the graph's default axis. I want the x intervals to be more frequent than every 5 years
plot((Time_Series/1000), xaxt="n",
main = "New York State's Home Value Index, 2010 - 2025",
xlab = "Year",
ylab = "Value (1000's $USD)")
axis(1,
at = seq(2010, 2025, by = 1),
labels = seq(2010, 2025, by = 1))

Decomposition
Analysis
Before creating time series models of varying sizes and using them to
forecast future values, I performed decomposition on the dataset.
Decomposition is basically the process of breaking down the makeup of a
time series into its different key components. These components being
the seasonal patterns, overall trend, and random error (sometimes called
remainder) that exist within the data. Below are visuals from two
decomposition processes; classical and STL.
Classical
Decomposition
Here is a display of the New York home value index data from 2010 to
2025, post classical decomposition. There are a few noticeable
takeaways. Looking at the trend component, we see a clear rise in home
values over the 15-year period. This is not surprising, as it was also
clearly visible in our original plot above. Regarding seasonality, we
see consistent oscillation at approximately the same interval length
throughout the dataset. On average throughout the years, New York homes
had their highest values in the Fall (~ $340,676) and their lowest in
the Spring (~ 332,837). Finally, when it comes to the random error
component of the decomposed time series, we see a spike in the
remainder’s magnitude after 2020. This can most likely be attributed to
the economic uncertainty related to the COVID pandemic.
Classic_Decomp = decompose(Time_Series)
plot(Classic_Decomp)

Summer = filter(Data, Season == "Summer")
Fall = filter(Data, Season == "Fall")
Winter = filter(Data, Season == "Winter")
Spring = filter(Data, Season == "Spring")
invisible(round(mean(Summer$NY)))
invisible(round(mean(Fall$NY)))
invisible(round(mean(Winter$NY)))
invisible(round(mean(Spring$NY)))
Seasonal and Trend
LOESS (STL) Decomposition
The STL decomposition of the data tells practically the same story of
the classical decomposition. The only large difference being that this
decomposition shows a much larger magnitude of seasonal oscillation from
about 2020 to 2025, while the classical decomposition shows equivalent
seasonal oscillation throughout.
Generally speaking, STL decomposition is considered a more robust
procedure than its classical counterpart, as STL is more effective in
dealing with outliers and non-linearity in data. The STL method uses
LOESS (modern locally estimated scatterplot smoothing), while the
classical method uses a more basic moving average. That is why we see
variation in the seasonality of the data in our STL visual.
Going forward, I used the STL method when formulating the time series
models.
STL_Decomp = stl(Time_Series, s.window = 12)
# the s.window argument essentially tells the stl function how to estimate the seasonal component. Since I put the number 12, that is basically telling the function that every 12 observations (months) the seasonal pattern (year) should be reset to re-estimate for the next series of observations. If I was trying to estimate the seasonal component for summer/fall/winter/spring, I would set s.window = to 3
plot(STL_Decomp,
main = "STL Decomposition of Time Series")

Creating Training and
Testing Sets
Since it is bad statistical practice to test a model on the same data
which it is trained on, I devoted the data’s ten most recent
observations (April of 2024 to January of 2025) for post-creation
testing purposes. For the training data, I used R’s runif function to
randomly select four sample sizes (n) to assign to each of the
four training subsets of the data. All four of the training datasets
ended with the observation on March of 2024, and respectively began
(n - 1) months after January of 2010. I created the training
datasets (1 through 4) in sequential order of descending sample size
(set 1 has the most observations, set 2 has the second most, etc…).
After subsetting the data into these four separate training sets, I
performed STL decomposition on each one and then forecasted each model’s
next ten observations (the same ten which make up the known testing
dataset). For each model I used the drift method for forecasting, as the
drift accounts for historical increases and decreases in a response
variable over time, something that is very prevalent in this
dataset.
# Training dataset of 171 observations, most we want to take out is about 30.
# use runif function for random selection, to select four numbers between 1 and 30, our training subsets of the data will go from that randomly selected observation point up to point 171 (March of 2024)
# sort(round(runif(4, min = 1, max = 30)))
# Results are 9, 12, 16, 25
Testing_Data = TS_Data[172:181,]
# Training set 1:
Training_Data1 = TS_Data[9:171, ]
# Training set 2:
Training_Data2 = TS_Data[12:171, ]
# Training set 3:
Training_Data3 = TS_Data[16:171, ]
# Training set 4:
Training_Data4 = TS_Data[25:171, ]
### Now that training and testing subsets of data have been created, make time series objects for each
TS_Train1 = ts(Training_Data1$NY, frequency = 12, start = c(2010, 9))
TS_Train2 = ts(Training_Data2$NY, frequency = 12, start = c(2010, 12))
TS_Train3 = ts(Training_Data3$NY, frequency = 12, start = c(2011, 4))
TS_Train4 = ts(Training_Data4$NY, frequency = 12, start = c(2012, 1))
### going to use the stl() function to decompose each of the training dataset time series objects, then use those decomposed objects for forecasting
STL_Training1 = stl(TS_Train1, s.window = 12)
STL_Training2 = stl(TS_Train2, s.window = 12)
STL_Training3 = stl(TS_Train3, s.window = 12)
STL_Training4 = stl(TS_Train4, s.window = 12)
### Forecast calculations with decomposed training set time series objects
# Set h = 10 as there is 10 observations in the testing dataset, so we can do a one-to-one comparison between our training forecasts for each time series model and our observed values in the testing dataset (April 2024 to January 2025)
Train_Set1_Forecasts = forecast(STL_Training1, h = 10, method = "rwdrift")
Train_Set2_Forecasts = forecast(STL_Training2, h = 10, method = "rwdrift")
Train_Set3_Forecasts = forecast(STL_Training3, h = 10, method = "rwdrift")
Train_Set4_Forecasts = forecast(STL_Training4, h = 10, method = "rwdrift")
Examining each
Training Set’s Forecasted Values
Below I created both a table to quantify each training set’s
forecasts as well as a graph to visualize their performances relative to
both one another and the true New York home values
provided in the original dataset. As we can see, all of the models
underestimated the rise in home values that would take place from August
of 2024 to January of 2025.
# Use the $mean selection to see the forecasted predicted values at particular points
TSMean1 = data.frame(Train_Set1_Forecasts$mean)
colnames(TSMean1) = "Errors"
TSMean2 = data.frame(Train_Set2_Forecasts$mean)
colnames(TSMean2) = "Errors"
TSMean3 = data.frame(Train_Set3_Forecasts$mean)
colnames(TSMean3) = "Errors"
TSMean4 = data.frame(Train_Set4_Forecasts$mean)
colnames(TSMean4) = "Errors"
Years = data.frame(TS_Data$Date[172:181])
Forecasted_Values = cbind(Years, TSMean1, TSMean2, TSMean3, TSMean4, Testing_Data[,2])
colnames(Forecasted_Values) = c("Date", "TS 1", "TS 2", "TS 3", "TS 4", "True Values")
kable(Forecasted_Values, caption = "Forecasted Values Per Training Set")
Forecasted Values Per Training Set
| 2024-04-01 |
471873.8 |
471906.1 |
471970.9 |
472416.2 |
474674.4 |
| 2024-05-01 |
473687.4 |
473749.5 |
473884.2 |
474484.1 |
478114.6 |
| 2024-06-01 |
475432.6 |
475524.3 |
475729.0 |
476477.5 |
480880.8 |
| 2024-07-01 |
476944.1 |
477081.9 |
477258.2 |
478134.8 |
483467.0 |
| 2024-08-01 |
478031.1 |
478215.0 |
478421.9 |
479375.2 |
486631.5 |
| 2024-09-01 |
478733.7 |
478963.6 |
479201.1 |
480193.7 |
489556.9 |
| 2024-10-01 |
479461.4 |
479739.6 |
480047.0 |
481079.5 |
492028.3 |
| 2024-11-01 |
480458.1 |
480784.5 |
481130.9 |
482225.5 |
493899.7 |
| 2024-12-01 |
481615.7 |
481990.3 |
482375.8 |
483545.4 |
495692.6 |
| 2025-01-01 |
482804.7 |
483219.2 |
483708.2 |
485002.2 |
496846.3 |
List_Of_Dates = as.Date(c("2024-04-01", "2024-05-01", "2024-06-01", "2024-07-01", "2024-08-01", "2024-09-01", "2024-10-01", "2024-11-01", "2024-12-01", "2025-01-01"))
TS1 = data.frame(List_Of_Dates, as.double(TSMean1$Errors))
TS2 = data.frame(List_Of_Dates, as.double(TSMean2$Errors))
TS3 = data.frame(List_Of_Dates, as.double(TSMean3$Errors))
TS4 = data.frame(List_Of_Dates, as.double(TSMean4$Errors))
plot(Testing_Data, col = "blue", lwd = 2,
main = "Forecasted Vs True New York Home Values \n (August 2024 - January 2025)",
xlab = "Date",
ylab = "Value($USD)")
lines(Testing_Data, col = "blue", lwd = 2)
lines(TS1, col = "red", lwd = 2)
points(TS1, col = "red")
lines(TS2, col = "black", lwd = 2)
points(TS2, col = "black")
lines(TS3, col = "green", lwd = 2)
points(TS3, col = "green")
lines(TS4, col = "purple", lwd = 2)
points(TS4, col = "purple")
legend("topleft",
legend = c("True Values", "Time Series 1", "Time Series 2",
"Time Series 3", "Time Series 4"),
col = c("blue", "red", "black", "green", "purple"),
lty = 1, pch = 16, lwd = 2)

Training Set Forecast
Error Analysis
As we saw above, there was a consistent underestimation by each of
the training set time series. However, there appeared to be a linear and
negative correlation between the sample size of the training set, and
that set’s forecasts relative to the true values. Training set 4 had the
smallest sample size (beginning at January of 2012) and was the most
accurate.
A numeric breakdown of each training sets forecasts’ accuracy is
below. The metrics I used were mean error (ME), mean square error (MSE)
and mean absolute prediction error (MAPE). As seen in the visuals above,
as the sample size of our time series training set decreased, its
accuracy increased.
This is likely due to non-linear rise in New York home values,
especially from 2018 to 2025. The smaller time series training sets were
less influenced by the lesser home values of the early parts of the
2010s.
####### Define Error Objects
TS_Forecasts1_Errors = Testing_Data[,2] - TSMean1
TS_Forecasts2_Errors = Testing_Data[,2] - TSMean2
TS_Forecasts3_Errors = Testing_Data[,2] - TSMean3
TS_Forecasts4_Errors = Testing_Data[,2] - TSMean4
####### ME
TS1_ME = sum(TS_Forecasts1_Errors)/nrow(TS_Forecasts1_Errors)
TS2_ME = sum(TS_Forecasts2_Errors)/nrow(TS_Forecasts2_Errors)
TS3_ME = sum(TS_Forecasts3_Errors)/nrow(TS_Forecasts3_Errors)
TS4_ME = sum(TS_Forecasts4_Errors)/nrow(TS_Forecasts4_Errors)
####### MSE
TS1_MSE = sum(TS_Forecasts1_Errors^2)/nrow(TS_Forecasts1_Errors)
TS2_MSE = sum(TS_Forecasts2_Errors^2)/nrow(TS_Forecasts2_Errors)
TS3_MSE = sum(TS_Forecasts3_Errors^2)/nrow(TS_Forecasts3_Errors)
TS4_MSE = sum(TS_Forecasts4_Errors^2)/nrow(TS_Forecasts4_Errors)
####### MAPE
TS1_MAPE = (sum(abs((TS_Forecasts1_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts1_Errors)
TS2_MAPE = (sum(abs((TS_Forecasts2_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts2_Errors)
TS3_MAPE = (sum(abs((TS_Forecasts3_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts3_Errors)
TS4_MAPE = (sum(abs((TS_Forecasts4_Errors/Testing_Data[,2])*100)))/nrow(TS_Forecasts4_Errors)
##### Table to Visualize
All_MEs = rbind(TS1_ME, TS2_ME, TS3_ME, TS4_ME)
All_MSEs = rbind(TS1_MSE, TS2_MSE, TS3_MSE, TS4_MSE)
All_MAPEs = rbind(TS1_MAPE, TS2_MAPE, TS3_MAPE, TS4_MAPE)
Forecast_Errors = cbind(All_MEs, All_MSEs, All_MAPEs)
colnames(Forecast_Errors) = c("ME", "MSE", "MAPE")
rownames(Forecast_Errors) = c("TS1", "TS2", "TS3", "TS4")
kable(Forecast_Errors, caption = "Model Forecasts' Accuracy Measures")
Model Forecasts’ Accuracy Measures
| TS1 |
9274.949 |
102471188 |
1.891789 |
| TS2 |
9061.826 |
97571016 |
1.848419 |
| TS3 |
8806.477 |
92147504 |
1.796344 |
| TS4 |
7885.797 |
75042461 |
1.608069 |
Conclusion
Ultimately, when looking at New York state’s home values over the
past 15 years, forecasting monthly index values via STL-decomposed
training sets did not yield particularly accurate results. Despite
training our forecast algorithm with the drift method, which is meant to
take into account historical increases and decreases, all four of our
time series underestimated the true values of New York’s home value
index from August of 2024 to January of 2025.
In a future analysis, it would possibly be valuable during the
training set process, to widen the scope of sample size selection. Doing
so would allow us to see at which point does constraining the time
interval of observations for the training data become detrimental. As in
this instance, with the maximum number of observations coming out being
set to 30, we saw a directly negative relationship between sample size
of the training set and forecasts’ accuracy.
References
Original Dataset Source:
Dataset Download Link via Github:
LS0tCnRpdGxlOiAiTmV3IFlvcmsgU3RhdGUncyBNb250aGx5IEhvbWUgVmFsdWUgSW5kZXggKFNpbmNlIDIwMTApIgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiMjAyNS0xMS0yMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgZmlnX3dpZHRoOiA2CiAgICBmaWdfaGVpZ2h0OiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB0YW5nbwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0Ci0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOwogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOwogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsKICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsKfQoKaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8KICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KCmlmICghcmVxdWlyZSgia25pdHIiKSkgeyAgICAgICAgICAgICAgICAgICAgICAjIHVzZSBjb25kaXRpb25hbCBzdGF0ZW1lbnQgdG8gZGV0ZWN0CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgYSBwYWNrYWdlIHdhcyBpbnN0YWxsZWQgaW4KICAgbGlicmFyeShrbml0cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91ciBtYWNoaW5lLiBJZiBub3QsIGluc3RhbGwgaXQgYW5kCn0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGxvYWQgaXQgdG8gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKaWYgKCFyZXF1aXJlKHRpZHl2ZXJzZSkpIHtsaWJyYXJ5KHRpZHl2c2Vyc2UpfSAKCmlmICghcmVxdWlyZShHR2FsbHkpKSB7bGlicmFyeShHR2FsbHkpfSAKCmlmICghcmVxdWlyZShrYWJsZUV4dHJhKSkge2xpYnJhcnkoa2FibGVFeHRyYSl9IAoKaWYgKCFyZXF1aXJlKGdncGxvdDIpKSB7bGlicmFyeShnZ3Bsb3QyKX0gCgppZiAoIXJlcXVpcmUoY2FyKSkge2xpYnJhcnkoY2FyKX0gCgppZiAoIXJlcXVpcmUoZHBseXIpKSB7bGlicmFyeShkcGx5cil9IAoKaWYgKCFyZXF1aXJlKHBhbmRlcikpIHtsaWJyYXJ5KHBhbmRlcil9IAoKaWYgKCFyZXF1aXJlKGZvcmVjYXN0KSkge2xpYnJhcnkoZm9yZWNhc3QpfSAKCmlmICghcmVxdWlyZShsdWJyaWRhdGUpKSB7bGlicmFyeShsdWJyaWRhdGUpfSAKCmlmICghcmVxdWlyZSgic2NhbGVzIikpIHsKaW5zdGFsbC5wYWNrYWdlcygic2NhbGVzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmxpYnJhcnkoInNjYWxlcyIpIAp9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoCgllY2hvID0gVFJVRSwKCW1lc3NhZ2UgPSBGQUxTRSwKCXdhcm5pbmcgPSBGQUxTRSwKCWNvbW1lbnQgPSBOQSwKCXJlc3VsdHMgPSBUUlVFCikKYGBgCgojIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZCAKVGhlIGRhdGFzZXQgaW4gdXNlIHRvZGF5IG9yaWdpbmFsbHkgc3RlbXMgZnJvbSB0aGUgZXh0cmVtZWx5IHBvcHVsYXIgcmVhbCBlc3RhdGUgd2Vic2l0ZSwgWmlsbG93LiBJdCBpcyBhIGNvbXBpbGF0aW9uIG9mIFppbGxvdydzIGhvbWUgdmFsdWUgaW5kZXggcmFua2luZ3MgYnJva2VuIGRvd24gaW4gYSBtb250aC1ieS1tb250aCBhbmQgc3RhdGUtYnktc3RhdGUgbWFubmVyLCBiZWdpbm5pbmcgaW4gSmFudWFyeSBvZiAyMDAwIGFuZCBiZWluZyBtb3N0IHJlY2VudGx5IHVwZGF0ZWQgaW4gU2VwdGVtYmVyIG9mIDIwMjUuCgpUZWNobmljYWxseSBzcGVha2luZywgdGhlIGRhdGFzZXQncyBzdHJ1Y3R1cmUgaXMgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZC4gVGhlcmUgYXJlIDUxIHZhcmlhYmxlcywgd2l0aCB0aGUgZmlyc3QgZGF5IG9mIGVhY2ggbW9udGggYWN0aW5nIGFzIGEgZGF0ZSBvYmplY3Qgd2l0aGluIFIgaW4gWVlZWS1NTS1ERCBmb3JtYXQsIGFuZCBldmVyeSBzdGF0ZSBpbiB0aGUgbmF0aW9uJ3MgaG9tZSB2YWx1ZSBpbmRleCBnZXR0aW5nIGl0cyBvd24gdmFyaWFibGUsIHN0b3JlZCBhcyBhIGRvdWJsZSAqKih1bml0cyBhcmUgJFVTRCkqKi4gVGhlcmUgYXJlIDIyOCBtaXNzaW5nIHZhbHVlcyBhY3Jvc3MgdGhlIGRhdGFzZXQsIHdpdGggdGhlIHZhc3QgbWFqb3JpdHkgb2YgdGhlbSBjb21pbmcgZnJvbSBOb3J0aCBEYWtvdGEsIE1vbnRhbmEsIFd5b21pbmcgYW5kIE5ldyBNZXhpY28uCgpGb3IgbXkgYW5hbHlzaXMsIEkgd2lsbCBiZSBzcGVjaWZpY2FsbHkgZm9jdXNpbmcgb24gdGhlIHR5cGljYWwgaG9tZSB2YWx1ZXMgaW4gdGhlIHN0YXRlIG9mIE5ldyBZb3JrLCBhbmQgY29uc3RyYWluaW5nIG15IHN0dWR5IHRvIHRoZSAxNSB5ZWFyIHRpbWUgd2luZG93IG9mIEphbnVhcnkgMjAxMCB0byBKYW51YXJ5IG9mIDIwMjUuIEkgd2lsbCBub3QgYmUgcHJpbWFyaWx5IGNvbmNlcm5lZCB3aXRoIGFzc29jaWF0aXZlIGFuZCBleHRlcm5hbCBleHBsb3JhdGlvbiBhcyB0byAqd2h5KiB0aGUgY2hhbmdlcyBpbiBob21lIHByaWNlcyBoYXZlIG9jY3VycmVkIGluIHRoZSBtYW5uZXIgd2hpY2ggdGhleSBoYXZlLiBSYXRoZXIgSSB3aWxsIGJlIGFwcGx5aW5nIGEgbG9uZ2l0dWRpbmFsIHBlcnNwZWN0aXZlIGFuZCBkZXZlbG9waW5nIGEgbnVtYmVyIG9mIHRpbWUgc2VyaWVzIG1vZGVscyB3aXRoIHRoZSBob3BlIG9mIGNyZWF0aW5nIGEgbW9kZWwgdGhhdCBjYW4gcmVsaWFibHksIGJhc2VkIG9uIHRoZSBoaXN0b3JpY2FsIGRhdGEgYXQgaGFuZCwgcHJlZGljdCBmdXR1cmUgTmV3IFlvcmsgaG9tZSB2YWx1ZXMuCgpgYGB7ciBEYXRhIExvYWRpbmcgYW5kIENsZWFuaW5nLCBpbmNsdWRlPUZBTFNFfQpEYXRhX1VybD0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaHJpc0IyMzIzL1NUQTMyMS9yZWZzL2hlYWRzL21haW4vWmlsbG93X0RhdGEuY3N2IgoKT3JpZ2luYWxfRGF0YSA9IHJlYWRfZGVsaW0oRGF0YV9VcmwsIGRlbGltID0gIiwiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpzdW0oaXMubmEoT3JpZ2luYWxfRGF0YSkpICMgPSAyMjggbWlzc2luZyB2YWx1ZXMKCiAgIyBCcmVha2Rvd24gb2YgbWlzc2luZyB2YWx1ZXMgcGVyIHN0YXRlCmNvbFN1bXMoaXMubmEoT3JpZ2luYWxfRGF0YSkpW2NvbFN1bXMoaXMubmEoT3JpZ2luYWxfRGF0YSkpID4gMF0KCiMgV2lsbCB1c2UgdGhlIGxhc3QgMTUgeWVhcnMgb2YgZGF0YSwgMTUgeWVhcnMgKiAxMiBtb250aHMgPSAxODAgb2JzZXJ2YXRpb25zCgpEYXRhID0gT3JpZ2luYWxfRGF0YVsxMjE6MzAxLF0KY29sbmFtZXMoRGF0YSlbMV0gPSAiRGF0ZSIKZ2xpbXBzZShEYXRhKQogICMgQWxsIHZhcmlhYmxlcyBmb3JtYXR0ZWQgcmlnaHQsIE1vbnRoIGlzIGRhdGUgb2JqZWN0IGFuZCB0aGUgcmVzdCBhcmUgZG91YmxlcwoKICAjIEdvaW5nIHRvIGNvbmR1Y3QgdW5pdmFyaWF0ZSBhbmFseXNpcywgd2l0aCBOZXcgWW9yaydzIGF2ZXJhZ2UgaG9tZSB2YWx1ZSBpbmRleCAoaW4gJFVTRCkgYXMgdGhlIHJlc3BvbnNlIGluIHRoaXMgdGltZSBzZXJpZXMKCkRhdGEgPSBEYXRhWyAsYygiRGF0ZSIsICJOZXcgWW9yayIpXQpjb2xuYW1lcyhEYXRhKVsyXSA9ICJOWSIKICAjIF4gRm9yIGNvZGluZyBjb252ZW5pZW5jZQoKIyBXYW50IHRvIGxhYmVsIG15IGRhdGEgYnkgbW9udGgsIHNlYXNvbiBhbmQgeWVhci4KICAjIFVzZWQgQUkgZm9yIHNlYXNvbiBhc3NpZ25tZW50IGJlbG93CkRhdGEgPSBEYXRhICU+JQogIG11dGF0ZSgKICAgIFllYXIgPSB5ZWFyKERhdGUpLAogICAgTW9udGggPSBtb250aChEYXRlLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBUUlVFKSwKICAgIFNlYXNvbiA9IGNhc2Vfd2hlbigKICAgICAgbW9udGgoRGF0ZSkgJWluJSBjKDEyLCAxLCAyKSB+ICJXaW50ZXIiLAogICAgICBtb250aChEYXRlKSAlaW4lIGMoMywgNCwgNSkgIH4gIlNwcmluZyIsCiAgICAgIG1vbnRoKERhdGUpICVpbiUgYyg2LCA3LCA4KSAgfiAiU3VtbWVyIiwKICAgICAgbW9udGgoRGF0ZSkgJWluJSBjKDksIDEwLCAxMSkgfiAiRmFsbCIKICAgICkKICApCgpUU19EYXRhID0gRGF0YVssMToyXQpgYGAKCiMgUGxvdCBvZiB0aGUgRGF0YQpCZWxvdyB3ZSBzZWUgYSBwbG90IG9mIHRoZSBzdGFuZGFyZCBOZXcgWW9yayBob21lJ3MgdmFsdWUgb3ZlciB0aGUgcGFzdCAxNSB5ZWFycy4gRnJvbSB0aGlzIHBsb3QsIHRoZXJlIGlzIG9uZSBvYnZpb3VzIHRha2Vhd2F5IHRoYXQgaW5zdGFudGx5IGNvbWVzIHRvIHRoZSB2aWV3ZXIncyBtaW5kLiBUaGF0IGJlaW5nLCB0aGVyZSBpcyBhIGNsZWFyLCBub3RpY2VhYmxlIGFuZCBhcHByb3hpbWF0ZWx5IGNvbnNpc3RlbnQgaW5jcmVhc2UgaW4gaG9tZSB2YWx1ZXMgdGhyb3VnaG91dCB0aGUgZHVyYXRpb24gYmV0d2VlbiBKYW51YXJ5IG9mIDIwMTAgYW5kIEphbnVhcnkgb2YgMjAyNS4gVG8gcXVhbnRpZnk7IHRoZSBob21lIHZhbHVlIGluZGV4IGZvciBOZXcgWW9yayBpbiBKYW51YXJ5IG9mIDIwMjUgd2FzIGFib3V0ICQ0OTYsODQ2IHBlciBob21lLCB3aGlsZSBpbiBKYW51YXJ5IG9mIDIwMTAgdGhhdCBzYW1lIG1ldHJpYyB3YXMgb25seSAkMjY3LDE1My4gVGhpcyBpcyBhIHN0YWdnZXJpbmcgaW5jcmVhc2Ugb2YgYWJvdXQgYHIgcm91bmQoKCgoNDk2ODQ2IC0gMjY3MTUzKS8yNjcxNTMpICogMTAwKSwgMilgJS4gCmBgYHtyLCBmaWcuYWxpZ24gPSdjZW50ZXInfQpUaW1lX1NlcmllcyA9IHRzKFRTX0RhdGEkTlksIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxMCwxKSkKICAjIGZyZXF1ZW5jeSBzZXQgdG8gMTIgc2luY2Ugb3VyIGRhdGFzZXQgaXMgY29tcG9zZWQgb2YgeWVhcnMsIHdoaWNoIGFyZSAxMi1tb250aCBwZXJpb2RzCiAgIyBrZXl3b3JkIHN0YXJ0IGVuc3VyZXMgdGhhdCB0aGUgYXhlcyBvbiBncmFwaCBiZWxvdyB3aWxsIGJlIGFjY3VyYXRlLCB0aGF0IHRzIGZ1bmN0aW9uIHJlY29nbml6ZXMgdGhhdCB0aGUgZmlyc3Qgb2JzZXJ2YXRpb24gaXMgdGhlIGZpcnN0IG9mIDEyIG9mIHZhbHVlIDIwMTAKCiMgdXNpbmcgeGF4dCA9ICJuIiB3aWxsIG92ZXJyaWRlIHRoZSBncmFwaCdzIGRlZmF1bHQgYXhpcy4gSSB3YW50IHRoZSB4IGludGVydmFscyB0byBiZSBtb3JlIGZyZXF1ZW50IHRoYW4gZXZlcnkgNSB5ZWFycwpwbG90KChUaW1lX1Nlcmllcy8xMDAwKSwgeGF4dD0ibiIsCiAgICAgbWFpbiA9ICJOZXcgWW9yayBTdGF0ZSdzIEhvbWUgVmFsdWUgSW5kZXgsIDIwMTAgLSAyMDI1IiwKICAgICB4bGFiID0gIlllYXIiLAogICAgIHlsYWIgPSAiVmFsdWUgKDEwMDAncyAkVVNEKSIpCmF4aXMoMSwKICAgICBhdCA9IHNlcSgyMDEwLCAyMDI1LCBieSA9IDEpLAogICAgIGxhYmVscyA9IHNlcSgyMDEwLCAyMDI1LCBieSA9IDEpKQpgYGAKCgojIERlY29tcG9zaXRpb24gQW5hbHlzaXMKQmVmb3JlIGNyZWF0aW5nIHRpbWUgc2VyaWVzIG1vZGVscyBvZiB2YXJ5aW5nIHNpemVzIGFuZCB1c2luZyB0aGVtIHRvIGZvcmVjYXN0IGZ1dHVyZSB2YWx1ZXMsIEkgcGVyZm9ybWVkIGRlY29tcG9zaXRpb24gb24gdGhlIGRhdGFzZXQuIERlY29tcG9zaXRpb24gaXMgYmFzaWNhbGx5IHRoZSBwcm9jZXNzIG9mIGJyZWFraW5nIGRvd24gdGhlIG1ha2V1cCBvZiBhIHRpbWUgc2VyaWVzIGludG8gaXRzIGRpZmZlcmVudCBrZXkgY29tcG9uZW50cy4gVGhlc2UgY29tcG9uZW50cyBiZWluZyB0aGUgc2Vhc29uYWwgcGF0dGVybnMsIG92ZXJhbGwgdHJlbmQsIGFuZCByYW5kb20gZXJyb3IgKHNvbWV0aW1lcyBjYWxsZWQgcmVtYWluZGVyKSB0aGF0IGV4aXN0IHdpdGhpbiB0aGUgZGF0YS4gQmVsb3cgYXJlIHZpc3VhbHMgZnJvbSB0d28gZGVjb21wb3NpdGlvbiBwcm9jZXNzZXM7IGNsYXNzaWNhbCBhbmQgU1RMLgoKIyMgQ2xhc3NpY2FsIERlY29tcG9zaXRpb24KSGVyZSBpcyBhIGRpc3BsYXkgb2YgdGhlIE5ldyBZb3JrIGhvbWUgdmFsdWUgaW5kZXggZGF0YSBmcm9tIDIwMTAgdG8gMjAyNSwgcG9zdCBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbi4gVGhlcmUgYXJlIGEgZmV3IG5vdGljZWFibGUgdGFrZWF3YXlzLiBMb29raW5nIGF0IHRoZSB0cmVuZCBjb21wb25lbnQsIHdlIHNlZSBhIGNsZWFyIHJpc2UgaW4gaG9tZSB2YWx1ZXMgb3ZlciB0aGUgMTUteWVhciBwZXJpb2QuIFRoaXMgaXMgbm90IHN1cnByaXNpbmcsIGFzIGl0IHdhcyBhbHNvIGNsZWFybHkgdmlzaWJsZSBpbiBvdXIgb3JpZ2luYWwgcGxvdCBhYm92ZS4gUmVnYXJkaW5nIHNlYXNvbmFsaXR5LCB3ZSBzZWUgY29uc2lzdGVudCBvc2NpbGxhdGlvbiBhdCBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGludGVydmFsIGxlbmd0aCB0aHJvdWdob3V0IHRoZSBkYXRhc2V0LiBPbiBhdmVyYWdlIHRocm91Z2hvdXQgdGhlIHllYXJzLCBOZXcgWW9yayBob21lcyBoYWQgdGhlaXIgaGlnaGVzdCB2YWx1ZXMgaW4gdGhlIEZhbGwgKH4gJDM0MCw2NzYpIGFuZCB0aGVpciBsb3dlc3QgaW4gdGhlIFNwcmluZyAofiAzMzIsODM3KS4gRmluYWxseSwgd2hlbiBpdCBjb21lcyB0byB0aGUgcmFuZG9tIGVycm9yIGNvbXBvbmVudCBvZiB0aGUgZGVjb21wb3NlZCB0aW1lIHNlcmllcywgd2Ugc2VlIGEgc3Bpa2UgaW4gdGhlIHJlbWFpbmRlcidzIG1hZ25pdHVkZSBhZnRlciAyMDIwLiBUaGlzIGNhbiBtb3N0IGxpa2VseSBiZSBhdHRyaWJ1dGVkIHRvIHRoZSBlY29ub21pYyB1bmNlcnRhaW50eSByZWxhdGVkIHRvIHRoZSBDT1ZJRCBwYW5kZW1pYy4KYGBge3IsIGZpZy5hbGlnbiA9J2NlbnRlcid9CkNsYXNzaWNfRGVjb21wID0gZGVjb21wb3NlKFRpbWVfU2VyaWVzKQpwbG90KENsYXNzaWNfRGVjb21wKQoKICBTdW1tZXIgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJTdW1tZXIiKQogIEZhbGwgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJGYWxsIikKICBXaW50ZXIgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJXaW50ZXIiKQogIFNwcmluZyA9IGZpbHRlcihEYXRhLCBTZWFzb24gPT0gIlNwcmluZyIpCiAgICAKICBpbnZpc2libGUocm91bmQobWVhbihTdW1tZXIkTlkpKSkKICBpbnZpc2libGUocm91bmQobWVhbihGYWxsJE5ZKSkpCiAgaW52aXNpYmxlKHJvdW5kKG1lYW4oV2ludGVyJE5ZKSkpCiAgaW52aXNpYmxlKHJvdW5kKG1lYW4oU3ByaW5nJE5ZKSkpCmBgYAoKIyMgU2Vhc29uYWwgYW5kIFRyZW5kIExPRVNTIChTVEwpIERlY29tcG9zaXRpb24KVGhlIFNUTCBkZWNvbXBvc2l0aW9uIG9mIHRoZSBkYXRhIHRlbGxzIHByYWN0aWNhbGx5IHRoZSBzYW1lIHN0b3J5IG9mIHRoZSBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbi4gVGhlIG9ubHkgbGFyZ2UgZGlmZmVyZW5jZSBiZWluZyB0aGF0IHRoaXMgZGVjb21wb3NpdGlvbiBzaG93cyBhIG11Y2ggbGFyZ2VyIG1hZ25pdHVkZSBvZiBzZWFzb25hbCBvc2NpbGxhdGlvbiBmcm9tIGFib3V0IDIwMjAgdG8gMjAyNSwgd2hpbGUgdGhlIGNsYXNzaWNhbCBkZWNvbXBvc2l0aW9uIHNob3dzIGVxdWl2YWxlbnQgc2Vhc29uYWwgb3NjaWxsYXRpb24gdGhyb3VnaG91dC4KCkdlbmVyYWxseSBzcGVha2luZywgU1RMIGRlY29tcG9zaXRpb24gaXMgY29uc2lkZXJlZCBhIG1vcmUgcm9idXN0IHByb2NlZHVyZSB0aGFuIGl0cyBjbGFzc2ljYWwgY291bnRlcnBhcnQsIGFzIFNUTCBpcyBtb3JlIGVmZmVjdGl2ZSBpbiBkZWFsaW5nIHdpdGggb3V0bGllcnMgYW5kIG5vbi1saW5lYXJpdHkgaW4gZGF0YS4gVGhlIFNUTCBtZXRob2QgdXNlcyBMT0VTUyAobW9kZXJuIGxvY2FsbHkgZXN0aW1hdGVkIHNjYXR0ZXJwbG90IHNtb290aGluZyksIHdoaWxlIHRoZSBjbGFzc2ljYWwgbWV0aG9kIHVzZXMgYSBtb3JlIGJhc2ljIG1vdmluZyBhdmVyYWdlLiBUaGF0IGlzIHdoeSB3ZSBzZWUgdmFyaWF0aW9uIGluIHRoZSBzZWFzb25hbGl0eSBvZiB0aGUgZGF0YSBpbiBvdXIgU1RMIHZpc3VhbC4KCkdvaW5nIGZvcndhcmQsIEkgdXNlZCB0aGUgU1RMIG1ldGhvZCB3aGVuIGZvcm11bGF0aW5nIHRoZSB0aW1lIHNlcmllcyBtb2RlbHMuCgpgYGB7ciwgZmlnLmFsaWduID0nY2VudGVyJ30KU1RMX0RlY29tcCA9IHN0bChUaW1lX1Nlcmllcywgcy53aW5kb3cgPSAxMikKICAjIHRoZSBzLndpbmRvdyBhcmd1bWVudCBlc3NlbnRpYWxseSB0ZWxscyB0aGUgc3RsIGZ1bmN0aW9uIGhvdyB0byBlc3RpbWF0ZSB0aGUgc2Vhc29uYWwgY29tcG9uZW50LiBTaW5jZSBJIHB1dCB0aGUgbnVtYmVyIDEyLCB0aGF0IGlzIGJhc2ljYWxseSB0ZWxsaW5nIHRoZSBmdW5jdGlvbiB0aGF0IGV2ZXJ5IDEyIG9ic2VydmF0aW9ucyAobW9udGhzKSB0aGUgc2Vhc29uYWwgcGF0dGVybiAoeWVhcikgc2hvdWxkIGJlIHJlc2V0IHRvIHJlLWVzdGltYXRlIGZvciB0aGUgbmV4dCBzZXJpZXMgb2Ygb2JzZXJ2YXRpb25zLiBJZiBJIHdhcyB0cnlpbmcgdG8gZXN0aW1hdGUgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCBmb3Igc3VtbWVyL2ZhbGwvd2ludGVyL3NwcmluZywgSSB3b3VsZCBzZXQgcy53aW5kb3cgPSB0byAzCgpwbG90KFNUTF9EZWNvbXAsCiAgICAgbWFpbiA9ICJTVEwgRGVjb21wb3NpdGlvbiBvZiBUaW1lIFNlcmllcyIpCmBgYAoKIyBDcmVhdGluZyBUcmFpbmluZyBhbmQgVGVzdGluZyBTZXRzClNpbmNlIGl0IGlzIGJhZCBzdGF0aXN0aWNhbCBwcmFjdGljZSB0byB0ZXN0IGEgbW9kZWwgb24gdGhlIHNhbWUgZGF0YSB3aGljaCBpdCBpcyB0cmFpbmVkIG9uLCBJIGRldm90ZWQgdGhlIGRhdGEncyB0ZW4gbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zIChBcHJpbCBvZiAyMDI0IHRvIEphbnVhcnkgb2YgMjAyNSkgZm9yIHBvc3QtY3JlYXRpb24gdGVzdGluZyBwdXJwb3Nlcy4gRm9yIHRoZSB0cmFpbmluZyBkYXRhLCBJIHVzZWQgUidzIHJ1bmlmIGZ1bmN0aW9uIHRvIHJhbmRvbWx5IHNlbGVjdCBmb3VyIHNhbXBsZSBzaXplcyAoKm4qKSB0byBhc3NpZ24gdG8gZWFjaCBvZiB0aGUgZm91ciB0cmFpbmluZyBzdWJzZXRzIG9mIHRoZSBkYXRhLiBBbGwgZm91ciBvZiB0aGUgdHJhaW5pbmcgZGF0YXNldHMgZW5kZWQgd2l0aCB0aGUgb2JzZXJ2YXRpb24gb24gTWFyY2ggb2YgMjAyNCwgYW5kIHJlc3BlY3RpdmVseSBiZWdhbiAoKm4qIC0gMSkgbW9udGhzIGFmdGVyIEphbnVhcnkgb2YgMjAxMC4gSSBjcmVhdGVkIHRoZSB0cmFpbmluZyBkYXRhc2V0cyAoMSB0aHJvdWdoIDQpIGluIHNlcXVlbnRpYWwgb3JkZXIgb2YgZGVzY2VuZGluZyBzYW1wbGUgc2l6ZSAoc2V0IDEgaGFzIHRoZSBtb3N0IG9ic2VydmF0aW9ucywgc2V0IDIgaGFzIHRoZSBzZWNvbmQgbW9zdCwgZXRjLi4uKS4KCkFmdGVyIHN1YnNldHRpbmcgdGhlIGRhdGEgaW50byB0aGVzZSBmb3VyIHNlcGFyYXRlIHRyYWluaW5nIHNldHMsIEkgcGVyZm9ybWVkIFNUTCBkZWNvbXBvc2l0aW9uIG9uIGVhY2ggb25lIGFuZCB0aGVuIGZvcmVjYXN0ZWQgZWFjaCBtb2RlbCdzIG5leHQgdGVuIG9ic2VydmF0aW9ucyAodGhlIHNhbWUgdGVuIHdoaWNoIG1ha2UgdXAgdGhlIGtub3duIHRlc3RpbmcgZGF0YXNldCkuIEZvciBlYWNoIG1vZGVsIEkgdXNlZCB0aGUgZHJpZnQgbWV0aG9kIGZvciBmb3JlY2FzdGluZywgYXMgdGhlIGRyaWZ0IGFjY291bnRzIGZvciBoaXN0b3JpY2FsIGluY3JlYXNlcyBhbmQgZGVjcmVhc2VzIGluIGEgcmVzcG9uc2UgdmFyaWFibGUgb3ZlciB0aW1lLCBzb21ldGhpbmcgdGhhdCBpcyB2ZXJ5IHByZXZhbGVudCBpbiB0aGlzIGRhdGFzZXQuCmBgYHtyLCBNYWtpbmcgVHJhaW5pbmcgU2V0c30KIyBUcmFpbmluZyBkYXRhc2V0IG9mIDE3MSBvYnNlcnZhdGlvbnMsIG1vc3Qgd2Ugd2FudCB0byB0YWtlIG91dCBpcyBhYm91dCAzMC4KIyB1c2UgcnVuaWYgZnVuY3Rpb24gZm9yIHJhbmRvbSBzZWxlY3Rpb24sIHRvIHNlbGVjdCBmb3VyIG51bWJlcnMgYmV0d2VlbiAxIGFuZCAzMCwgb3VyIHRyYWluaW5nIHN1YnNldHMgb2YgdGhlIGRhdGEgd2lsbCBnbyBmcm9tIHRoYXQgcmFuZG9tbHkgc2VsZWN0ZWQgb2JzZXJ2YXRpb24gcG9pbnQgdXAgdG8gcG9pbnQgMTcxIChNYXJjaCBvZiAyMDI0KQogICAjIHNvcnQocm91bmQocnVuaWYoNCwgbWluID0gMSwgbWF4ID0gMzApKSkKICAgICMgUmVzdWx0cyBhcmUgOSwgMTIsIDE2LCAyNQoKVGVzdGluZ19EYXRhID0gVFNfRGF0YVsxNzI6MTgxLF0KCiMgVHJhaW5pbmcgc2V0IDE6IApUcmFpbmluZ19EYXRhMSA9IFRTX0RhdGFbOToxNzEsIF0KCiMgVHJhaW5pbmcgc2V0IDI6IApUcmFpbmluZ19EYXRhMiA9IFRTX0RhdGFbMTI6MTcxLCBdCgojIFRyYWluaW5nIHNldCAzOiAKVHJhaW5pbmdfRGF0YTMgPSBUU19EYXRhWzE2OjE3MSwgXQoKIyBUcmFpbmluZyBzZXQgNDogClRyYWluaW5nX0RhdGE0ID0gVFNfRGF0YVsyNToxNzEsIF0KCgojIyMgTm93IHRoYXQgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc3Vic2V0cyBvZiBkYXRhIGhhdmUgYmVlbiBjcmVhdGVkLCBtYWtlIHRpbWUgc2VyaWVzIG9iamVjdHMgZm9yIGVhY2gKClRTX1RyYWluMSA9IHRzKFRyYWluaW5nX0RhdGExJE5ZLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTAsIDkpKQpUU19UcmFpbjIgPSB0cyhUcmFpbmluZ19EYXRhMiROWSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEwLCAxMikpClRTX1RyYWluMyA9IHRzKFRyYWluaW5nX0RhdGEzJE5ZLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTEsIDQpKQpUU19UcmFpbjQgPSB0cyhUcmFpbmluZ19EYXRhNCROWSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEyLCAxKSkKCiMjIyBnb2luZyB0byB1c2UgdGhlIHN0bCgpIGZ1bmN0aW9uIHRvIGRlY29tcG9zZSBlYWNoIG9mIHRoZSB0cmFpbmluZyBkYXRhc2V0IHRpbWUgc2VyaWVzIG9iamVjdHMsIHRoZW4gdXNlIHRob3NlIGRlY29tcG9zZWQgb2JqZWN0cyBmb3IgZm9yZWNhc3RpbmcKClNUTF9UcmFpbmluZzEgPSBzdGwoVFNfVHJhaW4xLCBzLndpbmRvdyA9IDEyKQpTVExfVHJhaW5pbmcyID0gc3RsKFRTX1RyYWluMiwgcy53aW5kb3cgPSAxMikKU1RMX1RyYWluaW5nMyA9IHN0bChUU19UcmFpbjMsIHMud2luZG93ID0gMTIpClNUTF9UcmFpbmluZzQgPSBzdGwoVFNfVHJhaW40LCBzLndpbmRvdyA9IDEyKQoKIyMjIEZvcmVjYXN0IGNhbGN1bGF0aW9ucyB3aXRoIGRlY29tcG9zZWQgdHJhaW5pbmcgc2V0IHRpbWUgc2VyaWVzIG9iamVjdHMKCiAgIyBTZXQgaCA9IDEwIGFzIHRoZXJlIGlzIDEwIG9ic2VydmF0aW9ucyBpbiB0aGUgdGVzdGluZyBkYXRhc2V0LCBzbyB3ZSBjYW4gZG8gYSBvbmUtdG8tb25lIGNvbXBhcmlzb24gYmV0d2VlbiBvdXIgdHJhaW5pbmcgZm9yZWNhc3RzIGZvciBlYWNoIHRpbWUgc2VyaWVzIG1vZGVsIGFuZCBvdXIgb2JzZXJ2ZWQgdmFsdWVzIGluIHRoZSB0ZXN0aW5nIGRhdGFzZXQgKEFwcmlsIDIwMjQgdG8gSmFudWFyeSAyMDI1KQpUcmFpbl9TZXQxX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzEsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQyX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzIsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQzX0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzMsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpUcmFpbl9TZXQ0X0ZvcmVjYXN0cyA9IGZvcmVjYXN0KFNUTF9UcmFpbmluZzQsIGggPSAxMCwgbWV0aG9kID0gInJ3ZHJpZnQiKQpgYGAKCiMjIEV4YW1pbmluZyBlYWNoIFRyYWluaW5nIFNldCdzIEZvcmVjYXN0ZWQgVmFsdWVzCkJlbG93IEkgY3JlYXRlZCBib3RoIGEgdGFibGUgdG8gcXVhbnRpZnkgZWFjaCB0cmFpbmluZyBzZXQncyBmb3JlY2FzdHMgYXMgd2VsbCBhcyBhIGdyYXBoIHRvIHZpc3VhbGl6ZSB0aGVpciBwZXJmb3JtYW5jZXMgcmVsYXRpdmUgdG8gYm90aCBvbmUgYW5vdGhlciBhbmQgdGhlICoqdHJ1ZSoqIE5ldyBZb3JrIGhvbWUgdmFsdWVzIHByb3ZpZGVkIGluIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiBBcyB3ZSBjYW4gc2VlLCBhbGwgb2YgdGhlIG1vZGVscyB1bmRlcmVzdGltYXRlZCB0aGUgcmlzZSBpbiBob21lIHZhbHVlcyB0aGF0IHdvdWxkIHRha2UgcGxhY2UgZnJvbSBBdWd1c3Qgb2YgMjAyNCB0byBKYW51YXJ5IG9mIDIwMjUuCmBgYHtyLCBmaWcuYWxpZ249J2NlbnRlcid9CiAgIyBVc2UgdGhlICRtZWFuIHNlbGVjdGlvbiB0byBzZWUgdGhlIGZvcmVjYXN0ZWQgcHJlZGljdGVkIHZhbHVlcyBhdCBwYXJ0aWN1bGFyIHBvaW50cwpUU01lYW4xID0gZGF0YS5mcmFtZShUcmFpbl9TZXQxX0ZvcmVjYXN0cyRtZWFuKQogIGNvbG5hbWVzKFRTTWVhbjEpID0gIkVycm9ycyIKVFNNZWFuMiA9IGRhdGEuZnJhbWUoVHJhaW5fU2V0Ml9Gb3JlY2FzdHMkbWVhbikKICBjb2xuYW1lcyhUU01lYW4yKSA9ICJFcnJvcnMiClRTTWVhbjMgPSBkYXRhLmZyYW1lKFRyYWluX1NldDNfRm9yZWNhc3RzJG1lYW4pCiAgY29sbmFtZXMoVFNNZWFuMykgPSAiRXJyb3JzIgpUU01lYW40ID0gZGF0YS5mcmFtZShUcmFpbl9TZXQ0X0ZvcmVjYXN0cyRtZWFuKQogIGNvbG5hbWVzKFRTTWVhbjQpID0gIkVycm9ycyIKWWVhcnMgPSBkYXRhLmZyYW1lKFRTX0RhdGEkRGF0ZVsxNzI6MTgxXSkKCkZvcmVjYXN0ZWRfVmFsdWVzID0gY2JpbmQoWWVhcnMsIFRTTWVhbjEsIFRTTWVhbjIsIFRTTWVhbjMsIFRTTWVhbjQsIFRlc3RpbmdfRGF0YVssMl0pCmNvbG5hbWVzKEZvcmVjYXN0ZWRfVmFsdWVzKSA9IGMoIkRhdGUiLCAiVFMgMSIsICJUUyAyIiwgIlRTIDMiLCAiVFMgNCIsICJUcnVlIFZhbHVlcyIpCmthYmxlKEZvcmVjYXN0ZWRfVmFsdWVzLCBjYXB0aW9uID0gIkZvcmVjYXN0ZWQgVmFsdWVzIFBlciBUcmFpbmluZyBTZXQiKQoKTGlzdF9PZl9EYXRlcyA9IGFzLkRhdGUoYygiMjAyNC0wNC0wMSIsICIyMDI0LTA1LTAxIiwgIjIwMjQtMDYtMDEiLCAiMjAyNC0wNy0wMSIsICIyMDI0LTA4LTAxIiwgIjIwMjQtMDktMDEiLCAiMjAyNC0xMC0wMSIsICIyMDI0LTExLTAxIiwgIjIwMjQtMTItMDEiLCAiMjAyNS0wMS0wMSIpKQoKVFMxID0gZGF0YS5mcmFtZShMaXN0X09mX0RhdGVzLCBhcy5kb3VibGUoVFNNZWFuMSRFcnJvcnMpKQpUUzIgPSBkYXRhLmZyYW1lKExpc3RfT2ZfRGF0ZXMsIGFzLmRvdWJsZShUU01lYW4yJEVycm9ycykpClRTMyA9IGRhdGEuZnJhbWUoTGlzdF9PZl9EYXRlcywgYXMuZG91YmxlKFRTTWVhbjMkRXJyb3JzKSkKVFM0ID0gZGF0YS5mcmFtZShMaXN0X09mX0RhdGVzLCBhcy5kb3VibGUoVFNNZWFuNCRFcnJvcnMpKQoKcGxvdChUZXN0aW5nX0RhdGEsIGNvbCA9ICJibHVlIiwgbHdkID0gMiwKICAgICBtYWluID0gIkZvcmVjYXN0ZWQgVnMgVHJ1ZSBOZXcgWW9yayBIb21lIFZhbHVlcyBcbiAoQXVndXN0IDIwMjQgLSBKYW51YXJ5IDIwMjUpIiwKICAgICB4bGFiID0gIkRhdGUiLAogICAgIHlsYWIgPSAiVmFsdWUoJFVTRCkiKQogIGxpbmVzKFRlc3RpbmdfRGF0YSwgY29sID0gImJsdWUiLCBsd2QgPSAyKQogIGxpbmVzKFRTMSwgY29sID0gInJlZCIsIGx3ZCA9IDIpCiAgICBwb2ludHMoVFMxLCBjb2wgPSAicmVkIikKICBsaW5lcyhUUzIsIGNvbCA9ICJibGFjayIsIGx3ZCA9IDIpCiAgICBwb2ludHMoVFMyLCBjb2wgPSAiYmxhY2siKQogIGxpbmVzKFRTMywgY29sID0gImdyZWVuIiwgbHdkID0gMikKICAgIHBvaW50cyhUUzMsIGNvbCA9ICJncmVlbiIpCiAgbGluZXMoVFM0LCBjb2wgPSAicHVycGxlIiwgbHdkID0gMikKICAgIHBvaW50cyhUUzQsIGNvbCA9ICJwdXJwbGUiKQogICAgbGVnZW5kKCJ0b3BsZWZ0IiwKICAgICAgIGxlZ2VuZCA9IGMoIlRydWUgVmFsdWVzIiwgIlRpbWUgU2VyaWVzIDEiLCAiVGltZSBTZXJpZXMgMiIsCiAgICAgICAgICAgICAgICAgICJUaW1lIFNlcmllcyAzIiwgIlRpbWUgU2VyaWVzIDQiKSwKICAgICAgIGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImJsYWNrIiwgImdyZWVuIiwgInB1cnBsZSIpLAogICAgICAgbHR5ID0gMSwgcGNoID0gMTYsIGx3ZCA9IDIpCmBgYAoKIyMgVHJhaW5pbmcgU2V0IEZvcmVjYXN0IEVycm9yIEFuYWx5c2lzCkFzIHdlIHNhdyBhYm92ZSwgdGhlcmUgd2FzIGEgY29uc2lzdGVudCB1bmRlcmVzdGltYXRpb24gYnkgZWFjaCBvZiB0aGUgdHJhaW5pbmcgc2V0IHRpbWUgc2VyaWVzLiBIb3dldmVyLCB0aGVyZSBhcHBlYXJlZCB0byBiZSBhIGxpbmVhciBhbmQgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgc2FtcGxlIHNpemUgb2YgdGhlIHRyYWluaW5nIHNldCwgYW5kIHRoYXQgc2V0J3MgZm9yZWNhc3RzIHJlbGF0aXZlIHRvIHRoZSB0cnVlIHZhbHVlcy4gVHJhaW5pbmcgc2V0IDQgaGFkIHRoZSBzbWFsbGVzdCBzYW1wbGUgc2l6ZSAoYmVnaW5uaW5nIGF0IEphbnVhcnkgb2YgMjAxMikgYW5kIHdhcyB0aGUgbW9zdCBhY2N1cmF0ZS4KCkEgbnVtZXJpYyBicmVha2Rvd24gb2YgZWFjaCB0cmFpbmluZyBzZXRzIGZvcmVjYXN0cycgYWNjdXJhY3kgaXMgYmVsb3cuIFRoZSBtZXRyaWNzIEkgdXNlZCB3ZXJlIG1lYW4gZXJyb3IgKE1FKSwgbWVhbiBzcXVhcmUgZXJyb3IgKE1TRSkgYW5kIG1lYW4gYWJzb2x1dGUgcHJlZGljdGlvbiBlcnJvciAoTUFQRSkuIEFzIHNlZW4gaW4gdGhlIHZpc3VhbHMgYWJvdmUsIGFzIHRoZSBzYW1wbGUgc2l6ZSBvZiBvdXIgdGltZSBzZXJpZXMgdHJhaW5pbmcgc2V0IGRlY3JlYXNlZCwgaXRzIGFjY3VyYWN5IGluY3JlYXNlZC4gCgpUaGlzIGlzIGxpa2VseSBkdWUgdG8gbm9uLWxpbmVhciByaXNlIGluIE5ldyBZb3JrIGhvbWUgdmFsdWVzLCBlc3BlY2lhbGx5IGZyb20gMjAxOCB0byAyMDI1LiBUaGUgc21hbGxlciB0aW1lIHNlcmllcyB0cmFpbmluZyBzZXRzIHdlcmUgbGVzcyBpbmZsdWVuY2VkIGJ5IHRoZSBsZXNzZXIgaG9tZSB2YWx1ZXMgb2YgdGhlIGVhcmx5IHBhcnRzIG9mIHRoZSAyMDEwcy4KYGBge3IsIEVycm9yIEFuYWx5c2lzfQojIyMjIyMjIERlZmluZSBFcnJvciBPYmplY3RzClRTX0ZvcmVjYXN0czFfRXJyb3JzID0gVGVzdGluZ19EYXRhWywyXSAtIFRTTWVhbjEKVFNfRm9yZWNhc3RzMl9FcnJvcnMgPSBUZXN0aW5nX0RhdGFbLDJdIC0gVFNNZWFuMgpUU19Gb3JlY2FzdHMzX0Vycm9ycyA9IFRlc3RpbmdfRGF0YVssMl0gLSBUU01lYW4zClRTX0ZvcmVjYXN0czRfRXJyb3JzID0gVGVzdGluZ19EYXRhWywyXSAtIFRTTWVhbjQKCiMjIyMjIyMgTUUKVFMxX01FID0gc3VtKFRTX0ZvcmVjYXN0czFfRXJyb3JzKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTUUgPSBzdW0oVFNfRm9yZWNhc3RzMl9FcnJvcnMpL25yb3coVFNfRm9yZWNhc3RzMl9FcnJvcnMpClRTM19NRSA9IHN1bShUU19Gb3JlY2FzdHMzX0Vycm9ycykvbnJvdyhUU19Gb3JlY2FzdHMzX0Vycm9ycykKVFM0X01FID0gc3VtKFRTX0ZvcmVjYXN0czRfRXJyb3JzKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMjIyBNU0UKVFMxX01TRSA9IHN1bShUU19Gb3JlY2FzdHMxX0Vycm9yc14yKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTVNFID0gc3VtKFRTX0ZvcmVjYXN0czJfRXJyb3JzXjIpL25yb3coVFNfRm9yZWNhc3RzMl9FcnJvcnMpClRTM19NU0UgPSBzdW0oVFNfRm9yZWNhc3RzM19FcnJvcnNeMikvbnJvdyhUU19Gb3JlY2FzdHMzX0Vycm9ycykKVFM0X01TRSA9IHN1bShUU19Gb3JlY2FzdHM0X0Vycm9yc14yKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMjIyBNQVBFClRTMV9NQVBFID0gKHN1bShhYnMoKFRTX0ZvcmVjYXN0czFfRXJyb3JzL1Rlc3RpbmdfRGF0YVssMl0pKjEwMCkpKS9ucm93KFRTX0ZvcmVjYXN0czFfRXJyb3JzKQpUUzJfTUFQRSA9IChzdW0oYWJzKChUU19Gb3JlY2FzdHMyX0Vycm9ycy9UZXN0aW5nX0RhdGFbLDJdKSoxMDApKSkvbnJvdyhUU19Gb3JlY2FzdHMyX0Vycm9ycykKVFMzX01BUEUgPSAoc3VtKGFicygoVFNfRm9yZWNhc3RzM19FcnJvcnMvVGVzdGluZ19EYXRhWywyXSkqMTAwKSkpL25yb3coVFNfRm9yZWNhc3RzM19FcnJvcnMpClRTNF9NQVBFID0gKHN1bShhYnMoKFRTX0ZvcmVjYXN0czRfRXJyb3JzL1Rlc3RpbmdfRGF0YVssMl0pKjEwMCkpKS9ucm93KFRTX0ZvcmVjYXN0czRfRXJyb3JzKQoKIyMjIyMgVGFibGUgdG8gVmlzdWFsaXplCkFsbF9NRXMgPSByYmluZChUUzFfTUUsIFRTMl9NRSwgVFMzX01FLCBUUzRfTUUpCkFsbF9NU0VzID0gcmJpbmQoVFMxX01TRSwgVFMyX01TRSwgVFMzX01TRSwgVFM0X01TRSkKQWxsX01BUEVzID0gcmJpbmQoVFMxX01BUEUsIFRTMl9NQVBFLCBUUzNfTUFQRSwgVFM0X01BUEUpCgpGb3JlY2FzdF9FcnJvcnMgPSBjYmluZChBbGxfTUVzLCBBbGxfTVNFcywgQWxsX01BUEVzKQpjb2xuYW1lcyhGb3JlY2FzdF9FcnJvcnMpID0gYygiTUUiLCAiTVNFIiwgIk1BUEUiKQpyb3duYW1lcyhGb3JlY2FzdF9FcnJvcnMpID0gYygiVFMxIiwgIlRTMiIsICJUUzMiLCAiVFM0IikKa2FibGUoRm9yZWNhc3RfRXJyb3JzLCBjYXB0aW9uID0gIk1vZGVsIEZvcmVjYXN0cycgQWNjdXJhY3kgTWVhc3VyZXMiKQpgYGAKCiMgQ29uY2x1c2lvbgpVbHRpbWF0ZWx5LCB3aGVuIGxvb2tpbmcgYXQgTmV3IFlvcmsgc3RhdGUncyBob21lIHZhbHVlcyBvdmVyIHRoZSBwYXN0IDE1IHllYXJzLCBmb3JlY2FzdGluZyBtb250aGx5IGluZGV4IHZhbHVlcyB2aWEgU1RMLWRlY29tcG9zZWQgdHJhaW5pbmcgc2V0cyBkaWQgbm90IHlpZWxkIHBhcnRpY3VsYXJseSBhY2N1cmF0ZSByZXN1bHRzLiBEZXNwaXRlIHRyYWluaW5nIG91ciBmb3JlY2FzdCBhbGdvcml0aG0gd2l0aCB0aGUgZHJpZnQgbWV0aG9kLCB3aGljaCBpcyBtZWFudCB0byB0YWtlIGludG8gYWNjb3VudCBoaXN0b3JpY2FsIGluY3JlYXNlcyBhbmQgZGVjcmVhc2VzLCBhbGwgZm91ciBvZiBvdXIgdGltZSBzZXJpZXMgdW5kZXJlc3RpbWF0ZWQgdGhlIHRydWUgdmFsdWVzIG9mIE5ldyBZb3JrJ3MgaG9tZSB2YWx1ZSBpbmRleCBmcm9tIEF1Z3VzdCBvZiAyMDI0IHRvIEphbnVhcnkgb2YgMjAyNS4KCkluIGEgZnV0dXJlIGFuYWx5c2lzLCBpdCB3b3VsZCBwb3NzaWJseSBiZSB2YWx1YWJsZSBkdXJpbmcgdGhlIHRyYWluaW5nIHNldCBwcm9jZXNzLCB0byB3aWRlbiB0aGUgc2NvcGUgb2Ygc2FtcGxlIHNpemUgc2VsZWN0aW9uLiBEb2luZyBzbyB3b3VsZCBhbGxvdyB1cyB0byBzZWUgYXQgd2hpY2ggcG9pbnQgZG9lcyBjb25zdHJhaW5pbmcgdGhlIHRpbWUgaW50ZXJ2YWwgb2Ygb2JzZXJ2YXRpb25zIGZvciB0aGUgdHJhaW5pbmcgZGF0YSBiZWNvbWUgZGV0cmltZW50YWwuIEFzIGluIHRoaXMgaW5zdGFuY2UsIHdpdGggdGhlIG1heGltdW0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBjb21pbmcgb3V0IGJlaW5nIHNldCB0byAzMCwgd2Ugc2F3IGEgZGlyZWN0bHkgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gc2FtcGxlIHNpemUgb2YgdGhlIHRyYWluaW5nIHNldCBhbmQgZm9yZWNhc3RzJyBhY2N1cmFjeS4KCiMgUmVmZXJlbmNlcwpPcmlnaW5hbCBEYXRhc2V0IFNvdXJjZToKCi0gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9yb2Jpa3NjdWJlL3ppbGxvdy1ob21lLXZhbHVlLWluZGV4CgpEYXRhc2V0IERvd25sb2FkIExpbmsgdmlhIEdpdGh1YjoKCi0gaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9aaWxsb3dfRGF0YS5jc3Y=