Imagine que um pesquisador esteja interessado em investigar se existe algum tipo de relação entre a origem de capital (controle acionário: asiático, brasileiro, americano, europeu ou latino) e o nível de transparência (disclosure) das informações contábeis (alto, médio ou baixo) das empresas pertencentes a uma amostra com 216 empresas

# install.packages("FactoMineR", "gglot2", "readxl")
# install.packages("devtools")
# devtools::install_github("kassambara/factoextra")
rm(list=ls(all=TRUE))
library("ggplot2")
library("FactoMineR")
library("factoextra")
library("readxl")
library("gplots")
library("corrplot")
library("graphics")
# ler e carregar os dados
disclosure <- read_excel("disclosure.xls")
head(disclosure)
str(disclosure)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   216 obs. of  2 variables:
 $ pais      : num  1 1 1 1 1 1 1 1 1 1 ...
 $ disclosure: num  3 3 3 3 3 3 1 1 1 2 ...
# atribuindo categorias aos números (VA qualitativa)
disclosure$pais <- factor(disclosure$pais, labels = c("asiático", "brasileiro", "americano", "europeu", "latino"))
disclosure$disclosure <- factor(disclosure$disclosure, labels = c("baixo", "médio", "alto"))
head(disclosure)
tab <- table(disclosure)
tab
            disclosure
pais         baixo médio alto
  asiático       8    10   13
  brasileiro    34    27   14
  americano     16    19   39
  europeu        3     2    1
  latino        10    17    3
### 1. convert the data as a table
dt <- as.table(as.matrix(tab))
### 2. Graph
balloonplot(t(dt), main ="País - Disclosure", xlab ="", ylab="",
            label = T, show.margins = T)

As células com os resíduos padronizados absolutos mais elevados contribuem mais para a pontuação total do Qui-quadrado.

chisq <- chisq.test(tab)
Aproxima攼㸷攼㸳o do qui-quadrado pode estar incorreta
chisq

    Pearson's Chi-squared test

data:  tab
X-squared = 33.149, df = 8, p-value = 5.791e-05
### Observed counts
chisq$observed
            disclosure
pais         baixo médio alto
  asiático       8    10   13
  brasileiro    34    27   14
  americano     16    19   39
  europeu        3     2    1
  latino        10    17    3
### Expected counts
round(chisq$expected,2)
            disclosure
pais         baixo médio  alto
  asiático   10.19 10.76 10.05
  brasileiro 24.65 26.04 24.31
  americano  24.32 25.69 23.98
  europeu     1.97  2.08  1.94
  latino      9.86 10.42  9.72
# residuals
round(chisq$residuals, 3)
            disclosure
pais          baixo  médio   alto
  asiático   -0.686 -0.233  0.932
  brasileiro  1.883  0.188 -2.090
  americano  -1.688 -1.321  3.067
  europeu     0.732 -0.058 -0.677
  latino      0.044  2.040 -2.156
#ou 
#(chisq$observed-chisq$expected)^2/chisq$expected
corrplot(chisq$residuals, is.cor = FALSE)

A contribuição (em %) de uma dada célula para a pontuação total do Qui-quadrado é calculada da seguinte forma:

### Contibution in percentage (%)
contrib <- 100*chisq$residuals^2/chisq$statistic
round(contrib, 3)
            disclosure
pais          baixo  médio   alto
  asiático    1.420  0.164  2.620
  brasileiro 10.691  0.106 13.182
  americano   8.594  5.262 28.374
  europeu     1.616  0.010  1.384
  latino      0.006 12.552 14.022
### Visualize the contribution
corrplot(contrib, is.cor = FALSE)

A inércia total (\(\phi^2\)) é a quantidade de informação contida na tabela de dados

phi2 <- as.numeric(chisq$statistic/sum(tab))
phi2
[1] 0.1534655

A raiz quadrada de \(\phi^2\) é chamada traço e pode ser interpretada como um coeficiente de correlação

o valor \(\phi\) > 0,2 indica uma dependência significativa entre linhas e colunas

O gráfico mosaico é usado para visualizar uma tabela de contingência para examinar a associação entre as variáveis categóricas.

### Mosaic plot of observed values
mosaicplot(tab,  las=2, col="steelblue",
           main = "Países.Disclosure - observed counts")

### Mosaic plot of expected values
mosaicplot(chisq$expected,  las=2, col = "gray",
           main = "Países.Disclosure - expected counts")

Nessas parcelas, as variáveis de coluna são primeiramente divididas (divisão vertical) e, em seguida, as variáveis de linha são divididas (divisão horizontal).

Para cada célula, a altura das barras é proporcional à frequência relativa observada que contém:

O gráfico azul, é o gráfico de mosaico dos valores observados.

O cinzento é o gráfico em mosaico dos valores esperados sob hipótese nula.

Se as variáveis de linha e coluna fossem completamente independentes, as barras de mosaico para os valores observados (gráfico azul) seriam alinhadas como as barras de mosaico para os valores esperados (gráfico cinza).

Também é possível colorir o mosaico de acordo com o valor dos resíduos padronizados:

mosaicplot(tab, shade = TRUE, las=2,main = "Países.Disclosure")

Análise de correspondência

Análise de correspondência (ANACOR) é necessária para a tabela de contingência grande.

Aplica-se para visualizar pontos da linha e pontos da coluna em um espaço dimensional reduzido.

ANACOR é um método de redução dimensional aplicado a uma tabela de contingência.

A informação retida por cada dimensão é chamada autovalor.

A informação total (ou inércia) contida nos dados é chamada phi (\(\phi^2\)) e pode ser calculado da seguinte forma:

\(\phi^2 = \frac{\chi^2}{grand.total}\)

Para um determinado eixo, o autovalor (λ) é calculado da seguinte forma:

\(\lambda_{axis} = \sum{\frac{row.sum}{grand.total} * row.coord^2}\)

\(\lambda_{axis} = \sum{\frac{col.sum}{grand.total} * col.coord^2}\)

A análise de correspondência é usada para representar graficamente a tabela de distâncias entre variáveis de linha ou entre variáveis de coluna.

A abordagem ANACOR inclui as seguintes etapas:

1.Calcular os resíduos padronizados

Os resíduos padronizados (S) são:

\(S = \frac{o - e}{\sqrt{e}}\)

De fato, S é apenas a raíz quadrada dos termos que compõem a estatística \(\chi^2\).

2. Calcule a decomposição do valor singular (SVD) dos resíduos padronizados.

\(M = \frac{1}{sqrt(grand.total)} \times S\)

SVD significa que queremos encontrar matrizes ortogonais U e V, em conjunto com uma matriz diagonal \(\Delta\), tal que:

