Md Mahmudul Hasan

Assignment:


Context:
You are a quantitative analyst for a hedge fund which uses predictive models of the economy to try to forecast movements of key economic indicators, and creates trading strategies which attempt to “front run” changes in these indicators. You have been asked by your Director to compare several models of U.S. Retail Sales, evaluate their forecasting ability, and submit a report to be discussed at your next investment committee meeting.

Assignment:
- Within the above context, write a report suitable for sharing with your team on the modelling and predictability of Retail Sales.
- Retail Sales: Non-seasonally adjusted Advance Retail Sales: Retail Trade from FRED from January 1990 to July 2022.

Data

Fetching Data from FRED

# Advance Retail Sales: Retail Trade (RSXFSN)
# Data is not available from 1990, its available from 1992!
# https://fred.stlouisfed.org/series/RSXFSN

retail_sales<-tidyquant::tq_get(c("RSXFSN"), 
                           get="economic.data",
                           from="1992-01-01", 
                           to="2022-07-31") %>% 
  tidyr::fill(price,.direction="down") %>% stats::na.omit()

kable(head(retail_sales)) %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
symbol date price
RSXFSN 1992-01-01 130683
RSXFSN 1992-02-01 131244
RSXFSN 1992-03-01 142488
RSXFSN 1992-04-01 147175
RSXFSN 1992-05-01 152420
RSXFSN 1992-06-01 151849

Descriptive Table

A full descriptive table of your time series variable. This includes # of observations, # of missing values, mean, median, standard deviation, skewness, and kurtosis. Discuss any notable statistical features of your variable.

retail_sales %>% 
  dplyr::group_by(symbol) %>% 
  dplyr::summarise(min=min(price), 
                   max=max(price),
                   mean=mean(price),
                   median=median(price), 
                   sd=sd(price), 
                   skew=skewness(price), 
                   kurtosis = kurtosis(price) - 3) %>%
  kable(caption="Advance Retail Sales: Retail Trade (RSXFSN)")  %>% 
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive")) %>% 
  row_spec(1, bold = TRUE, color = "white", background = "#1f77b4")
Advance Retail Sales: Retail Trade (RSXFSN)
symbol min max mean median sd skew kurtosis
RSXFSN 130683 625145 316065.8 311292 106797.7 0.4703032 -0.2044121

Notable Features

Volatility:

The high standard deviation (106797.7) relative to the mean (316065.8) suggests significant volatility, which could have implications for forecasting and risk assessment.

Potential for Positive Outliers:

The positive skewness (0.4703032) suggests that there could be periods where sales exceed the average significantly, which is important for modeling scenarios that may capture such outliers.

Symmetry in Central Tendency:

The closeness of the mean(316065.8) and median (311292) indicates that while there may be occasional spikes, the general behavior of the series is not heavily affected by extreme values.

Forecasting Implications:

Given the high variability and potential for positive outliers, any forecasting model developed using this data may need to account for periods of rapid growth or spikes in sales.

Time Series & ACF/PACF

Time Series Plot and ACF/PACF Generate a time series plot and an ACF and PACF chart.

- Discuss any interesting features in the time series chart and the ACF and PACF related to potential non-stationarity, AR or MA lag orders, and potential seasonality
- If the data appears non-stationary, take a first difference and re-evaluate the ACF and PACF as above


Time Series Plot and ACF/PACF

# Converting to time series
retail_ts <- ts(retail_sales$price, start = c(1992, 1), frequency = 12)

# Plotting 
p <- autoplot(retail_ts) + ggtitle("U.S. Retail Sales (1992-2022)")
interactive_plot <- ggplotly(p)
interactive_plot
# ACF and PACF plots
acf_plot <- ggAcf(retail_ts) + ggtitle("ACF of Retail Sales") 
interactive_acf <- ggplotly(acf_plot)
interactive_acf
pacf_plot <- ggPacf(retail_ts) + ggtitle("PACF of Retail Sales")
interactive_pacf <- ggplotly(pacf_plot)
interactive_pacf


Time Series Plot and Autocorrelation Analysis Time Series Plot:
Notable Observations:
- Retail sales exhibit a strong upward trend from 1992 to 2022, suggesting potential non-stationarity.
- There are signs of seasonality, particularly in annual cycles, which aligns with economic patterns of consumer behavior.

ACF and PACF Charts (Before Differencing):

plot_grid(acf_plot, pacf_plot, align = "hv", rel_widths = c(1, 1), rel_heights = c(1, 1))

The ACF shows high autocorrelations at low lags that gradually decline, which is a typical sign of non-stationarity. The PACF has significant autocorrelations at the first few lags, suggesting potential AR stationarity.



Differencing to Address Non-Stationarity
ACF and PACF Charts (After First Differencing):

# First difference to remove trend
diff_retail_ts <- diff(retail_ts)
# Plotting differenced time series
autoplot(diff_retail_ts, facets=FALSE, ts.colour="#1f77b4") + 
  ggtitle("Differenced U.S. Retail Sales")

# ACF and PACF for differenced series
diff_retail_ts_acf <- ggAcf(diff_retail_ts) +
  ggtitle("ACF of Differenced Retail Sales")
interactive_diff_acf <- ggplotly(diff_retail_ts_acf)
interactive_diff_acf
diff_retail_ts_pacf <- ggPacf(diff_retail_ts) + ggtitle("PACF of Differenced Retail Sales")
interactive_diff_pacf <- ggplotly(diff_retail_ts_pacf)
interactive_diff_pacf


Given the strong trend and the behavior in the ACF and PACF charts, the data likely exhibits non-stationarity, potentially requiring first-differencing to stabilize the mean.
After taking first differences, the ACF shows significant autocorrelation at seasonal lags (e.g., lag 12), indicating the presence of seasonality. The PACF shows significant partial autocorrelations at lower lags, suggesting AR components.

AR Model & Forecasting

Lag Selection and Unit Root Testing Optimal Lag Order Using BIC: ARIMA Model Selection Using BIC

Auto ARIMA Model Selection:

# Use auto.arima to find the best ARIMA model based on BIC
auto_model <- auto.arima(retail_ts, seasonal = TRUE, ic = "bic")
summary(auto_model)
## Series: retail_ts 
## ARIMA(2,1,0)(0,1,1)[12] 
## 
## Coefficients:
##           ar1      ar2     sma1
##       -0.2897  -0.2934  -0.7146
## s.e.   0.0511   0.0509   0.0365
## 
## sigma^2 = 96894256:  log likelihood = -3760.08
## AIC=7528.16   AICc=7528.27   BIC=7543.63
## 
## Training set error measures:
##                    ME     RMSE    MAE       MPE     MAPE      MASE        ACF1
## Training set 421.7904 9626.525 6265.5 0.0291091 1.894702 0.3587668 0.008958633

Model Specification: ARIMA(2,1,0)(0,1,1)[12]

model_selected <- Arima(retail_ts, order = c(2, 1, 0), seasonal = c(0, 1, 1))
summary(model_selected)
## Series: retail_ts 
## ARIMA(2,1,0)(0,1,1)[12] 
## 
## Coefficients:
##           ar1      ar2     sma1
##       -0.2897  -0.2934  -0.7146
## s.e.   0.0511   0.0509   0.0365
## 
## sigma^2 = 96894256:  log likelihood = -3760.08
## AIC=7528.16   AICc=7528.27   BIC=7543.63
## 
## Training set error measures:
##                    ME     RMSE    MAE       MPE     MAPE      MASE        ACF1
## Training set 421.7904 9626.525 6265.5 0.0291091 1.894702 0.3587668 0.008958633
checkresiduals(model_selected)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(2,1,0)(0,1,1)[12]
## Q* = 77.973, df = 21, p-value = 1.757e-08
## 
## Model df: 3.   Total lags used: 24


Overall, this output suggests that the ARIMA(2,1,0)(0,1,1)[12] model provides a good fit for the retail sales data, as evidenced by the low AIC/BIC values and reasonable error measures.
It indicates that the model effectively captures both the trend and seasonality in the data. we can compare this model’s AIC/BIC values with other candidate models to ensure it’s the best choice for forecasting.

Unit Root Test (Augmented Dickey-Fuller):

