Introduction

The solo project consists of two parts. Part A tasks us with forecasting the amount of cash withdrawn from 4 ATM machines. Part B is forecasting residential power usage. The data provided for this project is in two excel files. The major outline of my approach is to examine the data, clean and prepare the data for analysis, and compare a range of forecasting models to the data. The model that performs the best based on RMSE will be the one chosen to forecast the next time period.


Part A
I. DATA PREPARATION
  1. Import and discuss the state of the data
  2. Exploratory Data Analysis and Cleaning
  3. Identify Missing Data
  4. Split the Main Dataset into 4 for each ATM
  5. Address the Missing Data for each ATM
  6. Identify and Address Outliers
  7. Convert the Data into a Time Series
  8. Review time series plots


II. EXPERIMENTATION AND RESULTS
  1. Split the Time Series
  2. Apply Diiferent Models
  3. Compare and discuss the results from each model
  4. Select the best model and forecast the next month per ATM


III. Summary of Findings and Forecast for May 2010

Part B
I. DATA PREPARATION
  1. Import and discuss the state of the data
  2. Exploratory Data Analysis and Cleaning
  3. Identify Missing Data
  4. Address the Missing Data for each ATM
  5. Identify and Address Outliers
  6. Convert the Data into a Time Series
  7. Review time series plots


II. EXPERIMENTATION AND RESULTS
  1. Split the Time Series
  2. Apply the Naive, Simple Exponential Smoothing, Holt Winters, and ARIMA models to each time series
  3. Compare and discuss the results from each model
  4. Select the best model and forecast the next month per ATM


III. Summary of Findings and Monthly Forecast for 2014


Part A

I. DATA PREPARATION

Import and discuss the state of the data

Key Assumption

We are given no details about the ATM data. We don’t know if they’re from the same bank or in the same building or in the same city. Thus, I made the assumption that these are 4 distinct, unrelated ATMs. They are managed by an independent, non-bank, solo entrepeneur. These are the kinds of ATMs that one would find in a convenience store or at a gas station. This entrepeneur services these ATMs by keeping them stocked with cash. Revenue comes from the user fees for each withdrawal. So, if the ATMs are out of cash, the entrepeneur loses money because no withdrawals can be made. If they have too much cash, the money sits idle and the company loses money as well. So, the entrepeneur needs accurate withdrawal forecasts to maximize profits.

Exploratory Data Analysis and Cleaning

I begin by taking a glimpse at the raw data. There are 1,474 observations and three variables. We see that the Date variable is in integer format, not date. Data for each of the 4 ATMs are mingled in one dataset. There are 14 missing values in the ATM variables and 19 missing values in the Cash variable. I handle Missing Data in the next section.

## Observations: 1,474
## Variables: 3
## $ DATE <dbl> 39934, 39934, 39935, 39935, 39936, 39936, 39937, 39937, 39938,...
## $ ATM  <chr> "ATM1", "ATM2", "ATM1", "ATM2", "ATM1", "ATM2", "ATM1", "ATM2"...
## $ Cash <dbl> 96, 107, 82, 89, 85, 90, 90, 55, 99, 79, 88, 19, 8, 2, 104, 10...
DATE ATM Cash
39934 ATM1 96
39934 ATM2 107
39935 ATM1 82
39935 ATM2 89
39936 ATM1 85
39936 ATM2 90

Using the excel_numeric_to_date function from the janitor library package, the dates were converted to the ‘YYYY-MM-DD’ format.

DATE ATM Cash
2009-05-01 ATM1 96
2009-05-01 ATM2 107
2009-05-02 ATM1 82
2009-05-02 ATM2 89
2009-05-03 ATM1 85

Identify Missing Data

Looking at the summary of the data shows that there are 19 observations with missing data. Further inspection shows that there are 14 observations without any ATM or Cash information, and five observations with only the ATM information. Since we have no details on how this data was collected and as such, there is no logical answer as to why 14 values are missing. For example, these missing values are on consecutive days so attributing the missingness to holidays or some other explanation like an equipment replacement.

Key Assumption

My next key assumption is regarding handling missing data.Both the amounts and the dates are missing. I am going to assume that the 14 missing values are Missing Completely at Random (MCAR) which means that the missing data has no relationship to the other data. I cannot use data from any of the other ATMs because as I stated earlier, they’re all independent. I also cannot assume that it came from one particular ATM given the uniqueness of each.

The link below goes into details about MCAR.

https://www.theanalysisfactor.com/mar-and-mcar-missing-data/

The first step in cleaning up this data will be to remove these 14 rows with no information.

##       DATE                ATM                 Cash        
##  Min.   :2009-05-01   Length:1474        Min.   :    0.0  
##  1st Qu.:2009-08-01   Class :character   1st Qu.:    0.5  
##  Median :2009-11-01   Mode  :character   Median :   73.0  
##  Mean   :2009-10-31                      Mean   :  155.6  
##  3rd Qu.:2010-02-01                      3rd Qu.:  114.0  
##  Max.   :2010-05-14                      Max.   :10919.8  
##                                          NA's   :19
DATE ATM Cash
2009-06-13 ATM1 NA
2009-06-16 ATM1 NA
2009-06-18 ATM2 NA
2009-06-22 ATM1 NA
2009-06-24 ATM2 NA
2010-05-01 NA NA

The 14 rows with Missing Data

DATE ATM Cash
2010-05-01 NA NA
2010-05-02 NA NA
2010-05-03 NA NA
2010-05-04 NA NA
2010-05-05 NA NA
2010-05-06 NA NA
2010-05-07 NA NA
2010-05-08 NA NA
2010-05-09 NA NA
2010-05-10 NA NA
2010-05-11 NA NA
2010-05-12 NA NA
2010-05-13 NA NA
2010-05-14 NA NA

I created a new data frame, ATM624Data_Raw1, with the 14 removed.

Address the Missing Data for each ATM

ATM1

A summary of ATM1 shows that there are three NA values.

##       DATE                ATM                 Cash       
##  Min.   :2009-05-01   Length:365         Min.   :  1.00  
##  1st Qu.:2009-07-31   Class :character   1st Qu.: 73.00  
##  Median :2009-10-30   Mode  :character   Median : 91.00  
##  Mean   :2009-10-30                      Mean   : 83.89  
##  3rd Qu.:2010-01-29                      3rd Qu.:108.00  
##  Max.   :2010-04-30                      Max.   :180.00  
##                                          NA's   :3

When I isolated three of the missing cash values for ATM1, I saw that it’s all within the month of June 2009.

DATE ATM Cash
2009-06-13 ATM1 NA
2009-06-16 ATM1 NA
2009-06-22 ATM1 NA

k-Nearest Neighbour Imputation

I used a kNN imputation strategy to fill in for the missing Cash values for ATM1. I also used the default value of k=5.

“One popular technique for imputation is a K-nearest neighbor model. A new sample is imputed by finding the samples in the training set”closest" to it and averages these nearby points to fill in the value."

Kuhn, Max and Johnson, Kjell, Applied Predictive Modeling, pg. 42

DATE ATM Cash Cash_imp
44 2009-06-13 ATM1 90 TRUE
47 2009-06-16 ATM1 90 TRUE
53 2009-06-22 ATM1 90 TRUE

ATM2

For ATM2, there are 2 NA values, and I used the same imputation strategy

DATE ATM Cash Cash_imp
49 2009-06-18 ATM2 89 TRUE
55 2009-06-24 ATM2 89 TRUE

Identify and Address Outliers for each ATM

The box and whisker plots below show that ATM1 and ATM4 have outliers while ATM3 contains no data at all except for three entries.

The Tukey Method

Invented by mathematician, John Tukey. “Tukey Fences uses the interquartile range (”IQR“) to flag observations (financial transactions in this case) that are considered outliers. Tukey Fences defines an outlier based on the below formula: Outlier = Transaction > Q3 + 1.5 x IQR OR Transaction < Q1-1.5 x IQR”

https://medium.com/mario-burstein/implementing-tukey-outlier-detection-in-m-a-due-diligence-374efa9c387

In this section, I created two functions that can identify outliers. The function, Identify_Outlier, uses the Tukey method, where outliers are identified by being below Q1-1.5IQR and above Q3+1.5IQR. The second function, tag_outlier, returns a binary list of values, “Acceptable” or “Outlier” that will be added to the dataframe.

ATM1

After applying the functions and tagging the outliers, we see that there are 51 outliers in ATM1. Most of the outliers are below the first quartile. To handle the outliers, I will Winsorize the data. Outliers outside of 1.5 * the IQR will be replaced with either the lower or upper boundary.

“Winsorizing or winsorization is the transformation of statistics by limiting extreme values in the statistical data to reduce the effect of possibly spurious outliers. It is named after the engineer-turned-biostatistician Charles P. Winsor (1895-1951). The effect is the same as clipping in signal processing.”

https://en.wikipedia.org/wiki/Winsorizing

DATE ATM Cash Cash_imp Cash_Outlier
7 2009-05-07 ATM1 8 FALSE Outlier
14 2009-05-14 ATM1 6 FALSE Outlier
21 2009-05-21 ATM1 20 FALSE Outlier
28 2009-05-28 ATM1 10 FALSE Outlier
35 2009-06-04 ATM1 14 FALSE Outlier
36 2009-06-05 ATM1 3 FALSE Outlier

The box plot shows that the outliers in ATM1 have been replaced and ATM1 is cleaned:

##         DATE  ATM Cash Cash_imp Cash_Outlier
## 1 2009-05-01 ATM1   96    FALSE   Acceptable
## 2 2009-05-02 ATM1   82    FALSE   Acceptable
## 3 2009-05-03 ATM1   85    FALSE   Acceptable
## 4 2009-05-04 ATM1   90    FALSE   Acceptable
## 5 2009-05-05 ATM1   99    FALSE   Acceptable
## 6 2009-05-06 ATM1   88    FALSE   Acceptable

ATM2

We see that the two functions did not identify any outliers in ATM2. The box and whiskers plot confirms this, and even though the histogram for ATM2 is not perfectly normally distributed, the skew is small enough.

## [1] DATE         ATM          Cash         Cash_imp     Cash_Outlier
## <0 rows> (or 0-length row.names)

## [1] -0.04273822

ATN2 has been cleaned:

ATM3

Key Assumption

99% of the values for ATM3 are zeroes even though there are date entries for the ATM. I am making the assumption that ATM3 was malfunctioning or blocked in some way until April 2010. Thus, I cannot remove the Outliers nor can I make any reasonable forecast. If I take an average of the last three days ($87.66) ATM3 would not have been able to fulfill the 04/28/2010 withdrawal. I am going to need more data to make any assumption for this machine. Thus, I am going to use a default value of 100.

## [1] 0.9917808
DATE ATM Cash Cash_Outlier
2010-04-26 ATM3 0 Acceptable
2010-04-27 ATM3 0 Acceptable
2010-04-28 ATM3 96 Outlier
2010-04-29 ATM3 82 Outlier
2010-04-30 ATM3 85 Outlier

## [1] 10.92911

ATM4

I see that there are two very large outliers for ATM4 which skews the data to the right. I used the same Winsor approach for handling outliers as I did with ATM1.

## Warning: `...` is not empty.
## 
## We detected these problematic arguments:
## * `needs_dots`
## 
## These dots only exist to allow future extensions and should be empty.
## Did you misspecify an argument?
## # A tibble: 3 x 4
##   DATE       ATM     Cash Cash_Outlier
##   <date>     <chr>  <dbl> <chr>       
## 1 2010-01-29 ATM4   1575. Outlier     
## 2 2009-09-22 ATM4   1712. Outlier     
## 3 2010-02-09 ATM4  10920. Outlier

## Warning: `...` is not empty.
## 
## We detected these problematic arguments:
## * `needs_dots`
## 
## These dots only exist to allow future extensions and should be empty.
## Did you misspecify an argument?
## # A tibble: 3 x 4
##   DATE       ATM    Cash Cash_Outlier
##   <date>     <chr> <dbl> <chr>       
## 1 2009-09-22 ATM4  1575. Outlier     
## 2 2010-01-29 ATM4  1575. Outlier     
## 3 2010-02-09 ATM4  1575. Outlier

Review time series plots

ATM1_ts

The autoplot below shows that the ATM1 cash withdrawal data shows an uptick in the first 10 weeks, then a small drop from weeks 20 to 30, and finally a leveling off from weeks 38 to 53.

## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

The seasonal, polar, subseries plots of ATM1 below show that for most of the days of the week withdrawals have the same or nearly the same activity except for Saturdays when there’s a huge drop off. This may mean that the scheduling for re-filling ATM1 needs to be looked at.

The Seasonal and Trend decomposition using Loess (STL) shows that there is not a discernable trend over the length of the time series with the exceptions at the low points at the 25th and 43rd weeks. We also see in the seasonal plots less of a variation between the 22nd and the 44th weeks.

These plots show that the data is not stationary. Also, there are strong positive correlations with lags at days 7, 14, and 21.

ATM2_ts

The autoplot for ATM2 show a slight downward trend over the span of the time series along with a descrease in the seasonal variation.

## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

The seasonal plot of ATM2 show that withdrawls change over time. In the later weeks, Wednesdays and Thursdays have see less withdrawals while Fridays and Saturdays have seen peaks. This is a reversal of the pattern seen in earlier weeks.

The polar and subseries plots show a big drop off in Fridays and Saturday withdrawals.

The seasonal plot for ATM2 does not show an increase or decrease in the trend over time.

These plots show that the data is not stationary. Also, there are strong positive correlations with lags at days 7, 14, and 21.

The lag plots show the strong correlation at lags 7, 14, and 21.

ATM4_ts

The autoplot for ATM4 show a very slight downward beginning at the 20th week. The trend then evens out after week 35.

## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

The seasonal, polar, and subseries plots show the most activity on Sundays and Thurdays with a huge drop off on Saturdays.

The is no discernable trend for ATM4 although the seasonal variation around lag 40 seems to tighten.

These plots show that the data is not stationary. Also, there are strong positive correlations with lags at days 7 and 14.

The lag plots show the strong correlation at lags 7 and 14.

II. EXPERIMENTATION AND RESULTS

In this section, I split the data into train and test sets. I then evaluated a range of time series models:

  • SEASONAL NAIVE FORECAST
  • SIMPLE EXPONENTIAL SMOOTHING (SES)
  • HOLT WINTERS
  • HOLT WINTERS with DAMPED METHOD
  • AUTO ARIMA


Key Assumption

I used different classes of models from the basic to the more advanced to gauge which one would have the best RMSE score.

Apply the Models:

ATM1

SEASONAL NAIVE FORECAST

Beginning with the Seasonal Naive forecast where each forecast to be equal to the last observed value from the same season. This is considered to be one of the more basic time series model. It provides a ballpark estimate for the anticipated amount of withdrawals.

I trained the model to forecast the next 71 days (the length of the test set). Then, I evaluated the accuracy of the model. The seasonal naive method yields an RMSE of 54.37. A check of the residuals shows that there is still some information leakage in the seasonal naive model. Also that there is correlation in the lags.The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 0.4320557 26.24980 16.87456 -7.745595 23.67519 1.000000 0.1366565 NA
Test set -15.5070423 54.37002 44.94366 -64.370018 92.52089 2.663397 0.2410099 0.7745795

## 
##  Ljung-Box test
## 
## data:  Residuals from Seasonal naive method
## Q* = 57.005, df = 14, p-value = 3.904e-07
## 
## Model df: 0.   Total lags used: 14

SIMPLE EXPONENTIAL SMOOTHING (SES)

The next model, Simple Exponential Smoothing (SES), assumes no trend nor seasonality in the data. SES assigns larger weights to more recent observations. The weights decrease exponentially the further back the observation is. We see that the SES’s RMSE of 29.99595 is already lower than the Seasonal Naive model which shows that more advanced models may get us closer to a better forecast.

A check of the residuals shows that there is still some information leakage in the SES method. There are strong correlations in the lags at time period 7 and 14 which means that the residuals are not White Noise. The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 1.493721 34.26072 26.56414 -39.15612 63.15481 1.574212 0.0800819 NA
Test set -1.900756 29.99595 21.42742 -39.03785 56.65852 1.269805 -0.0532251 0.3660872

## 
##  Ljung-Box test
## 
## data:  Residuals from Simple exponential smoothing
## Q* = 316.42, df = 12, p-value < 2.2e-16
## 
## Model df: 2.   Total lags used: 14

HOLT WINTERS

The next model, the Holt Winters model, is used to capture trend and seasonality. This is a departure from the earlier models which were based on past observations. I used the additive method because as we saw earlier, there is no increase in trend or seasonality for this data over time.The HOLT WINTERS approach shows that the RMSE is for the test set is 48.66 which is higher than the two previous models.

Given the small p-value again, we have to reject the null hypothesis and say that the model is showing a lack of fit.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -0.3136776 20.62943 13.31811 -9.611706 23.31315 0.789242 0.1421814 NA
Test set -16.4063009 48.66144 37.35665 -75.744872 97.35845 2.213785 0.0001390 0.462075

## 
##  Ljung-Box test
## 
## data:  Residuals from Holt-Winters' additive method
## Q* = 14.96, df = 3, p-value = 0.001851
## 
## Model df: 11.   Total lags used: 14

HOLT WINTERS with DAMPED METHOD

The HOLT WINTERS DAMPED creates a trend line that “dampens” or flattens the trend over time. This approach shows that the RMSE is for the test set is 45.76854. The residuals are still not showing independence.

The Holt Winters approaches may not performing as well as the other models primarily due to the lack of trend and seasonality in the data.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -0.0633654 20.59383 13.28339 -10.08907 23.10647 0.7871842 0.1480174 NA
Test set -11.1128971 45.76854 34.61795 -65.54882 89.83930 2.0514871 0.0094684 0.4562158

## 
##  Ljung-Box test
## 
## data:  Residuals from Damped Holt-Winters' additive method
## Q* = 14.987, df = 3, p-value = 0.001827
## 
## Model df: 12.   Total lags used: 15

ARIMA Models

The next model to try is the ARIMA models which stands for Auto Regressive Integrated Moving Average models. To evaluate the model, I tested whether ATM1_Train was stationary, and it was given it p-value of 0.4081. No differencing was needed. I then tested different Arima models, and the model with the lowest AICc was ARIMA(1,0,1). I confirmed these results using auto arima which added a seasonal component to the model. The residuals from this model also show independnce. The best model, as confirmed by the auto.arima function, was ARIMA(1,0,1)(0,1,1)[7]

The RMSE for the auto.arima model, 43.66641, is much higher than it is for the SES model. However, the SES model is less of a good fit because of the non-independence of the residuals.

## 
## ####################### 
## # KPSS Unit Root Test # 
## ####################### 
## 
## Test is of type: mu with 5 lags. 
## 
## Value of test-statistic is: 0.4081 
## 
## Critical value for a significance level of: 
##                 10pct  5pct 2.5pct  1pct
## critical values 0.347 0.463  0.574 0.739

## [1] 0.09231135
## [1] 0

## Series: ATM1_train 
## ARIMA(1,0,1) with non-zero mean 
## 
## Coefficients:
##           ar1     ma1     mean
##       -0.7253  0.8820  85.7531
## s.e.   0.0696  0.0434   2.1222
## 
## sigma^2 estimated as 1125:  log likelihood=-1448.48
## AIC=2904.96   AICc=2905.09   BIC=2919.69
## Series: ATM1_train 
## ARIMA(0,0,1)(1,0,1)[7] with non-zero mean 
## 
## Coefficients:
##          ma1    sar1     sma1     mean
##       0.2090  0.9950  -0.8762  85.2799
## s.e.  0.0548  0.0061   0.0659  11.6250
## 
## sigma^2 estimated as 458:  log likelihood=-1322.66
## AIC=2655.31   AICc=2655.52   BIC=2673.73
## Series: ATM1_train 
## ARIMA(0,0,1)(0,0,1)[7] with non-zero mean 
## 
## Coefficients:
##          ma1    sma1     mean
##       0.1107  0.4921  85.9188
## s.e.  0.0633  0.0411   2.7123
## 
## sigma^2 estimated as 808.6:  log likelihood=-1400.84
## AIC=2809.68   AICc=2809.81   BIC=2824.41
## Series: ATM1_train 
## ARIMA(1,0,1)(0,1,1)[7] 
## 
## Coefficients:
##          ar1      ma1     sma1
##       0.5466  -0.2967  -0.9140
## s.e.  0.2016   0.2260   0.0441
## 
## sigma^2 estimated as 445.9:  log likelihood=-1287.43
## AIC=2582.85   AICc=2582.99   BIC=2597.49
## Series: ATM1_train 
## ARIMA(1,0,1)(0,1,1)[7] 
## 
## Coefficients:
##          ar1      ma1     sma1
##       0.5466  -0.2967  -0.9140
## s.e.  0.2016   0.2260   0.0441
## 
## sigma^2 estimated as 445.9:  log likelihood=-1287.43
## AIC=2582.85   AICc=2582.99   BIC=2597.49
##                  RMSE      MAE     MAPE      MASE
## Training set 20.75324 13.54075 21.46173 0.8024353
## Test set     43.66641 34.03410 83.13523 2.0168875

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(1,0,1)(0,1,1)[7]
## Q* = 8.5273, df = 11, p-value = 0.6654
## 
## Model df: 3.   Total lags used: 14

ATM2

