# 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")
library("foreign")
library("readxl")
Tabela de contingência
# entrada de dados já tabulados
# o comum é usar o comando table para cruzar os dados
tab <- matrix(data = c(15,27,50,43,25,37,12,8,8,13,9,10), nrow = 3, ncol = 4, byrow = T)
rownames(tab) <- c("menos de 2000", "2000 a 5000", "5000 ou mais")
colnames(tab) <- c("0", "1", "2", ">2")
tab
0 1 2 >2
menos de 2000 15 27 50 43
2000 a 5000 25 37 12 8
5000 ou mais 8 13 9 10
# 1. convert the data as a table
dt <- as.table(as.matrix(tab))
# 2. Graph
balloonplot(t(dt), main ="Tabela de contingência - Renda x nº de Filhos", xlab ="", ylab="",
label = T, show.margins = T)

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 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\)
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)
n
[1] 257
### Standardized residuals
residuals <- chisq$residuals/sqrt(n)
residuals
0 1 2 >2
menos de 2000 -0.12688453 -0.1318950 0.12976393 0.12074460
2000 a 5000 0.15437047 0.1564536 -0.13962533 -0.16207938
5000 ou mais 0.01207689 0.0182992 -0.03847852 0.01024036
### Number of dimensions
nb.axes <- min(nrow(residuals)-1, ncol(residuals)-1)
nb.axes
[1] 2
### Singular value decomposition
res.svd <- svd(residuals, nu = nb.axes, nv = nb.axes)
res.svd
$d
[1] 3.994798e-01 3.832625e-02 4.351618e-17
$u
[,1] [,2]
[1,] 0.63728969 0.2618588
[2,] -0.76722779 0.3038015
[3,] -0.07227289 -0.9160429
$v
[,1] [,2]
[1,] -0.5010825 0.06807878
[2,] -0.5142022 -0.09836301
[3,] 0.4821335 0.69950511
[4,] 0.5020554 -0.70454425
### singular value
sv <- res.svd$d[1:nb.axes]
sv
[1] 0.39947979 0.03832625
u <-res.svd$u
u
[,1] [,2]
[1,] 0.63728969 0.2618588
[2,] -0.76722779 0.3038015
[3,] -0.07227289 -0.9160429
v <- res.svd$v
v
[,1] [,2]
[1,] -0.5010825 0.06807878
[2,] -0.5142022 -0.09836301
[3,] 0.4821335 0.69950511
[4,] 0.5020554 -0.70454425
# inércia total
sum(sv^2)
[1] 0.161053
### 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.
Coordenadas principais das linhas (Row coordinates)
### row sum
row.sum <- apply(tab, 1, sum)
row.sum
menos de 2000 2000 a 5000 5000 ou mais
135 82 40
### row mass
row.mass <- row.sum/n
row.mass
menos de 2000 2000 a 5000 5000 ou mais
0.5252918 0.3190661 0.1556420
### 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
menos de 2000 0.351 0.014
2000 a 5000 -0.543 0.021
5000 ou mais -0.073 -0.089
### 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)

Coordenadas principais das colunas (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
0 -0.4631802 0.006037457
1 -0.3752753 -0.006887306
2 0.3664372 0.051006395
>2 0.4116690 -0.055425073
### 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} = 0.3176\)
Nosso gráfico bidimensional captura 100% 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
menos de 2000 40.61 6.86
2000 a 5000 58.86 9.23
5000 ou mais 0.52 83.91
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
0 25.11 0.46
1 26.44 0.97
2 23.25 48.93
>2 25.21 49.64
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))
0 1 2 >2
menos de 2000 0.111 0.200 0.370 0.319
2000 a 5000 0.305 0.451 0.146 0.098
5000 ou mais 0.200 0.325 0.225 0.250
average.profile <- col.sum/n
head(round(average.profile, 3))
0 1 2 >2
0.187 0.300 0.276 0.237
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))
menos de 2000 2000 a 5000 5000 ou mais
0.124 0.295 0.013
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
menos de 2000 0.998 0.002
2000 a 5000 0.999 0.001
5000 ou mais 0.403 0.597
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)
0 1 2 >2
0.215 0.141 0.137 0.173
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
0 1.000 0.000
1 1.000 0.000
2 0.981 0.019
>2 0.982 0.018
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 41.39062 (p-value = 2.425291e-07 ).
Eigenvalues
Dim.1 Dim.2
Variance 0.160 0.001
% of var. 99.088 0.912
Cumulative % of var. 99.088 100.000
Rows
Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
menos de 2000 | 64.914 | -0.351 40.614 0.998 | -0.014 6.857 0.002 |
2000 a 5000 | 94.073 | 0.543 58.864 0.999 | -0.021 9.230 0.001 |
5000 ou mais | 2.066 | 0.073 0.522 0.403 | 0.089 83.913 0.597 |
Columns
Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
0 | 40.076 | 0.463 25.108 1.000 | -0.006 0.463 0.000 |
1 | 42.209 | 0.375 26.440 1.000 | 0.007 0.968 0.000 |
2 | 37.815 | -0.366 23.245 0.981 | -0.051 48.931 0.019 |
>2 | 40.954 | -0.412 25.206 0.982 | 0.055 49.638 0.018 |
### eigenvalue
head(res.ca$eig)[, 1:2]
### barplot of percentage of variance
barplot(res.ca$eig[,2], names.arg = rownames(res.ca$eig))

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

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

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

