Licença

This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

License: CC BY-SA 4.0

Citação

Sugestão de citação: FIGUEIREDO, Adriano Marcos Rodrigues. Séries Temporais com R: Modelo híbrido para BVSP Bovespa - B3. Campo Grande-MS,Brasil: RStudio/Rpubs, 2019. Disponível em http://rpubs.com/amrofi/Time_Series_Hybrid.

1 Apresentação

Este artigo procura ilustrar os procedimentos para trabalhar com métodos de séries temporais para modelos híbridos utilizando o pacote forecastHybrid.

1.1 Pacotes

O primeiro passo para tal é baixar os dados da Bolsa B3, antiga Bovespa (BVSP). O pacote quantmod nos auxiliará a obter os dados eletronicamente. O pesquisador deve conhecer os tickers do papel desejado. Alguns pacotes foram retirados do CRAN e precisará pegar e instalar do arquivo (GetHFData e stockPortfolio).

if (!require(quantmod)) {
    install.packages("quantmod")
    library(quantmod)
}
if (!require(fpp2)) {
    install.packages("fpp2")
    library(fpp2)
}
if (!require(GetHFData)) {
    install.packages("GetHFData")
    library(GetHFData)
}
if (!require(forecastHybrid)) {
    install.packages("forecastHybrid")
    library(forecastHybrid)
}

2 Dados Bovespa

quantmod::getSymbols("^BVSP", src = "yahoo")  # pelo {quantmod}
[1] "^BVSP"
chartSeries(BVSP)

2.0.1 Calculando o retorno

# require(stockPortfolio)

# install.packages('quantmod') require(quantmod)

### Bovespa getSymbols('^BVSP',src='yahoo') # pelo {quantmod}
BVSP.Close <- BVSP$BVSP.Close
#### limpeza dos dados
BVSP_clean <- is.na(BVSP.Close) <- BVSP.Close == 0
BVSP_clean <- na.locf(BVSP.Close, fromLast = FALSE, coredata = NULL)
max(BVSP_clean)
[1] 130776
min(BVSP_clean)
[1] 29435
plot(BVSP_clean)

# obtendo o retorno diário
r_BVSP <- dailyReturn(BVSP_clean, type = "log")
plot(r_BVSP)

hist(r_BVSP, 100)

# janela para após 2010
r_BVSP_pos2010 <- window(r_BVSP, start = "2010-01-01")
plot(r_BVSP_pos2010)

hist(r_BVSP_pos2010, 100)

max(r_BVSP_pos2010)
[1] 0.1302228
min(r_BVSP_pos2010)
[1] -0.1599303
plot(window(BVSP_clean, start = "2010-01-01"))

3 Modelo Híbrido forecastHybrid de Shaub e Ellis (2018)

Vou usar apenas a série “limpa” e com janela para após 2010. É um objeto diário com gaps implicitos para os finais de semana (non-traded days).

x <- as.ts(r_BVSP_pos2010)
library(forecastHybrid)
modelorapido <- hybridModel(x)
fcst <- forecast(modelorapido, h = 30)
fcst
     Point Forecast       Lo 80      Hi 80       Lo 95      Hi 95
2848   0.0011424536 -0.02010487 0.02259185 -0.03086524 0.03329822
2849  -0.0001370635 -0.02112048 0.02115043 -0.03187043 0.03191081
2850   0.0003097723 -0.02019024 0.02115067 -0.03095086 0.03191105
2851   0.0005659007 -0.02036992 0.02115092 -0.03113079 0.03191129
2852   0.0002069339 -0.02031911 0.02115116 -0.03108001 0.03191153
2853   0.0004170993 -0.02033015 0.02115140 -0.03109105 0.03191178
2854   0.0003835426 -0.02032731 0.02115164 -0.03108821 0.03191202
2855   0.0001520740 -0.02032796 0.02115189 -0.03108887 0.03191226
2856   0.0002530307 -0.02032780 0.02115213 -0.03108870 0.03191251
2857   0.0004605503 -0.02032784 0.02115237 -0.03108874 0.03191275
2858   0.0002028914 -0.02032783 0.02115261 -0.03108873 0.03191299
2859   0.0002670639 -0.02032783 0.02115286 -0.03108873 0.03191323
2860   0.0002931478 -0.02032783 0.02115310 -0.03108873 0.03191348
2861   0.0002417562 -0.02032783 0.02115334 -0.03108873 0.03191372
2862   0.0002885208 -0.02032783 0.02115358 -0.03108873 0.03191396
2863   0.0002896009 -0.02032783 0.02115383 -0.03108873 0.03191420
2864   0.0002233696 -0.02032783 0.02115407 -0.03108873 0.03191445
2865   0.0002935928 -0.02032783 0.02115431 -0.03108873 0.03191469
2866   0.0002943184 -0.02032783 0.02115455 -0.03108873 0.03191493
2867   0.0002529228 -0.02032783 0.02115480 -0.03108873 0.03191517
 [ reached 'max' / getOption("max.print") -- omitted 10 rows ]
