library(fpp3)
library(mlbench)
library(dplyr)
library(ggplot2)
library(tsibble)
library(tidyr)
library(corrplot)
library(cowplot)
library(psych)
library(MASS)
library(gridExtra)
library(tidyr)
library(stringr)
Introduction
Do exercises 8.1, 8.5, 8.6, 8.7, 8.8, 8.9 in Hyndman. Please submit
both the link to your Rpubs and the .pdf file with your run code.
8.1
Consider the number of pigs slaughtered in Victoria, available in the
aus_livestock dataset.
pigs_df<- aus_livestock%>%
filter(str_detect(Animal,"Pigs"),str_detect(State,"Victoria"))
pigs_df%>%
autoplot(Count)+
labs(y="Pig Count",
x="Month | Year",
title = "Slaughtered Pig Count, Victoria (Jul 1972 - Dec 2018)")+
geom_smooth(formula = y ~ x)

a.
Use the ETS() function to estimate the equivalent model for simple
exponential smoothing. Find the optimal values of \(\alpha\) and \(\ell\) 0, and generate forecasts for the
next four months.
Error Trend and Seasonality or Exponential Smoothing (ETS) Model:
8.1 Example: Algerian export
# Estimate parameters
fit <- algeria_economy |>
model(ETS(Exports ~ error("A") + trend("N") + season("N")))
fc <- fit |>
forecast(h = 5)
# Estimate parameters
pigs_fit <- pigs_df %>%
model(ETS(Count ~ error("A") + trend("N") + season("N")))
report(pigs_fit)
Series: Count
Model: ETS(A,N,N)
Smoothing parameters:
alpha = 0.3221247
Initial states:
l[0]
100646.6
sigma^2: 87480760
AIC AICc BIC
13737.10 13737.14 13750.07
OPTIMAL = \(\alpha\) =
0.3221247 \(\ell\) = 100646.6
(pigs_fc <- pigs_fit%>%
forecast(h = 4))
pigs_fc%>%
autoplot()+
geom_line(data=filter(pigs_df, Month >= yearmonth('2016 Jan')),
aes(x=Month,y=Count),color="lightgreen")

NA
b.
Compute a 95% prediction interval for the first forecast using \(\hat{y}\pm1.96s\) where \(s\) is the standard deviation of the
residuals. Compare your interval with the interval produced by \(R\).
class(pigs_fc)
[1] "fbl_ts" "tbl_ts" "tbl_df" "tbl" "data.frame"
pigs_yhat <- pigs_fc$.mean[1]
pigs_aug<- augment(pigs_fit)
pigs_sd<- sd(pigs_aug$.resid)
pigs_upper95<-pigs_yhat+(pigs_sd*1.96)
pigs_lower95<-pigs_yhat-(pigs_sd*1.96)
pigs_hilo<-pigs_fc%>%hilo()
paste0("Lower 95% ",pigs_lower95," Mean ",pigs_yhat, " Upper 95% ",pigs_upper95)
[1] "Lower 95% 76871.0124775157 Mean 95186.5574309915 Upper 95% 113502.102384467"
paste0("While our forecast had the values", pigs_hilo$`95%`[1],
" with a mean of ", pigs_hilo$.mean[1] )
[1] "While our forecast had the values[76854.7888896402, 113518.325972343]95 with a mean of 95186.5574309915"
The values match if we were going off whole numbers, but using
the functions in R provided a greater level of
accuracy.
8.5
Data set global_economy contains the annual Exports from
many countries. Select one country to analyse.
usa_df<-global_economy%>%
filter(Country=="United States" )
a.
Plot the Exports series and discuss the main features of the
data.
usa_df %>% autoplot(Exports)+
labs(y = "GDP (Percentage %)",x = "Year", title = "United States Export Series")

b.
Use an ETS(A,N,N) model to forecast the series, and plot the
forecasts.
usa_df <- na.omit(usa_df)
usa_fit <- usa_df %>%
model(ETS(Exports ~ error("A") + trend("N") + season("N")))
usa_fc <- usa_fit %>%
forecast(h = 5)
usa_fc %>%
autoplot(usa_df) +
geom_line(aes(y = .fitted), col="green",
data = augment(usa_fit)) +
labs(y="% of GDP", title="Exports: United States") +
guides(colour = "none")

c.
Compute the RMSE values for the training data.
accuracy(usa_fit)
d.
Compare the results to those from an ETS(A,A,N) model. (Remember that
the trended model is using one more parameter than the simpler model.)
Discuss the merits of the two forecasting methods for this data set.
usa_RMSE_ETS<-accuracy(usa_df %>%
model(
ANN = ETS (Exports ~ error("A") + trend("N") + season("N")),
AAN = ETS (Exports ~ error("A") + trend("A") + season("N"))
))[["RMSE"]]
usa_RMSE_train<-accuracy(usa_fit)[["RMSE"]]
paste0("Training Model RMSE is ",usa_RMSE_train)
[1] "Training Model RMSE is 0.631987696877015"
paste0("Compared to ")
[1] "Compared to "
paste0(usa_RMSE_ETS)
[1] "0.631987696877015" "0.620934771848593"
With the AAN model providing a smaller RMSE by about 0.011 than ANN,
it suggests a better model lies with AAN.
e.
Compare the forecasts from both methods. Which do you think is
best?
usa_df %>%
model(
ANN = ETS (Exports ~ error("A") + trend("N") + season("N")),
AAN = ETS (Exports ~ error("A") + trend("A") + season("N"))
) %>%
forecast(h=4) %>%
autoplot(usa_df, level=NULL) +
labs(title="US Export Predictions")

