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
License: CC BY-SA 4.0

Citação

Sugestão de citação: FIGUEIREDO, Adriano Marcos Rodrigues. Séries Temporais: previsão de ações com ETS. Campo Grande-MS,Brasil: RStudio/Rpubs, 2024. Disponível em http://rpubs.com/amrofi/stocks_ETS2.

1 Introdução

2 Dados e gráfico

2.1 VALE3 e PETR4

library(quantmod)
library(ggplot2)
library(scales)
library(ggthemes)
library(gridExtra)  # para vaios graficos juntos
library(dygraphs)  # para os graficos dinamicos
library(fpp2)  # para fazer o ETS
library(Metrics)  # para fazer acurácia
env = new.env()
# pegando cotações mensais da petrobras e do ibovespa
getSymbols(c("PETR4.SA", "VALE3.SA"), src = "yahoo", env = env, periodicity = "monthly",
    from = "2000-01-01", to = "2019-09-01")
[1] "PETR4.SA" "VALE3.SA"
vale = env$VALE3.SA[, 6]
petro = env$PETR4.SA[, 6]

g1 <- autoplot(vale) + geom_line(size = 0.8, colour = "darkblue") + scale_x_date(date_breaks = "12 months",
    labels = date_format("%b/%Y")) + theme(axis.text.x = element_text(angle = 60,
    vjust = 1, hjust = 1)) + labs(title = "VALE3.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    xlab("Mês/Ano") + ylab("R$")

g2 <- autoplot(petro) + geom_line(size = 0.8, colour = "darkblue") + scale_x_date(date_breaks = "12 months",
    labels = date_format("%b/%Y")) + theme(axis.text.x = element_text(angle = 60,
    vjust = 1, hjust = 1)) + labs(title = "PETR4.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    xlab("Mês/Ano") + ylab("R$")
# os dois graficos de cotacoes juntos
grid.arrange(g1, g2, nrow = 2)

2.2 Checando a periodicidade dos dados

# Checando a periodicidade dos dados 2000-01-01 até 2019-08-01
periodicity(petro)
Monthly periodicity from 2000-02-01 to 2019-08-01 
periodicity(vale)
Monthly periodicity from 2000-02-01 to 2019-08-01 

2.3 Retornos mensais PETR4 e VALE3 com base no preço ajustado

r_petro <- monthlyReturn(petro, type = "log")[-1, ]
r_vale <- monthlyReturn(vale, type = "log")[-1, ]
g3 <- autoplot(r_petro) + geom_line(size = 0.8, colour = "darkblue") + scale_x_date(date_breaks = "12 months",
    labels = date_format("%b/%Y")) + theme(axis.text.x = element_text(angle = 60,
    vjust = 1, hjust = 1)) + labs(title = "Retornos da PETR4.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    xlab("Mês/Ano") + ylab("")

g4 <- autoplot(r_vale) + geom_line(size = 0.8, colour = "darkblue") + scale_x_date(date_breaks = "12 months",
    labels = date_format("%b/%Y")) + theme(axis.text.x = element_text(angle = 60,
    vjust = 1, hjust = 1)) + labs(title = "Retornos da VALE3.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    xlab("Mês/Ano") + ylab("")
# os dois graficos de cotacoes juntos
grid.arrange(g3, g4, nrow = 2)

3 Forecast

3.1 Delimitando treino x teste

# transformando em ts
r_petro <- ts(r_petro, start = c(2000, 3), frequency = 12)
r_vale <- ts(r_vale, start = c(2000, 3), frequency = 12)

# treino até setembro 2015 (189 meses)
r_petro_treino <- window(r_petro, start = c(2000, 3), end = c(2015, 10))
r_vale_treino <- window(r_vale, start = c(2000, 3), end = c(2015, 10))
# teste (45 meses após outubro de 2019)
r_petro_teste <- window(r_petro, start = c(2015, 11))
r_vale_teste <- window(r_vale, start = c(2015, 11))

Vamos checar se separamos corretamente:

autoplot(r_petro) + labs(title = "Retornos da PETR4.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    autolayer(r_petro_treino, series = "Training") + autolayer(r_petro_teste, series = "Test")

autoplot(r_vale) + labs(title = "Retornos da VALE3.SA", caption = "Fonte: Dados do Yahoo Finance.") +
    autolayer(r_vale_treino, series = "Training") + autolayer(r_vale_teste, series = "Test")

3.2 Holt-Winters

Farei a previsão pelo método Holt-Winters conforme Hyndman e Athanasopoulos (2018).

# Holt-Winters petro
petro.hw <- forecast::hw(r_petro_treino, h = 60, seasonal = "additive")
summary(petro.hw)

Forecast method: Holt-Winters' additive method

Model Information:
Holt-Winters' additive method 

Call:
 forecast::hw(y = r_petro_treino, h = 60, seasonal = "additive") 

  Smoothing parameters:
    alpha = 6e-04 
    beta  = 5e-04 
    gamma = 1e-04 

  Initial states:
    l = 0.0314 
    b = 2e-04 
    s = 0.0171 -0.0083 0.0162 -0.0073 -0.0152 -0.0106
           0.0347 -0.0134 -0.0227 0.0139 0.0177 -0.0221

  sigma:  0.1085

     AIC     AICc      BIC 
168.5795 172.1585 223.6892 

Error measures:
                      ME      RMSE        MAE      MPE     MAPE      MASE
Training set -0.01007944 0.1038463 0.08193888 99.96614 132.6828 0.7078731
                   ACF1
Training set 0.07285993

Forecasts:
         Point Forecast      Lo 80      Hi 80      Lo 95     Hi 95
Oct 2015   -0.007775968 -0.1468785 0.13132660 -0.2205150 0.2049630
Nov 2015   -0.033032914 -0.1721356 0.10606973 -0.2457721 0.1797062
Dec 2015   -0.008338471 -0.1474413 0.13076434 -0.2210779 0.2044009
Jan 2016   -0.048215589 -0.1873187 0.09088752 -0.2609554 0.1645243
Feb 2016   -0.009212942 -0.1483165 0.12989061 -0.2219535 0.2035276
Mar 2016   -0.013759614 -0.1528638 0.12534458 -0.2265011 0.1989819
Apr 2016   -0.051037240 -0.1901423 0.08806782 -0.2637801 0.1617056
May 2016   -0.042546585 -0.1816528 0.09655959 -0.2552911 0.1701980
Jun 2016    0.004869241 -0.1342383 0.14397683 -0.2078775 0.2176159
Jul 2016   -0.041227503 -0.1803368 0.09788182 -0.2539769 0.1715218
Aug 2016   -0.046519365 -0.1856308 0.09259205 -0.2592719 0.1662332
Sep 2016   -0.039341979 -0.1784559 0.09977192 -0.2520983 0.1734144
Oct 2016   -0.016559135 -0.1556761 0.12255780 -0.2293201 0.1962019
Nov 2016   -0.041816081 -0.1809364 0.09730422 -0.2545822 0.1709501
Dec 2016   -0.017121638 -0.1562458 0.12200252 -0.2298937 0.1956504
Jan 2017   -0.056998755 -0.1961273 0.08212978 -0.2697775 0.1557800
Feb 2017   -0.017996109 -0.1571296 0.12113737 -0.2307824 0.1947902
Mar 2017   -0.022542781 -0.1616818 0.11659623 -0.2353375 0.1902520
Apr 2017   -0.059820407 -0.1989656 0.07932476 -0.2726246 0.1529838
May 2017   -0.051329752 -0.1904817 0.08782223 -0.2641443 0.1614848
 [ reached 'max' / getOption("max.print") -- omitted 40 rows ]
autoplot(r_petro) + forecast::autolayer(petro.hw, series = "Holt-Winters adit", PI = FALSE) +
    xlab("Ano") + ylab("Retorno") + ggtitle("Forecasts para PETR4") + guides(colour = guide_legend(title = "Forecast"))

# Holt-Winters vale
vale.hw <- forecast::hw(r_vale_treino, h = 60, seasonal = "additive")
summary(vale.hw)

Forecast method: Holt-Winters' additive method

Model Information:
Holt-Winters' additive method 

Call:
 forecast::hw(y = r_vale_treino, h = 60, seasonal = "additive") 

  Smoothing parameters:
    alpha = 1e-04 
    beta  = 1e-04 
    gamma = 1e-04 

  Initial states:
    l = 0.0498 
    b = -4e-04 
    s = 0.0246 0.0028 0.0292 -0.0188 0.0057 0.0283
           -0.0453 0.0268 -0.0234 0.0171 -0.016 -0.0311

  sigma:  0.0916

     AIC     AICc      BIC 
104.3911 107.9700 159.5008 

Error measures:
                       ME       RMSE        MAE  MPE MAPE     MASE        ACF1
Training set -0.002086669 0.08762808 0.06753594 -Inf  Inf 0.720988 -0.02451164

Forecasts:
         Point Forecast      Lo 80      Hi 80      Lo 95     Hi 95
Oct 2015    0.003356254 -0.1140219 0.12073440 -0.1761581 0.1828706
Nov 2015   -0.023438948 -0.1408171 0.09393920 -0.2029533 0.1560754
Dec 2015   -0.002002928 -0.1193811 0.11537523 -0.1815173 0.1775115
Jan 2016   -0.058097853 -0.1754760 0.05928032 -0.2376123 0.1214166
Feb 2016   -0.043399002 -0.1607772 0.07397919 -0.2229135 0.1361155
Mar 2016   -0.010795821 -0.1281740 0.10658240 -0.1903103 0.1687187
Apr 2016   -0.051649801 -0.1690281 0.06572846 -0.2311644 0.1278648
May 2016   -0.001820050 -0.1191984 0.11555827 -0.1813347 0.1776946
Jun 2016   -0.074279551 -0.1916579 0.04309883 -0.2537943 0.1052352
Jul 2016   -0.001166086 -0.1185446 0.11621238 -0.1806810 0.1783488
Aug 2016   -0.024127342 -0.1415059 0.09325122 -0.2036424 0.1553877
Sep 2016   -0.049077977 -0.1664567 0.06830071 -0.2285932 0.1304372
Oct 2016   -0.001493940 -0.1188728 0.11588491 -0.1810094 0.1780215
Nov 2016   -0.028289142 -0.1456682 0.08908987 -0.2078048 0.1512266
Dec 2016   -0.006853122 -0.1242323 0.11052608 -0.1863691 0.1726629
Jan 2017   -0.062948047 -0.1803275 0.05443136 -0.2424644 0.1165683
Feb 2017   -0.048249196 -0.1656288 0.06913045 -0.2277659 0.1312675
Mar 2017   -0.015646015 -0.1330259 0.10173390 -0.1951631 0.1638711
Apr 2017   -0.056499996 -0.1738802 0.06088022 -0.2360175 0.1230176
May 2017   -0.006670244 -0.1240508 0.11071030 -0.1861883 0.1728478
 [ reached 'max' / getOption("max.print") -- omitted 40 rows ]
autoplot(r_vale) + forecast::autolayer(vale.hw, series = "Holt-Winters adit", PI = FALSE) +
    xlab("Ano") + ylab("Retorno") + ggtitle("Forecasts para VALE3") + guides(colour = guide_legend(title = "Forecast"))

3.2.1 Acurácia

Metrics::smape(r_petro_teste, petro.hw$mean)
[1] 1.473701
Metrics::smape(r_vale_teste, vale.hw$mean)
[1] 1.539472
Metrics::mape(r_petro_teste, petro.hw$mean)
[1] 1.736309
Metrics::mape(r_vale_teste, vale.hw$mean)
[1] 1.227286

3.3 ETS

Farei a previsão pelo método ETS (Error Trend Seasonal) conforme Hyndman e Athanasopoulos (2018).

# ETS (error trend seasonal) de Hyndman - pacote fpp2
set.seed(123)
petro.ets <- ets(r_petro_treino, model = "ZZZ")  # N=none, A=additive, M=multiplicative e Z=automatic
summary(petro.ets)
ETS(A,N,N) 

Call:
 ets(y = r_petro_treino, model = "ZZZ") 

  Smoothing parameters:
    alpha = 0.0137 

  Initial states:
    l = 0.0089 

  sigma:  0.1058

     AIC     AICc      BIC 
145.5134 145.6431 155.2386 

Training set error measures:
                       ME      RMSE        MAE      MPE     MAPE      MASE
Training set -0.006332792 0.1052107 0.08227167 82.30262 126.2395 0.7107481
                   ACF1
Training set 0.07332308
petro.ets.forecasts <- forecast.ets(petro.ets, h = 12)
summary(petro.ets.forecasts)

Forecast method: ETS(A,N,N)

Model Information:
ETS(A,N,N) 

Call:
 ets(y = r_petro_treino, model = "ZZZ") 

  Smoothing parameters:
    alpha = 0.0137 

  Initial states:
    l = 0.0089 

  sigma:  0.1058

     AIC     AICc      BIC 
145.5134 145.6431 155.2386 

Error measures:
                       ME      RMSE        MAE      MPE     MAPE      MASE
Training set -0.006332792 0.1052107 0.08227167 82.30262 126.2395 0.7107481
                   ACF1
Training set 0.07332308

Forecasts:
         Point Forecast      Lo 80     Hi 80      Lo 95     Hi 95
Oct 2015   -0.007514248 -0.1430663 0.1280378 -0.2148232 0.1997947
Nov 2015   -0.007514248 -0.1430790 0.1280505 -0.2148426 0.1998141
Dec 2015   -0.007514248 -0.1430916 0.1280631 -0.2148620 0.1998335
Jan 2016   -0.007514248 -0.1431043 0.1280758 -0.2148813 0.1998528
Feb 2016   -0.007514248 -0.1431170 0.1280885 -0.2149007 0.1998722
Mar 2016   -0.007514248 -0.1431296 0.1281011 -0.2149201 0.1998916
Apr 2016   -0.007514248 -0.1431423 0.1281138 -0.2149394 0.1999109
May 2016   -0.007514248 -0.1431550 0.1281265 -0.2149588 0.1999303
Jun 2016   -0.007514248 -0.1431676 0.1281391 -0.2149782 0.1999497
Jul 2016   -0.007514248 -0.1431803 0.1281518 -0.2149975 0.1999691
Aug 2016   -0.007514248 -0.1431929 0.1281645 -0.2150169 0.1999884
Sep 2016   -0.007514248 -0.1432056 0.1281771 -0.2150363 0.2000078
plot(petro.ets.forecasts, col = 2)

# ETS (error trend seasonal) de Hyndman - pacote fpp2
set.seed(123)
vale.ets <- ets(r_vale_treino, model = "ZZZ")  # N=none, A=additive, M=multiplicative e Z=automatic
summary(vale.ets)
ETS(A,N,N) 

Call:
 ets(y = r_vale_treino, model = "ZZZ") 

  Smoothing parameters:
    alpha = 0.0266 

  Initial states:
    l = 0.0221 

  sigma:  0.0931

      AIC      AICc       BIC 
 97.38815  97.51788 107.11339 

Training set error measures:
                       ME       RMSE        MAE  MPE MAPE      MASE        ACF1
Training set -0.007819222 0.09263336 0.07108109 -Inf  Inf 0.7588347 -0.06733914
vale.ets.forecasts <- forecast.ets(vale.ets, h = 12)
summary(vale.ets.forecasts)

Forecast method: ETS(A,N,N)

Model Information:
ETS(A,N,N) 

Call:
 ets(y = r_vale_treino, model = "ZZZ") 

  Smoothing parameters:
    alpha = 0.0266 

  Initial states:
    l = 0.0221 

  sigma:  0.0931

      AIC      AICc       BIC 
 97.38815  97.51788 107.11339 

Error measures:
                       ME       RMSE        MAE  MPE MAPE      MASE        ACF1
Training set -0.007819222 0.09263336 0.07108109 -Inf  Inf 0.7588347 -0.06733914

Forecasts:
         Point Forecast      Lo 80     Hi 80      Lo 95     Hi 95
Oct 2015    -0.01722824 -0.1365758 0.1021193 -0.1997546 0.1652981
Nov 2015    -0.01722824 -0.1366181 0.1021617 -0.1998193 0.1653629
Dec 2015    -0.01722824 -0.1366605 0.1022040 -0.1998840 0.1654276
Jan 2016    -0.01722824 -0.1367027 0.1022463 -0.1999487 0.1654922
Feb 2016    -0.01722824 -0.1367450 0.1022885 -0.2000134 0.1655569
Mar 2016    -0.01722824 -0.1367873 0.1023308 -0.2000780 0.1656215
Apr 2016    -0.01722824 -0.1368295 0.1023730 -0.2001426 0.1656861
May 2016    -0.01722824 -0.1368718 0.1024153 -0.2002072 0.1657507
Jun 2016    -0.01722824 -0.1369140 0.1024575 -0.2002718 0.1658153
Jul 2016    -0.01722824 -0.1369562 0.1024997 -0.2003363 0.1658798
Aug 2016    -0.01722824 -0.1369984 0.1025419 -0.2004008 0.1659444
Sep 2016    -0.01722824 -0.1370405 0.1025841 -0.2004653 0.1660089
plot(vale.ets.forecasts, col = 2)

3.3.1 Acurácia

Metrics::smape(r_petro_teste, petro.ets.forecasts$mean)
[1] 1.941631
Metrics::smape(r_vale_teste, vale.ets.forecasts$mean)
[1] 1.782595
Metrics::mape(r_petro_teste, petro.ets.forecasts$mean)
[1] 1.027739
Metrics::mape(r_vale_teste, vale.ets.forecasts$mean)
[1] 1.023852

Referências

FIGUEIREDO, A.M.R. Tópicos de econometria: ações. UFMS:Campo Grande,2019. Disponível em: http://rpubs.com/amrofi/acoesBOV_VALE3.

HYNDMAN, Rob. (2018). fpp2: Data for “Forecasting: Principles and Practice” (2nd Edition). R package version 2.3. Disponível em: https://CRAN.R-project.org/package=fpp2.

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

LS0tDQp0aXRsZTogIlPDqXJpZXMgVGVtcG9yYWlzOiBwcmV2aXPDo28gZGUgYcOnw7VlcyBjb20gRVRTIg0KYXV0aG9yOiAiQWRyaWFubyBNYXJjb3MgUm9kcmlndWVzIEZpZ3VlaXJlZG8sICplLW1haWw6IGFkcmlhbm8uZmlndWVpcmVkb0B1Zm1zLmJyKiINCmxpbmtjb2xvcjogYmx1ZQ0KYWJzdHJhY3Q6IA0KICBUaGlzIGlzIGFuIHVuZGVyZ3JhZCBzdHVkZW50IGxldmVsIGluc3RydWN0aW9uIGZvciBjbGFzcyB1c2UuICANCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogZGVmYXVsdA0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIHRodW1ibmFpbHM6IHRydWUNCiAgICBsaWdodGJveDogdHJ1ZQ0KICAgIGdhbGxlcnk6IGZhbHNlDQogICAgaGlnaGxpZ2h0OiAidGFuZ28iDQogICAgdXNlX2Jvb2tkb3duOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6DQogICAgaGlnaGxpZ2h0OiAidGFuZ28iDQogICAgdGhlbWU6IGpvdXJuYWwNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KZ3JhcGhpY3M6IHllcw0KLS0tDQoNCg0KYGBge3Iga25pdHJfaW5pdCwgZWNobz1GQUxTRSwgY2FjaGU9RkFMU0V9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShybWFya2Rvd24pDQpsaWJyYXJ5KHJtZGZvcm1hdHMpDQoNCiMjIEdsb2JhbCBvcHRpb25zDQpvcHRpb25zKG1heC5wcmludD0iMTAwIikNCm9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwNCgkgICAgICAgICAgICAgY2FjaGU9VFJVRSwNCiAgICAgICAgICAgICAgIHByb21wdD1GQUxTRSwNCiAgICAgICAgICAgICAgIHRpZHk9VFJVRSwNCiAgICAgICAgICAgICAgIGNvbW1lbnQ9TkEsDQogICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLA0KICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkNCm9wdHNfa25pdCRzZXQod2lkdGg9MTAwKQ0KYGBgDQoNCg0KTGljZW7Dp2Egey0jTGljZW7Dp2F9DQo9PT09PT09PT09PT09PT09PT09DQoNClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIFRvIHZpZXcgYSBjb3B5IG9mIHRoaXMgbGljZW5zZSwgdmlzaXQgPGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8+IG9yIHNlbmQgYSBsZXR0ZXIgdG8gQ3JlYXRpdmUgQ29tbW9ucywgUE8gQm94IDE4NjYsIE1vdW50YWluIFZpZXcsIENBIDk0MDQyLCBVU0EuDQoNCiFbTGljZW5zZTogQ0MgQlktU0EgNC4wXShodHRwczovL21pcnJvcnMuY3JlYXRpdmVjb21tb25zLm9yZy9wcmVzc2tpdC9idXR0b25zLzg4eDMxL3BuZy9ieS1zYS5wbmcpeyB3aWR0aD0yNSUgfQ0KDQpDaXRhw6fDo28gey0jQ2l0YcOnw6NvfQ0KPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KU3VnZXN0w6NvIGRlIGNpdGHDp8OjbzoNCkZJR1VFSVJFRE8sIEFkcmlhbm8gTWFyY29zIFJvZHJpZ3Vlcy4gU8OpcmllcyBUZW1wb3JhaXM6IHByZXZpc8OjbyBkZSBhw6fDtWVzIGNvbSBFVFMuIENhbXBvIEdyYW5kZS1NUyxCcmFzaWw6IFJTdHVkaW8vUnB1YnMsIDIwMjQuIERpc3BvbsOtdmVsIGVtIDxodHRwOi8vcnB1YnMuY29tL2Ftcm9maS9zdG9ja3NfRVRTMj4uIA0KDQpJbnRyb2R1w6fDo28NCj09PT09PT09PT09PT09PT09PT0NCg0KRGFkb3MgZSBncsOhZmljbw0KPT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyMgVkFMRTMgZSBQRVRSNA0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KGdyaWRFeHRyYSkgIyBwYXJhIHZhaW9zIGdyYWZpY29zIGp1bnRvcw0KbGlicmFyeShkeWdyYXBocykgICMgcGFyYSBvcyBncmFmaWNvcyBkaW5hbWljb3MNCmxpYnJhcnkoZnBwMikgICAgICAjIHBhcmEgZmF6ZXIgbyBFVFMNCmxpYnJhcnkoTWV0cmljcykgICAjIHBhcmEgZmF6ZXIgYWN1csOhY2lhDQplbnYgPSBuZXcuZW52KCkNCiMgcGVnYW5kbyBjb3Rhw6fDtWVzIG1lbnNhaXMgZGEgcGV0cm9icmFzIGUgZG8gaWJvdmVzcGENCmdldFN5bWJvbHMoYygiUEVUUjQuU0EiLCJWQUxFMy5TQSIpLA0KICAgICAgICAgICBzcmM9InlhaG9vIiwgDQogICAgICAgICAgIGVudj1lbnYsDQogICAgICAgICAgIHBlcmlvZGljaXR5PSdtb250aGx5JywgDQogICAgICAgICAgIGZyb209JzIwMDAtMDEtMDEnLA0KICAgICAgICAgICB0bz0nMjAxOS0wOS0wMScNCikNCnZhbGUgPSBlbnYkVkFMRTMuU0FbLDZdDQpwZXRybyA9IGVudiRQRVRSNC5TQVssNl0NCg0KZzE8LWF1dG9wbG90KHZhbGUpKw0KICBnZW9tX2xpbmUoc2l6ZT0uOCwgY29sb3VyPSdkYXJrYmx1ZScpKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAnMTIgbW9udGhzJywNCiAgICAgICAgICAgICAgIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlYi8lWSIpKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgdmp1c3QgPSAxLjAsIGhqdXN0ID0gMS4wKSkrDQogIGxhYnModGl0bGU9J1ZBTEUzLlNBJywNCiAgICAgICBjYXB0aW9uPSdGb250ZTogRGFkb3MgZG8gWWFob28gRmluYW5jZS4nKSsNCiAgeGxhYignTcOqcy9Bbm8nKSt5bGFiKCdSJCcpDQoNCmcyPC1hdXRvcGxvdChwZXRybykrDQogIGdlb21fbGluZShzaXplPS44LCBjb2xvdXI9J2RhcmtibHVlJykrDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICcxMiBtb250aHMnLA0KICAgICAgICAgICAgICAgbGFiZWxzID0gZGF0ZV9mb3JtYXQoIiViLyVZIikpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCB2anVzdCA9IDEuMCwgaGp1c3QgPSAxLjApKSsNCiAgbGFicyh0aXRsZT0nUEVUUjQuU0EnLA0KICAgICAgIGNhcHRpb249J0ZvbnRlOiBEYWRvcyBkbyBZYWhvbyBGaW5hbmNlLicpKw0KICB4bGFiKCdNw6pzL0FubycpK3lsYWIoJ1IkJykNCiMgb3MgZG9pcyBncmFmaWNvcyBkZSBjb3RhY29lcyBqdW50b3MgIA0KZ3JpZC5hcnJhbmdlKGcxLCBnMiwgbnJvdyA9IDIpDQpgYGANCg0KIyMgQ2hlY2FuZG8gYSBwZXJpb2RpY2lkYWRlIGRvcyBkYWRvcw0KDQpgYGB7cn0NCiMgQ2hlY2FuZG8gYSBwZXJpb2RpY2lkYWRlIGRvcyBkYWRvcw0KIyAyMDAwLTAxLTAxIGF0w6kgMjAxOS0wOC0wMQ0KcGVyaW9kaWNpdHkocGV0cm8pDQpwZXJpb2RpY2l0eSh2YWxlKQ0KYGBgDQoNCiMjIFJldG9ybm9zIG1lbnNhaXMgUEVUUjQgZSBWQUxFMyBjb20gYmFzZSBubyBwcmXDp28gYWp1c3RhZG8NCg0KYGBge3J9DQpyX3BldHJvIDwtIG1vbnRobHlSZXR1cm4ocGV0cm8sdHlwZT0nbG9nJylbLTEsXQ0Kcl92YWxlIDwtIG1vbnRobHlSZXR1cm4odmFsZSx0eXBlPSJsb2ciKVstMSxdDQpgYGANCg0KYGBge3J9DQpnMzwtYXV0b3Bsb3Qocl9wZXRybykrDQogIGdlb21fbGluZShzaXplPS44LCBjb2xvdXI9J2RhcmtibHVlJykrDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICcxMiBtb250aHMnLA0KICAgICAgICAgICAgICAgbGFiZWxzID0gZGF0ZV9mb3JtYXQoIiViLyVZIikpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCB2anVzdCA9IDEuMCwgaGp1c3QgPSAxLjApKSsNCiAgbGFicyh0aXRsZT0nUmV0b3Jub3MgZGEgUEVUUjQuU0EnLA0KICAgICAgIGNhcHRpb249J0ZvbnRlOiBEYWRvcyBkbyBZYWhvbyBGaW5hbmNlLicpKw0KICB4bGFiKCdNw6pzL0FubycpK3lsYWIoJycpDQoNCmc0PC1hdXRvcGxvdChyX3ZhbGUpKw0KICBnZW9tX2xpbmUoc2l6ZT0uOCwgY29sb3VyPSdkYXJrYmx1ZScpKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAnMTIgbW9udGhzJywNCiAgICAgICAgICAgICAgIGxhYmVscyA9IGRhdGVfZm9ybWF0KCIlYi8lWSIpKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgdmp1c3QgPSAxLjAsIGhqdXN0ID0gMS4wKSkrDQogIGxhYnModGl0bGU9J1JldG9ybm9zIGRhIFZBTEUzLlNBJywNCiAgICAgICBjYXB0aW9uPSdGb250ZTogRGFkb3MgZG8gWWFob28gRmluYW5jZS4nKSsNCiAgeGxhYignTcOqcy9Bbm8nKSt5bGFiKCcnKQ0KIyBvcyBkb2lzIGdyYWZpY29zIGRlIGNvdGFjb2VzIGp1bnRvcyAgDQpncmlkLmFycmFuZ2UoZzMsIGc0LCBucm93ID0gMikNCmBgYA0KDQpGb3JlY2FzdA0KPT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyMgRGVsaW1pdGFuZG8gdHJlaW5vIHggdGVzdGUNCmBgYHtyfQ0KDQojIHRyYW5zZm9ybWFuZG8gZW0gdHMNCnJfcGV0cm88LXRzKHJfcGV0cm8sc3RhcnQ9YygyMDAwLDMpLGZyZXF1ZW5jeSA9IDEyKQ0Kcl92YWxlPC10cyhyX3ZhbGUsc3RhcnQ9YygyMDAwLDMpLGZyZXF1ZW5jeSA9IDEyKQ0KDQojIHRyZWlubyBhdMOpIHNldGVtYnJvIDIwMTUgKDE4OSBtZXNlcykNCnJfcGV0cm9fdHJlaW5vPC0gd2luZG93KHJfcGV0cm8sc3RhcnQ9YygyMDAwLDMpLGVuZD1jKDIwMTUsMTApKSANCnJfdmFsZV90cmVpbm88LSB3aW5kb3cocl92YWxlLHN0YXJ0PWMoMjAwMCwzKSxlbmQ9YygyMDE1LDEwKSkgDQojIHRlc3RlICg0NSBtZXNlcyBhcMOzcyBvdXR1YnJvIGRlIDIwMTkpDQpyX3BldHJvX3Rlc3RlPC13aW5kb3cocl9wZXRybywgc3RhcnQ9YygyMDE1LDExKSkgDQpyX3ZhbGVfdGVzdGU8LXdpbmRvdyhyX3ZhbGUsIHN0YXJ0PWMoMjAxNSwxMSkpIA0KYGBgDQoNClZhbW9zIGNoZWNhciBzZSBzZXBhcmFtb3MgY29ycmV0YW1lbnRlOg0KYGBge3J9DQphdXRvcGxvdChyX3BldHJvKSArDQogIGxhYnModGl0bGU9J1JldG9ybm9zIGRhIFBFVFI0LlNBJywNCiAgICAgICBjYXB0aW9uPSdGb250ZTogRGFkb3MgZG8gWWFob28gRmluYW5jZS4nKSsNCiAgYXV0b2xheWVyKHJfcGV0cm9fdHJlaW5vLCBzZXJpZXM9IlRyYWluaW5nIikgKw0KICBhdXRvbGF5ZXIocl9wZXRyb190ZXN0ZSwgc2VyaWVzPSJUZXN0IikNCmBgYA0KDQpgYGB7cn0NCmF1dG9wbG90KHJfdmFsZSkgKw0KICBsYWJzKHRpdGxlPSdSZXRvcm5vcyBkYSBWQUxFMy5TQScsDQogICAgICAgY2FwdGlvbj0nRm9udGU6IERhZG9zIGRvIFlhaG9vIEZpbmFuY2UuJykrDQogIGF1dG9sYXllcihyX3ZhbGVfdHJlaW5vLCBzZXJpZXM9IlRyYWluaW5nIikgKw0KICBhdXRvbGF5ZXIocl92YWxlX3Rlc3RlLCBzZXJpZXM9IlRlc3QiKQ0KYGBgDQoNCiMjIEhvbHQtV2ludGVycw0KDQpGYXJlaSBhIHByZXZpc8OjbyBwZWxvIG3DqXRvZG8gSG9sdC1XaW50ZXJzIGNvbmZvcm1lIEh5bmRtYW4gZSBBdGhhbmFzb3BvdWxvcyAoMjAxOCkuDQoNCmBgYHtyfQ0KIyBIb2x0LVdpbnRlcnMgcGV0cm8NCnBldHJvLmh3IDwtIGZvcmVjYXN0OjpodyhyX3BldHJvX3RyZWlubywgaD02MCxzZWFzb25hbD0iYWRkaXRpdmUiKSANCnN1bW1hcnkocGV0cm8uaHcpDQphdXRvcGxvdChyX3BldHJvKSArDQogIGZvcmVjYXN0OjphdXRvbGF5ZXIocGV0cm8uaHcsIHNlcmllcz0iSG9sdC1XaW50ZXJzIGFkaXQiLCBQST1GQUxTRSkgKw0KICB4bGFiKCJBbm8iKSArIHlsYWIoIlJldG9ybm8iKSArDQogIGdndGl0bGUoIkZvcmVjYXN0cyBwYXJhIFBFVFI0IikgKw0KICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZCh0aXRsZT0iRm9yZWNhc3QiKSkNCmBgYA0KDQpgYGB7cn0NCiMgSG9sdC1XaW50ZXJzIHZhbGUNCnZhbGUuaHcgPC0gZm9yZWNhc3Q6Omh3KHJfdmFsZV90cmVpbm8sIGg9NjAsc2Vhc29uYWw9ImFkZGl0aXZlIikgDQpzdW1tYXJ5KHZhbGUuaHcpDQphdXRvcGxvdChyX3ZhbGUpICsNCiAgZm9yZWNhc3Q6OmF1dG9sYXllcih2YWxlLmh3LCBzZXJpZXM9IkhvbHQtV2ludGVycyBhZGl0IiwgUEk9RkFMU0UpICsNCiAgeGxhYigiQW5vIikgKyB5bGFiKCJSZXRvcm5vIikgKw0KICBnZ3RpdGxlKCJGb3JlY2FzdHMgcGFyYSBWQUxFMyIpICsNCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQodGl0bGU9IkZvcmVjYXN0IikpDQpgYGANCg0KIyMjIEFjdXLDoWNpYQ0KDQpgYGB7cn0NCk1ldHJpY3M6OnNtYXBlKHJfcGV0cm9fdGVzdGUscGV0cm8uaHckbWVhbikNCk1ldHJpY3M6OnNtYXBlKHJfdmFsZV90ZXN0ZSx2YWxlLmh3JG1lYW4pDQoNCk1ldHJpY3M6Om1hcGUocl9wZXRyb190ZXN0ZSxwZXRyby5odyRtZWFuKQ0KTWV0cmljczo6bWFwZShyX3ZhbGVfdGVzdGUsdmFsZS5odyRtZWFuKQ0KYGBgDQoNCiMjIEVUUw0KDQpGYXJlaSBhIHByZXZpc8OjbyBwZWxvIG3DqXRvZG8gRVRTIChFcnJvciBUcmVuZCBTZWFzb25hbCkgY29uZm9ybWUgSHluZG1hbiBlIEF0aGFuYXNvcG91bG9zICgyMDE4KS4gICAgDQpgYGB7cn0NCiMgRVRTIChlcnJvciB0cmVuZCBzZWFzb25hbCkgZGUgSHluZG1hbiAtIHBhY290ZSBmcHAyDQpzZXQuc2VlZCgxMjMpDQpwZXRyby5ldHM8LWV0cyhyX3BldHJvX3RyZWlubywgbW9kZWwgPSAiWlpaIikgIyBOPW5vbmUsIEE9YWRkaXRpdmUsIE09bXVsdGlwbGljYXRpdmUgZSBaPWF1dG9tYXRpYw0Kc3VtbWFyeShwZXRyby5ldHMpDQpwZXRyby5ldHMuZm9yZWNhc3RzPC1mb3JlY2FzdC5ldHMocGV0cm8uZXRzLGg9MTIpDQpzdW1tYXJ5KHBldHJvLmV0cy5mb3JlY2FzdHMpDQpwbG90KHBldHJvLmV0cy5mb3JlY2FzdHMsY29sPTIpDQpgYGANCg0KYGBge3J9DQojIEVUUyAoZXJyb3IgdHJlbmQgc2Vhc29uYWwpIGRlIEh5bmRtYW4gLSBwYWNvdGUgZnBwMg0Kc2V0LnNlZWQoMTIzKQ0KdmFsZS5ldHM8LWV0cyhyX3ZhbGVfdHJlaW5vLCBtb2RlbCA9ICJaWloiKSAjIE49bm9uZSwgQT1hZGRpdGl2ZSwgTT1tdWx0aXBsaWNhdGl2ZSBlIFo9YXV0b21hdGljDQpzdW1tYXJ5KHZhbGUuZXRzKQ0KdmFsZS5ldHMuZm9yZWNhc3RzPC1mb3JlY2FzdC5ldHModmFsZS5ldHMsaD0xMikNCnN1bW1hcnkodmFsZS5ldHMuZm9yZWNhc3RzKQ0KcGxvdCh2YWxlLmV0cy5mb3JlY2FzdHMsY29sPTIpDQpgYGANCg0KIyMjIEFjdXLDoWNpYQ0KDQpgYGB7cn0NCk1ldHJpY3M6OnNtYXBlKHJfcGV0cm9fdGVzdGUscGV0cm8uZXRzLmZvcmVjYXN0cyRtZWFuKQ0KTWV0cmljczo6c21hcGUocl92YWxlX3Rlc3RlLHZhbGUuZXRzLmZvcmVjYXN0cyRtZWFuKQ0KDQpNZXRyaWNzOjptYXBlKHJfcGV0cm9fdGVzdGUscGV0cm8uZXRzLmZvcmVjYXN0cyRtZWFuKQ0KTWV0cmljczo6bWFwZShyX3ZhbGVfdGVzdGUsdmFsZS5ldHMuZm9yZWNhc3RzJG1lYW4pDQpgYGANCg0KUmVmZXLDqm5jaWFzIHstI1JlZmVyw6puY2lhc30NCj09PT09PT09PT09PT09PT09PT09PT09DQoNCkZJR1VFSVJFRE8sIEEuTS5SLiBUw7NwaWNvcyBkZSBlY29ub21ldHJpYTogYcOnw7Vlcy4gVUZNUzpDYW1wbyBHcmFuZGUsMjAxOS4gRGlzcG9uw612ZWwgZW06IDxodHRwOi8vcnB1YnMuY29tL2Ftcm9maS9hY29lc0JPVl9WQUxFMz4uICANCg0KSFlORE1BTiwgUm9iLiAoMjAxOCkuIGZwcDI6IERhdGEgZm9yICJGb3JlY2FzdGluZzogUHJpbmNpcGxlcyBhbmQgUHJhY3RpY2UiICgybmQgRWRpdGlvbikuIFIgcGFja2FnZSB2ZXJzaW9uIDIuMy4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWZwcDI+LiAgDQoNCkhZTkRNQU4sIFJvYiBKLjsgQVRIQU5BU09QT1VMT1MsIEdlb3JnZSAuIEZvcmVjYXN0aW5nOiBwcmluY2lwbGVzIGFuZCBwcmFjdGljZS4gT3RleHRzLCAyMDE4LiBTZWNvbmQgRWRpdGlvbi4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL3d3dy5vdGV4dHMub3JnL2ZwcDI+Lg0KDQo=