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. Exemplo Séries Temporais: consumo Morettin e Toloi: hierárquico - formatos ts. Campo Grande-MS, Brasil: RStudio/Rpubs, 2023. Disponível em https://rpubs.com/amrofi/morettin_toloi_hierarquico.

1 Introdução

Os dados vem do livro de Morettin e Toloi, Análise de Séries Temporais (https://www.ime.usp.br/~pam/ST.html), consumo no varejo de São Paulo, mensais de Jan/1984 a Out/1996, em https://www.ime.usp.br/~pam/CONSUMO.XLS.

Inicialmente, trabalharemos com o formato ts, conforme o livro de Hyndman (2018), segunda edição. O artigo segue a rotina de Hyndman (2016).

2 Dados em formato ts

# vou puxar os libraries que tenho costume de usar: destaque para o readxl e
# tseries
library(readxl)  # puxar Excel
library(fpp2)  # livro Hyndman formato ts - já carrega ggplot2 e forecast
# codigo para puxar do Excel dados <- read_excel('CONSUMO morettin R.xlsx',
# sheet = 'dados')
dados <- structure(list(obs = structure(c(441763200, 444441600, 446947200, 449625600,
    452217600, 454896000, 457488000, 460166400, 462844800, 465436800, 468115200,
    470707200, 473385600, 476064000, 478483200, 481161600, 483753600, 486432000,
    489024000, 491702400, 494380800, 496972800, 499651200, 502243200, 504921600,
    507600000, 510019200, 512697600, 515289600, 517968000, 520560000, 523238400,
    525916800, 528508800, 531187200, 533779200, 536457600, 539136000, 541555200,
    544233600, 546825600, 549504000, 552096000, 554774400, 557452800, 560044800,
    562723200, 565315200, 567993600, 570672000, 573177600, 575856000, 578448000,
    581126400, 583718400, 586396800, 589075200, 591667200, 594345600, 596937600,
    599616000, 602294400, 604713600, 607392000, 609984000, 612662400, 615254400,
    617932800, 620611200, 623203200, 625881600, 628473600, 631152000, 633830400,
    636249600, 638928000, 641520000, 644198400, 646790400, 649468800, 652147200,
    654739200, 657417600, 660009600, 662688000, 665366400, 667785600, 670464000,
    673056000, 675734400, 678326400, 681004800, 683683200, 686275200, 688953600,
    691545600, 694224000, 696902400, 699408000, 702086400, 704678400, 707356800,
    709948800, 712627200, 715305600, 717897600, 720576000, 723168000, 725846400,
    728524800, 730944000, 733622400, 736214400, 738892800, 741484800, 744163200,
    746841600, 749433600, 752112000, 754704000, 757382400, 760060800, 762480000,
    765158400, 767750400, 770428800, 773020800, 775699200, 778377600, 780969600,
    783648000, 786240000, 788918400, 791596800, 794016000, 796694400, 799286400,
    801964800, 804556800, 807235200, 809913600, 812505600, 815184000, 817776000,
    820454400, 823132800, 825638400, 828316800, 830908800, 833587200, 836179200,
    838857600, 841536000, 844128000), class = c("POSIXct", "POSIXt"), tzone = "UTC"),
    t = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
        21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
        40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
        59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
        78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
        97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
        113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
        128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
        143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154), consumo = c(114.13,
        110.79, 116.46, 111.57, 120.66, 121.15, 121.27, 127.02, 129.04, 133.3, 130.6,
        179.39, 120.64, 114.05, 130.6, 118.26, 145.54, 135.13, 153.35, 159.95, 150.01,
        164.93, 170.37, 220.96, 134.26, 133.11, 147.84, 164.46, 181.86, 170.44, 186.64,
        174.21, 181.62, 194.16, 181.9, 232.01, 140.16, 130.78, 119.04, 120.73, 129.81,
        111.04, 122.75, 133.95, 125.41, 132.05, 129.54, 176.37, 110.09, 113.25, 124.03,
        110.63, 116.72, 124.63, 124.38, 130.27, 119.87, 115.75, 122.44, 162.43, 105.89,
        115.59, 147, 131.7, 131.32, 136.66, 126.43, 134.88, 128.26, 125.32, 124.61,
        166.11, 116.25, 96.93, 89.27, 101.87, 125.57, 113.31, 109.39, 127.33, 120.56,
        117.73, 113.81, 147.25, 100.15, 95.11, 112.26, 109.39, 114.2, 113.8, 126.47,
        128.36, 115.71, 116.09, 99.53, 127.27, 87.08, 85.67, 82.02, 98.2, 96.44,
        90.23, 97.15, 95.08, 94, 93, 96.09, 129.21, 75.39, 77.7, 97.34, 84.97, 87.55,
        86.64, 90.52, 95.4, 95.2, 95.8, 101.23, 128.49, 85.63, 82.77, 96.55, 81.33,
        96.91, 83.76, 90.19, 114.84, 108.4, 106.05, 109.71, 143.86, 99.12, 99.28,
        114.75, 106.13, 110.02, 108.07, 112.52, 113.87, 107.84, 112.12, 112.03, 139.37,
        92.24, 93.56, 107.37, 102.89, 114.78, 102.88, 118.41, 119.23, 117.36, 122.06)),
    row.names = c(NA, -154L), class = c("tbl_df", "tbl", "data.frame"))
# atribuir objeto ts
dados.ts <- ts(dados$consumo, start = c(1984, 1), frequency = 12)
# plot inicial
plot(dados.ts, main = "Consumo do varejo de Sao Paulo, Morettin e Toloi (2006)",
    xlab = "Ano", ylab = "Indice")

# plot no ggplot
library(ggplot2)
datas <- seq(as.Date(paste(c(start(dados.ts), 1), collapse = "/")), by = "month",
    length.out = length(dados$consumo))
dados.df <- data.frame(date = datas, value = dados$consumo)
ggplot(dados.df) + aes(x = date, y = value) + geom_line(colour = "#112446") + labs(x = "Mês/Ano",
    y = "Índice (base 100)", title = "Série de consumo:", subtitle = "varejo de São Paulo",
    caption = "Fonte: Morettin e Toloi (2006). Disponível em: <https://www.ime.usp.br/~pam/CONSUMO.XLS>") +
    ggthemes::theme_economist_white()

2.0.1 Estatísticas descritivas