f.
Calculate a 95% prediction interval for the first forecast for each
model, using the RMSE values and assuming normal errors. Compare your
intervals with those produced using R.
usa_yhat <- usa_fc$.mean[1]
usa_aug <- augment(usa_fit)
usa_sd <- sd(usa_aug$.resid)
usa_upper95 <- usa_yhat + (usa_sd * 1.96)
usa_lower95 <- usa_yhat - (usa_sd * 1.96)
usa_hilo <- usa_fc %>% hilo()
paste0("Lower 95% ",usa_lower95," Mean ",usa_yhat, " Upper 95% ",usa_upper95)
[1] "Lower 95% 10.6654088104703 Mean 11.8906832823187 Upper 95% 13.115957754167"
paste0("While our forecast had the values", usa_hilo$`95%`[1],
" with a mean of ", usa_hilo$.mean[1] )
[1] "While our forecast had the values[10.6292803146377, 13.1520862499996]95 with a mean of 11.8906832823187"
Both are accurate up to the first decimal. The method using R vs the
manual, accounts for degrees of freedom and has a more precise value for
the critical values, but also does gave a greater range.
paste0(“Lower 95%”,pigs_lower95,” Mean “,pigs_yhat,” Upper 95%
“,pigs_upper95) paste0(”While our forecast had the values”,
pigs_hilo\(`95%`[1], " with a mean of
", pigs_hilo\).mean[1] )
8.6
Forecast the Chinese GDP from the global_economy data set using an
ETS model. Experiment with the various options in the ETS() function to
see how much the forecasts change with damped trend, or with a Box-Cox
transformation. Try to develop an intuition of what each is doing to the
forecasts.
[Hint: use a relatively large value of h when forecasting, so you can
clearly see the differences between the various options when plotting
the forecasts.]
china_df <- global_economy %>%
filter(Country == "China")
china_plot1<-china_df %>% autoplot(GDP) +
labs(title="Chinese GDP")
china_lambda <- china_df %>%
features(GDP, features = guerrero) %>%
pull(lambda_guerrero)
fit_china <- china_df %>%
model(
# ETS
ETS = ETS(GDP),
# Log Transformation
`Log` = ETS(log(GDP)),
# Damped Model
`Damped` = ETS(GDP ~ trend("Ad")),
# Box-Cox Transformation
`Box-Cox` = ETS(box_cox(GDP, china_lambda)),
# Damped Model w Box-Cox Transformation
`Box-Cox, Damped` = ETS(box_cox(GDP, china_lambda) ~ trend("Ad"))
)
china_plot2<-fit_china %>%
forecast(h="20 years") %>%
autoplot(china_df, level = NULL)+
labs(title="Chinese GDP Forecast") +
guides(colour = guide_legend(title = "Forecast"))
plot_grid(china_plot1,
china_plot2, nrow = 2)

Damped and ETS show similar continued
growth, while Log and Box-Cox seem to
exaggerate its forecast. Box-Cox, Damped shows
slightly more growth than ETS and Damped.
8.7
Find an ETS model for the Gas data from aus_production
and forecast the next few years. Why is multiplicative seasonality
necessary here? Experiment with making the trend damped. Does it improve
the forecasts?
*Seasonal variation makes multiplicative seasonality necessary.
gas_plot1<-aus_production %>% autoplot(Gas)+
labs(title="Austrailian Gas Production")
gas_fit <- aus_production %>%
model(
# Multiplicative
Multiplicative = ETS(Gas ~ error("M") + trend("A") + season("M")),
# Damped multiplicative
`Multiplicative, Damped` = ETS(Gas ~ error("M") + trend("Ad") + season("M"))
)
gas_fc <- gas_fit %>% forecast(h = "5 years")
gas_plot2<-gas_fc %>%
autoplot(aus_production, level = NULL) +
labs(title="Australian Gas Production Forecast") +
guides(colour = guide_legend(title = "Forecast"))
plot_grid(gas_plot1,
gas_plot2, nrow = 2)

Very little difference between the two models. About 3.099
difference, meaning either would be accurate or optimal
rm(list = ls()[!grepl("^my", ls())])
8.8
Recall your retail time series data (from Exercise 7 in Section 2.10).
a.
Why is multiplicative seasonality necessary for this series?
B/c there is clear seasonality and peaks on January
b.
Apply Holt-Winters’ multiplicative method to the data. Experiment
with making the trend damped.
set.seed(123)
myseries <- aus_retail %>%
filter(`Series ID` == sample(aus_retail$`Series ID`,1))
myfit <- myseries %>%
model(
`Holt-Winters’ Multiplicative` = ETS(Turnover ~ error("M") + trend("A") +
season("M")),
`Holt-Winters’ Damped Multiplicative` = ETS(Turnover ~ error("M") + trend("Ad") +
season("M"))
)
myfc <- myfit %>% forecast(h = "5 years")
myfc %>%
autoplot(myseries, level = NULL) +
labs(title="Australian Department Stores",
y="Turnover") +
guides(colour = guide_legend(title = "Forecast"))

c.
Compare the RMSE of the one-step forecasts from the two methods.
Which do you prefer?
accuracy(myfit)%>%
dplyr::select(".model","RMSE")
NA
The values are pretty close, within 0.62109 of each other, but the
Dampled has the lower of the two.
d.
Check that the residuals from the best method look like white
noise.
myfit%>%
dplyr::select("Holt-Winters’ Damped Multiplicative")%>%gg_tsresiduals()

NA
Holt-Winters’ Damped Multiplicative is not white noise
base on the acf plot, which has over 5% of the spikes out
ousid of the bounds made by dashed lines.
e.
Now find the test set RMSE, while training the model to the end of
2010. Can you beat the seasonal naïve approach from Exercise 7 in
Section 5.11?
mytrain<-myseries%>%
filter(Month >= yearmonth('2011 Jan'))
# seasonal naïve
myfit2 <- mytrain %>%
model(
"Holt-Winters' Damped" = ETS(Turnover ~ error("M") + trend("Ad") +
season("M")),
"Holt-Winters' Multiplicative" = ETS(Turnover ~ error("M") + trend("A") +
season("M")),
"Seasonal Naïve Forecast" = SNAIVE(Turnover)
)
comparison <- anti_join(myseries, mytrain,
by = c("State", "Industry", "Series ID", "Month", "Turnover"))
# Do the forecasting according to comparison data
myfc2 <- myfit2 %>%
forecast(comparison)
# plot
autoplot(comparison, Turnover) +
autolayer(myfc2, level = NULL) +
guides(colour=guide_legend(title="Forecast")) +
ggtitle('Forecast Comparison (AUS Dept Stores)')

accuracy(myfit2)
It appears the Damped model is the best performing, base on the RMSE
values.
8.9
For the same retail data, try an STL decomposition applied to the
Box-Cox transformed series, followed by ETS on the seasonally adjusted
data. How does that compare with your best previous forecasts on the
test set?
#find optimal lambda
mylambda <- mytrain %>%
features(Turnover, features = guerrero) %>%
pull(lambda_guerrero)
#bc transformed data
ts_bc <- mytrain %>%
mutate(
bc_turnover = box_cox(Turnover, mylambda)
)
# bc transformed model
fit <- ts_bc %>%
model(
'Box-Cox STL' = STL(bc_turnover ~ season(window = "periodic"),
robust = T),
'Box-Cox ETS' = ETS(bc_turnover)
)
# best previous model
best_fit <-ts_bc %>%
model(
"Holt-Winters' Damped" = ETS(Turnover ~ error("M") + trend("Ad") +
season("M"))
)
rbind(accuracy(fit),accuracy(best_fit))
Based on the Values the Box-Cox ETS is the best performing of the
three.
LS0tCnRpdGxlOiAnREFUQSA2MjQ6IFBSRURJQ1RJVkUgQU5BTFlUSUNTIEhXNScKYXV0aG9yOiAiR2FicmllbCBDYW1wb3MiCmRhdGU6ICJMYXN0IGVkaXRlZCBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBnZW9tZXRyeTogbGVmdD0wLjVjbSxyaWdodD0wLjVjbSx0b3A9MWNtLGJvdHRvbT0yY20KICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OgogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4CnVybGNvbG9yOiBibHVlCi0tLQoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZnBwMykKbGlicmFyeShtbGJlbmNoKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodHNpYmJsZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCgpgYGAKCiMgSW50cm9kdWN0aW9uCgpEbyBleGVyY2lzZXMgOC4xLCA4LjUsIDguNiwgOC43LCA4LjgsIDguOSAgaW4gSHluZG1hbi4gIFBsZWFzZSBzdWJtaXQgYm90aCB0aGUgbGluayB0byB5b3VyIFJwdWJzIGFuZCB0aGUgLnBkZiBmaWxlIHdpdGggeW91ciBydW4gY29kZS4KCiMgOC4xCgpDb25zaWRlciB0aGUgbnVtYmVyIG9mIHBpZ3Mgc2xhdWdodGVyZWQgaW4gVmljdG9yaWEsIGF2YWlsYWJsZSBpbiB0aGUgYGF1c19saXZlc3RvY2tgIGRhdGFzZXQuCgpgYGB7cn0KcGlnc19kZjwtIGF1c19saXZlc3RvY2slPiUKICAgICAgICAgICAgZmlsdGVyKHN0cl9kZXRlY3QoQW5pbWFsLCJQaWdzIiksc3RyX2RldGVjdChTdGF0ZSwiVmljdG9yaWEiKSkKYGBgCgpgYGB7cn0KcGlnc19kZiU+JQogIGF1dG9wbG90KENvdW50KSsKICAgIGxhYnMoeT0iUGlnIENvdW50IiwKICAgICAgICAgeD0iTW9udGggfCBZZWFyIiwKICAgICAgICAgdGl0bGUgPSAiU2xhdWdodGVyZWQgUGlnIENvdW50LCBWaWN0b3JpYSAoSnVsIDE5NzIgLSBEZWMgMjAxOCkiKSsKICBnZW9tX3Ntb290aChmb3JtdWxhID0geSB+IHgpCmBgYAoKCiMjIGEuCgpVc2UgdGhlIEVUUygpIGZ1bmN0aW9uIHRvIGVzdGltYXRlIHRoZSBlcXVpdmFsZW50IG1vZGVsIGZvciBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nLiBGaW5kIHRoZSBvcHRpbWFsIHZhbHVlcyBvZiAkXGFscGhhJAphbmQgJFxlbGwkIDAsIGFuZCBnZW5lcmF0ZSBmb3JlY2FzdHMgZm9yIHRoZSBuZXh0IGZvdXIgbW9udGhzLgoKRXJyb3IgVHJlbmQgYW5kIFNlYXNvbmFsaXR5IG9yIEV4cG9uZW50aWFsIFNtb290aGluZyAoRVRTKSBNb2RlbDoKCio4LjEqCipFeGFtcGxlOiBBbGdlcmlhbiBleHBvcnQqCgogICAgICAgICAgIyBFc3RpbWF0ZSBwYXJhbWV0ZXJzCiAgICAgICAgICBmaXQgPC0gYWxnZXJpYV9lY29ub215IHw+CiAgICAgICAgICAgIG1vZGVsKEVUUyhFeHBvcnRzIH4gZXJyb3IoIkEiKSArIHRyZW5kKCJOIikgKyBzZWFzb24oIk4iKSkpCiAgICAgICAgICBmYyA8LSBmaXQgfD4KICAgICAgICAgICAgZm9yZWNhc3QoaCA9IDUpCgpgYGB7cn0KIyBFc3RpbWF0ZSBwYXJhbWV0ZXJzCnBpZ3NfZml0IDwtIHBpZ3NfZGYgJT4lCiAgbW9kZWwoRVRTKENvdW50IH4gZXJyb3IoIkEiKSArIHRyZW5kKCJOIikgKyBzZWFzb24oIk4iKSkpCgpyZXBvcnQocGlnc19maXQpCmBgYAoKKk9QVElNQUwqID0gJFxhbHBoYSQgPSAwLjMyMjEyNDcgJFxlbGwkID0gMTAwNjQ2LjYKCmBgYHtyfQoocGlnc19mYyA8LSBwaWdzX2ZpdCU+JQogIGZvcmVjYXN0KGggPSA0KSkKYGBgCgpgYGB7cn0KcGlnc19mYyU+JQogICAgYXV0b3Bsb3QoKSsKICAgICAgZ2VvbV9saW5lKGRhdGE9ZmlsdGVyKHBpZ3NfZGYsIE1vbnRoID49IHllYXJtb250aCgnMjAxNiBKYW4nKSksCiAgICAgICAgICAgICAgICBhZXMoeD1Nb250aCx5PUNvdW50KSxjb2xvcj0ibGlnaHRncmVlbiIpCiAgCmBgYAoKIyMgYi4KCkNvbXB1dGUgYSA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbCBmb3IgdGhlIGZpcnN0IGZvcmVjYXN0IHVzaW5nICRcaGF0e3l9XHBtMS45NnMkCndoZXJlICRzJCBpcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSByZXNpZHVhbHMuIENvbXBhcmUgeW91ciBpbnRlcnZhbCB3aXRoIHRoZSBpbnRlcnZhbCBwcm9kdWNlZCBieSAkUiQuCgpgYGB7cn0KY2xhc3MocGlnc19mYykKCmBgYAoKCmBgYHtyfQpwaWdzX3loYXQgPC0gcGlnc19mYyQubWVhblsxXQpwaWdzX2F1ZzwtIGF1Z21lbnQocGlnc19maXQpCnBpZ3Nfc2Q8LSBzZChwaWdzX2F1ZyQucmVzaWQpCgpwaWdzX3VwcGVyOTU8LXBpZ3NfeWhhdCsocGlnc19zZCoxLjk2KQpwaWdzX2xvd2VyOTU8LXBpZ3NfeWhhdC0ocGlnc19zZCoxLjk2KQoKcGlnc19oaWxvPC1waWdzX2ZjJT4laGlsbygpCgpwYXN0ZTAoIkxvd2VyIDk1JSAiLHBpZ3NfbG93ZXI5NSwiIE1lYW4gIixwaWdzX3loYXQsICIgVXBwZXIgOTUlICIscGlnc191cHBlcjk1KQpwYXN0ZTAoIldoaWxlIG91ciBmb3JlY2FzdCBoYWQgdGhlIHZhbHVlcyIsIHBpZ3NfaGlsbyRgOTUlYFsxXSwKICAgICAgICIgd2l0aCBhIG1lYW4gb2YgIiwgcGlnc19oaWxvJC5tZWFuWzFdICkKYGBgCgoKKlRoZSB2YWx1ZXMgbWF0Y2ggaWYgd2Ugd2VyZSBnb2luZyBvZmYgd2hvbGUgbnVtYmVycywgYnV0IHVzaW5nIHRoZSBmdW5jdGlvbnMgaW4gYFJgIHByb3ZpZGVkIGEgZ3JlYXRlciBsZXZlbCBvZiBhY2N1cmFjeS4qCgojIDguNQoKRGF0YSBzZXQgYGdsb2JhbF9lY29ub215YCBjb250YWlucyB0aGUgYW5udWFsIEV4cG9ydHMgZnJvbSBtYW55IGNvdW50cmllcy4gU2VsZWN0IG9uZSBjb3VudHJ5IHRvIGFuYWx5c2UuCgpgYGB7cn0KdXNhX2RmPC1nbG9iYWxfZWNvbm9teSU+JQogICAgICAgICAgICAgICAgZmlsdGVyKENvdW50cnk9PSJVbml0ZWQgU3RhdGVzIiApCmBgYAoKCiMjIGEuCgpQbG90IHRoZSBFeHBvcnRzIHNlcmllcyBhbmQgZGlzY3VzcyB0aGUgbWFpbiBmZWF0dXJlcyBvZiB0aGUgZGF0YS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQp1c2FfZGYgJT4lIGF1dG9wbG90KEV4cG9ydHMpKwogIGxhYnMoeSA9ICJHRFAgKFBlcmNlbnRhZ2UgJSkiLHggPSAiWWVhciIsIHRpdGxlID0gIlVuaXRlZCBTdGF0ZXMgRXhwb3J0IFNlcmllcyIpCmBgYAoKCiMjIGIuCgpVc2UgYW4gRVRTKEEsTixOKSBtb2RlbCB0byBmb3JlY2FzdCB0aGUgc2VyaWVzLCBhbmQgcGxvdCB0aGUgZm9yZWNhc3RzLgoKYGBge3J9Cgp1c2FfZGYgPC0gbmEub21pdCh1c2FfZGYpCgp1c2FfZml0IDwtIHVzYV9kZiAlPiUKICBtb2RlbChFVFMoRXhwb3J0cyB+IGVycm9yKCJBIikgKyB0cmVuZCgiTiIpICsgc2Vhc29uKCJOIikpKQoKCnVzYV9mYyA8LSB1c2FfZml0ICU+JQogIGZvcmVjYXN0KGggPSA1KQoKdXNhX2ZjICU+JQogIGF1dG9wbG90KHVzYV9kZikgKwogIGdlb21fbGluZShhZXMoeSA9IC5maXR0ZWQpLCBjb2w9ImdyZWVuIiwKICAgICAgICAgICAgZGF0YSA9IGF1Z21lbnQodXNhX2ZpdCkpICsKICBsYWJzKHk9IiUgb2YgR0RQIiwgdGl0bGU9IkV4cG9ydHM6IFVuaXRlZCBTdGF0ZXMiKSArCiAgZ3VpZGVzKGNvbG91ciA9ICJub25lIikKCmBgYAoKCiMjIGMuCgpDb21wdXRlIHRoZSBSTVNFIHZhbHVlcyBmb3IgdGhlIHRyYWluaW5nIGRhdGEuCgpgYGB7cn0KYWNjdXJhY3kodXNhX2ZpdCkKYGBgCgojIyBkLgoKQ29tcGFyZSB0aGUgcmVzdWx0cyB0byB0aG9zZSBmcm9tIGFuIEVUUyhBLEEsTikgbW9kZWwuIChSZW1lbWJlciB0aGF0IHRoZSB0cmVuZGVkIG1vZGVsIGlzIHVzaW5nIG9uZSBtb3JlIHBhcmFtZXRlciB0aGFuIHRoZSBzaW1wbGVyIG1vZGVsLikgRGlzY3VzcyB0aGUgbWVyaXRzIG9mIHRoZSB0d28gZm9yZWNhc3RpbmcgbWV0aG9kcyBmb3IgdGhpcyBkYXRhIHNldC4KCmBgYHtyfQp1c2FfUk1TRV9FVFM8LWFjY3VyYWN5KHVzYV9kZiAlPiUKICBtb2RlbCgKICAgIEFOTiA9IEVUUyAoRXhwb3J0cyB+IGVycm9yKCJBIikgKyB0cmVuZCgiTiIpICsgc2Vhc29uKCJOIikpLAogICAgQUFOID0gRVRTIChFeHBvcnRzIH4gZXJyb3IoIkEiKSArIHRyZW5kKCJBIikgKyBzZWFzb24oIk4iKSkKICAgICkpW1siUk1TRSJdXQp1c2FfUk1TRV90cmFpbjwtYWNjdXJhY3kodXNhX2ZpdClbWyJSTVNFIl1dCgpwYXN0ZTAoIlRyYWluaW5nIE1vZGVsIFJNU0UgaXMgIix1c2FfUk1TRV90cmFpbikKcGFzdGUwKCJDb21wYXJlZCB0byAiKQpwYXN0ZTAodXNhX1JNU0VfRVRTKQpgYGAKCldpdGggdGhlIEFBTiBtb2RlbCBwcm92aWRpbmcgYSBzbWFsbGVyIFJNU0UgYnkgYWJvdXQgMC4wMTEgdGhhbiBBTk4sIGl0IHN1Z2dlc3RzIGEgYmV0dGVyIG1vZGVsIGxpZXMgd2l0aCBBQU4uIAoKIyMgZS4KCkNvbXBhcmUgdGhlIGZvcmVjYXN0cyBmcm9tIGJvdGggbWV0aG9kcy4gV2hpY2ggZG8geW91IHRoaW5rIGlzIGJlc3Q/CgpgYGB7cn0KdXNhX2RmICU+JQogIG1vZGVsKAogICAgQU5OID0gRVRTIChFeHBvcnRzIH4gZXJyb3IoIkEiKSArIHRyZW5kKCJOIikgKyBzZWFzb24oIk4iKSksCiAgICBBQU4gPSBFVFMgKEV4cG9ydHMgfiBlcnJvcigiQSIpICsgdHJlbmQoIkEiKSArIHNlYXNvbigiTiIpKQogICAgKSAlPiUgCiAgZm9yZWNhc3QoaD00KSAlPiUgCiAgYXV0b3Bsb3QodXNhX2RmLCBsZXZlbD1OVUxMKSArCiAgbGFicyh0aXRsZT0iVVMgRXhwb3J0IFByZWRpY3Rpb25zIikKYGBgCgoKIyMgZi4KCkNhbGN1bGF0ZSBhIDk1JSBwcmVkaWN0aW9uIGludGVydmFsIGZvciB0aGUgZmlyc3QgZm9yZWNhc3QgZm9yIGVhY2ggbW9kZWwsIHVzaW5nIHRoZSBSTVNFIHZhbHVlcyBhbmQgYXNzdW1pbmcgbm9ybWFsIGVycm9ycy4gQ29tcGFyZSB5b3VyIGludGVydmFscyB3aXRoIHRob3NlIHByb2R1Y2VkIHVzaW5nIFIuCgpgYGB7cn0KCnVzYV95aGF0IDwtIHVzYV9mYyQubWVhblsxXQoKCnVzYV9hdWcgPC0gYXVnbWVudCh1c2FfZml0KQoKCnVzYV9zZCA8LSBzZCh1c2FfYXVnJC5yZXNpZCkKCgp1c2FfdXBwZXI5NSA8LSB1c2FfeWhhdCArICh1c2Ffc2QgKiAxLjk2KQp1c2FfbG93ZXI5NSA8LSB1c2FfeWhhdCAtICh1c2Ffc2QgKiAxLjk2KQoKCnVzYV9oaWxvIDwtIHVzYV9mYyAlPiUgaGlsbygpCgpwYXN0ZTAoIkxvd2VyIDk1JSAiLHVzYV9sb3dlcjk1LCIgTWVhbiAiLHVzYV95aGF0LCAiIFVwcGVyIDk1JSAiLHVzYV91cHBlcjk1KQpwYXN0ZTAoIldoaWxlIG91ciBmb3JlY2FzdCBoYWQgdGhlIHZhbHVlcyIsIHVzYV9oaWxvJGA5NSVgWzFdLAogICAgICAgIiB3aXRoIGEgbWVhbiBvZiAiLCB1c2FfaGlsbyQubWVhblsxXSApCgpgYGAKCkJvdGggYXJlIGFjY3VyYXRlIHVwIHRvIHRoZSBmaXJzdCBkZWNpbWFsLiBUaGUgbWV0aG9kIHVzaW5nIFIgdnMgdGhlIG1hbnVhbCwgYWNjb3VudHMgZm9yIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgaGFzIGEgbW9yZSBwcmVjaXNlIHZhbHVlIGZvciB0aGUgY3JpdGljYWwgdmFsdWVzLCBidXQgYWxzbyBkb2VzIGdhdmUgYSBncmVhdGVyIHJhbmdlLgoKcGFzdGUwKCJMb3dlciA5NSUgIixwaWdzX2xvd2VyOTUsIiBNZWFuICIscGlnc195aGF0LCAiIFVwcGVyIDk1JSAiLHBpZ3NfdXBwZXI5NSkKcGFzdGUwKCJXaGlsZSBvdXIgZm9yZWNhc3QgaGFkIHRoZSB2YWx1ZXMiLCBwaWdzX2hpbG8kYDk1JWBbMV0sCiAgICAgICAiIHdpdGggYSBtZWFuIG9mICIsIHBpZ3NfaGlsbyQubWVhblsxXSApCgojIDguNgoKRm9yZWNhc3QgdGhlIENoaW5lc2UgR0RQIGZyb20gdGhlIGdsb2JhbF9lY29ub215IGRhdGEgc2V0IHVzaW5nIGFuIEVUUyBtb2RlbC4gRXhwZXJpbWVudCB3aXRoIHRoZSB2YXJpb3VzIG9wdGlvbnMgaW4gdGhlIEVUUygpIGZ1bmN0aW9uIHRvIHNlZSBob3cgbXVjaCB0aGUgZm9yZWNhc3RzIGNoYW5nZSB3aXRoIGRhbXBlZCB0cmVuZCwgb3Igd2l0aCBhIEJveC1Db3ggdHJhbnNmb3JtYXRpb24uIFRyeSB0byBkZXZlbG9wIGFuIGludHVpdGlvbiBvZiB3aGF0IGVhY2ggaXMgZG9pbmcgdG8gdGhlIGZvcmVjYXN0cy4KCltIaW50OiB1c2UgYSByZWxhdGl2ZWx5IGxhcmdlIHZhbHVlIG9mIGggd2hlbiBmb3JlY2FzdGluZywgc28geW91IGNhbiBjbGVhcmx5IHNlZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdmFyaW91cyBvcHRpb25zIHdoZW4gcGxvdHRpbmcgdGhlIGZvcmVjYXN0cy5dCgpgYGB7cn0KY2hpbmFfZGYgPC0gZ2xvYmFsX2Vjb25vbXkgJT4lCiAgZmlsdGVyKENvdW50cnkgPT0gIkNoaW5hIikKCmNoaW5hX3Bsb3QxPC1jaGluYV9kZiAlPiUgYXV0b3Bsb3QoR0RQKSArCiAgbGFicyh0aXRsZT0iQ2hpbmVzZSBHRFAiKQoKY2hpbmFfbGFtYmRhIDwtIGNoaW5hX2RmICU+JQogIGZlYXR1cmVzKEdEUCwgZmVhdHVyZXMgPSBndWVycmVybykgJT4lCiAgcHVsbChsYW1iZGFfZ3VlcnJlcm8pCgpmaXRfY2hpbmEgPC0gY2hpbmFfZGYgJT4lIAogIG1vZGVsKAogICAgIyBFVFMKICAgIEVUUyA9IEVUUyhHRFApLAogICAgIyBMb2cgVHJhbnNmb3JtYXRpb24KICAgIGBMb2dgID0gRVRTKGxvZyhHRFApKSwKICAgICMgRGFtcGVkIE1vZGVsCiAgICBgRGFtcGVkYCA9IEVUUyhHRFAgfiB0cmVuZCgiQWQiKSksCiAgICAjIEJveC1Db3ggVHJhbnNmb3JtYXRpb24KICAgIGBCb3gtQ294YCA9IEVUUyhib3hfY294KEdEUCwgY2hpbmFfbGFtYmRhKSksCiAgICAjIERhbXBlZCBNb2RlbCB3IEJveC1Db3ggVHJhbnNmb3JtYXRpb24KICAgIGBCb3gtQ294LCBEYW1wZWRgID0gRVRTKGJveF9jb3goR0RQLCBjaGluYV9sYW1iZGEpIH4gdHJlbmQoIkFkIikpCikKCmNoaW5hX3Bsb3QyPC1maXRfY2hpbmEgJT4lCiAgZm9yZWNhc3QoaD0iMjAgeWVhcnMiKSAlPiUKICBhdXRvcGxvdChjaGluYV9kZiwgbGV2ZWwgPSBOVUxMKSsKICBsYWJzKHRpdGxlPSJDaGluZXNlIEdEUCBGb3JlY2FzdCIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkZvcmVjYXN0IikpCgpwbG90X2dyaWQoY2hpbmFfcGxvdDEsCiAgICAgICAgICBjaGluYV9wbG90MiwgbnJvdyA9IDIpCmBgYAoKYERhbXBlZGAgYW5kIGBFVFNgIHNob3cgc2ltaWxhciBjb250aW51ZWQgZ3Jvd3RoLCB3aGlsZSBgTG9nYCBhbmQgYEJveC1Db3hgIHNlZW0gdG8gZXhhZ2dlcmF0ZSBpdHMgZm9yZWNhc3QuIGBCb3gtQ294YCwgYERhbXBlZGAgc2hvd3Mgc2xpZ2h0bHkgbW9yZSBncm93dGggdGhhbiBgRVRTYCBhbmQgYERhbXBlZGAuCgojIDguNwoKRmluZCBhbiBgRVRTYCBtb2RlbCBmb3IgdGhlIEdhcyBkYXRhIGZyb20gYXVzX3Byb2R1Y3Rpb24gYW5kIGZvcmVjYXN0IHRoZSBuZXh0IGZldyB5ZWFycy4gV2h5IGlzIG11bHRpcGxpY2F0aXZlIHNlYXNvbmFsaXR5IG5lY2Vzc2FyeSBoZXJlPyBFeHBlcmltZW50IHdpdGggbWFraW5nIHRoZSB0cmVuZCBkYW1wZWQuIERvZXMgaXQgaW1wcm92ZSB0aGUgZm9yZWNhc3RzPwoKKlNlYXNvbmFsIHZhcmlhdGlvbiBtYWtlcyBtdWx0aXBsaWNhdGl2ZSBzZWFzb25hbGl0eSBuZWNlc3NhcnkuCgpgYGB7cn0KZ2FzX3Bsb3QxPC1hdXNfcHJvZHVjdGlvbiAlPiUgYXV0b3Bsb3QoR2FzKSsKICBsYWJzKHRpdGxlPSJBdXN0cmFpbGlhbiBHYXMgUHJvZHVjdGlvbiIpCgpnYXNfZml0IDwtIGF1c19wcm9kdWN0aW9uICU+JQogIG1vZGVsKAogICAgIyBNdWx0aXBsaWNhdGl2ZQogICAgTXVsdGlwbGljYXRpdmUgPSBFVFMoR2FzIH4gZXJyb3IoIk0iKSArIHRyZW5kKCJBIikgKyBzZWFzb24oIk0iKSksCiAgICAjIERhbXBlZCBtdWx0aXBsaWNhdGl2ZQogICAgYE11bHRpcGxpY2F0aXZlLCBEYW1wZWRgID0gRVRTKEdhcyB+IGVycm9yKCJNIikgKyB0cmVuZCgiQWQiKSArIHNlYXNvbigiTSIpKQogICkKZ2FzX2ZjIDwtIGdhc19maXQgJT4lIGZvcmVjYXN0KGggPSAiNSB5ZWFycyIpCgpnYXNfcGxvdDI8LWdhc19mYyAlPiUKICBhdXRvcGxvdChhdXNfcHJvZHVjdGlvbiwgbGV2ZWwgPSBOVUxMKSArCiAgbGFicyh0aXRsZT0iQXVzdHJhbGlhbiBHYXMgUHJvZHVjdGlvbiBGb3JlY2FzdCIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkZvcmVjYXN0IikpCgpwbG90X2dyaWQoZ2FzX3Bsb3QxLAogICAgICAgICAgZ2FzX3Bsb3QyLCBucm93ID0gMikKYGBgCgoqVmVyeSBsaXR0bGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gbW9kZWxzLiBBYm91dCAzLjA5OSBkaWZmZXJlbmNlLCBtZWFuaW5nIGVpdGhlciB3b3VsZCBiZSBhY2N1cmF0ZSBvciBvcHRpbWFsKgoKYGBge3J9CnJtKGxpc3QgPSBscygpWyFncmVwbCgiXm15IiwgbHMoKSldKQpgYGAKCgojIDguOAoKUmVjYWxsIHlvdXIgcmV0YWlsIHRpbWUgc2VyaWVzIGRhdGEgKGZyb20gRXhlcmNpc2UgNyBpbiBTZWN0aW9uIFsyLjEwXShodHRwczovL290ZXh0cy5jb20vZnBwMy9ncmFwaGljcy1leGVyY2lzZXMuaHRtbCNncmFwaGljcy1leGVyY2lzZXMpKS4KCiMjIGEuCgpXaHkgaXMgbXVsdGlwbGljYXRpdmUgc2Vhc29uYWxpdHkgbmVjZXNzYXJ5IGZvciB0aGlzIHNlcmllcz8KCipCL2MgdGhlcmUgaXMgY2xlYXIgc2Vhc29uYWxpdHkgYW5kIHBlYWtzIG9uIEphbnVhcnkqCgojIyBiLiAKCkFwcGx5IEhvbHQtV2ludGVyc+KAmSBtdWx0aXBsaWNhdGl2ZSBtZXRob2QgdG8gdGhlIGRhdGEuIEV4cGVyaW1lbnQgd2l0aCBtYWtpbmcgdGhlIHRyZW5kIGRhbXBlZC4KCmBgYHtyfQpzZXQuc2VlZCgxMjMpCgpteXNlcmllcyA8LSBhdXNfcmV0YWlsICU+JQogIGZpbHRlcihgU2VyaWVzIElEYCA9PSBzYW1wbGUoYXVzX3JldGFpbCRgU2VyaWVzIElEYCwxKSkKCm15Zml0IDwtIG15c2VyaWVzICU+JQogIG1vZGVsKAogICAgYEhvbHQtV2ludGVyc+KAmSBNdWx0aXBsaWNhdGl2ZWAgPSBFVFMoVHVybm92ZXIgfiBlcnJvcigiTSIpICsgdHJlbmQoIkEiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbigiTSIpKSwKICAgIGBIb2x0LVdpbnRlcnPigJkgRGFtcGVkIE11bHRpcGxpY2F0aXZlYCA9IEVUUyhUdXJub3ZlciB+IGVycm9yKCJNIikgKyB0cmVuZCgiQWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbigiTSIpKQogICkKCgpteWZjIDwtIG15Zml0ICU+JSBmb3JlY2FzdChoID0gIjUgeWVhcnMiKQpteWZjICU+JQogIGF1dG9wbG90KG15c2VyaWVzLCBsZXZlbCA9IE5VTEwpICsKICBsYWJzKHRpdGxlPSJBdXN0cmFsaWFuIERlcGFydG1lbnQgU3RvcmVzIiwKICAgICAgIHk9IlR1cm5vdmVyIikgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiRm9yZWNhc3QiKSkKYGBgCgoKIyMgYy4KCkNvbXBhcmUgdGhlIFJNU0Ugb2YgdGhlIG9uZS1zdGVwIGZvcmVjYXN0cyBmcm9tIHRoZSB0d28gbWV0aG9kcy4gV2hpY2ggZG8geW91IHByZWZlcj8KCmBgYHtyfQphY2N1cmFjeShteWZpdCklPiUKICBkcGx5cjo6c2VsZWN0KCIubW9kZWwiLCJSTVNFIikKCmBgYAoKVGhlIHZhbHVlcyBhcmUgcHJldHR5IGNsb3NlLCB3aXRoaW4gMC42MjEwOSBvZiBlYWNoIG90aGVyLCBidXQgdGhlIGBEYW1wbGVkYCBoYXMgdGhlIGxvd2VyIG9mIHRoZSB0d28uCgojIyBkLgoKQ2hlY2sgdGhhdCB0aGUgcmVzaWR1YWxzIGZyb20gdGhlIGJlc3QgbWV0aG9kIGxvb2sgbGlrZSB3aGl0ZSBub2lzZS4KCmBgYHtyfQpteWZpdCU+JQogIGRwbHlyOjpzZWxlY3QoIkhvbHQtV2ludGVyc+KAmSBEYW1wZWQgTXVsdGlwbGljYXRpdmUiKSU+JWdnX3RzcmVzaWR1YWxzKCkKIApgYGAKCmBIb2x0LVdpbnRlcnPigJkgRGFtcGVkIE11bHRpcGxpY2F0aXZlYCBpcyBub3Qgd2hpdGUgbm9pc2UgYmFzZSBvbiB0aGUgYGFjZmAgcGxvdCwgd2hpY2ggaGFzIG92ZXIgNSUgb2YgdGhlIHNwaWtlcyBvdXQgb3VzaWQgb2YgdGhlIGJvdW5kcyBtYWRlIGJ5IGRhc2hlZCBsaW5lcy4KCiMjIGUuCgpOb3cgZmluZCB0aGUgdGVzdCBzZXQgUk1TRSwgd2hpbGUgdHJhaW5pbmcgdGhlIG1vZGVsIHRvIHRoZSBlbmQgb2YgMjAxMC4gQ2FuIHlvdSBiZWF0IHRoZSBzZWFzb25hbCBuYcOvdmUgYXBwcm9hY2ggZnJvbSBFeGVyY2lzZSA3IGluIFNlY3Rpb24gWzUuMTFdKGh0dHBzOi8vb3RleHRzLmNvbS9mcHAzL3Rvb2xib3gtZXhlcmNpc2VzLmh0bWwjdG9vbGJveC1leGVyY2lzZXMpPwoKCmBgYHtyfQpteXRyYWluPC1teXNlcmllcyU+JQogIGZpbHRlcihNb250aCA+PSB5ZWFybW9udGgoJzIwMTEgSmFuJykpCgojIHNlYXNvbmFsIG5hw692ZQpteWZpdDIgPC0gbXl0cmFpbiAlPiUKICBtb2RlbCgKICAgICJIb2x0LVdpbnRlcnMnIERhbXBlZCIgPSBFVFMoVHVybm92ZXIgfiBlcnJvcigiTSIpICsgdHJlbmQoIkFkIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbigiTSIpKSwKICAgICJIb2x0LVdpbnRlcnMnIE11bHRpcGxpY2F0aXZlIiA9IEVUUyhUdXJub3ZlciB+IGVycm9yKCJNIikgKyB0cmVuZCgiQSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXNvbigiTSIpKSwKICAgICJTZWFzb25hbCBOYcOvdmUgRm9yZWNhc3QiID0gU05BSVZFKFR1cm5vdmVyKQogICkKCgpjb21wYXJpc29uIDwtIGFudGlfam9pbihteXNlcmllcywgbXl0cmFpbiwgCiAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiU3RhdGUiLCAiSW5kdXN0cnkiLCAiU2VyaWVzIElEIiwgIk1vbnRoIiwgIlR1cm5vdmVyIikpCgojIERvIHRoZSBmb3JlY2FzdGluZyBhY2NvcmRpbmcgdG8gY29tcGFyaXNvbiBkYXRhCm15ZmMyIDwtIG15Zml0MiAlPiUKICAgICAgZm9yZWNhc3QoY29tcGFyaXNvbikKCiMgcGxvdAphdXRvcGxvdChjb21wYXJpc29uLCBUdXJub3ZlcikgKwogIGF1dG9sYXllcihteWZjMiwgbGV2ZWwgPSBOVUxMKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQodGl0bGU9IkZvcmVjYXN0IikpICsKICBnZ3RpdGxlKCdGb3JlY2FzdCBDb21wYXJpc29uIChBVVMgRGVwdCBTdG9yZXMpJykgCmBgYAoKYGBge3J9CmFjY3VyYWN5KG15Zml0MikKYGBgCgpJdCBhcHBlYXJzIHRoZSBEYW1wZWQgbW9kZWwgaXMgdGhlIGJlc3QgcGVyZm9ybWluZywgYmFzZSBvbiB0aGUgUk1TRSB2YWx1ZXMuCgojIDguOQoKRm9yIHRoZSBzYW1lIHJldGFpbCBkYXRhLCB0cnkgYW4gU1RMIGRlY29tcG9zaXRpb24gYXBwbGllZCB0byB0aGUgQm94LUNveCB0cmFuc2Zvcm1lZCBzZXJpZXMsIGZvbGxvd2VkIGJ5IEVUUyBvbiB0aGUgc2Vhc29uYWxseSBhZGp1c3RlZCBkYXRhLiBIb3cgZG9lcyB0aGF0IGNvbXBhcmUgd2l0aCB5b3VyIGJlc3QgcHJldmlvdXMgZm9yZWNhc3RzIG9uIHRoZSB0ZXN0IHNldD8KCmBgYHtyfQojZmluZCBvcHRpbWFsIGxhbWJkYQpteWxhbWJkYSA8LSBteXRyYWluICU+JQogIGZlYXR1cmVzKFR1cm5vdmVyLCBmZWF0dXJlcyA9IGd1ZXJyZXJvKSAlPiUKICBwdWxsKGxhbWJkYV9ndWVycmVybykKCiNiYyB0cmFuc2Zvcm1lZCBkYXRhCnRzX2JjIDwtIG15dHJhaW4gJT4lCiAgbXV0YXRlKAogICAgYmNfdHVybm92ZXIgPSBib3hfY294KFR1cm5vdmVyLCBteWxhbWJkYSkKICApCgojIGJjIHRyYW5zZm9ybWVkIG1vZGVsCmZpdCA8LSB0c19iYyAlPiUKICBtb2RlbCgKICAgICdCb3gtQ294IFNUTCcgPSBTVEwoYmNfdHVybm92ZXIgfiBzZWFzb24od2luZG93ID0gInBlcmlvZGljIiksCiAgICAgICAgICAgICByb2J1c3QgPSBUKSwKICAgICdCb3gtQ294IEVUUycgPSBFVFMoYmNfdHVybm92ZXIpCiAgKQoKIyBiZXN0IHByZXZpb3VzIG1vZGVsIApiZXN0X2ZpdCA8LXRzX2JjICU+JQogIG1vZGVsKAogICAgIkhvbHQtV2ludGVycycgRGFtcGVkIiA9IEVUUyhUdXJub3ZlciB+IGVycm9yKCJNIikgKyB0cmVuZCgiQWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFzb24oIk0iKSkKICApCgpyYmluZChhY2N1cmFjeShmaXQpLGFjY3VyYWN5KGJlc3RfZml0KSkKYGBgCgpCYXNlZCBvbiB0aGUgVmFsdWVzIHRoZSBCb3gtQ294IEVUUyBpcyB0aGUgYmVzdCBwZXJmb3JtaW5nIG9mIHRoZSB0aHJlZS4K