plot(forecast(modelorapido))

A função hybridModel utiliza a opção models para indicar quais os modelos a serem utilizados: - a = auto.arima;
- e = ets;
- n = nnetar;
- s = stlm;
- t = tbats;
- z = snaive.

Assim, ao especificar models = "aet", weights = "equal", estamos definindo que serão utilizados os modelos ARIMA, ETS e TBATS com pesos iguais para cada na realização da combinação dos forecasts.

3.1 Modelo 1

# opção aet indica o modelo hibrido para
hm1 <- hybridModel(y = x, models = "aet", weights = "equal")

# resumo arima
hm1$auto.arima
Series: y 
ARIMA(2,0,0) with zero mean 

Coefficients:
          ar1     ar2
      -0.0850  0.0375
s.e.   0.0187  0.0187

sigma^2 estimated as 0.0002493:  log likelihood=7771.93
AIC=-15537.86   AICc=-15537.85   BIC=-15520
# o pesquisador pode retirar dos demais modelos caso deseje
plot(forecast(hm1$auto.arima))

print(hm1)
Hybrid forecast model comprised of the following models: auto.arima, ets, tbats
############
auto.arima with weight 0.333 
############
ets with weight 0.333 
############
tbats with weight 0.333 
plot(hm1, type = "fit")

plot(hm1, type = "models")

Veja que nesse caso, o modelo “automático” levou a um ARIMA (0,0,0). A função hybridModel com opção weights = "equal" levou aos pesos 0.33 para cada modelo por serem 3 modelos (ARIMA, ETS e TBATS).

3.2 Modelo 2

hm2 <- hybridModel(y = x, models = "aet", weights = "equal")

hm2$auto.arima
Series: y 
ARIMA(2,0,0) with zero mean 

Coefficients:
          ar1     ar2
      -0.0850  0.0375
s.e.   0.0187  0.0187

sigma^2 estimated as 0.0002493:  log likelihood=7771.93
AIC=-15537.86   AICc=-15537.85   BIC=-15520
plot(forecast(hm2$auto.arima))

print(hm2)
Hybrid forecast model comprised of the following models: auto.arima, ets, tbats
############
auto.arima with weight 0.333 
############
ets with weight 0.333 
############
tbats with weight 0.333 
plot(hm2, type = "fit")

plot(hm2, type = "models")

# hm2$ets

etspetr <- ets(x)
summary(etspetr)
ETS(A,N,N) 

Call:
 ets(y = x) 

  Smoothing parameters:
    alpha = 1e-04 

  Initial states:
    l = 2e-04 

  sigma:  0.0159

      AIC      AICc       BIC 
-946.1829 -946.1745 -928.3209 

Training set error measures:
                       ME       RMSE        MAE  MPE MAPE      MASE        ACF1
Training set 3.217528e-05 0.01585554 0.01121434 -Inf  Inf 0.6826243 -0.08846717
arimabvsp <- auto.arima(x, stepwise = FALSE, approximation = FALSE)
summary(arimabvsp)
Series: x 
ARIMA(2,0,2) with non-zero mean 

Coefficients:
          ar1      ar2     ma1     ma2   mean
      -1.4211  -0.6426  1.3303  0.5598  5e-04
s.e.   0.0255   0.0762  0.0271  0.0804  3e-04

sigma^2 estimated as 0.0002473:  log likelihood=7784.79
AIC=-15557.57   AICc=-15557.54   BIC=-15521.85

Training set error measures:
                        ME       RMSE        MAE MPE MAPE      MASE       ACF1
Training set -0.0003308969 0.01571207 0.01119238 NaN  Inf 0.6812878 0.01398369
plot(hm2, type = "fit", ggplot = TRUE)

3.3 Modelo 3 - pesos do modelo

Veja que agora o modelo obteve pesos automaticamente e por acaso foram 0.33 cada.

hm3 <- hybridModel(y = x, models = "aet", weights = "insample.errors", errorMethod = "MASE")
hm3
Hybrid forecast model comprised of the following models: auto.arima, ets, tbats
############
auto.arima with weight 0.333 
############
ets with weight 0.333 
############
tbats with weight 0.334 
hm3$auto.arima
Series: y 
ARIMA(2,0,0) with zero mean 

Coefficients:
          ar1     ar2
      -0.0850  0.0375
s.e.   0.0187  0.0187