# Augmented Dickey-Fuller Test
adf_test <- adf.test(diff_retail_ts, alternative = "stationary")
print(adf_test)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  diff_retail_ts
## Dickey-Fuller = -10.566, Lag order = 7, p-value = 0.01
## alternative hypothesis: stationary


Interpretation of the Results Dickey-Fuller Statistic:
The value of the Dickey-Fuller statistic (-10.566) is significantly negative. In general, the more negative this statistic, the stronger the evidence against the null hypothesis of a unit root.
The p-value is 0.01, which is less than the common significance level of 0.05. This indicates that we can reject the null hypothesis.
Since we can reject the null hypothesis, we conclude that the differenced series (diff_retail_ts) is stationary.
This means that the original series (retail_ts) was difference stationary.

Selection & Comparison

Based on your analysis in parts 2 and 3, select 3 potential candidate ARIMA(p,d,q)(P,D,Q) models • Estimate each model and compute information criteria • Compare and contrast the results from each model • Discuss which model appears to be the best fit in-sample


Using the three models proposed in part 4 • Use a training period from January 1990-Dec. 2009 • Generate 1-step ahead recursive forecasts using each model for the out-of-sample period from Jan. 2010 to Jul. 2022 • Plot the forecasts against the actual time series during the out-of-sample period • Use RMSE to compare the forecasting performance of each model • Which model is best?


ARIMA Model Selection and Estimation Candidate ARIMA Models:

# Manually explore alternative models
model_1 <- Arima(retail_ts, order = c(1,1,0), seasonal = c(1,1,0))
model_2 <- Arima(retail_ts, order = c(0,1,1), seasonal = c(0,1,1))
model_3 <- Arima(retail_ts, order = c(1,1,1), seasonal = c(1,1,1))

# Compare Auto Selected model with other models
AIC(model_selected, model_1, model_2, model_3)  
##                df      AIC
## model_selected  4 7528.156
## model_1         3 7619.501
## model_2         3 7540.931
## model_3         5 7534.199
BIC(model_selected, model_1, model_2, model_3)
##                df      BIC
## model_selected  4 7543.633
## model_1         3 7631.109
## model_2         3 7552.539
## model_3         5 7553.546


Forecasting with ARIMA Models

# test periods
train_end <- c(2014, 12)  
test_start <- c(2015, 1) 
test_end <- c(2022, 7)    

train_data <- window(retail_ts, end = train_end)
test_data <- window(retail_ts, start = test_start, end = test_end)

# model on training data
model_selected <- Arima(train_data, order = c(2, 1, 0), seasonal = c(0, 1, 1))

# Generating forecasts for the length of the test data
forecasts <- forecast(model_selected, h = length(test_data))
plot(forecasts)
lines(test_data, col = 'red')  # Add actual test data to the plot

# Calculate accuracy metrics
actuals <- test_data  # Actual values from the test set
predicted <- forecasts$mean  # Predicted values from the model

rmse <- sqrt(mean((actuals - predicted)^2))
mae <- mean(abs(actuals - predicted))
mape <- mean(abs((actuals - predicted) / actuals)) * 100

cat("RMSE:", rmse, "\nMAE:", mae, "\nMAPE:", mape, "%\n")
## RMSE: 35135.85 
## MAE: 24215.66 
## MAPE: 5.009539 %


Training and forecasting ARIMA Models (Manually selected):

# Fit ARIMA models on the training set
train_model_1 <- Arima(train_data, order = c(1,1,0), seasonal = c(1,1,0))
train_model_2 <- Arima(train_data, order = c(0,1,1), seasonal = c(0,1,1))
train_model_3 <- Arima(train_data, order = c(1,1,1), seasonal = c(1,1,1))


# forecasts
fc_1 <- forecast(train_model_1, h = length(test_data))
fc_2 <- forecast(train_model_2, h = length(test_data))
fc_3 <- forecast(train_model_3, h = length(test_data))

plot_fc_1 <- autoplot(fc_1) + ggtitle("Forecast Model 1- ARIMA(1,1,0)(1,1,0)")
plot_fc_2 <- autoplot(fc_2) + ggtitle("Forecast Model 2- ARIMA(0,1,1)(0,1,1)")
plot_fc_3 <- autoplot(fc_3) + ggtitle("Forecast Model 3- ARIMA(1,1,1)(1,1,1)")

# Combination of All plots
plot_grid(plot_fc_1, plot_fc_2, plot_fc_3, ncol = 1, align = "hv", rel_widths = c(1, 1, 1), rel_heights = c(1, 1, 1))


RMSE Comparison

# Calculate RMSE for each model
rmse_1 <- sqrt(mean((test_data - fc_1$mean)^2, na.rm = TRUE))
rmse_2 <- sqrt(mean((test_data - fc_2$mean)^2, na.rm = TRUE))
rmse_3 <- sqrt(mean((test_data - fc_3$mean)^2, na.rm = TRUE))

# Print RMSE for each model
cat("RMSE of ARIMA(1,1,0):", rmse_1, "\n")
## RMSE of ARIMA(1,1,0): 31873.37
cat("RMSE of ARIMA(0,1,1):", rmse_2, "\n")
## RMSE of ARIMA(0,1,1): 35229.9
cat("RMSE of ARIMA(1,1,1):", rmse_3, "\n")
## RMSE of ARIMA(1,1,1): 36625.75


Conclusion and Recommendations
Predictability of U.S. Retail Sales
Based on the analysis conducted on U.S. Retail Sales data from January 1992 to July 2022, it is evident that retail sales can be predicted with a reasonable degree of accuracy using time series modeling techniques. The presence of trends, seasonal patterns, and cyclical fluctuations makes the data amenable to forecasting methodologies, particularly ARIMA models.
Recommended Model
After evaluating various ARIMA models, including ARIMA(2,1,0)(0,1,1)[12], the results indicated that this model provided a suitable balance between fit and complexity, as evidenced by its lower AIC and BIC values compared to other candidate models.


Md Mahmudul Hasan
MQIM 3760573
Faculty of Management
University of New Brunswick
mahmudul.hasan@unb.ca


