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