sigma^2 estimated as 0.0002493:  log likelihood=7771.93
AIC=-15537.86   AICc=-15537.85   BIC=-15520
# hm3$ets # suprimi saida apenas para reduzir espaço hm3$tbats # suprimi saida
# apenas para reduzir espaço
tbats(x)
BATS(1, {2,0}, -, -)

Call: tbats(y = x)

Parameters
  Alpha: -0.0002107319
  AR coefficients: -0.085003 0.037504

Seed States:
             [,1]
[1,] 0.0003585277
[2,] 0.0000000000
[3,] 0.0000000000

Sigma: 0.0157815
AIC: -966.835

3.4 Modelo 4 - pesos do usuário

Recorde os pesos obtidos no modelo 2:

hm2$weights
auto.arima        ets      tbats 
 0.3333333  0.3333333  0.3333333 

Vou alterar os pesos aleatoriamente treinando com outros pesos fornecidos pelo usuario.

novospesos <- c(0.4, 0.4, 0.2)
names(novospesos) <- c("auto.arima", "ets", "tbats")
hm2$weights <- novospesos
hm2
Hybrid forecast model comprised of the following models: auto.arima, ets, tbats
############
auto.arima with weight 0.4 
############
ets with weight 0.4 
############
tbats with weight 0.2 
accuracy(hm2)
                    ME       RMSE        MAE MPE MAPE        ACF1 Theil's U
Test set -1.370438e-05 0.01578899 0.01119625 NaN  Inf -0.02915247       NaN
accuracy(hm2, individual = TRUE)
$auto.arima
                       ME       RMSE        MAE MPE MAPE      MASE
Training set 0.0002278112 0.01578324 0.01120936 NaN  Inf 0.6823217
                      ACF1
Training set -0.0003974951

$ets
                       ME       RMSE        MAE  MPE MAPE      MASE        ACF1
Training set 3.217528e-05 0.01585554 0.01121434 -Inf  Inf 0.6826243 -0.08846717

$tbats
                        ME      RMSE        MAE MPE MAPE      MASE
Training set -0.0003010996 0.0157815 0.01120292 NaN  Inf 0.6819296
                      ACF1
Training set -0.0005892115
hForecast <- forecast(hm2, h = 180)
plot(hForecast)

hForecast
     Point Forecast       Lo 80      Hi 80       Lo 95      Hi 95
2848   0.0012865785 -0.02010487 0.02259185 -0.03086524 0.03329822
2849  -0.0002974781 -0.02112048 0.02054880 -0.03187043 0.03130918
2850   0.0002777778 -0.02019024 0.02098895 -0.03095086 0.03174469
2851   0.0001694804 -0.02036992 0.02080635 -0.03113079 0.03156237
2852   0.0002002562 -0.02031911 0.02085854 -0.03108001 0.03161458
2853   0.0001935793 -0.02033015 0.02084725 -0.03109105 0.03160329
2854   0.0001953008 -0.02032731 0.02085017 -0.03108821 0.03160621
2855   0.0001949041 -0.02032796 0.02084949 -0.03108887 0.03160554
2856   0.0001950024 -0.02032780 0.02084966 -0.03108870 0.03160570
2857   0.0001949792 -0.02032784 0.02084962 -0.03108874 0.03160566
2858   0.0001949848 -0.02032783 0.02084963 -0.03108873 0.03160567
2859   0.0001949835 -0.02032783 0.02084963 -0.03108873 0.03160567
2860   0.0001949838 -0.02032783 0.02084963 -0.03108873 0.03160567
2861   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160567
2862   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160567
2863   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160568
2864   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160568
2865   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160568
2866   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160568
2867   0.0001949837 -0.02032783 0.02084963 -0.03108873 0.03160568
 [ reached 'max' / getOption("max.print") -- omitted 160 rows ]

3.5 Modelo 4 - passando argumentos ao arima

# aet = auto.arima, ets, tbats
hm4 <- hybridModel(y = x, models = "aet", a.args = list(stepwise = FALSE, approximation = FALSE),
    weights = "insample.errors", errorMethod = "MASE")
accuracy(hm4, individual = TRUE)
$auto.arima
                        ME       RMSE        MAE MPE MAPE      MASE       ACF1
Training set -0.0003308969 0.01571207 0.01119238 NaN  Inf 0.6812878 0.01398369

$ets
                       ME       RMSE        MAE  MPE MAPE      MASE        ACF1
Training set 3.217528e-05 0.01585554 0.01121434 -Inf  Inf 0.6826243 -0.08846717

$tbats
                        ME      RMSE        MAE MPE MAPE      MASE
Training set -0.0003010996 0.0157815 0.01120292 NaN  Inf 0.6819296
                      ACF1