LS0tDQp0aXRsZTogIkEgQ29tcGFyYXRpdmUgQW5hbHlzaXMgb2YgVS5TLiBSZXRhaWwgU2FsZXMgRm9yZWNhc3RpbmcgTW9kZWxzOiBJbXBsaWNhdGlvbnMgZm9yIEludmVzdG1lbnQgRGVjaXNpb25zIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgaGlnaGxpZ2h0OiBlc3ByZXNzbw0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQojIyMjICoqTWQgTWFobXVkdWwgSGFzYW4qKg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4gYm9keSwgdGQge2ZvbnQtc2l6ZTogMTRweDt9IGNvZGUucntmb250LXNpemU6IDEycHg7fSBwcmUge2ZvbnQtc2l6ZTogMTRweH0gPC9zdHlsZT4NCjxzY3JpcHQgc3JjPSJodHRwczovL2NvZGUuanF1ZXJ5LmNvbS9qcXVlcnktMy43LjEuc2xpbS5taW4uanMiPjwvc2NyaXB0Pg0KPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPg0KICAkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHsNCiAgJCgnYScpLmF0dHIoJ3RhcmdldCcsICdfYmxhbmsnKTsNCiAgfSk7DQo8L3NjcmlwdD4NCjxzdHlsZT4NCi5ib3hlZCB7DQogIGJhY2tncm91bmQ6ICMyMzIwMjM7DQogIGNvbG9yOiB3aGl0ZTsNCiAgYm9yZGVyOiAwcHggc29saWQgIzUzNTM1MzsNCiAgbWFyZ2luOiAwcHggYXV0bzsNCiAgd2lkdGg6IGF1dG87DQogIHBhZGRpbmc6IDEwcHg7DQogIGJvcmRlci1yYWRpdXM6IDBweDsNCn0NCjwvc3R5bGU+DQoNCiMgIHsudGFic2V0fQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCglmaWcuYWxpZ24gPSAiY2VudGVyIiwNCgltZXNzYWdlID0gRkFMU0UsDQoJd2FybmluZyA9IEZBTFNFDQopDQpsaWJyYXJ5KGZwcDIpDQpsaWJyYXJ5KHRpZHlxdWFudCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShxdWFudG1vZCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShjdXJsKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KGd0RXh0cmFzKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoZ2dmb3J0aWZ5KQ0KbGlicmFyeShtb21lbnRzKQ0KbGlicmFyeShza2ltcikNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeSh0aWJibGUpDQpgYGANCg0KIyMgQXNzaWdubWVudDogDQo8YnI+DQoqQ29udGV4dDoqIA0KPGJyPg0KWW91IGFyZSBhIHF1YW50aXRhdGl2ZSBhbmFseXN0IGZvciBhIGhlZGdlIGZ1bmQgd2hpY2ggdXNlcyBwcmVkaWN0aXZlIG1vZGVscyBvZiB0aGUgZWNvbm9teSB0byB0cnkgdG8gZm9yZWNhc3QgbW92ZW1lbnRzIG9mIGtleSBlY29ub21pYyBpbmRpY2F0b3JzLCBhbmQgY3JlYXRlcyB0cmFkaW5nIHN0cmF0ZWdpZXMgd2hpY2ggYXR0ZW1wdCB0byDigJxmcm9udCBydW7igJ0gY2hhbmdlcyBpbiB0aGVzZSBpbmRpY2F0b3JzLiBZb3UgaGF2ZSBiZWVuIGFza2VkIGJ5IHlvdXIgRGlyZWN0b3IgdG8gY29tcGFyZSBzZXZlcmFsIG1vZGVscyBvZiBVLlMuIFJldGFpbCBTYWxlcywgZXZhbHVhdGUgdGhlaXIgZm9yZWNhc3RpbmcgYWJpbGl0eSwgYW5kIHN1Ym1pdCBhIHJlcG9ydCB0byBiZSBkaXNjdXNzZWQgYXQgeW91ciBuZXh0IGludmVzdG1lbnQgY29tbWl0dGVlIG1lZXRpbmcuPGJyPg0KPGJyPg0KKkFzc2lnbm1lbnQ6KiANCjxicj4NCi0gV2l0aGluIHRoZSBhYm92ZSBjb250ZXh0LCB3cml0ZSBhIHJlcG9ydCBzdWl0YWJsZSBmb3Igc2hhcmluZyB3aXRoIHlvdXIgdGVhbSBvbiB0aGUgbW9kZWxsaW5nIGFuZCBwcmVkaWN0YWJpbGl0eSBvZiBSZXRhaWwgU2FsZXMuDQo8YnI+DQotIFJldGFpbCBTYWxlczogTm9uLXNlYXNvbmFsbHkgYWRqdXN0ZWQgQWR2YW5jZSBSZXRhaWwgU2FsZXM6IFJldGFpbCBUcmFkZSBmcm9tIEZSRUQgZnJvbSBKYW51YXJ5IDE5OTAgdG8gSnVseSAyMDIyLg0KDQojIyBEYXRhDQpGZXRjaGluZyBEYXRhIGZyb20gRlJFRA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZHZhbmNlIFJldGFpbCBTYWxlczogUmV0YWlsIFRyYWRlIChSU1hGU04pDQojIERhdGEgaXMgbm90IGF2YWlsYWJsZSBmcm9tIDE5OTAsIGl0cyBhdmFpbGFibGUgZnJvbSAxOTkyIQ0KIyBodHRwczovL2ZyZWQuc3Rsb3Vpc2ZlZC5vcmcvc2VyaWVzL1JTWEZTTg0KDQpyZXRhaWxfc2FsZXM8LXRpZHlxdWFudDo6dHFfZ2V0KGMoIlJTWEZTTiIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdldD0iZWNvbm9taWMuZGF0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmcm9tPSIxOTkyLTAxLTAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0bz0iMjAyMi0wNy0zMSIpICU+JSANCiAgdGlkeXI6OmZpbGwocHJpY2UsLmRpcmVjdGlvbj0iZG93biIpICU+JSBzdGF0czo6bmEub21pdCgpDQoNCmthYmxlKGhlYWQocmV0YWlsX3NhbGVzKSkgJT4lIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIikpDQoNCmBgYA0KIyMgRGVzY3JpcHRpdmUgVGFibGUNCjxkaXYgY2xhc3M9ImJveGVkIj4NCkEgZnVsbCBkZXNjcmlwdGl2ZSB0YWJsZSBvZiB5b3VyIHRpbWUgc2VyaWVzIHZhcmlhYmxlLiBUaGlzIGluY2x1ZGVzICMgb2Ygb2JzZXJ2YXRpb25zLCAjIG9mIG1pc3NpbmcgdmFsdWVzLCBtZWFuLCBtZWRpYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgc2tld25lc3MsIGFuZCBrdXJ0b3Npcy4gRGlzY3VzcyBhbnkgbm90YWJsZSBzdGF0aXN0aWNhbCBmZWF0dXJlcyBvZiB5b3VyIHZhcmlhYmxlLg0KPC9kaXY+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpyZXRhaWxfc2FsZXMgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ltYm9sKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UobWluPW1pbihwcmljZSksIA0KICAgICAgICAgICAgICAgICAgIG1heD1tYXgocHJpY2UpLA0KICAgICAgICAgICAgICAgICAgIG1lYW49bWVhbihwcmljZSksDQogICAgICAgICAgICAgICAgICAgbWVkaWFuPW1lZGlhbihwcmljZSksIA0KICAgICAgICAgICAgICAgICAgIHNkPXNkKHByaWNlKSwgDQogICAgICAgICAgICAgICAgICAgc2tldz1za2V3bmVzcyhwcmljZSksIA0KICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0ga3VydG9zaXMocHJpY2UpIC0gMykgJT4lDQogIGthYmxlKGNhcHRpb249IkFkdmFuY2UgUmV0YWlsIFNhbGVzOiBSZXRhaWwgVHJhZGUgKFJTWEZTTikiKSAgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKSAlPiUgDQogIHJvd19zcGVjKDEsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSAiIzFmNzdiNCIpDQpgYGANCg0KKipOb3RhYmxlIEZlYXR1cmVzKiogDQo8YnI+DQo8YnI+DQoqVm9sYXRpbGl0eToqIA0KPGJyPg0KPGJyPg0KVGhlIGhpZ2ggc3RhbmRhcmQgZGV2aWF0aW9uICgxMDY3OTcuNykgcmVsYXRpdmUgdG8gdGhlIG1lYW4gKDMxNjA2NS44KSBzdWdnZXN0cyBzaWduaWZpY2FudCB2b2xhdGlsaXR5LCB3aGljaCBjb3VsZCBoYXZlIGltcGxpY2F0aW9ucyBmb3IgZm9yZWNhc3RpbmcgYW5kIHJpc2sgYXNzZXNzbWVudC4NCjxicj4NCjxicj4NCipQb3RlbnRpYWwgZm9yIFBvc2l0aXZlIE91dGxpZXJzOioNCjxicj4NCjxicj4NClRoZSBwb3NpdGl2ZSBza2V3bmVzcyAoMC40NzAzMDMyKSBzdWdnZXN0cyB0aGF0IHRoZXJlIGNvdWxkIGJlIHBlcmlvZHMgd2hlcmUgc2FsZXMgZXhjZWVkIHRoZSBhdmVyYWdlIHNpZ25pZmljYW50bHksIHdoaWNoIGlzIGltcG9ydGFudCBmb3IgbW9kZWxpbmcgc2NlbmFyaW9zIHRoYXQgbWF5IGNhcHR1cmUgc3VjaCBvdXRsaWVycy4NCjxicj4NCjxicj4NCipTeW1tZXRyeSBpbiBDZW50cmFsIFRlbmRlbmN5OiogDQo8YnI+DQo8YnI+DQpUaGUgY2xvc2VuZXNzIG9mIHRoZSBtZWFuKDMxNjA2NS44KSBhbmQgbWVkaWFuICgzMTEyOTIpIGluZGljYXRlcyB0aGF0IHdoaWxlIHRoZXJlIG1heSBiZSBvY2Nhc2lvbmFsIHNwaWtlcywgdGhlIGdlbmVyYWwgYmVoYXZpb3Igb2YgdGhlIHNlcmllcyBpcyBub3QgaGVhdmlseSBhZmZlY3RlZCBieSBleHRyZW1lIHZhbHVlcy4NCjxicj4NCjxicj4NCipGb3JlY2FzdGluZyBJbXBsaWNhdGlvbnM6KiANCjxicj4NCjxicj4NCkdpdmVuIHRoZSBoaWdoIHZhcmlhYmlsaXR5IGFuZCBwb3RlbnRpYWwgZm9yIHBvc2l0aXZlIG91dGxpZXJzLCBhbnkgZm9yZWNhc3RpbmcgbW9kZWwgZGV2ZWxvcGVkIHVzaW5nIHRoaXMgZGF0YSBtYXkgbmVlZCB0byBhY2NvdW50IGZvciBwZXJpb2RzIG9mIHJhcGlkIGdyb3d0aCBvciBzcGlrZXMgaW4gc2FsZXMuDQo8YnI+DQo8YnI+DQoNCiMjIFRpbWUgU2VyaWVzICYgQUNGL1BBQ0YNCg0KPGRpdiBjbGFzcz0iYm94ZWQiPg0KVGltZSBTZXJpZXMgUGxvdCBhbmQgQUNGL1BBQ0YNCkdlbmVyYXRlIGEgdGltZSBzZXJpZXMgcGxvdCBhbmQgYW4gQUNGIGFuZCBQQUNGIGNoYXJ0LlwNCjxicj4NCi0gRGlzY3VzcyBhbnkgaW50ZXJlc3RpbmcgZmVhdHVyZXMgaW4gdGhlIHRpbWUgc2VyaWVzIGNoYXJ0IGFuZCB0aGUgQUNGIGFuZCBQQUNGIHJlbGF0ZWQgdG8gcG90ZW50aWFsIG5vbi1zdGF0aW9uYXJpdHksIEFSIG9yIE1BIGxhZyBvcmRlcnMsIGFuZCBwb3RlbnRpYWwgc2Vhc29uYWxpdHlcDQotIElmIHRoZSBkYXRhIGFwcGVhcnMgbm9uLXN0YXRpb25hcnksIHRha2UgYSBmaXJzdCBkaWZmZXJlbmNlIGFuZCByZS1ldmFsdWF0ZSB0aGUgQUNGIGFuZCBQQUNGIGFzIGFib3ZlXA0KPC9kaXY+DQo8YnI+DQoqKlRpbWUgU2VyaWVzIFBsb3QgYW5kIEFDRi9QQUNGKioNCjxicj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENvbnZlcnRpbmcgdG8gdGltZSBzZXJpZXMNCnJldGFpbF90cyA8LSB0cyhyZXRhaWxfc2FsZXMkcHJpY2UsIHN0YXJ0ID0gYygxOTkyLCAxKSwgZnJlcXVlbmN5ID0gMTIpDQoNCiMgUGxvdHRpbmcgDQpwIDwtIGF1dG9wbG90KHJldGFpbF90cykgKyBnZ3RpdGxlKCJVLlMuIFJldGFpbCBTYWxlcyAoMTk5Mi0yMDIyKSIpDQppbnRlcmFjdGl2ZV9wbG90IDwtIGdncGxvdGx5KHApDQppbnRlcmFjdGl2ZV9wbG90DQojIEFDRiBhbmQgUEFDRiBwbG90cw0KYWNmX3Bsb3QgPC0gZ2dBY2YocmV0YWlsX3RzKSArIGdndGl0bGUoIkFDRiBvZiBSZXRhaWwgU2FsZXMiKSANCmludGVyYWN0aXZlX2FjZiA8LSBnZ3Bsb3RseShhY2ZfcGxvdCkNCmludGVyYWN0aXZlX2FjZg0KDQpwYWNmX3Bsb3QgPC0gZ2dQYWNmKHJldGFpbF90cykgKyBnZ3RpdGxlKCJQQUNGIG9mIFJldGFpbCBTYWxlcyIpDQppbnRlcmFjdGl2ZV9wYWNmIDwtIGdncGxvdGx5KHBhY2ZfcGxvdCkNCmludGVyYWN0aXZlX3BhY2YNCg0KYGBgDQo8YnI+DQpUaW1lIFNlcmllcyBQbG90IGFuZCBBdXRvY29ycmVsYXRpb24gQW5hbHlzaXMgVGltZSBTZXJpZXMgUGxvdDoNCjxicj4NCioqTm90YWJsZSBPYnNlcnZhdGlvbnM6KiogDQo8YnI+DQotIFJldGFpbCBzYWxlcyBleGhpYml0IGEgc3Ryb25nIHVwd2FyZCB0cmVuZCBmcm9tIDE5OTIgdG8gMjAyMiwgc3VnZ2VzdGluZyBwb3RlbnRpYWwgbm9uLXN0YXRpb25hcml0eS4gXA0KLSBUaGVyZSBhcmUgc2lnbnMgb2Ygc2Vhc29uYWxpdHksIHBhcnRpY3VsYXJseSBpbiBhbm51YWwgY3ljbGVzLCB3aGljaCBhbGlnbnMgd2l0aCBlY29ub21pYyBwYXR0ZXJucyBvZiBjb25zdW1lciBiZWhhdmlvci4gXA0KPGJyPg0KKipBQ0YgYW5kIFBBQ0YgQ2hhcnRzIChCZWZvcmUgRGlmZmVyZW5jaW5nKToqKg0KPGJyPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBsb3RfZ3JpZChhY2ZfcGxvdCwgcGFjZl9wbG90LCBhbGlnbiA9ICJodiIsIHJlbF93aWR0aHMgPSBjKDEsIDEpLCByZWxfaGVpZ2h0cyA9IGMoMSwgMSkpDQpgYGANCg0KKlRoZSBBQ0Ygc2hvd3MgaGlnaCBhdXRvY29ycmVsYXRpb25zIGF0IGxvdyBsYWdzIHRoYXQgZ3JhZHVhbGx5IGRlY2xpbmUsIHdoaWNoIGlzIGEgdHlwaWNhbCBzaWduIG9mIG5vbi1zdGF0aW9uYXJpdHkuKiANCipUaGUgUEFDRiBoYXMgc2lnbmlmaWNhbnQgYXV0b2NvcnJlbGF0aW9ucyBhdCB0aGUgZmlyc3QgZmV3IGxhZ3MsIHN1Z2dlc3RpbmcgcG90ZW50aWFsIEFSIHN0YXRpb25hcml0eS4qDQoNCjxicj4NCjxicj4NCg0KKipEaWZmZXJlbmNpbmcgdG8gQWRkcmVzcyBOb24tU3RhdGlvbmFyaXR5KioNCjxicj4NCkFDRiBhbmQgUEFDRiBDaGFydHMgKEFmdGVyIEZpcnN0IERpZmZlcmVuY2luZyk6DQo8YnI+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEZpcnN0IGRpZmZlcmVuY2UgdG8gcmVtb3ZlIHRyZW5kDQpkaWZmX3JldGFpbF90cyA8LSBkaWZmKHJldGFpbF90cykNCiMgUGxvdHRpbmcgZGlmZmVyZW5jZWQgdGltZSBzZXJpZXMNCmF1dG9wbG90KGRpZmZfcmV0YWlsX3RzLCBmYWNldHM9RkFMU0UsIHRzLmNvbG91cj0iIzFmNzdiNCIpICsgDQogIGdndGl0bGUoIkRpZmZlcmVuY2VkIFUuUy4gUmV0YWlsIFNhbGVzIikNCiMgQUNGIGFuZCBQQUNGIGZvciBkaWZmZXJlbmNlZCBzZXJpZXMNCmRpZmZfcmV0YWlsX3RzX2FjZiA8LSBnZ0FjZihkaWZmX3JldGFpbF90cykgKw0KICBnZ3RpdGxlKCJBQ0Ygb2YgRGlmZmVyZW5jZWQgUmV0YWlsIFNhbGVzIikNCmludGVyYWN0aXZlX2RpZmZfYWNmIDwtIGdncGxvdGx5KGRpZmZfcmV0YWlsX3RzX2FjZikNCmludGVyYWN0aXZlX2RpZmZfYWNmDQoNCmRpZmZfcmV0YWlsX3RzX3BhY2YgPC0gZ2dQYWNmKGRpZmZfcmV0YWlsX3RzKSArIGdndGl0bGUoIlBBQ0Ygb2YgRGlmZmVyZW5jZWQgUmV0YWlsIFNhbGVzIikNCmludGVyYWN0aXZlX2RpZmZfcGFjZiA8LSBnZ3Bsb3RseShkaWZmX3JldGFpbF90c19wYWNmKQ0KaW50ZXJhY3RpdmVfZGlmZl9wYWNmDQoNCmBgYA0KPGJyPg0KR2l2ZW4gdGhlIHN0cm9uZyB0cmVuZCBhbmQgdGhlIGJlaGF2aW9yIGluIHRoZSBBQ0YgYW5kIFBBQ0YgY2hhcnRzLCB0aGUgZGF0YSBsaWtlbHkgZXhoaWJpdHMgbm9uLXN0YXRpb25hcml0eSwgcG90ZW50aWFsbHkgcmVxdWlyaW5nIGZpcnN0LWRpZmZlcmVuY2luZyB0byBzdGFiaWxpemUgdGhlIG1lYW4uIA0KPGJyPg0KQWZ0ZXIgdGFraW5nIGZpcnN0IGRpZmZlcmVuY2VzLCB0aGUgQUNGIHNob3dzIHNpZ25pZmljYW50IGF1dG9jb3JyZWxhdGlvbiBhdCBzZWFzb25hbCBsYWdzIChlLmcuLCBsYWcgMTIpLCBpbmRpY2F0aW5nIHRoZSBwcmVzZW5jZSBvZiBzZWFzb25hbGl0eS4gVGhlIFBBQ0Ygc2hvd3Mgc2lnbmlmaWNhbnQgcGFydGlhbCBhdXRvY29ycmVsYXRpb25zIGF0IGxvd2VyIGxhZ3MsIHN1Z2dlc3RpbmcgQVIgY29tcG9uZW50cy4NCg0KIyMgQVIgTW9kZWwgJiBGb3JlY2FzdGluZw0KKipMYWcgU2VsZWN0aW9uIGFuZCBVbml0IFJvb3QgVGVzdGluZyBPcHRpbWFsIExhZyBPcmRlciBVc2luZyBCSUM6KioNCioqQVJJTUEgTW9kZWwgU2VsZWN0aW9uIFVzaW5nIEJJQyoqDQoNCioqQXV0byBBUklNQSBNb2RlbCBTZWxlY3Rpb246KioNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFVzZSBhdXRvLmFyaW1hIHRvIGZpbmQgdGhlIGJlc3QgQVJJTUEgbW9kZWwgYmFzZWQgb24gQklDDQphdXRvX21vZGVsIDwtIGF1dG8uYXJpbWEocmV0YWlsX3RzLCBzZWFzb25hbCA9IFRSVUUsIGljID0gImJpYyIpDQpzdW1tYXJ5KGF1dG9fbW9kZWwpDQoNCmBgYA0KDQo8IS0tIE1vZGVsIFNwZWNpZmljYXRpb246IEFSSU1BKDIsMSwwKSgwLDEsMSlbMTJdIC0tPg0KPCEtLSBBUklNQSgyLDEsMCk6IC0tPg0KDQo8IS0tIEFSIChBdXRvUmVncmVzc2l2ZSkgb3JkZXIgPSAyOiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSBtb2RlbCB1c2VzIHRoZSBwYXN0IDIgdmFsdWVzIG9mIHRoZSB0aW1lIHNlcmllcyB0byBwcmVkaWN0IGZ1dHVyZSB2YWx1ZXMuXCAtLT4NCjwhLS0gSSAoSW50ZWdyYXRlZCkgb3JkZXIgPSAxOiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIGRhdGEgd2FzIGRpZmZlcmVuY2VkIG9uY2UgdG8gYWNoaWV2ZSBzdGF0aW9uYXJpdHkuXCAtLT4NCjwhLS0gTUEgKE1vdmluZyBBdmVyYWdlKSBvcmRlciA9IDA6IFRoaXMgbWVhbnMgdGhhdCB0aGVyZSBpcyBubyBtb3ZpbmcgYXZlcmFnZSBjb21wb25lbnQgaW4gdGhpcyBwYXJ0IG9mIHRoZSBtb2RlbC5cIC0tPg0KDQo8IS0tIDxicj4gLS0+DQo8IS0tIDxicj4gLS0+DQo8IS0tIFNlYXNvbmFsIHBhcnQgKDAsMSwxKTpcIC0tPg0KPCEtLSBQIChTZWFzb25hbCBBUikgb3JkZXIgPSAwOiBObyBzZWFzb25hbCBhdXRvcmVncmVzc2l2ZSB0ZXJtcy5cIC0tPg0KPCEtLSBEIChTZWFzb25hbCBkaWZmZXJlbmNpbmcpIG9yZGVyID0gMTogU2Vhc29uYWwgZGlmZmVyZW5jaW5nIHdhcyBhcHBsaWVkIG9uY2UuXCAtLT4NCjwhLS0gUSAoU2Vhc29uYWwgTUEpIG9yZGVyID0gMTogQSBzZWFzb25hbCBtb3ZpbmcgYXZlcmFnZSBjb21wb25lbnQgd2FzIGluY2x1ZGVkLlwgLS0+DQo8IS0tIDxicj4gLS0+DQo8IS0tIDEyOiBJbmRpY2F0ZXMgdGhlIHNlYXNvbmFsaXR5IHBlcmlvZCAoMTIgbW9udGhzIGZvciBtb250aGx5IGRhdGEpLlwgLS0+DQoNCg0KPCEtLSBDb2VmZmljaWVudHNcIC0tPg0KPCEtLSBhcjE6IC0wLjI4OTcgKHdpdGggYSBzdGFuZGFyZCBlcnJvciBvZiAwLjA1MTEpXCAtLT4NCjwhLS0gYXIyOiAtMC4yOTM0ICh3aXRoIGEgc3RhbmRhcmQgZXJyb3Igb2YgMC4wNTA5KVwgLS0+DQo8IS0tIHNtYTE6IC0wLjcxNDYgKHdpdGggYSBzdGFuZGFyZCBlcnJvciBvZiAwLjAzNjUpXCAtLT4NCjwhLS0gVGhlc2UgY29lZmZpY2llbnRzIHJlcHJlc2VudCB0aGUgd2VpZ2h0cyBhcHBsaWVkIHRvIHRoZSBwcmV2aW91cyB2YWx1ZXMgYW5kIHRoZSBzZWFzb25hbCBtb3ZpbmcgYXZlcmFnZTpcIC0tPg0KDQo8IS0tIFRoZSBhcjEgYW5kIGFyMiBjb2VmZmljaWVudHMgYXJlIG5lZ2F0aXZlLCBpbmRpY2F0aW5nIHRoYXQgdGhlIGN1cnJlbnQgdmFsdWUgaXMgaW52ZXJzZWx5IHJlbGF0ZWQgdG8gaXRzIHR3byBwcmV2aW91cyB2YWx1ZXMuXCAtLT4NCjwhLS0gVGhlIHNtYTEgY29lZmZpY2llbnQgYmVpbmcgbmVnYXRpdmUgc3VnZ2VzdHMgdGhhdCB0aGUgY3VycmVudCB2YWx1ZSBpcyBuZWdhdGl2ZWx5IGluZmx1ZW5jZWQgYnkgdGhlIHByZXZpb3VzIHNlYXNvbmFsIGVycm9yIHRlcm0uXCAtLT4NCjwhLS0gMy4gTW9kZWwgRml0IFN0YXRpc3RpY3NcIC0tPg0KPCEtLSBzaWdtYV4yID0gOTY4OTQyNTY6IFRoaXMgaXMgdGhlIGVzdGltYXRlZCB2YXJpYW5jZSBvZiB0aGUgcmVzaWR1YWxzICh0aGUgZXJyb3JzIGZyb20gdGhlIG1vZGVsKS4gQSBsb3dlciB2YWx1ZSBpbmRpY2F0ZXMgYSBiZXR0ZXIgZml0LCB0aG91Z2ggaXQgc2hvdWxkIGJlIGNvbXBhcmVkIHJlbGF0aXZlIHRvIG90aGVyIG1vZGVscy5cIC0tPg0KPCEtLSBsb2cgbGlrZWxpaG9vZCA9IC0zNzYwLjA4OiBUaGlzIHN0YXRpc3RpYyBoZWxwcyBldmFsdWF0ZSB0aGUgbW9kZWwgZml0OyBoaWdoZXIgdmFsdWVzIChsZXNzIG5lZ2F0aXZlKSBpbmRpY2F0ZSBhIGJldHRlciBmaXQuXCAtLT4NCjwhLS0gNC4gSW5mb3JtYXRpb24gQ3JpdGVyaWFcIC0tPg0KPCEtLSBBSUMgPSA3NTI4LjE2OiBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uLiBMb3dlciB2YWx1ZXMgaW5kaWNhdGUgYSBiZXR0ZXIgZml0LCB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyB1c2VkIGluIHRoZSBtb2RlbC4gSXTigJlzIHVzZWZ1bCBmb3IgbW9kZWwgY29tcGFyaXNvbi5cIC0tPg0KPCEtLSBBSUNjID0gNzUyOC4yNzogQUlDIGNvcnJlY3RlZCBmb3Igc21hbGwgc2FtcGxlIHNpemVzLiBUaGlzIGlzIHNsaWdodGx5IGhpZ2hlciB0aGFuIEFJQyBidXQgaGFzIGEgc2ltaWxhciBpbnRlcnByZXRhdGlvbi5cIC0tPg0KPCEtLSBCSUMgPSA3NTQzLjYzOiBCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24uIExpa2UgQUlDLCBidXQgd2l0aCBhIGdyZWF0ZXIgcGVuYWx0eSBmb3IgdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzLiBMb3dlciB2YWx1ZXMgYXJlIGJldHRlciwgYW5kIGl0IGNhbiBiZSB1c2VkIGZvciBtb2RlbCBzZWxlY3Rpb24uXCAtLT4NCjwhLS0gNS4gVHJhaW5pbmcgU2V0IEVycm9yIE1lYXN1cmVzXCAtLT4NCjwhLS0gTUUgKE1lYW4gRXJyb3IpID0gNDIxLjc5MDQ6IFRoZSBhdmVyYWdlIG9mIHRoZSByZXNpZHVhbHMuIElkZWFsbHksIGl0IHNob3VsZCBiZSBjbG9zZSB0byB6ZXJvLCBpbmRpY2F0aW5nIG5vIHN5c3RlbWF0aWMgYmlhcyBpbiBwcmVkaWN0aW9ucy5cIC0tPg0KPCEtLSBSTVNFIChSb290IE1lYW4gU3F1YXJlIEVycm9yKSA9IDk2MjYuNTI1OiBUaGlzIG1lYXN1cmVzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHJlc2lkdWFscy4gQSBsb3dlciB2YWx1ZSBpbmRpY2F0ZXMgYSBiZXR0ZXIgZml0LlwgLS0+DQo8IS0tIE1BRSAoTWVhbiBBYnNvbHV0ZSBFcnJvcikgPSA2MjY1LjU6IFRoZSBhdmVyYWdlIGFic29sdXRlIGVycm9yLiBJdCBwcm92aWRlcyBhIHN0cmFpZ2h0Zm9yd2FyZCBtZWFzdXJlIG9mIHByZWRpY3Rpb24gYWNjdXJhY3kuXCAtLT4NCjwhLS0gTVBFIChNZWFuIFBlcmNlbnRhZ2UgRXJyb3IpID0gMC4wMjkxMDkxOiBUaGUgYXZlcmFnZSBvZiB0aGUgcGVyY2VudGFnZSBlcnJvcnMuIEEgdmFsdWUgbmVhciB6ZXJvIGluZGljYXRlcyBnb29kIGFjY3VyYWN5IHdpdGhvdXQgc3lzdGVtYXRpYyBiaWFzLlwgLS0+DQo8IS0tIE1BUEUgKE1lYW4gQWJzb2x1dGUgUGVyY2VudGFnZSBFcnJvcikgPSAxLjg5NDcwMjogQXZlcmFnZSBwZXJjZW50YWdlIGVycm9yOyB2YWx1ZXMgYmVsb3cgNSUgYXJlIHR5cGljYWxseSBjb25zaWRlcmVkIGV4Y2VsbGVudC5cIC0tPg0KPCEtLSBNQVNFIChNZWFuIEFic29sdXRlIFNjYWxlZCBFcnJvcikgPSAwLjM1ODc2Njg6IEEgbWVhc3VyZSB0aGF0IGNvbXBhcmVzIHRoZSBmb3JlY2FzdCBlcnJvciB0byBhIG5haXZlIGZvcmVjYXN0LiBWYWx1ZXMgbGVzcyB0aGFuIDEgaW5kaWNhdGUgYmV0dGVyIHBlcmZvcm1hbmNlIHRoYW4gYSBuYWl2ZSBtb2RlbC5cIC0tPg0KPCEtLSBBQ0YxID0gMC4wMDg5NTg2MzM6IFRoZSBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscyBhdCBsYWcgMS4gQSB2YWx1ZSBuZWFyIHplcm8gc3VnZ2VzdHMgbm8gc2lnbmlmaWNhbnQgYXV0b2NvcnJlbGF0aW9uLCBpbmRpY2F0aW5nIHRoZSBtb2RlbCBoYXMgY2FwdHVyZWQgdGhlIHJlbGF0aW9uc2hpcCBpbiB0aGUgZGF0YSB3ZWxsLlwgLS0+DQoqKk1vZGVsIFNwZWNpZmljYXRpb246IEFSSU1BKDIsMSwwKSgwLDEsMSlbMTJdKioNCjxicj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptb2RlbF9zZWxlY3RlZCA8LSBBcmltYShyZXRhaWxfdHMsIG9yZGVyID0gYygyLCAxLCAwKSwgc2Vhc29uYWwgPSBjKDAsIDEsIDEpKQ0Kc3VtbWFyeShtb2RlbF9zZWxlY3RlZCkNCg0KY2hlY2tyZXNpZHVhbHMobW9kZWxfc2VsZWN0ZWQpDQpgYGANCjxicj4NCk92ZXJhbGwsIHRoaXMgb3V0cHV0IHN1Z2dlc3RzIHRoYXQgdGhlIEFSSU1BKDIsMSwwKSgwLDEsMSlbMTJdIG1vZGVsIHByb3ZpZGVzIGEgZ29vZCBmaXQgZm9yIHRoZSByZXRhaWwgc2FsZXMgZGF0YSwgYXMgZXZpZGVuY2VkIGJ5IHRoZSBsb3cgQUlDL0JJQyB2YWx1ZXMgYW5kIHJlYXNvbmFibGUgZXJyb3IgbWVhc3VyZXMuDQo8YnI+DQpJdCBpbmRpY2F0ZXMgdGhhdCB0aGUgbW9kZWwgZWZmZWN0aXZlbHkgY2FwdHVyZXMgYm90aCB0aGUgdHJlbmQgYW5kIHNlYXNvbmFsaXR5IGluIHRoZSBkYXRhLiB3ZSBjYW4gY29tcGFyZSB0aGlzIG1vZGVsJ3MgQUlDL0JJQyB2YWx1ZXMgd2l0aCBvdGhlciBjYW5kaWRhdGUgbW9kZWxzIHRvIGVuc3VyZSBpdCdzIHRoZSBiZXN0IGNob2ljZSBmb3IgZm9yZWNhc3RpbmcuDQo8YnI+DQo8YnI+DQoqKlVuaXQgUm9vdCBUZXN0IChBdWdtZW50ZWQgRGlja2V5LUZ1bGxlcik6KioNCjxicj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEF1Z21lbnRlZCBEaWNrZXktRnVsbGVyIFRlc3QNCmFkZl90ZXN0IDwtIGFkZi50ZXN0KGRpZmZfcmV0YWlsX3RzLCBhbHRlcm5hdGl2ZSA9ICJzdGF0aW9uYXJ5IikNCnByaW50KGFkZl90ZXN0KQ0KDQpgYGANCjxicj4NCioqSW50ZXJwcmV0YXRpb24gb2YgdGhlIFJlc3VsdHMgRGlja2V5LUZ1bGxlciBTdGF0aXN0aWM6KioNCjxicj4NClRoZSB2YWx1ZSBvZiB0aGUgRGlja2V5LUZ1bGxlciBzdGF0aXN0aWMgKiooLTEwLjU2NikqKiBpcyBzaWduaWZpY2FudGx5IG5lZ2F0aXZlLiBJbiBnZW5lcmFsLCB0aGUgbW9yZSBuZWdhdGl2ZSB0aGlzIHN0YXRpc3RpYywgdGhlIHN0cm9uZ2VyIHRoZSBldmlkZW5jZSBhZ2FpbnN0IHRoZSBudWxsIGh5cG90aGVzaXMgb2YgYSB1bml0IHJvb3QuDQo8YnI+DQpUaGUgKipwLXZhbHVlIGlzIDAuMDEqKiwgd2hpY2ggaXMgbGVzcyB0aGFuIHRoZSBjb21tb24gc2lnbmlmaWNhbmNlIGxldmVsIG9mIDAuMDUuIFRoaXMgaW5kaWNhdGVzIHRoYXQgd2UgY2FuIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLg0KPGJyPg0KKipTaW5jZSB3ZSBjYW4gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMsIHdlIGNvbmNsdWRlIHRoYXQgdGhlIGRpZmZlcmVuY2VkIHNlcmllcyAoZGlmZl9yZXRhaWxfdHMpIGlzIHN0YXRpb25hcnkuKiogDQo8YnI+DQoqKlRoaXMgbWVhbnMgdGhhdCB0aGUgb3JpZ2luYWwgc2VyaWVzIChyZXRhaWxfdHMpIHdhcyBkaWZmZXJlbmNlIHN0YXRpb25hcnkuKioNCg0KDQojIyBTZWxlY3Rpb24gJiBDb21wYXJpc29uDQo8ZGl2IGNsYXNzPSJib3hlZCI+DQpCYXNlZCBvbiB5b3VyIGFuYWx5c2lzIGluIHBhcnRzIDIgYW5kIDMsIHNlbGVjdCAzIHBvdGVudGlhbCBjYW5kaWRhdGUgQVJJTUEocCxkLHEpKFAsRCxRKSBtb2RlbHMNCuKAoiBFc3RpbWF0ZSBlYWNoIG1vZGVsIGFuZCBjb21wdXRlIGluZm9ybWF0aW9uIGNyaXRlcmlhDQrigKIgQ29tcGFyZSBhbmQgY29udHJhc3QgdGhlIHJlc3VsdHMgZnJvbSBlYWNoIG1vZGVsDQrigKIgRGlzY3VzcyB3aGljaCBtb2RlbCBhcHBlYXJzIHRvIGJlIHRoZSBiZXN0IGZpdCBpbi1zYW1wbGUgDQo8L2Rpdj4NCjxicj4NCjxkaXYgY2xhc3M9ImJveGVkIj4NClVzaW5nIHRoZSB0aHJlZSBtb2RlbHMgcHJvcG9zZWQgaW4gcGFydCA0DQrigKIgVXNlIGEgdHJhaW5pbmcgcGVyaW9kIGZyb20gSmFudWFyeSAxOTkwLURlYy4gMjAwOQ0K4oCiIEdlbmVyYXRlIDEtc3RlcCBhaGVhZCByZWN1cnNpdmUgZm9yZWNhc3RzIHVzaW5nIGVhY2ggbW9kZWwgZm9yIHRoZSBvdXQtb2Ytc2FtcGxlIHBlcmlvZCBmcm9tIEphbi4gMjAxMCB0byBKdWwuIDIwMjINCuKAoiBQbG90IHRoZSBmb3JlY2FzdHMgYWdhaW5zdCB0aGUgYWN0dWFsIHRpbWUgc2VyaWVzIGR1cmluZyB0aGUgb3V0LW9mLXNhbXBsZSBwZXJpb2QNCuKAoiBVc2UgUk1TRSB0byBjb21wYXJlIHRoZSBmb3JlY2FzdGluZyBwZXJmb3JtYW5jZSBvZiBlYWNoIG1vZGVsDQrigKIgV2hpY2ggbW9kZWwgaXMgYmVzdD8NCjwvZGl2Pg0KPGJyPg0KKipBUklNQSBNb2RlbCBTZWxlY3Rpb24gYW5kIEVzdGltYXRpb24gQ2FuZGlkYXRlIEFSSU1BIE1vZGVsczoqKg0KPGJyPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgTWFudWFsbHkgZXhwbG9yZSBhbHRlcm5hdGl2ZSBtb2RlbHMNCm1vZGVsXzEgPC0gQXJpbWEocmV0YWlsX3RzLCBvcmRlciA9IGMoMSwxLDApLCBzZWFzb25hbCA9IGMoMSwxLDApKQ0KbW9kZWxfMiA8LSBBcmltYShyZXRhaWxfdHMsIG9yZGVyID0gYygwLDEsMSksIHNlYXNvbmFsID0gYygwLDEsMSkpDQptb2RlbF8zIDwtIEFyaW1hKHJldGFpbF90cywgb3JkZXIgPSBjKDEsMSwxKSwgc2Vhc29uYWwgPSBjKDEsMSwxKSkNCg0KIyBDb21wYXJlIEF1dG8gU2VsZWN0ZWQgbW9kZWwgd2l0aCBvdGhlciBtb2RlbHMNCkFJQyhtb2RlbF9zZWxlY3RlZCwgbW9kZWxfMSwgbW9kZWxfMiwgbW9kZWxfMykgIA0KQklDKG1vZGVsX3NlbGVjdGVkLCBtb2RlbF8xLCBtb2RlbF8yLCBtb2RlbF8zKQ0KYGBgDQoNCjxicj4NCkZvcmVjYXN0aW5nIHdpdGggQVJJTUEgTW9kZWxzDQo8YnI+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyB0ZXN0IHBlcmlvZHMNCnRyYWluX2VuZCA8LSBjKDIwMTQsIDEyKSAgDQp0ZXN0X3N0YXJ0IDwtIGMoMjAxNSwgMSkgDQp0ZXN0X2VuZCA8LSBjKDIwMjIsIDcpICAgIA0KDQp0cmFpbl9kYXRhIDwtIHdpbmRvdyhyZXRhaWxfdHMsIGVuZCA9IHRyYWluX2VuZCkNCnRlc3RfZGF0YSA8LSB3aW5kb3cocmV0YWlsX3RzLCBzdGFydCA9IHRlc3Rfc3RhcnQsIGVuZCA9IHRlc3RfZW5kKQ0KDQojIG1vZGVsIG9uIHRyYWluaW5nIGRhdGENCm1vZGVsX3NlbGVjdGVkIDwtIEFyaW1hKHRyYWluX2RhdGEsIG9yZGVyID0gYygyLCAxLCAwKSwgc2Vhc29uYWwgPSBjKDAsIDEsIDEpKQ0KDQojIEdlbmVyYXRpbmcgZm9yZWNhc3RzIGZvciB0aGUgbGVuZ3RoIG9mIHRoZSB0ZXN0IGRhdGENCmZvcmVjYXN0cyA8LSBmb3JlY2FzdChtb2RlbF9zZWxlY3RlZCwgaCA9IGxlbmd0aCh0ZXN0X2RhdGEpKQ0KcGxvdChmb3JlY2FzdHMpDQpsaW5lcyh0ZXN0X2RhdGEsIGNvbCA9ICdyZWQnKSAgIyBBZGQgYWN0dWFsIHRlc3QgZGF0YSB0byB0aGUgcGxvdA0KIyBDYWxjdWxhdGUgYWNjdXJhY3kgbWV0cmljcw0KYWN0dWFscyA8LSB0ZXN0X2RhdGEgICMgQWN0dWFsIHZhbHVlcyBmcm9tIHRoZSB0ZXN0IHNldA0KcHJlZGljdGVkIDwtIGZvcmVjYXN0cyRtZWFuICAjIFByZWRpY3RlZCB2YWx1ZXMgZnJvbSB0aGUgbW9kZWwNCg0Kcm1zZSA8LSBzcXJ0KG1lYW4oKGFjdHVhbHMgLSBwcmVkaWN0ZWQpXjIpKQ0KbWFlIDwtIG1lYW4oYWJzKGFjdHVhbHMgLSBwcmVkaWN0ZWQpKQ0KbWFwZSA8LSBtZWFuKGFicygoYWN0dWFscyAtIHByZWRpY3RlZCkgLyBhY3R1YWxzKSkgKiAxMDANCg0KY2F0KCJSTVNFOiIsIHJtc2UsICJcbk1BRToiLCBtYWUsICJcbk1BUEU6IiwgbWFwZSwgIiVcbiIpDQoNCmBgYA0KPGJyPg0KKipUcmFpbmluZyBhbmQgZm9yZWNhc3RpbmcgQVJJTUEgTW9kZWxzIChNYW51YWxseSBzZWxlY3RlZCk6KioNCjxicj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgRml0IEFSSU1BIG1vZGVscyBvbiB0aGUgdHJhaW5pbmcgc2V0DQp0cmFpbl9tb2RlbF8xIDwtIEFyaW1hKHRyYWluX2RhdGEsIG9yZGVyID0gYygxLDEsMCksIHNlYXNvbmFsID0gYygxLDEsMCkpDQp0cmFpbl9tb2RlbF8yIDwtIEFyaW1hKHRyYWluX2RhdGEsIG9yZGVyID0gYygwLDEsMSksIHNlYXNvbmFsID0gYygwLDEsMSkpDQp0cmFpbl9tb2RlbF8zIDwtIEFyaW1hKHRyYWluX2RhdGEsIG9yZGVyID0gYygxLDEsMSksIHNlYXNvbmFsID0gYygxLDEsMSkpDQoNCg0KIyBmb3JlY2FzdHMNCmZjXzEgPC0gZm9yZWNhc3QodHJhaW5fbW9kZWxfMSwgaCA9IGxlbmd0aCh0ZXN0X2RhdGEpKQ0KZmNfMiA8LSBmb3JlY2FzdCh0cmFpbl9tb2RlbF8yLCBoID0gbGVuZ3RoKHRlc3RfZGF0YSkpDQpmY18zIDwtIGZvcmVjYXN0KHRyYWluX21vZGVsXzMsIGggPSBsZW5ndGgodGVzdF9kYXRhKSkNCg0KcGxvdF9mY18xIDwtIGF1dG9wbG90KGZjXzEpICsgZ2d0aXRsZSgiRm9yZWNhc3QgTW9kZWwgMS0gQVJJTUEoMSwxLDApKDEsMSwwKSIpDQpwbG90X2ZjXzIgPC0gYXV0b3Bsb3QoZmNfMikgKyBnZ3RpdGxlKCJGb3JlY2FzdCBNb2RlbCAyLSBBUklNQSgwLDEsMSkoMCwxLDEpIikNCnBsb3RfZmNfMyA8LSBhdXRvcGxvdChmY18zKSArIGdndGl0bGUoIkZvcmVjYXN0IE1vZGVsIDMtIEFSSU1BKDEsMSwxKSgxLDEsMSkiKQ0KDQojIENvbWJpbmF0aW9uIG9mIEFsbCBwbG90cw0KcGxvdF9ncmlkKHBsb3RfZmNfMSwgcGxvdF9mY18yLCBwbG90X2ZjXzMsIG5jb2wgPSAxLCBhbGlnbiA9ICJodiIsIHJlbF93aWR0aHMgPSBjKDEsIDEsIDEpLCByZWxfaGVpZ2h0cyA9IGMoMSwgMSwgMSkpDQoNCg0KYGBgDQo8YnI+DQoqKlJNU0UgQ29tcGFyaXNvbioqDQo8YnI+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDYWxjdWxhdGUgUk1TRSBmb3IgZWFjaCBtb2RlbA0Kcm1zZV8xIDwtIHNxcnQobWVhbigodGVzdF9kYXRhIC0gZmNfMSRtZWFuKV4yLCBuYS5ybSA9IFRSVUUpKQ0Kcm1zZV8yIDwtIHNxcnQobWVhbigodGVzdF9kYXRhIC0gZmNfMiRtZWFuKV4yLCBuYS5ybSA9IFRSVUUpKQ0Kcm1zZV8zIDwtIHNxcnQobWVhbigodGVzdF9kYXRhIC0gZmNfMyRtZWFuKV4yLCBuYS5ybSA9IFRSVUUpKQ0KDQojIFByaW50IFJNU0UgZm9yIGVhY2ggbW9kZWwNCmNhdCgiUk1TRSBvZiBBUklNQSgxLDEsMCk6Iiwgcm1zZV8xLCAiXG4iKQ0KY2F0KCJSTVNFIG9mIEFSSU1BKDAsMSwxKToiLCBybXNlXzIsICJcbiIpDQpjYXQoIlJNU0Ugb2YgQVJJTUEoMSwxLDEpOiIsIHJtc2VfMywgIlxuIikNCg0KYGBgDQo8YnI+DQoqKkNvbmNsdXNpb24gYW5kIFJlY29tbWVuZGF0aW9ucyoqDQo8YnI+DQoqUHJlZGljdGFiaWxpdHkgb2YgVS5TLiBSZXRhaWwgU2FsZXMqDQo8YnI+DQpCYXNlZCBvbiB0aGUgYW5hbHlzaXMgY29uZHVjdGVkIG9uIFUuUy4gUmV0YWlsIFNhbGVzIGRhdGEgZnJvbSBKYW51YXJ5IDE5OTIgdG8gSnVseSAyMDIyLCBpdCBpcyBldmlkZW50IHRoYXQgcmV0YWlsIHNhbGVzIGNhbiBiZSBwcmVkaWN0ZWQgd2l0aCBhIHJlYXNvbmFibGUgZGVncmVlIG9mIGFjY3VyYWN5IHVzaW5nIHRpbWUgc2VyaWVzIG1vZGVsaW5nIHRlY2huaXF1ZXMuIFRoZSBwcmVzZW5jZSBvZiB0cmVuZHMsIHNlYXNvbmFsIHBhdHRlcm5zLCBhbmQgY3ljbGljYWwgZmx1Y3R1YXRpb25zIG1ha2VzIHRoZSBkYXRhIGFtZW5hYmxlIHRvIGZvcmVjYXN0aW5nIG1ldGhvZG9sb2dpZXMsIHBhcnRpY3VsYXJseSBBUklNQSBtb2RlbHMuDQo8YnI+DQoqKlJlY29tbWVuZGVkIE1vZGVsKioNCjxicj4NCkFmdGVyIGV2YWx1YXRpbmcgdmFyaW91cyBBUklNQSBtb2RlbHMsIGluY2x1ZGluZyBBUklNQSgyLDEsMCkoMCwxLDEpWzEyXSwgdGhlIHJlc3VsdHMgaW5kaWNhdGVkIHRoYXQgdGhpcyBtb2RlbCBwcm92aWRlZCBhIHN1aXRhYmxlIGJhbGFuY2UgYmV0d2VlbiBmaXQgYW5kIGNvbXBsZXhpdHksIGFzIGV2aWRlbmNlZCBieSBpdHMgbG93ZXIgQUlDIGFuZCBCSUMgdmFsdWVzIGNvbXBhcmVkIHRvIG90aGVyIGNhbmRpZGF0ZSBtb2RlbHMuDQoNCg0KPGJyPg0KDQo8c3Bhbj4gIDxzcGFuIHN0eWxlPSJjb2xvcjogU3RlZWxibHVlOyI+KipNZCBNYWhtdWR1bCBIYXNhbioqPC9zcGFuPiBcDQpNUUlNIDM3NjA1NzNcDQpGYWN1bHR5IG9mIE1hbmFnZW1lbnQgXA0KVW5pdmVyc2l0eSBvZiBOZXcgQnJ1bnN3aWNrIFwNCm1haG11ZHVsLmhhc2FuXEB1bmIuY2EgXA0KDQo8YnI+DQo=