Regressão com Dados em Painel

O modelo de regressão com dados em painel possui uma característica especial: se constitui de uma dimensão temporal e outra espacial. Isto porque a mesma unidade de corte transversal (família, países, etc.) é acompanhada ao longo do tempo. Por exemplo, a produção industrial mensal dos Estados brasileiros em função da taxa de juros no período de 2015-2016. Têm-se então a 624 (26x24) observações combinadas: de cada um dos 26 Estados (exluindo o Distrito Federal) e 24 observações para os meses.

Dentre os benefícios da regressão com dados em painel (Gujarati e Porter 2011):

Devido à heterogeneidade da análise entre indivíduos, empresas, estados, países, etc., esta técnica pode levar em conta estas variáveis individuais específicas;

Maior informação, maior variabilidade e menor colinearidade entre variáveis, devido à combinaçãod e séries temporais e dados com corte transversal;

Dados em painel são mais adequados ao estudo da dinâmica da mudança (emprego, renda, etc).

Detecta e mede melhor os efeitos em comparação aos estudos transversais puros ou em séries temporais puras;

Possibilidade de modelos comportamentais mais complexos;

Minimização do viés decorrente da agregação de pessoas e/ou empresas nos grandes conjuntos.

A base de dados utilizada neste exemplo (“Grunfeld”) é proveniente do pacote AER. É constituída da variável dependente do nível de investimento (“invest”) de diversas empresas (“firm”), bem como das variáveis explicativas de seu valor de mercado (“value”) e do valor do estoque de capital (“capital”) durante o período de 1935-1954 (20 anos). Portanto pretende-se descobrir os determinantes do valor do nível investimento das firmas durente o período.

require(AER) 
data(Grunfeld, package="AER")

Após carregada a base para o estudo, serão selecionadas quatro empresas (“General Electric”, “General Motors”, “US Steel” e “Westinghouse”) para fins de análise dos dados. Utiliza-se o pacote plm e a função pdata.frame para alocar a base de dados para a análise de regressão de dados em painel, uma vez que é necessário definir o atributo individual (“firm”) e temporal (“year”) das observações. Para isso utiliza-se o argumento index, como segue:

require(plm)

Grunfeld=subset(Grunfeld, firm %in% c("General Electric",
                                      "General Motors",
                                      "US Steel",
                                      "Westinghouse"))
Grunfeld=pdata.frame(Grunfeld, index=c("firm","year"))
  
head(Grunfeld)

Nossa base de dados possui igualmente 20 informações para cada empresa, se constituindo em um painel equilibrado. Caso o número de informações para cada empresa fossem desiguais, teríamos um painel desequilibrado.

summary(Grunfeld)
     invest            value           capital      
 Min.   :  12.93   Min.   : 191.5   Min.   :   0.8  
 1st Qu.:  55.27   1st Qu.:1192.3   1st Qu.: 118.1  
 Median : 199.75   Median :1971.2   Median : 254.7  
 Mean   : 290.92   Mean   :2229.5   Mean   : 357.3  
 3rd Qu.: 459.77   3rd Qu.:2795.0   3rd Qu.: 368.9  
 Max.   :1486.70   Max.   :6241.7   Max.   :2226.3  
                                                    
               firm         year   
 General Motors  :20   1935   : 4  
 US Steel        :20   1936   : 4  
 General Electric:20   1937   : 4  
 Westinghouse    :20   1938   : 4  
                       1939   : 4  
                       1940   : 4  
                       (Other):56  

Uma questão interessante emerge para a análise de regressão de dados em painel, em virtude da interação de variáveis individuais (“firm”) com a série temporal (“year”): a elevação da complexidade da análise. Desta forma, várias possibilidades de análise de modelos de regressão surgem, dentre elas:

regressão considerando que o intercepto do modelo e seus coeficientes angulares são constantes ao londo do tempo e no espaço, sendo que o termo de erro capta a diferença no tempo e entre os indivíduos (POOLED);

regressão considerando que os coeficientes angulares são constantes e o intercepto varia entre os indivíduos (EFEITOS FIXOS);

regressão considerando que o intercepto assume um valor médio comum entre os indivíduos e os coeficientes angulares variam ao longo do tempo e também entre indivíduos (EFEITOS ALEATÓRIOS).

Abaixo é demonstrada a evolução do investimento de acordo com cada empresa estudada:
coplot(invest ~ year|firm, type="b", data=Grunfeld)

Modelo Pooled

Este modelo trata de “empilhar” todas as observações da base de dados, ignorando a estrutura de dados em painel. Desta forma, todas as observações são tratadas como não correlacionadas para os indivíduos, com erros homoscedásticos para com os indivíduos. Trata-se, portanto, da forma mais simplista e ingênua pois desconsidera as dimensões de tempo e espaço combinados, ao mesmo tempo que estima a regressão pelo método dos Mínimos Quadrados Ordinários (MQO) (Gujarati e Porter 2011). Desta forma:

\(\begin{matrix} Y_{it} = \beta_1+\beta_2X_{2it} + \beta_3X_{3it} +u_{it}\\ i=1,2,3,4\\ t=1,2,\dots,20 \end{matrix}\)

em que i corresponde à i-nésima unidade de corte transversal e t o t-nésimo período de tempo.

Para executar este modelo de regressão é necessário utilizar a função plm, juntamente com as variáveis dependente e independentes, indicando a base de dados (data) e o tipo da regressão (“pooling”).


reg.pooled=plm(invest~value+capital, 
               data=Grunfeld, model="pooling")
summary(reg.pooled)
Pooling Model

Call:
plm(formula = invest ~ value + capital, data = Grunfeld, model = "pooling")

Balanced Panel: n = 4, T = 20, N = 80

Residuals:
     Min.   1st Qu.    Median   3rd Qu.      Max. 
-319.6766  -99.9523    1.9647   65.9905  336.2072 

Coefficients:
              Estimate Std. Error t-value  Pr(>|t|)    
(Intercept) -62.831841  29.725385 -2.1137   0.03778 *  
value         0.110521   0.013776  8.0230 9.186e-12 ***
capital       0.300463   0.049399  6.0823 4.273e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Total Sum of Squares:    6410400
Residual Sum of Squares: 1572700
R-Squared:      0.75466
Adj. R-Squared: 0.74829
F-statistic: 118.424 on 2 and 77 DF, p-value: < 2.22e-16

A estimação da regressão pooled averiguou alta significância estatística nas variáveis dependentes (“value” e “capital”), indicando sinal positivo para os coeficientes (em consonância com a literatura), bem como um valor de R2 alto. Este tipo de modelo não faz diferenciação entre a influência/diferença das empresas na variável investimento e nem se a resposta do investimento às variáveis explicativas é a mesma ao longo do tempo. Isto faz com que não se saiba se existe heterogeneidade entre as empresas. A comparação do modelo pooled com as regressões de efeitos fixos e efeitos aleatórios, que serão estimados na sequência, servirá mostrar ao pesquisador qual é o melhor modelo dentre eles.

Modelo Efeitos Fixos

O modelo de regressão com efeitos fixos considera, como visto anteriormente, que os valores dos interceptos para cada regressão (\(\alpha_i\)) variam de acordo com o efeito de cada indivíduo (“firma”) e que os coeficientes de declividade (das variáveis independentes “value” e “capital”) para cada equação são os mesmos para cada empresa, conforme equação abaixo:

\(invest_{it} = value_{1it} + capital_{2it} + \alpha_i + \varepsilon_{it}\) em que i=1,…,4, t=1,…,20 (painel balanceado).

Desta forma, o intercepto da equação é diferente para cada empresa, mas o efeito das variáveis independentes é o mesmo sobre a variável independente. Isto indica que existe características especiais em cada empresa influenciando o investimento, como por exemplo o estilo de gestão (Gujarati e Porter 2011).

Abaixo é montada a regressão de efeitos fixos:

reg.ef=plm(invest~value+capital, 
           data=Grunfeld, model="within")
summary(reg.ef)
Oneway (individual) effect Within Model

Call:
plm(formula = invest ~ value + capital, data = Grunfeld, model = "within")

Balanced Panel: n = 4, T = 20, N = 80

Residuals:
     Min.   1st Qu.    Median   3rd Qu.      Max. 
-184.6581  -48.2612    9.3252   40.5471  197.6681 

Coefficients:
        Estimate Std. Error t-value Pr(>|t|)    
value   0.108400   0.017566  6.1711  3.3e-08 ***
capital 0.345058   0.026708 12.9195  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Total Sum of Squares:    2171500
Residual Sum of Squares: 422220
R-Squared:      0.80556
Adj. R-Squared: 0.79242
F-statistic: 153.291 on 2 and 74 DF, p-value: < 2.22e-16

Nota-se que o impacto do valor da empresa (“value”) e do capital (“capital”) é positivo sobre o investimento (“invest”), para todas as empresas como visto acima. Inclusive, há significância estatística para estas variáveis. No entanto, ainda resta definir o efeito dos interceptos de cada empresa, como segue:

summary(fixef(reg.ef))
                 Estimate Std. Error t-value  Pr(>|t|)    
General Motors    -85.515     73.490 -1.1636  0.248310    
US Steel           94.988     36.664  2.5907  0.011530 *  
General Electric -246.228     35.938 -6.8515 1.857e-09 ***
Westinghouse      -59.386     20.233 -2.9351  0.004439 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