\(M = U \Delta V^T\)

  • U É uma matriz contendo autovetores de linhas
  • Δ É a matriz diagonal. Os números na diagonal da matriz são chamados de valores singulares (SV). Os autovalores são o SV quadrado.
  • V É uma matriz contendo autovetores de coluna

O autovalor de um determinado eixo é:

\(\lambda = \delta^2\)

\(\delta\) É o valor singular

As coordenadas das variáveis de linha em um determinado eixo são:

\(row.coord = \frac{U * \delta }{\sqrt{row.mass}}\)

As coordenadas das colunas são

\(col.coord = \frac{V * \delta }{\sqrt{col.mass}}\)

cálculo SVD

### Grand total
n <- sum(tab)
### Standardized residuals
residuals <- chisq$residuals/sqrt(n)
### Number of dimensions
nb.axes <- min(nrow(residuals)-1, ncol(residuals)-1)
### Singular value decomposition
res.svd <- svd(residuals, nu = nb.axes, nv = nb.axes)
res.svd
$d
[1] 3.682595e-01 1.336053e-01 1.766556e-17

$u
           [,1]        [,2]
[1,] -0.2123970 -0.13641520
[2,]  0.4812011  0.54991331
[3,] -0.6910928 -0.04463595
[4,]  0.1576045  0.26465257
[5,]  0.4699837 -0.77907182

$v
           [,1]        [,2]
[1,]  0.4349627  0.69433693
[2,]  0.3699150 -0.71829008
[3,] -0.8209570  0.04422198
### singular value
sv <- res.svd$d[1:nb.axes] 
u <-res.svd$u
v <- res.svd$v
# inércia total
sum(sv^2)
[1] 0.1534655
### Eigenvalues
eig <- sv^2
### Variances in percentage
variance <- eig*100/sum(eig)
### Cumulative variances
cumvar <- cumsum(variance)
eig<- data.frame(eig = eig, variance = variance,
                     cumvariance = cumvar)
head(eig)
barplot(eig[, 2], names.arg=1:nrow(eig), 
       main = "Variances",
       xlab = "Dimensions",
       ylab = "Percentage of variances",
       col ="steelblue")
### Add connected line segments to the plot
lines(x = 1:nrow(eig), eig[, 2], 
      type="b", pch=19, col = "red")

Quantas dimensões reter ?

1. O número máximo de eixos na ANACOR é:

\(nb.axes = min(r-1, c-1)\)

r e c são respectivamente o número de linhas e colunas na tabela.

Row coordinates

### row sum
row.sum <- apply(tab, 1, sum)
### row mass
row.mass <- row.sum/n
### row coord = sv * u /sqrt(row.mass)
cc <- t(apply(u, 1, '*', sv)) ### each row X sv
row.coord <- apply(cc, 2, '/', sqrt(row.mass))
rownames(row.coord) <- rownames(tab)
colnames(row.coord) <- paste0("Dim.", 1:nb.axes)
round(row.coord,3)
            Dim.1  Dim.2
asiático   -0.206 -0.048
brasileiro  0.301  0.125
americano  -0.435 -0.010
europeu     0.348  0.212
latino      0.464 -0.279
### plot
plot(row.coord, pch=19, col = "blue")
text(row.coord, labels =rownames(row.coord), pos = 3, col ="blue")
abline(v=0, h=0, lty = 2)

Column coordinates

### Coordinates of columns
col.sum <- apply(tab, 2, sum)
col.mass <- col.sum/n
### coordinates sv * v /sqrt(col.mass)
cc <- t(apply(v, 1, '*', sv))
col.coord <- apply(cc, 2, '/', sqrt(col.mass))
rownames(col.coord) <- colnames(tab)
colnames(col.coord) <- paste0("Dim", 1:nb.axes)
head(col.coord)
            Dim1        Dim2
baixo  0.2793854  0.16180484
médio  0.2311811 -0.16286196
alto  -0.5310706  0.01037862
### plot
plot(col.coord, pch=17, col = "red")
text(col.coord, labels =rownames(col.coord), pos = 3, col ="red")
abline(v=0, h=0, lty = 2)

Biplot de linhas e colunas para ver a associação

xlim <- range(c(row.coord[,1], col.coord[,1]))*1.1
ylim <- range(c(row.coord[,2], col.coord[,2]))*1.1
### Plot of rows
plot(row.coord, pch=19, col = "blue", xlim = xlim, ylim = ylim)
text(row.coord, labels =rownames(row.coord), pos = 3, col ="blue")
### plot off columns
points(col.coord, pch=17, col = "red")
text(col.coord, labels =rownames(col.coord), pos = 3, col ="red")
abline(v=0, h=0, lty = 2)

Diagnóstico

Lembre-se que, a inércia total contida nos dados é:

\(\phi^2 = \frac{\chi^2}{n}\)

Nosso gráfico bidimensional captura cerca de 88% da inércia total da tabela.

Contribuição de linhas e colunas

As contribuições de uma linha / coluna para a definição de um eixo principal são:

\(row.contrib = \frac{row.mass * row.coord^2}{eigenvalue}\)

\(col.contrib = \frac{col.mass * col.coord^2}{eigenvalue}\)

Contribuição de linhas em %

### contrib <- row.mass * row.coord^2/eigenvalue
cc <- apply(row.coord^2, 2, "*", row.mass)
row.contrib <- t(apply(cc, 1, "/", eig[1:nb.axes,1])) *100
round(row.contrib, 2)
           Dim.1 Dim.2
asiático    4.51  1.86
brasileiro 23.16 30.24
americano  47.76  0.20
europeu     2.48  7.00
latino     22.09 60.70
corrplot(row.contrib, is.cor = FALSE)

Contribuição das colunas em %

### contrib <- col.mass * col.coord^2/eigenvalue
cc <- apply(col.coord^2, 2, "*", col.mass)
col.contrib <- t(apply(cc, 1, "/", eig[1:nb.axes,1])) *100
round(col.contrib, 2)
       Dim1  Dim2
baixo 18.92 48.21
médio 13.68 51.59
alto  67.40  0.20
corrplot(col.contrib, is.cor = FALSE)

Qualidade da representação

A qualidade da representação é chamada COS2.

A qualidade da representação de uma linha em um eixo é:

\(row.cos2 = \frac{row.coord^2}{d^2}\)

  • Row.coord é a coordenada da linha no eixo
  • \(d^2\) É a distância ao quadrado do perfil médio

Lembre-se de que a distância entre cada perfil de linha e o perfil de linha médio é:

\(d^2(row_i, average.profile) = \sum{\frac{(row.profile_i - average.profile)^2}{average.profile}}\)

row.profile <- tab/row.sum
head(round(row.profile, 3))
            disclosure
