7.8.1

Consider the pigs series – the number of pigs slaughtered in Victoria each month.

a.

Use the ses() function in R to find the optimal values of \(\alpha\) and \(\ell_0\) and generate forecasts for the next four months.

First, we begin by inspecting the pigs time series by looking at its information, its head and tail. We see that the time series is captured on a monthly scale. An autoplot of the time series shows no consistent long term trend.

## starting httpd help server ... done

Number of pigs slaughtered Description Monthly total number of pigs slaughtered in Victoria, Australia (Jan 1980 to Aug 1995).

Usage pigs Format Time series data

Source Makridakis, Wheelwright and Hyndman (1998) Forecasting: methods and applications, John Wiley & Sons: New York. Chapter 7.

##         Jan    Feb    Mar    Apr    May    Jun
## 1980  76378  71947  33873  96428 105084  95741
##         Mar    Apr    May    Jun    Jul    Aug
## 1995 106723  84307 114896 106749  87892 100506

Next, R’s simple exponential series, “ses”, function is applied to the pigs time series to forecast the next four months. The results are also plotted below.

Looking its summary, we see that the optimal level of alpha is, alpha = 0.2971 and the level is, l = 77260.0561.

## 
## Forecast method: Simple exponential smoothing
## 
## Model Information:
## Simple exponential smoothing 
## 
## Call:
##  ses(y = pigs, h = 4) 
## 
##   Smoothing parameters:
##     alpha = 0.2971 
## 
##   Initial states:
##     l = 77260.0561 
## 
##   sigma:  10308.58
## 
##      AIC     AICc      BIC 
## 4462.955 4463.086 4472.665 
## 
## Error measures:
##                    ME    RMSE      MAE       MPE     MAPE      MASE       ACF1
## Training set 385.8721 10253.6 7961.383 -0.922652 9.274016 0.7966249 0.01282239
## 
## Forecasts:
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Sep 1995       98816.41 85605.43 112027.4 78611.97 119020.8
## Oct 1995       98816.41 85034.52 112598.3 77738.83 119894.0
## Nov 1995       98816.41 84486.34 113146.5 76900.46 120732.4
## Dec 1995       98816.41 83958.37 113674.4 76092.99 121539.8
ME RMSE MAE MPE MAPE MASE ACF1
Training set 385.87 10253.6 7961.38 -0.92 9.27 0.8 0.01

b.

Compute a 95% prediction interval for the first forecast using where is the standard deviation of the residuals. Compare your interval with the interval produced by R.

The custom function below, “calc_95_CI”, calculates the 95% Confidence Interval.

The manually calculated 95% Confidence Interval is:

lower upper
78679.97 118952.8

The R generated confidence interval is:

lower upper
78611.97 119020.8

The R generated 95% confidence interval seems to be wider than the manually calculated 95% confidence interval. The difference is greater than a simple rounding error.

7.8.5

Data set books contains the daily sales of paperback and hardcover books at the same store. The task is to forecast the next four days’ sales for paperback and hardcover books.

a.

Plot the series and discuss the main features of the data.

From the help function, head and tail, we see that the time series is a daily time series split between Paperback and Hardcover. The autoplot of the series shows a long term upward trend for both Paperback and Hardcover book sales along with cyclical patterns.

Sales of paperback and hardcover books Description Daily sales of paperback and hardcover books at the same store.

Usage books Format Bivariate time series containing the following columns:

Paperback Number of paperback sales each day

Hardcover Number of hardcover sales each day

Source Makridakis, Wheelwright and Hyndman (1998) Forecasting: methods and applications, John Wiley & Sons: New York. Exercise 4.5.

## Time Series:
## Start = 1 
## End = 6 
## Frequency = 1 
##   Paperback Hardcover
## 1       199       139
## 2       172       128
## 3       111       172
## 4       209       139
## 5       161       191
## 6       119       168
## Time Series:
## Start = 25 
## End = 30 
## Frequency = 1 
##    Paperback Hardcover
## 25       190       214
## 26       182       200
## 27       222       201
## 28       217       283
## 29       188       220
## 30       247       259

b.

Use the ses() function to forecast each series, and plot the forecasts.

Below, R’s “ses” function is applied to the hardcover and paperback book sales time series separately. As per instructions, the time forecast is for the next 4 days.

## 
## Forecast method: Simple exponential smoothing
## 
## Model Information:
## Simple exponential smoothing 
## 
## Call:
##  ses(y = hardcover, h = 4) 
## 
##   Smoothing parameters:
##     alpha = 0.3283 
## 
##   Initial states:
##     l = 149.2861 
## 
##   sigma:  33.0517
## 
##      AIC     AICc      BIC 
## 315.8506 316.7737 320.0542 
## 
## Error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE       ACF1
## Training set 9.166735 31.93101 26.77319 2.636189 13.39487 0.7987887 -0.1417763
## 
## Forecasts:
##    Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 31       239.5601 197.2026 281.9176 174.7799 304.3403
## 32       239.5601 194.9788 284.1414 171.3788 307.7414
## 33       239.5601 192.8607 286.2595 168.1396 310.9806
## 34       239.5601 190.8347 288.2855 165.0410 314.0792
## 
## Forecast method: Simple exponential smoothing
## 
## Model Information:
## Simple exponential smoothing 
## 
## Call:
##  ses(y = paperback, h = 4) 
## 
##   Smoothing parameters:
##     alpha = 0.1685 
## 
##   Initial states:
##     l = 170.8271 
## 
##   sigma:  34.8183
## 
##      AIC     AICc      BIC 
## 318.9747 319.8978 323.1783 
## 
## Error measures:
##                    ME     RMSE     MAE       MPE     MAPE      MASE       ACF1
## Training set 7.175981 33.63769 27.8431 0.4736071 15.57784 0.7021303 -0.2117522
## 
## Forecasts:
##    Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 31       207.1097 162.4882 251.7311 138.8670 275.3523
## 32       207.1097 161.8589 252.3604 137.9046 276.3147
## 33       207.1097 161.2382 252.9811 136.9554 277.2639
## 34       207.1097 160.6259 253.5935 136.0188 278.2005

c.

Compute the RMSE values for the training data in each case.

My custom function below, calc_RMSE, calculates the RMSE of the forecast for the hardcover book sales in the variable HC_RMSE.

The manually calculated RMSE for hardcover book sales training data using simple exponential smoothing is: 31.93101

## [1] 31.93101

I confirmed that this is correct by taking the R generated RMSE. The same process is repeated for the paperback forecast.

The R RMSE for the hardcover training data is: 31.93101

## [1] 31.93101

The manually calculated RMSE for paperback book sales training data using simple exponential smoothing is: 33.63769

## [1] 33.63769

The R RMSE for the paperback training data is: 33.63769

## [1] 33.63769

7.8.6

a.

Apply Holt’s linear method to the paperback and hardback series and compute four-day forecasts in each case.

The R function “holt” applies Holt’s linear forecast for the next four days.

The output from the summary from the hardcover forecast shows a very small alpha and beta as the two smoothing parameters.

## 
## Forecast method: Holt's method
## 
## Model Information:
## Holt's method 
## 
## Call:
##  holt(y = hardcover, h = 4) 
## 
##   Smoothing parameters:
##     alpha = 1e-04 
##     beta  = 1e-04 
## 
##   Initial states:
##     l = 147.7935 
##     b = 3.303 
## 
##   sigma:  29.2106
## 
##      AIC     AICc      BIC 
## 310.2148 312.7148 317.2208 
## 
## Error measures:
##                      ME     RMSE      MAE       MPE    MAPE      MASE
## Training set -0.1357882 27.19358 23.15557 -2.114792 12.1626 0.6908555
##                     ACF1
## Training set -0.03245186
## 
## Forecasts:
##    Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 31       250.1739 212.7390 287.6087 192.9222 307.4256
## 32       253.4765 216.0416 290.9113 196.2248 310.7282
## 33       256.7791 219.3442 294.2140 199.5274 314.0308
## 34       260.0817 222.6468 297.5166 202.8300 317.3334

The output from the summary from the paperback forecast also shows a very small alpha and beta as the two smoothing parameters.

## 
## Forecast method: Holt's method
## 
## Model Information:
## Holt's method 
## 
## Call:
##  holt(y = paperback, h = 4) 
## 
##   Smoothing parameters:
##     alpha = 1e-04 
##     beta  = 1e-04 
## 
##   Initial states:
##     l = 170.699 
##     b = 1.2621 
## 
##   sigma:  33.4464
## 
##      AIC     AICc      BIC 
## 318.3396 320.8396 325.3456 
## 
## Error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set -3.717178 31.13692 26.18083 -5.508526 15.58354 0.6602122
##                    ACF1
## Training set -0.1750792
## 
## Forecasts:
##    Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 31       209.4668 166.6035 252.3301 143.9130 275.0205
## 32       210.7177 167.8544 253.5811 145.1640 276.2715
## 33       211.9687 169.1054 254.8320 146.4149 277.5225
## 34       213.2197 170.3564 256.0830 147.6659 278.7735

We can see clearly from the plots that the Holt method alone, with no other parameters set, captures the trend of the time series, but not much else. The forecast should not be relied upon since it does not capture seasonality in the series and that the upward trend continues on into infinity.

b.

Using the custom function, calc_RMSE, the RMSE of the simple exponential smoothing forecast are compared to the Holt linear forecast. We see that by adding the linear trend to the forecast, even though the Beta parameter is quite small, did improve the RSME of the forecast.

ses_hardcover_rmse Holt_linear_hardcover_rmse ses_paperback_rmse Holt_linear_paperback_rmse
31.93101 27.19358 33.63769 31.13692

d.

Calculate a 95% prediction interval for the first forecast for each series, using the RMSE values and assuming normal errors. Compare your intervals with those produced using ses and holt.

Using the generate 95% CI custom function and comparing it to the R generated confidence intervals, we see that the R intervals are wider for each series.

Within each series, the Holt confidence intervals are tighter.

lower 95 CI upper 95 CI
ses hardcover 178.5848 300.5354
Holt hardcover 195.9640 304.3838
ses paperback 141.5964 272.6230
Holt paperback 147.8390 271.0945
lower 95 CI upper 95 CI
ses hardcover 174.7799 304.3403
Holt hardcover 192.9222 307.4256
ses paperback 138.8670 275.3523
Holt paperback 143.9130 275.0205

7.8.7

For this exercise use data set eggs, the price of a dozen eggs in the United States from 1900-1993. Experiment with the various options in the holt() function to see how much the forecasts change with damped trend, or with a Box-Cox transformation. Try to develop an intuition of what each argument is doing to the forecasts.