I followed the same approach for ATMs 2 and 4.

SEASONAL NAIVE FORECAST

The seasonal naive method yields an RMSE of 40.13551. A check of the residuals shows that there is still some information leakage in the seasonal naive model for ATM2. Also that there is strong negative correlation at time 7 in the lags.The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -0.0836237 31.74254 21.90941 -Inf Inf 1.000000 0.0807212 NA
Test set -3.2253521 40.13551 32.12676 -Inf Inf 1.466346 0.0907574 0

## 
##  Ljung-Box test
## 
## data:  Residuals from Seasonal naive method
## Q* = 88.664, df = 14, p-value = 6.781e-13
## 
## Model df: 0.   Total lags used: 14

SIMPLE EXPONENTIAL SMOOTHING (SES)

The next model is SES which has a lower RMSE than the seasonal naive method, 39.26611. A check of the residuals shows that there are strong correlations in the lags which means that the residuals are not independent. The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -3.1817681 38.23963 32.16199 -Inf Inf 1.467953 -0.0253341 NA
Test set 0.5218097 39.19669 35.99792 -Inf Inf 1.643035 0.0262781 0

## 
##  Ljung-Box test
## 
## data:  Residuals from Simple exponential smoothing
## Q* = 415.25, df = 12, p-value < 2.2e-16
## 
## Model df: 2.   Total lags used: 14

HOLT WINTERS

HOLT WINTERS model has an RMSE of 61.04838, but once again the residuals do not show independence of each other.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 0.306212 23.43502 16.03738 -Inf Inf 0.731986 0.0833972 NA
Test set 7.155758 61.04838 55.86088 -Inf Inf 2.549630 -0.0349627 0

## 
##  Ljung-Box test
## 
## data:  Residuals from Holt-Winters' additive method
## Q* = 12.188, df = 3, p-value = 0.006766
## 
## Model df: 11.   Total lags used: 14

HOLT WINTERS with Damped

The RMSE for Holt Winters with the Damped method is 60.67069.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -1.748178 23.51733 16.40822 -Inf Inf 0.7489122 0.0845853 NA
Test set 1.591616 60.67069 55.37023 -Inf Inf 2.5272352 -0.0357414 0

## 
##  Ljung-Box test
## 
## data:  Residuals from Damped Holt-Winters' additive method
## Q* = 12.117, df = 3, p-value = 0.006993
## 
## Model df: 12.   Total lags used: 15

ARIMA Models

Running through the same procedure that I did for ATM1, the best ARIMA model is ARIMA(0,0,1)(0,1,1)[7] with a seasonal component to the model. The residuals show independence as well.

## 
## ####################### 
## # KPSS Unit Root Test # 
## ####################### 
## 
## Test is of type: mu with 5 lags. 
## 
## Value of test-statistic is: 1.9423 
## 
## Critical value for a significance level of: 
##                 10pct  5pct 2.5pct  1pct
## critical values 0.347 0.463  0.574 0.739

## [1] 0.6073268
## [1] 1

## Series: ATM2_train 
## ARIMA(1,1,0)(1,1,1)[7] 
## 
## Coefficients:
##           ar1     sar1     sma1
##       -0.4670  -0.0212  -0.8798
## s.e.   0.0521   0.0673   0.0321
## 
## sigma^2 estimated as 785.7:  log likelihood=-1363.1
## AIC=2734.2   AICc=2734.34   BIC=2748.82
## Series: ATM2_train 
## ARIMA(2,1,2)(1,0,1)[7] 
## 
## Coefficients:
##           ar1     ar2      ma1      ma2    sar1     sma1
##       -0.6721  0.1267  -0.2272  -0.7644  0.9966  -0.8803
## s.e.   0.2037  0.0610   0.1963   0.1951  0.0027   0.0324
## 
## sigma^2 estimated as 564.8:  log likelihood=-1349.76
## AIC=2713.53   AICc=2713.92   BIC=2739.29
## Series: ATM2_train 
## ARIMA(1,1,1)(0,1,1)[7] 
## 
## Coefficients:
##          ar1      ma1     sma1
##       0.0901  -0.9999  -0.8877
## s.e.  0.0607   0.0141   0.0300
## 
## sigma^2 estimated as 561.5:  log likelihood=-1319.7
## AIC=2647.4   AICc=2647.54   BIC=2662.03
## Series: ATM2_train 
## ARIMA(1,1,1)(1,1,1)[7] 
## 
## Coefficients:
##          ar1     ma1     sar1     sma1
##       0.0880  -1.000  -0.0624  -0.8765
## s.e.  0.0608   0.014   0.0680   0.0340
## 
## sigma^2 estimated as 561.6:  log likelihood=-1319.28
## AIC=2648.57   AICc=2648.78   BIC=2666.85
## Series: ATM2_train 
## ARIMA(0,0,1)(0,1,1)[7] with drift 
## 
## Coefficients:
##          ma1     sma1    drift
##       0.0828  -0.8934  -0.0829
## s.e.  0.0578   0.0289   0.0296
## 
## sigma^2 estimated as 558.9:  log likelihood=-1319.1
## AIC=2646.2   AICc=2646.34   BIC=2660.84
## Series: ATM2_train 
## ARIMA(0,0,1)(0,1,1)[7] with drift 
## 
## Coefficients:
##          ma1     sma1    drift
##       0.0828  -0.8934  -0.0829
## s.e.  0.0578   0.0289   0.0296
## 
## sigma^2 estimated as 558.9:  log likelihood=-1319.1
## AIC=2646.2   AICc=2646.34   BIC=2660.84
##                  RMSE      MAE MAPE      MASE
## Training set 23.23479 15.45587  Inf 0.7054445
## Test set     60.02590 55.58951  Inf 2.5372440

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(1,0,1)(0,1,1)[7]
## Q* = 8.5273, df = 11, p-value = 0.6654
## 
## Model df: 3.   Total lags used: 14

ATM4

SEASONAL NAIVE FORECAST

The seasonal naive method yields an RMSE of 537.9173. A check of the residuals shows that there is still some information leakage in the seasonal naive model for ATM4. Also that there is strong negative correlation at time 7 in the lags the same as ATM2.The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 4.490081 462.9165 351.3659 -364.6133 420.9499 1.000000 0.0507322 NA
Test set -208.441862 537.9173 443.9707 -1546.3391 1580.9963 1.263556 -0.2048002 0.8476732

## 
##  Ljung-Box test
## 
## data:  Residuals from Seasonal naive method
## Q* = 80.29, df = 14, p-value = 2.5e-11
## 
## Model df: 0.   Total lags used: 14

SIMPLE EXPONENTIAL SMOOTHING (SES)

The next model is SES which has a lower RMSE than the seasonal naive method at 309.5954. A check of the residuals shows that there is some correlations in the lags which means that the residuals are not independent. The very small p-value from the Ljung-Box test shows that we can reject the null hypothesis that the residuals are independent.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set -0.00023 364.0978 304.0387 -538.9422 572.6629 0.8653051 0.0767115 NA
Test set -29.41341 309.5954 258.8207 -781.1552 809.4647 0.7366129 -0.0538860 0.2651169

## 
##  Ljung-Box test
## 
## data:  Residuals from Simple exponential smoothing
## Q* = 23.797, df = 12, p-value = 0.02167
## 
## Model df: 2.   Total lags used: 14

HOLT WINTERS

HOLT WINTERS model has an RMSE of 499.6356. The small p-value means that we cannot reject the null hypothesis.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 23.75904 330.9405 260.7417 -347.7947 412.2755 0.7420802 0.0543639 NA
Test set -147.00463 405.0530 330.1076 -1178.4626 1203.6448 0.9394981 0.0121899 0.2934021

## 
##  Ljung-Box test
## 
## data:  Residuals from Holt-Winters' additive method
## Q* = 17.254, df = 3, p-value = 0.0006265
## 
## Model df: 11.   Total lags used: 14

HOLT WINTERS with Damped

The RMSE for Holt Winters with the Damped method is 485.5957, and there is still information leakage in the residuals.

ME RMSE MAE MPE MAPE MASE ACF1 Theil’s U
Training set 1.12895 328.4283 258.1154 -409.0397 442.8975 0.7346056 0.0845203 NA
Test set -74.74384 384.4139 317.7409 -1036.1018 1070.9761 0.9043019 0.0117797 0.2592924

## 
##  Ljung-Box test
## 
## data:  Residuals from Damped Holt-Winters' additive method
## Q* = 20.41, df = 3, p-value = 0.0001395
## 
## Model df: 12.   Total lags used: 15

ARIMA Models

Following the same procedure, the best ARIMA model was ARIMA(0,0,0)(1,0,0)[7] with an RMSE of 311.767. A check of the residuals show their independence.

## [1] 0.423857
## [1] 0

## Series: ATM2_train 
## ARIMA(1,1,0)(1,1,1)[7] 
## 
## Coefficients:
##           ar1     sar1     sma1
##       -0.4670  -0.0212  -0.8798
## s.e.   0.0521   0.0673   0.0321
## 
## sigma^2 estimated as 785.7:  log likelihood=-1363.1
## AIC=2734.2   AICc=2734.34   BIC=2748.82
## Series: ATM4_train 
## ARIMA(1,0,1) with non-zero mean 
## 
## Coefficients:
##          ar1      ma1      mean
##       0.1942  -0.1178  454.0816
## s.e.  0.7614   0.7711   23.1723
## 
## sigma^2 estimated as 133118:  log likelihood=-2150.11
## AIC=4308.23   AICc=4308.37   BIC=4322.96
## Series: ATM4_train 
## ARIMA(0,0,1)(0,0,1)[7] with non-zero mean 
## 
## Coefficients:
##          ma1    sma1      mean
##       0.0671  0.1630  454.6767
## s.e.  0.0579  0.0542   25.7854
## 
## sigma^2 estimated as 129107:  log likelihood=-2145.71
## AIC=4299.42   AICc=4299.56   BIC=4314.16
## Series: ATM4_train 
## ARIMA(0,0,0)(0,1,0)[7] 
## 
## sigma^2 estimated as 214292:  log likelihood=-2168.71
## AIC=4339.42   AICc=4339.44   BIC=4343.08
## Series: ATM4_train 
## ARIMA(0,0,0)(1,0,0)[7] with non-zero mean 
## 
## Coefficients:
##         sar1      mean
##       0.1915  454.8773
## s.e.  0.0579   25.6351
## 
## sigma^2 estimated as 128574:  log likelihood=-2145.64
## AIC=4297.28   AICc=4297.37   BIC=4308.33

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,0)(1,0,0)[7] with non-zero mean
## Q* = 12.298, df = 12, p-value = 0.422
## 
## Model df: 2.   Total lags used: 14
##                 RMSE      MAE     MAPE      MASE
## Training set 357.351 299.1113 539.7646 0.8512815
## Test set     311.767 261.8851 828.3793 0.7453343

III. Summary of Findings and Forecast for May 2010

In all three experiments across different classes of models, the auto.arima model showed the most accurate forecast for each ATM with the exception of ATM3 which did not have enough data to make an accurate forecast. For that ATM, I would use a default value of 100 until more data is collected.

The final step is to build auto.arima models across the entire time series for ATM1, ATM2, and ATM4, and then forecast for the next 31 days.

ATM1

## Series: ATM1_ts 
## ARIMA(0,0,1)(0,1,2)[7] 
## 
## Coefficients:
##          ma1     sma1     sma2
##       0.1519  -0.5777  -0.1191
## s.e.  0.0544   0.0508   0.0501
## 
## sigma^2 estimated as 476.7:  log likelihood=-1612.43
## AIC=3232.85   AICc=3232.97   BIC=3248.38

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,1)(0,1,2)[7]
## Q* = 18.031, df = 11, p-value = 0.08087
## 
## Model df: 3.   Total lags used: 14
Date Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
53.14286 2010-05-01 87.40152 59.420743 115.38230 44.60861 130.19444
53.28571 2010-05-02 104.47097 76.169174 132.77276 61.18711 147.75482
53.42857 2010-05-03 72.99315 44.691363 101.29494 29.70930 116.27701
53.57143 2010-05-04 23.96954 -4.332252 52.27133 -19.31432 67.25339
53.71429 2010-05-05 99.70527 71.403482 128.00706 56.42142 142.98913
53.85714 2010-05-06 80.97688 52.675089 109.27867 37.69303 124.26073
54.00000 2010-05-07 86.88567 58.583884 115.18747 43.60182 130.16953
54.14286 2010-05-08 88.16500 57.495003 118.83499 41.25929 135.07070
54.28571 2010-05-09 102.97742 72.254932 133.69991 55.99143 149.96341
54.42857 2010-05-10 73.30308 42.580593 104.02557 26.31709 120.28907

The forecast for ATM1 for May 2010 is exported here:

ATM2

## Series: ATM2_ts 
## ARIMA(2,0,2)(0,1,1)[7] 
## 
## Coefficients:
##           ar1      ar2     ma1     ma2     sma1
##       -0.4322  -0.9172  0.4729  0.8135  -0.7571
## s.e.   0.0550   0.0398  0.0860  0.0546   0.0382
## 
## sigma^2 estimated as 620.1:  log likelihood=-1658.84
## AIC=3329.68   AICc=3329.92   BIC=3352.96

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,0,2)(0,1,1)[7]
## Q* = 11.228, df = 9, p-value = 0.2604
## 
## Model df: 5.   Total lags used: 14
Date Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
53.14286 2010-05-01 66.372742 34.46012 98.28536 17.56661 115.17888
53.28571 2010-05-02 72.889482 40.95043 104.82854 24.04291 121.73605
53.42857 2010-05-03 13.711143 -18.46153 45.88381 -35.49271 62.91500
53.57143 2010-05-04 5.262535 -26.91373 37.43880 -43.94682 54.47189
53.71429 2010-05-05 97.633753 65.28442 129.98309 48.15971 147.10780
53.85714 2010-05-06 88.225388 55.82115 120.62963 38.66738 137.78340
54.00000 2010-05-07 64.753541 32.27126 97.23582 15.07619 114.43089
54.14286 2010-05-08 66.381329 32.25868 100.50398 14.19524 118.56742
54.28571 2010-05-09 72.892832 38.74868 107.03698 20.67386 125.11181
54.42857 2010-05-10 13.701819 -20.65375 48.05739 -38.84049 66.24413

The forecast for ATM2 for May 2010 is exported here:

ATM3

As stated previously, there is not nearly enough data to make any realistic forecast for ATM3, and I did not want to use an average of the three values as that would cause the ATM to have insufficient funds to complete the transaction. Instead, I will use a default value of 100 until I can collect more data.

##          Date default
## 1  2010-05-01     100
## 2  2010-05-02     100
## 3  2010-05-03     100
## 4  2010-05-04     100
## 5  2010-05-05     100
## 6  2010-05-06     100
## 7  2010-05-07     100
## 8  2010-05-08     100
## 9  2010-05-09     100
## 10 2010-05-10     100
## 11 2010-05-11     100
## 12 2010-05-12     100
## 13 2010-05-13     100
## 14 2010-05-14     100
## 15 2010-05-15     100
## 16 2010-05-16     100
## 17 2010-05-17     100
## 18 2010-05-18     100
## 19 2010-05-19     100
## 20 2010-05-20     100
## 21 2010-05-21     100
## 22 2010-05-22     100
## 23 2010-05-23     100
## 24 2010-05-24     100
## 25 2010-05-25     100
## 26 2010-05-26     100
## 27 2010-05-27     100
## 28 2010-05-28     100
## 29 2010-05-29     100
## 30 2010-05-30     100
## 31 2010-05-31     100

The forecast for ATM3 for May 2010 is exported here:

ATM4

## Series: ATM4_ts 
## ARIMA(3,0,2)(1,0,0)[7] with non-zero mean 
## 
## Coefficients:
##           ar1      ar2     ar3     ma1     ma2    sar1      mean
##       -0.9610  -0.6672  0.1415  1.0318  0.7564  0.2402  446.9595
## s.e.   0.1409   0.1316  0.0576  0.1355  0.1217  0.0550   26.4231
## 
## sigma^2 estimated as 120826:  log likelihood=-2650.22
## AIC=5316.44   AICc=5316.84   BIC=5347.64

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(3,0,2)(1,0,0)[7] with non-zero mean
## Q* = 5.2881, df = 7, p-value = 0.6249
## 
## Model df: 7.   Total lags used: 14
Date Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
53.14286 2010-05-01 367.2026 -78.26566 812.6708 -314.0823 1048.487
53.28571 2010-05-02 395.7143 -50.86834 842.2969 -287.2749 1078.703
53.42857 2010-05-03 504.8763 58.19368 951.5589 -178.2658 1188.018
53.57143 2010-05-04 330.4565 -117.43716 778.3501 -354.5377 1015.451
53.71429 2010-05-05 379.1307 -70.01214 828.2735 -307.7740 1066.035
53.85714 2010-05-06 410.5516 -38.73962 859.8428 -276.5800 1097.683
54.00000 2010-05-07 425.1336 -24.43869 874.7059 -262.4279 1112.695
54.14286 2010-05-08 410.4359 -46.07617 866.9480 -287.7391 1108.611
54.28571 2010-05-09 480.0971 22.88792 937.3062 -219.1440 1179.338
54.42857 2010-05-10 424.4931 -32.75584 881.7421 -274.8088 1123.795

The forecast for ATM4 for May 2010 is exported here:

Part B

Import and discuss the state of the data

For Part B, we are given a simple dataset of residential power usage for January 1998 until December 2013. We are to model this data and provide a monthly forecast for the year 2014. From the import, there are 192 observations and 3 variables. The date column needs to be updated and renamed, and there is a missing value.

## [1] "ResidentialCustomerForecastLoad624 has been loaded."

Exploratory Data Analysis and Cleaning

## Classes 'tbl_df', 'tbl' and 'data.frame':    192 obs. of  3 variables:
##  $ CaseSequence: num  733 734 735 736 737 738 739 740 741 742 ...
##  $ YYYY-MMM    : chr  "1998-Jan" "1998-Feb" "1998-Mar" "1998-Apr" ...
##  $ KWH         : num  6862583 5838198 5420658 5010364 4665377 ...
##   CaseSequence     YYYY-MMM              KWH          
##  Min.   :733.0   Length:192         Min.   :  770523  
##  1st Qu.:780.8   Class :character   1st Qu.: 5429912  
##  Median :828.5   Mode  :character   Median : 6283324  
##  Mean   :828.5                      Mean   : 6502475  
##  3rd Qu.:876.2                      3rd Qu.: 7620524  
##  Max.   :924.0                      Max.   :10655730  
##                                     NA's   :1

Rename the date column to “Date”

Add an “-01” to the date values

CaseSequence Date KWH
733 1998-01-01 6862583
734 1998-02-01 5838198
735 1998-03-01 5420658
736 1998-04-01 5010364
737 1998-05-01 4665377
738 1998-06-01 6467147
739 1998-07-01 8914755
740 1998-08-01 8607428
741 1998-09-01 6989888
742 1998-10-01 6345620

Identify and Handle Missing Data

As was done in Part A, I will use kNN to impute the missing item.

CaseSequence Date KWH KWH_imp
129 861 2008-09-01 6548439 TRUE

Convert the Data into a Time Series and Plot It

We see the strong seasonal and a distinct upward trend of energy usage from 1998 to 2013.

## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

Decomposition shows the upward trend in usage over the time series as well as a strongly defined seasonality.

The polar, seasonal, and series plots show that the periods of June to Aug and Nov to Feb are the heaviest usage months.

The seasonal and subseries plots confirm that the peak usage for the months

The gglagplot shows the highest lag correlation at month 12.

Split the Time Series

The data will be split into training and test sets. The training set will be comprised of the first 12 years and the test set will be the last three years (h=36 months).

Experimentation and Results

I followed the same experimentation procedure as I did for Part A.

SEASONAL NAIVE FORECAST

The Seasonal Naive model has a RMSE of 1145248.6, and the Ljung-Box test has an extremely small p-value which means that the residuals are not independent.

##                    ME      RMSE      MAE       MPE      MAPE     MASE      ACF1
## Training set  64862.3  731206.9 580023.4 0.3531193  9.135197 1.000000 0.2742628
## Test set     523464.3 1145248.6 906533.9 6.1475757 11.672843 1.562926 0.1745470
##              Theil's U
## Training set        NA
## Test set     0.6984242

## 
##  Ljung-Box test
## 
## data:  Residuals from Seasonal naive method
## Q* = 73.802, df = 24, p-value = 5.723e-07
## 
## Model df: 0.   Total lags used: 24

SIMPLE EXPONENTIAL SMOOTHING

The Simple Exponential Smoothing RMSE is 1964548 with non-independent residuals.

##                        ME    RMSE     MAE       MPE     MAPE     MASE      ACF1
## Training set     601.9718 1241146 1067381 -3.903186 17.49222 1.840238 0.4620137
## Test set     1184397.2306 1964548 1555443 12.042544 18.56283 2.681691 0.3618090
##              Theil's U
## Training set        NA
## Test set       1.04319

## 
##  Ljung-Box test
## 
## data:  Residuals from Simple exponential smoothing
## Q* = 708.51, df = 22, p-value < 2.2e-16
## 
## Model df: 2.   Total lags used: 24

HOLT WINTERS