Olhando as estatísticas descritivas, o pesquisador percebe a amplitude de variação, e o gráfico do dygraphs permite “caminhar” com o mouse sobre a série. Perceberás que a sazonalidade está bem marcada com picos em dezembro de cada ano.

# estatisticas basicas
summary(dados.ts)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  75.39  102.12  116.36  120.94  130.52  232.01 
# Min. 1st Qu.  Median Mean 3rd Qu.  Max.  75.39 102.12 116.36 120.94 130.52
# 232.01 pelo pacote dygraph dá mais opções
library(dygraphs)
dygraph(dados.ts)

É possível visualizar nos plots acima: sazonalidade (por exemplo, picos em dezembro de cada ano); a tendência aparentemente crescente e depois decresce com a “crise” brasileira; e uma aparente não-estacionariedade (média e variância mudam no tempo). Em outra postagem aplicarei o teste de raiz unitária na série para avaliar a estacionariedade de modo mais explícito.

3 Hierarquico - thief

O pacote thief é um acrônimo para Temporal HIErarchical Forecasting. A ideia é pegar uma série temporal sazonal e calcular todas as agregações temporais possíveis que resultem em um número inteiro de observações por ano. Por exemplo, uma série temporal trimestral é agregada a bianual e anual; enquanto uma série temporal mensal é agregada a bimestral, trimestral, quadrimestral, semestral e anual. Cada uma das séries temporais resultantes é prevista e, em seguida, as previsões são reconciliadas usando o algoritmo de reconciliação hierárquica descrito por Hyndman (2016). Isso tende a fornecer melhores previsões, mesmo que nenhuma informação nova tenha sido adicionada, especialmente para séries temporais com longos períodos sazonais. Também permite que diferentes tipos de previsões para diferentes horizontes de previsão sejam combinados de maneira consistente.

A função principal é thief que pode ser usada como qualquer uma das funções de previsão do pacote forecast.

# Hierarquico
library(thief)
library(ggplot2)
fc <- thief(dados.ts)
autoplot(fc)

summary(fc)

Forecast method: THieF-ETS

Model Information:
NULL

Error measures:
                     ME     RMSE      MAE        MPE     MAPE      MASE
Training set -0.5387926 11.85398 8.645059 -0.1400359 7.037349 0.5160809
                  ACF1
Training set 0.4713074

Forecasts:
           Jan       Feb       Mar       Apr       May       Jun       Jul
1996                                                                      
1997 100.83958  98.39163 109.67194 106.59647 115.93014 109.41115 115.86202
1998 100.89544  98.46595 109.78544 106.67949 116.05506 109.48834 115.95766
           Aug       Sep       Oct       Nov       Dec
1996                               118.62168 155.55950
1997 121.89536 117.11705 119.26108 118.69737 155.83767
1998 122.00948 117.20760 119.34892                    

A função thief calcula os agregados temporais, depois calcula todas as previsões (usando ets por padrão) e, finalmente, reconcilia as previsões usando a abordagem descrita em Hyndman (2016). As previsões reconciliadas correspondentes à série original são retornadas.

Existem opções para calcular previsões usando outros métodos, como auto.arima, o método Theta (thetaf) ou uma função de previsão definida pelo usuário.

Existem também funções para fazer cada parte separadamente: tsaggregates calculará todas as séries temporais agregadas, reconcilethief reconciliará uma lista de séries temporais (ou uma lista de objetos de previsão) de diferentes níveis de agregação temporal.

# Construct all temporal aggregates
totalagg <- tsaggregates(dados.ts)
autoplot(totalagg, main = "Varejo Morettin - tsaggregates")

4 Cálculo dos Forecasts

Faremos com ets.

# Compute base forecasts
base <- list()
for (i in seq_along(totalagg)) base[[i]] <- forecast(ets(totalagg[[i]]), h = 2 *
    frequency(totalagg[[i]]), level = 80)

# Reconcile forecasts
reconciled <- reconcilethief(base)
# Plot original and reconciled forecasts
par(mfrow = c(2, 3), mar = c(3, 3, 1, 0))
for (i in 6:1) {
    plot(reconciled[[i]], main = names(totalagg)[i], xlim = c(1984.1, 1998.1), flwd = 1)
    lines(base[[i]]$mean, col = "red")
}

A linha vermelha representa as previsões de base originais e a linha azul as previsões reconciliadas. Observe como as previsões básicas são diferentes nos níveis de agregação. No nível anual, não há tendência capturada na previsão devido ao ajuste limitado da amostra, e há uma tendência fraca capturada nas previsões semanais devido aos dados ruidosos. Mas a tendência é bastante forte nos níveis intermediários de agregação temporal. Da mesma forma, a sazonalidade é capturada com relativa precisão nos níveis trimestral, mensal e quinzenal, mas não no nível semanal. Uma vez conciliados, a tendência nos níveis anual e semanal é mais forte, e a sazonalidade semanal parece mais razoável.

Faremos com auto.arima.

# Compute base forecasts
baseaa <- list()
for (i in seq_along(totalagg)) baseaa[[i]] <- forecast(auto.arima(totalagg[[i]],
    stepwise = F, approximation = F), h = 2 * frequency(totalagg[[i]]), level = 80)

# Reconcile forecasts
reconciledaa <- reconcilethief(baseaa)
# Plot original and reconciled forecasts
par(mfrow = c(2, 3), mar = c(3, 3, 1, 0))
for (i in 6:1) {
    plot(reconciledaa[[i]], main = names(totalagg)[i], xlim = c(1984.1, 1998.1),
        flwd = 1)
    lines(baseaa[[i]]$mean, col = "red")
}

5 Referências

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

HYNDMAN, R.J. The thief package for R: Temporal HIErarchical Forecasting. Hyndsight blog. 22 August 2016. Disponível em: https://robjhyndman.com/hyndsight/thief/. Acesso em: 20.04.2023.

MORETTIN, Pedro A.; TOLOI, Clélia M.C. Análise de Séries Temporais. São paulo: Editora Edgard Blücher, 2004. https://www.ime.usp.br/~pam/st/