com este resultado é possível observar que o efeito das firmas sobre o investimento parece ser diferente para cada indivíduo. Desta forma, somente a empresa US Steel consta com efeito positivo sobre o investimento. Por outo lado, a fórmula da regressão é apresentada de maneira diversa, por exemplo: invest=−85,515+0,108400value+0,345058capital para a regressão considerando a General Motors; invest=94.988+0,108400value+0,345058capital considerando a firma US Steel e assim por diante.

Outra forma de visualizar a equação de efeitos fixos é utilizando a função lm para definir a regressão, definindo a variável “firm” como um fator:

summary(lm(invest~value+capital+as.factor(firm), 
           data=Grunfeld))

Call:
lm(formula = invest ~ value + capital + as.factor(firm), data = Grunfeld)

Residuals:
     Min       1Q   Median       3Q      Max 
-184.658  -48.261    9.325   40.547  197.668 

Coefficients:
                                  Estimate Std. Error t value
(Intercept)                      -85.51533   73.48978  -1.164
value                              0.10840    0.01757   6.171
capital                            0.34506    0.02671  12.919
as.factor(firm)US Steel          180.50295   45.71679   3.948
as.factor(firm)General Electric -160.71218   46.62236  -3.447
as.factor(firm)Westinghouse       26.12959   64.94348   0.402
                                Pr(>|t|)    
(Intercept)                     0.248310    
value                            3.3e-08 ***
capital                          < 2e-16 ***
as.factor(firm)US Steel         0.000178 ***
as.factor(firm)General Electric 0.000938 ***
as.factor(firm)Westinghouse     0.688591    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 75.54 on 74 degrees of freedom
Multiple R-squared:  0.9341,    Adjusted R-squared:  0.9297 
F-statistic: 209.9 on 5 and 74 DF,  p-value: < 2.2e-16

Note que o intercepto definido (-85,51533) refere-se à presença da empresa General Motors. Caso seja evidenciada a presença da empresa US Steel, o valor do intercepto passa para 94,988 (= -85,51533 + 180,50295), a mesma lógica vale para as demais empresas.

Modelo Efeitos Aleatórios

No modelo de regressão com efeitos aleatórios, os efeitos individuais das firmas (“firms”) são considerados variáveis aleatórias, ao contrário do modelo visto anteriormente. Desta forma:

\(Y_{1i}=\beta_{1i}+\beta_2X_{2it}+\beta_3X_{3it}+u_{it}\)

onde β1i é variável aleatória com valor médio β1, e o intercepto para a empresa individual é dado por (Gujarati e Porter 2011):

\(\beta_{1i} = \beta_{1}+\varepsilon_{i} \quad i=1,2,\dots,N\)

em que εi é um termo de erro de média zero e variânvia σ2ε. Assim, as empresas possuem um valor médio para o intercepto (=β1), sendo que as diferenças refletem o termo de erro εi. Obtêm-se:

\(\begin{matrix} Y_{it}=\beta_1+\beta_2X_{2it}+\beta_3X_{3it}+ w_{it}\\ w_{it}=\varepsilon_i+u_{it} \end{matrix}\)

O erro composto wit é formado por εi - elemento de corte transversal dos indivíduos e uit, que é o elemento da série temporal e do corte transversal (Gujarati e Porter 2011). Desta forma, assume-se que os erros individuais não estão correlacionados entre si e também não estão correlacionados entre aquelas unidades de corte transversal e das séries temporais.

A montagem deste tipo de regressão é feita através da função plm, incluindo como modelo “random” e como método “walhus”, como segue:

reg.ea=plm(invest~value+capital,
           data=Grunfeld, model="random", 
           random.method = "walhus")