pais         baixo médio  alto
  asiático   0.258 0.323 0.419
  brasileiro 0.453 0.360 0.187
  americano  0.216 0.257 0.527
  europeu    0.500 0.333 0.167
  latino     0.333 0.567 0.100
average.profile <- col.sum/n
head(round(average.profile, 3))
baixo médio  alto 
0.329 0.347 0.324 

O código R abaixo calcula a distância do perfil médio para todas as variáveis de linha

average.rp <- col.sum/n 
d2.row <- apply(row.profile, 1, 
                function(row.p, av.p){sum(((row.p - av.p)^2)/av.p)}, 
                average.rp)
head(round(d2.row,3))
  asiático brasileiro  americano    europeu     latino 
     0.045      0.106      0.189      0.166      0.294 

O cos2 de linhas no mapa de fatores são:

row.cos2 <- apply(row.coord^2, 2, "/", d2.row)
round(row.cos2, 3)
           Dim.1 Dim.2
asiático   0.949 0.051
brasileiro 0.853 0.147
americano  0.999 0.001
europeu    0.729 0.271
latino     0.734 0.266
corrplot(row.cos2, is.cor = FALSE)

Cos2 das colunas

\(col.cos2 = \frac{col.coord^2}{d^2}\)

col.profile <- t(tab)/col.sum
col.profile <- t(col.profile)
###head(round(col.profile, 3))
average.profile <- row.sum/n
###head(round(average.profile, 3))

O código R abaixo calcula a distância do perfil médio para todas as variáveis da coluna

d2.col <- apply(col.profile, 2, 
        function(col.p, av.p){sum(((col.p - av.p)^2)/av.p)}, 
        average.profile)
round(d2.col,3)
baixo médio  alto 
0.104 0.080 0.282 

O cos2 das colunas no mapa de fatores são:

col.cos2 <- apply(col.coord^2, 2, "/", d2.col)
round(col.cos2, 3)
       Dim1  Dim2
baixo 0.749 0.251
médio 0.668 0.332
alto  1.000 0.000
corrplot(col.cos2, is.cor = FALSE)

Pacotes no R para ANACOR

-FactoMineR -ade4 -ca

library(FactoMineR)
res.ca <- CA(tab, graph = F)
summary(res.ca)

Call:
CA(X = tab, graph = F) 

The chi square of independence between the two variables is equal to 33.14854 (p-value =  5.790601e-05 ).

Eigenvalues
                       Dim.1   Dim.2
Variance               0.136   0.018
% of var.             88.368  11.632
Cumulative % of var.  88.368 100.000

Rows
             Iner*1000    Dim.1    ctr   cos2    Dim.2    ctr   cos2  
asiático   |     6.450 |  0.206  4.511  0.949 | -0.048  1.861  0.051 |
brasileiro |    36.800 | -0.301 23.155  0.853 |  0.125 30.240  0.147 |
americano  |    64.807 |  0.435 47.761  0.999 | -0.010  0.199  0.001 |
europeu    |     4.619 | -0.348  2.484  0.729 |  0.212  7.004  0.271 |
latino     |    40.790 | -0.464 22.088  0.734 | -0.279 60.695  0.266 |

Columns
             Iner*1000    Dim.1    ctr   cos2    Dim.2    ctr   cos2  
baixo      |    34.263 | -0.279 18.919  0.749 |  0.162 48.210  0.251 |
médio      |    27.767 | -0.231 13.684  0.668 | -0.163 51.594  0.332 |
alto       |    91.435 |  0.531 67.397  1.000 |  0.010  0.196  0.000 |
### Plot row points
plot(res.ca, invisible ="col")

### Plot column points
plot(res.ca, invisible ="row")

### Biplot of rows and columns
plot(res.ca)