LS0tDQp0aXRsZTogIkV4ZW1wbG8gU8OpcmllcyBUZW1wb3JhaXM6IGNvbnN1bW8gTW9yZXR0aW4gZSBUb2xvaTogaGllcsOhcnF1aWNvICAtIGZvcm1hdG8gdHMiDQphdXRob3I6ICJBZHJpYW5vIE1hcmNvcyBSb2RyaWd1ZXMgRmlndWVpcmVkbywgKmUtbWFpbDogYWRyaWFuby5maWd1ZWlyZWRvQHVmbXMuYnIqIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiBkZWZhdWx0DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IG5vDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgZmlnX2NhcHRpb246IHRydWUNCi0tLQ0KDQpgYGB7ciBrbml0cl9pbml0LCBlY2hvPUZBTFNFLCBjYWNoZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJtYXJrZG93bikNCmxpYnJhcnkocm1kZm9ybWF0cykNCg0KIyMgR2xvYmFsIG9wdGlvbnMNCm9wdGlvbnMobWF4LnByaW50PSIxMDAiKQ0Kb3B0c19jaHVuayRzZXQoZWNobz1UUlVFLA0KCSAgICAgICAgICAgICBjYWNoZT1ULA0KICAgICAgICAgICAgICAgcHJvbXB0PUZBTFNFLA0KICAgICAgICAgICAgICAgdGlkeT1UUlVFLA0KICAgICAgICAgICAgICAgY29tbWVudD1OQSwNCiAgICAgICAgICAgICAgIG1lc3NhZ2U9RkFMU0UsDQogICAgICAgICAgICAgICB3YXJuaW5nPUZBTFNFKQ0Kb3B0c19rbml0JHNldCh3aWR0aD0xMDApDQpgYGANCg0KIyBMaWNlbsOnYSB7I0xpY2Vuw6dhIC51bm51bWJlcmVkfQ0KDQpUaGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgdGhlIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiBUbyB2aWV3IGEgY29weSBvZiB0aGlzIGxpY2Vuc2UsIHZpc2l0IDxodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS80LjAvPiBvciBzZW5kIGEgbGV0dGVyIHRvIENyZWF0aXZlIENvbW1vbnMsIFBPIEJveCAxODY2LCBNb3VudGFpbiBWaWV3LCBDQSA5NDA0MiwgVVNBLg0KDQohW0xpY2Vuc2U6IENDIEJZLVNBIDQuMF0oaHR0cHM6Ly9taXJyb3JzLmNyZWF0aXZlY29tbW9ucy5vcmcvcHJlc3NraXQvYnV0dG9ucy84OHgzMS9wbmcvYnktc2EucG5nKXt3aWR0aD0iMjUlIn0NCg0KDQojIENpdGHDp8OjbyB7I0NpdGHDp8OjbyAudW5udW1iZXJlZH0NCg0KU3VnZXN0w6NvIGRlIGNpdGHDp8OjbzogRklHVUVJUkVETywgQWRyaWFubyBNYXJjb3MgUm9kcmlndWVzLiBFeGVtcGxvIFPDqXJpZXMgVGVtcG9yYWlzOiBjb25zdW1vIE1vcmV0dGluIGUgVG9sb2k6IGhpZXLDoXJxdWljbyAtIGZvcm1hdG9zIHRzLiBDYW1wbyBHcmFuZGUtTVMsIEJyYXNpbDogUlN0dWRpby9ScHVicywgMjAyMy4gRGlzcG9uw612ZWwgZW0gPGh0dHBzOi8vcnB1YnMuY29tL2Ftcm9maS9tb3JldHRpbl90b2xvaV9oaWVyYXJxdWljbz4uDQoNCiMgSW50cm9kdcOnw6NvDQoNCk9zIGRhZG9zIHZlbSBkbyBsaXZybyBkZSBNb3JldHRpbiBlIFRvbG9pLCBBbsOhbGlzZSBkZSBTw6lyaWVzIFRlbXBvcmFpcyAoPGh0dHBzOi8vd3d3LmltZS51c3AuYnIvfnBhbS9TVC5odG1sPiksIGNvbnN1bW8gbm8gdmFyZWpvIGRlIFPDo28gUGF1bG8sIG1lbnNhaXMgZGUgSmFuLzE5ODQgYSBPdXQvMTk5NiwgZW0gPGh0dHBzOi8vd3d3LmltZS51c3AuYnIvfnBhbS9DT05TVU1PLlhMUz4uDQoNCkluaWNpYWxtZW50ZSwgdHJhYmFsaGFyZW1vcyBjb20gbyBmb3JtYXRvIGB0c2AsIGNvbmZvcm1lIG8gbGl2cm8gZGUgSHluZG1hbiAoMjAxOCksIHNlZ3VuZGEgZWRpw6fDo28uIE8gYXJ0aWdvIHNlZ3VlIGEgcm90aW5hIGRlIEh5bmRtYW4gKDIwMTYpLiANCg0KIyBEYWRvcyBlbSBmb3JtYXRvIHRzDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsY2FjaGU9VFJVRX0NCg0KI3ZvdSBwdXhhciBvcyBsaWJyYXJpZXMgcXVlIHRlbmhvIGNvc3R1bWUgZGUgdXNhcjogZGVzdGFxdWUgcGFyYSBvIHJlYWR4bCBlIHRzZXJpZXMNCmxpYnJhcnkocmVhZHhsKSAjIHB1eGFyIEV4Y2VsDQpsaWJyYXJ5KGZwcDIpICMgbGl2cm8gSHluZG1hbiBmb3JtYXRvIHRzIC0gasOhIGNhcnJlZ2EgZ2dwbG90MiBlIGZvcmVjYXN0DQojIGNvZGlnbyBwYXJhIHB1eGFyIGRvIEV4Y2VsDQojIGRhZG9zIDwtIHJlYWRfZXhjZWwoIkNPTlNVTU8gbW9yZXR0aW4gUi54bHN4IiwgDQojICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJkYWRvcyIpDQpkYWRvcyA8LXN0cnVjdHVyZShsaXN0KG9icyA9IHN0cnVjdHVyZShjKDQ0MTc2MzIwMCwgNDQ0NDQxNjAwLCA0NDY5NDcyMDAsIA0KNDQ5NjI1NjAwLCA0NTIyMTc2MDAsIDQ1NDg5NjAwMCwgNDU3NDg4MDAwLCA0NjAxNjY0MDAsIDQ2Mjg0NDgwMCwgDQo0NjU0MzY4MDAsIDQ2ODExNTIwMCwgNDcwNzA3MjAwLCA0NzMzODU2MDAsIDQ3NjA2NDAwMCwgNDc4NDgzMjAwLCANCjQ4MTE2MTYwMCwgNDgzNzUzNjAwLCA0ODY0MzIwMDAsIDQ4OTAyNDAwMCwgNDkxNzAyNDAwLCA0OTQzODA4MDAsIA0KNDk2OTcyODAwLCA0OTk2NTEyMDAsIDUwMjI0MzIwMCwgNTA0OTIxNjAwLCA1MDc2MDAwMDAsIDUxMDAxOTIwMCwgDQo1MTI2OTc2MDAsIDUxNTI4OTYwMCwgNTE3OTY4MDAwLCA1MjA1NjAwMDAsIDUyMzIzODQwMCwgNTI1OTE2ODAwLCANCjUyODUwODgwMCwgNTMxMTg3MjAwLCA1MzM3NzkyMDAsIDUzNjQ1NzYwMCwgNTM5MTM2MDAwLCA1NDE1NTUyMDAsIA0KNTQ0MjMzNjAwLCA1NDY4MjU2MDAsIDU0OTUwNDAwMCwgNTUyMDk2MDAwLCA1NTQ3NzQ0MDAsIDU1NzQ1MjgwMCwgDQo1NjAwNDQ4MDAsIDU2MjcyMzIwMCwgNTY1MzE1MjAwLCA1Njc5OTM2MDAsIDU3MDY3MjAwMCwgNTczMTc3NjAwLCANCjU3NTg1NjAwMCwgNTc4NDQ4MDAwLCA1ODExMjY0MDAsIDU4MzcxODQwMCwgNTg2Mzk2ODAwLCA1ODkwNzUyMDAsIA0KNTkxNjY3MjAwLCA1OTQzNDU2MDAsIDU5NjkzNzYwMCwgNTk5NjE2MDAwLCA2MDIyOTQ0MDAsIDYwNDcxMzYwMCwgDQo2MDczOTIwMDAsIDYwOTk4NDAwMCwgNjEyNjYyNDAwLCA2MTUyNTQ0MDAsIDYxNzkzMjgwMCwgNjIwNjExMjAwLCANCjYyMzIwMzIwMCwgNjI1ODgxNjAwLCA2Mjg0NzM2MDAsIDYzMTE1MjAwMCwgNjMzODMwNDAwLCA2MzYyNDk2MDAsIA0KNjM4OTI4MDAwLCA2NDE1MjAwMDAsIDY0NDE5ODQwMCwgNjQ2NzkwNDAwLCA2NDk0Njg4MDAsIDY1MjE0NzIwMCwgDQo2NTQ3MzkyMDAsIDY1NzQxNzYwMCwgNjYwMDA5NjAwLCA2NjI2ODgwMDAsIDY2NTM2NjQwMCwgNjY3Nzg1NjAwLCANCjY3MDQ2NDAwMCwgNjczMDU2MDAwLCA2NzU3MzQ0MDAsIDY3ODMyNjQwMCwgNjgxMDA0ODAwLCA2ODM2ODMyMDAsIA0KNjg2Mjc1MjAwLCA2ODg5NTM2MDAsIDY5MTU0NTYwMCwgNjk0MjI0MDAwLCA2OTY5MDI0MDAsIDY5OTQwODAwMCwgDQo3MDIwODY0MDAsIDcwNDY3ODQwMCwgNzA3MzU2ODAwLCA3MDk5NDg4MDAsIDcxMjYyNzIwMCwgNzE1MzA1NjAwLCANCjcxNzg5NzYwMCwgNzIwNTc2MDAwLCA3MjMxNjgwMDAsIDcyNTg0NjQwMCwgNzI4NTI0ODAwLCA3MzA5NDQwMDAsIA0KNzMzNjIyNDAwLCA3MzYyMTQ0MDAsIDczODg5MjgwMCwgNzQxNDg0ODAwLCA3NDQxNjMyMDAsIDc0Njg0MTYwMCwgDQo3NDk0MzM2MDAsIDc1MjExMjAwMCwgNzU0NzA0MDAwLCA3NTczODI0MDAsIDc2MDA2MDgwMCwgNzYyNDgwMDAwLCANCjc2NTE1ODQwMCwgNzY3NzUwNDAwLCA3NzA0Mjg4MDAsIDc3MzAyMDgwMCwgNzc1Njk5MjAwLCA3NzgzNzc2MDAsIA0KNzgwOTY5NjAwLCA3ODM2NDgwMDAsIDc4NjI0MDAwMCwgNzg4OTE4NDAwLCA3OTE1OTY4MDAsIDc5NDAxNjAwMCwgDQo3OTY2OTQ0MDAsIDc5OTI4NjQwMCwgODAxOTY0ODAwLCA4MDQ1NTY4MDAsIDgwNzIzNTIwMCwgODA5OTEzNjAwLCANCjgxMjUwNTYwMCwgODE1MTg0MDAwLCA4MTc3NzYwMDAsIDgyMDQ1NDQwMCwgODIzMTMyODAwLCA4MjU2Mzg0MDAsIA0KODI4MzE2ODAwLCA4MzA5MDg4MDAsIDgzMzU4NzIwMCwgODM2MTc5MjAwLCA4Mzg4NTc2MDAsIDg0MTUzNjAwMCwgDQo4NDQxMjgwMDApLCBjbGFzcyA9IGMoIlBPU0lYY3QiLCAiUE9TSVh0IiksIHR6b25lID0gIlVUQyIpLCB0ID0gYygxLCANCjIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTUsIDE2LCAxNywgMTgsIDE5LCANCjIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsIDI2LCAyNywgMjgsIDI5LCAzMCwgMzEsIDMyLCAzMywgMzQsIDM1LCANCjM2LCAzNywgMzgsIDM5LCA0MCwgNDEsIDQyLCA0MywgNDQsIDQ1LCA0NiwgNDcsIDQ4LCA0OSwgNTAsIDUxLCANCjUyLCA1MywgNTQsIDU1LCA1NiwgNTcsIDU4LCA1OSwgNjAsIDYxLCA2MiwgNjMsIDY0LCA2NSwgNjYsIDY3LCANCjY4LCA2OSwgNzAsIDcxLCA3MiwgNzMsIDc0LCA3NSwgNzYsIDc3LCA3OCwgNzksIDgwLCA4MSwgODIsIDgzLCANCjg0LCA4NSwgODYsIDg3LCA4OCwgODksIDkwLCA5MSwgOTIsIDkzLCA5NCwgOTUsIDk2LCA5NywgOTgsIDk5LCANCjEwMCwgMTAxLCAxMDIsIDEwMywgMTA0LCAxMDUsIDEwNiwgMTA3LCAxMDgsIDEwOSwgMTEwLCAxMTEsIDExMiwgDQoxMTMsIDExNCwgMTE1LCAxMTYsIDExNywgMTE4LCAxMTksIDEyMCwgMTIxLCAxMjIsIDEyMywgMTI0LCAxMjUsIA0KMTI2LCAxMjcsIDEyOCwgMTI5LCAxMzAsIDEzMSwgMTMyLCAxMzMsIDEzNCwgMTM1LCAxMzYsIDEzNywgMTM4LCANCjEzOSwgMTQwLCAxNDEsIDE0MiwgMTQzLCAxNDQsIDE0NSwgMTQ2LCAxNDcsIDE0OCwgMTQ5LCAxNTAsIDE1MSwgDQoxNTIsIDE1MywgMTU0KSwgY29uc3VtbyA9IGMoMTE0LjEzLCAxMTAuNzksIDExNi40NiwgMTExLjU3LCAxMjAuNjYsIA0KMTIxLjE1LCAxMjEuMjcsIDEyNy4wMiwgMTI5LjA0LCAxMzMuMywgMTMwLjYsIDE3OS4zOSwgMTIwLjY0LCANCjExNC4wNSwgMTMwLjYsIDExOC4yNiwgMTQ1LjU0LCAxMzUuMTMsIDE1My4zNSwgMTU5Ljk1LCAxNTAuMDEsIA0KMTY0LjkzLCAxNzAuMzcsIDIyMC45NiwgMTM0LjI2LCAxMzMuMTEsIDE0Ny44NCwgMTY0LjQ2LCAxODEuODYsIA0KMTcwLjQ0LCAxODYuNjQsIDE3NC4yMSwgMTgxLjYyLCAxOTQuMTYsIDE4MS45LCAyMzIuMDEsIDE0MC4xNiwgDQoxMzAuNzgsIDExOS4wNCwgMTIwLjczLCAxMjkuODEsIDExMS4wNCwgMTIyLjc1LCAxMzMuOTUsIDEyNS40MSwgDQoxMzIuMDUsIDEyOS41NCwgMTc2LjM3LCAxMTAuMDksIDExMy4yNSwgMTI0LjAzLCAxMTAuNjMsIDExNi43MiwgDQoxMjQuNjMsIDEyNC4zOCwgMTMwLjI3LCAxMTkuODcsIDExNS43NSwgMTIyLjQ0LCAxNjIuNDMsIDEwNS44OSwgDQoxMTUuNTksIDE0NywgMTMxLjcsIDEzMS4zMiwgMTM2LjY2LCAxMjYuNDMsIDEzNC44OCwgMTI4LjI2LCAxMjUuMzIsIA0KMTI0LjYxLCAxNjYuMTEsIDExNi4yNSwgOTYuOTMsIDg5LjI3LCAxMDEuODcsIDEyNS41NywgMTEzLjMxLCANCjEwOS4zOSwgMTI3LjMzLCAxMjAuNTYsIDExNy43MywgMTEzLjgxLCAxNDcuMjUsIDEwMC4xNSwgOTUuMTEsIA0KMTEyLjI2LCAxMDkuMzksIDExNC4yLCAxMTMuOCwgMTI2LjQ3LCAxMjguMzYsIDExNS43MSwgMTE2LjA5LCANCjk5LjUzLCAxMjcuMjcsIDg3LjA4LCA4NS42NywgODIuMDIsIDk4LjIsIDk2LjQ0LCA5MC4yMywgOTcuMTUsIA0KOTUuMDgsIDk0LCA5MywgOTYuMDksIDEyOS4yMSwgNzUuMzksIDc3LjcsIDk3LjM0LCA4NC45NywgODcuNTUsIA0KODYuNjQsIDkwLjUyLCA5NS40LCA5NS4yLCA5NS44LCAxMDEuMjMsIDEyOC40OSwgODUuNjMsIDgyLjc3LCANCjk2LjU1LCA4MS4zMywgOTYuOTEsIDgzLjc2LCA5MC4xOSwgMTE0Ljg0LCAxMDguNCwgMTA2LjA1LCAxMDkuNzEsIA0KMTQzLjg2LCA5OS4xMiwgOTkuMjgsIDExNC43NSwgMTA2LjEzLCAxMTAuMDIsIDEwOC4wNywgMTEyLjUyLCANCjExMy44NywgMTA3Ljg0LCAxMTIuMTIsIDExMi4wMywgMTM5LjM3LCA5Mi4yNCwgOTMuNTYsIDEwNy4zNywgDQoxMDIuODksIDExNC43OCwgMTAyLjg4LCAxMTguNDEsIDExOS4yMywgMTE3LjM2LCAxMjIuMDYpKSwgcm93Lm5hbWVzID0gYyhOQSwgDQotMTU0TCksIGNsYXNzID0gYygidGJsX2RmIiwgInRibCIsICJkYXRhLmZyYW1lIikpDQojIGF0cmlidWlyIG9iamV0byB0cw0KZGFkb3MudHM8LSB0cyhkYWRvcyRjb25zdW1vLHN0YXJ0PWMoMTk4NCwxKSwgZnJlcXVlbmN5ID0gMTIpDQojIHBsb3QgaW5pY2lhbA0KcGxvdChkYWRvcy50cyxtYWluPSJDb25zdW1vIGRvIHZhcmVqbyBkZSBTYW8gUGF1bG8sIE1vcmV0dGluIGUgVG9sb2kgKDIwMDYpIiwNCiAgICAgICAgICAgICAgeGxhYj0iQW5vIix5bGFiPSJJbmRpY2UiKQ0KIw0KIyBwbG90IG5vIGdncGxvdA0KbGlicmFyeShnZ3Bsb3QyKQ0KZGF0YXMgPC0gc2VxKGFzLkRhdGUocGFzdGUoYyhzdGFydChkYWRvcy50cyksMSksIGNvbGxhcHNlPSIvIikpLCANCiAgICAgICAgICAgICBieSA9ICJtb250aCIsIGxlbmd0aC5vdXQgPSBsZW5ndGgoZGFkb3MkY29uc3VtbykpDQpkYWRvcy5kZiA8LSBkYXRhLmZyYW1lKGRhdGUgPSBkYXRhcywgdmFsdWUgPSBkYWRvcyRjb25zdW1vKQ0KZ2dwbG90KGRhZG9zLmRmKSArDQogIGFlcyh4ID0gZGF0ZSwgeSA9IHZhbHVlKSArDQogIGdlb21fbGluZShjb2xvdXIgPSAiIzExMjQ0NiIpICsNCiAgbGFicygNCiAgICB4ID0gIk3DqnMvQW5vIiwNCiAgICB5ID0gIsONbmRpY2UgKGJhc2UgMTAwKSIsDQogICAgdGl0bGUgPSAiU8OpcmllIGRlIGNvbnN1bW86IiwNCiAgICBzdWJ0aXRsZSA9ICJ2YXJlam8gZGUgU8OjbyBQYXVsbyIsDQogICAgY2FwdGlvbiA9ICJGb250ZTogTW9yZXR0aW4gZSBUb2xvaSAoMjAwNikuIERpc3BvbsOtdmVsIGVtOiA8aHR0cHM6Ly93d3cuaW1lLnVzcC5ici9+cGFtL0NPTlNVTU8uWExTPiINCiAgKSArDQogIGdndGhlbWVzOjp0aGVtZV9lY29ub21pc3Rfd2hpdGUoKQ0KDQpgYGANCg0KIyMjIEVzdGF0w61zdGljYXMgZGVzY3JpdGl2YXMNCg0KT2xoYW5kbyBhcyBlc3RhdMOtc3RpY2FzIGRlc2NyaXRpdmFzLCBvIHBlc3F1aXNhZG9yIHBlcmNlYmUgYSBhbXBsaXR1ZGUgZGUgdmFyaWHDp8OjbywgZSBvIGdyw6FmaWNvIGRvIGR5Z3JhcGhzIHBlcm1pdGUgImNhbWluaGFyIiBjb20gbyBtb3VzZSBzb2JyZSBhIHPDqXJpZS4gUGVyY2ViZXLDoXMgcXVlIGEgc2F6b25hbGlkYWRlIGVzdMOhIGJlbSBtYXJjYWRhIGNvbSBwaWNvcyBlbSBkZXplbWJybyBkZSBjYWRhIGFuby4NCg0KYGBge3IgZXN0YXRkZXNjLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGNhY2hlPVRSVUV9DQojIGVzdGF0aXN0aWNhcyBiYXNpY2FzDQpzdW1tYXJ5KGRhZG9zLnRzKQ0KIyAgIE1pbi4gMXN0IFF1LiAgTWVkaWFuICAgIE1lYW4gM3JkIFF1LiAgICBNYXguIA0KIyAgNzUuMzkgIDEwMi4xMiAgMTE2LjM2ICAxMjAuOTQgIDEzMC41MiAgMjMyLjAxIA0KIyBwZWxvIHBhY290ZSBkeWdyYXBoIGTDoSBtYWlzIG9ww6fDtWVzDQpsaWJyYXJ5KGR5Z3JhcGhzKQ0KZHlncmFwaChkYWRvcy50cykNCmBgYA0KDQrDiSBwb3Nzw612ZWwgdmlzdWFsaXphciBub3MgcGxvdHMgYWNpbWE6IHNhem9uYWxpZGFkZSAocG9yIGV4ZW1wbG8sIHBpY29zIGVtIGRlemVtYnJvIGRlIGNhZGEgYW5vKTsgYSB0ZW5kw6puY2lhIGFwYXJlbnRlbWVudGUgY3Jlc2NlbnRlIGUgZGVwb2lzIGRlY3Jlc2NlIGNvbSBhICJjcmlzZSIgYnJhc2lsZWlyYTsgZSB1bWEgYXBhcmVudGUgbsOjby1lc3RhY2lvbmFyaWVkYWRlIChtw6lkaWEgZSB2YXJpw6JuY2lhIG11ZGFtIG5vIHRlbXBvKS4gRW0gb3V0cmEgcG9zdGFnZW0gYXBsaWNhcmVpIG8gdGVzdGUgZGUgcmFpeiB1bml0w6FyaWEgbmEgc8OpcmllIHBhcmEgYXZhbGlhciBhIGVzdGFjaW9uYXJpZWRhZGUgZGUgbW9kbyBtYWlzIGV4cGzDrWNpdG8uDQoNCiMgSGllcmFycXVpY28gLSB0aGllZg0KDQpPIHBhY290ZSBgdGhpZWZgIMOpIHVtIGFjcsO0bmltbyBwYXJhIFRlbXBvcmFsIEhJRXJhcmNoaWNhbCBGb3JlY2FzdGluZy4gQSBpZGVpYSDDqSBwZWdhciB1bWEgc8OpcmllIHRlbXBvcmFsIHNhem9uYWwgZSBjYWxjdWxhciB0b2RhcyBhcyBhZ3JlZ2HDp8O1ZXMgdGVtcG9yYWlzIHBvc3PDrXZlaXMgcXVlIHJlc3VsdGVtIGVtIHVtIG7Dum1lcm8gaW50ZWlybyBkZSBvYnNlcnZhw6fDtWVzIHBvciBhbm8uIFBvciBleGVtcGxvLCB1bWEgc8OpcmllIHRlbXBvcmFsIHRyaW1lc3RyYWwgw6kgYWdyZWdhZGEgYSBiaWFudWFsIGUgYW51YWw7IGVucXVhbnRvIHVtYSBzw6lyaWUgdGVtcG9yYWwgbWVuc2FsIMOpIGFncmVnYWRhIGEgYmltZXN0cmFsLCB0cmltZXN0cmFsLCBxdWFkcmltZXN0cmFsLCBzZW1lc3RyYWwgZSBhbnVhbC4gQ2FkYSB1bWEgZGFzIHPDqXJpZXMgdGVtcG9yYWlzIHJlc3VsdGFudGVzIMOpIHByZXZpc3RhIGUsIGVtIHNlZ3VpZGEsIGFzIHByZXZpc8O1ZXMgc8OjbyByZWNvbmNpbGlhZGFzIHVzYW5kbyBvIGFsZ29yaXRtbyBkZSByZWNvbmNpbGlhw6fDo28gaGllcsOhcnF1aWNhIGRlc2NyaXRvIHBvciBIeW5kbWFuICgyMDE2KS4gSXNzbyB0ZW5kZSBhIGZvcm5lY2VyIG1lbGhvcmVzIHByZXZpc8O1ZXMsIG1lc21vIHF1ZSBuZW5odW1hIGluZm9ybWHDp8OjbyBub3ZhIHRlbmhhIHNpZG8gYWRpY2lvbmFkYSwgZXNwZWNpYWxtZW50ZSBwYXJhIHPDqXJpZXMgdGVtcG9yYWlzIGNvbSBsb25nb3MgcGVyw61vZG9zIHNhem9uYWlzLiBUYW1iw6ltIHBlcm1pdGUgcXVlIGRpZmVyZW50ZXMgdGlwb3MgZGUgcHJldmlzw7VlcyBwYXJhIGRpZmVyZW50ZXMgaG9yaXpvbnRlcyBkZSBwcmV2aXPDo28gc2VqYW0gY29tYmluYWRvcyBkZSBtYW5laXJhIGNvbnNpc3RlbnRlLg0KICAgIA0KQSBmdW7Dp8OjbyBwcmluY2lwYWwgw6kgYHRoaWVmYCBxdWUgcG9kZSBzZXIgdXNhZGEgY29tbyBxdWFscXVlciB1bWEgZGFzIGZ1bsOnw7VlcyBkZSBwcmV2aXPDo28gZG8gcGFjb3RlIGBmb3JlY2FzdGAuICAgICANCg0KDQoNCmBgYHtyIGhpZXJhcnEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsY2FjaGU9VFJVRX0NCiMgSGllcmFycXVpY28gDQpsaWJyYXJ5KHRoaWVmKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZmMgPC0gdGhpZWYoZGFkb3MudHMpDQphdXRvcGxvdChmYykNCnN1bW1hcnkoZmMpDQpgYGANCg0KQSBmdW7Dp8OjbyBgdGhpZWZgIGNhbGN1bGEgb3MgYWdyZWdhZG9zIHRlbXBvcmFpcywgZGVwb2lzIGNhbGN1bGEgdG9kYXMgYXMgcHJldmlzw7VlcyAodXNhbmRvIGBldHNgIHBvciBwYWRyw6NvKSBlLCBmaW5hbG1lbnRlLCByZWNvbmNpbGlhIGFzIHByZXZpc8O1ZXMgdXNhbmRvIGEgYWJvcmRhZ2VtIGRlc2NyaXRhIGVtIEh5bmRtYW4gKDIwMTYpLiBBcyBwcmV2aXPDtWVzIHJlY29uY2lsaWFkYXMgY29ycmVzcG9uZGVudGVzIMOgIHPDqXJpZSBvcmlnaW5hbCBzw6NvIHJldG9ybmFkYXMuDQoNCkV4aXN0ZW0gb3DDp8O1ZXMgcGFyYSBjYWxjdWxhciBwcmV2aXPDtWVzIHVzYW5kbyBvdXRyb3MgbcOpdG9kb3MsIGNvbW8gYGF1dG8uYXJpbWFgLCBvIG3DqXRvZG8gVGhldGEgKGB0aGV0YWZgKSBvdSB1bWEgZnVuw6fDo28gZGUgcHJldmlzw6NvIGRlZmluaWRhIHBlbG8gdXN1w6FyaW8uDQoNCkV4aXN0ZW0gdGFtYsOpbSBmdW7Dp8O1ZXMgcGFyYSBmYXplciBjYWRhIHBhcnRlIHNlcGFyYWRhbWVudGU6IGB0c2FnZ3JlZ2F0ZXNgIGNhbGN1bGFyw6EgdG9kYXMgYXMgc8OpcmllcyB0ZW1wb3JhaXMgYWdyZWdhZGFzLCBgcmVjb25jaWxldGhpZWZgIHJlY29uY2lsaWFyw6EgdW1hIGxpc3RhIGRlIHPDqXJpZXMgdGVtcG9yYWlzIChvdSB1bWEgbGlzdGEgZGUgb2JqZXRvcyBkZSBwcmV2aXPDo28pIGRlIGRpZmVyZW50ZXMgbsOtdmVpcyBkZSBhZ3JlZ2HDp8OjbyB0ZW1wb3JhbC4gICAgDQoNCmBgYHtyIGFnZ3JlZ2F0ZXMsY2FjaGU9VFJVRX0NCiMgQ29uc3RydWN0IGFsbCB0ZW1wb3JhbCBhZ2dyZWdhdGVzDQp0b3RhbGFnZyA8LSB0c2FnZ3JlZ2F0ZXMoZGFkb3MudHMpDQphdXRvcGxvdCh0b3RhbGFnZywgbWFpbj0iVmFyZWpvIE1vcmV0dGluIC0gdHNhZ2dyZWdhdGVzIikNCmBgYA0KDQojIEPDoWxjdWxvIGRvcyBGb3JlY2FzdHMNCg0KRmFyZW1vcyBjb20gYGV0c2AuDQoNCmBgYHtyIGJhc2VmY3N0LGNhY2hlPVRSVUUsZXZhbD1UfQ0KIyBDb21wdXRlIGJhc2UgZm9yZWNhc3RzDQpiYXNlIDwtIGxpc3QoKQ0KZm9yKGkgaW4gc2VxX2Fsb25nKHRvdGFsYWdnKSkNCiAgYmFzZVtbaV1dIDwtIGZvcmVjYXN0KA0KICAgIGV0cyh0b3RhbGFnZ1tbaV1dKSwNCiAgICAgICAgICAgICAgICAgaD0yKmZyZXF1ZW5jeSh0b3RhbGFnZ1tbaV1dKSwgDQogICAgICAgICAgICAgICAgIGxldmVsPTgwKQ0KDQojIFJlY29uY2lsZSBmb3JlY2FzdHMNCnJlY29uY2lsZWQgPC0gcmVjb25jaWxldGhpZWYoYmFzZSkNCiAgDQpgYGANCg0KYGBge3IgcGxvdGZjc3QsIGV2YWw9VH0NCiNQbG90IG9yaWdpbmFsIGFuZCByZWNvbmNpbGVkIGZvcmVjYXN0cw0KcGFyKG1mcm93PWMoMiwzKSwgbWFyPWMoMywzLDEsMCkpDQpmb3IoaSBpbiA2OjEpDQp7DQogIHBsb3QocmVjb25jaWxlZFtbaV1dLCBtYWluPW5hbWVzKHRvdGFsYWdnKVtpXSwNCiAgICAgICB4bGltPWMoMTk4NC4xLDE5OTguMTApLCBmbHdkPTEpDQogIGxpbmVzKGJhc2VbW2ldXSRtZWFuLCBjb2w9InJlZCIpDQp9DQpgYGANCg0KDQpBIGxpbmhhIHZlcm1lbGhhIHJlcHJlc2VudGEgYXMgcHJldmlzw7VlcyBkZSBiYXNlIG9yaWdpbmFpcyBlIGEgbGluaGEgYXp1bCBhcyBwcmV2aXPDtWVzIHJlY29uY2lsaWFkYXMuIE9ic2VydmUgY29tbyBhcyBwcmV2aXPDtWVzIGLDoXNpY2FzIHPDo28gZGlmZXJlbnRlcyBub3MgbsOtdmVpcyBkZSBhZ3JlZ2HDp8Ojby4gTm8gbsOtdmVsIGFudWFsLCBuw6NvIGjDoSB0ZW5kw6puY2lhIGNhcHR1cmFkYSBuYSBwcmV2aXPDo28gZGV2aWRvIGFvIGFqdXN0ZSBsaW1pdGFkbyBkYSBhbW9zdHJhLCBlIGjDoSB1bWEgdGVuZMOqbmNpYSBmcmFjYSBjYXB0dXJhZGEgbmFzIHByZXZpc8O1ZXMgc2VtYW5haXMgZGV2aWRvIGFvcyBkYWRvcyBydWlkb3Nvcy4gTWFzIGEgdGVuZMOqbmNpYSDDqSBiYXN0YW50ZSBmb3J0ZSBub3MgbsOtdmVpcyBpbnRlcm1lZGnDoXJpb3MgZGUgYWdyZWdhw6fDo28gdGVtcG9yYWwuIERhIG1lc21hIGZvcm1hLCBhIHNhem9uYWxpZGFkZSDDqSBjYXB0dXJhZGEgY29tIHJlbGF0aXZhIHByZWNpc8OjbyBub3MgbsOtdmVpcyB0cmltZXN0cmFsLCBtZW5zYWwgZSBxdWluemVuYWwsIG1hcyBuw6NvIG5vIG7DrXZlbCBzZW1hbmFsLiBVbWEgdmV6IGNvbmNpbGlhZG9zLCBhIHRlbmTDqm5jaWEgbm9zIG7DrXZlaXMgYW51YWwgZSBzZW1hbmFsIMOpIG1haXMgZm9ydGUsIGUgYSBzYXpvbmFsaWRhZGUgc2VtYW5hbCBwYXJlY2UgbWFpcyByYXpvw6F2ZWwuDQoNCkZhcmVtb3MgY29tIGBhdXRvLmFyaW1hYC4NCg0KYGBge3IgYmFzZWZjc3RhYSxjYWNoZT1UUlVFLGV2YWw9VH0NCiMgQ29tcHV0ZSBiYXNlIGZvcmVjYXN0cw0KYmFzZWFhIDwtIGxpc3QoKQ0KZm9yKGkgaW4gc2VxX2Fsb25nKHRvdGFsYWdnKSkNCiAgYmFzZWFhW1tpXV0gPC0gZm9yZWNhc3QoDQogICAgYXV0by5hcmltYSh0b3RhbGFnZ1tbaV1dLCBzdGVwd2lzZSA9IEYsYXBwcm94aW1hdGlvbiA9IEYpLA0KICAgICAgICAgICAgICAgICBoPTIqZnJlcXVlbmN5KHRvdGFsYWdnW1tpXV0pLCANCiAgICAgICAgICAgICAgICAgbGV2ZWw9ODApDQoNCiMgUmVjb25jaWxlIGZvcmVjYXN0cw0KcmVjb25jaWxlZGFhIDwtIHJlY29uY2lsZXRoaWVmKGJhc2VhYSkNCiAgDQpgYGANCg0KDQpgYGB7ciBwbG90ZmNzdGFhLCBldmFsPVR9DQojUGxvdCBvcmlnaW5hbCBhbmQgcmVjb25jaWxlZCBmb3JlY2FzdHMNCnBhcihtZnJvdz1jKDIsMyksIG1hcj1jKDMsMywxLDApKQ0KZm9yKGkgaW4gNjoxKQ0Kew0KICBwbG90KHJlY29uY2lsZWRhYVtbaV1dLCBtYWluPW5hbWVzKHRvdGFsYWdnKVtpXSwNCiAgICAgICB4bGltPWMoMTk4NC4xLDE5OTguMTApLCBmbHdkPTEpDQogIGxpbmVzKGJhc2VhYVtbaV1dJG1lYW4sIGNvbD0icmVkIikNCn0NCmBgYA0KDQojIFJlZmVyw6puY2lhcw0KDQpIWU5ETUFOLCBSb2IgSi4gIF9mcHAyOiBEYXRhIGZvciAiRm9yZWNhc3Rpbmc6IFByaW5jaXBsZXMgYW5kIFByYWN0aWNlIl8gKDJuZCBFZGl0aW9uKS4gQ1JBTiwgUiBwYWNrYWdlIHZlcnNpb24gMi4zLiAyMDE4LiBEaXNwb27DrXZlbCBlbTogPGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9ZnBwMj4uDQoNCkhZTkRNQU4sIFIuSi4gX1RoZSB0aGllZiBwYWNrYWdlIGZvciBSOiBUZW1wb3JhbCBISUVyYXJjaGljYWwgRm9yZWNhc3RpbmdfLiAqKkh5bmRzaWdodCBibG9nKiouIDIyIEF1Z3VzdCAgMjAxNi4gRGlzcG9uw612ZWwgZW06IDxodHRwczovL3JvYmpoeW5kbWFuLmNvbS9oeW5kc2lnaHQvdGhpZWYvPi4gQWNlc3NvIGVtOiAyMC4wNC4yMDIzLg0KDQpNT1JFVFRJTiwgUGVkcm8gQS47IFRPTE9JLCBDbMOpbGlhIE0uQy4gKipBbsOhbGlzZSBkZSBTw6lyaWVzIFRlbXBvcmFpcyoqLiBTw6NvIHBhdWxvOiBFZGl0b3JhIEVkZ2FyZCBCbMO8Y2hlciwgMjAwNC4gPGh0dHBzOi8vd3d3LmltZS51c3AuYnIvfnBhbS9zdC8+DQo=