[Hint: use h=100 when calling holt() so you can clearly see the differences between the various options when plotting the forecasts.]

Which model gives the best RMSE?

Price of eggs Description Price of dozen eggs in US, 1900-1993, in constant dollars.

Usage eggs Format Time series data

Source Makridakis, Wheelwright and Hyndman (1998) Forecasting: methods and applications, John Wiley & Sons: New York. Chapter 9.

Examples plot(eggs)

## Time Series:
## Start = 1900 
## End = 1905 
## Frequency = 1 
## [1] 276.79 315.42 314.87 321.25 314.54 317.92
## Time Series:
## Start = 1988 
## End = 1993 
## Frequency = 1 
## [1] 64.55 80.36 79.79 74.79 64.86 62.27

Below is the plot of the time series. We see a long term downward trend. We also see outlier spikes between ~1910 to 1920, and between ~1930 to 1940.

This plot show the Holt linear trend with no parameters. We see that the forecasted price goes to zero and below. Although Holt captures the trend, it’s not a reliable forecast since the trend turns negative.

Setting the damped parameter to TRUE improves on the forecast where it levels off before zero.

The Holt linear trend with the lambda set to BoXCox lambda captures the trend correctly, but the trend does not go to zero or below.

Setting the damped parameter to TRUE along with setting the lambda parameter to Box Cox for the Holt linear trend shows a trailing off of the trend well above zero.

The manually calculated RMSE values show that the Holt trend with damped parameter has the lowest RMSE. The R generated RMSE shows that the Holt linear trend with the BoX Cox parameter alone has the lowest RMSE.

Manually calculated RMSE comparisons:

eggs_linear eggs_damped_linear eggs_box_cox eggs_box_cox_damped
RMSE 31.93101 27.19358 33.63769 31.13692

R generated RMSE comparisons:

eggs_linear eggs_damped_linear eggs_box_cox eggs_box_cox_damped
RMSE 26.58219 26.62317 26.39376 26.53321

7.8.8

a.

Why is multiplicative seasonality necessary for this series?

We see from the plots below that multiplicative seasonality is necessary because variations are changing proportional to the level of the series.

c.

Compare the RMSE of the one-step forecasts from the two methods. Which do you prefer?

The manually generated RMSE values are far lower than the R generated values. In each instance the Holt Winters with the damped option have the lower RMSE although not by much. However, it is the better method.

The manually generated RMSE comparisons:

liquor_hw_one_step liquor_hw_damped_one_step
RMSE 0.0625853 0.0613796

The R generated RMSE comparisons:

liquor_hw_one_step liquor_hw_damped_one_step
RMSE 4.237051 4.147425

d.

Check that the residuals from the best method look like white noise.

The residuals from the best method, Holt Winters with the damped parameter set to TRUE, do not show that it is White noise based on the p value of the Ljung-Box test which is less than 0.05, as well as the ACF plot which shows correlations between the lags.

## 
##  Ljung-Box test
## 
## data:  Residuals from Damped Holt-Winters' multiplicative method
## Q* = 84.18, df = 7, p-value = 1.887e-15
## 
## Model df: 17.   Total lags used: 24

e.

Now find the test set RMSE, while training the model to the end of 2010. Can you beat the naive approach?

The naive approach shows that the RMSE is for the test set is 22.956217

##                     ME      RMSE       MAE      MPE      MAPE     MASE
## Training set  4.455255  8.699864  5.818619  6.15400  9.948117 1.000000
## Test set     19.170833 22.956217 19.520833 11.59039 11.813322 3.354891
##                   ACF1 Theil's U
## Training set 0.7261600        NA
## Test set     0.5801161 0.7479721

The Holt Winters approach shows that the RMSE is for the test set is 12.152124

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 0.3379808 3.814454 2.454955 0.5733706 4.504932 0.4219137 0.0076021 NA
Test set -4.8791198 12.152124 9.850873 -3.4254451 6.222885 1.6929918 0.6721037 0.4188652

The Holt Winters Damped approach shows that the RMSE is for the test set is 10.386188

I was able to greatly improve on the RMSE of the naive model (22.956217) with the Holt Winters Damped model (10.386188), cutting down the error rate by more than half from the naive method.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 0.4223714 3.717405 2.456063 0.3612467 4.543397 0.4221041 -0.0015053 NA
Test set 6.8376905 10.386188 7.953292 3.8069337 4.597764 1.3668694 0.4206074 0.3118086

7.8.9

For the same retail data, try an STL decomposition applied to the Box-Cox transformed series, followed by ETS on the seasonally adjusted data. How does that compare with your best previous forecasts on the test set?

I found that the RMSE for the forecast from the ETS, seasonally adjusted, Box Cox transformed data is (9.873769) which is lower than the RMSE from the Holt Winters Damped model (10.386188)

Below are the steps that I took to arrive at the answer:

Step One: Transform the liquor_sales_train using Box-Cox transformation. The best lambda is -0.07455321. The next two plots show the original training data and the Box Cox transformed data,

##       Apr  May  Jun  Jul  Aug  Sep
## 1982 17.3 18.1 18.1 18.9 19.0 18.4

## [1] -0.07455321

Step 2; Use STL decomposition on the Box Cox transformed data

Step 3: ETS on the seasonally adjusted data

First, as per Hyndman’s blog:

As with other methods of decomposition, it is easy enough to remove the seasonal component to get the seasonally adjusted data.

adjust_df <- df - components[,‘season’] autoplot(df, series=“Data”) + autolayer(adjust_df, series=“Seasonally adjusted”)

https://robjhyndman.com/hyndsight/tslm-decomposition/

## ETS(M,A,M) 
## 
## Call:
##  ets(y = train_box_cox_trans_stl_seasonal_adj) 
## 
##   Smoothing parameters:
##     alpha = 0.5171 
##     beta  = 0.0025 
##     gamma = 0.2477 
## 
##   Initial states:
##     l = 20.2743 
##     b = 0.1729 
##     s = 1.0222 0.9479 1.0174 1.3945 1.0661 0.9953
##            0.9255 0.9497 0.9247 0.8984 0.9257 0.9327
## 
##   sigma:  0.0611
## 
##      AIC     AICc      BIC 
## 2740.354 2742.226 2805.694 
## 
## Training set error measures:
##                     ME     RMSE      MAE          MPE     MAPE     MASE
## Training set 0.2937121 3.825107 2.453263 -0.009510912 4.412601 0.421623
##                    ACF1
## Training set 0.06158662
ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 0.2937121 3.825107 2.453263 -0.0095109 4.412601 0.421623 0.0615866 NA
Test set 2.1311634 9.873769 8.360848 0.8148709 4.979854 1.436913 0.5532785 0.3151752

