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. Econometria em Python: Tabela 5.6 PNB e demanda de moeda, Gujarati e Porter (2011, p.157). Campo Grande-MS,Brasil: RStudio/Rpubs, 2022. Disponível em http://rpubs.com/amrofi/Gujarati_tab5_6_python.

1 Introdução

Esse post é semelhante ao que uso no video do Youtube em: https://youtu.be/lpni-E1PAbU, ECONOMETRIA 2020.2 Slides 02a Instalação R e RStudio. Mas nesse caso trabalharei o código em Python.

Os primeiros passos são criar ou abrir um diretório de trabalho. Se optar por criar um novo projeto, haverá a possibilidade de criar em uma pasta vazia. Em seguida, sugere-se que coloque os dados nesta pasta, se possível em um arquivo MS Excel e chame a planilha de ‘dados’.Neste caso, a planilha chama-se Tabela 5.6aula_gujarati 5ed p157.xlsx.

A Tabela 5.6 apresenta dados sobre o PNB e quatro definições do estoque de moeda dos Estados Unidos no período 1970-1983. Fazendo as regressões do PNB contra as várias definições de moeda, obtemos os resultados apresentados na Tabela 5.7. Os monetaristas ou adeptos da teoria quantitativa afirmam que a renda nominal (o PNB nominal) é determinada, em grande parte, pela variação na quantidade ou estoque de moeda, embora não haja consenso quanto à definição “certa” de moeda. De acordo com os resultados, responda às seguintes perguntas:
a. Que definição de moeda parece apresentar relação mais estreita com o PNB nominal?
b. Como os \(R^2\) são todos elevados, isso significa que a escolha da definição de moeda não tem importância?
c. Se o FED (Banco Central dos Estados Unidos) quer controlar a oferta de moeda, qual desses indicadores de moeda seria o melhor objetivo para esse fim? Isso pode ser dito com base nos resultados da regressão?

Exercício para os dados da tabela 5.6, conforme Gujarati (2011, p.157), PNB e estoque de moeda segundo quatro critérios, Estados Unidos, 1970-1983.

Usarei o pacote reticulate em um primeiro chunk em R, para depois rodar chunks em python dentro do RStudio.

# chunk em R
library(reticulate)
# py_install('openpyxl') # para instalar pacote openpyxl se acusar avisos de
# nova versao do conda, abrir o Terminal e executar como abaixo conda update -n
# base -c defaults conda

Coloco aqui a opção de download do xlsx mas coloquei os dados embeded no code para quem quiser. É só executar o chunk a seguir que conseguem carregar os dados.

# chunk em python
# atualizar o caminho do arquivo xlsx a ser lido
import pandas as pd
# precisei instalar openpyxl (para xlsx) e xlrd (para xls)
# neste caso, os dados estão na sheet 'dados'
df = pd.read_excel (r'E:\disciplinas\econometria\laboratorio_Python\demanda_moeda_gujarati_tab5-6\Tabela 5.6aula_gujarati 5ed p157.xlsx', sheet_name='dados')
# exibir dados e checar se vieram corretamente
print (df[["ANO" , "PNB" , "M1" , "M2" , "M3","L"]])
     ANO     PNB     M1      M2      M3       L
0   1970   992.7  216.6   628.2   677.5   816.3
1   1971  1077.6  230.8   712.8   776.2   903.1
2   1972  1185.9  252.0   805.2   886.0  1023.0
3   1973  1326.4  265.9   861.0   985.0  1141.7
4   1974  1434.2  277.6   908.5  1070.5  1249.3
5   1975  1549.2  291.2  1023.3  1174.2  1367.9
6   1976  1718.0  310.4  1163.6  1311.9  1516.6
7   1977  1918.3  335.4  1286.7  1472.9  1704.7
8   1978  2163.9  363.1  1389.1  1647.1  1910.6
9   1979  2417.8  389.1  1498.5  1804.8  2117.1
10  1980  2631.7  414.9  1632.6  1990.0  2326.2
11  1981  2957.8  441.9  1796.6  2238.2  2599.8
12  1982  3069.3  480.5  1965.4  2462.5  2870.8
13  1983  3304.8  525.4  2196.3  2710.4  3183.1

Portanto, temos 14 observações para 6 variáveis dentro do DataFrame de 14 linhas e 6 colunas. Podemos extrair a estrutura dos dados fazendo o código semelhante ao dput do R (link).

#data_as_dict= print(df.to_dict())
#df = pd.DataFrame.from_dict(data_as_dict)
df = pd.DataFrame.from_dict({'ANO': {0: 1970, 1: 1971, 2: 1972, 3: 1973, 4: 1974, 5: 1975, 6: 1976, 7: 1977, 8: 1978, 9: 1979, 10: 1980, 11: 1981, 12: 1982, 13: 1983}, 'PNB': {0: 992.7, 1: 1077.6, 2: 1185.9, 3: 1326.4, 4: 1434.2, 5: 1549.2, 6: 1718.0, 7: 1918.3, 8: 2163.9, 9: 2417.8, 10: 2631.7, 11: 2957.8, 12: 3069.3, 13: 3304.8}, 'M1': {0: 216.6, 1: 230.8, 2: 252.0, 3: 265.9, 4: 277.6, 5: 291.2, 6: 310.4, 7: 335.4, 8: 363.1, 9: 389.1, 10: 414.9, 11: 441.9, 12: 480.5, 13: 525.4}, 'M2': {0: 628.2, 1: 712.8, 2: 805.2, 3: 861.0, 4: 908.5, 5: 1023.3, 6: 1163.6, 7: 1286.7, 8: 1389.1, 9: 1498.5, 10: 1632.6, 11: 1796.6, 12: 1965.4, 13: 2196.3}, 'M3': {0: 677.5, 1: 776.2, 2: 886.0, 3: 985.0, 4: 1070.5, 5: 1174.2, 6: 1311.9, 7: 1472.9, 8: 1647.1, 9: 1804.8, 10: 1990.0, 11: 2238.2, 12: 2462.5, 13: 2710.4}, 'L': {0: 816.3, 1: 903.1, 2: 1023.0, 3: 1141.7, 4: 1249.3, 5: 1367.9, 6: 1516.6, 7: 1704.7, 8: 1910.6, 9: 2117.1, 10: 2326.2, 11: 2599.8, 12: 2870.8, 13: 3183.1}})