LS0tDQp0aXRsZTogJ0Fuw6FsaXNlIGRlIENvcnJlc3BvbmTDqm5jaWEgLSBkaXNjbG9zdXJlIC0gQU5BQ09SICcNCmF1dGhvcjogIkxlb25pLCBSLiBDLiBQcm9mZXNzb3IgRHIuIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KKioqDQoNCiMjIyBJbWFnaW5lIHF1ZSB1bSBwZXNxdWlzYWRvciBlc3RlamEgaW50ZXJlc3NhZG8gZW0gaW52ZXN0aWdhciBzZSBleGlzdGUgYWxndW0gdGlwbyBkZSByZWxhw6fDo28gZW50cmUgYSBvcmlnZW0gZGUgY2FwaXRhbCAoY29udHJvbGUgYWNpb27DoXJpbzogYXNpw6F0aWNvLCBicmFzaWxlaXJvLCBhbWVyaWNhbm8sIGV1cm9wZXUgb3UgbGF0aW5vKSBlIG8gbsOtdmVsIGRlIHRyYW5zcGFyw6puY2lhIChkaXNjbG9zdXJlKSBkYXMgaW5mb3JtYcOnw7VlcyBjb250w6FiZWlzIChhbHRvLCBtw6lkaW8gb3UgYmFpeG8pIGRhcyBlbXByZXNhcyBwZXJ0ZW5jZW50ZXMgYSB1bWEgYW1vc3RyYSBjb20gMjE2IGVtcHJlc2FzICAgIA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRikNCmBgYA0KDQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygiRmFjdG9NaW5lUiIsICJnZ2xvdDIiLCAicmVhZHhsIikNCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQ0KIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImthc3NhbWJhcmEvZmFjdG9leHRyYSIpDQpybShsaXN0PWxzKGFsbD1UUlVFKSkNCmxpYnJhcnkoImdncGxvdDIiKQ0KbGlicmFyeSgiRmFjdG9NaW5lUiIpDQpsaWJyYXJ5KCJmYWN0b2V4dHJhIikNCmxpYnJhcnkoInJlYWR4bCIpDQpsaWJyYXJ5KCJncGxvdHMiKQ0KbGlicmFyeSgiY29ycnBsb3QiKQ0KbGlicmFyeSgiZ3JhcGhpY3MiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBsZXIgZSBjYXJyZWdhciBvcyBkYWRvcw0KZGlzY2xvc3VyZSA8LSByZWFkX2V4Y2VsKCJkaXNjbG9zdXJlLnhscyIpDQpoZWFkKGRpc2Nsb3N1cmUpDQpzdHIoZGlzY2xvc3VyZSkNCmBgYA0KDQpgYGB7cn0NCiMgYXRyaWJ1aW5kbyBjYXRlZ29yaWFzIGFvcyBuw7ptZXJvcyAoVkEgcXVhbGl0YXRpdmEpDQpkaXNjbG9zdXJlJHBhaXMgPC0gZmFjdG9yKGRpc2Nsb3N1cmUkcGFpcywgbGFiZWxzID0gYygiYXNpw6F0aWNvIiwgImJyYXNpbGVpcm8iLCAiYW1lcmljYW5vIiwgImV1cm9wZXUiLCAibGF0aW5vIikpDQpkaXNjbG9zdXJlJGRpc2Nsb3N1cmUgPC0gZmFjdG9yKGRpc2Nsb3N1cmUkZGlzY2xvc3VyZSwgbGFiZWxzID0gYygiYmFpeG8iLCAibcOpZGlvIiwgImFsdG8iKSkNCmhlYWQoZGlzY2xvc3VyZSkNCmBgYA0KDQpgYGB7cn0NCnRhYiA8LSB0YWJsZShkaXNjbG9zdXJlKQ0KdGFiDQoNCiMjIyAxLiBjb252ZXJ0IHRoZSBkYXRhIGFzIGEgdGFibGUNCmR0IDwtIGFzLnRhYmxlKGFzLm1hdHJpeCh0YWIpKQ0KIyMjIDIuIEdyYXBoDQpiYWxsb29ucGxvdCh0KGR0KSwgbWFpbiA9IlBhw61zIC0gRGlzY2xvc3VyZSIsIHhsYWIgPSIiLCB5bGFiPSIiLA0KICAgICAgICAgICAgbGFiZWwgPSBULCBzaG93Lm1hcmdpbnMgPSBUKQ0KDQpgYGANCg0KIyMjIEFzIGPDqWx1bGFzIGNvbSBvcyByZXPDrWR1b3MgcGFkcm9uaXphZG9zIGFic29sdXRvcyBtYWlzIGVsZXZhZG9zIGNvbnRyaWJ1ZW0gbWFpcyBwYXJhIGEgcG9udHVhw6fDo28gdG90YWwgZG8gUXVpLXF1YWRyYWRvLg0KDQpgYGB7cn0NCmNoaXNxIDwtIGNoaXNxLnRlc3QodGFiKQ0KY2hpc3ENCiMjIyBPYnNlcnZlZCBjb3VudHMNCmNoaXNxJG9ic2VydmVkDQojIyMgRXhwZWN0ZWQgY291bnRzDQpyb3VuZChjaGlzcSRleHBlY3RlZCwyKQ0KIyByZXNpZHVhbHMNCnJvdW5kKGNoaXNxJHJlc2lkdWFscywgMykNCiNvdSANCiMoY2hpc3Ekb2JzZXJ2ZWQtY2hpc3EkZXhwZWN0ZWQpXjIvY2hpc3EkZXhwZWN0ZWQNCg0KY29ycnBsb3QoY2hpc3EkcmVzaWR1YWxzLCBpcy5jb3IgPSBGQUxTRSkNCg0KYGBgDQoNCiMjIyBBIGNvbnRyaWJ1acOnw6NvIChlbSAlKSBkZSB1bWEgZGFkYSBjw6lsdWxhIHBhcmEgYSBwb250dWHDp8OjbyB0b3RhbCBkbyBRdWktcXVhZHJhZG8gw6kgY2FsY3VsYWRhIGRhIHNlZ3VpbnRlIGZvcm1hOg0KDQpgYGB7cn0NCiMjIyBDb250aWJ1dGlvbiBpbiBwZXJjZW50YWdlICglKQ0KY29udHJpYiA8LSAxMDAqY2hpc3EkcmVzaWR1YWxzXjIvY2hpc3Ekc3RhdGlzdGljDQpyb3VuZChjb250cmliLCAzKQ0KIyMjIFZpc3VhbGl6ZSB0aGUgY29udHJpYnV0aW9uDQpjb3JycGxvdChjb250cmliLCBpcy5jb3IgPSBGQUxTRSkNCmBgYA0KDQojIyMgQSBpbsOpcmNpYSB0b3RhbCAoJFxwaGleMiQpIMOpIGEgcXVhbnRpZGFkZSBkZSBpbmZvcm1hw6fDo28gY29udGlkYSBuYSB0YWJlbGEgZGUgZGFkb3MNCiANCmBgYHtyfQ0KcGhpMiA8LSBhcy5udW1lcmljKGNoaXNxJHN0YXRpc3RpYy9zdW0odGFiKSkNCnBoaTINCmBgYA0KDQojIyMgQSByYWl6IHF1YWRyYWRhIGRlICRccGhpXjIkIMOpIGNoYW1hZGEgdHJhw6dvIGUgcG9kZSBzZXIgaW50ZXJwcmV0YWRhIGNvbW8gdW0gY29lZmljaWVudGUgZGUgY29ycmVsYcOnw6NvIA0KIyMjIG8gdmFsb3IgJFxwaGkkID4gMCwyIGluZGljYSB1bWEgZGVwZW5kw6puY2lhIHNpZ25pZmljYXRpdmEgZW50cmUgbGluaGFzIGUgY29sdW5hcyANCiMjIyBPIGdyw6FmaWNvIG1vc2FpY28gw6kgdXNhZG8gcGFyYSB2aXN1YWxpemFyIHVtYSB0YWJlbGEgZGUgY29udGluZ8OqbmNpYSBwYXJhIGV4YW1pbmFyIGEgYXNzb2NpYcOnw6NvIGVudHJlIGFzIHZhcmnDoXZlaXMgY2F0ZWfDs3JpY2FzLg0KDQpgYGB7cn0NCiMjIyBNb3NhaWMgcGxvdCBvZiBvYnNlcnZlZCB2YWx1ZXMNCm1vc2FpY3Bsb3QodGFiLCAgbGFzPTIsIGNvbD0ic3RlZWxibHVlIiwNCiAgICAgICAgICAgbWFpbiA9ICJQYcOtc2VzLkRpc2Nsb3N1cmUgLSBvYnNlcnZlZCBjb3VudHMiKQ0KDQojIyMgTW9zYWljIHBsb3Qgb2YgZXhwZWN0ZWQgdmFsdWVzDQptb3NhaWNwbG90KGNoaXNxJGV4cGVjdGVkLCAgbGFzPTIsIGNvbCA9ICJncmF5IiwNCiAgICAgICAgICAgbWFpbiA9ICJQYcOtc2VzLkRpc2Nsb3N1cmUgLSBleHBlY3RlZCBjb3VudHMiKQ0KYGBgDQoNCiMjIyBOZXNzYXMgcGFyY2VsYXMsIGFzIHZhcmnDoXZlaXMgZGUgY29sdW5hIHPDo28gcHJpbWVpcmFtZW50ZSBkaXZpZGlkYXMgKGRpdmlzw6NvIHZlcnRpY2FsKSBlLCBlbSBzZWd1aWRhLCBhcyB2YXJpw6F2ZWlzIGRlIGxpbmhhIHPDo28gZGl2aWRpZGFzIChkaXZpc8OjbyBob3Jpem9udGFsKS4gDQojIyMgUGFyYSBjYWRhIGPDqWx1bGEsIGEgYWx0dXJhIGRhcyBiYXJyYXMgw6kgcHJvcG9yY2lvbmFsIMOgIGZyZXF1w6puY2lhIHJlbGF0aXZhIG9ic2VydmFkYSBxdWUgY29udMOpbToNCiMjIyBPIGdyw6FmaWNvIGF6dWwsIMOpIG8gZ3LDoWZpY28gZGUgbW9zYWljbyBkb3MgdmFsb3JlcyBvYnNlcnZhZG9zLg0KIyMjIE8gY2luemVudG8gw6kgbyBncsOhZmljbyBlbSBtb3NhaWNvIGRvcyB2YWxvcmVzIGVzcGVyYWRvcyBzb2IgaGlww7N0ZXNlIG51bGEuDQojIyMgU2UgYXMgdmFyacOhdmVpcyBkZSBsaW5oYSBlIGNvbHVuYSBmb3NzZW0gY29tcGxldGFtZW50ZSBpbmRlcGVuZGVudGVzLCBhcyBiYXJyYXMgZGUgbW9zYWljbyBwYXJhIG9zIHZhbG9yZXMgb2JzZXJ2YWRvcyAoZ3LDoWZpY28gYXp1bCkgc2VyaWFtIGFsaW5oYWRhcyBjb21vIGFzIGJhcnJhcyBkZSBtb3NhaWNvIHBhcmEgb3MgdmFsb3JlcyBlc3BlcmFkb3MgKGdyw6FmaWNvIGNpbnphKS4NCiMjIyBUYW1iw6ltIMOpIHBvc3PDrXZlbCBjb2xvcmlyIG8gbW9zYWljbyBkZSBhY29yZG8gY29tIG8gdmFsb3IgZG9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3M6DQoNCmBgYHtyfQ0KbW9zYWljcGxvdCh0YWIsIHNoYWRlID0gVFJVRSwgbGFzPTIsbWFpbiA9ICJQYcOtc2VzLkRpc2Nsb3N1cmUiKQ0KYGBgDQoNCg0KDQojIyAgQW7DoWxpc2UgZGUgY29ycmVzcG9uZMOqbmNpYQ0KIyMjIEFuw6FsaXNlIGRlIGNvcnJlc3BvbmTDqm5jaWEgKEFOQUNPUikgw6kgbmVjZXNzw6FyaWEgcGFyYSBhIHRhYmVsYSBkZSBjb250aW5nw6puY2lhIGdyYW5kZS4NCiMjIyBBcGxpY2Etc2UgcGFyYSB2aXN1YWxpemFyIHBvbnRvcyBkYSBsaW5oYSBlIHBvbnRvcyBkYSBjb2x1bmEgZW0gdW0gZXNwYcOnbyBkaW1lbnNpb25hbCByZWR1emlkby4NCiMjIyBBTkFDT1Igw6kgdW0gbcOpdG9kbyBkZSByZWR1w6fDo28gZGltZW5zaW9uYWwgYXBsaWNhZG8gYSB1bWEgdGFiZWxhIGRlIGNvbnRpbmfDqm5jaWEuIA0KIyMjIEEgaW5mb3JtYcOnw6NvIHJldGlkYSBwb3IgY2FkYSBkaW1lbnPDo28gw6kgY2hhbWFkYSBhdXRvdmFsb3IuDQojIyMgQSBpbmZvcm1hw6fDo28gdG90YWwgKG91IGluw6lyY2lhKSBjb250aWRhIG5vcyBkYWRvcyDDqSBjaGFtYWRhIHBoaSAoJFxwaGleMiQpIGUgcG9kZSBzZXIgY2FsY3VsYWRvIGRhIHNlZ3VpbnRlIGZvcm1hOg0KDQokXHBoaV4yID0gXGZyYWN7XGNoaV4yfXtncmFuZC50b3RhbH0kDQoNCiMjIyBQYXJhIHVtIGRldGVybWluYWRvIGVpeG8sIG8gYXV0b3ZhbG9yICjOuykgw6kgY2FsY3VsYWRvIGRhIHNlZ3VpbnRlIGZvcm1hOg0KDQokXGxhbWJkYV97YXhpc30gPSBcc3Vte1xmcmFje3Jvdy5zdW19e2dyYW5kLnRvdGFsfSAqIHJvdy5jb29yZF4yfSQNCg0KJFxsYW1iZGFfe2F4aXN9ID0gXHN1bXtcZnJhY3tjb2wuc3VtfXtncmFuZC50b3RhbH0gKiBjb2wuY29vcmReMn0kDQoNCiMjIyBBIGFuw6FsaXNlIGRlIGNvcnJlc3BvbmTDqm5jaWEgw6kgdXNhZGEgcGFyYSByZXByZXNlbnRhciBncmFmaWNhbWVudGUgYSB0YWJlbGEgZGUgZGlzdMOibmNpYXMgZW50cmUgdmFyacOhdmVpcyBkZSBsaW5oYSBvdSBlbnRyZSB2YXJpw6F2ZWlzIGRlIGNvbHVuYS4NCiMjIyBBIGFib3JkYWdlbSBBTkFDT1IgaW5jbHVpIGFzIHNlZ3VpbnRlcyBldGFwYXM6DQoNCiMjIyAxLkNhbGN1bGFyIG9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MNCg0KIyMjIE9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MgKFMpIHPDo286DQoNCiRTID0gXGZyYWN7byAtIGV9e1xzcXJ0e2V9fSQNCg0KIyMjIERlIGZhdG8sIFMgw6kgYXBlbmFzIGEgcmHDrXogcXVhZHJhZGEgZG9zIHRlcm1vcyBxdWUgY29tcMO1ZW0gYSBlc3RhdMOtc3RpY2EgJFxjaGleMiQuDQoNCiMjIyAyLiBDYWxjdWxlIGEgZGVjb21wb3Npw6fDo28gZG8gdmFsb3Igc2luZ3VsYXIgKFNWRCkgZG9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MuDQoNCiRNID0gXGZyYWN7MX17c3FydChncmFuZC50b3RhbCl9IFx0aW1lcyBTJA0KDQojIyMgU1ZEIHNpZ25pZmljYSBxdWUgcXVlcmVtb3MgZW5jb250cmFyIG1hdHJpemVzIG9ydG9nb25haXMgVSBlIFYsIGVtIGNvbmp1bnRvIGNvbSB1bWEgbWF0cml6IGRpYWdvbmFsICRcRGVsdGEkLCB0YWwgcXVlOg0KDQokTSA9IFUgXERlbHRhIFZeVCQNCg0KLSBVIMOJIHVtYSBtYXRyaXogY29udGVuZG8gYXV0b3ZldG9yZXMgZGUgbGluaGFzDQotIM6UIMOJIGEgbWF0cml6IGRpYWdvbmFsLiBPcyBuw7ptZXJvcyBuYSBkaWFnb25hbCBkYSBtYXRyaXogc8OjbyBjaGFtYWRvcyBkZSB2YWxvcmVzIHNpbmd1bGFyZXMgKFNWKS4gT3MgYXV0b3ZhbG9yZXMgc8OjbyBvIFNWIHF1YWRyYWRvLg0KLSBWIMOJIHVtYSBtYXRyaXogY29udGVuZG8gYXV0b3ZldG9yZXMgZGUgY29sdW5hDQoNCiMjIyBPIGF1dG92YWxvciBkZSB1bSBkZXRlcm1pbmFkbyBlaXhvIMOpOg0KDQokXGxhbWJkYSA9IFxkZWx0YV4yJA0KDQokXGRlbHRhJCDDiSBvIHZhbG9yIHNpbmd1bGFyDQoNCiMjIyBBcyBjb29yZGVuYWRhcyBkYXMgdmFyacOhdmVpcyBkZSBsaW5oYSBlbSB1bSBkZXRlcm1pbmFkbyBlaXhvIHPDo286DQoNCiRyb3cuY29vcmQgPSBcZnJhY3tVICogXGRlbHRhIH17XHNxcnR7cm93Lm1hc3N9fSQNCg0KIyMjIEFzIGNvb3JkZW5hZGFzIGRhcyBjb2x1bmFzIHPDo28NCg0KJGNvbC5jb29yZCA9IFxmcmFje1YgKiBcZGVsdGEgfXtcc3FydHtjb2wubWFzc319JA0KDQojIyMgY8OhbGN1bG8gU1ZEDQoNCmBgYHtyfQ0KIyMjIEdyYW5kIHRvdGFsDQpuIDwtIHN1bSh0YWIpDQojIyMgU3RhbmRhcmRpemVkIHJlc2lkdWFscw0KcmVzaWR1YWxzIDwtIGNoaXNxJHJlc2lkdWFscy9zcXJ0KG4pDQojIyMgTnVtYmVyIG9mIGRpbWVuc2lvbnMNCm5iLmF4ZXMgPC0gbWluKG5yb3cocmVzaWR1YWxzKS0xLCBuY29sKHJlc2lkdWFscyktMSkNCiMjIyBTaW5ndWxhciB2YWx1ZSBkZWNvbXBvc2l0aW9uDQpyZXMuc3ZkIDwtIHN2ZChyZXNpZHVhbHMsIG51ID0gbmIuYXhlcywgbnYgPSBuYi5heGVzKQ0KcmVzLnN2ZA0KDQojIyMgc2luZ3VsYXIgdmFsdWUNCnN2IDwtIHJlcy5zdmQkZFsxOm5iLmF4ZXNdIA0KdSA8LXJlcy5zdmQkdQ0KdiA8LSByZXMuc3ZkJHYNCg0KIyBpbsOpcmNpYSB0b3RhbA0Kc3VtKHN2XjIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyMjIEVpZ2VudmFsdWVzDQplaWcgPC0gc3ZeMg0KIyMjIFZhcmlhbmNlcyBpbiBwZXJjZW50YWdlDQp2YXJpYW5jZSA8LSBlaWcqMTAwL3N1bShlaWcpDQojIyMgQ3VtdWxhdGl2ZSB2YXJpYW5jZXMNCmN1bXZhciA8LSBjdW1zdW0odmFyaWFuY2UpDQplaWc8LSBkYXRhLmZyYW1lKGVpZyA9IGVpZywgdmFyaWFuY2UgPSB2YXJpYW5jZSwNCiAgICAgICAgICAgICAgICAgICAgIGN1bXZhcmlhbmNlID0gY3VtdmFyKQ0KaGVhZChlaWcpDQpgYGANCg0KYGBge3J9DQpiYXJwbG90KGVpZ1ssIDJdLCBuYW1lcy5hcmc9MTpucm93KGVpZyksIA0KICAgICAgIG1haW4gPSAiVmFyaWFuY2VzIiwNCiAgICAgICB4bGFiID0gIkRpbWVuc2lvbnMiLA0KICAgICAgIHlsYWIgPSAiUGVyY2VudGFnZSBvZiB2YXJpYW5jZXMiLA0KICAgICAgIGNvbCA9InN0ZWVsYmx1ZSIpDQojIyMgQWRkIGNvbm5lY3RlZCBsaW5lIHNlZ21lbnRzIHRvIHRoZSBwbG90DQpsaW5lcyh4ID0gMTpucm93KGVpZyksIGVpZ1ssIDJdLCANCiAgICAgIHR5cGU9ImIiLCBwY2g9MTksIGNvbCA9ICJyZWQiKQ0KYGBgDQoNCiMjIyBRdWFudGFzIGRpbWVuc8O1ZXMgcmV0ZXIgPw0KDQojIyMgMS4gTyBuw7ptZXJvIG3DoXhpbW8gZGUgZWl4b3MgbmEgQU5BQ09SIMOpOg0KDQokbmIuYXhlcyA9IG1pbihyLTEsIGMtMSkkDQoNCiMjIyByIGUgYyBzw6NvIHJlc3BlY3RpdmFtZW50ZSBvIG7Dum1lcm8gZGUgbGluaGFzIGUgY29sdW5hcyBuYSB0YWJlbGEuDQoNCiMjIyBSb3cgY29vcmRpbmF0ZXMNCmBgYHtyfQ0KIyMjIHJvdyBzdW0NCnJvdy5zdW0gPC0gYXBwbHkodGFiLCAxLCBzdW0pDQojIyMgcm93IG1hc3MNCnJvdy5tYXNzIDwtIHJvdy5zdW0vbg0KIyMjIHJvdyBjb29yZCA9IHN2ICogdSAvc3FydChyb3cubWFzcykNCmNjIDwtIHQoYXBwbHkodSwgMSwgJyonLCBzdikpICMjIyBlYWNoIHJvdyBYIHN2DQpyb3cuY29vcmQgPC0gYXBwbHkoY2MsIDIsICcvJywgc3FydChyb3cubWFzcykpDQpyb3duYW1lcyhyb3cuY29vcmQpIDwtIHJvd25hbWVzKHRhYikNCmNvbG5hbWVzKHJvdy5jb29yZCkgPC0gcGFzdGUwKCJEaW0uIiwgMTpuYi5heGVzKQ0Kcm91bmQocm93LmNvb3JkLDMpDQoNCg0KIyMjIHBsb3QNCnBsb3Qocm93LmNvb3JkLCBwY2g9MTksIGNvbCA9ICJibHVlIikNCnRleHQocm93LmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKHJvdy5jb29yZCksIHBvcyA9IDMsIGNvbCA9ImJsdWUiKQ0KYWJsaW5lKHY9MCwgaD0wLCBsdHkgPSAyKQ0KYGBgDQoNCiMjIyAgQ29sdW1uIGNvb3JkaW5hdGVzDQoNCmBgYHtyfQ0KIyMjIENvb3JkaW5hdGVzIG9mIGNvbHVtbnMNCmNvbC5zdW0gPC0gYXBwbHkodGFiLCAyLCBzdW0pDQpjb2wubWFzcyA8LSBjb2wuc3VtL24NCiMjIyBjb29yZGluYXRlcyBzdiAqIHYgL3NxcnQoY29sLm1hc3MpDQpjYyA8LSB0KGFwcGx5KHYsIDEsICcqJywgc3YpKQ0KY29sLmNvb3JkIDwtIGFwcGx5KGNjLCAyLCAnLycsIHNxcnQoY29sLm1hc3MpKQ0Kcm93bmFtZXMoY29sLmNvb3JkKSA8LSBjb2xuYW1lcyh0YWIpDQpjb2xuYW1lcyhjb2wuY29vcmQpIDwtIHBhc3RlMCgiRGltIiwgMTpuYi5heGVzKQ0KaGVhZChjb2wuY29vcmQpDQoNCiMjIyBwbG90DQpwbG90KGNvbC5jb29yZCwgcGNoPTE3LCBjb2wgPSAicmVkIikNCnRleHQoY29sLmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKGNvbC5jb29yZCksIHBvcyA9IDMsIGNvbCA9InJlZCIpDQphYmxpbmUodj0wLCBoPTAsIGx0eSA9IDIpDQpgYGANCg0KIyMjIEJpcGxvdCBkZSBsaW5oYXMgZSBjb2x1bmFzIHBhcmEgdmVyIGEgYXNzb2NpYcOnw6NvDQoNCmBgYHtyfQ0KeGxpbSA8LSByYW5nZShjKHJvdy5jb29yZFssMV0sIGNvbC5jb29yZFssMV0pKSoxLjENCnlsaW0gPC0gcmFuZ2UoYyhyb3cuY29vcmRbLDJdLCBjb2wuY29vcmRbLDJdKSkqMS4xDQojIyMgUGxvdCBvZiByb3dzDQpwbG90KHJvdy5jb29yZCwgcGNoPTE5LCBjb2wgPSAiYmx1ZSIsIHhsaW0gPSB4bGltLCB5bGltID0geWxpbSkNCnRleHQocm93LmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKHJvdy5jb29yZCksIHBvcyA9IDMsIGNvbCA9ImJsdWUiKQ0KIyMjIHBsb3Qgb2ZmIGNvbHVtbnMNCnBvaW50cyhjb2wuY29vcmQsIHBjaD0xNywgY29sID0gInJlZCIpDQp0ZXh0KGNvbC5jb29yZCwgbGFiZWxzID1yb3duYW1lcyhjb2wuY29vcmQpLCBwb3MgPSAzLCBjb2wgPSJyZWQiKQ0KYWJsaW5lKHY9MCwgaD0wLCBsdHkgPSAyKQ0KYGBgDQoNCg0KIyMjIERpYWduw7NzdGljbw0KDQojIyNMZW1icmUtc2UgcXVlLCBhIGluw6lyY2lhIHRvdGFsIGNvbnRpZGEgbm9zIGRhZG9zIMOpOg0KDQokXHBoaV4yID0gXGZyYWN7XGNoaV4yfXtufSQNCg0KIyMjTm9zc28gZ3LDoWZpY28gYmlkaW1lbnNpb25hbCBjYXB0dXJhIGNlcmNhIGRlIDg4JSBkYSBpbsOpcmNpYSB0b3RhbCBkYSB0YWJlbGEuDQoNCiMjIyBDb250cmlidWnDp8OjbyBkZSBsaW5oYXMgZSBjb2x1bmFzDQoNCiMjI0FzIGNvbnRyaWJ1acOnw7VlcyBkZSB1bWEgbGluaGEgLyBjb2x1bmEgcGFyYSBhIGRlZmluacOnw6NvIGRlIHVtIGVpeG8gcHJpbmNpcGFsIHPDo286DQoNCiRyb3cuY29udHJpYiA9IFxmcmFje3Jvdy5tYXNzICogcm93LmNvb3JkXjJ9e2VpZ2VudmFsdWV9JA0KDQokY29sLmNvbnRyaWIgPSBcZnJhY3tjb2wubWFzcyAqIGNvbC5jb29yZF4yfXtlaWdlbnZhbHVlfSQNCg0KIyMjQ29udHJpYnVpw6fDo28gZGUgbGluaGFzIGVtICUNCg0KYGBge3J9DQojIyMgY29udHJpYiA8LSByb3cubWFzcyAqIHJvdy5jb29yZF4yL2VpZ2VudmFsdWUNCmNjIDwtIGFwcGx5KHJvdy5jb29yZF4yLCAyLCAiKiIsIHJvdy5tYXNzKQ0Kcm93LmNvbnRyaWIgPC0gdChhcHBseShjYywgMSwgIi8iLCBlaWdbMTpuYi5heGVzLDFdKSkgKjEwMA0Kcm91bmQocm93LmNvbnRyaWIsIDIpDQoNCmNvcnJwbG90KHJvdy5jb250cmliLCBpcy5jb3IgPSBGQUxTRSkNCmBgYA0KDQojIyNDb250cmlidWnDp8OjbyBkYXMgY29sdW5hcyBlbSAlDQoNCmBgYHtyfQ0KIyMjIGNvbnRyaWIgPC0gY29sLm1hc3MgKiBjb2wuY29vcmReMi9laWdlbnZhbHVlDQpjYyA8LSBhcHBseShjb2wuY29vcmReMiwgMiwgIioiLCBjb2wubWFzcykNCmNvbC5jb250cmliIDwtIHQoYXBwbHkoY2MsIDEsICIvIiwgZWlnWzE6bmIuYXhlcywxXSkpICoxMDANCnJvdW5kKGNvbC5jb250cmliLCAyKQ0KDQpjb3JycGxvdChjb2wuY29udHJpYiwgaXMuY29yID0gRkFMU0UpDQpgYGANCg0KIyMjIFF1YWxpZGFkZSBkYSByZXByZXNlbnRhw6fDo28NCg0KIyMjQSBxdWFsaWRhZGUgZGEgcmVwcmVzZW50YcOnw6NvIMOpIGNoYW1hZGEgQ09TMi4NCg0KIyMjQSBxdWFsaWRhZGUgZGEgcmVwcmVzZW50YcOnw6NvIGRlIHVtYSBsaW5oYSBlbSB1bSBlaXhvIMOpOg0KDQokcm93LmNvczIgPSBcZnJhY3tyb3cuY29vcmReMn17ZF4yfSQNCg0KLSBSb3cuY29vcmQgw6kgYSBjb29yZGVuYWRhIGRhIGxpbmhhIG5vIGVpeG8NCi0gJGReMiQgw4kgYSBkaXN0w6JuY2lhIGFvIHF1YWRyYWRvIGRvIHBlcmZpbCBtw6lkaW8NCg0KIyMjTGVtYnJlLXNlIGRlIHF1ZSBhIGRpc3TDom5jaWEgZW50cmUgY2FkYSBwZXJmaWwgZGUgbGluaGEgZSBvIHBlcmZpbCBkZSBsaW5oYSBtw6lkaW8gw6k6DQoNCiRkXjIocm93X2ksIGF2ZXJhZ2UucHJvZmlsZSkgPSBcc3Vte1xmcmFjeyhyb3cucHJvZmlsZV9pIC0gYXZlcmFnZS5wcm9maWxlKV4yfXthdmVyYWdlLnByb2ZpbGV9fSQNCg0KYGBge3J9DQpyb3cucHJvZmlsZSA8LSB0YWIvcm93LnN1bQ0KaGVhZChyb3VuZChyb3cucHJvZmlsZSwgMykpDQoNCmF2ZXJhZ2UucHJvZmlsZSA8LSBjb2wuc3VtL24NCmhlYWQocm91bmQoYXZlcmFnZS5wcm9maWxlLCAzKSkNCmBgYA0KDQojIyNPIGPDs2RpZ28gUiBhYmFpeG8gY2FsY3VsYSBhIGRpc3TDom5jaWEgZG8gcGVyZmlsIG3DqWRpbyBwYXJhIHRvZGFzIGFzIHZhcmnDoXZlaXMgZGUgbGluaGENCg0KYGBge3J9DQphdmVyYWdlLnJwIDwtIGNvbC5zdW0vbiANCmQyLnJvdyA8LSBhcHBseShyb3cucHJvZmlsZSwgMSwgDQogICAgICAgICAgICAgICAgZnVuY3Rpb24ocm93LnAsIGF2LnApe3N1bSgoKHJvdy5wIC0gYXYucCleMikvYXYucCl9LCANCiAgICAgICAgICAgICAgICBhdmVyYWdlLnJwKQ0KaGVhZChyb3VuZChkMi5yb3csMykpDQpgYGANCg0KIyMjTyBjb3MyIGRlIGxpbmhhcyBubyBtYXBhIGRlIGZhdG9yZXMgc8OjbzoNCg0KYGBge3J9DQpyb3cuY29zMiA8LSBhcHBseShyb3cuY29vcmReMiwgMiwgIi8iLCBkMi5yb3cpDQpyb3VuZChyb3cuY29zMiwgMykNCg0KY29ycnBsb3Qocm93LmNvczIsIGlzLmNvciA9IEZBTFNFKQ0KYGBgDQoNCiMjI0NvczIgZGFzIGNvbHVuYXMNCg0KJGNvbC5jb3MyID0gXGZyYWN7Y29sLmNvb3JkXjJ9e2ReMn0kDQoNCmBgYHtyfQ0KY29sLnByb2ZpbGUgPC0gdCh0YWIpL2NvbC5zdW0NCmNvbC5wcm9maWxlIDwtIHQoY29sLnByb2ZpbGUpDQojIyNoZWFkKHJvdW5kKGNvbC5wcm9maWxlLCAzKSkNCmF2ZXJhZ2UucHJvZmlsZSA8LSByb3cuc3VtL24NCiMjI2hlYWQocm91bmQoYXZlcmFnZS5wcm9maWxlLCAzKSkNCmBgYA0KDQojIyNPIGPDs2RpZ28gUiBhYmFpeG8gY2FsY3VsYSBhIGRpc3TDom5jaWEgZG8gcGVyZmlsIG3DqWRpbyBwYXJhIHRvZGFzIGFzIHZhcmnDoXZlaXMgZGEgY29sdW5hDQoNCmBgYHtyfQ0KDQpkMi5jb2wgPC0gYXBwbHkoY29sLnByb2ZpbGUsIDIsIA0KICAgICAgICBmdW5jdGlvbihjb2wucCwgYXYucCl7c3VtKCgoY29sLnAgLSBhdi5wKV4yKS9hdi5wKX0sIA0KICAgICAgICBhdmVyYWdlLnByb2ZpbGUpDQpyb3VuZChkMi5jb2wsMykNCmBgYA0KDQojIyNPIGNvczIgZGFzIGNvbHVuYXMgbm8gbWFwYSBkZSBmYXRvcmVzIHPDo286DQoNCmBgYHtyfQ0KY29sLmNvczIgPC0gYXBwbHkoY29sLmNvb3JkXjIsIDIsICIvIiwgZDIuY29sKQ0Kcm91bmQoY29sLmNvczIsIDMpDQoNCmNvcnJwbG90KGNvbC5jb3MyLCBpcy5jb3IgPSBGQUxTRSkNCmBgYA0KDQoNCg0KIyMjIFBhY290ZXMgbm8gUiBwYXJhIEFOQUNPUg0KDQotRmFjdG9NaW5lUg0KLWFkZTQNCi1jYQ0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCnJlcy5jYSA8LSBDQSh0YWIsIGdyYXBoID0gRikNCnN1bW1hcnkocmVzLmNhKQ0KYGBgDQoNCmBgYHtyfQ0KIyMjIFBsb3Qgcm93IHBvaW50cw0KcGxvdChyZXMuY2EsIGludmlzaWJsZSA9ImNvbCIpDQpgYGANCg0KYGBge3J9DQojIyMgUGxvdCBjb2x1bW4gcG9pbnRzDQpwbG90KHJlcy5jYSwgaW52aXNpYmxlID0icm93IikNCmBgYA0KDQpgYGB7cn0NCiMjIyBCaXBsb3Qgb2Ygcm93cyBhbmQgY29sdW1ucw0KcGxvdChyZXMuY2EpDQpgYGANCg0KDQoNCg==