LS0tDQp0aXRsZTogIkRBVEE2MjQgU3ByaW5nIDIwMjEgSFc1IC0gRXhwb25lbnRpYWwgU21vb3RoaW5nIg0KYXV0aG9yOiAiSm9obiBLLiBIYW5jb2NrIg0KZGF0ZTogIjMvMTQvMjAyMSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSgnZnBwMicpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KG1sYmVuY2gpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KCJjb21wYXJlIikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHNlYXNvbmFsKQ0KZGF0YShwaWdzKQ0KZGF0YSgiYm9va3MiKQ0KZGF0YShlZ2dzKQ0KDQoNCmBgYA0KDQoNCiMjIDcuOC4xDQpDb25zaWRlciB0aGUgcGlncyBzZXJpZXMgLS0gdGhlIG51bWJlciBvZiBwaWdzIHNsYXVnaHRlcmVkIGluIFZpY3RvcmlhIGVhY2ggbW9udGguDQoNCiMjIyBhLg0KPGk+VXNlIHRoZSBzZXMoKSBmdW5jdGlvbiBpbiBSIHRvIGZpbmQgdGhlIG9wdGltYWwgdmFsdWVzIG9mICRcYWxwaGEkIGFuZCAgJFxlbGxfMCQgYW5kIGdlbmVyYXRlIGZvcmVjYXN0cyBmb3IgdGhlIG5leHQgZm91ciBtb250aHMuPC9pPg0KDQpGaXJzdCwgd2UgYmVnaW4gYnkgaW5zcGVjdGluZyB0aGUgcGlncyB0aW1lIHNlcmllcyBieSBsb29raW5nIGF0IGl0cyBpbmZvcm1hdGlvbiwgaXRzIGhlYWQgYW5kIHRhaWwuIFdlIHNlZSB0aGF0IHRoZSB0aW1lIHNlcmllcyBpcyBjYXB0dXJlZCBvbiBhIG1vbnRobHkgc2NhbGUuIEFuIGF1dG9wbG90IG9mIHRoZSB0aW1lIHNlcmllcyBzaG93cyBubyBjb25zaXN0ZW50IGxvbmcgdGVybSB0cmVuZC4gDQoNCmBgYHtyfQ0KaGVscChwaWdzKQ0KYGBgDQpOdW1iZXIgb2YgcGlncyBzbGF1Z2h0ZXJlZA0KRGVzY3JpcHRpb24NCk1vbnRobHkgdG90YWwgbnVtYmVyIG9mIHBpZ3Mgc2xhdWdodGVyZWQgaW4gVmljdG9yaWEsIEF1c3RyYWxpYSAoSmFuIDE5ODAgdG8gQXVnIDE5OTUpLg0KDQpVc2FnZQ0KcGlncw0KRm9ybWF0DQpUaW1lIHNlcmllcyBkYXRhDQoNClNvdXJjZQ0KTWFrcmlkYWtpcywgV2hlZWx3cmlnaHQgYW5kIEh5bmRtYW4gKDE5OTgpIEZvcmVjYXN0aW5nOiBtZXRob2RzIGFuZCBhcHBsaWNhdGlvbnMsIEpvaG4gV2lsZXkgJiBTb25zOiBOZXcgWW9yay4gQ2hhcHRlciA3Lg0KDQpgYGB7cn0NCmhlYWQocGlncykNCmBgYA0KYGBge3J9DQp0YWlsKHBpZ3MpDQpgYGANCg0KDQpgYGB7cn0NCg0KYXV0b3Bsb3QocGlncykgKw0KICB5bGFiKCJNb250aGx5IE5vLiBvZiBQaWdzIHNsYXVnaHRlcmVkIGluIFZpY3RvcmlhLCBBVVMiKSArIHhsYWIoIkphbiAxOTgwIHRvICBBdWcgMTk5NSIpDQpgYGANCg0KTmV4dCwgUidzIHNpbXBsZSBleHBvbmVudGlhbCBzZXJpZXMsICJzZXMiLCBmdW5jdGlvbiBpcyBhcHBsaWVkIHRvIHRoZSBwaWdzIHRpbWUgc2VyaWVzIHRvIGZvcmVjYXN0IHRoZSBuZXh0IGZvdXIgbW9udGhzLiBUaGUgcmVzdWx0cyBhcmUgYWxzbyBwbG90dGVkIGJlbG93Lg0KDQpgYGB7cn0NCmZjIDwtIHNlcyhwaWdzLCBoPTQpDQpgYGANCg0KDQpgYGB7cn0NCmF1dG9wbG90KGZjKSArDQogIGF1dG9sYXllcihmaXR0ZWQoZmMpLCBzZXJpZXM9IkZpdHRlZCIpICsNCiAgIHlsYWIoIk1vbnRobHkgTm8uIG9mIFBpZ3Mgc2xhdWdodGVyZWQgaW4gVmljdG9yaWEsIEFVUyIpICsgeGxhYigiRGF0ZXMiKSArIGdndGl0bGUoIkZvcmVjYXN0IE5vLiBvZiBQaWdzIHNsYXVnaHRlcmVkIGluIFZpY3RvcmlhLCBBVVMiKQ0KYGBgDQpMb29raW5nIGl0cyBzdW1tYXJ5LCB3ZSBzZWUgdGhhdCB0aGUgb3B0aW1hbCBsZXZlbCBvZiBhbHBoYSBpcywgYWxwaGEgPSAwLjI5NzEgYW5kIHRoZSBsZXZlbCBpcywgbCA9IDc3MjYwLjA1NjEuDQoNCg0KYGBge3J9DQoNCnN1bW1hcnkoZmMpDQoNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiMgQWNjdXJhY3kgb2YgZm91ci1zdGVwcy1haGVhZCB0cmFpbmluZyBlcnJvcnMNCnJvdW5kKGFjY3VyYWN5KGZjKSwyKQ0KYGBgDQoNCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShyb3VuZChhY2N1cmFjeShmYyksMiksIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCg0KDQojIyMgYi4gDQoNCjxpPkNvbXB1dGUgYSA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbCBmb3IgdGhlIGZpcnN0IGZvcmVjYXN0IHVzaW5nIHdoZXJlIGlzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHJlc2lkdWFscy4gQ29tcGFyZSB5b3VyIGludGVydmFsIHdpdGggdGhlIGludGVydmFsIHByb2R1Y2VkIGJ5IFIuPC9pPg0KDQoNClRoZSBjdXN0b20gZnVuY3Rpb24gYmVsb3csICJjYWxjXzk1X0NJIiwgY2FsY3VsYXRlcyB0aGUgOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwuIA0KDQoNCmBgYHtyfQ0KY2FsY185NV9DSSA8LSBmdW5jdGlvbihmYyl7DQogIHN0ZF9kZXYgPC0gc2QocmVzaWR1YWxzKGZjKSkNCiAgZmlyc3RfZmMgPC0gZmMkbWVhblsxXQ0KICBsb3dlciA8LSBmaXJzdF9mYyAtIDEuOTYqc3RkX2Rldg0KICB1cHBlciA8LSBmaXJzdF9mYyArIDEuOTYqc3RkX2Rldg0KICBDb25maV85NSA8LSB0aWJibGUobG93ZXIsdXBwZXIpDQogIGNvbG5hbWVzKENvbmZpXzk1KSA8LSBjKCdsb3dlcicsICd1cHBlcicpDQogIHJldHVybiAoQ29uZmlfOTUpDQogIA0KfQ0KDQpgYGANCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmNhbGNfOTVfQ0koZmMpDQpgYGANCg0KVGhlIG1hbnVhbGx5IGNhbGN1bGF0ZWQgOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwgaXM6DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmthYmxlKGNhbGNfOTVfQ0koZmMpLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KVGhlIFIgZ2VuZXJhdGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXM6DQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KUl9Db25maV85NSA8LSB0aWJibGUoZmMkbG93ZXJbMSwyXSwgZmMkdXBwZXJbMSwyXSkNCmNvbG5hbWVzKFJfQ29uZmlfOTUpIDwtIGMoImxvd2VyIiwgInVwcGVyIikNClJfQ29uZmlfOTUNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShSX0NvbmZpXzk1LCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQoNCg0KDQpUaGUgUiBnZW5lcmF0ZWQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgc2VlbXMgdG8gYmUgd2lkZXIgdGhhbiB0aGUgbWFudWFsbHkgY2FsY3VsYXRlZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbC4gVGhlIGRpZmZlcmVuY2UgaXMgZ3JlYXRlciB0aGFuIGEgc2ltcGxlIHJvdW5kaW5nIGVycm9yLiANCg0KDQoNCg0KIyMgNy44LjUNCkRhdGEgc2V0IGJvb2tzIGNvbnRhaW5zIHRoZSBkYWlseSBzYWxlcyBvZiBwYXBlcmJhY2sgYW5kIGhhcmRjb3ZlciBib29rcyBhdCB0aGUgc2FtZSBzdG9yZS4gVGhlIHRhc2sgaXMgdG8gZm9yZWNhc3QgdGhlIG5leHQgZm91ciBkYXlzJyBzYWxlcyBmb3IgcGFwZXJiYWNrIGFuZCBoYXJkY292ZXIgYm9va3MuDQoNCiMjIyBhLg0KPGk+UGxvdCB0aGUgc2VyaWVzIGFuZCBkaXNjdXNzIHRoZSBtYWluIGZlYXR1cmVzIG9mIHRoZSBkYXRhLjwvaT4NCg0KRnJvbSB0aGUgaGVscCBmdW5jdGlvbiwgaGVhZCBhbmQgdGFpbCwgd2Ugc2VlIHRoYXQgdGhlIHRpbWUgc2VyaWVzIGlzIGEgZGFpbHkgdGltZSBzZXJpZXMgc3BsaXQgYmV0d2VlbiBQYXBlcmJhY2sgYW5kIEhhcmRjb3Zlci4gVGhlIGF1dG9wbG90IG9mIHRoZSBzZXJpZXMgc2hvd3MgYSBsb25nIHRlcm0gdXB3YXJkIHRyZW5kIGZvciBib3RoIFBhcGVyYmFjayBhbmQgSGFyZGNvdmVyIGJvb2sgc2FsZXMgYWxvbmcgd2l0aCBjeWNsaWNhbCBwYXR0ZXJucy4gDQoNCmBgYHtyfQ0KaGVscChib29rcykNCmBgYA0KU2FsZXMgb2YgcGFwZXJiYWNrIGFuZCBoYXJkY292ZXIgYm9va3MNCkRlc2NyaXB0aW9uDQpEYWlseSBzYWxlcyBvZiBwYXBlcmJhY2sgYW5kIGhhcmRjb3ZlciBib29rcyBhdCB0aGUgc2FtZSBzdG9yZS4NCg0KVXNhZ2UNCmJvb2tzDQpGb3JtYXQNCkJpdmFyaWF0ZSB0aW1lIHNlcmllcyBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgY29sdW1uczoNCg0KUGFwZXJiYWNrDQpOdW1iZXIgb2YgcGFwZXJiYWNrIHNhbGVzIGVhY2ggZGF5DQoNCkhhcmRjb3Zlcg0KTnVtYmVyIG9mIGhhcmRjb3ZlciBzYWxlcyBlYWNoIGRheQ0KDQpTb3VyY2UNCk1ha3JpZGFraXMsIFdoZWVsd3JpZ2h0IGFuZCBIeW5kbWFuICgxOTk4KSBGb3JlY2FzdGluZzogbWV0aG9kcyBhbmQgYXBwbGljYXRpb25zLCBKb2huIFdpbGV5ICYgU29uczogTmV3IFlvcmsuIEV4ZXJjaXNlIDQuNS4NCg0KYGBge3J9DQpoZWFkKGJvb2tzKQ0KYGBgDQoNCg0KYGBge3J9DQp0YWlsKGJvb2tzKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmF1dG9wbG90KGJvb2tzKSArDQogIHlsYWIoIkRhaWx5IHNhbGVzIG9mIHBhcGVyYmFjayBhbmQgaGFyZGNvdmVyIGJvb2tzIGF0IHRoZSBzYW1lIHN0b3JlIikgKyB4bGFiKCJEYWlseSBTYWxlcyIpDQpgYGANCg0KDQoNCiMjIyBiLg0KPGk+VXNlIHRoZSBzZXMoKSBmdW5jdGlvbiB0byBmb3JlY2FzdCBlYWNoIHNlcmllcywgYW5kIHBsb3QgdGhlIGZvcmVjYXN0cy48L2k+DQoNCkJlbG93LCBSJ3MgInNlcyIgZnVuY3Rpb24gaXMgYXBwbGllZCB0byB0aGUgaGFyZGNvdmVyIGFuZCBwYXBlcmJhY2sgYm9vayBzYWxlcyB0aW1lIHNlcmllcyBzZXBhcmF0ZWx5LiBBcyBwZXIgaW5zdHJ1Y3Rpb25zLCB0aGUgdGltZSBmb3JlY2FzdCBpcyBmb3IgdGhlIG5leHQgNCBkYXlzLiANCg0KYGBge3J9DQpoYXJkY292ZXIgPC0gYm9va3NbLDJdDQpwYXBlcmJhY2sgPC0gYm9va3NbLDFdDQpoYXJkY292ZXJfZmMgPC0gc2VzKGhhcmRjb3ZlciwgaD00KQ0KcGFwZXJiYWNrX2ZjIDwtIHNlcyhwYXBlcmJhY2ssIGg9NCkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoaGFyZGNvdmVyX2ZjKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShwYXBlcmJhY2tfZmMpDQpgYGANCg0KDQpgYGB7cn0NCmF1dG9wbG90KGhhcmRjb3Zlcl9mYykgKw0KICBhdXRvbGF5ZXIoZml0dGVkKGhhcmRjb3Zlcl9mYyksIHNlcmllcz0iRml0dGVkIikgKw0KICB5bGFiKCJEYWlseSIpICsgeGxhYigiU2FsZXMiKSArIGdndGl0bGUoIkhhcmRjb3ZlciBTYWxlcyBQcm9qZWN0aW9uIG92ZXIgNCBkYXlzIikNCmBgYA0KDQoNCg0KYGBge3J9DQphdXRvcGxvdChwYXBlcmJhY2tfZmMpICsNCiAgYXV0b2xheWVyKGZpdHRlZChwYXBlcmJhY2tfZmMpLCBzZXJpZXM9IkZpdHRlZCIpICsNCiAgeWxhYigiRGFpbHkiKSArIHhsYWIoIlNhbGVzIikgKyBnZ3RpdGxlKCJQYXBlcmJhY2sgU2FsZXMgUHJvamVjdGlvbiBvdmVyIDQgZGF5cyIpDQpgYGANCg0KIyMjIGMuDQo8aT5Db21wdXRlIHRoZSBSTVNFIHZhbHVlcyBmb3IgdGhlIHRyYWluaW5nIGRhdGEgaW4gZWFjaCBjYXNlLjwvaT4NCg0KTXkgY3VzdG9tIGZ1bmN0aW9uIGJlbG93LCBjYWxjX1JNU0UsIGNhbGN1bGF0ZXMgdGhlIFJNU0Ugb2YgdGhlIGZvcmVjYXN0IGZvciB0aGUgaGFyZGNvdmVyIGJvb2sgc2FsZXMgaW4gdGhlIHZhcmlhYmxlIEhDX1JNU0UuIA0KDQpgYGB7cn0NCmNhbGNfUk1TRSA8LSBmdW5jdGlvbihmYyl7DQogIE1TRSA8LSBtZWFuKGZjJHJlc2lkdWFsc14yLCBuYS5ybT1UUlVFKQ0KICByZXR1cm4gKHNxcnQoTVNFKSkNCiAgDQp9DQpgYGANCg0KVGhlIG1hbnVhbGx5IGNhbGN1bGF0ZWQgUk1TRSBmb3IgaGFyZGNvdmVyIGJvb2sgc2FsZXMgdHJhaW5pbmcgZGF0YSB1c2luZyBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nIGlzOiAzMS45MzEwMQ0KYGBge3J9DQpIQ19STVNFIDwtICBjYWxjX1JNU0UoaGFyZGNvdmVyX2ZjKQ0KSENfUk1TRQ0KYGBgDQpJIGNvbmZpcm1lZCB0aGF0IHRoaXMgaXMgY29ycmVjdCBieSB0YWtpbmcgdGhlIFIgZ2VuZXJhdGVkIFJNU0UuIFRoZSBzYW1lIHByb2Nlc3MgaXMgcmVwZWF0ZWQgZm9yIHRoZSBwYXBlcmJhY2sgZm9yZWNhc3QuDQoNClRoZSBSIFJNU0UgZm9yIHRoZSBoYXJkY292ZXIgdHJhaW5pbmcgZGF0YSBpczogMzEuOTMxMDENCmBgYHtyfQ0KYWNjdXJhY3koaGFyZGNvdmVyX2ZjKVsxLDJdDQpgYGANClRoZSBtYW51YWxseSBjYWxjdWxhdGVkIFJNU0UgZm9yIHBhcGVyYmFjayBib29rIHNhbGVzIHRyYWluaW5nIGRhdGEgdXNpbmcgc2ltcGxlIGV4cG9uZW50aWFsIHNtb290aGluZyBpczogMzMuNjM3NjkNCmBgYHtyfQ0KUGFwZXJiYWNrX1JNU0UgPC0gY2FsY19STVNFKHBhcGVyYmFja19mYykNClBhcGVyYmFja19STVNFIA0KYGBgDQoNCg0KVGhlIFIgUk1TRSBmb3IgdGhlIHBhcGVyYmFjayB0cmFpbmluZyBkYXRhIGlzOiAzMy42Mzc2OQ0KYGBge3J9DQphY2N1cmFjeShwYXBlcmJhY2tfZmMpWzEsMl0NCmBgYA0KDQoNCg0KIyMgNy44LjYNCg0KIyMjIGEuDQo8aT5BcHBseSBIb2x0J3MgbGluZWFyIG1ldGhvZCB0byB0aGUgcGFwZXJiYWNrIGFuZCBoYXJkYmFjayBzZXJpZXMgYW5kIGNvbXB1dGUgZm91ci1kYXkgZm9yZWNhc3RzIGluIGVhY2ggY2FzZS48L2k+DQoNClRoZSBSIGZ1bmN0aW9uICJob2x0IiBhcHBsaWVzIEhvbHQncyBsaW5lYXIgZm9yZWNhc3QgZm9yIHRoZSBuZXh0IGZvdXIgZGF5cy4gIA0KDQpgYGB7cn0NCmhhcmRjb3Zlcl9ob2x0X2ZjIDwtIGhvbHQoaGFyZGNvdmVyLCBoPTQpDQpwYXBlcmJhY2tfaG9sdF9mYyA8LSBob2x0KHBhcGVyYmFjaywgaD00KQ0KYGBgDQoNClRoZSBvdXRwdXQgZnJvbSB0aGUgc3VtbWFyeSBmcm9tIHRoZSBoYXJkY292ZXIgZm9yZWNhc3Qgc2hvd3MgYSB2ZXJ5IHNtYWxsIGFscGhhIGFuZCBiZXRhIGFzIHRoZSB0d28gc21vb3RoaW5nIHBhcmFtZXRlcnMuIA0KDQpgYGB7cn0NCnN1bW1hcnkoaGFyZGNvdmVyX2hvbHRfZmMpDQpgYGANCg0KVGhlIG91dHB1dCBmcm9tIHRoZSBzdW1tYXJ5IGZyb20gdGhlIHBhcGVyYmFjayBmb3JlY2FzdCBhbHNvIHNob3dzIGEgdmVyeSBzbWFsbCBhbHBoYSBhbmQgYmV0YSBhcyB0aGUgdHdvIHNtb290aGluZyBwYXJhbWV0ZXJzLiANCmBgYHtyfQ0Kc3VtbWFyeShwYXBlcmJhY2tfaG9sdF9mYykNCmBgYA0KDQpXZSBjYW4gc2VlIGNsZWFybHkgZnJvbSB0aGUgcGxvdHMgdGhhdCB0aGUgSG9sdCBtZXRob2QgYWxvbmUsIHdpdGggbm8gb3RoZXIgcGFyYW1ldGVycyBzZXQsIGNhcHR1cmVzIHRoZSB0cmVuZCBvZiB0aGUgdGltZSBzZXJpZXMsIGJ1dCBub3QgbXVjaCBlbHNlLiBUaGUgZm9yZWNhc3Qgc2hvdWxkIG5vdCBiZSByZWxpZWQgdXBvbiBzaW5jZSBpdCBkb2VzIG5vdCBjYXB0dXJlIHNlYXNvbmFsaXR5IGluIHRoZSBzZXJpZXMgYW5kIHRoYXQgdGhlIHVwd2FyZCB0cmVuZCBjb250aW51ZXMgb24gaW50byBpbmZpbml0eS4gDQoNCg0KYGBge3J9DQphdXRvcGxvdChoYXJkY292ZXJfZmMpICsNCiAgYXV0b2xheWVyKGZpdHRlZChoYXJkY292ZXJfaG9sdF9mYyksIHNlcmllcz0iRml0dGVkIikgKw0KICB5bGFiKCJEYWlseSIpICsgeGxhYigiU2FsZXMiKSArIGdndGl0bGUoIkhvbHQgTGluZWFyIEhhcmRjb3ZlciBTYWxlcyBQcm9qZWN0aW9uIG92ZXIgNCBkYXlzIikNCmBgYA0KDQoNCg0KYGBge3J9DQphdXRvcGxvdChwYXBlcmJhY2tfZmMpICsNCiAgYXV0b2xheWVyKGZpdHRlZChwYXBlcmJhY2tfaG9sdF9mYyksIHNlcmllcz0iRml0dGVkIikgKw0KICB5bGFiKCJEYWlseSIpICsgeGxhYigiU2FsZXMiKSArIGdndGl0bGUoIkhvbHQgTGluZWFyIFBhcGVyYmFjayBTYWxlcyBQcm9qZWN0aW9uIG92ZXIgNCBkYXlzIikNCmBgYA0KDQoNCiMjIyBiLg0KDQo8aT5Vc2luZyB0aGUgY3VzdG9tIGZ1bmN0aW9uLCBjYWxjX1JNU0UsIHRoZSBSTVNFIG9mIHRoZSBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nIGZvcmVjYXN0IGFyZSBjb21wYXJlZCB0byB0aGUgSG9sdCBsaW5lYXIgZm9yZWNhc3QuIFdlIHNlZSB0aGF0IGJ5IGFkZGluZyB0aGUgbGluZWFyIHRyZW5kIHRvIHRoZSBmb3JlY2FzdCwgZXZlbiB0aG91Z2ggdGhlIEJldGEgcGFyYW1ldGVyIGlzIHF1aXRlIHNtYWxsLCBkaWQgaW1wcm92ZSB0aGUgUlNNRSBvZiB0aGUgZm9yZWNhc3QuPC9pPg0KDQoNCmBgYHtyfQ0KaGFyZGNvdmVyX2hvbHRfUk1TRSA8LSBjYWxjX1JNU0UoaGFyZGNvdmVyX2hvbHRfZmMpDQpwYXBlcmJhY2tfaG9sdF9STVNFIDwtIGNhbGNfUk1TRShwYXBlcmJhY2tfaG9sdF9mYykNCg0KYGBgDQoNCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnJtc2VfY29tcGFyaXNvbnMgPC0gY2JpbmQoSENfUk1TRSwgaGFyZGNvdmVyX2hvbHRfUk1TRSwgUGFwZXJiYWNrX1JNU0UsIHBhcGVyYmFja19ob2x0X1JNU0UpDQpjb2xuYW1lcyhybXNlX2NvbXBhcmlzb25zKSA8LSBjKCdzZXNfaGFyZGNvdmVyX3Jtc2UnLCAnSG9sdF9saW5lYXJfaGFyZGNvdmVyX3Jtc2UnLCAnc2VzX3BhcGVyYmFja19ybXNlJywgJ0hvbHRfbGluZWFyX3BhcGVyYmFja19ybXNlJykNCnJtc2VfY29tcGFyaXNvbnMgDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6a2FibGUocm1zZV9jb21wYXJpc29ucywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNCg0KDQoNCg0KIyMjIGMuDQoNCjxpPlRoZSBwbG90cyBiZWxvdyBjb21wYXJlIHRoZSB0d28gc2V0cyBvZiBmb3JlY2FzdHMsIHRoZSBTRVMgYW5kIEhvbHQgTGluZWFyLiAgTmVpdGhlciBmb3JlY2FzdHMgZml0IHdlbGwgdG8gdGhlIHNlcmllcywgYnV0IGVhY2ggZG9lcyBjYXB0dXJlIHRoZSB0cmVuZC4gIFRoZSBIb2x0IGxpbmVhciBmb3JlY2FzdCBzbW9vdGhzIG91dCB0aGUgZmx1Y3R1YXRpb25zIGFuZCBzaG93cyBvbmx5IHRoZSB0cmVuZC4gQXMgYSByZXN1bHQgdGhlIDQgZGF5IGZvcmVjYXN0cyBmb3IgdGhlIEhvbHQgbGluZWFyIHRyZW5kIGlzIGhpZ2hlciB0aGFuIHRoZSBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nIHByb2plY3Rpb24uPC9pPg0KDQoNCmBgYHtyfQ0KDQpzZXNfaGFyZGNvdmVyIDwtIGF1dG9wbG90KGhhcmRjb3Zlcl9mYykgKw0KICBhdXRvbGF5ZXIoZml0dGVkKGhhcmRjb3Zlcl9mYyksIHNlcmllcz0iRml0dGVkIikgKw0KICB5bGFiKCJEYWlseSIpICsgeGxhYigiU2FsZXMiKSArIGdndGl0bGUoIkhhcmRjb3ZlciBTYWxlcyBQcm9qZWN0aW9uIG92ZXIgNCBkYXlzIikNCg0KaG9sdF9saW5lYXJfaGFyZGNvdmVyIDwtIGF1dG9wbG90KGhhcmRjb3Zlcl9mYykgKw0KICBhdXRvbGF5ZXIoZml0dGVkKGhhcmRjb3Zlcl9ob2x0X2ZjKSwgc2VyaWVzPSJGaXR0ZWQiKSArDQogIHlsYWIoIkRhaWx5IikgKyB4bGFiKCJTYWxlcyIpICsgZ2d0aXRsZSgiSG9sdCBMaW5lYXIgSGFyZGNvdmVyIFNhbGVzIFByb2plY3Rpb24gb3ZlciA0IGRheXMiKQ0KDQpzZXNfcGFwZXJiYWNrIDwtIGF1dG9wbG90KHBhcGVyYmFja19mYykgKw0KICBhdXRvbGF5ZXIoZml0dGVkKHBhcGVyYmFja19mYyksIHNlcmllcz0iRml0dGVkIikgKw0KICB5bGFiKCJEYWlseSIpICsgeGxhYigiU2FsZXMiKSArIGdndGl0bGUoIlBhcGVyYmFjayBTYWxlcyBQcm9qZWN0aW9uIG92ZXIgNCBkYXlzIikNCg0KaG9sdF9saW5lYXJfcGFwZXJiYWNrIDwtIGF1dG9wbG90KHBhcGVyYmFja19mYykgKw0KICBhdXRvbGF5ZXIoZml0dGVkKHBhcGVyYmFja19ob2x0X2ZjKSwgc2VyaWVzPSJGaXR0ZWQiKSArDQogIHlsYWIoIkRhaWx5IikgKyB4bGFiKCJTYWxlcyIpICsgZ2d0aXRsZSgiSG9sdCBMaW5lYXIgUGFwZXJiYWNrIFNhbGVzIFByb2plY3Rpb24gb3ZlciA0IGRheXMiKQ0KDQpncmlkLmFycmFuZ2Uoc2VzX2hhcmRjb3ZlciwgaG9sdF9saW5lYXJfaGFyZGNvdmVyLCBzZXNfcGFwZXJiYWNrLCBob2x0X2xpbmVhcl9wYXBlcmJhY2ssIG5jb2w9MikNCmBgYA0KDQoNCiMjIyBkLg0KDQo8aT5DYWxjdWxhdGUgYSA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbCBmb3IgdGhlIGZpcnN0IGZvcmVjYXN0IGZvciBlYWNoIHNlcmllcywgdXNpbmcgdGhlIFJNU0UgdmFsdWVzIGFuZCBhc3N1bWluZyBub3JtYWwgZXJyb3JzLiBDb21wYXJlIHlvdXIgaW50ZXJ2YWxzIHdpdGggdGhvc2UgcHJvZHVjZWQgdXNpbmcgc2VzIGFuZCBob2x0LjwvaT4NCg0KVXNpbmcgdGhlIGdlbmVyYXRlIDk1JSBDSSBjdXN0b20gZnVuY3Rpb24gYW5kIGNvbXBhcmluZyBpdCB0byB0aGUgUiBnZW5lcmF0ZWQgY29uZmlkZW5jZSBpbnRlcnZhbHMsIHdlIHNlZSB0aGF0IHRoZSBSIGludGVydmFscyBhcmUgd2lkZXIgZm9yIGVhY2ggc2VyaWVzLiAgDQoNCldpdGhpbiBlYWNoIHNlcmllcywgdGhlIEhvbHQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIHRpZ2h0ZXIuIA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmRmIDwtIGRhdGEuZnJhbWUoRG91Ymxlcz1kb3VibGUoKSxEb3VibGVzPWRvdWJsZSgpKQ0KZGYgPC0gcmJpbmQoY2FsY185NV9DSShoYXJkY292ZXJfZmMpKQ0KZGYgPC0gcmJpbmQoZGYsIGNhbGNfOTVfQ0koaGFyZGNvdmVyX2hvbHRfZmMpKQ0KZGYgPC0gcmJpbmQoZGYsIGNhbGNfOTVfQ0kocGFwZXJiYWNrX2ZjKSkNCmRmIDwtIHJiaW5kKGRmLCBjYWxjXzk1X0NJKHBhcGVyYmFja19ob2x0X2ZjKSkNCmNvbG5hbWVzKGRmKSA8LSBjKCJsb3dlciA5NSBDSSIsICJ1cHBlciA5NSBDSSIpDQpyb3duYW1lcyhkZikgPC0gYygic2VzIGhhcmRjb3ZlciIsICJIb2x0IGhhcmRjb3ZlciIsICJzZXMgcGFwZXJiYWNrIiwgIkhvbHQgcGFwZXJiYWNrIikNCmRmDQpgYGANCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShkZiwibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNCg0KDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KDQpyX2RmIDwtIGRhdGEuZnJhbWUoRG91Ymxlcz1kb3VibGUoKSxEb3VibGVzPWRvdWJsZSgpKQ0Kcl9kZiA8LSByYmluZChjKGhhcmRjb3Zlcl9mYyRsb3dlclsxLDJdLCBoYXJkY292ZXJfZmMkdXBwZXJbMSwyXSkpDQpyX2RmIDwtIHJiaW5kKHJfZGYsIGMoaGFyZGNvdmVyX2hvbHRfZmMkbG93ZXJbMSwyXSwgaGFyZGNvdmVyX2hvbHRfZmMkdXBwZXJbMSwyXSkpDQpyX2RmIDwtIHJiaW5kKHJfZGYsIGMocGFwZXJiYWNrX2ZjJGxvd2VyWzEsMl0sIHBhcGVyYmFja19mYyR1cHBlclsxLDJdKSkNCnJfZGYgPC0gcmJpbmQocl9kZiwgYyhwYXBlcmJhY2tfaG9sdF9mYyRsb3dlclsxLDJdLCBwYXBlcmJhY2tfaG9sdF9mYyR1cHBlclsxLDJdKSkNCmNvbG5hbWVzKHJfZGYpIDwtIGMoImxvd2VyIDk1IENJIiwgInVwcGVyIDk1IENJIikNCnJvd25hbWVzKHJfZGYpIDwtIGMoInNlcyBoYXJkY292ZXIiLCAiSG9sdCBoYXJkY292ZXIiLCAic2VzIHBhcGVyYmFjayIsICJIb2x0IHBhcGVyYmFjayIpDQpyX2RmDQpgYGANCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShyX2RmLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCiMjIDcuOC43DQoNCjxpPkZvciB0aGlzIGV4ZXJjaXNlIHVzZSBkYXRhIHNldCBlZ2dzLCB0aGUgcHJpY2Ugb2YgYSBkb3plbiBlZ2dzIGluIHRoZSBVbml0ZWQgU3RhdGVzIGZyb20gMTkwMC0xOTkzLiBFeHBlcmltZW50IHdpdGggdGhlIHZhcmlvdXMgb3B0aW9ucyBpbiB0aGUgaG9sdCgpIGZ1bmN0aW9uIHRvIHNlZSBob3cgbXVjaCB0aGUgZm9yZWNhc3RzIGNoYW5nZSB3aXRoIGRhbXBlZCB0cmVuZCwgb3Igd2l0aCBhIEJveC1Db3ggdHJhbnNmb3JtYXRpb24uIFRyeSB0byBkZXZlbG9wIGFuIGludHVpdGlvbiBvZiB3aGF0IGVhY2ggYXJndW1lbnQgaXMgZG9pbmcgdG8gdGhlIGZvcmVjYXN0cy4NCg0KW0hpbnQ6IHVzZSBoPTEwMCB3aGVuIGNhbGxpbmcgaG9sdCgpIHNvIHlvdSBjYW4gY2xlYXJseSBzZWUgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHZhcmlvdXMgb3B0aW9ucyB3aGVuIHBsb3R0aW5nIHRoZSBmb3JlY2FzdHMuXTwvaT4NCg0KV2hpY2ggbW9kZWwgZ2l2ZXMgdGhlIGJlc3QgUk1TRT8NCg0KYGBge3J9DQpoZWxwKGVnZ3MpDQpgYGANCg0KUHJpY2Ugb2YgZWdncw0KRGVzY3JpcHRpb24NClByaWNlIG9mIGRvemVuIGVnZ3MgaW4gVVMsIDE5MDAtMTk5MywgaW4gY29uc3RhbnQgZG9sbGFycy4NCg0KVXNhZ2UNCmVnZ3MNCkZvcm1hdA0KVGltZSBzZXJpZXMgZGF0YQ0KDQpTb3VyY2UNCk1ha3JpZGFraXMsIFdoZWVsd3JpZ2h0IGFuZCBIeW5kbWFuICgxOTk4KSBGb3JlY2FzdGluZzogbWV0aG9kcyBhbmQgYXBwbGljYXRpb25zLCBKb2huIFdpbGV5ICYgU29uczogTmV3IFlvcmsuIENoYXB0ZXIgOS4NCg0KRXhhbXBsZXMNCnBsb3QoZWdncykNCg0KYGBge3J9DQpoZWFkKGVnZ3MpDQpgYGANCmBgYHtyfQ0KdGFpbChlZ2dzKQ0KYGBgDQpCZWxvdyBpcyB0aGUgcGxvdCBvZiB0aGUgdGltZSBzZXJpZXMuICBXZSBzZWUgYSBsb25nIHRlcm0gZG93bndhcmQgdHJlbmQuIFdlIGFsc28gc2VlIG91dGxpZXIgc3Bpa2VzIGJldHdlZW4gfjE5MTAgdG8gMTkyMCwgYW5kIGJldHdlZW4gfjE5MzAgdG8gMTk0MC4NCg0KYGBge3J9DQphdXRvcGxvdChlZ2dzKSArDQogIHlsYWIoIlByaWNlIikgKyB4bGFiKCIxOTkwIHRvIDE5OTMiKSArIGdndGl0bGUoIlByaWNlIG9mIGRvemVuIGVnZ3MgaW4gVVMsIDE5MDAtMTk5MywgaW4gY29uc3RhbnQgZG9sbGFycyIpDQpgYGANCg0KVGhpcyBwbG90IHNob3cgdGhlIEhvbHQgbGluZWFyIHRyZW5kIHdpdGggbm8gcGFyYW1ldGVycy4gV2Ugc2VlIHRoYXQgdGhlIGZvcmVjYXN0ZWQgcHJpY2UgZ29lcyB0byB6ZXJvIGFuZCBiZWxvdy4gIEFsdGhvdWdoIEhvbHQgY2FwdHVyZXMgdGhlIHRyZW5kLCBpdCdzIG5vdCBhIHJlbGlhYmxlIGZvcmVjYXN0IHNpbmNlIHRoZSB0cmVuZCB0dXJucyBuZWdhdGl2ZS4gDQoNCmBgYHtyfQ0KZWdnc19saW5lYXIgPC0gaG9sdChlZ2dzLCBoPTEwMCkNCmF1dG9wbG90KGVnZ3NfbGluZWFyKSArIA0KICBhdXRvbGF5ZXIoZml0dGVkKGVnZ3NfbGluZWFyKSkgKw0KICB5bGFiKCJQcmljZSIpICsgeGxhYigiMTk5MCB0byAxOTkzIikgKyBnZ3RpdGxlKCJIb2x0IExpbmVhciBUcmVuZCB3aXRoIG5vIFBhcmFtZXRlcnMiKQ0KDQpgYGANClNldHRpbmcgdGhlIGRhbXBlZCBwYXJhbWV0ZXIgdG8gVFJVRSBpbXByb3ZlcyBvbiB0aGUgZm9yZWNhc3Qgd2hlcmUgaXQgbGV2ZWxzIG9mZiBiZWZvcmUgemVyby4gDQoNCmBgYHtyfQ0KZWdnc19kYW1wZWRfbGluZWFyIDwtIGhvbHQoZWdncywgZGFtcGVkPVRSVUUsIHBoaSA9IDAuOSwgaD0xMDApDQphdXRvcGxvdChlZ2dzX2RhbXBlZF9saW5lYXIpICsgDQogIGF1dG9sYXllcihlZ2dzX2RhbXBlZF9saW5lYXIkZml0dGVkKSArDQogIHlsYWIoIlByaWNlIikgKyB4bGFiKCIxOTkwIHRvIDE5OTMiKSArIGdndGl0bGUoIkhvbHQgRGFtcGVkIikNCg0KYGBgDQoNClRoZSBIb2x0IGxpbmVhciB0cmVuZCB3aXRoIHRoZSBsYW1iZGEgc2V0IHRvIEJvWENveCBsYW1iZGEgY2FwdHVyZXMgdGhlIHRyZW5kIGNvcnJlY3RseSwgYnV0IHRoZSB0cmVuZCBkb2VzIG5vdCBnbyB0byB6ZXJvIG9yIGJlbG93LiANCg0KDQpgYGB7cn0NCmVnZ3NfYm94X2NveCA8LSBob2x0KGVnZ3MsIGxhbWJkYSA9IEJveENveC5sYW1iZGEoZWdncyksIGg9MTAwKQ0KYXV0b3Bsb3QoZWdnc19ib3hfY294KSArIA0KICBhdXRvbGF5ZXIoZml0dGVkKGVnZ3NfYm94X2NveCkpICsNCiAgeWxhYigiUHJpY2UiKSArIHhsYWIoIjE5OTAgdG8gMTk5MyIpICsgZ2d0aXRsZSgiSG9sdCBCb3ggQ294IikNCg0KYGBgDQoNClNldHRpbmcgdGhlIGRhbXBlZCBwYXJhbWV0ZXIgdG8gVFJVRSBhbG9uZyB3aXRoIHNldHRpbmcgdGhlIGxhbWJkYSBwYXJhbWV0ZXIgdG8gQm94IENveCBmb3IgdGhlIEhvbHQgbGluZWFyIHRyZW5kIHNob3dzIGEgdHJhaWxpbmcgb2ZmIG9mIHRoZSB0cmVuZCB3ZWxsIGFib3ZlIHplcm8uDQoNCmBgYHtyfQ0KZWdnc19ib3hfY294X2RhbXBlZCA8LSBob2x0KGVnZ3MsIGRhbXBlZD1UUlVFLCBsYW1iZGEgPSBCb3hDb3gubGFtYmRhKGVnZ3MpLCAgaD0xMDApDQphdXRvcGxvdChlZ2dzX2JveF9jb3hfZGFtcGVkKSArIA0KICBhdXRvbGF5ZXIoZml0dGVkKGVnZ3NfYm94X2NveF9kYW1wZWQpKSArDQogIHlsYWIoIlByaWNlIikgKyB4bGFiKCIxOTkwIHRvIDE5OTMiKSArIGdndGl0bGUoIkhvbHQgQm94IENveCBEYW1wZWQiKQ0KDQpgYGANCg0KVGhlIG1hbnVhbGx5IGNhbGN1bGF0ZWQgUk1TRSB2YWx1ZXMgc2hvdyB0aGF0IHRoZSBIb2x0IHRyZW5kIHdpdGggZGFtcGVkIHBhcmFtZXRlciBoYXMgdGhlIGxvd2VzdCBSTVNFLiBUaGUgUiBnZW5lcmF0ZWQgUk1TRSBzaG93cyB0aGF0IHRoZSBIb2x0IGxpbmVhciB0cmVuZCB3aXRoIHRoZSBCb1ggQ294IHBhcmFtZXRlciBhbG9uZSBoYXMgdGhlIGxvd2VzdCBSTVNFLg0KDQoNCk1hbnVhbGx5IGNhbGN1bGF0ZWQgUk1TRSBjb21wYXJpc29uczoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQplZ2dzX2xpbmVhcl9STVNFIDwtIGNhbGNfUk1TRShlZ2dzX2xpbmVhcikNCmVnZ3NfZGFtcGVkX2xpbmVhcl9STVNFIDwtIGNhbGNfUk1TRShlZ2dzX2RhbXBlZF9saW5lYXIpDQplZ2dzX2JveF9jb3hfUk1TRSA8LSBjYWxjX1JNU0UoZWdnc19ib3hfY294KQ0KZWdnc19ib3hfY294X2RhbXBlZF9STVNFIDwtIGNhbGNfUk1TRShlZ2dzX2JveF9jb3hfZGFtcGVkKQ0KDQpybXNlX2NhbGNfY29tcGFyaXNvbnMgPC0gY2JpbmQoZWdnc19saW5lYXJfUk1TRSwgZWdnc19kYW1wZWRfbGluZWFyX1JNU0UsIGVnZ3NfYm94X2NveF9STVNFLCBlZ2dzX2JveF9jb3hfZGFtcGVkX1JNU0UgKQ0KY29sbmFtZXMocm1zZV9jb21wYXJpc29ucykgPC0gYygnZWdnc19saW5lYXInLCAnZWdnc19kYW1wZWRfbGluZWFyJywgJ2VnZ3NfYm94X2NveCcsICdlZ2dzX2JveF9jb3hfZGFtcGVkJykNCnJvd25hbWVzKHJtc2VfY29tcGFyaXNvbnMpIDwtIGMoJ1JNU0UnKQ0Kcm1zZV9jb21wYXJpc29ucw0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6a2FibGUocm1zZV9jb21wYXJpc29ucywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNCg0KDQoNCg0KUiBnZW5lcmF0ZWQgUk1TRSBjb21wYXJpc29uczoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpybXNlX2NvbXBhcmlzb25zIDwtIGNiaW5kKGFjY3VyYWN5KGVnZ3NfbGluZWFyKVsxLDJdLCBhY2N1cmFjeShlZ2dzX2RhbXBlZF9saW5lYXIpWzEsMl0sIGFjY3VyYWN5KGVnZ3NfYm94X2NveClbMSwyXSwgYWNjdXJhY3koZWdnc19ib3hfY294X2RhbXBlZClbMSwyXSkNCmNvbG5hbWVzKHJtc2VfY29tcGFyaXNvbnMpIDwtIGMoJ2VnZ3NfbGluZWFyJywgJ2VnZ3NfZGFtcGVkX2xpbmVhcicsICdlZ2dzX2JveF9jb3gnLCAnZWdnc19ib3hfY294X2RhbXBlZCcpDQpyb3duYW1lcyhybXNlX2NvbXBhcmlzb25zKSA8LSBjKCdSTVNFJykNCnJtc2VfY29tcGFyaXNvbnMNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmthYmxlKHJtc2VfY29tcGFyaXNvbnMsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQojIyA3LjguOCANCg0KDQpgYGB7cn0NCnJldGFpbGRhdGEgPC0gcmVhZF9leGNlbCgicmV0YWlsLnhsc3giLCBza2lwPTEpDQpsaXF1b3Jfc2FsZXMgPC0gdHMocmV0YWlsZGF0YVssIkEzMzQ5NDE0UiJdLA0KICBmcmVxdWVuY3k9MTIsIHN0YXJ0PWMoMTk4Miw0KSkNCmBgYA0KDQojIyMgYS4NCjxpPldoeSBpcyBtdWx0aXBsaWNhdGl2ZSBzZWFzb25hbGl0eSBuZWNlc3NhcnkgZm9yIHRoaXMgc2VyaWVzPzwvaT4NCg0KV2Ugc2VlIGZyb20gdGhlIHBsb3RzIGJlbG93IHRoYXQgbXVsdGlwbGljYXRpdmUgc2Vhc29uYWxpdHkgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgdmFyaWF0aW9ucyBhcmUgY2hhbmdpbmcgcHJvcG9ydGlvbmFsIHRvIHRoZSBsZXZlbCBvZiB0aGUgc2VyaWVzLiANCg0KYGBge3J9DQpsaXF1b3Jfc2FsZXMgICU+JSBzZWFzKHgxMT0iIikgLT4gZml0DQphdXRvcGxvdChmaXQpICsNCiAgZ2d0aXRsZSgiWDExIGRlY29tcG9zaXRpb24gb2YgQXVzdHJhbGlhbiBMaXF1b3IgU2FsZXMiKQ0KYGBgDQoNCg0KIyMjIGIuDQo8aT5BcHBseSBIb2x0LVdpbnRlcnMnIG11bHRpcGxpY2F0aXZlIG1ldGhvZCB0byB0aGUgZGF0YS4gRXhwZXJpbWVudCB3aXRoIG1ha2luZyB0aGUgdHJlbmQgZGFtcGVkLjwvaT4NCg0KVGhlIEhvbHQtV2ludGVycyBtb2RlbCBhZGQgc2Vhc29uYWxpdHkgdG8gdGhlIEhvbHQgbGluZWFyIG1vZGVsLiBEb2luZyB0aGlzIGNhcHR1cmVzIHRoZSBvdmVyYWxsIHRyZW5kIHBlcmZlY3RseSBmb3IgdGhpcyB0aW1lIHNlcmllcy4gRGFtcGluZyB0aGUgdHJlbmQgZG9lcyBub3QgYWRkIGFueXRoaW5nLg0KDQpgYGB7cn0NCmxpcXVvcl9odyA8LSBodyhsaXF1b3Jfc2FsZXMsc2Vhc29uYWw9Im11bHRpcGxpY2F0aXZlIikNCmF1dG9wbG90KGxpcXVvcl9zYWxlcykgKw0KICBhdXRvbGF5ZXIobGlxdW9yX2h3LCBzZXJpZXM9IkhXIG11bHRpcGxpY2F0aXZlIGZvcmVjYXN0cyIsDQogICAgUEk9RkFMU0UpICsNCiAgeGxhYigiWWVhciIpICsNCiAgeWxhYigiU2FsZXMgKG1pbGxpb25zKSIpICsNCiAgZ2d0aXRsZSgiSG9sdCBXaW50ZXJzIE11bHRpcGxpY2F0aXZlIEZvcmVjYXN0IGluIEF1c3RyYWxpYSIpICsNCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQodGl0bGU9IkZvcmVjYXN0IikpDQpgYGANCg0KYGBge3J9DQpsaXF1b3JfaHdfZGFtcGVkIDwtIGh3KGxpcXVvcl9zYWxlcyxzZWFzb25hbD0ibXVsdGlwbGljYXRpdmUiKQ0KYXV0b3Bsb3QobGlxdW9yX3NhbGVzKSArDQogIGF1dG9sYXllcihsaXF1b3JfaHdfZGFtcGVkLCBzZXJpZXM9IkhXIG11bHRpcGxpY2F0aXZlIGRhbXBlZCBmb3JlY2FzdHMiLA0KICAgIFBJPUZBTFNFKSArDQogIHhsYWIoIlllYXIiKSArDQogIHlsYWIoIlNhbGVzIChtaWxsaW9ucykiKSArDQogIGdndGl0bGUoIkhvbHQgV2ludGVycyBNdWx0aXBsaWNhdGl2ZSBEYW1wZWQgRm9yZWNhc3QgaW4gQXVzdHJhbGlhIikgKw0KICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZCh0aXRsZT0iRm9yZWNhc3QiKSkNCmBgYA0KDQoNCiMjIyBjLg0KPGk+Q29tcGFyZSB0aGUgUk1TRSBvZiB0aGUgb25lLXN0ZXAgZm9yZWNhc3RzIGZyb20gdGhlIHR3byBtZXRob2RzLiBXaGljaCBkbyB5b3UgcHJlZmVyPzwvaT4NCg0KVGhlIG1hbnVhbGx5IGdlbmVyYXRlZCBSTVNFIHZhbHVlcyBhcmUgZmFyIGxvd2VyIHRoYW4gdGhlIFIgZ2VuZXJhdGVkIHZhbHVlcy4gSW4gZWFjaCBpbnN0YW5jZSB0aGUgSG9sdCBXaW50ZXJzIHdpdGggdGhlIGRhbXBlZCBvcHRpb24gaGF2ZSB0aGUgbG93ZXIgUk1TRSBhbHRob3VnaCBub3QgYnkgbXVjaC4gSG93ZXZlciwgaXQgaXMgdGhlIGJldHRlciBtZXRob2QuIA0KDQpgYGB7cn0NCmxpcXVvcl9od19vbmVfc3RlcCA8LSBodyhsaXF1b3Jfc2FsZXMsc2Vhc29uYWw9Im11bHRpcGxpY2F0aXZlIiwgaD0xKQ0KbGlxdW9yX2h3X2RhbXBlZF9vbmVfc3RlcCA8LSBodyhsaXF1b3Jfc2FsZXMsc2Vhc29uYWw9Im11bHRpcGxpY2F0aXZlIixkYW1wZWQgPSBUUlVFLCAgaD0xKQ0KDQoNCmBgYA0KDQoNClRoZSBtYW51YWxseSBnZW5lcmF0ZWQgUk1TRSBjb21wYXJpc29uczoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpsaXF1b3JfaHdfb25lX3N0ZXBfUk1TRSA8LSBjYWxjX1JNU0UobGlxdW9yX2h3X29uZV9zdGVwKQ0KbGlxdW9yX2h3X2RhbXBlZF9vbmVfc3RlcF9STVNFIDwtIGNhbGNfUk1TRShsaXF1b3JfaHdfZGFtcGVkX29uZV9zdGVwKQ0KDQptYW51YWxfcm1zZV9jb21wYXJpc29ucyA8LSBjYmluZChsaXF1b3JfaHdfb25lX3N0ZXBfUk1TRSwgbGlxdW9yX2h3X2RhbXBlZF9vbmVfc3RlcF9STVNFICkNCmNvbG5hbWVzKG1hbnVhbF9ybXNlX2NvbXBhcmlzb25zKSA8LSBjKCdsaXF1b3JfaHdfb25lX3N0ZXAnLCAnbGlxdW9yX2h3X2RhbXBlZF9vbmVfc3RlcCcpDQpyb3duYW1lcyhtYW51YWxfcm1zZV9jb21wYXJpc29ucykgPC0gYygnUk1TRScpDQptYW51YWxfcm1zZV9jb21wYXJpc29ucw0KDQpgYGANCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShtYW51YWxfcm1zZV9jb21wYXJpc29ucywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNClRoZSBSIGdlbmVyYXRlZCBSTVNFIGNvbXBhcmlzb25zOg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnJtc2VfY29tcGFyaXNvbnMgPC0gY2JpbmQoYWNjdXJhY3kobGlxdW9yX2h3X29uZV9zdGVwKVsxLDJdLCBhY2N1cmFjeShsaXF1b3JfaHdfZGFtcGVkX29uZV9zdGVwKVsxLDJdKQ0KY29sbmFtZXMocm1zZV9jb21wYXJpc29ucykgPC0gYygnbGlxdW9yX2h3X29uZV9zdGVwJywgJ2xpcXVvcl9od19kYW1wZWRfb25lX3N0ZXAnKQ0Kcm93bmFtZXMocm1zZV9jb21wYXJpc29ucykgPC0gYygnUk1TRScpDQpybXNlX2NvbXBhcmlzb25zDQpgYGANCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShybXNlX2NvbXBhcmlzb25zLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQojIyMgZC4NCjxpPkNoZWNrIHRoYXQgdGhlIHJlc2lkdWFscyBmcm9tIHRoZSBiZXN0IG1ldGhvZCBsb29rIGxpa2Ugd2hpdGUgbm9pc2UuPC9pPg0KDQpUaGUgcmVzaWR1YWxzIGZyb20gdGhlIGJlc3QgbWV0aG9kLCBIb2x0IFdpbnRlcnMgd2l0aCB0aGUgZGFtcGVkIHBhcmFtZXRlciBzZXQgdG8gVFJVRSwgZG8gbm90IHNob3cgdGhhdCBpdCBpcyBXaGl0ZSBub2lzZSBiYXNlZCBvbiB0aGUgcCB2YWx1ZSBvZiB0aGUgIExqdW5nLUJveCB0ZXN0IHdoaWNoIGlzIGxlc3MgdGhhbiAwLjA1LCBhcyB3ZWxsIGFzIHRoZSBBQ0YgcGxvdCB3aGljaCBzaG93cyBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgbGFncy4gDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMobGlxdW9yX2h3X2RhbXBlZF9vbmVfc3RlcCkNCmBgYA0KIyMjIGUuIA0KPGk+Tm93IGZpbmQgdGhlIHRlc3Qgc2V0IFJNU0UsIHdoaWxlIHRyYWluaW5nIHRoZSBtb2RlbCB0byB0aGUgZW5kIG9mIDIwMTAuIENhbiB5b3UgYmVhdCB0aGUgbmFpdmUgYXBwcm9hY2g/PC9pPg0KDQoNCg0KYGBge3J9DQpsaXF1b3Jfc2FsZXNfdHJhaW4gPC0gd2luZG93KGxpcXVvcl9zYWxlcywgZW5kPWMoMjAxMCwxMikpDQpsaXF1b3Jfc2FsZXNfdGVzdCA8LSB3aW5kb3cobGlxdW9yX3NhbGVzLCBzdGFydD0yMDExKQ0KYXV0b3Bsb3QobGlxdW9yX3NhbGVzKSArDQogIGF1dG9sYXllcihsaXF1b3Jfc2FsZXNfdHJhaW4sIHNlcmllcz0iVHJhaW5pbmciKSArDQogIGF1dG9sYXllcihsaXF1b3Jfc2FsZXNfdGVzdCwgc2VyaWVzPSJUZXN0IikNCg0KYGBgDQoNClRoZSBuYWl2ZSBhcHByb2FjaCBzaG93cyB0aGF0IHRoZSBSTVNFIGlzIGZvciB0aGUgdGVzdCBzZXQgaXMgMjIuOTU2MjE3DQoNCmBgYHtyfQ0KZmNfbGlxdW9yX3NhbGVzX25haXZlIDwtIHNuYWl2ZShsaXF1b3Jfc2FsZXNfdHJhaW4pDQphdXRvcGxvdChmY19saXF1b3Jfc2FsZXNfbmFpdmUpDQpgYGANCg0KYGBge3J9DQphY2N1cmFjeShmY19saXF1b3Jfc2FsZXNfbmFpdmUsbGlxdW9yX3NhbGVzX3Rlc3QpDQpgYGANCg0KDQpUaGUgSG9sdCBXaW50ZXJzIGFwcHJvYWNoIHNob3dzIHRoYXQgdGhlIFJNU0UgaXMgZm9yIHRoZSB0ZXN0IHNldCBpcyAxMi4xNTIxMjQNCg0KYGBge3J9DQpsaXF1b3Jfc2FsZXNfdHJhaW5fSFdfTXVsdGkgPC0gaHcobGlxdW9yX3NhbGVzX3RyYWluLCBoID0gMzYsIHNlYXNvbmFsID0gIm11bHRpcGxpY2F0aXZlIikNCg0KYXV0b3Bsb3QobGlxdW9yX3NhbGVzX3RyYWluX0hXX011bHRpICkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmFjY3VyYWN5KGxpcXVvcl9zYWxlc190cmFpbl9IV19NdWx0aSwgbGlxdW9yX3NhbGVzX3Rlc3QpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6a2FibGUoYWNjdXJhY3kobGlxdW9yX3NhbGVzX3RyYWluX0hXX011bHRpLCBsaXF1b3Jfc2FsZXNfdGVzdCksIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQpUaGUgSG9sdCBXaW50ZXJzIERhbXBlZCBhcHByb2FjaCBzaG93cyB0aGF0IHRoZSBSTVNFIGlzIGZvciB0aGUgdGVzdCBzZXQgaXMgMTAuMzg2MTg4DQoNCmBgYHtyfQ0KbGlxdW9yX3NhbGVzX3RyYWluX0hXX011bHRpX2RhbXBlZCA8LSBodyhsaXF1b3Jfc2FsZXNfdHJhaW4sIGggPSAzNiwgc2Vhc29uYWwgPSAibXVsdGlwbGljYXRpdmUiLCBkYW1wZWQgPSBUUlVFKQ0KDQphdXRvcGxvdChsaXF1b3Jfc2FsZXNfdHJhaW5fSFdfTXVsdGlfZGFtcGVkICkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmFjY3VyYWN5KGxpcXVvcl9zYWxlc190cmFpbl9IV19NdWx0aV9kYW1wZWQsIGxpcXVvcl9zYWxlc190ZXN0KQ0KYGBgDQpJIHdhcyBhYmxlIHRvIGdyZWF0bHkgaW1wcm92ZSBvbiB0aGUgUk1TRSBvZiB0aGUgbmFpdmUgbW9kZWwgKDIyLjk1NjIxNykgd2l0aCB0aGUgSG9sdCBXaW50ZXJzIERhbXBlZCBtb2RlbCAoMTAuMzg2MTg4KSwgY3V0dGluZyBkb3duIHRoZSBlcnJvciByYXRlIGJ5IG1vcmUgdGhhbiBoYWxmIGZyb20gdGhlIG5haXZlIG1ldGhvZC4gDQoNCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmtuaXRyOjprYWJsZShhY2N1cmFjeShsaXF1b3Jfc2FsZXNfdHJhaW5fSFdfTXVsdGlfZGFtcGVkLCBsaXF1b3Jfc2FsZXNfdGVzdCksIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCg0KIyMgNy44LjkNCg0KPGk+Rm9yIHRoZSBzYW1lIHJldGFpbCBkYXRhLCB0cnkgYW4gU1RMIGRlY29tcG9zaXRpb24gYXBwbGllZCB0byB0aGUgQm94LUNveCB0cmFuc2Zvcm1lZCBzZXJpZXMsIGZvbGxvd2VkIGJ5IEVUUyBvbiB0aGUgc2Vhc29uYWxseSBhZGp1c3RlZCBkYXRhLiBIb3cgZG9lcyB0aGF0IGNvbXBhcmUgd2l0aCB5b3VyIGJlc3QgcHJldmlvdXMgZm9yZWNhc3RzIG9uIHRoZSB0ZXN0IHNldD88L2k+DQoNCg0KSSBmb3VuZCB0aGF0IHRoZSBSTVNFIGZvciB0aGUgZm9yZWNhc3QgZnJvbSB0aGUgRVRTLCBzZWFzb25hbGx5IGFkanVzdGVkLCBCb3ggQ294IHRyYW5zZm9ybWVkIGRhdGEgaXMgKDkuODczNzY5KSB3aGljaCBpcyBsb3dlciB0aGFuIHRoZSBSTVNFIGZyb20gdGhlICBIb2x0IFdpbnRlcnMgRGFtcGVkIG1vZGVsICgxMC4zODYxODgpDQoNCg0KQmVsb3cgYXJlIHRoZSBzdGVwcyB0aGF0IEkgdG9vayB0byBhcnJpdmUgYXQgdGhlIGFuc3dlcjoNCg0KU3RlcCBPbmU6IFRyYW5zZm9ybSB0aGUgbGlxdW9yX3NhbGVzX3RyYWluIHVzaW5nIEJveC1Db3ggdHJhbnNmb3JtYXRpb24uICBUaGUgYmVzdCBsYW1iZGEgaXMgLTAuMDc0NTUzMjEuIFRoZSBuZXh0IHR3byBwbG90cyBzaG93IHRoZSBvcmlnaW5hbCB0cmFpbmluZyBkYXRhIGFuZCB0aGUgQm94IENveCB0cmFuc2Zvcm1lZCBkYXRhLCANCg0KDQpgYGB7cn0NCmhlYWQobGlxdW9yX3NhbGVzX3RyYWluKQ0KYGBgDQoNCmBgYHtyfQ0KYXV0b3Bsb3QobGlxdW9yX3NhbGVzX3RyYWluKQ0KYGBgDQoNCmBgYHtyfQ0KbGFtYmRhIDwtIEJveENveC5sYW1iZGEobGlxdW9yX3NhbGVzX3RyYWluKQ0KbGFtYmRhDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQp0cmFpbl9ib3hfY294X3RyYW5zZm9ybWVkIDwtIEJveENveChsaXF1b3Jfc2FsZXNfdHJhaW4sIGxhbWJkYSkNCnRyYWluX2JveF9jb3hfdHJhbnNmb3JtZWQgJT4lICBhdXRvcGxvdCgpDQpgYGANCg0KDQpTdGVwIDI7IFVzZSBTVEwgZGVjb21wb3NpdGlvbiBvbiB0aGUgQm94IENveCB0cmFuc2Zvcm1lZCBkYXRhDQoNCmBgYHtyfQ0KdHJhaW5fYm94X2NveF90cmFuc2Zvcm1lZDIgPC0gdHMoDQogIHRyYWluX2JveF9jb3hfdHJhbnNmb3JtZWQsIA0KICBzdGFydCA9IGMoMTk4MiwxKSwgDQogIGVuZCA9IGMoMjAxMCwxMiksIA0KICBmcmVxdWVuY3kgPSAxMikNCmBgYA0KDQoNCmBgYHtyfQ0KICB0cmFpbl9ib3hfY294X3RyYW5fc3RsIDwtIHN0bCh0cmFpbl9ib3hfY294X3RyYW5zZm9ybWVkMix0LndpbmRvdz0xMiwgcy53aW5kb3c9J3BlcmlvZGljJywgcm9idXN0ID0gVFJVRSkNCiAgdHJhaW5fYm94X2NveF90cmFuX3N0bCAlPiUgIGF1dG9wbG90KCkNCmBgYA0KU3RlcCAzOiBFVFMgb24gdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgZGF0YQ0KDQpGaXJzdCwgYXMgcGVyIEh5bmRtYW4ncyBibG9nOg0KDQoNCjxpPkFzIHdpdGggb3RoZXIgbWV0aG9kcyBvZiBkZWNvbXBvc2l0aW9uLCBpdCBpcyBlYXN5IGVub3VnaCB0byByZW1vdmUgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCB0byBnZXQgdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgZGF0YS4NCg0KYWRqdXN0X2RmIDwtIGRmIC0gY29tcG9uZW50c1ssJ3NlYXNvbiddDQphdXRvcGxvdChkZiwgc2VyaWVzPSJEYXRhIikgKw0KICBhdXRvbGF5ZXIoYWRqdXN0X2RmLCBzZXJpZXM9IlNlYXNvbmFsbHkgYWRqdXN0ZWQiKQ0KDQo8L2k+DQoNCmh0dHBzOi8vcm9iamh5bmRtYW4uY29tL2h5bmRzaWdodC90c2xtLWRlY29tcG9zaXRpb24vDQoNCg0KYGBge3J9DQp0cmFpbl9ib3hfY294X3RyYW5zX3N0bF9zZWFzb25hbF9hZGogPC0gbGlxdW9yX3NhbGVzX3RyYWluIC0gIHRyYWluX2JveF9jb3hfdHJhbl9zdGwkdGltZS5zZXJpZXNbLCAnc2Vhc29uYWwnXQ0KdHJhaW5fYm94X2NveF90cmFuc19zdGxfc2Vhc29uYWxfYWRqX2V0cyA8LSBldHModHJhaW5fYm94X2NveF90cmFuc19zdGxfc2Vhc29uYWxfYWRqKQ0Kc3VtbWFyeSh0cmFpbl9ib3hfY294X3RyYW5zX3N0bF9zZWFzb25hbF9hZGpfZXRzKQ0KDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQphY2N1cmFjeSh0cmFpbl9ib3hfY294X3RyYW5zX3N0bF9zZWFzb25hbF9hZGpfZXRzICU+JSBmb3JlY2FzdChoPTM2KSwgbGlxdW9yX3NhbGVzX3Rlc3QpDQpgYGANCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Ka25pdHI6OmthYmxlKGFjY3VyYWN5KHRyYWluX2JveF9jb3hfdHJhbnNfc3RsX3NlYXNvbmFsX2Fkal9ldHMgJT4lIGZvcmVjYXN0KGg9MzYpLCBsaXF1b3Jfc2FsZXNfdGVzdCksIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCg0KDQoNCmBgYHtyfQ0KdHJhaW5fYm94X2NveF90cmFuc19zdGxfc2Vhc29uYWxfYWRqX2V0cyAlPiUgZm9yZWNhc3QoaD0zNikgJT4lIGF1dG9wbG90KCkNCmBgYA0KDQoNCg0K