For Holt Winters, I set the seasonal parameter to “multiplicative” because of the increasing variance of the trend and seasonality. The Holt Winters model RMSE is 1136637.5. So, far this model performs the best, RMSE of 1136637.5, because it captures the trend and seasonality. However, the residuals are not independent.

##                     ME      RMSE      MAE       MPE      MAPE     MASE
## Training set -39611.18  546618.7 422413.1 -1.313133  6.723668 0.728269
## Test set     761002.17 1136637.5 863245.9  9.081672 10.752058 1.488295
##                   ACF1 Theil's U
## Training set 0.3480073        NA
## Test set     0.1204219 0.7026044

## 
##  Ljung-Box test
## 
## data:  Residuals from Holt-Winters' multiplicative method
## Q* = 55.456, df = 8, p-value = 3.6e-09
## 
## Model df: 16.   Total lags used: 24

HOLT WINTERS with Damped

The Holt Winters model using the Damped approach’s RMSE is 1206318.5 with non-independent residuals.

##                      ME      RMSE      MAE        MPE      MAPE      MASE
## Training set   3682.852  539719.6 426777.0 -0.5395034  6.814871 0.7357927
## Test set     857755.126 1206318.5 922850.2 10.3659723 11.439927 1.5910568
##                   ACF1 Theil's U
## Training set 0.1318510        NA
## Test set     0.1169638  0.745225

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

ARIMA Models

Using the same procedure as before, I found that the best ARIMA model is ARIMA(0,0,1)(2,1,0)[12] with drift. The RMSE of the ARIMA model is the lowest for all of the above models at 1047126.6.

## 
## ####################################### 
## # KPSS Unit Root / Cointegration Test # 
## ####################################### 
## 
## The value of the test statistic is: 0.3845

## [1] 0.3474603
## [1] 0

## Series: KWH_train 
## ARIMA(0,0,1)(2,1,1)[12] with drift 
## 
## Coefficients:
##          ma1     sar1     sar2     sma1     drift
##       0.3109  -0.2827  -0.2105  -0.5307  4421.573
## s.e.  0.1009   0.1899   0.1390   0.1851  1827.769
## 
## sigma^2 estimated as 3.067e+11:  log likelihood=-2111.32
## AIC=4234.63   AICc=4235.25   BIC=4252.45
## Series: KWH_train 
## ARIMA(1,0,1) with non-zero mean 
## 
## Coefficients:
##          ar1     ma1       mean
##       0.1545  0.6327  6327446.1
## s.e.  0.0981  0.0660   149251.4
## 
## sigma^2 estimated as 9.57e+11:  log likelihood=-2371.99
## AIC=4751.98   AICc=4752.24   BIC=4764.18
## Series: KWH_train 
## ARIMA(1,0,1)(0,0,1)[12] with non-zero mean 
## 
## Coefficients:
##          ar1     ma1    sma1       mean
##       0.0586  0.6102  0.5511  6351418.0
## s.e.  0.1154  0.0854  0.0648   164964.4
## 
## sigma^2 estimated as 6.558e+11:  log likelihood=-2344.08
## AIC=4698.15   AICc=4698.55   BIC=4713.4
## Series: KWH_train 
## ARIMA(0,0,1)(2,1,0)[12] with drift 
## 
## Coefficients:
##          ma1     sar1     sar2     drift
##       0.2821  -0.7137  -0.4286  4979.243
## s.e.  0.1057   0.0853   0.0835  2466.045
## 
## sigma^2 estimated as 3.185e+11:  log likelihood=-2113.55
## AIC=4237.11   AICc=4237.54   BIC=4251.96
## Series: KWH_train 
## ARIMA(0,0,1)(2,1,0)[12] with drift 
## 
## Coefficients:
##          ma1     sar1     sar2     drift
##       0.2821  -0.7137  -0.4286  4979.243
## s.e.  0.1057   0.0853   0.0835  2466.045
## 
## sigma^2 estimated as 3.185e+11:  log likelihood=-2113.55
## AIC=4237.11   AICc=4237.54   BIC=4251.96

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,1)(2,1,0)[12] with drift
## Q* = 36.622, df = 20, p-value = 0.01298
## 
## Model df: 4.   Total lags used: 24
##                   RMSE      MAE     MAPE      MASE
## Training set  534637.1 398144.7 6.358980 0.6864288
## Test set     1047126.6 765875.5 9.428987 1.3204217

III. Summary of Findings and Monthly Forecast for 2014

Applying the auto.arima model across the entire time series to project the next 12 months shows that the best model is ARIMA(0,0,3)(2,1,0)[12]

## Series: KWH_ts 
## ARIMA(0,0,3)(2,1,0)[12] with drift 
## 
## Coefficients:
##          ma1     ma2     ma3     sar1     sar2     drift
##       0.3308  0.0452  0.2391  -0.6834  -0.4000  9003.910
## s.e.  0.0789  0.0871  0.0757   0.0772   0.0793  3121.791
## 
## sigma^2 estimated as 3.96e+11:  log likelihood=-2659.68
## AIC=5333.35   AICc=5334   BIC=5355.7

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,3)(2,1,0)[12] with drift
## Q* = 15.236, df = 18, p-value = 0.6457
## 
## Model df: 6.   Total lags used: 24
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
Jan 2014 10369540 9563069 11176012 9136149 11602932
Feb 2014 8598539 7749091 9447987 7299420 9897658
Mar 2014 7232369 6382139 8082599 5932054 8532684
Apr 2014 6010640 5138824 6882456 4677313 7343967
May 2014 5947452 5075636 6819268 4614125 7280779
Jun 2014 8194390 7322574 9066206 6861063 9527717
Jul 2014 9445287 8573472 10317103 8111960 10778615
Aug 2014 9947311 9075496 10819127 8613984 11280638
Sep 2014 8467560 7595744 9339376 7134233 9800887
Oct 2014 5870569 4998753 6742385 4537242 7203896
Nov 2014 6137679 5265863 7009495 4804352 7471006
Dec 2014 8448896 7577080 9320712 7115569 9782223

The 2014 monthly forecasts are exported here:

LS0tDQp0aXRsZTogIkNVTlkgREFUQTYyNCBTcHJpbmcgMjAyMSBQcm9qZWN0IE9uZSINCmF1dGhvcjogIkpvaG4gSy4gSGFuY29jayINCmRhdGU6ICI0LzEwLzIwMjEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KCdmcHAyJykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobW9vbkJvb2spDQpsaWJyYXJ5KGdnaXJhcGhFeHRyYSkNCmxpYnJhcnkoZ2djb3JycGxvdCkNCmxpYnJhcnkobWxiZW5jaCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeSgiY29tcGFyZSIpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoZGF0YS50YWJsZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShzZWFzb25hbCkNCmxpYnJhcnkodXJjYSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh0aWJibGUpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh4dHMpDQpsaWJyYXJ5KFRTc3R1ZGlvKQ0KbGlicmFyeSgicXVhbnRtb2QiKQ0KbGlicmFyeSgidHNlcmllcyIpDQpsaWJyYXJ5KFZJTSkNCmxpYnJhcnkoSUNTTlApDQoNCg0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KDQpUaGUgc29sbyBwcm9qZWN0IGNvbnNpc3RzIG9mIHR3byBwYXJ0cy4gUGFydCBBIHRhc2tzIHVzIHdpdGggZm9yZWNhc3RpbmcgdGhlIGFtb3VudCBvZiBjYXNoIHdpdGhkcmF3biBmcm9tIDQgQVRNIG1hY2hpbmVzLiBQYXJ0IEIgaXMgZm9yZWNhc3RpbmcgcmVzaWRlbnRpYWwgcG93ZXIgdXNhZ2UuIFRoZSBkYXRhIHByb3ZpZGVkIGZvciB0aGlzIHByb2plY3QgaXMgaW4gdHdvIGV4Y2VsIGZpbGVzLiBUaGUgbWFqb3Igb3V0bGluZSBvZiBteSBhcHByb2FjaCBpcyB0byBleGFtaW5lIHRoZSBkYXRhLCBjbGVhbiBhbmQgcHJlcGFyZSB0aGUgZGF0YSBmb3IgYW5hbHlzaXMsIGFuZCBjb21wYXJlIGEgcmFuZ2Ugb2YgZm9yZWNhc3RpbmcgbW9kZWxzIHRvIHRoZSBkYXRhLiAgVGhlIG1vZGVsIHRoYXQgcGVyZm9ybXMgdGhlIGJlc3QgYmFzZWQgb24gUk1TRSB3aWxsIGJlIHRoZSBvbmUgY2hvc2VuIHRvIGZvcmVjYXN0IHRoZSBuZXh0IHRpbWUgcGVyaW9kLg0KDQo8YnIvPg0KDQo8Yj5QYXJ0IEE8L2I+PGJyLz4NCjxiPjx1PkkuIERBVEEgUFJFUEFSQVRJT048L3U+PC9iPjxici8+DQo8b2w+DQogIDxsaT5JbXBvcnQgYW5kIGRpc2N1c3MgdGhlIHN0YXRlIG9mIHRoZSBkYXRhPC9saT4NCiAgPGxpPkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgYW5kIENsZWFuaW5nPC9saT4NCiAgPGxpPklkZW50aWZ5IE1pc3NpbmcgRGF0YSA8L2xpPg0KICA8bGk+U3BsaXQgdGhlIE1haW4gRGF0YXNldCBpbnRvIDQgZm9yIGVhY2ggQVRNPC9saT4NCiAgPGxpPkFkZHJlc3MgdGhlIE1pc3NpbmcgRGF0YSBmb3IgZWFjaCBBVE08L2xpPg0KICA8bGk+SWRlbnRpZnkgYW5kIEFkZHJlc3MgT3V0bGllcnM8L2xpPg0KICA8bGk+Q29udmVydCB0aGUgRGF0YSBpbnRvIGEgVGltZSBTZXJpZXM8L2xpPg0KICA8bGk+UmV2aWV3IHRpbWUgc2VyaWVzIHBsb3RzPC9saT4NCjwvb2w+DQo8YnIvPg0KDQo8Yj48dT5JSS4gRVhQRVJJTUVOVEFUSU9OIEFORCBSRVNVTFRTPC91PjwvYj4NCjxvbD4NCiAgPGxpPlNwbGl0IHRoZSBUaW1lIFNlcmllczwvbGk+DQogIDxsaT5BcHBseSBEaWlmZXJlbnQgTW9kZWxzPC9saT4NCiAgPGxpPkNvbXBhcmUgYW5kIGRpc2N1c3MgdGhlIHJlc3VsdHMgZnJvbSBlYWNoIG1vZGVsPC9saT4NCiAgPGxpPlNlbGVjdCB0aGUgYmVzdCBtb2RlbCBhbmQgZm9yZWNhc3QgdGhlIG5leHQgbW9udGggcGVyIEFUTTwvbGk+DQo8L29sPg0KPGJyLz4NCg0KPGI+PHU+SUlJLiBTdW1tYXJ5IG9mIEZpbmRpbmdzIGFuZCBGb3JlY2FzdCBmb3IgTWF5IDIwMTA8L3U+PC9iPg0KDQoNCjxiPlBhcnQgQjwvYj48YnIvPg0KPGI+PHU+SS4gREFUQSBQUkVQQVJBVElPTjwvdT48L2I+PGJyLz4NCjxvbD4NCiAgPGxpPkltcG9ydCBhbmQgZGlzY3VzcyB0aGUgc3RhdGUgb2YgdGhlIGRhdGE8L2xpPg0KICA8bGk+RXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBhbmQgQ2xlYW5pbmc8L2xpPg0KICA8bGk+SWRlbnRpZnkgTWlzc2luZyBEYXRhIDwvbGk+DQogIDxsaT5BZGRyZXNzIHRoZSBNaXNzaW5nIERhdGEgZm9yIGVhY2ggQVRNPC9saT4NCiAgPGxpPklkZW50aWZ5IGFuZCBBZGRyZXNzIE91dGxpZXJzPC9saT4NCiAgPGxpPkNvbnZlcnQgdGhlIERhdGEgaW50byBhIFRpbWUgU2VyaWVzPC9saT4NCiAgPGxpPlJldmlldyB0aW1lIHNlcmllcyBwbG90czwvbGk+DQo8L29sPg0KPGJyLz4NCg0KPGI+PHU+SUkuIEVYUEVSSU1FTlRBVElPTiBBTkQgUkVTVUxUUzwvdT48L2I+PGJyLz4NCjxvbD4NCiAgPGxpPlNwbGl0IHRoZSBUaW1lIFNlcmllczwvbGk+DQogIDxsaT5BcHBseSB0aGUgTmFpdmUsIFNpbXBsZSBFeHBvbmVudGlhbCBTbW9vdGhpbmcsIEhvbHQgV2ludGVycywgYW5kIEFSSU1BIG1vZGVscyB0byBlYWNoIHRpbWUgc2VyaWVzPC9saT4NCiAgPGxpPkNvbXBhcmUgYW5kIGRpc2N1c3MgdGhlIHJlc3VsdHMgZnJvbSBlYWNoIG1vZGVsPC9saT4NCiAgPGxpPlNlbGVjdCB0aGUgYmVzdCBtb2RlbCBhbmQgZm9yZWNhc3QgdGhlIG5leHQgbW9udGggcGVyIEFUTTwvbGk+DQo8L29sPg0KPGJyLz4NCg0KPGI+PHU+SUlJLiBTdW1tYXJ5IG9mIEZpbmRpbmdzIGFuZCBNb250aGx5IEZvcmVjYXN0IGZvciAyMDE0PC91PjwvYj4NCg0KPGJyLz4NCg0KIyBQYXJ0IEEgDQoNCiMjIEkuIERBVEEgUFJFUEFSQVRJT04NCg0KIyMjIEltcG9ydCBhbmQgZGlzY3VzcyB0aGUgc3RhdGUgb2YgdGhlIGRhdGENCg0KDQpgYGB7cn0NCkFUTTYyNERhdGFfUmF3IDwtIHJlYWR4bDo6cmVhZF9leGNlbCgiQVRNNjI0RGF0YS54bHN4IikNCmBgYA0KDQo8aT5LZXkgQXNzdW1wdGlvbjwvaT4NCg0KV2UgYXJlIGdpdmVuIG5vIGRldGFpbHMgYWJvdXQgdGhlIEFUTSBkYXRhLiBXZSBkb24ndCBrbm93IGlmIHRoZXkncmUgZnJvbSB0aGUgc2FtZSBiYW5rIG9yIGluIHRoZSBzYW1lIGJ1aWxkaW5nIG9yIGluIHRoZSBzYW1lIGNpdHkuIFRodXMsIEkgbWFkZSB0aGUgIGFzc3VtcHRpb24gdGhhdCB0aGVzZSBhcmUgNCBkaXN0aW5jdCwgdW5yZWxhdGVkIEFUTXMuIFRoZXkgYXJlIG1hbmFnZWQgYnkgYW4gaW5kZXBlbmRlbnQsIG5vbi1iYW5rLCBzb2xvIGVudHJlcGVuZXVyLiBUaGVzZSBhcmUgdGhlIGtpbmRzIG9mIEFUTXMgdGhhdCBvbmUgd291bGQgZmluZCBpbiBhIGNvbnZlbmllbmNlIHN0b3JlIG9yIGF0IGEgZ2FzIHN0YXRpb24uIFRoaXMgZW50cmVwZW5ldXIgc2VydmljZXMgdGhlc2UgQVRNcyBieSBrZWVwaW5nIHRoZW0gc3RvY2tlZCB3aXRoIGNhc2guIFJldmVudWUgY29tZXMgZnJvbSB0aGUgdXNlciBmZWVzIGZvciBlYWNoIHdpdGhkcmF3YWwuIFNvLCBpZiB0aGUgQVRNcyBhcmUgb3V0IG9mIGNhc2gsIHRoZSBlbnRyZXBlbmV1ciBsb3NlcyBtb25leSBiZWNhdXNlIG5vIHdpdGhkcmF3YWxzIGNhbiBiZSBtYWRlLiAgSWYgdGhleSBoYXZlIHRvbyBtdWNoIGNhc2gsIHRoZSBtb25leSBzaXRzIGlkbGUgYW5kIHRoZSBjb21wYW55IGxvc2VzIG1vbmV5IGFzIHdlbGwuIFNvLCB0aGUgZW50cmVwZW5ldXIgbmVlZHMgYWNjdXJhdGUgd2l0aGRyYXdhbCBmb3JlY2FzdHMgdG8gbWF4aW1pemUgcHJvZml0cy4gDQoNCg0KIyMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgYW5kIENsZWFuaW5nDQoNCkkgYmVnaW4gYnkgdGFraW5nIGEgZ2xpbXBzZSBhdCB0aGUgcmF3IGRhdGEuIFRoZXJlIGFyZSAxLDQ3NCBvYnNlcnZhdGlvbnMgYW5kIHRocmVlIHZhcmlhYmxlcy4gV2Ugc2VlIHRoYXQgdGhlIERhdGUgdmFyaWFibGUgaXMgaW4gaW50ZWdlciBmb3JtYXQsIG5vdCBkYXRlLiBEYXRhIGZvciBlYWNoIG9mIHRoZSA0IEFUTXMgYXJlIG1pbmdsZWQgaW4gb25lIGRhdGFzZXQuIFRoZXJlIGFyZSAxNCBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgQVRNIHZhcmlhYmxlcyBhbmQgMTkgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIENhc2ggdmFyaWFibGUuIEkgaGFuZGxlIE1pc3NpbmcgRGF0YSBpbiB0aGUgbmV4dCBzZWN0aW9uLg0KDQoNCmBgYHtyfQ0KZ2xpbXBzZShBVE02MjREYXRhX1JhdykNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmhlYWREYXRhIDwtIGhlYWQoQVRNNjI0RGF0YV9SYXcpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQprbml0cjo6a2FibGUoaGVhZERhdGEsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNClVzaW5nIHRoZSBleGNlbF9udW1lcmljX3RvX2RhdGUgZnVuY3Rpb24gZnJvbSB0aGUgamFuaXRvciBsaWJyYXJ5IHBhY2thZ2UsIHRoZSBkYXRlcyB3ZXJlIGNvbnZlcnRlZCB0byB0aGUgJ1lZWVktTU0tREQnIGZvcm1hdC4gDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KQVRNNjI0RGF0YV9SYXckREFURSA8LSBleGNlbF9udW1lcmljX3RvX2RhdGUoYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoQVRNNjI0RGF0YV9SYXckREFURSksIGRhdGVfc3lzdGVtID0gIm1vZGVybiIpKQ0KaGVhZERhdGEyIDwtIGhlYWQoQVRNNjI0RGF0YV9SYXcsIDUpDQpgYGANCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShoZWFkRGF0YTIsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCg0KIyMjIElkZW50aWZ5IE1pc3NpbmcgRGF0YQ0KDQpMb29raW5nIGF0IHRoZSBzdW1tYXJ5IG9mIHRoZSBkYXRhIHNob3dzIHRoYXQgdGhlcmUgYXJlIDE5IG9ic2VydmF0aW9ucyB3aXRoIG1pc3NpbmcgZGF0YS4gRnVydGhlciBpbnNwZWN0aW9uIHNob3dzIHRoYXQgdGhlcmUgYXJlIDE0IG9ic2VydmF0aW9ucyB3aXRob3V0IGFueSBBVE0gb3IgQ2FzaCBpbmZvcm1hdGlvbiwgYW5kIGZpdmUgb2JzZXJ2YXRpb25zIHdpdGggb25seSB0aGUgQVRNIGluZm9ybWF0aW9uLiBTaW5jZSB3ZSBoYXZlIG5vIGRldGFpbHMgb24gaG93IHRoaXMgZGF0YSB3YXMgY29sbGVjdGVkIGFuZCBhcyBzdWNoLCB0aGVyZSBpcyBubyBsb2dpY2FsIGFuc3dlciBhcyB0byB3aHkgMTQgdmFsdWVzIGFyZSBtaXNzaW5nLiBGb3IgZXhhbXBsZSwgdGhlc2UgbWlzc2luZyB2YWx1ZXMgYXJlIG9uIGNvbnNlY3V0aXZlIGRheXMgc28gYXR0cmlidXRpbmcgdGhlIG1pc3NpbmduZXNzIHRvIGhvbGlkYXlzIG9yIHNvbWUgb3RoZXIgZXhwbGFuYXRpb24gbGlrZSBhbiBlcXVpcG1lbnQgcmVwbGFjZW1lbnQuIA0KDQoNCjxpPktleSBBc3N1bXB0aW9uPC9pPg0KDQpNeSBuZXh0IGtleSBhc3N1bXB0aW9uIGlzIHJlZ2FyZGluZyBoYW5kbGluZyBtaXNzaW5nIGRhdGEuQm90aCB0aGUgYW1vdW50cyBhbmQgdGhlIGRhdGVzIGFyZSBtaXNzaW5nLiBJIGFtIGdvaW5nIHRvIGFzc3VtZSB0aGF0IHRoZSAxNCBtaXNzaW5nIHZhbHVlcyBhcmUgTWlzc2luZyBDb21wbGV0ZWx5IGF0IFJhbmRvbSAoTUNBUikgd2hpY2ggbWVhbnMgdGhhdCB0aGUgbWlzc2luZyBkYXRhIGhhcyBubyByZWxhdGlvbnNoaXAgdG8gdGhlIG90aGVyIGRhdGEuIEkgY2Fubm90IHVzZSBkYXRhIGZyb20gYW55IG9mIHRoZSBvdGhlciBBVE1zIGJlY2F1c2UgYXMgSSBzdGF0ZWQgZWFybGllciwgdGhleSdyZSBhbGwgaW5kZXBlbmRlbnQuIEkgYWxzbyBjYW5ub3QgYXNzdW1lIHRoYXQgaXQgY2FtZSBmcm9tIG9uZSBwYXJ0aWN1bGFyIEFUTSBnaXZlbiB0aGUgdW5pcXVlbmVzcyBvZiBlYWNoLiANCg0KVGhlIGxpbmsgYmVsb3cgZ29lcyBpbnRvIGRldGFpbHMgYWJvdXQgTUNBUi48YnIvPg0KDQpodHRwczovL3d3dy50aGVhbmFseXNpc2ZhY3Rvci5jb20vbWFyLWFuZC1tY2FyLW1pc3NpbmctZGF0YS8NCg0KVGhlIGZpcnN0IHN0ZXAgaW4gY2xlYW5pbmcgdXAgdGhpcyBkYXRhIHdpbGwgYmUgdG8gcmVtb3ZlIHRoZXNlIDE0IHJvd3Mgd2l0aCBubyBpbmZvcm1hdGlvbi4gDQoNCmBgYHtyfQ0Kc3VtbWFyeShBVE02MjREYXRhX1JhdykNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCkFsbF9NaXNzaW5nX0RhdGEgPC0gQVRNNjI0RGF0YV9SYXdbcm93U3Vtcyhpcy5uYShBVE02MjREYXRhX1JhdykpID4gMCxdDQpgYGANCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShoZWFkKEFsbF9NaXNzaW5nX0RhdGEpLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNClRoZSAxNCByb3dzIHdpdGggTWlzc2luZyBEYXRhDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KZm91cnRlZW5fTWlzc2luZyA8LSBBVE02MjREYXRhX1Jhd1tpcy5uYShBVE02MjREYXRhX1JhdyRBVE0pPT1UUlVFLF0NCmBgYA0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShmb3VydGVlbl9NaXNzaW5nLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KSSBjcmVhdGVkIGEgbmV3IGRhdGEgZnJhbWUsIEFUTTYyNERhdGFfUmF3MSwgd2l0aCB0aGUgMTQgcmVtb3ZlZC4NCg0KYGBge3J9DQpBVE02MjREYXRhX1JhdzEgPC0gQVRNNjI0RGF0YV9SYXdbaXMubmEoQVRNNjI0RGF0YV9SYXckQVRNKT09RkFMU0UsXQ0KYGBgDQoNCg0KIyMjIFNwbGl0IHRoZSBNYWluIERhdGFzZXQgaW50byA0IGZvciBlYWNoIEFUTQ0KDQpOZXh0LCBJIGNyZWF0ZWQgZm91ciBuZXcgZGF0YWZyYW1lcyBmb3IgZWFjaCBBVE0uIEFnYWluIGJlY2F1c2Ugb2YgdGhlIGluZGVwZW5kZW5jZSBvZiBlYWNoIG1hY2hpbmUuDQoNCg0KYGBge3J9DQpBVE0xIDwtIEFUTTYyNERhdGFfUmF3MVtBVE02MjREYXRhX1JhdzEkQVRNID09ICdBVE0xJywgXQ0KDQpBVE0yIDwtIEFUTTYyNERhdGFfUmF3MVtBVE02MjREYXRhX1JhdzEkQVRNID09ICdBVE0yJywgXQ0KDQpBVE0zIDwtIEFUTTYyNERhdGFfUmF3MVtBVE02MjREYXRhX1JhdzEkQVRNID09ICdBVE0zJywgXQ0KDQpBVE00IDwtIEFUTTYyNERhdGFfUmF3MVtBVE02MjREYXRhX1JhdzEkQVRNID09ICdBVE00JywgXQ0KDQpgYGANCg0KDQojIyMgQWRkcmVzcyB0aGUgTWlzc2luZyBEYXRhIGZvciBlYWNoIEFUTQ0KDQo8Yj48dT5BVE0xPC91PjwvYj4NCg0KQSBzdW1tYXJ5IG9mIEFUTTEgc2hvd3MgdGhhdCB0aGVyZSBhcmUgdGhyZWUgTkEgdmFsdWVzLiANCg0KYGBge3J9DQpzdW1tYXJ5KEFUTTEpDQpgYGANCldoZW4gSSBpc29sYXRlZCB0aHJlZSBvZiB0aGUgbWlzc2luZyBjYXNoIHZhbHVlcyBmb3IgQVRNMSwgSSBzYXcgdGhhdCBpdCdzIGFsbCB3aXRoaW4gdGhlIG1vbnRoIG9mIEp1bmUgMjAwOS4gDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpNaXNzaW5nX0FUTTEgPC0gQVRNMSAlPiUgDQogICAgZmlsdGVyKGlzLm5hKENhc2gpPT1UUlVFKQ0KYGBgDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoTWlzc2luZ19BVE0xLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCjxiPjx1PmstTmVhcmVzdCBOZWlnaGJvdXIgSW1wdXRhdGlvbjwvdT48L2I+DQoNCkkgdXNlZCBhIGtOTiBpbXB1dGF0aW9uIHN0cmF0ZWd5IHRvIGZpbGwgaW4gZm9yIHRoZSBtaXNzaW5nIENhc2ggdmFsdWVzIGZvciBBVE0xLiAgSSBhbHNvIHVzZWQgdGhlIGRlZmF1bHQgdmFsdWUgb2Ygaz01LiA8YnIvPg0KDQoiT25lIHBvcHVsYXIgdGVjaG5pcXVlIGZvciBpbXB1dGF0aW9uIGlzIGEgSy1uZWFyZXN0IG5laWdoYm9yIG1vZGVsLiBBIG5ldyBzYW1wbGUgaXMgaW1wdXRlZCBieSBmaW5kaW5nIHRoZSBzYW1wbGVzIGluIHRoZSB0cmFpbmluZyBzZXQgImNsb3Nlc3QiIHRvIGl0IGFuZCBhdmVyYWdlcyB0aGVzZSBuZWFyYnkgcG9pbnRzIHRvIGZpbGwgaW4gdGhlIHZhbHVlLiINCg0KS3VobiwgTWF4IGFuZCBKb2huc29uLCBLamVsbCwgPHU+QXBwbGllZCBQcmVkaWN0aXZlIE1vZGVsaW5nPC91PiwgcGcuIDQyDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE0xX0ltcHV0ZWQgPC0ga05OKEFUTTEsIHZhcmlhYmxlID0gYygiQ2FzaCIpLCBrPTUpDQoNCkFUTTFfSU1QIDwtIEFUTTFfSW1wdXRlZFtBVE0xX0ltcHV0ZWQkQ2FzaF9pbXAgPT0gVFJVRSxdDQpgYGANCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShBVE0xX0lNUCwibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQo8Yj48dT5BVE0yPC91PjwvYj4NCg0KRm9yIEFUTTIsIHRoZXJlIGFyZSAyIE5BIHZhbHVlcywgYW5kIEkgdXNlZCB0aGUgc2FtZSBpbXB1dGF0aW9uIHN0cmF0ZWd5DQoNCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCkFUTTJfSW1wdXRlZCA8LSBrTk4oQVRNMiwgdmFyaWFibGUgPSBjKCJDYXNoIiksIGs9NSkNCg0KQVRNMl9JTVAgPC0gQVRNMl9JbXB1dGVkW0FUTTJfSW1wdXRlZCRDYXNoX2ltcCA9PSBUUlVFLF0NCmBgYA0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTJfSU1QLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQojIyMgSWRlbnRpZnkgYW5kIEFkZHJlc3MgT3V0bGllcnMgZm9yIGVhY2ggQVRNDQoNCg0KVGhlIGJveCBhbmQgd2hpc2tlciBwbG90cyBiZWxvdyBzaG93IHRoYXQgQVRNMSBhbmQgQVRNNCBoYXZlIG91dGxpZXJzIHdoaWxlIEFUTTMgY29udGFpbnMgbm8gZGF0YSBhdCBhbGwgZXhjZXB0IGZvciB0aHJlZSBlbnRyaWVzLiANCg0KYGBge3IgZmlnMywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPSAxNSwgZmlnLmFsaWduPSdjZW50ZXInfQ0KcGFyKG1mcm93PWMoMiwyKSkNCg0KYm94cGxvdChBVE0xX0ltcHV0ZWQkQ2FzaCAsIGNvbD0icmVkIiAsIHhsYWI9IkFUTTEgQ2FzaCIpDQoNCmJveHBsb3QoQVRNMl9JbXB1dGVkJENhc2ggLCBjb2w9ImJsdWUiICwgeGxhYj0iQVRNMiBDYXNoIikNCg0KYm94cGxvdChBVE0zJENhc2gsIGNvbD0ieWVsbG93IiAsIHhsYWI9IkFUTTMgQ2FzaCIpDQoNCmJveHBsb3QoQVRNNCRDYXNoICwgY29sPSJvcmFuZ2UiICwgeGxhYj0iQVRNNCBDYXNoIikNCg0KDQoNCmBgYA0KDQo8dT4gVGhlIFR1a2V5IE1ldGhvZDwvdT4NCg0KSW52ZW50ZWQgYnkgbWF0aGVtYXRpY2lhbiwgSm9obiBUdWtleS4gIlR1a2V5IEZlbmNlcyB1c2VzIHRoZSBpbnRlcnF1YXJ0aWxlIHJhbmdlICgiSVFSIikgdG8gZmxhZyBvYnNlcnZhdGlvbnMgKGZpbmFuY2lhbCB0cmFuc2FjdGlvbnMgaW4gdGhpcyBjYXNlKSB0aGF0IGFyZSBjb25zaWRlcmVkIG91dGxpZXJzLiBUdWtleSBGZW5jZXMgZGVmaW5lcyBhbiBvdXRsaWVyIGJhc2VkIG9uIHRoZSBiZWxvdyBmb3JtdWxhOiBPdXRsaWVyID0gVHJhbnNhY3Rpb24gPiBRMyArIDEuNSB4IElRUiBPUiBUcmFuc2FjdGlvbiA8IFExLTEuNSB4IElRUiINCg0KaHR0cHM6Ly9tZWRpdW0uY29tL21hcmlvLWJ1cnN0ZWluL2ltcGxlbWVudGluZy10dWtleS1vdXRsaWVyLWRldGVjdGlvbi1pbi1tLWEtZHVlLWRpbGlnZW5jZS0zNzRlZmE5YzM4Nw0KDQpJbiB0aGlzIHNlY3Rpb24sIEkgY3JlYXRlZCB0d28gZnVuY3Rpb25zIHRoYXQgY2FuIGlkZW50aWZ5IG91dGxpZXJzLiBUaGUgZnVuY3Rpb24sIElkZW50aWZ5X091dGxpZXIsIHVzZXMgdGhlIFR1a2V5IG1ldGhvZCwgd2hlcmUgb3V0bGllcnMgYXJlIGlkZW50aWZpZWQgYnkgYmVpbmcgYmVsb3cgUTEtMS41KklRUiBhbmQgYWJvdmUgUTMrMS41KklRUi4gVGhlIHNlY29uZCBmdW5jdGlvbiwgdGFnX291dGxpZXIsIHJldHVybnMgYSBiaW5hcnkgbGlzdCBvZiB2YWx1ZXMsICJBY2NlcHRhYmxlIiBvciAiT3V0bGllciIgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBkYXRhZnJhbWUuDQoNCg0KYGBge3J9DQpJZGVudGlmeV9PdXRsaWVyIDwtIGZ1bmN0aW9uKHZhbHVlKXsNCg0KICAgIGludGVycXVhcnRpbGVfcmFuZ2UgPSBJUVIoc29ydCh2YWx1ZSksbmEucm0gPSBUUlVFKQ0KICAgIHExID0gbWF0cml4KGMocXVhbnRpbGUoc29ydCh2YWx1ZSksbmEucm0gPSBUUlVFKSkpWzJdDQogICAgcTMgPSBtYXRyaXgoYyhxdWFudGlsZShzb3J0KHZhbHVlKSxuYS5ybSA9IFRSVUUpKSlbNF0NCiAgICBsb3dlciA9IHExLSgxLjUqaW50ZXJxdWFydGlsZV9yYW5nZSkNCiAgICB1cHBlciA9IHEzKygxLjUqaW50ZXJxdWFydGlsZV9yYW5nZSkNCiAgICANCiAgICBib3VuZCA8LSBjKGxvd2VyLCB1cHBlcikNCiAgICANCiAgICByZXR1cm4gKGJvdW5kKQ0KfQ0KDQpgYGANCg0KDQpgYGB7cn0NCnRhZ19vdXRsaWVyIDwtIGZ1bmN0aW9uKHZhbHVlKSB7DQogICAgDQogICBib3VuZGFyaWVzIDwtIElkZW50aWZ5X091dGxpZXIodmFsdWUpDQogICB0YWdzIDwtIGMoKQ0KICAgY291bnRlciA9IDENCiAgICBmb3IgKGkgaW4gYXMubnVtZXJpYyh2YWx1ZSkpDQogICAgew0KDQogICAgICAgIGlmIChpID49IGJvdW5kYXJpZXNbMV0gJiBpIDw9IGJvdW5kYXJpZXNbMl0pew0KICAgICAgICAgIHRhZ3NbY291bnRlcl0gPC0gIkFjY2VwdGFibGUiDQogICAgICAgIH0gZWxzZXsNCiAgICAgICAgICB0YWdzW2NvdW50ZXJdIDwtICJPdXRsaWVyIg0KICAgICAgICB9DQogICAgICANCiAgICAgIGNvdW50ZXIgPSBjb3VudGVyICsxDQogICAgfQ0KICAgDQogICByZXR1cm4gKHRhZ3MpDQp9DQpgYGANCg0KDQpgYGB7cn0NCnRhZ3MxPC0gdGFnX291dGxpZXIoQVRNMV9JbXB1dGVkJENhc2gpDQpBVE0xX0ltcHV0ZWQkQ2FzaF9PdXRsaWVyIDwtIHRhZ3MxDQoNCnRhZ3MyPC0gdGFnX291dGxpZXIoQVRNMl9JbXB1dGVkJENhc2gpDQpBVE0yX0ltcHV0ZWQkQ2FzaF9PdXRsaWVyIDwtIHRhZ3MyDQoNCnRhZ3MzPC0gdGFnX291dGxpZXIoQVRNMyRDYXNoKQ0KQVRNMyRDYXNoX091dGxpZXIgPC0gdGFnczMNCg0KdGFnczQ8LSB0YWdfb3V0bGllcihBVE00JENhc2gpDQpBVE00JENhc2hfT3V0bGllciA8LSB0YWdzNA0KYGBgDQoNCg0KPGI+QVRNMTwvYj4NCg0KDQpBZnRlciBhcHBseWluZyB0aGUgZnVuY3Rpb25zIGFuZCB0YWdnaW5nIHRoZSBvdXRsaWVycywgd2Ugc2VlIHRoYXQgdGhlcmUgYXJlIDUxIG91dGxpZXJzIGluIEFUTTEuIE1vc3Qgb2YgdGhlIG91dGxpZXJzIGFyZSBiZWxvdyB0aGUgZmlyc3QgcXVhcnRpbGUuIFRvIGhhbmRsZSB0aGUgb3V0bGllcnMsIEkgd2lsbCBXaW5zb3JpemUgdGhlIGRhdGEuIE91dGxpZXJzIG91dHNpZGUgb2YgMS41ICogdGhlIElRUiB3aWxsIGJlIHJlcGxhY2VkIHdpdGggZWl0aGVyIHRoZSBsb3dlciBvciB1cHBlciBib3VuZGFyeS4NCg0KIldpbnNvcml6aW5nIG9yIHdpbnNvcml6YXRpb24gaXMgdGhlIHRyYW5zZm9ybWF0aW9uIG9mIHN0YXRpc3RpY3MgYnkgbGltaXRpbmcgZXh0cmVtZSB2YWx1ZXMgaW4gdGhlIHN0YXRpc3RpY2FsIGRhdGEgdG8gcmVkdWNlIHRoZSBlZmZlY3Qgb2YgcG9zc2libHkgc3B1cmlvdXMgb3V0bGllcnMuIEl0IGlzIG5hbWVkIGFmdGVyIHRoZSBlbmdpbmVlci10dXJuZWQtYmlvc3RhdGlzdGljaWFuIENoYXJsZXMgUC4gV2luc29yICgxODk1LTE5NTEpLiBUaGUgZWZmZWN0IGlzIHRoZSBzYW1lIGFzIGNsaXBwaW5nIGluIHNpZ25hbCBwcm9jZXNzaW5nLiINCg0KaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2luc29yaXppbmcNCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCkFUTTFfT3V0bGllciA8LSBoZWFkKEFUTTFfSW1wdXRlZFtBVE0xX0ltcHV0ZWQkQ2FzaF9PdXRsaWVyID09ICJPdXRsaWVyIiwgXSkNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTFfT3V0bGllciwibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNCmBgYHtyfQ0KYm91bmRhcmllcyA8LSBJZGVudGlmeV9PdXRsaWVyKEFUTTFfSW1wdXRlZCRDYXNoKQ0KZm9yKGkgaW4gQVRNMV9JbXB1dGVkJENhc2gpew0KICBpZiAoaSA8IGJvdW5kYXJpZXNbMV0pew0KICAgIEFUTTFfSW1wdXRlZCRDYXNoW0FUTTFfSW1wdXRlZCRDYXNoID09IGldIDwtIGJvdW5kYXJpZXNbMV0NCiAgfQ0KICBlbHNlIGlmIChpID4gYm91bmRhcmllc1syXSl7DQogICAgQVRNMV9JbXB1dGVkJENhc2hbQVRNMV9JbXB1dGVkJENhc2g9PWldIDwtIGJvdW5kYXJpZXNbMl0NCiAgfQ0KfQ0KDQpgYGANCg0KYGBge3J9DQpib3hwbG90KEFUTTFfSW1wdXRlZCRDYXNoKQ0KYGBgDQoNClRoZSBib3ggcGxvdCBzaG93cyB0aGF0IHRoZSBvdXRsaWVycyBpbiBBVE0xIGhhdmUgYmVlbiByZXBsYWNlZCBhbmQgQVRNMSBpcyBjbGVhbmVkOg0KDQpgYGB7cn0NCkFUTTFfQ2xlYW5lZCA8LSBBVE0xX0ltcHV0ZWQNCmhlYWQoQVRNMV9DbGVhbmVkKQ0KYGBgDQoNCg0KDQo8Yj5BVE0yPC9iPg0KDQpXZSBzZWUgdGhhdCB0aGUgdHdvIGZ1bmN0aW9ucyBkaWQgbm90IGlkZW50aWZ5IGFueSBvdXRsaWVycyBpbiBBVE0yLiBUaGUgYm94IGFuZCB3aGlza2VycyBwbG90IGNvbmZpcm1zIHRoaXMsIGFuZCBldmVuIHRob3VnaCB0aGUgaGlzdG9ncmFtIGZvciBBVE0yIGlzIG5vdCBwZXJmZWN0bHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHRoZSBza2V3IGlzIHNtYWxsIGVub3VnaC4NCg0KDQpgYGB7cn0NCkFUTTJfSW1wdXRlZCAlPiUgDQogIGZpbHRlcihDYXNoX091dGxpZXIgPT0gJ091dGxpZXInKSAlPiUgDQogIGFycmFuZ2UoQ2FzaCkNCmBgYA0KDQoNCmBgYHtyfQ0KYm94cGxvdChBVE0yX0ltcHV0ZWQkQ2FzaCkNCmBgYA0KDQoNCmBgYHtyfQ0KaGlzdChBVE0yX0ltcHV0ZWQkQ2FzaCkNCmBgYA0KDQpgYGB7cn0NCnNrZXcoQVRNMl9JbXB1dGVkJENhc2gpDQpgYGANCg0KQVROMiBoYXMgYmVlbiBjbGVhbmVkOg0KDQpgYGB7cn0NCkFUTTIgPC0gQVRNMl9JbXB1dGVkDQpgYGANCg0KDQoNCjxiPkFUTTM8L2I+DQoNCjxpPktleSBBc3N1bXB0aW9uPC9pPg0KDQo5OSUgb2YgdGhlIHZhbHVlcyBmb3IgQVRNMyBhcmUgemVyb2VzIGV2ZW4gdGhvdWdoIHRoZXJlIGFyZSBkYXRlIGVudHJpZXMgZm9yIHRoZSBBVE0uIEkgYW0gbWFraW5nIHRoZSBhc3N1bXB0aW9uIHRoYXQgQVRNMyB3YXMgbWFsZnVuY3Rpb25pbmcgb3IgYmxvY2tlZCBpbiBzb21lIHdheSB1bnRpbCBBcHJpbCAyMDEwLiBUaHVzLCBJIGNhbm5vdCByZW1vdmUgdGhlIE91dGxpZXJzIG5vciBjYW4gSSBtYWtlIGFueSByZWFzb25hYmxlIGZvcmVjYXN0LiBJZiBJIHRha2UgYW4gYXZlcmFnZSBvZiB0aGUgbGFzdCB0aHJlZSBkYXlzICgkODcuNjYpIEFUTTMgd291bGQgbm90IGhhdmUgYmVlbiBhYmxlIHRvIGZ1bGZpbGwgdGhlIDA0LzI4LzIwMTAgd2l0aGRyYXdhbC4gSSBhbSBnb2luZyB0byBuZWVkIG1vcmUgZGF0YSB0byBtYWtlIGFueSBhc3N1bXB0aW9uIGZvciB0aGlzIG1hY2hpbmUuIFRodXMsIEkgYW0gZ29pbmcgdG8gdXNlIGEgZGVmYXVsdCB2YWx1ZSBvZiAxMDAuIA0KDQoNCmBgYHtyfQ0KbnJvdyhBVE0zW0FUTTMkQ2FzaCA9PTAsXSkgLyBucm93KEFUTTMpDQpgYGANCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCkFUTTNfVGFpbCA8LSB0YWlsKEFUTTMsNSkNCmBgYA0KDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoQVRNM19UYWlsLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmJveHBsb3QoQVRNMyRDYXNoKQ0KYGBgDQoNCg0KYGBge3J9DQpoaXN0KEFUTTMkQ2FzaCkNCmBgYA0KDQpgYGB7cn0NCnNrZXcoQVRNMyRDYXNoKQ0KYGBgDQoNCg0KDQo8Yj5BVE00PC9iPg0KDQpJIHNlZSB0aGF0IHRoZXJlIGFyZSB0d28gdmVyeSBsYXJnZSBvdXRsaWVycyBmb3IgQVRNNCB3aGljaCBza2V3cyB0aGUgZGF0YSB0byB0aGUgcmlnaHQuIEkgdXNlZCB0aGUgc2FtZSBXaW5zb3IgYXBwcm9hY2ggZm9yIGhhbmRsaW5nIG91dGxpZXJzIGFzIEkgZGlkIHdpdGggQVRNMS4gDQoNCmBgYHtyfQ0KQVRNNCAlPiUgDQogIGZpbHRlcihDYXNoX091dGxpZXIgPT0gJ091dGxpZXInKSAlPiUgDQogIGFycmFuZ2UoQ2FzaCkNCmBgYA0KDQoNCmBgYHtyfQ0KYm94cGxvdChBVE00JENhc2gpDQpgYGANCg0KDQpgYGB7cn0NCmhpc3QoQVRNNCRDYXNoKQ0KYGBgDQoNCg0KYGBge3J9DQpib3VuZGFyaWVzIDwtIElkZW50aWZ5X091dGxpZXIoQVRNNCRDYXNoKQ0KZm9yKGkgaW4gQVRNNCRDYXNoKXsNCiAgaWYgKGkgPCBib3VuZGFyaWVzWzFdKXsNCiAgICBBVE00JENhc2hbQVRNNCRDYXNoID09IGldIDwtIGJvdW5kYXJpZXNbMV0NCiAgfQ0KICBlbHNlIGlmIChpID4gYm91bmRhcmllc1syXSl7DQogICAgQVRNNCRDYXNoW0FUTTQkQ2FzaCA9PSBpXSA8LSBib3VuZGFyaWVzWzJdDQogIH0NCn0NCg0KYGBgDQoNCmBgYHtyfQ0KYm94cGxvdChBVE00JENhc2gpDQpgYGANCg0KYGBge3J9DQpBVE00ICU+JSANCiAgZmlsdGVyKENhc2hfT3V0bGllciA9PSAnT3V0bGllcicpICU+JSANCiAgYXJyYW5nZShDYXNoKQ0KYGBgDQoNCg0KDQojIyMgQ29udmVydCB0aGUgRGF0YSBpbnRvIGEgVGltZSBTZXJpZXMgDQoNCk15IGN1c3RvbSBmdW5jdGlvbiBiZWxvdyBjb252ZXJ0cyB0aGUgdGhyZWUgZGF0YXNldHMgdG8gdGltZSBzZXJpZXMuIA0KDQoNCmBgYHtyfQ0KY29udmVydF90b190cyA8LSBmdW5jdGlvbihkYXRhKXsNCiAgICBwcmVwcGVkIDwtIGRhdGEgJT4lIA0KICAgICAgICAgICAgICAgIHNlbGVjdChEQVRFLCBDYXNoKQ0KICAgIHByZXBwZWQkREFURSA8LSBhcy5EYXRlKHByZXBwZWQkREFURSkNCiAgICB0aW1lX3NlcmllcyA8LSB0cyhwcmVwcGVkJENhc2gsIGZyZXF1ZW5jeSA9IDcpDQogICAgcmV0dXJuICh0aW1lX3NlcmllcykNCn0NCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpBVE0xX3RzIDwtIGNvbnZlcnRfdG9fdHMoQVRNMV9DbGVhbmVkKQ0KQVRNMl90cyA8LSBjb252ZXJ0X3RvX3RzKEFUTTIpDQpBVE00X3RzIDwtIGNvbnZlcnRfdG9fdHMoQVRNNCkNCg0KYGBgDQoNCiMjIyBSZXZpZXcgdGltZSBzZXJpZXMgcGxvdHMNCjxiPkFUTTFfdHM8L2I+DQoNClRoZSBhdXRvcGxvdCBiZWxvdyBzaG93cyB0aGF0IHRoZSBBVE0xIGNhc2ggd2l0aGRyYXdhbCBkYXRhIHNob3dzIGFuIHVwdGljayBpbiB0aGUgZmlyc3QgMTAgd2Vla3MsIHRoZW4gYSBzbWFsbCBkcm9wIGZyb20gd2Vla3MgMjAgdG8gMzAsIGFuZCBmaW5hbGx5IGEgbGV2ZWxpbmcgb2ZmIGZyb20gd2Vla3MgMzggdG8gNTMuDQoNCmBgYHtyfQ0KYXV0b3Bsb3QoQVRNMV90cykgKyBnZW9tX3Ntb290aChtZXRob2Q9ImF1dG8iKQ0KYGBgDQpUaGUgc2Vhc29uYWwsIHBvbGFyLCBzdWJzZXJpZXMgcGxvdHMgb2YgQVRNMSBiZWxvdyBzaG93IHRoYXQgZm9yIG1vc3Qgb2YgdGhlIGRheXMgb2YgdGhlIHdlZWsgd2l0aGRyYXdhbHMgaGF2ZSB0aGUgc2FtZSBvciBuZWFybHkgdGhlIHNhbWUgYWN0aXZpdHkgZXhjZXB0IGZvciBTYXR1cmRheXMgd2hlbiB0aGVyZSdzIGEgaHVnZSBkcm9wIG9mZi4gVGhpcyBtYXkgbWVhbiB0aGF0IHRoZSBzY2hlZHVsaW5nIGZvciByZS1maWxsaW5nIEFUTTEgbmVlZHMgdG8gYmUgbG9va2VkIGF0LiANCg0KYGBge3J9DQpnZ3NlYXNvbnBsb3QoQVRNMV90cykNCmBgYA0KDQoNCg0KYGBge3J9DQpnZ3NlYXNvbnBsb3QoQVRNMV90cywgeWVhci5sYWJlbHM9RkFMU0UsIGNvbnRpbnVvdXM9VFJVRSwgcG9sYXIgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dzdWJzZXJpZXNwbG90KEFUTTFfdHMpDQpgYGANCg0KDQpUaGUgU2Vhc29uYWwgYW5kIFRyZW5kIGRlY29tcG9zaXRpb24gdXNpbmcgTG9lc3MgKFNUTCkgc2hvd3MgdGhhdCB0aGVyZSBpcyBub3QgYSBkaXNjZXJuYWJsZSB0cmVuZCBvdmVyIHRoZSBsZW5ndGggb2YgdGhlIHRpbWUgc2VyaWVzIHdpdGggdGhlIGV4Y2VwdGlvbnMgYXQgdGhlIGxvdyBwb2ludHMgYXQgdGhlIDI1dGggYW5kIDQzcmQgd2Vla3MuIFdlIGFsc28gc2VlIGluIHRoZSBzZWFzb25hbCBwbG90cyBsZXNzIG9mIGEgdmFyaWF0aW9uIGJldHdlZW4gdGhlIDIybmQgYW5kIHRoZSA0NHRoIHdlZWtzLiANCg0KDQoNCmBgYHtyfQ0KQVRNMV90cyAlPiUgbXN0bCh0LndpbmRvdyA9IDcsIHJvYnVzdD1UUlVFKSAlPiUgYXV0b3Bsb3QoKQ0KDQpgYGANClRoZXNlIHBsb3RzIHNob3cgdGhhdCB0aGUgZGF0YSBpcyBub3Qgc3RhdGlvbmFyeS4gQWxzbywgdGhlcmUgYXJlIHN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbnMgd2l0aCBsYWdzIGF0IGRheXMgNywgMTQsIGFuZCAyMS4NCg0KYGBge3J9DQpnZ3RzZGlzcGxheShBVE0xX3RzLCBtYWluPSJBVE0xIFdpdGhkcmF3YWxzIikNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGggPSAyMH0NCmdnbGFncGxvdChBVE0xX3RzLCBsYWdzID0gMjEpDQpgYGANCg0KDQoNCjxiPkFUTTJfdHM8L2I+DQoNClRoZSBhdXRvcGxvdCBmb3IgQVRNMiBzaG93IGEgc2xpZ2h0IGRvd253YXJkIHRyZW5kIG92ZXIgdGhlIHNwYW4gb2YgdGhlIHRpbWUgc2VyaWVzIGFsb25nIHdpdGggYSBkZXNjcmVhc2UgaW4gdGhlIHNlYXNvbmFsIHZhcmlhdGlvbi4gDQpgYGB7cn0NCmF1dG9wbG90KEFUTTJfdHMpICsgZ2VvbV9zbW9vdGgobWV0aG9kPSJhdXRvIikNCmBgYA0KVGhlIHNlYXNvbmFsIHBsb3Qgb2YgQVRNMiBzaG93IHRoYXQgd2l0aGRyYXdscyBjaGFuZ2Ugb3ZlciB0aW1lLiBJbiB0aGUgbGF0ZXIgd2Vla3MsIFdlZG5lc2RheXMgYW5kIFRodXJzZGF5cyBoYXZlIHNlZSBsZXNzIHdpdGhkcmF3YWxzIHdoaWxlIEZyaWRheXMgYW5kIFNhdHVyZGF5cyBoYXZlIHNlZW4gcGVha3MuIFRoaXMgaXMgYSByZXZlcnNhbCBvZiB0aGUgcGF0dGVybiBzZWVuIGluIGVhcmxpZXIgd2Vla3MuIA0KDQpUaGUgcG9sYXIgYW5kIHN1YnNlcmllcyBwbG90cyBzaG93IGEgYmlnIGRyb3Agb2ZmIGluIEZyaWRheXMgYW5kIFNhdHVyZGF5IHdpdGhkcmF3YWxzLiANCg0KDQoNCmBgYHtyfQ0KZ2dzZWFzb25wbG90KEFUTTJfdHMpDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ2dzZWFzb25wbG90KEFUTTJfdHMsIHllYXIubGFiZWxzPUZBTFNFLCBjb250aW51b3VzPVRSVUUsIHBvbGFyID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCmdnc3Vic2VyaWVzcGxvdChBVE0yX3RzKQ0KYGBgDQoNClRoZSBzZWFzb25hbCBwbG90IGZvciBBVE0yIGRvZXMgbm90IHNob3cgYW4gaW5jcmVhc2Ugb3IgZGVjcmVhc2UgaW4gdGhlIHRyZW5kIG92ZXIgdGltZS4gDQoNCmBgYHtyfQ0KQVRNMl90cyAlPiUgbXN0bCh0LndpbmRvdyA9IDcsIHJvYnVzdD1UUlVFKSAlPiUgYXV0b3Bsb3QoKQ0KDQpgYGANClRoZXNlIHBsb3RzIHNob3cgdGhhdCB0aGUgZGF0YSBpcyBub3Qgc3RhdGlvbmFyeS4gQWxzbywgdGhlcmUgYXJlIHN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbnMgd2l0aCBsYWdzIGF0IGRheXMgNywgMTQsIGFuZCAyMS4NCg0KYGBge3J9DQpnZ3RzZGlzcGxheShBVE0yX3RzLCBtYWluPSJBVE0yIFdpdGhkcmF3YWxzIikNCmBgYA0KVGhlIGxhZyBwbG90cyBzaG93IHRoZSBzdHJvbmcgY29ycmVsYXRpb24gYXQgbGFncyA3LCAxNCwgYW5kIDIxLiANCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0KZ2dsYWdwbG90KEFUTTJfdHMsIGxhZ3MgPSAyMSkNCmBgYA0KDQoNCjxiPkFUTTRfdHM8L2I+DQoNCg0KVGhlIGF1dG9wbG90IGZvciBBVE00IHNob3cgYSB2ZXJ5IHNsaWdodCBkb3dud2FyZCBiZWdpbm5pbmcgYXQgdGhlIDIwdGggd2Vlay4gVGhlIHRyZW5kIHRoZW4gZXZlbnMgb3V0IGFmdGVyIHdlZWsgMzUuICANCg0KYGBge3J9DQphdXRvcGxvdChBVE00X3RzKSArIGdlb21fc21vb3RoKG1ldGhvZD0iYXV0byIpDQpgYGANCg0KVGhlIHNlYXNvbmFsLCBwb2xhciwgYW5kIHN1YnNlcmllcyBwbG90cyBzaG93IHRoZSBtb3N0IGFjdGl2aXR5IG9uIFN1bmRheXMgYW5kIFRodXJkYXlzIHdpdGggYSBodWdlIGRyb3Agb2ZmIG9uIFNhdHVyZGF5cy4gDQoNCg0KYGBge3J9DQpnZ3NlYXNvbnBsb3QoQVRNNF90cykNCmBgYA0KDQoNCg0KYGBge3J9DQpnZ3NlYXNvbnBsb3QoQVRNNF90cywgeWVhci5sYWJlbHM9RkFMU0UsIGNvbnRpbnVvdXM9VFJVRSwgcG9sYXIgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dzdWJzZXJpZXNwbG90KEFUTTRfdHMpDQpgYGANCg0KVGhlIGlzIG5vIGRpc2Nlcm5hYmxlIHRyZW5kIGZvciBBVE00IGFsdGhvdWdoIHRoZSBzZWFzb25hbCB2YXJpYXRpb24gYXJvdW5kIGxhZyA0MCBzZWVtcyB0byB0aWdodGVuLg0KDQpgYGB7cn0NCkFUTTRfdHMgJT4lIG1zdGwodC53aW5kb3cgPSA3LCByb2J1c3Q9VFJVRSkgJT4lIGF1dG9wbG90KCkNCg0KYGBgDQpUaGVzZSBwbG90cyBzaG93IHRoYXQgdGhlIGRhdGEgaXMgbm90IHN0YXRpb25hcnkuIEFsc28sIHRoZXJlIGFyZSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb25zIHdpdGggbGFncyBhdCBkYXlzIDcgYW5kIDE0Lg0KDQpgYGB7cn0NCmdndHNkaXNwbGF5KEFUTTRfdHMsIG1haW49IkFUTTQgV2l0aGRyYXdhbHMiKQ0KYGBgDQpUaGUgbGFnIHBsb3RzIHNob3cgdGhlIHN0cm9uZyBjb3JyZWxhdGlvbiBhdCBsYWdzIDcgYW5kIDE0LiANCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0KZ2dsYWdwbG90KEFUTTRfdHMsIGxhZ3MgPSAyMSkNCmBgYA0KDQoNCiMjIElJLiBFWFBFUklNRU5UQVRJT04gQU5EIFJFU1VMVFMNCg0KSW4gdGhpcyBzZWN0aW9uLCBJIHNwbGl0IHRoZSBkYXRhIGludG8gdHJhaW4gYW5kIHRlc3Qgc2V0cy4gIEkgdGhlbiBldmFsdWF0ZWQgYSByYW5nZSBvZiB0aW1lIHNlcmllcyBtb2RlbHM6IDxici8+DQoNCjx1bD4NCjxsaT5TRUFTT05BTCBOQUlWRSBGT1JFQ0FTVDwvbGk+DQo8bGk+U0lNUExFIEVYUE9ORU5USUFMIFNNT09USElORyAoU0VTKTwvbGk+DQo8bGk+SE9MVCBXSU5URVJTPC9saT4NCjxsaT5IT0xUIFdJTlRFUlMgd2l0aCBEQU1QRUQgTUVUSE9EPC9saT4NCjxsaT5BVVRPIEFSSU1BIDwvbGk+DQo8L3VsPg0KDQo8YnIvPg0KDQo8aT5LZXkgQXNzdW1wdGlvbjwvaT4NCg0KSSB1c2VkIGRpZmZlcmVudCBjbGFzc2VzIG9mIG1vZGVscyBmcm9tIHRoZSBiYXNpYyB0byB0aGUgbW9yZSBhZHZhbmNlZCB0byBnYXVnZSB3aGljaCBvbmUgd291bGQgaGF2ZSB0aGUgYmVzdCBSTVNFIHNjb3JlLiANCg0KDQoNCiMjIyBTcGxpdCB0aGUgVGltZSBTZXJpZXMNCg0KQmVsb3cgSSBzcGxpdCBlYWNoIHRpbWUgc2VyaWVzIGludG8gYSB0cmFpbi90ZXN0IHNwbGl0LCBhbmQgcGxvdHRlZCBlYWNoIG9uZS4NCg0KDQpgYGB7cn0NCkFUTTFfdHJhaW4gPC0gd2luZG93KEFUTTFfdHMsc3RhcnQ9YygxLDEpLCBlbmQ9Yyg0Miw3KSkNCkFUTTFfdGVzdCA8LSB3aW5kb3coQVRNMV90cyxzdGFydD1jKDQzLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KQVRNMl90cmFpbiA8LSB3aW5kb3coQVRNMl90cyxzdGFydD1jKDEsMSksIGVuZD1jKDQyLDcpKQ0KQVRNMl90ZXN0IDwtIHdpbmRvdyhBVE0yX3RzLHN0YXJ0PWMoNDMsMSkpDQpgYGANCg0KYGBge3J9DQpBVE00X3RyYWluIDwtIHdpbmRvdyhBVE00X3RzLHN0YXJ0PWMoMSwxKSwgZW5kPWMoNDIsNykpDQpBVE00X3Rlc3QgPC0gd2luZG93KEFUTTRfdHMsc3RhcnQ9Yyg0MywxKSkNCmBgYA0KDQo8Yj5QbG90IHRoZSBTcGxpdCBUaW1lIFNlcmllcyA8L2I+DQoNCmBgYHtyfQ0KYXV0b3Bsb3QoQVRNMV90cykgKw0KICBhdXRvbGF5ZXIoQVRNMV90cmFpbiwgIHNlcmllcz0iVHJhaW5pbmciKSArDQogIGF1dG9sYXllcihBVE0xX3Rlc3QsIHNlcmllcz0iVGVzdCIpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChBVE0yX3RzKSArDQogIGF1dG9sYXllcihBVE0yX3RyYWluLCAgc2VyaWVzPSJUcmFpbmluZyIpICsNCiAgYXV0b2xheWVyKEFUTTJfdGVzdCwgc2VyaWVzPSJUZXN0IikNCmBgYA0KDQpgYGB7cn0NCmF1dG9wbG90KEFUTTRfdHMpICsNCiAgYXV0b2xheWVyKEFUTTRfdHJhaW4sICBzZXJpZXM9IlRyYWluaW5nIikgKw0KICBhdXRvbGF5ZXIoQVRNNF90ZXN0LCBzZXJpZXM9IlRlc3QiKQ0KYGBgDQoNCkVhY2ggdGltZSBzZXJpZXMgaGFzIGJlZW4gc3BsaXQgaW50byA0MywgNy1kYXkgcGVyaW9kcyBmb3IgdGhlIFRyYWluaW5nIHNldCBhbmQgMTAsIDctZGF5IHBlcmlvZHMgZm9yIHRoZSBUZXN0IHNldC4gSSBzZXQgdGhlIGZvcmVjYXNyIGhvcml6b24gdG8gaD03MSBkdXJpbmcgdHJhaW5pbmcgb2YgZWFjaCBtb2RlbCwgYW5kIHRoZW4gZXZhbHVhdGUgZWFjaCBtb2RlbCdzIDcxIGRheSBmb3JlY2FzdCBhZ2FpbnN0IHRoZSB0ZXN0IHNldC4NCg0KYGBge3J9DQpoPTcxDQpgYGANCg0KDQojIyMgQXBwbHkgdGhlIE1vZGVsczoNCg0KPGI+IEFUTTE8L2I+DQoNCjxiPlNFQVNPTkFMIE5BSVZFIEZPUkVDQVNUPC9iPg0KDQpCZWdpbm5pbmcgd2l0aCB0aGUgU2Vhc29uYWwgTmFpdmUgZm9yZWNhc3Qgd2hlcmUgZWFjaCBmb3JlY2FzdCB0byBiZSBlcXVhbCB0byB0aGUgbGFzdCBvYnNlcnZlZCB2YWx1ZSBmcm9tIHRoZSBzYW1lIHNlYXNvbi4gVGhpcyBpcyBjb25zaWRlcmVkIHRvIGJlIG9uZSBvZiB0aGUgbW9yZSBiYXNpYyB0aW1lIHNlcmllcyBtb2RlbC4gSXQgcHJvdmlkZXMgYSBiYWxscGFyayBlc3RpbWF0ZSBmb3IgdGhlIGFudGljaXBhdGVkIGFtb3VudCBvZiB3aXRoZHJhd2Fscy4gDQoNCkkgdHJhaW5lZCB0aGUgbW9kZWwgdG8gZm9yZWNhc3QgdGhlIG5leHQgNzEgZGF5cyAodGhlIGxlbmd0aCBvZiB0aGUgdGVzdCBzZXQpLiBUaGVuLCBJIGV2YWx1YXRlZCB0aGUgYWNjdXJhY3kgb2YgdGhlIG1vZGVsLiBUaGUgc2Vhc29uYWwgbmFpdmUgbWV0aG9kIHlpZWxkcyBhbiBSTVNFIG9mIDU0LjM3LiBBIGNoZWNrIG9mIHRoZSByZXNpZHVhbHMgc2hvd3MgdGhhdCB0aGVyZSBpcyBzdGlsbCBzb21lIGluZm9ybWF0aW9uIGxlYWthZ2UgaW4gdGhlIHNlYXNvbmFsIG5haXZlIG1vZGVsLiBBbHNvIHRoYXQgdGhlcmUgaXMgY29ycmVsYXRpb24gaW4gdGhlIGxhZ3MuVGhlIHZlcnkgc21hbGwgcC12YWx1ZSBmcm9tIHRoZSBManVuZy1Cb3ggdGVzdCBzaG93cyB0aGF0IHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIGluZGVwZW5kZW50Lg0KDQoNCg0KYGBge3J9DQpmb3JlY2FzdF9BVE0xX1dpdGhkcmF3YWwgPC0gc25haXZlKEFUTTFfdHJhaW4sIGg9aCkNCmF1dG9wbG90KGZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbCkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NClNOYWl2ZV9yZXN1bHRzIDwtIGFjY3VyYWN5KGZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbCxBVE0xX3Rlc3QpDQpgYGANCiANCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShTTmFpdmVfcmVzdWx0cywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQpgYGB7cn0NCmNoZWNrX3JlcyA8LSBjaGVja3Jlc2lkdWFscyhmb3JlY2FzdF9BVE0xX1dpdGhkcmF3YWwpDQpgYGANCg0KIA0KIA0KPGI+U0lNUExFIEVYUE9ORU5USUFMIFNNT09USElORyAoU0VTKTwvYj4NCg0KVGhlIG5leHQgbW9kZWwsIFNpbXBsZSBFeHBvbmVudGlhbCBTbW9vdGhpbmcgKFNFUyksIGFzc3VtZXMgbm8gdHJlbmQgbm9yIHNlYXNvbmFsaXR5IGluIHRoZSBkYXRhLiBTRVMgYXNzaWducyBsYXJnZXIgd2VpZ2h0cyB0byBtb3JlIHJlY2VudCBvYnNlcnZhdGlvbnMuICBUaGUgd2VpZ2h0cyBkZWNyZWFzZSBleHBvbmVudGlhbGx5IHRoZSBmdXJ0aGVyIGJhY2sgdGhlIG9ic2VydmF0aW9uIGlzLiBXZSBzZWUgdGhhdCB0aGUgU0VTJ3MgUk1TRSBvZiAyOS45OTU5NSBpcyBhbHJlYWR5IGxvd2VyIHRoYW4gdGhlIFNlYXNvbmFsIE5haXZlIG1vZGVsIHdoaWNoIHNob3dzIHRoYXQgbW9yZSBhZHZhbmNlZCBtb2RlbHMgbWF5IGdldCB1cyBjbG9zZXIgdG8gYSBiZXR0ZXIgZm9yZWNhc3QuDQoNCkEgY2hlY2sgb2YgdGhlIHJlc2lkdWFscyBzaG93cyB0aGF0IHRoZXJlIGlzIHN0aWxsIHNvbWUgaW5mb3JtYXRpb24gbGVha2FnZSBpbiB0aGUgU0VTIG1ldGhvZC4gVGhlcmUgYXJlIHN0cm9uZyBjb3JyZWxhdGlvbnMgaW4gdGhlIGxhZ3MgYXQgdGltZSBwZXJpb2QgNyBhbmQgMTQgd2hpY2ggbWVhbnMgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBub3QgV2hpdGUgTm9pc2UuIFRoZSB2ZXJ5IHNtYWxsIHAtdmFsdWUgZnJvbSB0aGUgTGp1bmctQm94IHRlc3Qgc2hvd3MgdGhhdCB3ZSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBpbmRlcGVuZGVudC4NCg0KYGBge3J9DQoNCkFUTTFfU0VTX0ZDIDwtIHNlcyhBVE0xX3RyYWluLCBoID0gaCkNCkFUTTFfU0VTX1Jlc3VsdHMgPC0gYWNjdXJhY3koQVRNMV9TRVNfRkMsIEFUTTFfdGVzdCkNCmBgYA0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTFfU0VTX1Jlc3VsdHMsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCg0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhBVE0xX1NFU19GQykNCmBgYA0KDQo8Yj5IT0xUIFdJTlRFUlM8L2I+DQoNClRoZSBuZXh0IG1vZGVsLCB0aGUgSG9sdCBXaW50ZXJzIG1vZGVsLCBpcyB1c2VkIHRvIGNhcHR1cmUgdHJlbmQgYW5kIHNlYXNvbmFsaXR5LiBUaGlzIGlzIGEgZGVwYXJ0dXJlIGZyb20gdGhlIGVhcmxpZXIgbW9kZWxzIHdoaWNoIHdlcmUgYmFzZWQgb24gcGFzdCBvYnNlcnZhdGlvbnMuIEkgdXNlZCB0aGUgYWRkaXRpdmUgbWV0aG9kIGJlY2F1c2UgYXMgd2Ugc2F3IGVhcmxpZXIsIHRoZXJlIGlzIG5vIGluY3JlYXNlIGluIHRyZW5kIG9yIHNlYXNvbmFsaXR5IGZvciB0aGlzIGRhdGEgb3ZlciB0aW1lLlRoZSBIT0xUIFdJTlRFUlMgYXBwcm9hY2ggc2hvd3MgdGhhdCB0aGUgUk1TRSBpcyBmb3IgdGhlIHRlc3Qgc2V0IGlzIDQ4LjY2IHdoaWNoIGlzIGhpZ2hlciB0aGFuIHRoZSB0d28gcHJldmlvdXMgbW9kZWxzLg0KDQpHaXZlbiB0aGUgc21hbGwgcC12YWx1ZSBhZ2Fpbiwgd2UgaGF2ZSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgc2F5IHRoYXQgdGhlIG1vZGVsIGlzIHNob3dpbmcgYSBsYWNrIG9mIGZpdC4gDQoNCg0KYGBge3J9DQpGb3JlY2FzdF9BVE0xX1dpdGhkcmF3YWxfQWRkaXRpdmUgPC0gaHcoQVRNMV90cmFpbiwgaCA9IGgsIHNlYXNvbmFsID0gImFkZGl0aXZlIikNCg0KYXV0b3Bsb3QoRm9yZWNhc3RfQVRNMV9XaXRoZHJhd2FsX0FkZGl0aXZlKQ0KYGBgDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE0xX0hXX1Jlc3VsdHMgPC0gYWNjdXJhY3koRm9yZWNhc3RfQVRNMV9XaXRoZHJhd2FsX0FkZGl0aXZlLCBBVE0xX3Rlc3QpDQpgYGANCg0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTFfSFdfUmVzdWx0cywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhGb3JlY2FzdF9BVE0xX1dpdGhkcmF3YWxfQWRkaXRpdmUpDQpgYGANCg0KPGI+SE9MVCBXSU5URVJTIHdpdGggREFNUEVEIE1FVEhPRDwvYj4NCg0KVGhlIEhPTFQgV0lOVEVSUyBEQU1QRUQgY3JlYXRlcyBhIHRyZW5kIGxpbmUgdGhhdCAiZGFtcGVucyIgb3IgZmxhdHRlbnMgdGhlIHRyZW5kIG92ZXIgdGltZS4gVGhpcyBhcHByb2FjaCBzaG93cyB0aGF0IHRoZSBSTVNFIGlzIGZvciB0aGUgdGVzdCBzZXQgaXMgNDUuNzY4NTQuIFRoZSByZXNpZHVhbHMgYXJlIHN0aWxsIG5vdCBzaG93aW5nIGluZGVwZW5kZW5jZS4gDQoNClRoZSBIb2x0IFdpbnRlcnMgYXBwcm9hY2hlcyBtYXkgbm90IHBlcmZvcm1pbmcgYXMgd2VsbCBhcyB0aGUgb3RoZXIgbW9kZWxzIHByaW1hcmlseSBkdWUgdG8gdGhlIGxhY2sgb2YgdHJlbmQgYW5kIHNlYXNvbmFsaXR5IGluIHRoZSBkYXRhLiANCg0KDQpgYGB7cn0NCkZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbF9BRERJVElWRV9EYW1wZWQgPC0gaHcoQVRNMV90cmFpbiwgaCA9IGgsIHNlYXNvbmFsID0gImFkZGl0aXZlIiwgZGFtcGVkPVRSVUUpDQoNCmF1dG9wbG90KEZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbF9BRERJVElWRV9EYW1wZWQpDQoNCmBgYA0KDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE0xX0hXRF9yZXN1bHRzIDwtIGFjY3VyYWN5KEZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbF9BRERJVElWRV9EYW1wZWQsIEFUTTFfdGVzdCkNCg0KYGBgDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTFfSFdEX3Jlc3VsdHMsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEZvcmVjYXN0X0FUTTFfV2l0aGRyYXdhbF9BRERJVElWRV9EYW1wZWQpDQpgYGANCg0KDQo8Yj5BUklNQSBNb2RlbHMgPC9iPg0KDQpUaGUgbmV4dCBtb2RlbCB0byB0cnkgaXMgdGhlIEFSSU1BIG1vZGVscyB3aGljaCBzdGFuZHMgZm9yIEF1dG8gUmVncmVzc2l2ZSBJbnRlZ3JhdGVkIE1vdmluZyBBdmVyYWdlIG1vZGVscy4gVG8gZXZhbHVhdGUgdGhlIG1vZGVsLCBJIHRlc3RlZCB3aGV0aGVyIEFUTTFfVHJhaW4gd2FzIHN0YXRpb25hcnksIGFuZCBpdCB3YXMgZ2l2ZW4gaXQgcC12YWx1ZSBvZiAwLjQwODEuIE5vIGRpZmZlcmVuY2luZyB3YXMgbmVlZGVkLiBJIHRoZW4gdGVzdGVkIGRpZmZlcmVudCBBcmltYSBtb2RlbHMsIGFuZCB0aGUgbW9kZWwgd2l0aCB0aGUgbG93ZXN0IEFJQ2Mgd2FzIEFSSU1BKDEsMCwxKS4gSSBjb25maXJtZWQgdGhlc2UgcmVzdWx0cyB1c2luZyBhdXRvIGFyaW1hIHdoaWNoIGFkZGVkIGEgc2Vhc29uYWwgY29tcG9uZW50IHRvIHRoZSBtb2RlbC4gVGhlIHJlc2lkdWFscyBmcm9tIHRoaXMgbW9kZWwgYWxzbyBzaG93IGluZGVwZW5kbmNlLiBUaGUgYmVzdCBtb2RlbCwgYXMgY29uZmlybWVkIGJ5IHRoZSBhdXRvLmFyaW1hIGZ1bmN0aW9uLCB3YXMgQVJJTUEoMSwwLDEpKDAsMSwxKVs3XSANCg0KVGhlIFJNU0UgZm9yIHRoZSBhdXRvLmFyaW1hIG1vZGVsLCA0My42NjY0MSwgaXMgbXVjaCBoaWdoZXIgdGhhbiBpdCBpcyBmb3IgdGhlIFNFUyBtb2RlbC4gSG93ZXZlciwgdGhlIFNFUyBtb2RlbCBpcyBsZXNzIG9mIGEgZ29vZCBmaXQgYmVjYXVzZSBvZiB0aGUgbm9uLWluZGVwZW5kZW5jZSBvZiB0aGUgcmVzaWR1YWxzLiANCg0KDQpgYGB7cn0NCnVyLmtwc3MoQVRNMV90cmFpbikgJT4lIHN1bW1hcnkoKQ0KYGBgDQoNCg0KYGBge3J9DQp0c2Rpc3BsYXkoQVRNMV90cmFpbikNCmBgYA0KDQpgYGB7cn0NCmxhbWJkYSA8LSBCb3hDb3gubGFtYmRhKEFUTTFfdHJhaW4pDQpsYW1iZGENCmBgYA0KDQoNCmBgYHtyfQ0KbmRpZmZzKEFUTTFfdHJhaW4pDQpgYGANCg0KDQpgYGB7cn0NCkFUTTFfdHJhaW5fdHJhbnMgPC0gQm94Q294KEFUTTFfdHJhaW4sIGxhbWJkYSA9IGxhbWJkYSkNCmBgYA0KDQoNCg0KYGBge3J9DQp0c2Rpc3BsYXkoQVRNMV90cmFpbl90cmFucykNCmBgYA0KDQoNCmBgYHtyfQ0KQXJpbWEoQVRNMV90cmFpbiwgb3JkZXI9YygxLDAsMSksIHNlYXNvbmFsID0gYygwLDAsMCkpDQpgYGANCg0KYGBge3J9DQpBcmltYShBVE0xX3RyYWluLCBvcmRlcj1jKDAsMCwxKSwgc2Vhc29uYWwgPSBjKDEsMCwxKSkNCmBgYA0KDQpgYGB7cn0NCkFyaW1hKEFUTTFfdHJhaW4sIG9yZGVyPWMoMCwwLDEpLCBzZWFzb25hbCA9IGMoMCwwLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KYXV0by5hcmltYShBVE0xX3RyYWluKQ0KYGBgDQoNCg0KYGBge3J9DQooQVRNMS5maXQuYXJpbWEgPC0gYXV0by5hcmltYShBVE0xX3RyYWluKSkNCmBgYA0KDQoNCg0KYGBge3J9DQphMSA8LSBBVE0xLmZpdC5hcmltYSAgJT4lIGZvcmVjYXN0KGggPSBoKSAlPiUNCiAgYWNjdXJhY3koQVRNMV90ZXN0KQ0KYTFbLGMoIlJNU0UiLCJNQUUiLCJNQVBFIiwiTUFTRSIpXQ0KYGBgDQoNCg0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhBVE0xLmZpdC5hcmltYSApDQpgYGANCg0KDQo8Yj5BVE0yPC9iPg0KDQpJIGZvbGxvd2VkIHRoZSBzYW1lIGFwcHJvYWNoIGZvciBBVE1zIDIgYW5kIDQuIA0KDQo8Yj5TRUFTT05BTCBOQUlWRSBGT1JFQ0FTVDwvYj4NCg0KVGhlIHNlYXNvbmFsIG5haXZlIG1ldGhvZCB5aWVsZHMgYW4gUk1TRSBvZiA0MC4xMzU1MS4gQSBjaGVjayBvZiB0aGUgcmVzaWR1YWxzIHNob3dzIHRoYXQgdGhlcmUgaXMgc3RpbGwgc29tZSBpbmZvcm1hdGlvbiBsZWFrYWdlIGluIHRoZSBzZWFzb25hbCBuYWl2ZSBtb2RlbCBmb3IgQVRNMi4gQWxzbyB0aGF0IHRoZXJlIGlzIHN0cm9uZyBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBhdCB0aW1lIDcgaW4gdGhlIGxhZ3MuVGhlIHZlcnkgc21hbGwgcC12YWx1ZSBmcm9tIHRoZSBManVuZy1Cb3ggdGVzdCBzaG93cyB0aGF0IHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIGluZGVwZW5kZW50Lg0KDQpgYGB7cn0NCmZvcmVjYXN0X0FUTTJfV2l0aGRyYXdhbCA8LSBzbmFpdmUoQVRNMl90cmFpbiwgaD1oKQ0KYXV0b3Bsb3QoZm9yZWNhc3RfQVRNMl9XaXRoZHJhd2FsKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KU05haXZlX3Jlc3VsdHMgPC0gYWNjdXJhY3koZm9yZWNhc3RfQVRNMl9XaXRoZHJhd2FsLEFUTTJfdGVzdCkNCmBgYA0KIA0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKFNOYWl2ZV9yZXN1bHRzLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmNoZWNrX3JlcyA8LSBjaGVja3Jlc2lkdWFscyhmb3JlY2FzdF9BVE0yX1dpdGhkcmF3YWwpDQpgYGANCg0KIDxiPlNJTVBMRSBFWFBPTkVOVElBTCBTTU9PVEhJTkcgKFNFUyk8L2I+DQoNClRoZSBuZXh0IG1vZGVsIGlzIFNFUyB3aGljaCBoYXMgYSBsb3dlciBSTVNFIHRoYW4gdGhlIHNlYXNvbmFsIG5haXZlIG1ldGhvZCwgMzkuMjY2MTEuIEEgY2hlY2sgb2YgdGhlIHJlc2lkdWFscyBzaG93cyB0aGF0IHRoZXJlIGFyZSBzdHJvbmcgY29ycmVsYXRpb25zIGluIHRoZSBsYWdzIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgbm90IGluZGVwZW5kZW50LiBUaGUgdmVyeSBzbWFsbCBwLXZhbHVlIGZyb20gdGhlIExqdW5nLUJveCB0ZXN0IHNob3dzIHRoYXQgd2UgY2FuIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgaW5kZXBlbmRlbnQuDQoNCmBgYHtyfQ0KQVRNMl9TRVNfRkMgPC0gc2VzKEFUTTJfdHJhaW4sIGggPSBoKQ0KQVRNMl9TRVNfUmVzdWx0cyA8LSBhY2N1cmFjeShBVE0yX1NFU19GQywgQVRNMl90ZXN0KQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShBVE0yX1NFU19SZXN1bHRzLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEFUTTJfU0VTX0ZDKQ0KYGBgDQoNCg0KDQoNCjxiPkhPTFQgV0lOVEVSUzwvYj4NCg0KSE9MVCBXSU5URVJTIG1vZGVsIGhhcyBhbiBSTVNFIG9mIDYxLjA0ODM4LCBidXQgb25jZSBhZ2FpbiB0aGUgcmVzaWR1YWxzIGRvIG5vdCBzaG93IGluZGVwZW5kZW5jZSBvZiBlYWNoIG90aGVyLiANCg0KYGBge3J9DQpGb3JlY2FzdF9BVE0yX1dpdGhkcmF3YWxfQWRkaXRpdmUgPC0gaHcoQVRNMl90cmFpbiwgaD1oLCAgc2Vhc29uYWwgPSAiYWRkaXRpdmUiKQ0KDQphdXRvcGxvdChGb3JlY2FzdF9BVE0yX1dpdGhkcmF3YWxfQWRkaXRpdmUpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE0yX0hXX1Jlc3VsdHMgPC0gYWNjdXJhY3koRm9yZWNhc3RfQVRNMl9XaXRoZHJhd2FsX0FkZGl0aXZlLCBBVE0yX3Rlc3QpDQpgYGANCg0KYGBge3J9DQprbml0cjo6a2FibGUoQVRNMl9IV19SZXN1bHRzLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoRm9yZWNhc3RfQVRNMl9XaXRoZHJhd2FsX0FkZGl0aXZlKQ0KYGBgDQoNCg0KPGI+SE9MVCBXSU5URVJTIHdpdGggRGFtcGVkPC9iPg0KDQpUaGUgUk1TRSBmb3IgSG9sdCBXaW50ZXJzIHdpdGggdGhlIERhbXBlZCBtZXRob2QgaXMgNjAuNjcwNjkuICANCg0KYGBge3J9DQpGb3JlY2FzdF9BVE0yX1dpdGhkcmF3YWxfTXVsdGlfRGFtcGVkIDwtIGh3KEFUTTJfdHJhaW4sIGggPSBoLCBzZWFzb25hbCA9ICJhZGRpdGl2ZSIsIGRhbXBlZD1UUlVFKQ0KDQphdXRvcGxvdChGb3JlY2FzdF9BVE0yX1dpdGhkcmF3YWxfTXVsdGlfRGFtcGVkICkNCg0KYGBgDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE0yX0hXRF9yZXN1bHRzIDwtIGFjY3VyYWN5KEZvcmVjYXN0X0FUTTJfV2l0aGRyYXdhbF9NdWx0aV9EYW1wZWQsIEFUTTJfdGVzdCkNCg0KYGBgDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTJfSFdEX3Jlc3VsdHMsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEZvcmVjYXN0X0FUTTJfV2l0aGRyYXdhbF9NdWx0aV9EYW1wZWQpDQpgYGANCg0KPGI+QVJJTUEgTW9kZWxzIDwvYj4NCg0KUnVubmluZyB0aHJvdWdoIHRoZSBzYW1lIHByb2NlZHVyZSB0aGF0IEkgZGlkIGZvciBBVE0xLCB0aGUgYmVzdCBBUklNQSBtb2RlbCBpcyBBUklNQSgwLDAsMSkoMCwxLDEpWzddIHdpdGggYSBzZWFzb25hbCBjb21wb25lbnQgdG8gdGhlIG1vZGVsLiBUaGUgcmVzaWR1YWxzIHNob3cgaW5kZXBlbmRlbmNlIGFzIHdlbGwuDQoNCmBgYHtyfQ0KdXIua3BzcyhBVE0yX3RyYWluKSAlPiUgc3VtbWFyeSgpDQpgYGANCg0KDQpgYGB7cn0NCnRzZGlzcGxheShBVE0yX3RyYWluKQ0KYGBgDQoNCmBgYHtyfQ0KbGFtYmRhIDwtIEJveENveC5sYW1iZGEoQVRNMl90cmFpbikNCmxhbWJkYQ0KYGBgDQoNCg0KYGBge3J9DQpuZGlmZnMoQVRNMl90cmFpbikNCmBgYA0KDQoNCmBgYHtyfQ0KQVRNMl90cmFpbl90cmFucyA8LSBCb3hDb3goQVRNMl90cmFpbiwgbGFtYmRhID0gbGFtYmRhKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnRzZGlzcGxheShBVE0yX3RyYWluX3RyYW5zKQ0KYGBgDQoNCg0KYGBge3J9DQpBcmltYShBVE0yX3RyYWluLCBvcmRlcj1jKDEsMSwwKSwgc2Vhc29uYWwgPSBjKDEsMSwxKSkNCmBgYA0KDQpgYGB7cn0NCkFyaW1hKEFUTTJfdHJhaW4sIG9yZGVyPWMoMiwxLDIpLCBzZWFzb25hbCA9IGMoMSwwLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KQXJpbWEoQVRNMl90cmFpbiwgb3JkZXI9YygxLDEsMSksIHNlYXNvbmFsID0gYygwLDEsMSkpDQpgYGANCg0KDQpgYGB7cn0NCkFyaW1hKEFUTTJfdHJhaW4sIG9yZGVyPWMoMSwxLDEpLCBzZWFzb25hbCA9IGMoMSwxLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KYXV0by5hcmltYShBVE0yX3RyYWluKQ0KYGBgDQoNCg0KYGBge3J9DQooQVRNMi5maXQuYXJpbWEgPC0gYXV0by5hcmltYShBVE0yX3RyYWluKSkNCmBgYA0KDQoNCg0KYGBge3J9DQphMSA8LSBBVE0yLmZpdC5hcmltYSAgJT4lIGZvcmVjYXN0KGggPSBoKSAlPiUNCiAgYWNjdXJhY3koQVRNMl90ZXN0KQ0KYTFbLGMoIlJNU0UiLCJNQUUiLCJNQVBFIiwiTUFTRSIpXQ0KYGBgDQoNCg0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhBVE0xLmZpdC5hcmltYSApDQpgYGANCg0KDQo8Yj5BVE00PC9iPg0KDQo8Yj5TRUFTT05BTCBOQUlWRSBGT1JFQ0FTVDwvYj4NCg0KVGhlIHNlYXNvbmFsIG5haXZlIG1ldGhvZCB5aWVsZHMgYW4gUk1TRSBvZiA1MzcuOTE3My4gQSBjaGVjayBvZiB0aGUgcmVzaWR1YWxzIHNob3dzIHRoYXQgdGhlcmUgaXMgc3RpbGwgc29tZSBpbmZvcm1hdGlvbiBsZWFrYWdlIGluIHRoZSBzZWFzb25hbCBuYWl2ZSBtb2RlbCBmb3IgQVRNNC4gQWxzbyB0aGF0IHRoZXJlIGlzIHN0cm9uZyBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBhdCB0aW1lIDcgaW4gdGhlIGxhZ3MgdGhlIHNhbWUgYXMgQVRNMi5UaGUgdmVyeSBzbWFsbCBwLXZhbHVlIGZyb20gdGhlIExqdW5nLUJveCB0ZXN0IHNob3dzIHRoYXQgd2UgY2FuIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgaW5kZXBlbmRlbnQNCg0KDQpgYGB7cn0NCmZvcmVjYXN0X0FUTTRfV2l0aGRyYXdhbCA8LSBzbmFpdmUoQVRNNF90cmFpbiwgaD1oKQ0KYXV0b3Bsb3QoZm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KU05haXZlX3Jlc3VsdHMgPC0gYWNjdXJhY3koZm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsLEFUTTRfdGVzdCkNCmBgYA0KIA0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKFNOYWl2ZV9yZXN1bHRzLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmNoZWNrX3JlcyA8LSBjaGVja3Jlc2lkdWFscyhmb3JlY2FzdF9BVE00X1dpdGhkcmF3YWwpDQpgYGANCg0KIA0KIA0KPGI+U0lNUExFIEVYUE9ORU5USUFMIFNNT09USElORyAoU0VTKTwvYj4NCg0KVGhlIG5leHQgbW9kZWwgaXMgU0VTIHdoaWNoIGhhcyBhIGxvd2VyIFJNU0UgdGhhbiB0aGUgc2Vhc29uYWwgbmFpdmUgbWV0aG9kIGF0IDMwOS41OTU0LiBBIGNoZWNrIG9mIHRoZSByZXNpZHVhbHMgc2hvd3MgdGhhdCB0aGVyZSBpcyBzb21lIGNvcnJlbGF0aW9ucyBpbiB0aGUgbGFncyB3aGljaCBtZWFucyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIG5vdCBpbmRlcGVuZGVudC4gVGhlIHZlcnkgc21hbGwgcC12YWx1ZSBmcm9tIHRoZSBManVuZy1Cb3ggdGVzdCBzaG93cyB0aGF0IHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIGluZGVwZW5kZW50Lg0KDQpgYGB7cn0NCkFUTTRfU0VTX0ZDIDwtIHNlcyhBVE00X3RyYWluLCBoID0gaCkNCkFUTTRfU0VTX1Jlc3VsdHMgPC0gYWNjdXJhY3koQVRNNF9TRVNfRkMsIEFUTTRfdGVzdCkNCmBgYA0KDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoQVRNNF9TRVNfUmVzdWx0cywibWFya2Rvd24iLCBhbGlnbiA9ICdjJykNCmBgYA0KDQoNCg0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhBVE00X1NFU19GQykNCmBgYA0KDQoNCg0KDQo8Yj5IT0xUIFdJTlRFUlM8L2I+DQoNCkhPTFQgV0lOVEVSUyBtb2RlbCBoYXMgYW4gUk1TRSBvZiA0OTkuNjM1Ni4gVGhlIHNtYWxsIHAtdmFsdWUgbWVhbnMgdGhhdCB3ZSBjYW5ub3QgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuICANCg0KYGBge3J9DQpGb3JlY2FzdF9BVE00X1dpdGhkcmF3YWxfQWRkaXRpdmUgPC0gaHcoQVRNNF90cmFpbiwgaD1oLCAgc2Vhc29uYWwgPSAiYWRkaXRpdmUiKQ0KDQphdXRvcGxvdChGb3JlY2FzdF9BVE00X1dpdGhkcmF3YWxfQWRkaXRpdmUpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE00X0hXX1Jlc3VsdHMgPC0gYWNjdXJhY3koRm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsX0FkZGl0aXZlLCBBVE00X3Rlc3QpDQpgYGANCg0KYGBge3J9DQprbml0cjo6a2FibGUoQVRNNF9IV19SZXN1bHRzLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoRm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsX0FkZGl0aXZlKQ0KYGBgDQoNCg0KPGI+SE9MVCBXSU5URVJTIHdpdGggRGFtcGVkPC9iPg0KDQpUaGUgUk1TRSBmb3IgSG9sdCBXaW50ZXJzIHdpdGggdGhlIERhbXBlZCBtZXRob2QgaXMgNDg1LjU5NTcsIGFuZCB0aGVyZSBpcyBzdGlsbCBpbmZvcm1hdGlvbiBsZWFrYWdlIGluIHRoZSByZXNpZHVhbHMuDQoNCmBgYHtyfQ0KRm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsX0FkZGl0aXZlX0RhbXBlZCA8LSBodyhBVE00X3RyYWluLCBoID0gaCwgc2Vhc29uYWwgPSAiYWRkaXRpdmUiLCBkYW1wZWQ9VFJVRSkNCg0KYXV0b3Bsb3QoRm9yZWNhc3RfQVRNNF9XaXRoZHJhd2FsX0FkZGl0aXZlX0RhbXBlZCkNCg0KYGBgDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpBVE00X0hXRF9yZXN1bHRzIDwtIGFjY3VyYWN5KEZvcmVjYXN0X0FUTTRfV2l0aGRyYXdhbF9BZGRpdGl2ZV9EYW1wZWQsIEFUTTRfdGVzdCkNCg0KYGBgDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTRfSFdEX3Jlc3VsdHMsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEZvcmVjYXN0X0FUTTRfV2l0aGRyYXdhbF9BZGRpdGl2ZV9EYW1wZWQpDQpgYGANCg0KDQo8Yj5BUklNQSBNb2RlbHMgPC9iPg0KDQpGb2xsb3dpbmcgdGhlIHNhbWUgcHJvY2VkdXJlLCB0aGUgYmVzdCBBUklNQSBtb2RlbCB3YXMgQVJJTUEoMCwwLDApKDEsMCwwKVs3XSB3aXRoIGFuIFJNU0Ugb2YgMzExLjc2Ny4gQSBjaGVjayBvZiB0aGUgcmVzaWR1YWxzIHNob3cgdGhlaXIgaW5kZXBlbmRlbmNlLiANCg0KYGBge3J9DQp0c2Rpc3BsYXkoQVRNNF90cmFpbikNCmBgYA0KDQpgYGB7cn0NCmxhbWJkYSA8LSBCb3hDb3gubGFtYmRhKEFUTTRfdHJhaW4pDQoNCmxhbWJkYQ0KYGBgDQoNCmBgYHtyfQ0KbmRpZmZzKEFUTTRfdHJhaW4pDQpgYGANCg0KYGBge3J9DQojVHJhbnNmb3JtIHRoZSBzZXJpZXMgd2l0aCBCb3hDb3ggZnVuY3Rpb24gYW5kIHRoZSBiZXN0IGxhbWJkYQ0KICBBVE00X3RyYWluX3RyYW5zIDwtIEJveENveChBVE00X3RyYWluLCBsYW1iZGEpDQpgYGANCg0KDQpgYGB7cn0NCnRzZGlzcGxheShBVE00X3RyYWluX3RyYW5zKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCkFyaW1hKEFUTTJfdHJhaW4sIG9yZGVyPWMoMSwxLDApLCBzZWFzb25hbCA9IGMoMSwxLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KQXJpbWEoQVRNNF90cmFpbiwgb3JkZXI9YygxLDAsMSksIHNlYXNvbmFsID0gYygwLDAsMCkpDQpgYGANCg0KYGBge3J9DQpBcmltYShBVE00X3RyYWluLCBvcmRlcj1jKDAsMCwxKSwgc2Vhc29uYWwgPSBjKDAsMCwxKSkNCmBgYA0KDQoNCmBgYHtyfQ0KQXJpbWEoQVRNNF90cmFpbiwgb3JkZXI9YygwLDAsMCksIHNlYXNvbmFsID0gYygwLDEsMCkpDQpgYGANCg0KDQoNCg0KYGBge3J9DQooQVRNNC5maXQuYXJpbWEgPC0gYXV0by5hcmltYShBVE00X3RyYWluKSkNCmBgYA0KDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoQVRNNC5maXQuYXJpbWEgKQ0KYGBgDQoNCg0KYGBge3J9DQphMSA8LSBBVE00LmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IGgpICU+JQ0KICBhY2N1cmFjeShBVE00X3Rlc3QpDQphMVssYygiUk1TRSIsIk1BRSIsIk1BUEUiLCJNQVNFIildDQpgYGANCg0KDQoNCg0KIyMgSUlJLiBTdW1tYXJ5IG9mIEZpbmRpbmdzIGFuZCBGb3JlY2FzdCBmb3IgTWF5IDIwMTANCg0KSW4gYWxsIHRocmVlIGV4cGVyaW1lbnRzIGFjcm9zcyBkaWZmZXJlbnQgY2xhc3NlcyBvZiBtb2RlbHMsIHRoZSBhdXRvLmFyaW1hIG1vZGVsIHNob3dlZCB0aGUgbW9zdCBhY2N1cmF0ZSBmb3JlY2FzdCBmb3IgZWFjaCBBVE0gd2l0aCB0aGUgZXhjZXB0aW9uIG9mIEFUTTMgd2hpY2ggZGlkIG5vdCBoYXZlIGVub3VnaCBkYXRhIHRvIG1ha2UgYW4gYWNjdXJhdGUgZm9yZWNhc3QuIEZvciB0aGF0IEFUTSwgSSB3b3VsZCB1c2UgYSBkZWZhdWx0IHZhbHVlIG9mIDEwMCB1bnRpbCBtb3JlIGRhdGEgaXMgY29sbGVjdGVkLiANCg0KVGhlIGZpbmFsIHN0ZXAgaXMgdG8gYnVpbGQgYXV0by5hcmltYSBtb2RlbHMgYWNyb3NzIHRoZSBlbnRpcmUgdGltZSBzZXJpZXMgZm9yIEFUTTEsIEFUTTIsIGFuZCBBVE00LCBhbmQgdGhlbiBmb3JlY2FzdCBmb3IgdGhlIG5leHQgMzEgZGF5cy4NCg0KDQpgYGB7cn0NCg0KTWF5MjAxMCA8LSBkYXRhLmZyYW1lKHNlcShhcy5EYXRlKCIyMDEwLTA1LTAxIiksIGJ5ID0gImRheSIsIGxlbmd0aC5vdXQgPSAzMSkpDQpjb2xuYW1lcyhNYXkyMDEwKSA8LSBjKCJEYXRlIikNCg0KYGBgDQoNCg0KQVRNMQ0KDQpgYGB7cn0NCihBVE0xLmZpbmFsLmZpdC5hcmltYSA8LSBhdXRvLmFyaW1hKEFUTTFfdHMpKQ0KDQoNCkFUTTEuZmluYWwuZml0LmFyaW1hICU+JSBmb3JlY2FzdChoID0gMzEpICU+JSAgYXV0b3Bsb3QoKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCkFUTTFfTUFZMjAxMCA8LSBhcy5kYXRhLmZyYW1lKEFUTTEuZmluYWwuZml0LmFyaW1hICU+JSBmb3JlY2FzdChoID0gMzEpKQ0KQVRNMV9NQVkyMDEwIDwtIGNiaW5kKE1heTIwMTAsIEFUTTFfTUFZMjAxMCkNCkFUTTFfTUFZMjAxMF9oZWFkIDwtIGhlYWQoQVRNMV9NQVkyMDEwLCAxMCkNCmBgYA0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEFUTTEuZmluYWwuZml0LmFyaW1hKQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTFfTUFZMjAxMF9oZWFkLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCg0KVGhlIGZvcmVjYXN0IGZvciBBVE0xIGZvciBNYXkgMjAxMCBpcyBleHBvcnRlZCBoZXJlOg0KDQpgYGB7cn0NCndyaXRlLmNzdihBVE0xX01BWTIwMTAgLCJDOlxcVXNlcnNcXGpraGFuXFxEb2N1bWVudHNcXENVTllcXDIwMjFcXDAxX1NwcmluZzIwMjFcXERBVEEgNjI0XFxQcm9qZWN0IE9uZVxcRm9yZWNhc3RcXFBhcnQgQVxcQVRNMV9NQVkyMDEwLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCg0KDQoNCg0KDQpBVE0yDQoNCg0KYGBge3J9DQooQVRNMi5maW5hbC5maXQuYXJpbWEgPC0gYXV0by5hcmltYShBVE0yX3RzKSkNCg0KDQpBVE0yLmZpbmFsLmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IDMxKSAlPiUgIGF1dG9wbG90KCkNCmBgYA0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEFUTTIuZmluYWwuZml0LmFyaW1hKQ0KYGBgDQoNCg0KYGBge3J9DQpBVE0yX01BWTIwMTAgPC0gYXMuZGF0YS5mcmFtZShBVE0yLmZpbmFsLmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IDMxKSkNCkFUTTJfTUFZMjAxMCA8LSBjYmluZChNYXkyMDEwLCBBVE0yX01BWTIwMTApDQpBVE0yX01BWTIwMTBfaGVhZCA8LSBoZWFkKEFUTTJfTUFZMjAxMCwgMTApDQpgYGANCg0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTJfTUFZMjAxMF9oZWFkLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNClRoZSBmb3JlY2FzdCBmb3IgQVRNMiBmb3IgTWF5IDIwMTAgaXMgZXhwb3J0ZWQgaGVyZToNCg0KYGBge3J9DQp3cml0ZS5jc3YoQVRNMl9NQVkyMDEwICwiQzpcXFVzZXJzXFxqa2hhblxcRG9jdW1lbnRzXFxDVU5ZXFwyMDIxXFwwMV9TcHJpbmcyMDIxXFxEQVRBIDYyNFxcUHJvamVjdCBPbmVcXEZvcmVjYXN0XFxQYXJ0IEFcXEFUTTJfTUFZMjAxMC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCmBgYA0KDQoNCkFUTTMNCg0KQXMgc3RhdGVkIHByZXZpb3VzbHksIHRoZXJlIGlzIG5vdCBuZWFybHkgZW5vdWdoIGRhdGEgdG8gbWFrZSBhbnkgcmVhbGlzdGljIGZvcmVjYXN0IGZvciBBVE0zLCBhbmQgSSBkaWQgbm90IHdhbnQgdG8gdXNlIGFuIGF2ZXJhZ2Ugb2YgdGhlIHRocmVlIHZhbHVlcyBhcyB0aGF0IHdvdWxkIGNhdXNlIHRoZSBBVE0gdG8gaGF2ZSBpbnN1ZmZpY2llbnQgZnVuZHMgdG8gY29tcGxldGUgdGhlIHRyYW5zYWN0aW9uLiBJbnN0ZWFkLCBJIHdpbGwgdXNlIGEgZGVmYXVsdCB2YWx1ZSBvZiAxMDAgdW50aWwgSSBjYW4gY29sbGVjdCBtb3JlIGRhdGEuIA0KDQpgYGB7cn0NCmRlZmF1bHQgPC1yZXAoYygxMDApLHRpbWVzPWMoMzEpKQ0KQVRNM19NQVkyMDEwIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoTWF5MjAxMCwgZGVmYXVsdCkpDQpBVE0zX01BWTIwMTAgDQpgYGANCg0KVGhlIGZvcmVjYXN0IGZvciBBVE0zIGZvciBNYXkgMjAxMCBpcyBleHBvcnRlZCBoZXJlOg0KDQpgYGB7cn0NCndyaXRlLmNzdihBVE0zX01BWTIwMTAgLCJDOlxcVXNlcnNcXGpraGFuXFxEb2N1bWVudHNcXENVTllcXDIwMjFcXDAxX1NwcmluZzIwMjFcXERBVEEgNjI0XFxQcm9qZWN0IE9uZVxcRm9yZWNhc3RcXFBhcnQgQVxcQVRNM19NQVkyMDEwLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCkFUTTQNCg0KYGBge3J9DQooQVRNNC5maW5hbC5maXQuYXJpbWEgPC0gYXV0by5hcmltYShBVE00X3RzKSkNCg0KDQpBVE00LmZpbmFsLmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IDMxKSAlPiUgIGF1dG9wbG90KCkNCmBgYA0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEFUTTQuZmluYWwuZml0LmFyaW1hKQ0KYGBgDQoNCg0KYGBge3J9DQpBVE00X01BWTIwMTAgPC0gYXMuZGF0YS5mcmFtZShBVE00LmZpbmFsLmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IDMxKSkNCkFUTTRfTUFZMjAxMCA8LSBjYmluZChNYXkyMDEwLCBBVE00X01BWTIwMTApDQpBVE00X01BWTIwMTBfaGVhZCA8LSBoZWFkKEFUTTRfTUFZMjAxMCwgMTApDQpgYGANCg0KDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKEFUTTRfTUFZMjAxMF9oZWFkLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNClRoZSBmb3JlY2FzdCBmb3IgQVRNNCBmb3IgTWF5IDIwMTAgaXMgZXhwb3J0ZWQgaGVyZToNCg0KYGBge3J9DQp3cml0ZS5jc3YoQVRNNF9NQVkyMDEwICwiQzpcXFVzZXJzXFxqa2hhblxcRG9jdW1lbnRzXFxDVU5ZXFwyMDIxXFwwMV9TcHJpbmcyMDIxXFxEQVRBIDYyNFxcUHJvamVjdCBPbmVcXEZvcmVjYXN0XFxQYXJ0IEFcXEFUTTRfTUFZMjAxMC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCmBgYA0KDQoNCg0KIyBQYXJ0IEIgDQoNCiMjIEltcG9ydCBhbmQgZGlzY3VzcyB0aGUgc3RhdGUgb2YgdGhlIGRhdGENCg0KRm9yIFBhcnQgQiwgd2UgYXJlIGdpdmVuIGEgc2ltcGxlIGRhdGFzZXQgb2YgcmVzaWRlbnRpYWwgcG93ZXIgdXNhZ2UgZm9yIEphbnVhcnkgMTk5OCB1bnRpbCBEZWNlbWJlciAyMDEzLiAgV2UgYXJlIHRvIG1vZGVsIHRoaXMgZGF0YSBhbmQgIHByb3ZpZGUgYSBtb250aGx5IGZvcmVjYXN0IGZvciB0aGUgeWVhciAyMDE0LiAgRnJvbSB0aGUgaW1wb3J0LCB0aGVyZSBhcmUgMTkyIG9ic2VydmF0aW9ucyBhbmQgMyB2YXJpYWJsZXMuIFRoZSBkYXRlIGNvbHVtbiBuZWVkcyB0byBiZSB1cGRhdGVkIGFuZCByZW5hbWVkLCBhbmQgdGhlcmUgaXMgYSBtaXNzaW5nIHZhbHVlLg0KDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0IDwtIHJlYWR4bDo6cmVhZF9leGNlbCgiUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZC02MjQueGxzeCIpIA0KcHJpbnQoIlJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQgaGFzIGJlZW4gbG9hZGVkLiIpDQpgYGANCg0KIyMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBhbmQgQ2xlYW5pbmcNCg0KYGBge3J9DQpzdHIoUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCkNCmBgYA0KDQoNCg0KYGBge3J9DQpzdW1tYXJ5KFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQpDQpgYGANClJlbmFtZSB0aGUgZGF0ZSBjb2x1bW4gdG8gIkRhdGUiDQoNCmBgYHtyfQ0KY29sbmFtZXMoUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCkgPC0gYygiQ2FzZVNlcXVlbmNlIiwgIkRhdGUiLCAiS1dIIikNCmBgYA0KDQpBZGQgYW4gIi0wMSIgdG8gdGhlIGRhdGUgdmFsdWVzDQpgYGB7cn0NClJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQkRGF0ZSA8LSBhcy5EYXRlKHltZChwYXN0ZTAoUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCREYXRlLCItMDEiKSkpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpoZWFkUmVzaWRlbnRpYWwgPC0gaGVhZChSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0LCAxMCkNCmBgYA0KDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoaGVhZFJlc2lkZW50aWFsLCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNCiMjIElkZW50aWZ5IGFuZCBIYW5kbGUgTWlzc2luZyBEYXRhIA0KICANCg0KQXMgd2FzIGRvbmUgaW4gUGFydCBBLCBJIHdpbGwgdXNlIGtOTiB0byBpbXB1dGUgdGhlIG1pc3NpbmcgaXRlbS4gDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNFtyb3dTdW1zKGlzLm5hKFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQpKSA+IDAsXQ0KYGBgDQoNCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0IDwtIGtOTihSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0LCB2YXJpYWJsZSA9IGMoIktXSCIpLCBrPTUpDQoNClJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjRfSU1QIDwtIFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjRbUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCRLV0hfaW1wID09IFRSVUUsXQ0KYGBgDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNF9JTVAsIm1hcmtkb3duIiwgYWxpZ24gPSAnYycpDQpgYGANCg0KDQoNCiMjIElkZW50aWZ5IGFuZCBIYW5kbGUgT3V0bGllcnMNCg0KV2Ugc2VlIHRoZSBib3ggcGxvdCB0aGF0IHRoZXJlIGlzIGEgc2luZ2xlIG91dGxpZXIuIEFzIHdhcyBkb25lIGluIFBhcnQgQSwgSSB1c2VkIHRoZSAiV2luc29yaXplZCIgb2YgaGFuZGxpbmcgb3V0bGllcnMuIEhvd2V2ZXIsIHNpbmNlIHRoZXJlIGlzIG9ubHkgb25lIG91dGxpZXIsIEkgd2lsbCB1c2UgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdXBwZXIgYW5kIGxvd2VyIGJvdW5kYXJpZXMgb2YgdGhlIElRUi4gDQogIA0KICANCmBgYHtyfQ0KYm94cGxvdChSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0JEtXSCAsIGNvbD0icmVkIiAsIHhsYWI9IkVuZXJneSBVc2FnZSIpDQpgYGANCg0KYGBge3J9DQp0YWdzNSA8LSB0YWdfb3V0bGllcihSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0JEtXSCkNClJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQkT3V0bGllciA8LSB0YWdzNQ0KYGBgDQoNCg0KDQpgYGB7cn0NClJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjRbUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCRPdXRsaWVyID09ICdPdXRsaWVyJywgXQ0KYGBgDQoNCmBgYHtyfQ0KYm91bmRhcmllcyA8LSBJZGVudGlmeV9PdXRsaWVyKFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQkS1dIKQ0KZm9yKGkgaW4gUmVzaWRlbnRpYWxDdXN0b21lckZvcmVjYXN0TG9hZDYyNCRLV0gpew0KICBpZiAoaSA8IGJvdW5kYXJpZXNbMV0pew0KICAgIFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQkS1dIW1Jlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQkS1dIID09IGkgXSA8LSBib3VuZGFyaWVzWzJdIC0gYm91bmRhcmllc1sxXQ0KICB9DQogIGVsc2UgaWYgKGkgPiBib3VuZGFyaWVzWzJdKXsNCiAgICBSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0JEtXSFtSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0JEtXSCA9PSBpIF0gPC0gYm91bmRhcmllc1syXSAtIGJvdW5kYXJpZXNbMV0NCiAgfQ0KfQ0KDQpgYGANCg0KDQoNCg0KVGhlIGJveCBwbG90IGFmdGVyIG91dGxpZXIgaGFzIGJlZW4gYWRqdXN0ZWQuIA0KICANCmBgYHtyfQ0KYm94cGxvdChSZXNpZGVudGlhbEN1c3RvbWVyRm9yZWNhc3RMb2FkNjI0JEtXSCAsIGNvbD0icmVkIiAsIHhsYWI9IkVuZXJneSBVc2FnZSIpDQpgYGANCg0KDQojIyBDb252ZXJ0IHRoZSBEYXRhIGludG8gYSBUaW1lIFNlcmllcyBhbmQgUGxvdCBJdA0KDQpXZSBzZWUgdGhlIHN0cm9uZyBzZWFzb25hbCBhbmQgYSBkaXN0aW5jdCB1cHdhcmQgdHJlbmQgb2YgZW5lcmd5IHVzYWdlIGZyb20gMTk5OCB0byAyMDEzLiANCg0KDQpgYGB7cn0NCnRzS1dIIDwtIFJlc2lkZW50aWFsQ3VzdG9tZXJGb3JlY2FzdExvYWQ2MjQgJT4lIA0KICAgICAgICAgICAgc2VsZWN0KERhdGUsIEtXSCkNCg0KdHNLV0gkRGF0ZSA8LSBhcy5EYXRlKHRzS1dIJERhdGUpDQoNCktXSF90cyA8LSB0cyh0c0tXSCRLV0gsIHN0YXJ0PWMoMTk5OCwgMSksIGZyZXF1ZW5jeT0xMikNCmBgYA0KDQoNCmBgYHtyfQ0KYXV0b3Bsb3QoS1dIX3RzKSArIGdlb21fc21vb3RoKG1ldGhvZD0iYXV0byIpDQpgYGANCg0KRGVjb21wb3NpdGlvbiBzaG93cyB0aGUgdXB3YXJkIHRyZW5kIGluIHVzYWdlIG92ZXIgdGhlIHRpbWUgc2VyaWVzIGFzIHdlbGwgYXMgYSBzdHJvbmdseSBkZWZpbmVkIHNlYXNvbmFsaXR5LiANCg0KYGBge3J9DQpLV0hfdHMgJT4lIGRlY29tcG9zZSh0eXBlPSJtdWx0aXBsaWNhdGl2ZSIpICU+JSANCiAgICAgICAgYXV0b3Bsb3QoKSArIHhsYWIoIlllYXIiKSsNCiAgICAgICAgZ2d0aXRsZSgiQ2xhc3NpY2FsIG11bHRpcGxpY2F0aXZlIGRlY29tcG9zaXRpb24gb2YgS1dIIFVzYWdlIikNCmBgYA0KDQpUaGUgcG9sYXIsIHNlYXNvbmFsLCBhbmQgc2VyaWVzIHBsb3RzIHNob3cgdGhhdCB0aGUgcGVyaW9kcyBvZiBKdW5lIHRvIEF1ZyBhbmQgTm92IHRvIEZlYiBhcmUgdGhlIGhlYXZpZXN0IHVzYWdlIG1vbnRocy4NCg0KYGBge3J9DQpnZ3NlYXNvbnBsb3QoS1dIX3RzLCB5ZWFyLmxhYmVscz1GQUxTRSwgY29udGludW91cz1UUlVFLCBwb2xhciA9IFRSVUUpDQpgYGANCg0KVGhlIHNlYXNvbmFsIGFuZCBzdWJzZXJpZXMgcGxvdHMgY29uZmlybSAgdGhhdCB0aGUgcGVhayB1c2FnZSBmb3IgdGhlIG1vbnRocyAgIA0KDQoNCmBgYHtyfQ0KZ2dzZWFzb25wbG90KEtXSF90cykNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dzdWJzZXJpZXNwbG90KEtXSF90cykNCmBgYA0KDQoNCg0KVGhlIGdnbGFncGxvdCBzaG93cyB0aGUgaGlnaGVzdCBsYWcgY29ycmVsYXRpb24gYXQgbW9udGggMTIuIA0KDQpgYGB7cn0NCmdnbGFncGxvdChLV0hfdHMpDQpgYGANCg0KDQojIyMgU3BsaXQgdGhlIFRpbWUgU2VyaWVzDQoNClRoZSBkYXRhIHdpbGwgYmUgc3BsaXQgaW50byB0cmFpbmluZyBhbmQgdGVzdCBzZXRzLiBUaGUgdHJhaW5pbmcgc2V0IHdpbGwgYmUgY29tcHJpc2VkIG9mIHRoZSBmaXJzdCAxMiB5ZWFycyBhbmQgdGhlIHRlc3Qgc2V0IHdpbGwgYmUgdGhlIGxhc3QgdGhyZWUgeWVhcnMgKGg9MzYgbW9udGhzKS4NCg0KDQoNCmBgYHtyfQ0KS1dIX3RyYWluIDwtIHdpbmRvdyhLV0hfdHMsc3RhcnQ9YygxOTk4LDEpLCBlbmQ9YygyMDEwLDEyKSkNCktXSF90ZXN0IDwtIHdpbmRvdyhLV0hfdHMsc3RhcnQ9YygyMDExLDEpKQ0KYGBgDQoNCmBgYHtyfQ0KaD0zNg0KYGBgDQoNCg0KDQoNCiMjICBFeHBlcmltZW50YXRpb24gYW5kIFJlc3VsdHMNCg0KSSBmb2xsb3dlZCB0aGUgc2FtZSBleHBlcmltZW50YXRpb24gcHJvY2VkdXJlIGFzIEkgZGlkIGZvciBQYXJ0IEEuIA0KDQoNCjxiPlNFQVNPTkFMIE5BSVZFIEZPUkVDQVNUPC9iPg0KDQpUaGUgU2Vhc29uYWwgTmFpdmUgbW9kZWwgaGFzIGEgUk1TRSBvZiAxMTQ1MjQ4LjYsIGFuZCB0aGUgTGp1bmctQm94IHRlc3QgaGFzIGFuIGV4dHJlbWVseSBzbWFsbCBwLXZhbHVlIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgbm90IGluZGVwZW5kZW50Lg0KDQpgYGB7cn0NCmZvcmVjYXN0X0tXSF9Vc2FnZSA8LSBzbmFpdmUoS1dIX3RyYWluLCBoPWgpDQphdXRvcGxvdChmb3JlY2FzdF9LV0hfVXNhZ2UpDQpgYGANCg0KYGBge3J9DQphY2N1cmFjeShmb3JlY2FzdF9LV0hfVXNhZ2UsIEtXSF90ZXN0KQ0KYGBgDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoZm9yZWNhc3RfS1dIX1VzYWdlKQ0KYGBgDQoNCg0KDQo8Yj5TSU1QTEUgRVhQT05FTlRJQUwgU01PT1RISU5HPC9iPg0KDQpUaGUgU2ltcGxlIEV4cG9uZW50aWFsIFNtb290aGluZyBSTVNFIGlzIDE5NjQ1NDggd2l0aCBub24taW5kZXBlbmRlbnQgcmVzaWR1YWxzLg0KDQoNCmBgYHtyfQ0KS1dIX1NFU19GQyA8LSBzZXMoS1dIX3RyYWluLCBoID0gaCkNCmFjY3VyYWN5KEtXSF9TRVNfRkMsIEtXSF90ZXN0KQ0KYGBgDQoNCg0KYGBge3J9DQpjaGVja3Jlc2lkdWFscyhLV0hfU0VTX0ZDKQ0KYGBgDQoNCg0KDQo8Yj5IT0xUIFdJTlRFUlM8L2I+DQoNCkZvciBIb2x0IFdpbnRlcnMsIEkgc2V0IHRoZSBzZWFzb25hbCBwYXJhbWV0ZXIgdG8gIm11bHRpcGxpY2F0aXZlIiBiZWNhdXNlIG9mIHRoZSBpbmNyZWFzaW5nIHZhcmlhbmNlIG9mIHRoZSB0cmVuZCBhbmQgc2Vhc29uYWxpdHkuIFRoZSBIb2x0IFdpbnRlcnMgbW9kZWwgUk1TRSBpcyAxMTM2NjM3LjUuIFNvLCBmYXIgdGhpcyBtb2RlbCBwZXJmb3JtcyB0aGUgYmVzdCwgUk1TRSBvZiAxMTM2NjM3LjUsIGJlY2F1c2UgaXQgY2FwdHVyZXMgdGhlIHRyZW5kIGFuZCBzZWFzb25hbGl0eS4gSG93ZXZlciwgdGhlIHJlc2lkdWFscyBhcmUgIG5vdCBpbmRlcGVuZGVudC4gDQoNCmBgYHtyfQ0KRm9yZWNhc3RfS1dIX1dpdGhkcmF3YWxfTXVsdGkgPC0gaHcoS1dIX3RyYWluLCBoID0gaCwgc2Vhc29uYWwgPSAibXVsdGlwbGljYXRpdmUiKQ0KDQphdXRvcGxvdChGb3JlY2FzdF9LV0hfV2l0aGRyYXdhbF9NdWx0aSkNCmBgYA0KDQoNCmBgYHtyfQ0KYWNjdXJhY3koRm9yZWNhc3RfS1dIX1dpdGhkcmF3YWxfTXVsdGksIEtXSF90ZXN0KQ0KYGBgDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoRm9yZWNhc3RfS1dIX1dpdGhkcmF3YWxfTXVsdGkpDQpgYGANCg0KPGI+SE9MVCBXSU5URVJTIHdpdGggRGFtcGVkPC9iPg0KDQoNClRoZSBIb2x0IFdpbnRlcnMgbW9kZWwgdXNpbmcgdGhlIERhbXBlZCBhcHByb2FjaCdzIFJNU0UgaXMgMTIwNjMxOC41IHdpdGggbm9uLWluZGVwZW5kZW50IHJlc2lkdWFscy4NCg0KYGBge3J9DQpGb3JlY2FzdF9LV0hfTXVsdGlfRGFtcGVkIDwtIGh3KEtXSF90cmFpbiwgaCA9IGgsIHNlYXNvbmFsID0gIm11bHRpcGxpY2F0aXZlIiwgZGFtcGVkPVRSVUUpDQoNCmF1dG9wbG90KEZvcmVjYXN0X0tXSF9NdWx0aV9EYW1wZWQpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KYWNjdXJhY3koRm9yZWNhc3RfS1dIX011bHRpX0RhbXBlZCwgS1dIX3Rlc3QpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoRm9yZWNhc3RfS1dIX011bHRpX0RhbXBlZCkNCmBgYA0KDQoNCjxiPkFSSU1BIE1vZGVscyA8L2I+DQoNClVzaW5nIHRoZSBzYW1lIHByb2NlZHVyZSBhcyBiZWZvcmUsIEkgZm91bmQgdGhhdCB0aGUgYmVzdCBBUklNQSBtb2RlbCBpcyBBUklNQSgwLDAsMSkoMiwxLDApWzEyXSB3aXRoIGRyaWZ0LiBUaGUgUk1TRSBvZiB0aGUgQVJJTUEgbW9kZWwgaXMgdGhlIGxvd2VzdCBmb3IgYWxsIG9mIHRoZSBhYm92ZSBtb2RlbHMgYXQgMTA0NzEyNi42Lg0KDQpgYGB7cn0NCnVyLmtwc3MoS1dIX3RyYWluKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnRzZGlzcGxheShLV0hfdHJhaW4pDQpgYGANCg0KYGBge3J9DQpsYW1iZGEgPC0gQm94Q294LmxhbWJkYShLV0hfdHJhaW4pDQoNCmxhbWJkYQ0KYGBgDQoNCmBgYHtyfQ0KbmRpZmZzKEtXSF90cmFpbikNCmBgYA0KDQpgYGB7cn0NCiNUcmFuc2Zvcm0gdGhlIHNlcmllcyB3aXRoIEJveENveCBmdW5jdGlvbiBhbmQgdGhlIGJlc3QgbGFtYmRhDQogIEtXSF90cmFpbl90cmFucyA8LSBCb3hDb3goS1dIX3RyYWluLCBsYW1iZGEpDQpgYGANCg0KDQpgYGB7cn0NCnRzZGlzcGxheShLV0hfdHJhaW5fdHJhbnMpDQpgYGANCg0KDQoNCg0KDQpgYGB7cn0NCkFyaW1hKEtXSF90cmFpbiwgb3JkZXI9YygwLDAsMSksIHNlYXNvbmFsID0gYygyLDEsMSksIGluY2x1ZGUuY29uc3RhbnQgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KQXJpbWEoS1dIX3RyYWluLCBvcmRlcj1jKDEsMCwxKSwgc2Vhc29uYWwgPSBjKDAsMCwwKSwgaW5jbHVkZS5jb25zdGFudCA9IFRSVUUpDQpgYGANCg0KYGBge3J9DQpBcmltYShLV0hfdHJhaW4sIG9yZGVyPWMoMSwwLDEpLCBzZWFzb25hbCA9IGMoMCwwLDEpLCBpbmNsdWRlLmNvbnN0YW50ID0gVFJVRSkNCmBgYA0KDQoNCmBgYHtyfQ0KQXJpbWEoS1dIX3RyYWluLCBvcmRlcj1jKDAsMCwxKSwgc2Vhc29uYWwgPSBjKDIsMSwwKSwgaW5jbHVkZS5jb25zdGFudCA9IFRSVUUpDQpgYGANCg0KDQpgYGB7cn0NCihLV0guZml0LmFyaW1hIDwtIGF1dG8uYXJpbWEoS1dIX3RyYWluKSkNCmBgYA0KDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMoS1dILmZpdC5hcmltYSkNCmBgYA0KDQoNCmBgYHtyfQ0KYTEgPC0gS1dILmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IGgpICU+JQ0KICBhY2N1cmFjeSggS1dIX3Rlc3QpDQphMVssYygiUk1TRSIsIk1BRSIsIk1BUEUiLCJNQVNFIildDQpgYGANCg0KDQoNCg0KIyMgSUlJLiBTdW1tYXJ5IG9mIEZpbmRpbmdzIGFuZCBNb250aGx5IEZvcmVjYXN0IGZvciAyMDE0DQoNCkFwcGx5aW5nIHRoZSBhdXRvLmFyaW1hIG1vZGVsIGFjcm9zcyB0aGUgZW50aXJlIHRpbWUgc2VyaWVzIHRvIHByb2plY3QgdGhlIG5leHQgMTIgbW9udGhzIHNob3dzIHRoYXQgdGhlIGJlc3QgbW9kZWwgaXMgQVJJTUEoMCwwLDMpKDIsMSwwKVsxMl0gDQoNCg0KYGBge3J9DQooS1dILmZpbmFsLmZpdC5hcmltYSA8LSBhdXRvLmFyaW1hKEtXSF90cykpDQoNCg0KS1dILmZpbmFsLmZpdC5hcmltYSAlPiUgZm9yZWNhc3QoaCA9IDEyKSAlPiUgIGF1dG9wbG90KCkNCmBgYA0KDQpgYGB7cn0NCmNoZWNrcmVzaWR1YWxzKEtXSC5maW5hbC5maXQuYXJpbWEpDQpgYGANCg0KDQpgYGB7cn0NCk1vbnRoX2J5X01vbnRoXzIwMTQgPC0gYXMuZGF0YS5mcmFtZShLV0guZmluYWwuZml0LmFyaW1hICU+JSBmb3JlY2FzdChoID0gMTIpKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShNb250aF9ieV9Nb250aF8yMDE0LCJtYXJrZG93biIsIGFsaWduID0gJ2MnKQ0KYGBgDQoNClRoZSAyMDE0IG1vbnRobHkgZm9yZWNhc3RzIGFyZSBleHBvcnRlZCBoZXJlOg0KDQpgYGB7cn0NCndyaXRlLmNzdihNb250aF9ieV9Nb250aF8yMDE0ICwiQzpcXFVzZXJzXFxqa2hhblxcRG9jdW1lbnRzXFxDVU5ZXFwyMDIxXFwwMV9TcHJpbmcyMDIxXFxEQVRBIDYyNFxcUHJvamVjdCBPbmVcXEZvcmVjYXN0XFxQYXJ0IEJcXE1vbnRoX2J5X01vbnRoXzIwMTQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg==