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.
Citação
Sugestão de citação: FIGUEIREDO, Adriano Marcos Rodrigues. Séries Temporais: Rotina rápida para lidar com missings no fabletools
. Campo Grande-MS,Brasil: RStudio/Rpubs, 2021. Disponível em <http://rpubs.com/amrofi/missings_fabletools>.
Introdução
Segue uma rotina rápida para lidar com os missings (observações ausentes), com o pacote fabletools
e tidyr
.
Hyndman e Athanasopoulos (2020) no FPP 3, seção 13.9, mencionam o fato de ser comum termos séries temporais com dados ausentes, por exemplo, devido aos finais de semana, ou por outro motivo qualquer (esquecimento, ausência de coleta de dados, impedimento de negociação em bolsa, etc.). O caso mais importante que cito é aquele em que a série apresenta “falhas” implícitas. Ou seja, imagine um caso de um fim de semana (sábado e domingo) sem dados. A série terá então falhas no calendário. Seja o caso do mês de maio de 2021, teremos falhas em todos os dias em vermelho (Figura 1).
Uma tabela com dados diários para os dias úteis seria algo como:
Observe que na Tabela 1, temos a data de 21/05/2021 vazia, e as demais estão preenchidas. O leitor poderia dizer que basta excluir a data de 21/05/2021 e não teremos mais nenhuma observação ausente (NA = not available = o nosso missing explícito). Mas temos missings implícitos, que não aparecem diretamente, que são os finais de semana (08, 09, 15, 16 de maio de 2021).
Então, aqui veremos como lidar com essas situações, pois o fable
terá algumas restrições quando houver dados ausentes (explícitos ou implícitos), por exemplo, no ETS()
e no STL()
, conforme Hyndman e Athanasopoulos (2020) no FPP 3, seção 13.9.
A sugestão para este post é trabalhar com objetos tsibble
, em consonância com Hyndman e Athanasopoulos (2020).
Dados para exemplo
Primeiro chamamos os dados. Eles estão embeded no code Rmd. Como gerei no Excel e a coluna estava já como formato de data, ao importar para o Excel (antes de eu gerar o dput
), o R já entendeu que era coluna de data e mudou daquele formato da Tabela 1 (dd/mm/aaaa) para o formato (aaaa-mm-dd).
dados <- structure(list(Data = c("03/05/2021", "04/05/2021", "05/05/2021", "06/05/2021",
"07/05/2021", "10/05/2021", "11/05/2021", "12/05/2021", "13/05/2021", "14/05/2021",
"17/05/2021", "18/05/2021", "19/05/2021", "20/05/2021", "21/05/2021"), X = c(264,
281, 287, 284, 278, 281, 293, 292, 289, 294, 295, 293, 290, 288, NA)), row.names = c(NA,
-15L), class = c("tbl_df", "tbl", "data.frame"))
class(dados$Data)
[1] "character"
Veja que ele vem em data.frame. Então vamos gerar o tsibble
.
Peço vossa atenção para o fato de que a coluna data nem sempre está em formato de data do R. NO chunk acima está como data.frame.
Caso você tenha uma coluna Data em formato de caracter (testar fazendo class(dados$Data)
) então, antes de criar o tsibble
, criar uma coluna date para facilitar a indexação conforme chunk abaixo.
dados$date <- as.Date(dados$Data, format = "%d/%m/%Y")
print(dados)
Data X date
1 03/05/2021 264 2021-05-03
2 04/05/2021 281 2021-05-04
3 05/05/2021 287 2021-05-05
4 06/05/2021 284 2021-05-06
5 07/05/2021 278 2021-05-07
6 10/05/2021 281 2021-05-10
7 11/05/2021 293 2021-05-11
8 12/05/2021 292 2021-05-12
9 13/05/2021 289 2021-05-13
10 14/05/2021 294 2021-05-14
11 17/05/2021 295 2021-05-17
12 18/05/2021 293 2021-05-18
13 19/05/2021 290 2021-05-19
14 20/05/2021 288 2021-05-20
15 21/05/2021 NA 2021-05-21
Agora, além da coluna da data inicial (Data), temos a coluna (date).
Então criaremos o tsibble
no próximo chunk. Chamaremos o pacote fable
para executar a função as_tsibble()
e colocaremos a coluna date (pode ser a Data desde que esteja como na structure do nosso primeiro chunk.
library(fable)
dados.tsb <- as_tsibble(dados[, c(3, 2)], index = date, regular = T)
class(dados.tsb) # 'tbl_ts' 'tbl_df' 'tbl' 'data.frame'
[1] "tbl_ts" "tbl_df" "tbl" "data.frame"
fabletools::autoplot(dados.tsb, X)

O leitor atento à mensagens de erro verá que aparece a mensagem Removed 1 row(s) containing missing values (geom_path).
Ou seja, ele removeu automaticamente a linha do dia 2021-05-21, onde aparecia o NA
na coluna de X
. O objeto tsibble
de nome dados.tsb
foi criado. Neste exemplo, já exclui a coluna Data
para não gerar confusão, e o index
do tsibble
é a coluna date
.
O pacote já entendeu que a série é diária e uniu os pontos. Mas continuamos com as falhas dos finais de semana.
Portanto agora mostrarei duas formas de preencher os dados e recomendo ao leitor que consulte as opções do exemplo do manual do tsibble
: Exemplos do fill_gaps no tsibble , onde existem opções para preencher com NAs, interpolar, preencher com zeros, preencher com a média, preencher com o último valor etc. As duas opções aqui desenvolvidas são: com NAs explícitos, e a de preencher com o último valor disponível.
Referências
HYNDMAN, Rob J. (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. Accessed on 20 May 2021.
HYNDMAN, Rob J. (2019). fpp3: Data for “Forecasting: Principles and Practice” (3rd Edition). R package. Disponível em: https://github.com/robjhyndman/fpp3-package, https://OTexts.org/fpp3/. Accessed on 20 May 2021.
HYNDMAN, R.J.; ATHANASOPOULOS, G. (2020) Forecasting: principles and practice, 3rd edition, OTexts: Melbourne, Australia. Disponível em: https://otexts.com/fpp3/. Accessed on 20 May 2021.
O’HARA-WILD, Mitchell; HYNDMAN, Rob J.; WANG, Earo. (2021). feasts: Feature Extraction and Statistics for Time Series. R package version 0.2.1. Disponível em: https://CRAN.R-project.org/package=feasts. Accessed on 20 May 2021.
LS0tDQp0aXRsZTogIlPDqXJpZXMgVGVtcG9yYWlzOiBSb3RpbmEgcsOhcGlkYSBwYXJhIGxpZGFyIGNvbSBtaXNzaW5ncyBubyBmYWJsZXRvb2xzIg0KYXV0aG9yOiAiQWRyaWFubyBNYXJjb3MgUm9kcmlndWVzIEZpZ3VlaXJlZG8sICplLW1haWw6IGFkcmlhbm8uZmlndWVpcmVkb0B1Zm1zLmJyKiINCmxpbmtjb2xvcjogYmx1ZQ0KYWJzdHJhY3Q6IA0KICBUaGlzIGlzIGFuIHVuZGVyZ3JhZCBzdHVkZW50IGxldmVsIGluc3RydWN0aW9uIGZvciBjbGFzcyB1c2UuICANCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogZGVmYXVsdA0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiBubw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGZpZ19jYXB0aW9uOiB0cnVlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIGtuaXRyX2luaXQsIGVjaG89RkFMU0UsIGNhY2hlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocm1hcmtkb3duKQ0KbGlicmFyeShybWRmb3JtYXRzKQ0KDQojIyBHbG9iYWwgb3B0aW9ucw0Kb3B0aW9ucyhtYXgucHJpbnQ9IjEwMCIpDQpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsDQoJICAgICAgICAgICAgIGNhY2hlPUYsDQogICAgICAgICAgICAgICBwcm9tcHQ9RkFMU0UsDQogICAgICAgICAgICAgICB0aWR5PVRSVUUsDQogICAgICAgICAgICAgICBjb21tZW50PU5BLA0KICAgICAgICAgICAgICAgbWVzc2FnZT1GQUxTRSwNCiAgICAgICAgICAgICAgIHdhcm5pbmc9RkFMU0UpDQpvcHRzX2tuaXQkc2V0KHdpZHRoPTEwMCkNCmBgYA0KDQojIExpY2Vuw6dhIHsjTGljZW7Dp2EgLnVubnVtYmVyZWR9DQoNClRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIFRvIHZpZXcgYSBjb3B5IG9mIHRoaXMgbGljZW5zZSwgdmlzaXQgPGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8+IG9yIHNlbmQgYSBsZXR0ZXIgdG8gQ3JlYXRpdmUgQ29tbW9ucywgUE8gQm94IDE4NjYsIE1vdW50YWluIFZpZXcsIENBIDk0MDQyLCBVU0EuDQoNCiFbTGljZW5zZTogQ0MgQlktU0EgNC4wXShodHRwczovL21pcnJvcnMuY3JlYXRpdmVjb21tb25zLm9yZy9wcmVzc2tpdC9idXR0b25zLzg4eDMxL3BuZy9ieS1zYS5wbmcpe3dpZHRoPSIyNSUifQ0KDQojIENpdGHDp8OjbyB7I0NpdGHDp8OjbyAudW5udW1iZXJlZH0NCg0KU3VnZXN0w6NvIGRlIGNpdGHDp8OjbzogRklHVUVJUkVETywgQWRyaWFubyBNYXJjb3MgUm9kcmlndWVzLiBTw6lyaWVzIFRlbXBvcmFpczogUm90aW5hIHLDoXBpZGEgcGFyYSBsaWRhciBjb20gbWlzc2luZ3Mgbm8gYGZhYmxldG9vbHNgLiBDYW1wbyBHcmFuZGUtTVMsQnJhc2lsOiBSU3R1ZGlvL1JwdWJzLCAyMDIxLiBEaXNwb27DrXZlbCBlbSBbXDxodHRwOi8vcnB1YnMuY29tL2Ftcm9maS9taXNzaW5nc19mYWJsZXRvb2xzXD5dKGh0dHA6Ly9ycHVicy5jb20vYW1yb2ZpL21pc3NpbmdzX2ZhYmxldG9vbHMpey51cml9Lg0KDQojIEludHJvZHXDp8Ojbw0KDQpTZWd1ZSB1bWEgcm90aW5hIHLDoXBpZGEgcGFyYSBsaWRhciBjb20gb3MgbWlzc2luZ3MgKG9ic2VydmHDp8O1ZXMgYXVzZW50ZXMpLCBjb20gbyBwYWNvdGUgYGZhYmxldG9vbHNgIGUgYHRpZHlyYC5cDQpIeW5kbWFuIGUgQXRoYW5hc29wb3Vsb3MgKDIwMjApIG5vIFtGUFAgMywgc2XDp8OjbyAxMy45XShodHRwczovL290ZXh0cy5jb20vZnBwMy9taXNzaW5nLW91dGxpZXJzLmh0bWwgIkZQUCAzLCBzZcOnw6NvIDEzLjkiKSwgbWVuY2lvbmFtIG8gZmF0byBkZSBzZXIgY29tdW0gdGVybW9zIHPDqXJpZXMgdGVtcG9yYWlzIGNvbSBkYWRvcyBhdXNlbnRlcywgcG9yIGV4ZW1wbG8sIGRldmlkbyBhb3MgZmluYWlzIGRlIHNlbWFuYSwgb3UgcG9yIG91dHJvIG1vdGl2byBxdWFscXVlciAoZXNxdWVjaW1lbnRvLCBhdXPDqm5jaWEgZGUgY29sZXRhIGRlIGRhZG9zLCBpbXBlZGltZW50byBkZSBuZWdvY2lhw6fDo28gZW0gYm9sc2EsIGV0Yy4pLiBPIGNhc28gbWFpcyBpbXBvcnRhbnRlIHF1ZSBjaXRvIMOpIGFxdWVsZSBlbSBxdWUgYSBzw6lyaWUgYXByZXNlbnRhICJmYWxoYXMiIGltcGzDrWNpdGFzLiBPdSBzZWphLCBpbWFnaW5lIHVtIGNhc28gZGUgdW0gZmltIGRlIHNlbWFuYSAoc8OhYmFkbyBlIGRvbWluZ28pIHNlbSBkYWRvcy4gQSBzw6lyaWUgdGVyw6EgZW50w6NvIGZhbGhhcyBubyBjYWxlbmTDoXJpby4gU2VqYSBvIGNhc28gZG8gbcOqcyBkZSBtYWlvIGRlIDIwMjEsIHRlcmVtb3MgZmFsaGFzIGVtIHRvZG9zIG9zIGRpYXMgZW0gdmVybWVsaG8gKEZpZ3VyYSAxKS4NCg0KIVtGaWd1cmEgMS4gTWFpbyBkZSAyMDIxXShJbWFnZW0xLnBuZyAiRmlndXJhIDEuIE1haW8gZGUgMjAyMSIpDQoNClVtYSB0YWJlbGEgY29tIGRhZG9zIGRpw6FyaW9zIHBhcmEgb3MgZGlhcyDDunRlaXMgc2VyaWEgYWxnbyBjb21vOg0KDQohW1RhYmVsYSAxLiBEYWRvcyBhbGVhdMOzcmlvcy5dKEltYWdlbTIucG5nICJUYWJlbGEgMS4gRGFkb3MgYWxlYXTDs3Jpb3MuIikNCg0KT2JzZXJ2ZSBxdWUgbmEgVGFiZWxhIDEsIHRlbW9zIGEgZGF0YSBkZSAyMS8wNS8yMDIxIHZhemlhLCBlIGFzIGRlbWFpcyBlc3TDo28gcHJlZW5jaGlkYXMuIE8gbGVpdG9yIHBvZGVyaWEgZGl6ZXIgcXVlIGJhc3RhIGV4Y2x1aXIgYSBkYXRhIGRlIDIxLzA1LzIwMjEgZSBuw6NvIHRlcmVtb3MgbWFpcyBuZW5odW1hIG9ic2VydmHDp8OjbyBhdXNlbnRlIChOQSA9ICpub3QgYXZhaWxhYmxlID0qIG8gbm9zc28gbWlzc2luZyBleHBsw61jaXRvKS4gTWFzIHRlbW9zIG1pc3NpbmdzIGltcGzDrWNpdG9zLCBxdWUgbsOjbyBhcGFyZWNlbSBkaXJldGFtZW50ZSwgcXVlIHPDo28gb3MgZmluYWlzIGRlIHNlbWFuYSAoMDgsIDA5LCAxNSwgMTYgZGUgbWFpbyBkZSAyMDIxKS4NCg0KRW50w6NvLCBhcXVpIHZlcmVtb3MgY29tbyBsaWRhciBjb20gZXNzYXMgc2l0dWHDp8O1ZXMsIHBvaXMgbyBgZmFibGVgIHRlcsOhIGFsZ3VtYXMgcmVzdHJpw6fDtWVzIHF1YW5kbyBob3V2ZXIgZGFkb3MgYXVzZW50ZXMgKGV4cGzDrWNpdG9zIG91IGltcGzDrWNpdG9zKSwgcG9yIGV4ZW1wbG8sIG5vIGBFVFMoKWAgZSBubyBgU1RMKClgLCBjb25mb3JtZSBIeW5kbWFuIGUgQXRoYW5hc29wb3Vsb3MgKDIwMjApIG5vIFtGUFAgMywgc2XDp8OjbyAxMy45XShodHRwczovL290ZXh0cy5jb20vZnBwMy9taXNzaW5nLW91dGxpZXJzLmh0bWwgIkZQUCAzLCBzZcOnw6NvIDEzLjkiKS4NCg0KQSBzdWdlc3TDo28gcGFyYSBlc3RlIHBvc3Qgw6kgdHJhYmFsaGFyIGNvbSBvYmpldG9zIGB0c2liYmxlYCwgZW0gY29uc29uw6JuY2lhIGNvbSBIeW5kbWFuIGUgQXRoYW5hc29wb3Vsb3MgKDIwMjApLg0KDQojIERhZG9zIHBhcmEgZXhlbXBsbw0KDQpQcmltZWlybyBjaGFtYW1vcyBvcyBkYWRvcy4gRWxlcyBlc3TDo28gZW1iZWRlZCBubyBjb2RlIFJtZC4gQ29tbyBnZXJlaSBubyBFeGNlbCBlIGEgY29sdW5hIGVzdGF2YSBqw6EgY29tbyBmb3JtYXRvIGRlIGRhdGEsIGFvIGltcG9ydGFyIHBhcmEgbyBFeGNlbCAoYW50ZXMgZGUgZXUgZ2VyYXIgbyBgZHB1dGApLCBvIFIgasOhIGVudGVuZGV1IHF1ZSBlcmEgY29sdW5hIGRlIGRhdGEgZSBtdWRvdSBkYXF1ZWxlIGZvcm1hdG8gZGEgVGFiZWxhIDEgKGRkL21tL2FhYWEpIHBhcmEgbyBmb3JtYXRvIChhYWFhLW1tLWRkKS4NCg0KYGBge3IgZGFkb3N9DQpkYWRvczwtIHN0cnVjdHVyZShsaXN0KERhdGEgPSBjKCIwMy8wNS8yMDIxIiwgIjA0LzA1LzIwMjEiLCAiMDUvMDUvMjAyMSIsIA0KIjA2LzA1LzIwMjEiLCAiMDcvMDUvMjAyMSIsICIxMC8wNS8yMDIxIiwgIjExLzA1LzIwMjEiLCAiMTIvMDUvMjAyMSIsIA0KIjEzLzA1LzIwMjEiLCAiMTQvMDUvMjAyMSIsICIxNy8wNS8yMDIxIiwgIjE4LzA1LzIwMjEiLCAiMTkvMDUvMjAyMSIsIA0KIjIwLzA1LzIwMjEiLCAiMjEvMDUvMjAyMSIpLCBYID0gYygyNjQsIDI4MSwgMjg3LCAyODQsIDI3OCwgMjgxLCANCjI5MywgMjkyLCAyODksIDI5NCwgMjk1LCAyOTMsIDI5MCwgMjg4LCBOQSkpLCByb3cubmFtZXMgPSBjKE5BLCANCi0xNUwpLCBjbGFzcyA9IGMoInRibF9kZiIsICJ0YmwiLCAiZGF0YS5mcmFtZSIpKQ0KY2xhc3MoZGFkb3MkRGF0YSkNCmBgYA0KDQpWZWphIHF1ZSBlbGUgdmVtIGVtIGRhdGEuZnJhbWUuIEVudMOjbyB2YW1vcyBnZXJhciBvIGB0c2liYmxlYC4NCg0KUGXDp28gdm9zc2EgYXRlbsOnw6NvIHBhcmEgbyBmYXRvIGRlIHF1ZSBhIGNvbHVuYSBkYXRhIG5lbSBzZW1wcmUgZXN0w6EgZW0gZm9ybWF0byBkZSBkYXRhIGRvIFIuIE5PIGNodW5rIGFjaW1hIGVzdMOhIGNvbW8gZGF0YS5mcmFtZS4NCg0KQ2FzbyB2b2PDqiB0ZW5oYSB1bWEgY29sdW5hIERhdGEgZW0gZm9ybWF0byBkZSBjYXJhY3RlciAodGVzdGFyIGZhemVuZG8gYGNsYXNzKGRhZG9zJERhdGEpYCkgZW50w6NvLCBhbnRlcyBkZSBjcmlhciBvIGB0c2liYmxlYCwgY3JpYXIgdW1hIGNvbHVuYSBkYXRlIHBhcmEgZmFjaWxpdGFyIGEgaW5kZXhhw6fDo28gY29uZm9ybWUgY2h1bmsgYWJhaXhvLg0KDQpgYGB7ciBjb2x1bmFkYXRlLCBldmFsPVR9DQpkYWRvcyRkYXRlIDwtIGFzLkRhdGUoZGFkb3MkRGF0YSwgZm9ybWF0ID0gIiVkLyVtLyVZIikNCnByaW50KGRhZG9zKQ0KYGBgDQoNCkFnb3JhLCBhbMOpbSBkYSBjb2x1bmEgZGEgZGF0YSBpbmljaWFsIChEYXRhKSwgdGVtb3MgYSBjb2x1bmEgKGRhdGUpLg0KDQpFbnTDo28gY3JpYXJlbW9zIG8gYHRzaWJibGVgIG5vIHByw7N4aW1vIGNodW5rLiBDaGFtYXJlbW9zIG8gcGFjb3RlIGBmYWJsZWAgcGFyYSBleGVjdXRhciBhIGZ1bsOnw6NvIGBhc190c2liYmxlKClgIGUgY29sb2NhcmVtb3MgYSBjb2x1bmEgZGF0ZSAocG9kZSBzZXIgYSBEYXRhIGRlc2RlIHF1ZSBlc3RlamEgY29tbyBuYSBzdHJ1Y3R1cmUgZG8gbm9zc28gcHJpbWVpcm8gY2h1bmsuDQoNCmBgYHtyIHRzaWJibGV9DQpsaWJyYXJ5KGZhYmxlKQ0KZGFkb3MudHNiPC1hc190c2liYmxlKGRhZG9zWyxjKDMsMildLGluZGV4ID0gZGF0ZSxyZWd1bGFyID0gVCkNCmNsYXNzKGRhZG9zLnRzYikgICAjICJ0YmxfdHMiICAgICAidGJsX2RmIiAgICAgInRibCIgICAgICAgICJkYXRhLmZyYW1lIg0KZmFibGV0b29sczo6YXV0b3Bsb3QoZGFkb3MudHNiLFgpDQpgYGANCg0KTyBsZWl0b3IgYXRlbnRvIMOgIG1lbnNhZ2VucyBkZSBlcnJvIHZlcsOhIHF1ZSBhcGFyZWNlIGEgbWVuc2FnZW0gYFJlbW92ZWQgMSByb3cocykgY29udGFpbmluZyBtaXNzaW5nIHZhbHVlcyAoZ2VvbV9wYXRoKS5gIE91IHNlamEsIGVsZSByZW1vdmV1IGF1dG9tYXRpY2FtZW50ZSBhIGxpbmhhIGRvIGRpYSAyMDIxLTA1LTIxLCBvbmRlIGFwYXJlY2lhIG8gYE5BYCBuYSBjb2x1bmEgZGUgYFhgLiBPIG9iamV0byBgdHNpYmJsZWAgZGUgbm9tZSBgZGFkb3MudHNiYCBmb2kgY3JpYWRvLiBOZXN0ZSBleGVtcGxvLCBqw6EgZXhjbHVpIGEgY29sdW5hIGBEYXRhYCBwYXJhIG7Do28gZ2VyYXIgY29uZnVzw6NvLCBlIG8gYGluZGV4YCBkbyBgdHNpYmJsZWAgw6kgYSBjb2x1bmEgYGRhdGVgLg0KDQpPIHBhY290ZSBqw6EgZW50ZW5kZXUgcXVlIGEgc8OpcmllIMOpIGRpw6FyaWEgZSB1bml1IG9zIHBvbnRvcy4gTWFzIGNvbnRpbnVhbW9zIGNvbSBhcyBmYWxoYXMgZG9zIGZpbmFpcyBkZSBzZW1hbmEuDQoNClBvcnRhbnRvIGFnb3JhIG1vc3RyYXJlaSBkdWFzIGZvcm1hcyBkZSBwcmVlbmNoZXIgb3MgZGFkb3MgZSByZWNvbWVuZG8gYW8gbGVpdG9yIHF1ZSBjb25zdWx0ZSBhcyBvcMOnw7VlcyBkbyBleGVtcGxvIGRvIG1hbnVhbCBkbyBgdHNpYmJsZWAgOiBbRXhlbXBsb3MgZG8gZmlsbF9nYXBzIG5vIHRzaWJibGVdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy90c2liYmxlL3ZlcnNpb25zLzEuMC4xL3RvcGljcy9maWxsX2dhcHMgIkV4ZW1wbG9zIGRvIGZpbGxfZ2FwcyBubyB0c2liYmxlIikgLCBvbmRlIGV4aXN0ZW0gb3DDp8O1ZXMgcGFyYSBwcmVlbmNoZXIgY29tIE5BcywgaW50ZXJwb2xhciwgcHJlZW5jaGVyIGNvbSB6ZXJvcywgcHJlZW5jaGVyIGNvbSBhIG3DqWRpYSwgcHJlZW5jaGVyIGNvbSBvIMO6bHRpbW8gdmFsb3IgZXRjLiBBcyBkdWFzIG9ww6fDtWVzIGFxdWkgZGVzZW52b2x2aWRhcyBzw6NvOiBjb20gTkFzIGV4cGzDrWNpdG9zLCBlIGEgZGUgcHJlZW5jaGVyIGNvbSBvIMO6bHRpbW8gdmFsb3IgZGlzcG9uw612ZWwuDQoNCiMgT3DDp8OjbyAxOiBwcmVlbmNoZXIgY29tIE5Bcw0KDQpOZXN0ZSBjYXNvLCBvIGB0c2liYmxlYCBlbnRlbmRlcsOhIGFzIGRhdGFzIHF1ZSBmYWx0YW0sIGNyaWFyw6EgZXN0YXMgbm92YXMgbGluaGFzIGUgcHJlZW5jaGVyw6EgY29tIG8gc8OtbWJvbG8gZGUgbWlzc2luZyBwYWRyw6NvOiBgTkFgLiBFbmNvcmFqbyBvIGxlaXRvciBhIG9ic2VydmFyIGEgdGFiZWxhIGRvIGBwcmludGAsIGUgY29tcGFyYXIgY29tIGEgdGFiZWxhIDEsIGUgdmVyw6EgcXVlIGFnb3JhIGEgbm92YSBzYcOtZGEgKGBkYWRvcy5mdWxsYCkgdGVtIGFzIGRhdGFzIGluY2x1c2l2ZSBwYXJhIG9zIGZpbmFpcyBkZSBzZW1hbmEgKHPDoWJhZG8gZSBkb21pbmdvKS4NCg0KYGBge3J9DQpkYWRvcy5mdWxsPC10c2liYmxlOjpmaWxsX2dhcHMoZGFkb3MudHNiKQ0Kb3B0aW9ucyhtYXgucHJpbnQgPSAxMDApDQpwcmludChkYWRvcy5mdWxsKQ0KYGBgDQoNCiMgT3DDp8OjbyAyOiBwcmVlbmNoZXIgY29tIMO6bHRpbW8gdmFsb3INCg0KTmVzdGUgY2FzbywgbyBgdHNpYmJsZWAgZW50ZW5kZXLDoSBhcyBkYXRhcyBxdWUgZmFsdGFtLCBjcmlhcsOhIGVzdGFzIG5vdmFzIGxpbmhhcyBlIHByZWVuY2hlcsOhIGNvbSBvIMO6bHRpbW8gdmFsb3IgZGEgc8OpcmllIGBYYCwgcHJlZW5jaGVuZG8gcGFyYSBiYWl4byAoYC5kaXJlY3Rpb24gPSAiZG93biJgKSBjb20gdXNvIGRhIGZ1bsOnw6NvIGBmaWxsYCBkbyBwYWNvdGUgYHRpZHlyYC4gRW5jb3Jham8gbyBsZWl0b3IgYSBvYnNlcnZhciBhIHRhYmVsYSBkbyBgcHJpbnRgLCBlIGNvbXBhcmFyIGNvbSBhIHRhYmVsYSAxLCBlIHZlcsOhIHF1ZSBhZ29yYSBhIG5vdmEgc2HDrWRhIChgZGFkb3MuZnVsbDJgKSB0ZW0gYXMgZGF0YXMgaW5jbHVzaXZlIHBhcmEgb3MgZmluYWlzIGRlIHNlbWFuYSAoc8OhYmFkbyBlIGRvbWluZ28pIGUgbsOjbyBjb25zdGFtIE5Bcy4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHlyKQ0KZGFkb3MuZnVsbDI8LWRhZG9zLnRzYiAlPiUgDQogIHRzaWJibGU6OmZpbGxfZ2FwcygpICU+JQ0KICB0aWR5cjo6ZmlsbChYLCAuZGlyZWN0aW9uID0gImRvd24iKQ0KcHJpbnQoZGFkb3MuZnVsbDIpDQpgYGANCg0KRGVzdGUgbW9kbywgbyBsZWl0b3IgcG9kZSB2ZXJpZmljYXIgcXVlIG9zIHZhbG9yZXMgZGUgMDggZSAwOSBkZSBtYWlvIGRlIDIwMjEgZm9yYW0gcHJlZW5jaGlkb3MgY29tIG8gbWVzbW8gdmFsb3IgZGUgMDcgZGUgbWFpbyBkZSAyMDIxLiBEbyBtZXNtbyBtb2RvLCBwYXJhIDE1IGUgMTYgZGUgbWFpbywgdGVyZW1vcyBvcyB2YWxvcmVzIGRlIDE0IGRlIG1haW8gcmVwZXRpZG9zLiBPIG1lc21vIHNlcsOhIGZlaXRvIHBhcmEgcHJlZW5jaGVyIG8gZGlhIDIxLg0KDQpPIGdyw6FmaWNvIHNlcsOhIGFnb3JhOg0KDQpgYGB7cn0NCmZhYmxldG9vbHM6OmF1dG9wbG90KGRhZG9zLmZ1bGwyLFgpDQpgYGANCg0KTyBsZWl0b3IgcG9kZSB0ZXN0YXIgYWdvcmEgYXMgZmVycmFtZW50YXMgZGUgZm9yZWNhc3QgZG8gZmFibGUgZSBmYWJsZXRvb2xzLg0KDQpgYGB7cn0NCmxpYnJhcnkoZnBwMykNCmZpdCA8LSBkYWRvcy5mdWxsMiAlPiUgbW9kZWwoDQogICAgICAgICAgICAgICAgICAgYXJpbWEgPSBBUklNQShYKSwNCiAgICAgICAgICAgICAgICAgICBldHMgPSBFVFMoWCkNCiAgICAgICAgICAgICAgICAgICkNCmZpdF9mYyA8LSBmaXQgJT4lDQogIGZvcmVjYXN0KGggPSAxMCkNCmZpdF9mYyAlPiUNCiAgYXV0b3Bsb3QoZGFkb3MudHNiLA0KICAgICAgICAgICBsZXZlbCA9IE5VTEwpICsNCiAgbGFicyh5ID0gInZhbG9yIGRlIFgiLA0KICAgICAgIHRpdGxlID0gIkV4ZW1wbG8gZ2Vuw6lyaWNvIGRlIGZvcmVjYXN0IGFww7NzIGZpbGxfZ2FwcyIpDQpgYGANCg0KIyBSZWZlcsOqbmNpYXMgeyNSZWZlcsOqbmNpYXMgLnVubnVtYmVyZWR9DQoNCkhZTkRNQU4sIFJvYiBKLiAoMjAxOCkuIGZwcDI6IERhdGEgZm9yICJGb3JlY2FzdGluZzogUHJpbmNpcGxlcyBhbmQgUHJhY3RpY2UiICgybmQgRWRpdGlvbikuIFIgcGFja2FnZSB2ZXJzaW9uIDIuMy4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWZwcDI+LiBBY2Nlc3NlZCBvbiAyMCBNYXkgMjAyMS4NCg0KSFlORE1BTiwgUm9iIEouICgyMDE5KS4gZnBwMzogRGF0YSBmb3IgIkZvcmVjYXN0aW5nOiBQcmluY2lwbGVzIGFuZCBQcmFjdGljZSIgKDNyZCBFZGl0aW9uKS4gUiBwYWNrYWdlLiBEaXNwb27DrXZlbCBlbTogPGh0dHBzOi8vZ2l0aHViLmNvbS9yb2JqaHluZG1hbi9mcHAzLXBhY2thZ2U+LCA8aHR0cHM6Ly9PVGV4dHMub3JnL2ZwcDMvPi4gQWNjZXNzZWQgb24gMjAgTWF5IDIwMjEuDQoNCkhZTkRNQU4sIFIuSi47IEFUSEFOQVNPUE9VTE9TLCBHLiAoMjAyMCkgRm9yZWNhc3Rpbmc6IHByaW5jaXBsZXMgYW5kIHByYWN0aWNlLCAzcmQgZWRpdGlvbiwgT1RleHRzOiBNZWxib3VybmUsIEF1c3RyYWxpYS4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL290ZXh0cy5jb20vZnBwMy8+LiBBY2Nlc3NlZCBvbiAyMCBNYXkgMjAyMS4NCg0KTydIQVJBLVdJTEQsIE1pdGNoZWxsOyBIWU5ETUFOLCBSb2IgSi47IFdBTkcsIEVhcm8uICgyMDIxKS4gZmVhc3RzOiBGZWF0dXJlIEV4dHJhY3Rpb24gYW5kIFN0YXRpc3RpY3MgZm9yIFRpbWUgU2VyaWVzLiBSIHBhY2thZ2UgdmVyc2lvbiAwLjIuMS4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL0NSQU4uUi1wcm9qZWN0Lm9yZy9wYWNrYWdlPWZlYXN0cz4uIEFjY2Vzc2VkIG9uIDIwIE1heSAyMDIxLg0K