plot(res.ca)

ellipseCA(res.ca,ellipse="col")

ellipseCA(res.ca,ellipse="row")

ellipseCA(res.ca)

LS0tDQp0aXRsZTogJ0Fuw6FsaXNlIGRlIENvcnJlc3BvbmTDqm5jaWEgLSBSZW5kYSB4IE7CuiBkZSBmaWxob3MgLSBBTkFDT1IgJw0KYXV0aG9yOiAiTGVvbmksIFIuIEMuIFByb2Zlc3NvciBEci4iDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoqKioNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEYpDQpybShsaXN0PWxzKGFsbD1UUlVFKSkNCmBgYA0KDQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygiRmFjdG9NaW5lUiIsICJnZ2xvdDIiLCAicmVhZHhsIikNCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQ0KIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImthc3NhbWJhcmEvZmFjdG9leHRyYSIpDQpybShsaXN0PWxzKGFsbD1UUlVFKSkNCmxpYnJhcnkoImdncGxvdDIiKQ0KbGlicmFyeSgiRmFjdG9NaW5lUiIpDQpsaWJyYXJ5KCJmYWN0b2V4dHJhIikNCmxpYnJhcnkoInJlYWR4bCIpDQpsaWJyYXJ5KCJncGxvdHMiKQ0KbGlicmFyeSgiY29ycnBsb3QiKQ0KbGlicmFyeSgiZ3JhcGhpY3MiKQ0KbGlicmFyeSgiZm9yZWlnbiIpDQpsaWJyYXJ5KCJyZWFkeGwiKQ0KYGBgDQoNCiMjIyBUYWJlbGEgZGUgY29udGluZ8OqbmNpYQ0KDQpgYGB7cn0NCiMgZW50cmFkYSBkZSBkYWRvcyBqw6EgdGFidWxhZG9zIA0KIyBvIGNvbXVtIMOpIHVzYXIgbyBjb21hbmRvIHRhYmxlIHBhcmEgY3J1emFyIG9zIGRhZG9zDQp0YWIgPC0gbWF0cml4KGRhdGEgPSBjKDE1LDI3LDUwLDQzLDI1LDM3LDEyLDgsOCwxMyw5LDEwKSwgbnJvdyA9IDMsIG5jb2wgPSA0LCBieXJvdyA9IFQpDQpyb3duYW1lcyh0YWIpIDwtIGMoIm1lbm9zIGRlIDIwMDAiLCAiMjAwMCBhIDUwMDAiLCAiNTAwMCBvdSBtYWlzIikNCmNvbG5hbWVzKHRhYikgPC0gYygiMCIsICIxIiwgIjIiLCAiPjIiKQ0KDQp0YWINCmBgYA0KDQpgYGB7ciwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0NCg0KIyAxLiBjb252ZXJ0IHRoZSBkYXRhIGFzIGEgdGFibGUNCmR0IDwtIGFzLnRhYmxlKGFzLm1hdHJpeCh0YWIpKQ0KIyAyLiBHcmFwaA0KYmFsbG9vbnBsb3QodChkdCksIG1haW4gPSJUYWJlbGEgZGUgY29udGluZ8OqbmNpYSAtIFJlbmRhIHggbsK6IGRlIEZpbGhvcyIsIHhsYWIgPSIiLCB5bGFiPSIiLA0KICAgICAgICAgICAgbGFiZWwgPSBULCBzaG93Lm1hcmdpbnMgPSBUKQ0KDQpgYGANCg0KIyMjIEFzIGPDqWx1bGFzIGNvbSBvcyByZXPDrWR1b3MgcGFkcm9uaXphZG9zIGFic29sdXRvcyBtYWlzIGVsZXZhZG9zIGNvbnRyaWJ1ZW0gbWFpcyBwYXJhIGEgcG9udHVhw6fDo28gdG90YWwgZG8gUXVpLXF1YWRyYWRvLg0KDQpgYGB7cn0NCmNoaXNxIDwtIGNoaXNxLnRlc3QodGFiKQ0KY2hpc3ENCiMgT2JzZXJ2ZWQgY291bnRzDQpjaGlzcSRvYnNlcnZlZA0KIyBFeHBlY3RlZCBjb3VudHMgDQpyb3VuZChjaGlzcSRleHBlY3RlZCwyKQ0KIyByZXNpZHVhbHMgcGFkcm9uaXphZG9zIA0Kcm91bmQoY2hpc3EkcmVzaWR1YWxzLCAyKQ0KDQpjb3JycGxvdChjaGlzcSRyZXNpZHVhbHMsIGlzLmNvciA9IEZBTFNFKQ0KDQpgYGANCg0KDQojIyMgQSBpbsOpcmNpYSB0b3RhbCAoJFxwaGleMiQpIMOpIGEgcXVhbnRpZGFkZSBkZSBpbmZvcm1hw6fDo28gY29udGlkYSBuYSB0YWJlbGEgZGUgZGFkb3MNCiANCmBgYHtyfQ0KcGhpMiA8LSBhcy5udW1lcmljKGNoaXNxJHN0YXRpc3RpYy9zdW0odGFiKSkNCnBoaTINCmBgYA0KDQoNCg0KIyMjIEFuw6FsaXNlIGRlIGNvcnJlc3BvbmTDqm5jaWENCiMjIyBBbsOhbGlzZSBkZSBjb3JyZXNwb25kw6puY2lhIChBTkFDT1IpIMOpIG5lY2Vzc8OhcmlhIHBhcmEgYSB0YWJlbGEgZGUgY29udGluZ8OqbmNpYSBncmFuZGUuDQojIyMgQXBsaWNhLXNlIHBhcmEgdmlzdWFsaXphciBwb250b3MgZGEgbGluaGEgZSBwb250b3MgZGEgY29sdW5hIGVtIHVtIGVzcGHDp28gZGltZW5zaW9uYWwgcmVkdXppZG8uDQojIyMgQU5BQ09SIMOpIHVtIG3DqXRvZG8gZGUgcmVkdcOnw6NvIGRpbWVuc2lvbmFsIGFwbGljYWRvIGEgdW1hIHRhYmVsYSBkZSBjb250aW5nw6puY2lhLiANCiMjIyBBIGluZm9ybWHDp8OjbyByZXRpZGEgcG9yIGNhZGEgZGltZW5zw6NvIMOpIGNoYW1hZGEgYXV0b3ZhbG9yLg0KIyMjIEEgaW5mb3JtYcOnw6NvIHRvdGFsIChvdSBpbsOpcmNpYSkgY29udGlkYSBub3MgZGFkb3Mgw6kgY2hhbWFkYSBwaGkgKCRccGhpXjIkKSBlIHBvZGUgc2VyIGNhbGN1bGFkbyBkYSBzZWd1aW50ZSBmb3JtYToNCg0KJFxwaGleMiA9IFxmcmFje1xjaGleMn17Z3JhbmQudG90YWx9JA0KDQojIyMgQSBhbsOhbGlzZSBkZSBjb3JyZXNwb25kw6puY2lhIMOpIHVzYWRhIHBhcmEgcmVwcmVzZW50YXIgZ3JhZmljYW1lbnRlIGEgdGFiZWxhIGRlIGRpc3TDom5jaWFzIGVudHJlIHZhcmnDoXZlaXMgZGUgbGluaGEgb3UgZW50cmUgdmFyacOhdmVpcyBkZSBjb2x1bmEuDQoNCiMjIyBBIGFib3JkYWdlbSBBTkFDT1IgaW5jbHVpIGFzIHNlZ3VpbnRlcyBldGFwYXM6DQoNCiMjIyAxLkNhbGN1bGFyIG9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MNCg0KIyMjIE9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MgKFMpIHPDo286DQoNCiRTID0gXGZyYWN7byAtIGV9e1xzcXJ0e2V9fSQNCg0KIyMjIERlIGZhdG8sIFMgw6kgYXBlbmFzIGEgcmHDrXogcXVhZHJhZGEgZG9zIHRlcm1vcyBxdWUgY29tcMO1ZW0gYSBlc3RhdMOtc3RpY2EgJFxjaGleMiQuDQoNCiMjIyAyLiBDYWxjdWxlIGEgZGVjb21wb3Npw6fDo28gZG8gdmFsb3Igc2luZ3VsYXIgKFNWRCkgZG9zIHJlc8OtZHVvcyBwYWRyb25pemFkb3MuDQoNCiRNID0gXGZyYWN7MX17c3FydChncmFuZC50b3RhbCl9IFx0aW1lcyBTJA0KDQojIyMgU1ZEIHNpZ25pZmljYSBxdWUgcXVlcmVtb3MgZW5jb250cmFyIG1hdHJpemVzIG9ydG9nb25haXMgVSBlIFYsIGVtIGNvbmp1bnRvIGNvbSB1bWEgbWF0cml6IGRpYWdvbmFsICRcRGVsdGEkLCB0YWwgcXVlOg0KDQokTSA9IFUgXERlbHRhIFZeVCQNCg0KLSBVIMOJIHVtYSBtYXRyaXogY29udGVuZG8gYXV0b3ZldG9yZXMgZGUgbGluaGFzDQotICRcRGVsdGEkIMOJIGEgbWF0cml6IGRpYWdvbmFsLiBPcyBuw7ptZXJvcyBuYSBkaWFnb25hbCBkYSBtYXRyaXogc8OjbyBjaGFtYWRvcyBkZSB2YWxvcmVzIHNpbmd1bGFyZXMgKFNWKS4gT3MgYXV0b3ZhbG9yZXMgc8OjbyBvIFNWIHF1YWRyYWRvLg0KLSBWIMOJIHVtYSBtYXRyaXogY29udGVuZG8gYXV0b3ZldG9yZXMgZGUgY29sdW5hDQoNCiMjIyBPIGF1dG92YWxvciBkZSB1bSBkZXRlcm1pbmFkbyBlaXhvIMOpOg0KDQokXGxhbWJkYSA9IFxkZWx0YV4yJA0KDQokXGRlbHRhJCDDiSBvIHZhbG9yIHNpbmd1bGFyDQoNCiMjIyBBcyBjb29yZGVuYWRhcyBkYXMgdmFyacOhdmVpcyBkZSBsaW5oYSBlbSB1bSBkZXRlcm1pbmFkbyBlaXhvIHPDo286DQoNCiRyb3cuY29vcmQgPSBcZnJhY3tVICogXGRlbHRhIH17XHNxcnR7cm93Lm1hc3N9fSQNCg0KIyMjIEFzIGNvb3JkZW5hZGFzIGRhcyBjb2x1bmFzIHPDo28NCg0KJGNvbC5jb29yZCA9IFxmcmFje1YgKiBcZGVsdGEgfXtcc3FydHtjb2wubWFzc319JA0KDQojIyMgY8OhbGN1bG8gU1ZEDQoNCmBgYHtyfQ0KIyMjIEdyYW5kIHRvdGFsDQpuIDwtIHN1bSh0YWIpDQpuDQojIyMgU3RhbmRhcmRpemVkIHJlc2lkdWFscw0KcmVzaWR1YWxzIDwtIGNoaXNxJHJlc2lkdWFscy9zcXJ0KG4pDQpyZXNpZHVhbHMNCiMjIyBOdW1iZXIgb2YgZGltZW5zaW9ucw0KbmIuYXhlcyA8LSBtaW4obnJvdyhyZXNpZHVhbHMpLTEsIG5jb2wocmVzaWR1YWxzKS0xKQ0KbmIuYXhlcw0KDQojIyMgU2luZ3VsYXIgdmFsdWUgZGVjb21wb3NpdGlvbg0KcmVzLnN2ZCA8LSBzdmQocmVzaWR1YWxzLCBudSA9IG5iLmF4ZXMsIG52ID0gbmIuYXhlcykNCnJlcy5zdmQNCg0KIyMjIHNpbmd1bGFyIHZhbHVlDQpzdiA8LSByZXMuc3ZkJGRbMTpuYi5heGVzXSANCnN2DQp1IDwtcmVzLnN2ZCR1DQp1DQp2IDwtIHJlcy5zdmQkdg0Kdg0KDQojIGluw6lyY2lhIHRvdGFsDQpzdW0oc3ZeMikNCmBgYA0KDQoNCg0KYGBge3J9DQojIyMgRWlnZW52YWx1ZXMNCmVpZyA8LSBzdl4yDQojIyMgVmFyaWFuY2VzIGluIHBlcmNlbnRhZ2UNCnZhcmlhbmNlIDwtIGVpZyoxMDAvc3VtKGVpZykNCiMjIyBDdW11bGF0aXZlIHZhcmlhbmNlcw0KY3VtdmFyIDwtIGN1bXN1bSh2YXJpYW5jZSkNCmVpZzwtIGRhdGEuZnJhbWUoZWlnID0gZWlnLCB2YXJpYW5jZSA9IHZhcmlhbmNlLA0KICAgICAgICAgICAgICAgICAgICAgY3VtdmFyaWFuY2UgPSBjdW12YXIpDQpoZWFkKGVpZykNCmBgYA0KDQoNCmBgYHtyfQ0KYmFycGxvdChlaWdbLCAyXSwgbmFtZXMuYXJnPTE6bnJvdyhlaWcpLCANCiAgICAgICBtYWluID0gIlZhcmlhbmNlcyIsDQogICAgICAgeGxhYiA9ICJEaW1lbnNpb25zIiwNCiAgICAgICB5bGFiID0gIlBlcmNlbnRhZ2Ugb2YgdmFyaWFuY2VzIiwNCiAgICAgICBjb2wgPSJzdGVlbGJsdWUiKQ0KIyMjIEFkZCBjb25uZWN0ZWQgbGluZSBzZWdtZW50cyB0byB0aGUgcGxvdA0KbGluZXMoeCA9IDE6bnJvdyhlaWcpLCBlaWdbLCAyXSwgDQogICAgICB0eXBlPSJiIiwgcGNoPTE5LCBjb2wgPSAicmVkIikNCmBgYA0KIyMjIFF1YW50YXMgZGltZW5zw7VlcyByZXRlciA/DQoNCiMjIyAxLiBPIG7Dum1lcm8gbcOheGltbyBkZSBlaXhvcyBuYSBBTkFDT1Igw6k6DQoNCiRuYi5heGVzID0gbWluKHItMSwgYy0xKSQNCg0KIyMjIHIgZSBjIHPDo28gcmVzcGVjdGl2YW1lbnRlIG8gbsO6bWVybyBkZSBsaW5oYXMgZSBjb2x1bmFzIG5hIHRhYmVsYS4NCg0KIyMjIENvb3JkZW5hZGFzIHByaW5jaXBhaXMgZGFzIGxpbmhhcyAoUm93IGNvb3JkaW5hdGVzKQ0KDQpgYGB7cn0NCiMjIyByb3cgc3VtDQpyb3cuc3VtIDwtIGFwcGx5KHRhYiwgMSwgc3VtKQ0Kcm93LnN1bQ0KDQojIyMgcm93IG1hc3MNCnJvdy5tYXNzIDwtIHJvdy5zdW0vbg0Kcm93Lm1hc3MNCg0KIyMjIHJvdyBjb29yZCA9IHN2ICogdSAvc3FydChyb3cubWFzcykNCmNjIDwtIHQoYXBwbHkodSwgMSwgJyonLCBzdikpICMjIyBlYWNoIHJvdyBYIHN2DQpyb3cuY29vcmQgPC0gYXBwbHkoY2MsIDIsICcvJywgc3FydChyb3cubWFzcykpDQpyb3duYW1lcyhyb3cuY29vcmQpIDwtIHJvd25hbWVzKHRhYikNCmNvbG5hbWVzKHJvdy5jb29yZCkgPC0gcGFzdGUwKCJEaW0uIiwgMTpuYi5heGVzKQ0Kcm91bmQocm93LmNvb3JkLDMpDQoNCg0KIyMjIHBsb3QNCnBsb3Qocm93LmNvb3JkLCBwY2g9MTksIGNvbCA9ICJibHVlIikNCnRleHQocm93LmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKHJvdy5jb29yZCksIHBvcyA9IDMsIGNvbCA9ImJsdWUiKQ0KYWJsaW5lKHY9MCwgaD0wLCBsdHkgPSAyKQ0KYGBgDQoNCiMjIyAgQ29vcmRlbmFkYXMgcHJpbmNpcGFpcyBkYXMgY29sdW5hcyAoQ29sdW1uIGNvb3JkaW5hdGVzKQ0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KIyMjIENvb3JkaW5hdGVzIG9mIGNvbHVtbnMNCmNvbC5zdW0gPC0gYXBwbHkodGFiLCAyLCBzdW0pDQpjb2wubWFzcyA8LSBjb2wuc3VtL24NCiMjIyBjb29yZGluYXRlcyBzdiAqIHYgL3NxcnQoY29sLm1hc3MpDQpjYyA8LSB0KGFwcGx5KHYsIDEsICcqJywgc3YpKQ0KY29sLmNvb3JkIDwtIGFwcGx5KGNjLCAyLCAnLycsIHNxcnQoY29sLm1hc3MpKQ0Kcm93bmFtZXMoY29sLmNvb3JkKSA8LSBjb2xuYW1lcyh0YWIpDQpjb2xuYW1lcyhjb2wuY29vcmQpIDwtIHBhc3RlMCgiRGltIiwgMTpuYi5heGVzKQ0KaGVhZChjb2wuY29vcmQpDQoNCiMjIyBwbG90DQpwbG90KGNvbC5jb29yZCwgcGNoPTE3LCBjb2wgPSAicmVkIikNCnRleHQoY29sLmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKGNvbC5jb29yZCksIHBvcyA9IDMsIGNvbCA9InJlZCIpDQphYmxpbmUodj0wLCBoPTAsIGx0eSA9IDIpDQpgYGANCg0KIyMjIEJpcGxvdCBkZSBsaW5oYXMgZSBjb2x1bmFzIHBhcmEgdmVyIGEgYXNzb2NpYcOnw6NvDQoNCmBgYHtyfQ0KeGxpbSA8LSByYW5nZShjKHJvdy5jb29yZFssMV0sIGNvbC5jb29yZFssMV0pKSoxLjENCnlsaW0gPC0gcmFuZ2UoYyhyb3cuY29vcmRbLDJdLCBjb2wuY29vcmRbLDJdKSkqMS4xDQojIyMgUGxvdCBvZiByb3dzDQpwbG90KHJvdy5jb29yZCwgcGNoPTE5LCBjb2wgPSAiYmx1ZSIsIHhsaW0gPSB4bGltLCB5bGltID0geWxpbSkNCnRleHQocm93LmNvb3JkLCBsYWJlbHMgPXJvd25hbWVzKHJvdy5jb29yZCksIHBvcyA9IDMsIGNvbCA9ImJsdWUiKQ0KIyMjIHBsb3Qgb2ZmIGNvbHVtbnMNCnBvaW50cyhjb2wuY29vcmQsIHBjaD0xNywgY29sID0gInJlZCIpDQp0ZXh0KGNvbC5jb29yZCwgbGFiZWxzID1yb3duYW1lcyhjb2wuY29vcmQpLCBwb3MgPSAzLCBjb2wgPSJyZWQiKQ0KYWJsaW5lKHY9MCwgaD0wLCBsdHkgPSAyKQ0KYGBgDQoNCiMjIyBEaWFnbsOzc3RpY28NCg0KIyMjTGVtYnJlLXNlIHF1ZSwgYSBpbsOpcmNpYSB0b3RhbCBjb250aWRhIG5vcyBkYWRvcyDDqToNCg0KJFxwaGleMiA9IFxmcmFje1xjaGleMn17bn0gPSAwLjMxNzYkDQoNCiMjI05vc3NvIGdyw6FmaWNvIGJpZGltZW5zaW9uYWwgY2FwdHVyYSAxMDAlIGRhIGluw6lyY2lhIHRvdGFsIGRhIHRhYmVsYS4NCg0KIyMjIENvbnRyaWJ1acOnw6NvIGRlIGxpbmhhcyBlIGNvbHVuYXMNCg0KIyMjQXMgY29udHJpYnVpw6fDtWVzIGRlIHVtYSBsaW5oYSAvIGNvbHVuYSBwYXJhIGEgZGVmaW5pw6fDo28gZGUgdW0gZWl4byBwcmluY2lwYWwgc8OjbzoNCg0KJHJvdy5jb250cmliID0gXGZyYWN7cm93Lm1hc3MgKiByb3cuY29vcmReMn17ZWlnZW52YWx1ZX0kDQoNCiRjb2wuY29udHJpYiA9IFxmcmFje2NvbC5tYXNzICogY29sLmNvb3JkXjJ9e2VpZ2VudmFsdWV9JA0KDQojIyNDb250cmlidWnDp8OjbyBkZSBsaW5oYXMgZW0gJQ0KDQpgYGB7cn0NCiMjIyBjb250cmliIDwtIHJvdy5tYXNzICogcm93LmNvb3JkXjIvZWlnZW52YWx1ZQ0KY2MgPC0gYXBwbHkocm93LmNvb3JkXjIsIDIsICIqIiwgcm93Lm1hc3MpDQpyb3cuY29udHJpYiA8LSB0KGFwcGx5KGNjLCAxLCAiLyIsIGVpZ1sxOm5iLmF4ZXMsMV0pKSAqMTAwDQpyb3VuZChyb3cuY29udHJpYiwgMikNCg0KY29ycnBsb3Qocm93LmNvbnRyaWIsIGlzLmNvciA9IEZBTFNFKQ0KYGBgDQoNCiMjI0NvbnRyaWJ1acOnw6NvIGRhcyBjb2x1bmFzIGVtICUNCg0KYGBge3J9DQojIyMgY29udHJpYiA8LSBjb2wubWFzcyAqIGNvbC5jb29yZF4yL2VpZ2VudmFsdWUNCmNjIDwtIGFwcGx5KGNvbC5jb29yZF4yLCAyLCAiKiIsIGNvbC5tYXNzKQ0KY29sLmNvbnRyaWIgPC0gdChhcHBseShjYywgMSwgIi8iLCBlaWdbMTpuYi5heGVzLDFdKSkgKjEwMA0Kcm91bmQoY29sLmNvbnRyaWIsIDIpDQoNCmNvcnJwbG90KGNvbC5jb250cmliLCBpcy5jb3IgPSBGQUxTRSkNCmBgYA0KDQojIyMgUXVhbGlkYWRlIGRhIHJlcHJlc2VudGHDp8Ojbw0KDQojIyNBIHF1YWxpZGFkZSBkYSByZXByZXNlbnRhw6fDo28gw6kgY2hhbWFkYSBDT1MyLg0KDQojIyNBIHF1YWxpZGFkZSBkYSByZXByZXNlbnRhw6fDo28gZGUgdW1hIGxpbmhhIGVtIHVtIGVpeG8gw6k6DQoNCiRyb3cuY29zMiA9IFxmcmFje3Jvdy5jb29yZF4yfXtkXjJ9JA0KDQotIFJvdy5jb29yZCDDqSBhIGNvb3JkZW5hZGEgZGEgbGluaGEgbm8gZWl4bw0KLSAkZF4yJCDDiSBhIGRpc3TDom5jaWEgYW8gcXVhZHJhZG8gZG8gcGVyZmlsIG3DqWRpbw0KDQojIyNMZW1icmUtc2UgZGUgcXVlIGEgZGlzdMOibmNpYSBlbnRyZSBjYWRhIHBlcmZpbCBkZSBsaW5oYSBlIG8gcGVyZmlsIGRlIGxpbmhhIG3DqWRpbyDDqToNCg0KJGReMihyb3dfaSwgYXZlcmFnZS5wcm9maWxlKSA9IFxzdW17XGZyYWN7KHJvdy5wcm9maWxlX2kgLSBhdmVyYWdlLnByb2ZpbGUpXjJ9e2F2ZXJhZ2UucHJvZmlsZX19JA0KDQpgYGB7cn0NCnJvdy5wcm9maWxlIDwtIHRhYi9yb3cuc3VtDQpoZWFkKHJvdW5kKHJvdy5wcm9maWxlLCAzKSkNCg0KYXZlcmFnZS5wcm9maWxlIDwtIGNvbC5zdW0vbg0KaGVhZChyb3VuZChhdmVyYWdlLnByb2ZpbGUsIDMpKQ0KYGBgDQoNCiMjI08gY8OzZGlnbyBSIGFiYWl4byBjYWxjdWxhIGEgZGlzdMOibmNpYSBkbyBwZXJmaWwgbcOpZGlvIHBhcmEgdG9kYXMgYXMgdmFyacOhdmVpcyBkZSBsaW5oYQ0KDQpgYGB7cn0NCmF2ZXJhZ2UucnAgPC0gY29sLnN1bS9uIA0KZDIucm93IDwtIGFwcGx5KHJvdy5wcm9maWxlLCAxLCANCiAgICAgICAgICAgICAgICBmdW5jdGlvbihyb3cucCwgYXYucCl7c3VtKCgocm93LnAgLSBhdi5wKV4yKS9hdi5wKX0sIA0KICAgICAgICAgICAgICAgIGF2ZXJhZ2UucnApDQpoZWFkKHJvdW5kKGQyLnJvdywzKSkNCmBgYA0KDQojIyNPIGNvczIgZGUgbGluaGFzIG5vIG1hcGEgZGUgZmF0b3JlcyBzw6NvOg0KDQpgYGB7cn0NCnJvdy5jb3MyIDwtIGFwcGx5KHJvdy5jb29yZF4yLCAyLCAiLyIsIGQyLnJvdykNCnJvdW5kKHJvdy5jb3MyLCAzKQ0KDQpjb3JycGxvdChyb3cuY29zMiwgaXMuY29yID0gRkFMU0UpDQpgYGANCg0KIyMjQ29zMiBkYXMgY29sdW5hcw0KDQokY29sLmNvczIgPSBcZnJhY3tjb2wuY29vcmReMn17ZF4yfSQNCg0KYGBge3J9DQpjb2wucHJvZmlsZSA8LSB0KHRhYikvY29sLnN1bQ0KY29sLnByb2ZpbGUgPC0gdChjb2wucHJvZmlsZSkNCiMjI2hlYWQocm91bmQoY29sLnByb2ZpbGUsIDMpKQ0KYXZlcmFnZS5wcm9maWxlIDwtIHJvdy5zdW0vbg0KIyMjaGVhZChyb3VuZChhdmVyYWdlLnByb2ZpbGUsIDMpKQ0KYGBgDQoNCiMjI08gY8OzZGlnbyBSIGFiYWl4byBjYWxjdWxhIGEgZGlzdMOibmNpYSBkbyBwZXJmaWwgbcOpZGlvIHBhcmEgdG9kYXMgYXMgdmFyacOhdmVpcyBkYSBjb2x1bmENCg0KYGBge3J9DQoNCmQyLmNvbCA8LSBhcHBseShjb2wucHJvZmlsZSwgMiwgDQogICAgICAgIGZ1bmN0aW9uKGNvbC5wLCBhdi5wKXtzdW0oKChjb2wucCAtIGF2LnApXjIpL2F2LnApfSwgDQogICAgICAgIGF2ZXJhZ2UucHJvZmlsZSkNCnJvdW5kKGQyLmNvbCwzKQ0KYGBgDQoNCiMjI08gY29zMiBkYXMgY29sdW5hcyBubyBtYXBhIGRlIGZhdG9yZXMgc8OjbzoNCg0KYGBge3J9DQpjb2wuY29zMiA8LSBhcHBseShjb2wuY29vcmReMiwgMiwgIi8iLCBkMi5jb2wpDQpyb3VuZChjb2wuY29zMiwgMykNCg0KY29ycnBsb3QoY29sLmNvczIsIGlzLmNvciA9IEZBTFNFKQ0KYGBgDQoNCg0KIyMjIFBhY290ZXMgbm8gUiBwYXJhIEFOQUNPUg0KDQotRmFjdG9NaW5lUg0KLWFkZTQNCi1jYQ0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCnJlcy5jYSA8LSBDQSh0YWIsIGdyYXBoID0gRikNCg0Kc3VtbWFyeShyZXMuY2EpDQpgYGANCg0KDQpgYGB7cn0NCiMjIyBlaWdlbnZhbHVlDQpoZWFkKHJlcy5jYSRlaWcpWywgMToyXQ0KDQojIyMgYmFycGxvdCBvZiBwZXJjZW50YWdlIG9mIHZhcmlhbmNlDQpiYXJwbG90KHJlcy5jYSRlaWdbLDJdLCBuYW1lcy5hcmcgPSByb3duYW1lcyhyZXMuY2EkZWlnKSkNCmBgYA0KDQpgYGB7cn0NCiMjIyBQbG90IHJvdyBwb2ludHMNCnBsb3QocmVzLmNhLCBpbnZpc2libGUgPSJjb2wiKQ0KYGBgDQoNCmBgYHtyfQ0KIyMjIFBsb3QgY29sdW1uIHBvaW50cw0KcGxvdChyZXMuY2EsIGludmlzaWJsZSA9InJvdyIpDQpgYGANCg0KYGBge3J9DQojIyMgQmlwbG90IG9mIHJvd3MgYW5kIGNvbHVtbnMNCnBsb3QocmVzLmNhKQ0KcGxvdChyZXMuY2EpDQplbGxpcHNlQ0EocmVzLmNhLGVsbGlwc2U9ImNvbCIpDQplbGxpcHNlQ0EocmVzLmNhLGVsbGlwc2U9InJvdyIpDQplbGxpcHNlQ0EocmVzLmNhKQ0KYGBgDQo=