summary(reg.ea)
Oneway (individual) effect Random Effect Model 
   (Wallace-Hussain's transformation)

Call:
plm(formula = invest ~ value + capital, data = Grunfeld, model = "random", 
    random.method = "walhus")

Balanced Panel: n = 4, T = 20, N = 80

Effects:
                   var  std.dev share
idiosyncratic  5786.52    76.07 0.294
individual    13872.63   117.78 0.706
theta: 0.8571

Residuals:
     Min.   1st Qu.    Median   3rd Qu.      Max. 
-193.8933  -46.1737    1.3543   41.9791  198.1051 

Coefficients:
              Estimate Std. Error z-value  Pr(>|z|)    
(Intercept) -72.632165  68.908322 -1.0540    0.2919    
value         0.107899   0.016658  6.4773 9.339e-11 ***
capital       0.344258   0.026868 12.8128 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Total Sum of Squares:    2258100
Residual Sum of Squares: 446130
R-Squared:      0.80243
Adj. R-Squared: 0.7973
Chisq: 312.731 on 2 DF, p-value: < 2.22e-16

Os resultados corroboram com a direção dos sinais para as variáveis dependentes “value” e “capital”, ambos positivos. Por outro lado, os resultados do modelo de efeitos aleatórios trazem os valores sobre a variância dos erros, primeiramente voltado ao componente de corte transversal (específico dos indivíduos) denominado individual, e outro fator idissiossincrático, o qual varia com o tempo e também com o corte transversal, denominado idiosyncratic.

Comparação e escolha dos modelos

Após a evidenciação dos modelos de regressão dos tipos agrupado (pooled), de efeitos fixos e de efeitos aleatórios, é preciso efetuar os testes para definir qual é o melhor modelo e que por consequência deverá ser considerado.

Modelo Pooled x Modelo de Efeitos Fixos

Inicialmente compara-se o modelo Pooled com a regressão de Efeitos Fixos (within). Para isto utiliza-se o Teste F ou teste F de Chow. A hipótese nula é de que há igualdade nos interceptos e nas inclinações para todos os indivíduos, caracterizando o modelo de dados agrupados (pooled). A função utilizada é pFtest() do pacote plm.

require(plm)
pFtest(reg.ef,reg.pooled)

    F test for individual effects

data:  invest ~ value + capital
F = 67.215, df1 = 3, df2 = 74, p-value < 2.2e-16
alternative hypothesis: significant effects

Como o valor p é inferior a 0,05, o modelo de Efeitos Fixos é melhor do que o modelo Pooled.

Modelo Pooled x Modelo de Efeitos Aleatórios

O teste desenvolvido por Breusch e Pagan (1980) compara as estimativas entre os modelos, verificando se σ2α=0, sendo que:

\(\begin{matrix} H_{0}: \sigma^{2}_{\alpha} = 0 \\ H_{1}: \sigma^{2}_{\alpha} \neq 0 \end{matrix}\)

Desta forma, a aceitação da hipótese nula implica que o modelo de dados agrupados (pooled) é preferível. A função plmtest efetua este teste:

plmtest(reg.pooled, type="bp")

    Lagrange Multiplier Test - (Breusch-Pagan) for balanced
    panels

data:  invest ~ value + capital
chisq = 378.44, df = 1, p-value < 2.2e-16
alternative hypothesis: significant effects

Como o p valor foi inferior a 0,05 o modelo de Efeitos Aleatórios é superior ao modelo Pooled.

Modelo Efeitos Fixos x Modelo de Efeitos Aleatórios

O teste de Hausmann (Hausman 1978) efetua a especificação dos modelos de Efeito Fixo e de Efeitos Aleatórios, sendo que se o teste rejeitar a hipótese nula, o modelo de Efeitos Fixos é o mais adequado.

\(\begin{matrix} H_0: \alpha_{i} \text{ não são correlacionados com } X_{it} \\ H_1: \alpha_{i} \text{ são correlacionados com } X_{it} \end{matrix}\)

A função a ser utilizada para este teste é phtest:

phtest(reg.ef,reg.ea)

    Hausman Test

data:  invest ~ value + capital
chisq = 0.074639, df = 2, p-value = 0.9634
alternative hypothesis: one model is inconsistent

Como o valor p foi superior a 0,05 o modelo de Efeitos Aleatórios foi considerado superior ao modelo de Efeitos Fixos.

Alguns testes para os modelos

Testando dependência transversal (cross-sectional)

A dependência cross-sectional se apresenta em panieis com longas séries de tempo. A hipótese nula é de que os resíduos através dos indivíduos não estão correlacionados. Como resultado, nossa regressão aceita a hipótese nula do teste de Pesaran (2015):

pcdtest(reg.ea, test="cd")

    Pesaran CD test for cross-sectional dependence in panels

data:  invest ~ value + capital
z = 0.30924, p-value = 0.7571
alternative hypothesis: cross-sectional dependence

Normalidade dos resíduos

Segue o já conhecido teste para verificar a normalidade dos resíduos. Como resultado, foi aprovada a hipótese nula (H0 ) de normalidade nos resíduos da regressão.

shapiro.test(reg.ea$residuals)

    Shapiro-Wilk normality test

data:  reg.ea$residuals
W = 0.99198, p-value = 0.9045

Homocedasticidade dos resíduos

Abaixo o teste para homocedasticidade (variância constante) dos resíduos de Breusch-Pagan (1979):

library(lmtest)
bptest(reg.ea)

    studentized Breusch-Pagan test

data:  reg.ea
BP = 7.5567, df = 2, p-value = 0.02286

Como a hipótese nula é a de que não há homocedasticidade nos resíduos e o p-value foi inferior a 0,05, há problemas nos resíduos da regressão, portanto as variáveis apresentam problemas de heterocedasticidade. Algumas soluções são possíveis, como a transformação das variáveis.

Testando correlação serial

A hipótese nula do teste de correlação serial do teste Breusch-Godfrey/Wooldridge (Breusch 1978) é a de que não se encontra esta característica na série. Abaixo o resultado do teste, sendo que aprovou a hipótese nula, ou seja, não há problemas de correlação serial nos dados, pois o p-value é superior a 0,05.

# teste Breusch-Godfrey/Wooldridge - EFEITOS ALEATÓRIOS
pbgtest(reg.ea) 

    Breusch-Godfrey/Wooldridge test for serial correlation in
    panel models

data:  invest ~ value + capital
chisq = 26.17, df = 20, p-value = 0.1603
alternative hypothesis: serial correlation in idiosyncratic errors

Teste para efeitos individuais ou de tempo

Pode ser efetuado o teste para verificar a presença de efeitos não observados de tempo ou individuais nos modelos de dados em painel (Wooldridge 2010). A hipótse nula é a não correlação entre os erros do mesmo grupo. Observa-se que para o efeito tempo (“time”) há aceitação da hipótese alternativa, mostrando a correlação entre erros, ao contrário do efeito individual:

# teste Wooldridge - POOLED
pwtest(reg.pooled) 

    Wooldridge's test for unobserved individual effects

data:  formula
z = 1.4015, p-value = 0.1611
alternative hypothesis: unobserved effect
pwtest(reg.pooled, effect = "time") 

    Wooldridge's test for unobserved time effects

data:  formula
z = -3.2447, p-value = 0.001176
alternative hypothesis: unobserved effect

Testando raízes unitárias

O teste de Dickey-Fuller prova se a série é estocástica, sendo que a hipótese nula é de que a série possui raiz unitária (não-estacionaridade). Abaixo o resultado do teste, sendo que observou-se que a série é não estacionária, ou seja, tem problemas para a regressão pois o p-value aprovou a hipótese nula. Desta forma, algumas saídas são possíveis, como a transformação da série ou mesmo a utilização da primeira diferença da série.

require(tseries)
adf.test(Grunfeld$invest, k=2)

    Augmented Dickey-Fuller Test

data:  Grunfeld$invest
Dickey-Fuller = -3.3705, Lag order = 2, p-value = 0.06629
alternative hypothesis: stationary

Referências

Breusch, Trevor S. 1978. «Testing for autocorrelation in dynamic linear models». Australian Economic Papers 17 (31): 334–55.

Breusch, Trevor S, e Adrian R Pagan. 1979. «A simple test for heteroscedasticity and random coefficient variation». Econometrica: Journal of the Econometric Society, 1287–94.

Breusch, Trevor Stanley, e Adrian Rodney Pagan. 1980. «The Lagrange multiplier test and its applications to model specification in econometrics». The Review of Economic Studies 47 (1): 239–53.

Gujarati, Damodar N., e Down C Porter. 2011. Econometria básica. 5a ed. New York: Mc Graw Hill. https://doi.org/10.1126/science.1186874.

Hausman, Jerry A. 1978. «Specification tests in econometrics». Econometrica: Journal of the econometric society, 1251–71.

Pesaran, M Hashem. 2015. «Testing weak cross-sectional dependence in large panels». Econometric Reviews 34 (6-10): 1089–1117.

Wooldridge, Jeffrey M. 2010. Econometric analysis of cross section and panel data. MIT Press.

LS0tDQp0aXRsZTogJ0V4ZW1wbG8gZGUgUmVncmVzc8OjbyBkZSBkYWRvcyBlbSBwYWluZWwgLSBgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVZIilgJw0KYXV0aG9yOiAnTGVvbmksIFIuIEMuICcNCmVtYWlsOiAicmNsZW9uaUB5YWhvby5jb20uYnIiDQpkYXRlOiAnUmVsYXTDs3JpbyBnZXJhZG8gZW06IGByIGZvcm1hdChTeXMudGltZSgpLCAiJWQgZGUgJUIgZGUgJVkiKWAnDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOiANCiAgICB0aGVtZTogam91cm5hbA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCi0tLQ0KDQojIyBSZWdyZXNzw6NvIGNvbSBEYWRvcyBlbSBQYWluZWwNCg0KICBPIG1vZGVsbyBkZSByZWdyZXNzw6NvIGNvbSBkYWRvcyBlbSBwYWluZWwgcG9zc3VpIHVtYSBjYXJhY3RlcsOtc3RpY2EgZXNwZWNpYWw6IHNlIGNvbnN0aXR1aSBkZSB1bWEgZGltZW5zw6NvIHRlbXBvcmFsIGUgb3V0cmEgZXNwYWNpYWwuIElzdG8gcG9ycXVlIGEgbWVzbWEgdW5pZGFkZSBkZSBjb3J0ZSB0cmFuc3ZlcnNhbCAoZmFtw61saWEsIHBhw61zZXMsIGV0Yy4pIMOpIGFjb21wYW5oYWRhIGFvIGxvbmdvIGRvIHRlbXBvLiBQb3IgZXhlbXBsbywgYSBwcm9kdcOnw6NvIGluZHVzdHJpYWwgbWVuc2FsIGRvcyBFc3RhZG9zIGJyYXNpbGVpcm9zIGVtIGZ1bsOnw6NvIGRhIHRheGEgZGUganVyb3Mgbm8gcGVyw61vZG8gZGUgMjAxNS0yMDE2LiBUw6ptLXNlIGVudMOjbyBhIDYyNCAoMjZ4MjQpIG9ic2VydmHDp8O1ZXMgY29tYmluYWRhczogZGUgY2FkYSB1bSBkb3MgMjYgRXN0YWRvcyAoZXhsdWluZG8gbyBEaXN0cml0byBGZWRlcmFsKSBlIDI0IG9ic2VydmHDp8O1ZXMgcGFyYSBvcyBtZXNlcy4NCg0KICBEZW50cmUgb3MgYmVuZWbDrWNpb3MgZGEgcmVncmVzc8OjbyBjb20gZGFkb3MgZW0gcGFpbmVsIChHdWphcmF0aSBlIFBvcnRlciAyMDExKToNCg0KICAgIERldmlkbyDDoCBoZXRlcm9nZW5laWRhZGUgZGEgYW7DoWxpc2UgZW50cmUgaW5kaXbDrWR1b3MsIGVtcHJlc2FzLCBlc3RhZG9zLCBwYcOtc2VzLCBldGMuLCBlc3RhIHTDqWNuaWNhIHBvZGUgbGV2YXIgZW0gY29udGEgZXN0YXMgdmFyacOhdmVpcyBpbmRpdmlkdWFpcyBlc3BlY8OtZmljYXM7DQoNCiAgICBNYWlvciBpbmZvcm1hw6fDo28sIG1haW9yIHZhcmlhYmlsaWRhZGUgZSBtZW5vciBjb2xpbmVhcmlkYWRlIGVudHJlIHZhcmnDoXZlaXMsIGRldmlkbyDDoCBjb21iaW5hw6fDo29kIGUgc8OpcmllcyB0ZW1wb3JhaXMgZSBkYWRvcyBjb20gY29ydGUgdHJhbnN2ZXJzYWw7DQoNCiAgICBEYWRvcyBlbSBwYWluZWwgc8OjbyBtYWlzIGFkZXF1YWRvcyBhbyBlc3R1ZG8gZGEgZGluw6JtaWNhIGRhIG11ZGFuw6dhIChlbXByZWdvLCByZW5kYSwgZXRjKS4NCg0KICAgIERldGVjdGEgZSBtZWRlIG1lbGhvciBvcyBlZmVpdG9zIGVtIGNvbXBhcmHDp8OjbyBhb3MgZXN0dWRvcyB0cmFuc3ZlcnNhaXMgcHVyb3Mgb3UgZW0gc8OpcmllcyB0ZW1wb3JhaXMgcHVyYXM7DQoNCiAgICBQb3NzaWJpbGlkYWRlIGRlIG1vZGVsb3MgY29tcG9ydGFtZW50YWlzIG1haXMgY29tcGxleG9zOw0KDQogICAgTWluaW1pemHDp8OjbyBkbyB2acOpcyBkZWNvcnJlbnRlIGRhIGFncmVnYcOnw6NvIGRlIHBlc3NvYXMgZS9vdSBlbXByZXNhcyBub3MgZ3JhbmRlcyBjb25qdW50b3MuDQoNCg0KICBBIGJhc2UgZGUgZGFkb3MgdXRpbGl6YWRhIG5lc3RlIGV4ZW1wbG8gKOKAnEdydW5mZWxk4oCdKSDDqSBwcm92ZW5pZW50ZSBkbyBwYWNvdGUgQUVSLiDDiSBjb25zdGl0dcOtZGEgZGEgdmFyacOhdmVsIGRlcGVuZGVudGUgZG8gbsOtdmVsIGRlIGludmVzdGltZW50byAo4oCcaW52ZXN04oCdKSBkZSBkaXZlcnNhcyBlbXByZXNhcyAo4oCcZmlybeKAnSksIGJlbSBjb21vIGRhcyB2YXJpw6F2ZWlzIGV4cGxpY2F0aXZhcyBkZSBzZXUgdmFsb3IgZGUgbWVyY2FkbyAo4oCcdmFsdWXigJ0pIGUgZG8gdmFsb3IgZG8gZXN0b3F1ZSBkZSBjYXBpdGFsICjigJxjYXBpdGFs4oCdKSBkdXJhbnRlIG8gcGVyw61vZG8gZGUgMTkzNS0xOTU0ICgyMCBhbm9zKS4gUG9ydGFudG8gcHJldGVuZGUtc2UgZGVzY29icmlyIG9zIGRldGVybWluYW50ZXMgZG8gdmFsb3IgZG8gbsOtdmVsIGludmVzdGltZW50byBkYXMgZmlybWFzIGR1cmVudGUgbyBwZXLDrW9kby4NCg0KYGBge3J9DQpyZXF1aXJlKEFFUikgDQpkYXRhKEdydW5mZWxkLCBwYWNrYWdlPSJBRVIiKQ0KYGBgDQoNCiAgQXDDs3MgY2FycmVnYWRhIGEgYmFzZSBwYXJhIG8gZXN0dWRvLCBzZXLDo28gc2VsZWNpb25hZGFzIHF1YXRybyBlbXByZXNhcyAo4oCcR2VuZXJhbCBFbGVjdHJpY+KAnSwg4oCcR2VuZXJhbCBNb3RvcnPigJ0sIOKAnFVTIFN0ZWVs4oCdIGUg4oCcV2VzdGluZ2hvdXNl4oCdKSBwYXJhIGZpbnMgZGUgYW7DoWxpc2UgZG9zIGRhZG9zLiBVdGlsaXphLXNlIG8gcGFjb3RlIHBsbSBlIGEgZnVuw6fDo28gcGRhdGEuZnJhbWUgcGFyYSBhbG9jYXIgYSBiYXNlIGRlIGRhZG9zIHBhcmEgYSBhbsOhbGlzZSBkZSByZWdyZXNzw6NvIGRlIGRhZG9zIGVtIHBhaW5lbCwgdW1hIHZleiBxdWUgw6kgbmVjZXNzw6FyaW8gZGVmaW5pciBvIGF0cmlidXRvIGluZGl2aWR1YWwgKOKAnGZpcm3igJ0pIGUgdGVtcG9yYWwgKOKAnHllYXLigJ0pIGRhcyBvYnNlcnZhw6fDtWVzLiBQYXJhIGlzc28gdXRpbGl6YS1zZSBvIGFyZ3VtZW50byBpbmRleCwgY29tbyBzZWd1ZToNCg0KYGBge3J9DQpyZXF1aXJlKHBsbSkNCg0KR3J1bmZlbGQ9c3Vic2V0KEdydW5mZWxkLCBmaXJtICVpbiUgYygiR2VuZXJhbCBFbGVjdHJpYyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHZW5lcmFsIE1vdG9ycyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVUyBTdGVlbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZXN0aW5naG91c2UiKSkNCkdydW5mZWxkPXBkYXRhLmZyYW1lKEdydW5mZWxkLCBpbmRleD1jKCJmaXJtIiwieWVhciIpKQ0KICANCmhlYWQoR3J1bmZlbGQpDQpgYGANCg0KICBOb3NzYSBiYXNlIGRlIGRhZG9zIHBvc3N1aSBpZ3VhbG1lbnRlIDIwIGluZm9ybWHDp8O1ZXMgcGFyYSBjYWRhIGVtcHJlc2EsIHNlIGNvbnN0aXR1aW5kbyBlbSB1bSBwYWluZWwgZXF1aWxpYnJhZG8uIENhc28gbyBuw7ptZXJvIGRlIGluZm9ybWHDp8O1ZXMgcGFyYSBjYWRhIGVtcHJlc2EgZm9zc2VtIGRlc2lndWFpcywgdGVyw61hbW9zIHVtIHBhaW5lbCBkZXNlcXVpbGlicmFkby4NCg0KYGBge3J9DQpzdW1tYXJ5KEdydW5mZWxkKQ0KYGBgDQogICAgICANCiAgVW1hIHF1ZXN0w6NvIGludGVyZXNzYW50ZSBlbWVyZ2UgcGFyYSBhIGFuw6FsaXNlIGRlIHJlZ3Jlc3PDo28gZGUgZGFkb3MgZW0gcGFpbmVsLCBlbSB2aXJ0dWRlIGRhIGludGVyYcOnw6NvIGRlIHZhcmnDoXZlaXMgaW5kaXZpZHVhaXMgKOKAnGZpcm3igJ0pIGNvbSBhIHPDqXJpZSB0ZW1wb3JhbCAo4oCceWVhcuKAnSk6IGEgZWxldmHDp8OjbyBkYSBjb21wbGV4aWRhZGUgZGEgYW7DoWxpc2UuIERlc3RhIGZvcm1hLCB2w6FyaWFzIHBvc3NpYmlsaWRhZGVzIGRlIGFuw6FsaXNlIGRlIG1vZGVsb3MgZGUgcmVncmVzc8OjbyBzdXJnZW0sIGRlbnRyZSBlbGFzOg0KDQogIHJlZ3Jlc3PDo28gY29uc2lkZXJhbmRvIHF1ZSBvIGludGVyY2VwdG8gZG8gbW9kZWxvIGUgc2V1cyBjb2VmaWNpZW50ZXMgYW5ndWxhcmVzIHPDo28gY29uc3RhbnRlcyBhbyBsb25kbyBkbyB0ZW1wbyBlIG5vIGVzcGHDp28sIHNlbmRvIHF1ZSBvIHRlcm1vIGRlIGVycm8gY2FwdGEgYSBkaWZlcmVuw6dhIG5vIHRlbXBvIGUgZW50cmUgb3MgaW5kaXbDrWR1b3MgKFBPT0xFRCk7DQoNCiAgICByZWdyZXNzw6NvIGNvbnNpZGVyYW5kbyBxdWUgb3MgY29lZmljaWVudGVzIGFuZ3VsYXJlcyBzw6NvIGNvbnN0YW50ZXMgZSBvIGludGVyY2VwdG8gdmFyaWEgZW50cmUgb3MgaW5kaXbDrWR1b3MgKEVGRUlUT1MgRklYT1MpOw0KDQogICAgcmVncmVzc8OjbyBjb25zaWRlcmFuZG8gcXVlIG8gaW50ZXJjZXB0byBhc3N1bWUgdW0gdmFsb3IgbcOpZGlvIGNvbXVtIGVudHJlIG9zIGluZGl2w61kdW9zIGUgb3MgY29lZmljaWVudGVzIGFuZ3VsYXJlcyB2YXJpYW0gYW8gbG9uZ28gZG8gdGVtcG8gZSB0YW1iw6ltIGVudHJlIGluZGl2w61kdW9zIChFRkVJVE9TIEFMRUFUw5NSSU9TKS4NCg0KICAgIEFiYWl4byDDqSBkZW1vbnN0cmFkYSBhIGV2b2x1w6fDo28gZG8gaW52ZXN0aW1lbnRvIGRlIGFjb3JkbyBjb20gY2FkYSBlbXByZXNhIGVzdHVkYWRhOg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTJ9DQpjb3Bsb3QoaW52ZXN0IH4geWVhcnxmaXJtLCB0eXBlPSJiIiwgZGF0YT1HcnVuZmVsZCkNCmBgYA0KDQojIyBNb2RlbG8gUG9vbGVkDQoNCkVzdGUgbW9kZWxvIHRyYXRhIGRlIOKAnGVtcGlsaGFy4oCdIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgZGEgYmFzZSBkZSBkYWRvcywgaWdub3JhbmRvIGEgZXN0cnV0dXJhIGRlIGRhZG9zIGVtIHBhaW5lbC4gRGVzdGEgZm9ybWEsIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgc8OjbyB0cmF0YWRhcyBjb21vIG7Do28gY29ycmVsYWNpb25hZGFzIHBhcmEgb3MgaW5kaXbDrWR1b3MsIGNvbSBlcnJvcyBob21vc2NlZMOhc3RpY29zIHBhcmEgY29tIG9zIGluZGl2w61kdW9zLiBUcmF0YS1zZSwgcG9ydGFudG8sIGRhIGZvcm1hIG1haXMgc2ltcGxpc3RhIGUgaW5nw6pudWEgcG9pcyBkZXNjb25zaWRlcmEgYXMgZGltZW5zw7VlcyBkZSB0ZW1wbyBlIGVzcGHDp28gY29tYmluYWRvcywgYW8gbWVzbW8gdGVtcG8gcXVlIGVzdGltYSBhIHJlZ3Jlc3PDo28gcGVsbyBtw6l0b2RvIGRvcyBNw61uaW1vcyBRdWFkcmFkb3MgT3JkaW7DoXJpb3MgKE1RTykgKEd1amFyYXRpIGUgUG9ydGVyIDIwMTEpLiBEZXN0YSBmb3JtYToNCg0KJFxiZWdpbnttYXRyaXh9DQpZX3tpdH0gPSBcYmV0YV8xK1xiZXRhXzJYX3syaXR9ICsgXGJldGFfM1hfezNpdH0gK3Vfe2l0fVxcDQppPTEsMiwzLDRcXA0KdD0xLDIsXGRvdHMsMjANCiBcZW5ke21hdHJpeH0kDQoNCg0KZW0gcXVlIGkgY29ycmVzcG9uZGUgw6AgaS1uw6lzaW1hIHVuaWRhZGUgZGUgY29ydGUgdHJhbnN2ZXJzYWwgZSB0IG8gdC1uw6lzaW1vIHBlcsOtb2RvIGRlIHRlbXBvLg0KDQpQYXJhIGV4ZWN1dGFyIGVzdGUgbW9kZWxvIGRlIHJlZ3Jlc3PDo28gw6kgbmVjZXNzw6FyaW8gdXRpbGl6YXIgYSBmdW7Dp8OjbyBwbG0sIGp1bnRhbWVudGUgY29tIGFzIHZhcmnDoXZlaXMgZGVwZW5kZW50ZSBlIGluZGVwZW5kZW50ZXMsIGluZGljYW5kbyBhIGJhc2UgZGUgZGFkb3MgKGRhdGEpIGUgbyB0aXBvIGRhIHJlZ3Jlc3PDo28gKCJwb29saW5nIikuDQoNCmBgYHtyfQ0KDQpyZWcucG9vbGVkPXBsbShpbnZlc3R+dmFsdWUrY2FwaXRhbCwgDQogICAgICAgICAgICAgICBkYXRhPUdydW5mZWxkLCBtb2RlbD0icG9vbGluZyIpDQpzdW1tYXJ5KHJlZy5wb29sZWQpDQoNCmBgYA0KDQogIEEgZXN0aW1hw6fDo28gZGEgcmVncmVzc8OjbyBwb29sZWQgYXZlcmlndW91IGFsdGEgc2lnbmlmaWPDom5jaWEgZXN0YXTDrXN0aWNhIG5hcyB2YXJpw6F2ZWlzIGRlcGVuZGVudGVzICjigJx2YWx1ZeKAnSBlIOKAnGNhcGl0YWzigJ0pLCBpbmRpY2FuZG8gc2luYWwgcG9zaXRpdm8gcGFyYSBvcyBjb2VmaWNpZW50ZXMgKGVtIGNvbnNvbsOibmNpYSBjb20gYSBsaXRlcmF0dXJhKSwgYmVtIGNvbW8gdW0gdmFsb3IgZGUgUjIgYWx0by4gRXN0ZSB0aXBvIGRlIG1vZGVsbyBuw6NvIGZheiBkaWZlcmVuY2lhw6fDo28gZW50cmUgYSBpbmZsdcOqbmNpYS9kaWZlcmVuw6dhIGRhcyBlbXByZXNhcyBuYSB2YXJpw6F2ZWwgaW52ZXN0aW1lbnRvIGUgbmVtIHNlIGEgcmVzcG9zdGEgZG8gaW52ZXN0aW1lbnRvIMOgcyB2YXJpw6F2ZWlzIGV4cGxpY2F0aXZhcyDDqSBhIG1lc21hIGFvIGxvbmdvIGRvIHRlbXBvLiBJc3RvIGZheiBjb20gcXVlIG7Do28gc2Ugc2FpYmEgc2UgZXhpc3RlIGhldGVyb2dlbmVpZGFkZSBlbnRyZSBhcyBlbXByZXNhcy4gQSBjb21wYXJhw6fDo28gZG8gbW9kZWxvIHBvb2xlZCBjb20gYXMgcmVncmVzc8O1ZXMgZGUgZWZlaXRvcyBmaXhvcyBlIGVmZWl0b3MgYWxlYXTDs3Jpb3MsIHF1ZSBzZXLDo28gZXN0aW1hZG9zIG5hIHNlcXXDqm5jaWEsIHNlcnZpcsOhIG1vc3RyYXIgYW8gcGVzcXVpc2Fkb3IgcXVhbCDDqSBvIG1lbGhvciBtb2RlbG8gZGVudHJlIGVsZXMuDQoNCiMjIE1vZGVsbyBFZmVpdG9zIEZpeG9zDQoNCiAgTyBtb2RlbG8gZGUgcmVncmVzc8OjbyBjb20gZWZlaXRvcyBmaXhvcyBjb25zaWRlcmEsIGNvbW8gdmlzdG8gYW50ZXJpb3JtZW50ZSwgcXVlIG9zIHZhbG9yZXMgZG9zIGludGVyY2VwdG9zIHBhcmEgY2FkYSByZWdyZXNzw6NvICgkXGFscGhhX2kkKSB2YXJpYW0gZGUgYWNvcmRvIGNvbSBvIGVmZWl0byBkZSBjYWRhIGluZGl2w61kdW8gKOKAnGZpcm1h4oCdKSBlIHF1ZSBvcyBjb2VmaWNpZW50ZXMgZGUgZGVjbGl2aWRhZGUgKGRhcyB2YXJpw6F2ZWlzIGluZGVwZW5kZW50ZXMg4oCcdmFsdWXigJ0gZSDigJxjYXBpdGFs4oCdKSBwYXJhIGNhZGEgZXF1YcOnw6NvIHPDo28gb3MgbWVzbW9zIHBhcmEgY2FkYSBlbXByZXNhLCBjb25mb3JtZSBlcXVhw6fDo28gYWJhaXhvOg0KDQoNCiRpbnZlc3Rfe2l0fSA9IHZhbHVlX3sxaXR9ICsgY2FwaXRhbF97Mml0fSArIFxhbHBoYV9pICsgXHZhcmVwc2lsb25fe2l0fSQNCmVtIHF1ZSBpPTEsLi4uLDQsIHQ9MSwuLi4sMjAgKHBhaW5lbCBiYWxhbmNlYWRvKS4NCg0KICBEZXN0YSBmb3JtYSwgbyBpbnRlcmNlcHRvIGRhIGVxdWHDp8OjbyDDqSBkaWZlcmVudGUgcGFyYSBjYWRhIGVtcHJlc2EsIG1hcyBvIGVmZWl0byBkYXMgdmFyacOhdmVpcyBpbmRlcGVuZGVudGVzIMOpIG8gbWVzbW8gc29icmUgYSB2YXJpw6F2ZWwgaW5kZXBlbmRlbnRlLiBJc3RvIGluZGljYSBxdWUgZXhpc3RlIGNhcmFjdGVyw61zdGljYXMgZXNwZWNpYWlzIGVtIGNhZGEgZW1wcmVzYSBpbmZsdWVuY2lhbmRvIG8gaW52ZXN0aW1lbnRvLCBjb21vIHBvciBleGVtcGxvIG8gZXN0aWxvIGRlIGdlc3TDo28gKEd1amFyYXRpIGUgUG9ydGVyIDIwMTEpLg0KDQogIEFiYWl4byDDqSBtb250YWRhIGEgcmVncmVzc8OjbyBkZSBlZmVpdG9zIGZpeG9zOg0KICANCmBgYHtyfQ0KcmVnLmVmPXBsbShpbnZlc3R+dmFsdWUrY2FwaXRhbCwgDQogICAgICAgICAgIGRhdGE9R3J1bmZlbGQsIG1vZGVsPSJ3aXRoaW4iKQ0Kc3VtbWFyeShyZWcuZWYpDQoNCmBgYA0KICAgICAgDQogIE5vdGEtc2UgcXVlIG8gaW1wYWN0byBkbyB2YWxvciBkYSBlbXByZXNhICjigJx2YWx1ZeKAnSkgZSBkbyBjYXBpdGFsICjigJxjYXBpdGFs4oCdKSDDqSBwb3NpdGl2byBzb2JyZSBvIGludmVzdGltZW50byAo4oCcaW52ZXN04oCdKSwgcGFyYSB0b2RhcyBhcyBlbXByZXNhcyBjb21vIHZpc3RvIGFjaW1hLiBJbmNsdXNpdmUsIGjDoSBzaWduaWZpY8OibmNpYSBlc3RhdMOtc3RpY2EgcGFyYSBlc3RhcyB2YXJpw6F2ZWlzLiBObyBlbnRhbnRvLCBhaW5kYSByZXN0YSBkZWZpbmlyIG8gZWZlaXRvIGRvcyBpbnRlcmNlcHRvcyBkZSBjYWRhIGVtcHJlc2EsIGNvbW8gc2VndWU6DQogICAgICANCmBgYHtyfQ0Kc3VtbWFyeShmaXhlZihyZWcuZWYpKQ0KYGBgDQogICAgICANCiAgY29tIGVzdGUgcmVzdWx0YWRvIMOpIHBvc3PDrXZlbCBvYnNlcnZhciBxdWUgbyBlZmVpdG8gZGFzIGZpcm1hcyBzb2JyZSBvIGludmVzdGltZW50byBwYXJlY2Ugc2VyIGRpZmVyZW50ZSBwYXJhIGNhZGEgaW5kaXbDrWR1by4gRGVzdGEgZm9ybWEsIHNvbWVudGUgYSBlbXByZXNhIFVTIFN0ZWVsIGNvbnN0YSBjb20gZWZlaXRvIHBvc2l0aXZvIHNvYnJlIG8gaW52ZXN0aW1lbnRvLiBQb3Igb3V0byBsYWRvLCBhIGbDs3JtdWxhIGRhIHJlZ3Jlc3PDo28gw6kgYXByZXNlbnRhZGEgZGUgbWFuZWlyYSBkaXZlcnNhLCBwb3IgZXhlbXBsbzogaW52ZXN0PeKIkjg1LDUxNSswLDEwODQwMHZhbHVlKzAsMzQ1MDU4Y2FwaXRhbCBwYXJhIGEgcmVncmVzc8OjbyBjb25zaWRlcmFuZG8gYSBHZW5lcmFsIE1vdG9yczsgaW52ZXN0PTk0Ljk4OCswLDEwODQwMHZhbHVlKzAsMzQ1MDU4Y2FwaXRhbCBjb25zaWRlcmFuZG8gYSBmaXJtYSBVUyBTdGVlbCBlIGFzc2ltIHBvciBkaWFudGUuDQoNCiAgT3V0cmEgZm9ybWEgZGUgdmlzdWFsaXphciBhIGVxdWHDp8OjbyBkZSBlZmVpdG9zIGZpeG9zIMOpIHV0aWxpemFuZG8gYSBmdW7Dp8OjbyBsbSBwYXJhIGRlZmluaXIgYSByZWdyZXNzw6NvLCBkZWZpbmluZG8gYSB2YXJpw6F2ZWwg4oCcZmlybeKAnSBjb21vIHVtIGZhdG9yOg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbShpbnZlc3R+dmFsdWUrY2FwaXRhbCthcy5mYWN0b3IoZmlybSksIA0KICAgICAgICAgICBkYXRhPUdydW5mZWxkKSkNCmBgYA0KDQogIE5vdGUgcXVlIG8gaW50ZXJjZXB0byBkZWZpbmlkbyAoLTg1LDUxNTMzKSByZWZlcmUtc2Ugw6AgcHJlc2Vuw6dhIGRhIGVtcHJlc2EgR2VuZXJhbCBNb3RvcnMuIENhc28gc2VqYSBldmlkZW5jaWFkYSBhIHByZXNlbsOnYSBkYSBlbXByZXNhIFVTIFN0ZWVsLCBvIHZhbG9yIGRvIGludGVyY2VwdG8gcGFzc2EgcGFyYSA5NCw5ODggKD0gLTg1LDUxNTMzICsgMTgwLDUwMjk1KSwgYSBtZXNtYSBsw7NnaWNhIHZhbGUgcGFyYSBhcyBkZW1haXMgZW1wcmVzYXMuDQogICAgDQogICAgDQojIyBNb2RlbG8gRWZlaXRvcyBBbGVhdMOzcmlvcw0KDQpObyBtb2RlbG8gZGUgcmVncmVzc8OjbyBjb20gZWZlaXRvcyBhbGVhdMOzcmlvcywgb3MgZWZlaXRvcyBpbmRpdmlkdWFpcyBkYXMgZmlybWFzICjigJxmaXJtc+KAnSkgc8OjbyBjb25zaWRlcmFkb3MgdmFyacOhdmVpcyBhbGVhdMOzcmlhcywgYW8gY29udHLDoXJpbyBkbyBtb2RlbG8gdmlzdG8gYW50ZXJpb3JtZW50ZS4gRGVzdGEgZm9ybWE6DQoNCiRZX3sxaX09XGJldGFfezFpfStcYmV0YV8yWF97Mml0fStcYmV0YV8zWF97M2l0fSt1X3tpdH0kDQoNCm9uZGUgzrIxaSDDqSB2YXJpw6F2ZWwgYWxlYXTDs3JpYSBjb20gdmFsb3IgbcOpZGlvIM6yMSwgZSBvIGludGVyY2VwdG8gcGFyYSBhIGVtcHJlc2EgaW5kaXZpZHVhbCDDqSBkYWRvIHBvciAoR3VqYXJhdGkgZSBQb3J0ZXIgMjAxMSk6DQoNCiRcYmV0YV97MWl9ID0gXGJldGFfezF9K1x2YXJlcHNpbG9uX3tpfSBccXVhZCBpPTEsMixcZG90cyxOJA0KDQplbSBxdWUgzrVpIMOpIHVtIHRlcm1vIGRlIGVycm8gZGUgbcOpZGlhIHplcm8gZSB2YXJpw6JudmlhIM+DMs61LiBBc3NpbSwgYXMgZW1wcmVzYXMgcG9zc3VlbSB1bSB2YWxvciBtw6lkaW8gcGFyYSBvIGludGVyY2VwdG8gKD3OsjEpLCBzZW5kbyBxdWUgYXMgZGlmZXJlbsOnYXMgcmVmbGV0ZW0gbyB0ZXJtbyBkZSBlcnJvIM61aS4gT2J0w6ptLXNlOg0KDQokXGJlZ2lue21hdHJpeH0NCllfe2l0fT1cYmV0YV8xK1xiZXRhXzJYX3syaXR9K1xiZXRhXzNYX3szaXR9KyB3X3tpdH1cXA0Kd197aXR9PVx2YXJlcHNpbG9uX2krdV97aXR9DQogXGVuZHttYXRyaXh9JA0KDQogIE8gZXJybyBjb21wb3N0byB3aXQgw6kgZm9ybWFkbyBwb3IgzrVpIC0gZWxlbWVudG8gZGUgY29ydGUgdHJhbnN2ZXJzYWwgZG9zIGluZGl2w61kdW9zIGUgdWl0LCBxdWUgw6kgbyBlbGVtZW50byBkYSBzw6lyaWUgdGVtcG9yYWwgZSBkbyBjb3J0ZSB0cmFuc3ZlcnNhbCAoR3VqYXJhdGkgZSBQb3J0ZXIgMjAxMSkuIERlc3RhIGZvcm1hLCBhc3N1bWUtc2UgcXVlIG9zIGVycm9zIGluZGl2aWR1YWlzIG7Do28gZXN0w6NvIGNvcnJlbGFjaW9uYWRvcyBlbnRyZSBzaSBlIHRhbWLDqW0gbsOjbyBlc3TDo28gY29ycmVsYWNpb25hZG9zIGVudHJlIGFxdWVsYXMgdW5pZGFkZXMgZGUgY29ydGUgdHJhbnN2ZXJzYWwgZSBkYXMgc8OpcmllcyB0ZW1wb3JhaXMuDQoNCiAgQSBtb250YWdlbSBkZXN0ZSB0aXBvIGRlIHJlZ3Jlc3PDo28gw6kgZmVpdGEgYXRyYXbDqXMgZGEgZnVuw6fDo28gcGxtLCBpbmNsdWluZG8gY29tbyBtb2RlbG8g4oCccmFuZG9t4oCdIGUgY29tbyBtw6l0b2RvIOKAnHdhbGh1c+KAnSwgY29tbyBzZWd1ZToNCg0KYGBge3J9DQpyZWcuZWE9cGxtKGludmVzdH52YWx1ZStjYXBpdGFsLA0KICAgICAgICAgICBkYXRhPUdydW5mZWxkLCBtb2RlbD0icmFuZG9tIiwgDQogICAgICAgICAgIHJhbmRvbS5tZXRob2QgPSAid2FsaHVzIikNCnN1bW1hcnkocmVnLmVhKQ0KYGBgDQogICAgDQogIE9zIHJlc3VsdGFkb3MgY29ycm9ib3JhbSBjb20gYSBkaXJlw6fDo28gZG9zIHNpbmFpcyBwYXJhIGFzIHZhcmnDoXZlaXMgZGVwZW5kZW50ZXMg4oCcdmFsdWXigJ0gZSDigJxjYXBpdGFs4oCdLCBhbWJvcyBwb3NpdGl2b3MuIFBvciBvdXRybyBsYWRvLCBvcyByZXN1bHRhZG9zIGRvIG1vZGVsbyBkZSBlZmVpdG9zIGFsZWF0w7NyaW9zIHRyYXplbSBvcyB2YWxvcmVzIHNvYnJlIGEgdmFyacOibmNpYSBkb3MgZXJyb3MsIHByaW1laXJhbWVudGUgdm9sdGFkbyBhbyBjb21wb25lbnRlIGRlIGNvcnRlIHRyYW5zdmVyc2FsIChlc3BlY8OtZmljbyBkb3MgaW5kaXbDrWR1b3MpIGRlbm9taW5hZG8gaW5kaXZpZHVhbCwgZSBvdXRybyBmYXRvciBpZGlzc2lvc3NpbmNyw6F0aWNvLCBvIHF1YWwgdmFyaWEgY29tIG8gdGVtcG8gZSB0YW1iw6ltIGNvbSBvIGNvcnRlIHRyYW5zdmVyc2FsLCBkZW5vbWluYWRvIGlkaW9zeW5jcmF0aWMuICAgIA0KICAgIA0KDQojIyBDb21wYXJhw6fDo28gZSBlc2NvbGhhIGRvcyBtb2RlbG9zDQoNCiAgQXDDs3MgYSBldmlkZW5jaWHDp8OjbyBkb3MgbW9kZWxvcyBkZSByZWdyZXNzw6NvIGRvcyB0aXBvcyBhZ3J1cGFkbyAocG9vbGVkKSwgZGUgZWZlaXRvcyBmaXhvcyBlIGRlIGVmZWl0b3MgYWxlYXTDs3Jpb3MsIMOpIHByZWNpc28gZWZldHVhciBvcyB0ZXN0ZXMgcGFyYSBkZWZpbmlyIHF1YWwgw6kgbyBtZWxob3IgbW9kZWxvIGUgcXVlIHBvciBjb25zZXF1w6puY2lhIGRldmVyw6Egc2VyIGNvbnNpZGVyYWRvLg0KDQojIyAgTW9kZWxvIFBvb2xlZCB4IE1vZGVsbyBkZSBFZmVpdG9zIEZpeG9zDQoNCiAgSW5pY2lhbG1lbnRlIGNvbXBhcmEtc2UgbyBtb2RlbG8gUG9vbGVkIGNvbSBhIHJlZ3Jlc3PDo28gZGUgRWZlaXRvcyBGaXhvcyAod2l0aGluKS4gUGFyYSBpc3RvIHV0aWxpemEtc2UgbyBUZXN0ZSBGIG91IHRlc3RlIEYgZGUgQ2hvdy4gQSBoaXDDs3Rlc2UgbnVsYSDDqSBkZSBxdWUgaMOhIGlndWFsZGFkZSBub3MgaW50ZXJjZXB0b3MgZSBuYXMgaW5jbGluYcOnw7VlcyBwYXJhIHRvZG9zIG9zIGluZGl2w61kdW9zLCBjYXJhY3Rlcml6YW5kbyBvIG1vZGVsbyBkZSBkYWRvcyBhZ3J1cGFkb3MgKHBvb2xlZCkuIEEgZnVuw6fDo28gdXRpbGl6YWRhIMOpIHBGdGVzdCgpIGRvIHBhY290ZSBwbG0uDQoNCmBgYHtyfQ0KcmVxdWlyZShwbG0pDQpwRnRlc3QocmVnLmVmLHJlZy5wb29sZWQpDQpgYGANCiAgDQogIENvbW8gbyB2YWxvciBwIMOpIGluZmVyaW9yIGEgMCwwNSwgbyBtb2RlbG8gZGUgRWZlaXRvcyBGaXhvcyDDqSBtZWxob3IgZG8gcXVlIG8gbW9kZWxvIFBvb2xlZC4NCiAgICANCiAgICANCiAgICANCiMjICAgIE1vZGVsbyBQb29sZWQgeCBNb2RlbG8gZGUgRWZlaXRvcyBBbGVhdMOzcmlvcw0KDQogIE8gdGVzdGUgZGVzZW52b2x2aWRvIHBvciBCcmV1c2NoIGUgUGFnYW4gKDE5ODApIGNvbXBhcmEgYXMgZXN0aW1hdGl2YXMgZW50cmUgb3MgbW9kZWxvcywgdmVyaWZpY2FuZG8gc2Ugz4MyzrE9MCwgc2VuZG8gcXVlOg0KDQokXGJlZ2lue21hdHJpeH0NCkhfezB9OiBcc2lnbWFeezJ9X3tcYWxwaGF9ID0gMCBcXA0KSF97MX06IFxzaWdtYV57Mn1fe1xhbHBoYX0gXG5lcSAwDQogXGVuZHttYXRyaXh9JA0KDQogIERlc3RhIGZvcm1hLCBhIGFjZWl0YcOnw6NvIGRhIGhpcMOzdGVzZSBudWxhIGltcGxpY2EgcXVlIG8gbW9kZWxvIGRlIGRhZG9zIGFncnVwYWRvcyAocG9vbGVkKSDDqSBwcmVmZXLDrXZlbC4gQSBmdW7Dp8OjbyBwbG10ZXN0IGVmZXR1YSBlc3RlIHRlc3RlOg0KDQpgYGB7cn0NCnBsbXRlc3QocmVnLnBvb2xlZCwgdHlwZT0iYnAiKQ0KYGBgDQpDb21vIG8gcCB2YWxvciBmb2kgaW5mZXJpb3IgYSAwLDA1IG8gbW9kZWxvIGRlIEVmZWl0b3MgQWxlYXTDs3Jpb3Mgw6kgc3VwZXJpb3IgYW8gbW9kZWxvIFBvb2xlZC4NCg0KIyMgTW9kZWxvIEVmZWl0b3MgRml4b3MgeCBNb2RlbG8gZGUgRWZlaXRvcyBBbGVhdMOzcmlvcw0KDQoNCiAgTyB0ZXN0ZSBkZSBIYXVzbWFubiAoSGF1c21hbiAxOTc4KSBlZmV0dWEgYSBlc3BlY2lmaWNhw6fDo28gZG9zIG1vZGVsb3MgZGUgRWZlaXRvIEZpeG8gZSBkZSBFZmVpdG9zIEFsZWF0w7NyaW9zLCBzZW5kbyBxdWUgc2UgbyB0ZXN0ZSByZWplaXRhciBhIGhpcMOzdGVzZSBudWxhLCBvIG1vZGVsbyBkZSBFZmVpdG9zIEZpeG9zIMOpIG8gbWFpcyBhZGVxdWFkby4NCg0KJFxiZWdpbnttYXRyaXh9DQpIXzA6IFxhbHBoYV97aX0gXHRleHR7IG7Do28gc8OjbyBjb3JyZWxhY2lvbmFkb3MgY29tIH0gWF97aXR9IFxcDQpIXzE6IFxhbHBoYV97aX0gXHRleHR7IHPDo28gY29ycmVsYWNpb25hZG9zIGNvbSB9IFhfe2l0fQ0KIFxlbmR7bWF0cml4fSQNCg0KQSBmdW7Dp8OjbyBhIHNlciB1dGlsaXphZGEgcGFyYSBlc3RlIHRlc3RlIMOpIHBodGVzdDoNCg0KYGBge3J9DQpwaHRlc3QocmVnLmVmLHJlZy5lYSkNCmBgYA0KICAgIA0KQ29tbyBvIHZhbG9yIHAgZm9pIHN1cGVyaW9yIGEgMCwwNSBvIG1vZGVsbyBkZSBFZmVpdG9zIEFsZWF0w7NyaW9zIGZvaSBjb25zaWRlcmFkbyBzdXBlcmlvciBhbyBtb2RlbG8gZGUgRWZlaXRvcyBGaXhvcy4NCiAgICANCiAgICANCiMjICAgIEFsZ3VucyB0ZXN0ZXMgcGFyYSBvcyBtb2RlbG9zDQogICAgDQojIyBUZXN0YW5kbyBkZXBlbmTDqm5jaWEgdHJhbnN2ZXJzYWwgKGNyb3NzLXNlY3Rpb25hbCkNCg0KQSBkZXBlbmTDqm5jaWEgY3Jvc3Mtc2VjdGlvbmFsIHNlIGFwcmVzZW50YSBlbSBwYW5pZWlzIGNvbSBsb25nYXMgc8OpcmllcyBkZSB0ZW1wby4gQSBoaXDDs3Rlc2UgbnVsYSDDqSBkZSBxdWUgb3MgcmVzw61kdW9zIGF0cmF2w6lzIGRvcyBpbmRpdsOtZHVvcyBuw6NvIGVzdMOjbyBjb3JyZWxhY2lvbmFkb3MuIENvbW8gcmVzdWx0YWRvLCBub3NzYSByZWdyZXNzw6NvIGFjZWl0YSBhIGhpcMOzdGVzZSBudWxhIGRvIHRlc3RlIGRlIFBlc2FyYW4gKDIwMTUpOg0KDQpgYGB7cn0NCnBjZHRlc3QocmVnLmVhLCB0ZXN0PSJjZCIpDQpgYGANCiAgICANCiMjICAgTm9ybWFsaWRhZGUgZG9zIHJlc8OtZHVvcw0KDQpTZWd1ZSBvIGrDoSBjb25oZWNpZG8gdGVzdGUgcGFyYSB2ZXJpZmljYXIgYSBub3JtYWxpZGFkZSBkb3MgcmVzw61kdW9zLiBDb21vIHJlc3VsdGFkbywgZm9pIGFwcm92YWRhIGEgaGlww7N0ZXNlIG51bGEgKEgwDQopIGRlIG5vcm1hbGlkYWRlIG5vcyByZXPDrWR1b3MgZGEgcmVncmVzc8Ojby4NCg0KYGBge3J9DQpzaGFwaXJvLnRlc3QocmVnLmVhJHJlc2lkdWFscykNCmBgYA0KDQojIyBIb21vY2VkYXN0aWNpZGFkZSBkb3MgcmVzw61kdW9zDQoNCkFiYWl4byBvIHRlc3RlIHBhcmEgaG9tb2NlZGFzdGljaWRhZGUgKHZhcmnDom5jaWEgY29uc3RhbnRlKSBkb3MgcmVzw61kdW9zIGRlIEJyZXVzY2gtUGFnYW4gKDE5NzkpOg0KDQpgYGB7cn0NCmxpYnJhcnkobG10ZXN0KQ0KYnB0ZXN0KHJlZy5lYSkNCmBgYA0KICAgICAgDQogICBDb21vIGEgaGlww7N0ZXNlIG51bGEgw6kgYSBkZSBxdWUgbsOjbyBow6EgaG9tb2NlZGFzdGljaWRhZGUgbm9zIHJlc8OtZHVvcyBlIG8gcC12YWx1ZSBmb2kgaW5mZXJpb3IgYSAwLDA1LCBow6EgcHJvYmxlbWFzIG5vcyByZXPDrWR1b3MgZGEgcmVncmVzc8OjbywgcG9ydGFudG8gYXMgdmFyacOhdmVpcyBhcHJlc2VudGFtIHByb2JsZW1hcyBkZSBoZXRlcm9jZWRhc3RpY2lkYWRlLiBBbGd1bWFzIHNvbHXDp8O1ZXMgc8OjbyBwb3Nzw612ZWlzLCBjb21vIGEgdHJhbnNmb3JtYcOnw6NvIGRhcyB2YXJpw6F2ZWlzLg0KDQoNCiMjIFRlc3RhbmRvIGNvcnJlbGHDp8OjbyBzZXJpYWwNCg0KICBBIGhpcMOzdGVzZSBudWxhIGRvIHRlc3RlIGRlIGNvcnJlbGHDp8OjbyBzZXJpYWwgZG8gdGVzdGUgQnJldXNjaC1Hb2RmcmV5L1dvb2xkcmlkZ2UgKEJyZXVzY2ggMTk3OCkgw6kgYSBkZSBxdWUgbsOjbyBzZSBlbmNvbnRyYSBlc3RhIGNhcmFjdGVyw61zdGljYSBuYSBzw6lyaWUuIEFiYWl4byBvIHJlc3VsdGFkbyBkbyB0ZXN0ZSwgc2VuZG8gcXVlIGFwcm92b3UgYSBoaXDDs3Rlc2UgbnVsYSwgb3Ugc2VqYSwgbsOjbyBow6EgcHJvYmxlbWFzIGRlIGNvcnJlbGHDp8OjbyBzZXJpYWwgbm9zIGRhZG9zLCBwb2lzIG8gcC12YWx1ZSDDqSBzdXBlcmlvciBhIDAsMDUuDQoNCmBgYHtyfQ0KIyB0ZXN0ZSBCcmV1c2NoLUdvZGZyZXkvV29vbGRyaWRnZSAtIEVGRUlUT1MgQUxFQVTDk1JJT1MNCnBiZ3Rlc3QocmVnLmVhKSANCmBgYA0KDQoNCiMjIFRlc3RlIHBhcmEgZWZlaXRvcyBpbmRpdmlkdWFpcyBvdSBkZSB0ZW1wbw0KDQogICBQb2RlIHNlciBlZmV0dWFkbyBvIHRlc3RlIHBhcmEgdmVyaWZpY2FyIGEgcHJlc2Vuw6dhIGRlIGVmZWl0b3MgbsOjbyBvYnNlcnZhZG9zIGRlIHRlbXBvIG91IGluZGl2aWR1YWlzIG5vcyBtb2RlbG9zIGRlIGRhZG9zIGVtIHBhaW5lbCAoV29vbGRyaWRnZSAyMDEwKS4gQSBoaXDDs3RzZSBudWxhIMOpIGEgbsOjbyBjb3JyZWxhw6fDo28gZW50cmUgb3MgZXJyb3MgZG8gbWVzbW8gZ3J1cG8uIE9ic2VydmEtc2UgcXVlIHBhcmEgbyBlZmVpdG8gdGVtcG8gKOKAnHRpbWXigJ0pIGjDoSBhY2VpdGHDp8OjbyBkYSBoaXDDs3Rlc2UgYWx0ZXJuYXRpdmEsIG1vc3RyYW5kbyBhIGNvcnJlbGHDp8OjbyBlbnRyZSBlcnJvcywgYW8gY29udHLDoXJpbyBkbyBlZmVpdG8gaW5kaXZpZHVhbDoNCg0KDQpgYGB7cn0NCiMgdGVzdGUgV29vbGRyaWRnZSAtIFBPT0xFRA0KcHd0ZXN0KHJlZy5wb29sZWQpIA0KcHd0ZXN0KHJlZy5wb29sZWQsIGVmZmVjdCA9ICJ0aW1lIikgDQpgYGANCg0KDQojIyBUZXN0YW5kbyByYcOtemVzIHVuaXTDoXJpYXMNCg0KICBPIHRlc3RlIGRlIERpY2tleS1GdWxsZXIgcHJvdmEgc2UgYSBzw6lyaWUgw6kgZXN0b2PDoXN0aWNhLCBzZW5kbyBxdWUgYSBoaXDDs3Rlc2UgbnVsYSDDqSBkZSBxdWUgYSBzw6lyaWUgcG9zc3VpIHJhaXogdW5pdMOhcmlhIChuw6NvLWVzdGFjaW9uYXJpZGFkZSkuIEFiYWl4byBvIHJlc3VsdGFkbyBkbyB0ZXN0ZSwgc2VuZG8gcXVlIG9ic2Vydm91LXNlIHF1ZSBhIHPDqXJpZSDDqSBuw6NvIGVzdGFjaW9uw6FyaWEsIG91IHNlamEsIHRlbSBwcm9ibGVtYXMgcGFyYSBhIHJlZ3Jlc3PDo28gcG9pcyBvIHAtdmFsdWUgYXByb3ZvdSBhIGhpcMOzdGVzZSBudWxhLiBEZXN0YSBmb3JtYSwgYWxndW1hcyBzYcOtZGFzIHPDo28gcG9zc8OtdmVpcywgY29tbyBhIHRyYW5zZm9ybWHDp8OjbyBkYSBzw6lyaWUgb3UgbWVzbW8gYSB1dGlsaXphw6fDo28gZGEgcHJpbWVpcmEgZGlmZXJlbsOnYSBkYSBzw6lyaWUuDQoNCg0KYGBge3J9DQpyZXF1aXJlKHRzZXJpZXMpDQphZGYudGVzdChHcnVuZmVsZCRpbnZlc3QsIGs9MikNCmBgYA0KDQoNCg0KDQojIyBSZWZlcsOqbmNpYXMNCg0KQnJldXNjaCwgVHJldm9yIFMuIDE5NzguIMKrVGVzdGluZyBmb3IgYXV0b2NvcnJlbGF0aW9uIGluIGR5bmFtaWMgbGluZWFyIG1vZGVsc8K7LiBBdXN0cmFsaWFuIEVjb25vbWljIFBhcGVycyAxNyAoMzEpOiAzMzTigJM1NS4NCg0KQnJldXNjaCwgVHJldm9yIFMsIGUgQWRyaWFuIFIgUGFnYW4uIDE5NzkuIMKrQSBzaW1wbGUgdGVzdCBmb3IgaGV0ZXJvc2NlZGFzdGljaXR5IGFuZCByYW5kb20gY29lZmZpY2llbnQgdmFyaWF0aW9uwrsuIEVjb25vbWV0cmljYTogSm91cm5hbCBvZiB0aGUgRWNvbm9tZXRyaWMgU29jaWV0eSwgMTI4N+KAkzk0Lg0KDQpCcmV1c2NoLCBUcmV2b3IgU3RhbmxleSwgZSBBZHJpYW4gUm9kbmV5IFBhZ2FuLiAxOTgwLiDCq1RoZSBMYWdyYW5nZSBtdWx0aXBsaWVyIHRlc3QgYW5kIGl0cyBhcHBsaWNhdGlvbnMgdG8gbW9kZWwgc3BlY2lmaWNhdGlvbiBpbiBlY29ub21ldHJpY3PCuy4gVGhlIFJldmlldyBvZiBFY29ub21pYyBTdHVkaWVzIDQ3ICgxKTogMjM54oCTNTMuDQoNCkd1amFyYXRpLCBEYW1vZGFyIE4uLCBlIERvd24gQyBQb3J0ZXIuIDIwMTEuIEVjb25vbWV0cmlhIGLDoXNpY2EuIDVhIGVkLiBOZXcgWW9yazogTWMgR3JhdyBIaWxsLiBodHRwczovL2RvaS5vcmcvMTAuMTEyNi9zY2llbmNlLjExODY4NzQuDQoNCkhhdXNtYW4sIEplcnJ5IEEuIDE5NzguIMKrU3BlY2lmaWNhdGlvbiB0ZXN0cyBpbiBlY29ub21ldHJpY3PCuy4gRWNvbm9tZXRyaWNhOiBKb3VybmFsIG9mIHRoZSBlY29ub21ldHJpYyBzb2NpZXR5LCAxMjUx4oCTNzEuDQoNClBlc2FyYW4sIE0gSGFzaGVtLiAyMDE1LiDCq1Rlc3Rpbmcgd2VhayBjcm9zcy1zZWN0aW9uYWwgZGVwZW5kZW5jZSBpbiBsYXJnZSBwYW5lbHPCuy4gRWNvbm9tZXRyaWMgUmV2aWV3cyAzNCAoNi0xMCk6IDEwODnigJMxMTE3Lg0KDQpXb29sZHJpZGdlLCBKZWZmcmV5IE0uIDIwMTAuIEVjb25vbWV0cmljIGFuYWx5c2lzIG9mIGNyb3NzIHNlY3Rpb24gYW5kIHBhbmVsIGRhdGEuIE1JVCBQcmVzcy4NCg0KDQoNCg0KDQoNCg==