Training set -0.0005892115
accuracy(hm4)
                    ME      RMSE        MAE MPE MAPE        ACF1 Theil's U
Test set -0.0002000603 0.0157584 0.01118714 NaN  Inf -0.02371715       NaN
hm4$weights
auto.arima        ets      tbats 
 0.3336558  0.3330025  0.3333417 

Referências

HYNDMAN, Rob J. R packages for forecast combinations. 2016. Disponível em:https://robjhyndman.com/hyndsight/forecast-combinations/

HYNDMAN, Rob J.; ATHANASOPOULOS, George . Forecasting: principles and practice. 2nd ed. Otexts, 2018. Disponível em: https://otexts.org/fpp2/.

SHAUB, David; ELLIS, Peter. forecastHybrid: Convenient Functions for Ensemble Time Series Forecasts. R package version 3.0.14. 2018. Disponível em: https://CRAN.R-project.org/package=forecastHybrid.

SHAUB, David; ELLIS, Peter.forecastHybrid: vignette. 2016. Disponível em: https://cran.r-project.org/web/packages/forecastHybrid/vignettes/forecastHybrid.html.

LS0tDQp0aXRsZTogIlPDqXJpZXMgVGVtcG9yYWlzIGNvbSBSOiBNb2RlbG8gaMOtYnJpZG8gcGFyYSBCVlNQIEJvdmVzcGEgLSBCMyINCmF1dGhvcjogIkFkcmlhbm8gTWFyY29zIFJvZHJpZ3VlcyBGaWd1ZWlyZWRvLCAqZS1tYWlsOiBhZHJpYW5vLmZpZ3VlaXJlZG9AdWZtcy5icioiDQpsaW5rY29sb3I6IGJsdWUNCmFic3RyYWN0OiANCiAgVGhpcyBpcyBhbiB1bmRlcmdyYWQgc3R1ZGVudCBsZXZlbCBpbnN0cnVjdGlvbiBmb3IgY2xhc3MgdXNlLiAgV2UgdHJ5IHRvIGlsdXN0cmF0ZSB0aW1lIHNlcmllcyBtZXRob2RzIHdpdGggaHlicmlkIG1vZGVscyB1c2luZyBgZm9yZWNhc3RIeWJyaWRgIHBhY2thZ2UuDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IGRlZmF1bHQNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogbm8NCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7ciBrbml0cl9pbml0LCBlY2hvPUZBTFNFLCBjYWNoZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJtYXJrZG93bikNCmxpYnJhcnkocm1kZm9ybWF0cykNCg0KIyMgR2xvYmFsIG9wdGlvbnMNCm9wdGlvbnMobWF4LnByaW50PSIxMDAiKQ0Kb3B0c19jaHVuayRzZXQoZWNobz1UUlVFLA0KCSAgICAgICAgICAgICBjYWNoZT1UUlVFLA0KICAgICAgICAgICAgICAgcHJvbXB0PUZBTFNFLA0KICAgICAgICAgICAgICAgdGlkeT1UUlVFLA0KICAgICAgICAgICAgICAgY29tbWVudD1OQSwNCiAgICAgICAgICAgICAgIG1lc3NhZ2U9RkFMU0UsDQogICAgICAgICAgICAgICB3YXJuaW5nPUZBTFNFKQ0Kb3B0c19rbml0JHNldCh3aWR0aD0xMDApDQpgYGANCg0KIyBMaWNlbsOnYSB7I0xpY2Vuw6dhIC51bm51bWJlcmVkfQ0KDQpUaGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgdGhlIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiBUbyB2aWV3IGEgY29weSBvZiB0aGlzIGxpY2Vuc2UsIHZpc2l0IDxodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS80LjAvPiBvciBzZW5kIGEgbGV0dGVyIHRvIENyZWF0aXZlIENvbW1vbnMsIFBPIEJveCAxODY2LCBNb3VudGFpbiBWaWV3LCBDQSA5NDA0MiwgVVNBLg0KDQohW0xpY2Vuc2U6IENDIEJZLVNBIDQuMF0oaHR0cHM6Ly9taXJyb3JzLmNyZWF0aXZlY29tbW9ucy5vcmcvcHJlc3NraXQvYnV0dG9ucy84OHgzMS9wbmcvYnktc2EucG5nKXt3aWR0aD0iMjUlIn0NCg0KIyBDaXRhw6fDo28geyNDaXRhw6fDo28gLnVubnVtYmVyZWR9DQoNClN1Z2VzdMOjbyBkZSBjaXRhw6fDo286IEZJR1VFSVJFRE8sIEFkcmlhbm8gTWFyY29zIFJvZHJpZ3Vlcy4gU8OpcmllcyBUZW1wb3JhaXMgY29tIFI6IE1vZGVsbyBow61icmlkbyBwYXJhIEJWU1AgQm92ZXNwYSAtIEIzLiBDYW1wbyBHcmFuZGUtTVMsQnJhc2lsOiBSU3R1ZGlvL1JwdWJzLCAyMDE5LiBEaXNwb27DrXZlbCBlbSA8aHR0cDovL3JwdWJzLmNvbS9hbXJvZmkvVGltZV9TZXJpZXNfSHlicmlkPi4NCg0KIyBBcHJlc2VudGHDp8Ojbw0KDQpFc3RlIGFydGlnbyBwcm9jdXJhIGlsdXN0cmFyIG9zIHByb2NlZGltZW50b3MgcGFyYSB0cmFiYWxoYXIgY29tIG3DqXRvZG9zIGRlIHPDqXJpZXMgdGVtcG9yYWlzIHBhcmEgbW9kZWxvcyBow61icmlkb3MgdXRpbGl6YW5kbyBvIHBhY290ZSBgZm9yZWNhc3RIeWJyaWRgLg0KDQojIyBQYWNvdGVzDQoNCk8gcHJpbWVpcm8gcGFzc28gcGFyYSB0YWwgw6kgYmFpeGFyIG9zIGRhZG9zIGRhIEJvbHNhIEIzLCBhbnRpZ2EgQm92ZXNwYSAoQlZTUCkuIE8gcGFjb3RlIGBxdWFudG1vZGAgbm9zIGF1eGlsaWFyw6EgYSBvYnRlciBvcyBkYWRvcyBlbGV0cm9uaWNhbWVudGUuIE8gcGVzcXVpc2Fkb3IgZGV2ZSBjb25oZWNlciBvcyB0aWNrZXJzIGRvIHBhcGVsIGRlc2VqYWRvLiBBbGd1bnMgcGFjb3RlcyBmb3JhbSByZXRpcmFkb3MgZG8gQ1JBTiBlIHByZWNpc2Fyw6EgcGVnYXIgZSBpbnN0YWxhciBkbyBhcnF1aXZvIChbR2V0SEZEYXRhXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9zcmMvY29udHJpYi9BcmNoaXZlL0dldEhGRGF0YS9HZXRIRkRhdGFfMS43LnRhci5neiAiR2V0SEZEYXRhIikgZSBbc3RvY2tQb3J0Zm9saW9dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3NyYy9jb250cmliL0FyY2hpdmUvc3RvY2tQb3J0Zm9saW8vc3RvY2tQb3J0Zm9saW9fMS4yLnRhci5neiAic3RvY2tQb3J0Zm9saW8iKSkuDQoNCmBgYHtyIHBhY290ZXMsIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmlmICghcmVxdWlyZShxdWFudG1vZCkpIHsgDQogIGluc3RhbGwucGFja2FnZXMoJ3F1YW50bW9kJykgDQogIGxpYnJhcnkocXVhbnRtb2QpIA0KfQ0KaWYgKCFyZXF1aXJlKGZwcDIpKSB7IA0KICBpbnN0YWxsLnBhY2thZ2VzKCdmcHAyJykgDQogIGxpYnJhcnkoZnBwMikgDQp9DQppZiAoIXJlcXVpcmUoR2V0SEZEYXRhKSkgeyANCiAgaW5zdGFsbC5wYWNrYWdlcygnR2V0SEZEYXRhJykgDQogIGxpYnJhcnkoR2V0SEZEYXRhKSANCn0NCmlmICghcmVxdWlyZShmb3JlY2FzdEh5YnJpZCkpIHsgDQogIGluc3RhbGwucGFja2FnZXMoJ2ZvcmVjYXN0SHlicmlkJykgDQogIGxpYnJhcnkoZm9yZWNhc3RIeWJyaWQpIA0KfQ0KYGBgDQoNCiMgRGFkb3MgQm92ZXNwYQ0KDQpgYGB7ciBkYWRvcywgd2FybmluZz1GQUxTRX0NCnF1YW50bW9kOjpnZXRTeW1ib2xzKCdeQlZTUCcsc3JjPSd5YWhvbycpICAjIHBlbG8ge3F1YW50bW9kfQ0KY2hhcnRTZXJpZXMoQlZTUCkNCmBgYA0KDQojIyMgQ2FsY3VsYW5kbyBvIHJldG9ybm8NCg0KYGBge3IgcmV0b3Jub30NCiNyZXF1aXJlKHN0b2NrUG9ydGZvbGlvKQ0KDQojIGluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikNCiNyZXF1aXJlKHF1YW50bW9kKQ0KDQojIyMgQm92ZXNwYQ0KI2dldFN5bWJvbHMoJ15CVlNQJyxzcmM9J3lhaG9vJykgICMgcGVsbyB7cXVhbnRtb2R9DQpCVlNQLkNsb3NlIDwtIEJWU1AkQlZTUC5DbG9zZQ0KIyMjIyBsaW1wZXphIGRvcyBkYWRvcyANCkJWU1BfY2xlYW48LWlzLm5hKEJWU1AuQ2xvc2UpIDwtIEJWU1AuQ2xvc2UgPT0gMCANCkJWU1BfY2xlYW48LW5hLmxvY2YoQlZTUC5DbG9zZSwgZnJvbUxhc3QgPSBGQUxTRSwgY29yZWRhdGEgPSBOVUxMKQ0KbWF4KEJWU1BfY2xlYW4pDQptaW4oQlZTUF9jbGVhbikNCnBsb3QoQlZTUF9jbGVhbikNCmBgYA0KDQpgYGB7ciByZXRvcm5vZGlhfQ0KIyBvYnRlbmRvIG8gcmV0b3JubyBkacOhcmlvDQpyX0JWU1A8LWRhaWx5UmV0dXJuKEJWU1BfY2xlYW4sdHlwZSA9ICJsb2ciKQ0KcGxvdChyX0JWU1ApDQpoaXN0KHJfQlZTUCwxMDApDQojIGphbmVsYSBwYXJhIGFww7NzIDIwMTANCnJfQlZTUF9wb3MyMDEwPC13aW5kb3cocl9CVlNQLHN0YXJ0ID0gIjIwMTAtMDEtMDEiKQ0KcGxvdChyX0JWU1BfcG9zMjAxMCkNCmhpc3Qocl9CVlNQX3BvczIwMTAsMTAwKQ0KbWF4KHJfQlZTUF9wb3MyMDEwKQ0KbWluKHJfQlZTUF9wb3MyMDEwKQ0KDQpwbG90KHdpbmRvdyhCVlNQX2NsZWFuLHN0YXJ0ID0gIjIwMTAtMDEtMDEiKSkNCmBgYA0KDQojIE1vZGVsbyBIw61icmlkbyBgZm9yZWNhc3RIeWJyaWRgIGRlIFNoYXViIGUgRWxsaXMgKDIwMTgpDQoNClZvdSB1c2FyIGFwZW5hcyBhIHPDqXJpZSAibGltcGEiIGUgY29tIGphbmVsYSBwYXJhIGFww7NzIDIwMTAuIMOJIHVtIG9iamV0byBkacOhcmlvIGNvbSBnYXBzIGltcGxpY2l0b3MgcGFyYSBvcyBmaW5haXMgZGUgc2VtYW5hIChub24tdHJhZGVkIGRheXMpLg0KDQpgYGB7ciBtb2RlbG9yYXBpZG8sIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCng8LWFzLnRzKHJfQlZTUF9wb3MyMDEwKQ0KbGlicmFyeShmb3JlY2FzdEh5YnJpZCkNCm1vZGVsb3JhcGlkbyA8LSBoeWJyaWRNb2RlbCh4KQ0KZmNzdDwtZm9yZWNhc3QobW9kZWxvcmFwaWRvLGg9MzApDQpmY3N0DQpwbG90KGZvcmVjYXN0KG1vZGVsb3JhcGlkbykpDQoNCmBgYA0KDQpBIGZ1bsOnw6NvIGBoeWJyaWRNb2RlbGAgdXRpbGl6YSBhIG9ww6fDo28gYG1vZGVsc2AgcGFyYSBpbmRpY2FyIHF1YWlzIG9zIG1vZGVsb3MgYSBzZXJlbSB1dGlsaXphZG9zOiAtIGEgPSBhdXRvLmFyaW1hO1wNCi0gZSA9IGV0cztcDQotIG4gPSBubmV0YXI7XA0KLSBzID0gc3RsbTtcDQotIHQgPSB0YmF0cztcDQotIHogPSBzbmFpdmUuDQoNCkFzc2ltLCBhbyBlc3BlY2lmaWNhciBgbW9kZWxzID0gImFldCIsIHdlaWdodHMgPSAiZXF1YWwiYCwgZXN0YW1vcyBkZWZpbmluZG8gcXVlIHNlcsOjbyB1dGlsaXphZG9zIG9zIG1vZGVsb3MgQVJJTUEsIEVUUyBlIFRCQVRTIGNvbSBwZXNvcyBpZ3VhaXMgcGFyYSBjYWRhIG5hIHJlYWxpemHDp8OjbyBkYSBjb21iaW5hw6fDo28gZG9zIGZvcmVjYXN0cy4NCg0KIyMgTW9kZWxvIDENCg0KYGBge3IgbW9kZWxvMSwgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KIyBvcMOnw6NvIGFldCBpbmRpY2EgbyBtb2RlbG8gaGlicmlkbyBwYXJhIA0KaG0xIDwtIGh5YnJpZE1vZGVsKHkgPSB4LCANCiAgICAgICAgICAgICAgICAgICBtb2RlbHMgPSAiYWV0Iiwgd2VpZ2h0cyA9ICJlcXVhbCIpDQoNCiMgcmVzdW1vIGFyaW1hDQpobTEkYXV0by5hcmltYQ0KIyBvIHBlc3F1aXNhZG9yIHBvZGUgcmV0aXJhciBkb3MgZGVtYWlzIG1vZGVsb3MgY2FzbyBkZXNlamUNCnBsb3QoZm9yZWNhc3QoaG0xJGF1dG8uYXJpbWEpKQ0KcHJpbnQoaG0xKQ0KcGxvdChobTEsIHR5cGUgPSAiZml0IikgDQpwbG90KGhtMSwgdHlwZSA9ICJtb2RlbHMiKQ0KYGBgDQoNClZlamEgcXVlIG5lc3NlIGNhc28sIG8gbW9kZWxvICJhdXRvbcOhdGljbyIgbGV2b3UgYSB1bSBBUklNQSAoMCwwLDApLiBBIGZ1bsOnw6NvIGBoeWJyaWRNb2RlbGAgY29tIG9ww6fDo28gYHdlaWdodHMgPSAiZXF1YWwiYCBsZXZvdSBhb3MgcGVzb3MgMC4zMyBwYXJhIGNhZGEgbW9kZWxvIHBvciBzZXJlbSAzIG1vZGVsb3MgKEFSSU1BLCBFVFMgZSBUQkFUUykuDQoNCiMjIE1vZGVsbyAyDQoNCmBgYHtyIG1vZGVsbzIsIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmhtMiA8LSBoeWJyaWRNb2RlbCh5ID0geCwgDQogICAgICAgICAgICAgICAgICAgbW9kZWxzID0gImFldCIsIHdlaWdodHMgPSAiZXF1YWwiKQ0KDQpobTIkYXV0by5hcmltYQ0KcGxvdChmb3JlY2FzdChobTIkYXV0by5hcmltYSkpDQpwcmludChobTIpDQpwbG90KGhtMiwgdHlwZSA9ICJmaXQiKSANCnBsb3QoaG0yLCB0eXBlID0gIm1vZGVscyIpDQojaG0yJGV0cw0KDQpldHNwZXRyPC1ldHMoeCkNCnN1bW1hcnkoZXRzcGV0cikNCmFyaW1hYnZzcDwtYXV0by5hcmltYSh4LHN0ZXB3aXNlPUZBTFNFLCBhcHByb3hpbWF0aW9uPUZBTFNFKQ0Kc3VtbWFyeShhcmltYWJ2c3ApDQoNCnBsb3QoaG0yLCB0eXBlID0gImZpdCIsIGdncGxvdCA9IFRSVUUpDQpgYGANCg0KIyMgTW9kZWxvIDMgLSBwZXNvcyBkbyBtb2RlbG8NCg0KVmVqYSBxdWUgYWdvcmEgbyBtb2RlbG8gb2J0ZXZlIHBlc29zIGF1dG9tYXRpY2FtZW50ZSBlIHBvciBhY2FzbyBmb3JhbSAwLjMzIGNhZGEuDQoNCmBgYHtyIG1vZGVsbzMsIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmhtMyA8LSBoeWJyaWRNb2RlbCh5ID0geCwgDQogICAgICAgICAgICAgICAgICAgbW9kZWxzID0gImFldCIsIA0KICAgICAgICAgICAgICAgICAgIHdlaWdodHMgPSAiaW5zYW1wbGUuZXJyb3JzIiwgDQogICAgICAgICAgICAgICAgICAgZXJyb3JNZXRob2QgPSAiTUFTRSIpDQpobTMgDQpobTMkYXV0by5hcmltYQ0KI2htMyRldHMgIyBzdXByaW1pIHNhaWRhIGFwZW5hcyBwYXJhIHJlZHV6aXIgZXNwYcOnbw0KI2htMyR0YmF0cyAgIyBzdXByaW1pIHNhaWRhIGFwZW5hcyBwYXJhIHJlZHV6aXIgZXNwYcOnbw0KdGJhdHMoeCkNCmBgYA0KDQojIyBNb2RlbG8gNCAtIHBlc29zIGRvIHVzdcOhcmlvDQoNClJlY29yZGUgb3MgcGVzb3Mgb2J0aWRvcyBubyBtb2RlbG8gMjoNCg0KYGBge3IgbW9kZWxvNCwgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KDQpobTIkd2VpZ2h0cyANCiANCmBgYA0KDQpWb3UgYWx0ZXJhciBvcyBwZXNvcyBhbGVhdG9yaWFtZW50ZSB0cmVpbmFuZG8gY29tIG91dHJvcyBwZXNvcyBmb3JuZWNpZG9zIHBlbG8gdXN1YXJpby4NCg0KYGBge3Igbm92b3NwZXNvcywgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0Kbm92b3NwZXNvcyA8LSBjKDAuNCwgMC40LCAwLjIpDQpuYW1lcyhub3Zvc3Blc29zKSA8LSBjKCJhdXRvLmFyaW1hIiwgImV0cyIsICJ0YmF0cyIpDQpobTIkd2VpZ2h0cyA8LSBub3Zvc3Blc29zDQpobTINCmFjY3VyYWN5KGhtMikNCg0KDQphY2N1cmFjeShobTIsIGluZGl2aWR1YWwgPSBUUlVFKQ0KDQpoRm9yZWNhc3QgPC0gZm9yZWNhc3QoaG0yLCBoID0gMTgwKQ0KcGxvdChoRm9yZWNhc3QpDQpoRm9yZWNhc3QNCmBgYA0KDQojIyBNb2RlbG8gNCAtIHBhc3NhbmRvIGFyZ3VtZW50b3MgYW8gYXJpbWENCg0KYGBge3IgbW9kZWxvNG5ldywgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KIyBhZXQgPSBhdXRvLmFyaW1hLCBldHMsIHRiYXRzDQpobTQgPC0gaHlicmlkTW9kZWwoeSA9IHgsIA0KICAgICAgICAgICAgICAgICAgIG1vZGVscyA9ICJhZXQiLCANCiAgICAgICAgICAgICAgICAgICBhLmFyZ3MgPSBsaXN0KHN0ZXB3aXNlPUZBTFNFLCBhcHByb3hpbWF0aW9uPUZBTFNFKSwNCiAgICAgICAgICAgICAgICAgICB3ZWlnaHRzID0gImluc2FtcGxlLmVycm9ycyIsIA0KICAgICAgICAgICAgICAgICAgIGVycm9yTWV0aG9kID0gIk1BU0UiKQ0KYWNjdXJhY3koaG00LCBpbmRpdmlkdWFsID0gVFJVRSkNCmFjY3VyYWN5KGhtNCkNCg0KaG00JHdlaWdodHMNCg0KYGBgDQoNCiMgUmVmZXLDqm5jaWFzIHsjUmVmZXLDqm5jaWFzIC51bm51bWJlcmVkfQ0KDQpIWU5ETUFOLCBSb2IgSi4gUiBwYWNrYWdlcyBmb3IgZm9yZWNhc3QgY29tYmluYXRpb25zLiAyMDE2LiBEaXNwb27DrXZlbCBlbTo8aHR0cHM6Ly9yb2JqaHluZG1hbi5jb20vaHluZHNpZ2h0L2ZvcmVjYXN0LWNvbWJpbmF0aW9ucy8+DQoNCkhZTkRNQU4sIFJvYiBKLjsgQVRIQU5BU09QT1VMT1MsIEdlb3JnZSAuIEZvcmVjYXN0aW5nOiBwcmluY2lwbGVzIGFuZCBwcmFjdGljZS4gMm5kIGVkLiBPdGV4dHMsIDIwMTguIERpc3BvbsOtdmVsIGVtOiA8aHR0cHM6Ly9vdGV4dHMub3JnL2ZwcDIvPi4NCg0KU0hBVUIsIERhdmlkOyBFTExJUywgUGV0ZXIuIGZvcmVjYXN0SHlicmlkOiBDb252ZW5pZW50IEZ1bmN0aW9ucyBmb3IgRW5zZW1ibGUgVGltZSBTZXJpZXMgRm9yZWNhc3RzLiBSIHBhY2thZ2UgdmVyc2lvbiAzLjAuMTQuIDIwMTguIERpc3BvbsOtdmVsIGVtOiA8aHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1mb3JlY2FzdEh5YnJpZD4uDQoNClNIQVVCLCBEYXZpZDsgRUxMSVMsIFBldGVyLmZvcmVjYXN0SHlicmlkOiB2aWduZXR0ZS4gMjAxNi4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZm9yZWNhc3RIeWJyaWQvdmlnbmV0dGVzL2ZvcmVjYXN0SHlicmlkLmh0bWw+Lg0K