Vamos ver como está a tabela importada (usarei o knitr::kable para facilitar a exibição):

knitr::kable(py$df, caption = "Dados da tabela 5.6")
Dados da tabela 5.6
ANO PNB M1 M2 M3 L
0 1970 992.7 216.6 628.2 677.5 816.3
1 1971 1077.6 230.8 712.8 776.2 903.1
2 1972 1185.9 252.0 805.2 886.0 1023.0
3 1973 1326.4 265.9 861.0 985.0 1141.7
4 1974 1434.2 277.6 908.5 1070.5 1249.3
5 1975 1549.2 291.2 1023.3 1174.2 1367.9
6 1976 1718.0 310.4 1163.6 1311.9 1516.6
7 1977 1918.3 335.4 1286.7 1472.9 1704.7
8 1978 2163.9 363.1 1389.1 1647.1 1910.6
9 1979 2417.8 389.1 1498.5 1804.8 2117.1
10 1980 2631.7 414.9 1632.6 1990.0 2326.2
11 1981 2957.8 441.9 1796.6 2238.2 2599.8
12 1982 3069.3 480.5 1965.4 2462.5 2870.8
13 1983 3304.8 525.4 2196.3 2710.4 3183.1

2 Resultados

2.1 Visualização inicial

Vamos olhar os dados em gráficos de dispersão.

import numpy as np
import pandas as pd
# import seaborn
import seaborn as sns
df = pd.read_excel (r'E:\disciplinas\econometria\laboratorio_Python\demanda_moeda_gujarati_tab5-6\Tabela 5.6aula_gujarati 5ed p157.xlsx', sheet_name='dados')
bplot= sns.scatterplot('M1','PNB',data=df)
FALSE C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
FALSE   warnings.warn(
bplot.axes.set_title("Oferta de moeda M1 vs PNB: Gráfico de dispersão",
                    fontsize=16)
bplot.set_ylabel("PNB", 
                fontsize=16)
bplot.set_xlabel("Oferta de moeda M1", 
                fontsize=16)

# dispersao 2
bplot2= sns.scatterplot('M2','PNB',data=df)
FALSE C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
FALSE   warnings.warn(
bplot2.axes.set_title("Oferta de moeda M2 vs PNB: Gráfico de dispersão",
                    fontsize=16)
bplot2.set_ylabel("PNB", 
                fontsize=16)
bplot2.set_xlabel("Oferta de moeda M2", 
                fontsize=16)

# dispersao 3
bplot3= sns.scatterplot('M3','PNB',data=df)
FALSE C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
FALSE   warnings.warn(
bplot3.axes.set_title("Oferta de moeda M3 vs PNB: Gráfico de dispersão",
                    fontsize=16)
bplot3.set_ylabel("PNB", 
                fontsize=16)
bplot3.set_xlabel("Oferta de moeda M3", 
                fontsize=16)

# dispersao 4
bplot4= sns.scatterplot('L','PNB',data=df)
FALSE C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
FALSE   warnings.warn(
bplot4.axes.set_title("Oferta de moeda L vs PNB: Gráfico de dispersão",
                    fontsize=16)
bplot4.set_ylabel("PNB", 
                fontsize=16)
bplot4.set_xlabel("Oferta de moeda L", 
                fontsize=16)

2.2 Estimação

Vamos estimar o modelo linear múltipla fazendo as regressões do PNB contra as várias definições de moeda.

import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
df = pd.read_excel (r'E:\disciplinas\econometria\laboratorio_Python\demanda_moeda_gujarati_tab5-6\Tabela 5.6aula_gujarati 5ed p157.xlsx', sheet_name='dados')
import statsmodels.formula.api as sm
eq1 = sm.ols(formula="PNB ~ M1", data=df).fit()
print(eq1.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    PNB   R-squared:                       0.991
Model:                            OLS   Adj. R-squared:                  0.990
Method:                 Least Squares   F-statistic:                     1354.
Date:                Thu, 17 Mar 2022   Prob (F-statistic):           1.04e-13
Time:                        18:54:24   Log-Likelihood:                -79.468
No. Observations:                  14   AIC:                             162.9
Df Residuals:                      12   BIC:                             164.2
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept   -787.4724     77.966    -10.100      0.000    -957.347    -617.598
M1             8.0863      0.220     36.801      0.000       7.608       8.565
==============================================================================
Omnibus:                        3.736   Durbin-Watson:                   1.097
Prob(Omnibus):                  0.154   Jarque-Bera (JB):                1.275
Skew:                           0.285   Prob(JB):                        0.529
Kurtosis:                       4.364   Cond. No.                     1.36e+03
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.36e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\scipy\stats\stats.py:1603: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=14
  warnings.warn("kurtosistest only valid for n>=20 ... continuing "
eq2 = sm.ols(formula="PNB ~ M2", data=df).fit()
print(eq2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    PNB   R-squared:                       0.991
Model:                            OLS   Adj. R-squared:                  0.990
Method:                 Least Squares   F-statistic:                     1254.
Date:                Thu, 17 Mar 2022   Prob (F-statistic):           1.64e-13
Time:                        18:54:24   Log-Likelihood:                -80.003
No. Observations:                  14   AIC:                             164.0
Df Residuals:                      12   BIC:                             165.3
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    -44.0626     61.013     -0.722      0.484    -176.999      88.874
M2             1.5875      0.045     35.409      0.000       1.490       1.685
==============================================================================
Omnibus:                        0.139   Durbin-Watson:                   0.987
Prob(Omnibus):                  0.933   Jarque-Bera (JB):                0.125
Skew:                           0.136   Prob(JB):                        0.939
Kurtosis:                       2.625   Cond. No.                     3.92e+03
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 3.92e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\scipy\stats\stats.py:1603: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=14
  warnings.warn("kurtosistest only valid for n>=20 ... continuing "
eq3 = sm.ols(formula="PNB ~ M3", data=df).fit()
print(eq3.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    PNB   R-squared:                       0.994
Model:                            OLS   Adj. R-squared:                  0.994
Method:                 Least Squares   F-statistic:                     2099.
Date:                Thu, 17 Mar 2022   Prob (F-statistic):           7.63e-15
Time:                        18:54:24   Log-Likelihood:                -76.423
No. Observations:                  14   AIC:                             156.8
Df Residuals:                      12   BIC:                             158.1
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    158.7875     43.041      3.689      0.003      65.010     252.565
M3             1.2036      0.026     45.817      0.000       1.146       1.261
==============================================================================
Omnibus:                        0.385   Durbin-Watson:                   0.833
Prob(Omnibus):                  0.825   Jarque-Bera (JB):                0.108
Skew:                           0.192   Prob(JB):                        0.948
Kurtosis:                       2.805   Cond. No.                     4.30e+03
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 4.3e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\scipy\stats\stats.py:1603: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=14
  warnings.warn("kurtosistest only valid for n>=20 ... continuing "
eq4 = sm.ols(formula="PNB ~ L", data=df).fit()
print(eq4.summary())

# Predict values
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    PNB   R-squared:                       0.994
Model:                            OLS   Adj. R-squared:                  0.993
Method:                 Least Squares   F-statistic:                     1930.
Date:                Thu, 17 Mar 2022   Prob (F-statistic):           1.26e-14
Time:                        18:54:24   Log-Likelihood:                -77.005
No. Observations:                  14   AIC:                             158.0
Df Residuals:                      12   BIC:                             159.3
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    164.2071     44.766      3.668      0.003      66.671     261.744
L              1.0291      0.023     43.937      0.000       0.978       1.080
==============================================================================
Omnibus:                        1.395   Durbin-Watson:                   0.838
Prob(Omnibus):                  0.498   Jarque-Bera (JB):                0.130
Skew:                          -0.040   Prob(JB):                        0.937
Kurtosis:                       3.466   Cond. No.                     5.00e+03
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large,  5e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

C:\Users\amrof\AppData\Local\R-MINI~1\envs\R-RETI~1\lib\site-packages\scipy\stats\stats.py:1603: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=14
  warnings.warn("kurtosistest only valid for n>=20 ... continuing "
m1_pred = eq1.predict()
#Podemos visualizar nossa estimativa de yhat com o gráfico de dispersão.
import matplotlib.pyplot as plt
# Plot regression against actual data
plt.figure(figsize=(12, 6))
plt.plot(df['M1'], df['PNB'], 'o')           # scatter plot showing actual data
plt.plot(df['M1'], m1_pred, 'r', linewidth=2)   # regression line
plt.xlabel('Oferta de moeda M1')
plt.ylabel('PNB')
plt.title('Oferta de moeda M1 vs PNB: Gráfico de dispersão')
plt.show()

# Predict values
m2_pred = eq2.predict()
#Podemos visualizar nossa estimativa de yhat com o gráfico de dispersão.
import matplotlib.pyplot as plt
# Plot regression against actual data
plt.figure(figsize=(12, 6))
plt.plot(df['M2'], df['PNB'], 'o')           # scatter plot showing actual data
plt.plot(df['M2'], m2_pred, 'r', linewidth=2)   # regression line
plt.xlabel('Oferta de moeda M2')
plt.ylabel('PNB')
plt.title('Oferta de moeda M2 vs PNB: Gráfico de dispersão')
plt.show()

# Predict values
m3_pred = eq3.predict()
#Podemos visualizar nossa estimativa de yhat com o gráfico de dispersão.
import matplotlib.pyplot as plt
# Plot regression against actual data
plt.figure(figsize=(12, 6))
plt.plot(df['M3'], df['PNB'], 'o')           # scatter plot showing actual data
plt.plot(df['M3'], m3_pred, 'r', linewidth=2)   # regression line
plt.xlabel('Oferta de moeda M3')
plt.ylabel('PNB')
plt.title('Oferta de moeda M3 vs PNB: Gráfico de dispersão')
plt.show()

# Predict values
l_pred = eq4.predict()
#Podemos visualizar nossa estimativa de yhat com o gráfico de dispersão.
import matplotlib.pyplot as plt
# Plot regression against actual data
plt.figure(figsize=(12, 6))
plt.plot(df['L'], df['PNB'], 'o')           # scatter plot showing actual data
plt.plot(df['L'], l_pred, 'r', linewidth=2)   # regression line
plt.xlabel('Oferta de moeda L')
plt.ylabel('PNB')
plt.title('Oferta de moeda L vs PNB: Gráfico de dispersão')
plt.show()

3 Comentário

Este é um exercício introdutório de regressão simples, em que as variáveis são intimamente relacionadas, visto que o conceito de M2 contém M1, o de M3 contém M2, e L contém M3. Ou seja, serve apenas para visualizar como operacionalizar em Python, e eventualmente investigar se as partes acrescentadas em cada conceito podem gerar alguma alteração na relação (o que não era nosso objetivo neste exemplo). Sugiro ao leitor que na sequência realize os testes de resíduos do MQO a fim de melhor observar suas características.

LS0tDQp0aXRsZTogIkVjb25vbWV0cmlhIGVtIFB5dGhvbjogVGFiZWxhIDUuNiBQTkIgZSBkZW1hbmRhIGRlIG1vZWRhLCBHdWphcmF0aSBlIFBvcnRlciAoMjAxMSwgcC4xNTcpIg0KYXV0aG9yOiAiQWRyaWFubyBNYXJjb3MgUm9kcmlndWVzIEZpZ3VlaXJlZG8iDQplLW1haWw6ICJhZHJpYW5vLmZpZ3VlaXJlZG9AdWZtcy5iciINCmFic3RyYWN0OiANCiAgV2UgYW5hbHl6ZSBkaWZmZXJlbnQgbW9uZXkgc3VwcGx5IGNvbmNlcHRzIGFuZCBpdHMgcmVsYXRpb24gdG8gdGhlIEdEUC4gVGhlIGV4YW1wbGUgaXMgZHJhdyBmb2xsb3dpbmcgR3VqYXJhdGkgYW5kIFBvcnRlciAoMjAxMSwgcC4xNTcpIHVzaW5nIFB5dGhvbiBpbiBSU3R1ZGlvLiANCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBkZWZhdWx0DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogbm8NCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQotLS0NCg0KYGBge3Iga25pdHJfaW5pdCwgZWNobz1GQUxTRSwgY2FjaGU9RkFMU0V9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShybWFya2Rvd24pDQpsaWJyYXJ5KHJtZGZvcm1hdHMpDQoNCiMjIEdsb2JhbCBvcHRpb25zDQpvcHRpb25zKG1heC5wcmludD0iMTAwIikNCm9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwNCgkgICAgICAgICAgICAgY2FjaGU9VFJVRSwNCiAgICAgICAgICAgICAgIHByb21wdD1GQUxTRSwNCiAgICAgICAgICAgICAgIHRpZHk9VFJVRSwNCiAgICAgICAgICAgICAgIGNvbW1lbnQ9TkEsDQogICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLA0KICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSkNCm9wdHNfa25pdCRzZXQod2lkdGg9MTAwKQ0KYGBgDQoNCiMgTGljZW7Dp2EgeyNMaWNlbsOnYSAudW5udW1iZXJlZH0NCg0KVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgNC4wIEludGVybmF0aW9uYWwgTGljZW5zZS4gVG8gdmlldyBhIGNvcHkgb2YgdGhpcyBsaWNlbnNlLCB2aXNpdCA8aHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLz4gb3Igc2VuZCBhIGxldHRlciB0byBDcmVhdGl2ZSBDb21tb25zLCBQTyBCb3ggMTg2NiwgTW91bnRhaW4gVmlldywgQ0EgOTQwNDIsIFVTQS4NCg0KIVtMaWNlbnNlOiBDQyBCWS1TQSA0LjBdKGh0dHBzOi8vbWlycm9ycy5jcmVhdGl2ZWNvbW1vbnMub3JnL3ByZXNza2l0L2J1dHRvbnMvODh4MzEvcG5nL2J5LXNhLnBuZyl7d2lkdGg9IjI1JSJ9DQoNCiMgQ2l0YcOnw6NvIHsjQ2l0YcOnw6NvIC51bm51bWJlcmVkfQ0KDQpTdWdlc3TDo28gZGUgY2l0YcOnw6NvOiBGSUdVRUlSRURPLCBBZHJpYW5vIE1hcmNvcyBSb2RyaWd1ZXMuIEVjb25vbWV0cmlhIGVtIFB5dGhvbjogVGFiZWxhIDUuNiBQTkIgZSBkZW1hbmRhIGRlIG1vZWRhLCBHdWphcmF0aSBlIFBvcnRlciAoMjAxMSwgcC4xNTcpLiBDYW1wbyBHcmFuZGUtTVMsQnJhc2lsOiBSU3R1ZGlvL1JwdWJzLCAyMDIyLiBEaXNwb27DrXZlbCBlbSA8aHR0cDovL3JwdWJzLmNvbS9hbXJvZmkvR3VqYXJhdGlfdGFiNV82X3B5dGhvbj4uDQoNCiMgSW50cm9kdcOnw6NvDQoNCkVzc2UgcG9zdCDDqSBzZW1lbGhhbnRlIGFvIHF1ZSB1c28gbm8gdmlkZW8gZG8gWW91dHViZSBlbTogPGh0dHBzOi8veW91dHUuYmUvbHBuaS1FMVBBYlU+LCBFQ09OT01FVFJJQSAyMDIwLjIgU2xpZGVzIDAyYSBJbnN0YWxhw6fDo28gUiBlIFJTdHVkaW8uIE1hcyBuZXNzZSBjYXNvIHRyYWJhbGhhcmVpIG8gY8OzZGlnbyBlbSBQeXRob24uDQoNCk9zIHByaW1laXJvcyBwYXNzb3Mgc8OjbyBjcmlhciBvdSBhYnJpciB1bSBkaXJldMOzcmlvIGRlIHRyYWJhbGhvLiBTZSBvcHRhciBwb3IgY3JpYXIgdW0gbm92byBwcm9qZXRvLCBoYXZlcsOhIGEgcG9zc2liaWxpZGFkZSBkZSBjcmlhciBlbSB1bWEgcGFzdGEgdmF6aWEuIEVtIHNlZ3VpZGEsIHN1Z2VyZS1zZSBxdWUgY29sb3F1ZSBvcyBkYWRvcyBuZXN0YSBwYXN0YSwgc2UgcG9zc8OtdmVsIGVtIHVtIGFycXVpdm8gTVMgRXhjZWwgZSBjaGFtZSBhIHBsYW5pbGhhIGRlICdkYWRvcycuTmVzdGUgY2FzbywgYSBwbGFuaWxoYSBjaGFtYS1zZSAqVGFiZWxhIDUuNmF1bGFfZ3VqYXJhdGkgNWVkIHAxNTcueGxzeCouDQoNCj4gQSBUYWJlbGEgNS42IGFwcmVzZW50YSBkYWRvcyBzb2JyZSBvIFBOQiBlIHF1YXRybyBkZWZpbmnDp8O1ZXMgZG8gZXN0b3F1ZSBkZSBtb2VkYSBkb3MgRXN0YWRvcyBVbmlkb3Mgbm8gcGVyw61vZG8gMTk3MC0xOTgzLiBGYXplbmRvIGFzIHJlZ3Jlc3PDtWVzIGRvIFBOQiBjb250cmEgYXMgdsOhcmlhcyBkZWZpbmnDp8O1ZXMgZGUgbW9lZGEsIG9idGVtb3Mgb3MgcmVzdWx0YWRvcyBhcHJlc2VudGFkb3MgbmEgVGFiZWxhIDUuNy4gT3MgbW9uZXRhcmlzdGFzIG91IGFkZXB0b3MgZGEgdGVvcmlhIHF1YW50aXRhdGl2YSBhZmlybWFtIHF1ZSBhIHJlbmRhIG5vbWluYWwgKG8gUE5CIG5vbWluYWwpIMOpIGRldGVybWluYWRhLCBlbSBncmFuZGUgcGFydGUsIHBlbGEgdmFyaWHDp8OjbyBuYSBxdWFudGlkYWRlIG91IGVzdG9xdWUgZGUgbW9lZGEsIGVtYm9yYSBuw6NvIGhhamEgY29uc2Vuc28gcXVhbnRvIMOgIGRlZmluacOnw6NvICJjZXJ0YSIgZGUgbW9lZGEuIERlIGFjb3JkbyBjb20gb3MgcmVzdWx0YWRvcywgcmVzcG9uZGEgw6BzIHNlZ3VpbnRlcyBwZXJndW50YXM6XA0KPiBhLiBRdWUgZGVmaW5pw6fDo28gZGUgbW9lZGEgcGFyZWNlIGFwcmVzZW50YXIgcmVsYcOnw6NvIG1haXMgZXN0cmVpdGEgY29tIG8gUE5CIG5vbWluYWw/XA0KPiBiLiBDb21vIG9zICRSXjIkIHPDo28gdG9kb3MgZWxldmFkb3MsIGlzc28gc2lnbmlmaWNhIHF1ZSBhIGVzY29saGEgZGEgZGVmaW5pw6fDo28gZGUgbW9lZGEgbsOjbyB0ZW0gaW1wb3J0w6JuY2lhP1wNCj4gYy4gU2UgbyBGRUQgKEJhbmNvIENlbnRyYWwgZG9zIEVzdGFkb3MgVW5pZG9zKSBxdWVyIGNvbnRyb2xhciBhIG9mZXJ0YSBkZSBtb2VkYSwgcXVhbCBkZXNzZXMgaW5kaWNhZG9yZXMgZGUgbW9lZGEgc2VyaWEgbyBtZWxob3Igb2JqZXRpdm8gcGFyYSBlc3NlIGZpbT8gSXNzbyBwb2RlIHNlciBkaXRvIGNvbSBiYXNlIG5vcyByZXN1bHRhZG9zIGRhIHJlZ3Jlc3PDo28/DQoNCkV4ZXJjw61jaW8gcGFyYSBvcyBkYWRvcyBkYSB0YWJlbGEgNS42LCBjb25mb3JtZSBHdWphcmF0aSAoMjAxMSwgcC4xNTcpLCBQTkIgZSBlc3RvcXVlIGRlIG1vZWRhIHNlZ3VuZG8gcXVhdHJvIGNyaXTDqXJpb3MsIEVzdGFkb3MgVW5pZG9zLCAxOTcwLTE5ODMuDQoNClVzYXJlaSBvIHBhY290ZSBgcmV0aWN1bGF0ZWAgZW0gdW0gcHJpbWVpcm8gY2h1bmsgZW0gUiwgcGFyYSBkZXBvaXMgcm9kYXIgY2h1bmtzIGVtIHB5dGhvbiBkZW50cm8gZG8gUlN0dWRpby4NCg0KYGBge3IgcmV0aWN1bGF0ZX0NCiMgY2h1bmsgZW0gUg0KbGlicmFyeShyZXRpY3VsYXRlKQ0KIyBweV9pbnN0YWxsKCJvcGVucHl4bCIpICMgcGFyYSBpbnN0YWxhciBwYWNvdGUgb3BlbnB5eGwNCiMgc2UgYWN1c2FyIGF2aXNvcyBkZSBub3ZhIHZlcnNhbyBkbyBjb25kYSwNCiMgYWJyaXIgbyBUZXJtaW5hbCBlIGV4ZWN1dGFyIGNvbW8gYWJhaXhvDQojIGNvbmRhIHVwZGF0ZSAtbiBiYXNlIC1jIGRlZmF1bHRzIGNvbmRhDQpgYGANCg0KQ29sb2NvIGFxdWkgYSBvcMOnw6NvIGRlIGRvd25sb2FkIGRvIHhsc3ggbWFzIGNvbG9xdWVpIG9zIGRhZG9zIGVtYmVkZWQgbm8gY29kZSBwYXJhIHF1ZW0gcXVpc2VyLiDDiSBzw7MgZXhlY3V0YXIgbyBjaHVuayBhIHNlZ3VpciBxdWUgY29uc2VndWVtIGNhcnJlZ2FyIG9zIGRhZG9zLg0KDQpgYGB7cHl0aG9uIGltcG9ydGFybW9kdWxvc30NCiMgY2h1bmsgZW0gcHl0aG9uDQojIGF0dWFsaXphciBvIGNhbWluaG8gZG8gYXJxdWl2byB4bHN4IGEgc2VyIGxpZG8NCmltcG9ydCBwYW5kYXMgYXMgcGQNCiMgcHJlY2lzZWkgaW5zdGFsYXIgb3BlbnB5eGwgKHBhcmEgeGxzeCkgZSB4bHJkIChwYXJhIHhscykNCiMgbmVzdGUgY2Fzbywgb3MgZGFkb3MgZXN0w6NvIG5hIHNoZWV0ICdkYWRvcycNCmRmID0gcGQucmVhZF9leGNlbCAocidFOlxkaXNjaXBsaW5hc1xlY29ub21ldHJpYVxsYWJvcmF0b3Jpb19QeXRob25cZGVtYW5kYV9tb2VkYV9ndWphcmF0aV90YWI1LTZcVGFiZWxhIDUuNmF1bGFfZ3VqYXJhdGkgNWVkIHAxNTcueGxzeCcsIHNoZWV0X25hbWU9J2RhZG9zJykNCiMgZXhpYmlyIGRhZG9zIGUgY2hlY2FyIHNlIHZpZXJhbSBjb3JyZXRhbWVudGUNCnByaW50IChkZltbIkFOTyIgLCAiUE5CIiAsICJNMSIgLCAiTTIiICwgIk0zIiwiTCJdXSkNCmBgYA0KDQpQb3J0YW50bywgdGVtb3MgMTQgb2JzZXJ2YcOnw7VlcyBwYXJhIDYgdmFyacOhdmVpcyBkZW50cm8gZG8gRGF0YUZyYW1lIGRlIDE0IGxpbmhhcyBlIDYgY29sdW5hcy4gUG9kZW1vcyBleHRyYWlyIGEgZXN0cnV0dXJhIGRvcyBkYWRvcyBmYXplbmRvIG8gY8OzZGlnbyBzZW1lbGhhbnRlIGFvIGBkcHV0YCBkbyBSIChbbGlua10oaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDc0NTA5MzEvcHJpbnQtcGFuZGFzLWRhdGEtZnJhbWUtZm9yLXJlcHJvZHVjaWJsZS1leGFtcGxlLWVxdWl2YWxlbnQtdG8tZHB1dC1pbi1yICJMaW5rIHBhcmEgcHJvY2VkaW1lbnRvIHNlbWVsaGFudGUgYW8gZHB1dCBkbyBSIikpLg0KDQpgYGB7cHl0aG9ufQ0KI2RhdGFfYXNfZGljdD0gcHJpbnQoZGYudG9fZGljdCgpKQ0KI2RmID0gcGQuRGF0YUZyYW1lLmZyb21fZGljdChkYXRhX2FzX2RpY3QpDQpkZiA9IHBkLkRhdGFGcmFtZS5mcm9tX2RpY3QoeydBTk8nOiB7MDogMTk3MCwgMTogMTk3MSwgMjogMTk3MiwgMzogMTk3MywgNDogMTk3NCwgNTogMTk3NSwgNjogMTk3NiwgNzogMTk3NywgODogMTk3OCwgOTogMTk3OSwgMTA6IDE5ODAsIDExOiAxOTgxLCAxMjogMTk4MiwgMTM6IDE5ODN9LCAnUE5CJzogezA6IDk5Mi43LCAxOiAxMDc3LjYsIDI6IDExODUuOSwgMzogMTMyNi40LCA0OiAxNDM0LjIsIDU6IDE1NDkuMiwgNjogMTcxOC4wLCA3OiAxOTE4LjMsIDg6IDIxNjMuOSwgOTogMjQxNy44LCAxMDogMjYzMS43LCAxMTogMjk1Ny44LCAxMjogMzA2OS4zLCAxMzogMzMwNC44fSwgJ00xJzogezA6IDIxNi42LCAxOiAyMzAuOCwgMjogMjUyLjAsIDM6IDI2NS45LCA0OiAyNzcuNiwgNTogMjkxLjIsIDY6IDMxMC40LCA3OiAzMzUuNCwgODogMzYzLjEsIDk6IDM4OS4xLCAxMDogNDE0LjksIDExOiA0NDEuOSwgMTI6IDQ4MC41LCAxMzogNTI1LjR9LCAnTTInOiB7MDogNjI4LjIsIDE6IDcxMi44LCAyOiA4MDUuMiwgMzogODYxLjAsIDQ6IDkwOC41LCA1OiAxMDIzLjMsIDY6IDExNjMuNiwgNzogMTI4Ni43LCA4OiAxMzg5LjEsIDk6IDE0OTguNSwgMTA6IDE2MzIuNiwgMTE6IDE3OTYuNiwgMTI6IDE5NjUuNCwgMTM6IDIxOTYuM30sICdNMyc6IHswOiA2NzcuNSwgMTogNzc2LjIsIDI6IDg4Ni4wLCAzOiA5ODUuMCwgNDogMTA3MC41LCA1OiAxMTc0LjIsIDY6IDEzMTEuOSwgNzogMTQ3Mi45LCA4OiAxNjQ3LjEsIDk6IDE4MDQuOCwgMTA6IDE5OTAuMCwgMTE6IDIyMzguMiwgMTI6IDI0NjIuNSwgMTM6IDI3MTAuNH0sICdMJzogezA6IDgxNi4zLCAxOiA5MDMuMSwgMjogMTAyMy4wLCAzOiAxMTQxLjcsIDQ6IDEyNDkuMywgNTogMTM2Ny45LCA2OiAxNTE2LjYsIDc6IDE3MDQuNywgODogMTkxMC42LCA5OiAyMTE3LjEsIDEwOiAyMzI2LjIsIDExOiAyNTk5LjgsIDEyOiAyODcwLjgsIDEzOiAzMTgzLjF9fSkNCmBgYA0KDQpWYW1vcyB2ZXIgY29tbyBlc3TDoSBhIHRhYmVsYSBpbXBvcnRhZGEgKHVzYXJlaSBvIGtuaXRyOjprYWJsZSBwYXJhIGZhY2lsaXRhciBhIGV4aWJpw6fDo28pOg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShweSRkZixjYXB0aW9uPSJEYWRvcyBkYSB0YWJlbGEgNS42IikNCmBgYA0KDQojIFJlc3VsdGFkb3MNCg0KIyMgVmlzdWFsaXphw6fDo28gaW5pY2lhbA0KDQpWYW1vcyBvbGhhciBvcyBkYWRvcyBlbSBncsOhZmljb3MgZGUgZGlzcGVyc8Ojby4NCg0KYGBge3B5dGhvbiBkaXNwZXJzYW8sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbW1lbnQ9RkFMU0V9DQppbXBvcnQgbnVtcHkgYXMgbnANCmltcG9ydCBwYW5kYXMgYXMgcGQNCiMgaW1wb3J0IHNlYWJvcm4NCmltcG9ydCBzZWFib3JuIGFzIHNucw0KZGYgPSBwZC5yZWFkX2V4Y2VsIChyJ0U6XGRpc2NpcGxpbmFzXGVjb25vbWV0cmlhXGxhYm9yYXRvcmlvX1B5dGhvblxkZW1hbmRhX21vZWRhX2d1amFyYXRpX3RhYjUtNlxUYWJlbGEgNS42YXVsYV9ndWphcmF0aSA1ZWQgcDE1Ny54bHN4Jywgc2hlZXRfbmFtZT0nZGFkb3MnKQ0KYnBsb3Q9IHNucy5zY2F0dGVycGxvdCgnTTEnLCdQTkInLGRhdGE9ZGYpDQpicGxvdC5heGVzLnNldF90aXRsZSgiT2ZlcnRhIGRlIG1vZWRhIE0xIHZzIFBOQjogR3LDoWZpY28gZGUgZGlzcGVyc8OjbyIsDQogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KYnBsb3Quc2V0X3lsYWJlbCgiUE5CIiwgDQogICAgICAgICAgICAgICAgZm9udHNpemU9MTYpDQpicGxvdC5zZXRfeGxhYmVsKCJPZmVydGEgZGUgbW9lZGEgTTEiLCANCiAgICAgICAgICAgICAgICBmb250c2l6ZT0xNikNCmBgYA0KDQoNCmBgYHtweXRob24gZGlzcDIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbW1lbnQ9RkFMU0V9DQojIGRpc3BlcnNhbyAyDQpicGxvdDI9IHNucy5zY2F0dGVycGxvdCgnTTInLCdQTkInLGRhdGE9ZGYpDQpicGxvdDIuYXhlcy5zZXRfdGl0bGUoIk9mZXJ0YSBkZSBtb2VkYSBNMiB2cyBQTkI6IEdyw6FmaWNvIGRlIGRpc3BlcnPDo28iLA0KICAgICAgICAgICAgICAgICAgICBmb250c2l6ZT0xNikNCmJwbG90Mi5zZXRfeWxhYmVsKCJQTkIiLCANCiAgICAgICAgICAgICAgICBmb250c2l6ZT0xNikNCmJwbG90Mi5zZXRfeGxhYmVsKCJPZmVydGEgZGUgbW9lZGEgTTIiLCANCiAgICAgICAgICAgICAgICBmb250c2l6ZT0xNikNCmBgYA0KDQogICAgICAgICAgICAgIA0KYGBge3B5dGhvbiBkaXNwMywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY29tbWVudD1GQUxTRX0NCiMgZGlzcGVyc2FvIDMNCmJwbG90Mz0gc25zLnNjYXR0ZXJwbG90KCdNMycsJ1BOQicsZGF0YT1kZikNCmJwbG90My5heGVzLnNldF90aXRsZSgiT2ZlcnRhIGRlIG1vZWRhIE0zIHZzIFBOQjogR3LDoWZpY28gZGUgZGlzcGVyc8OjbyIsDQogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KYnBsb3QzLnNldF95bGFiZWwoIlBOQiIsIA0KICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KYnBsb3QzLnNldF94bGFiZWwoIk9mZXJ0YSBkZSBtb2VkYSBNMyIsIA0KICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KDQpgYGANCg0KDQpgYGB7cHl0aG9uIGRpc3A0LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PUZBTFNFfQ0KIyBkaXNwZXJzYW8gNA0KYnBsb3Q0PSBzbnMuc2NhdHRlcnBsb3QoJ0wnLCdQTkInLGRhdGE9ZGYpDQpicGxvdDQuYXhlcy5zZXRfdGl0bGUoIk9mZXJ0YSBkZSBtb2VkYSBMIHZzIFBOQjogR3LDoWZpY28gZGUgZGlzcGVyc8OjbyIsDQogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KYnBsb3Q0LnNldF95bGFiZWwoIlBOQiIsIA0KICAgICAgICAgICAgICAgIGZvbnRzaXplPTE2KQ0KYnBsb3Q0LnNldF94bGFiZWwoIk9mZXJ0YSBkZSBtb2VkYSBMIiwgDQogICAgICAgICAgICAgICAgZm9udHNpemU9MTYpDQpgYGANCg0KDQojIyBFc3RpbWHDp8Ojbw0KDQpWYW1vcyBlc3RpbWFyIG8gbW9kZWxvIGxpbmVhciBtw7psdGlwbGEgZmF6ZW5kbyBhcyByZWdyZXNzw7VlcyBkbyBQTkIgY29udHJhIGFzIHbDoXJpYXMgZGVmaW5pw6fDtWVzIGRlIG1vZWRhLg0KDQpgYGB7cHl0aG9uIHBhY290ZXNucF9saW5lYXJfbW9kZWx9DQppbXBvcnQgbnVtcHkgYXMgbnANCmltcG9ydCBwYW5kYXMgYXMgcGQNCmZyb20gc2tsZWFybi5saW5lYXJfbW9kZWwgaW1wb3J0IExpbmVhclJlZ3Jlc3Npb24NCmRmID0gcGQucmVhZF9leGNlbCAocidFOlxkaXNjaXBsaW5hc1xlY29ub21ldHJpYVxsYWJvcmF0b3Jpb19QeXRob25cZGVtYW5kYV9tb2VkYV9ndWphcmF0aV90YWI1LTZcVGFiZWxhIDUuNmF1bGFfZ3VqYXJhdGkgNWVkIHAxNTcueGxzeCcsIHNoZWV0X25hbWU9J2RhZG9zJykNCmltcG9ydCBzdGF0c21vZGVscy5mb3JtdWxhLmFwaSBhcyBzbQ0KZXExID0gc20ub2xzKGZvcm11bGE9IlBOQiB+IE0xIiwgZGF0YT1kZikuZml0KCkNCnByaW50KGVxMS5zdW1tYXJ5KCkpDQoNCmVxMiA9IHNtLm9scyhmb3JtdWxhPSJQTkIgfiBNMiIsIGRhdGE9ZGYpLmZpdCgpDQpwcmludChlcTIuc3VtbWFyeSgpKQ0KDQplcTMgPSBzbS5vbHMoZm9ybXVsYT0iUE5CIH4gTTMiLCBkYXRhPWRmKS5maXQoKQ0KcHJpbnQoZXEzLnN1bW1hcnkoKSkNCg0KZXE0ID0gc20ub2xzKGZvcm11bGE9IlBOQiB+IEwiLCBkYXRhPWRmKS5maXQoKQ0KcHJpbnQoZXE0LnN1bW1hcnkoKSkNCg0KIyBQcmVkaWN0IHZhbHVlcw0KbTFfcHJlZCA9IGVxMS5wcmVkaWN0KCkNCiNQb2RlbW9zIHZpc3VhbGl6YXIgbm9zc2EgZXN0aW1hdGl2YSBkZSB5aGF0IGNvbSBvIGdyw6FmaWNvIGRlIGRpc3BlcnPDo28uDQppbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0DQojIFBsb3QgcmVncmVzc2lvbiBhZ2FpbnN0IGFjdHVhbCBkYXRhDQpwbHQuZmlndXJlKGZpZ3NpemU9KDEyLCA2KSkNCnBsdC5wbG90KGRmWydNMSddLCBkZlsnUE5CJ10sICdvJykgICAgICAgICAgICMgc2NhdHRlciBwbG90IHNob3dpbmcgYWN0dWFsIGRhdGENCnBsdC5wbG90KGRmWydNMSddLCBtMV9wcmVkLCAncicsIGxpbmV3aWR0aD0yKSAgICMgcmVncmVzc2lvbiBsaW5lDQpwbHQueGxhYmVsKCdPZmVydGEgZGUgbW9lZGEgTTEnKQ0KcGx0LnlsYWJlbCgnUE5CJykNCnBsdC50aXRsZSgnT2ZlcnRhIGRlIG1vZWRhIE0xIHZzIFBOQjogR3LDoWZpY28gZGUgZGlzcGVyc8OjbycpDQpwbHQuc2hvdygpDQpgYGANCg0KYGBge3B5dGhvbiBwbG90Mn0NCiMgUHJlZGljdCB2YWx1ZXMNCm0yX3ByZWQgPSBlcTIucHJlZGljdCgpDQojUG9kZW1vcyB2aXN1YWxpemFyIG5vc3NhIGVzdGltYXRpdmEgZGUgeWhhdCBjb20gbyBncsOhZmljbyBkZSBkaXNwZXJzw6NvLg0KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdA0KIyBQbG90IHJlZ3Jlc3Npb24gYWdhaW5zdCBhY3R1YWwgZGF0YQ0KcGx0LmZpZ3VyZShmaWdzaXplPSgxMiwgNikpDQpwbHQucGxvdChkZlsnTTInXSwgZGZbJ1BOQiddLCAnbycpICAgICAgICAgICAjIHNjYXR0ZXIgcGxvdCBzaG93aW5nIGFjdHVhbCBkYXRhDQpwbHQucGxvdChkZlsnTTInXSwgbTJfcHJlZCwgJ3InLCBsaW5ld2lkdGg9MikgICAjIHJlZ3Jlc3Npb24gbGluZQ0KcGx0LnhsYWJlbCgnT2ZlcnRhIGRlIG1vZWRhIE0yJykNCnBsdC55bGFiZWwoJ1BOQicpDQpwbHQudGl0bGUoJ09mZXJ0YSBkZSBtb2VkYSBNMiB2cyBQTkI6IEdyw6FmaWNvIGRlIGRpc3BlcnPDo28nKQ0KcGx0LnNob3coKQ0KYGBgDQoNCmBgYHtweXRob24gcGxvdDN9DQojIFByZWRpY3QgdmFsdWVzDQptM19wcmVkID0gZXEzLnByZWRpY3QoKQ0KI1BvZGVtb3MgdmlzdWFsaXphciBub3NzYSBlc3RpbWF0aXZhIGRlIHloYXQgY29tIG8gZ3LDoWZpY28gZGUgZGlzcGVyc8Ojby4NCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQNCiMgUGxvdCByZWdyZXNzaW9uIGFnYWluc3QgYWN0dWFsIGRhdGENCnBsdC5maWd1cmUoZmlnc2l6ZT0oMTIsIDYpKQ0KcGx0LnBsb3QoZGZbJ00zJ10sIGRmWydQTkInXSwgJ28nKSAgICAgICAgICAgIyBzY2F0dGVyIHBsb3Qgc2hvd2luZyBhY3R1YWwgZGF0YQ0KcGx0LnBsb3QoZGZbJ00zJ10sIG0zX3ByZWQsICdyJywgbGluZXdpZHRoPTIpICAgIyByZWdyZXNzaW9uIGxpbmUNCnBsdC54bGFiZWwoJ09mZXJ0YSBkZSBtb2VkYSBNMycpDQpwbHQueWxhYmVsKCdQTkInKQ0KcGx0LnRpdGxlKCdPZmVydGEgZGUgbW9lZGEgTTMgdnMgUE5COiBHcsOhZmljbyBkZSBkaXNwZXJzw6NvJykNCnBsdC5zaG93KCkNCmBgYA0KDQpgYGB7cHl0aG9uIHBsb3Q9NH0NCiMgUHJlZGljdCB2YWx1ZXMNCmxfcHJlZCA9IGVxNC5wcmVkaWN0KCkNCiNQb2RlbW9zIHZpc3VhbGl6YXIgbm9zc2EgZXN0aW1hdGl2YSBkZSB5aGF0IGNvbSBvIGdyw6FmaWNvIGRlIGRpc3BlcnPDo28uDQppbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0DQojIFBsb3QgcmVncmVzc2lvbiBhZ2FpbnN0IGFjdHVhbCBkYXRhDQpwbHQuZmlndXJlKGZpZ3NpemU9KDEyLCA2KSkNCnBsdC5wbG90KGRmWydMJ10sIGRmWydQTkInXSwgJ28nKSAgICAgICAgICAgIyBzY2F0dGVyIHBsb3Qgc2hvd2luZyBhY3R1YWwgZGF0YQ0KcGx0LnBsb3QoZGZbJ0wnXSwgbF9wcmVkLCAncicsIGxpbmV3aWR0aD0yKSAgICMgcmVncmVzc2lvbiBsaW5lDQpwbHQueGxhYmVsKCdPZmVydGEgZGUgbW9lZGEgTCcpDQpwbHQueWxhYmVsKCdQTkInKQ0KcGx0LnRpdGxlKCdPZmVydGEgZGUgbW9lZGEgTCB2cyBQTkI6IEdyw6FmaWNvIGRlIGRpc3BlcnPDo28nKQ0KcGx0LnNob3coKQ0KYGBgDQoNCiMgQ29tZW50w6FyaW8NCg0KRXN0ZSDDqSB1bSBleGVyY8OtY2lvIGludHJvZHV0w7NyaW8gZGUgcmVncmVzc8OjbyBzaW1wbGVzLCBlbSBxdWUgYXMgdmFyacOhdmVpcyBzw6NvIGludGltYW1lbnRlIHJlbGFjaW9uYWRhcywgdmlzdG8gcXVlIG8gY29uY2VpdG8gZGUgTTIgY29udMOpbSBNMSwgbyBkZSBNMyBjb250w6ltIE0yLCBlIEwgY29udMOpbSBNMy4gT3Ugc2VqYSwgc2VydmUgYXBlbmFzIHBhcmEgdmlzdWFsaXphciBjb21vIG9wZXJhY2lvbmFsaXphciBlbSBQeXRob24sIGUgZXZlbnR1YWxtZW50ZSBpbnZlc3RpZ2FyIHNlIGFzIHBhcnRlcyBhY3Jlc2NlbnRhZGFzIGVtIGNhZGEgY29uY2VpdG8gcG9kZW0gZ2VyYXIgYWxndW1hIGFsdGVyYcOnw6NvIG5hIHJlbGHDp8OjbyAobyBxdWUgbsOjbyBlcmEgbm9zc28gb2JqZXRpdm8gbmVzdGUgZXhlbXBsbykuIFN1Z2lybyBhbyBsZWl0b3IgcXVlIG5hIHNlcXXDqm5jaWEgcmVhbGl6ZSBvcyB0ZXN0ZXMgZGUgcmVzw61kdW9zIGRvIE1RTyBhIGZpbSBkZSBtZWxob3Igb2JzZXJ2YXIgc3VhcyBjYXJhY3RlcsOtc3RpY2FzLg0K