Exemplo 1 - Taxa de Delitos por 100000 habitantes por divisão territorial das polícias do Estado de SP (Deinter) em 2002.

library(factoextra)
library(FactoMineR)
library(ggplot2)
library(ggcorrplot)
library(psych)
# Deinter
deinter  <- c("SJRP", "RP", "Bauru", "Campinas", "Sorocaba", "SP", "SJC", "Santos", "GSP")
# X1
homicidio_doloso <- c(10.85,14.13,8.62,23.04,16.04,43.74,25.39,42.86,42.55)
# X2
furto <- c(1500.80,1496.07,1448.79,1277.33,1204.02,1190.94,1292.91,1590.66,797.16)
# X3
roubo <- c(149.35,187.99,130.97,424.87,214.36,1139.52,358.39,721.90,520.73)
roubo_furto_veiculos <- c(108.38,116.66,69.98,435.75,207.06,909.21,268.24,275.89,602.63)
dados <- data.frame(homicidio_doloso,furto,roubo,roubo_furto_veiculos)
row.names(dados) <- deinter
str(dados)
'data.frame':   9 obs. of  4 variables:
 $ homicidio_doloso    : num  10.85 14.13 8.62 23.04 16.04 ...
 $ furto               : num  1501 1496 1449 1277 1204 ...
 $ roubo               : num  149 188 131 425 214 ...
 $ roubo_furto_veiculos: num  108 117 70 436 207 ...
dados
#tail(dados)
# sumário estatístico 
describe(dados)
                     vars n    mean     sd  median trimmed    mad    min     max
homicidio_doloso        1 9   25.25  14.36   23.04   25.25  18.07   8.62   43.74
furto                   2 9 1310.96 239.48 1292.91 1310.96 231.11 797.16 1590.66
roubo                   3 9  427.56 330.76  358.39  427.56 252.64 130.97 1139.52
roubo_furto_veiculos    4 9  332.64 275.01  268.24  332.64 237.01  69.98  909.21
                       range  skew kurtosis     se
homicidio_doloso       35.12  0.27    -1.84   4.79
furto                 793.50 -0.82    -0.33  79.83
roubo                1008.55  0.97    -0.37 110.25
roubo_furto_veiculos  839.23  0.91    -0.56  91.67
# gráfico boxplot 
boxplot(dados) # dados originais

boxplot(scale(dados)) # dados padronizados

correlações

# Correlation matrix
matcor <- round(cor(dados), 2)
matcor
                     homicidio_doloso furto roubo roubo_furto_veiculos
homicidio_doloso                 1.00 -0.44  0.88                 0.80
furto                           -0.44  1.00 -0.26                -0.63
roubo                            0.88 -0.26  1.00                 0.88
roubo_furto_veiculos             0.80 -0.63  0.88                 1.00
# Plot
ggcorrplot(matcor, hc.order = TRUE, 
           type = "lower", 
           lab = TRUE, 
           lab_size = 3, 
           method="circle", 
           colors = c("tomato2", "white", "springgreen3"), 
           title="Correlograma", 
           ggtheme=theme_bw)

teste de Bartlett

Bartlett.sphericity.test

Bartlett.sphericity.test <- function(x)
{
  method <- "Bartlett's test of sphericity"
  data.name <- deparse(substitute(x))
  x <- subset(x, complete.cases(x)) # Omit missing values
  n <- nrow(x)
  p <- ncol(x)
  chisq <- (1-n+(2*p+5)/6)*log(det(cor(x)))
  df <- p*(p-1)/2
  p.value <- pchisq(chisq, df, lower.tail=FALSE)
  names(chisq) <- "X-squared"
  names(df) <- "df"
  return(structure(list(statistic=chisq, parameter=df, p.value=p.value,
                        method=method, data.name=data.name), class="htest"))
}
Bartlett.sphericity.test(dados)

    Bartlett's test of sphericity

data:  dados
X-squared = 33.089, df = 6, p-value = 1.008e-05

PCA

# PCA com a matriz de cov
res.pca.cov <- PCA(dados, scale.unit = F, graph = FALSE)
# matriz de covariância
round(cov(dados),2)
                     homicidio_doloso     furto     roubo roubo_furto_veiculos
homicidio_doloso               206.07  -1526.24   4190.21              3156.38
furto                        -1526.24  57352.79 -20611.99            -41428.18
roubo                         4190.21 -20611.99 109401.24             80241.60
roubo_furto_veiculos          3156.38 -41428.18  80241.60             75628.46
# autovalores
round(res.pca.cov$eig,3)
# autovetores
round(res.pca.cov$svd$V,3)
       [,1]   [,2]   [,3]   [,4]
[1,]  0.029  0.006 -0.117  0.993
[2,] -0.310  0.866  0.389  0.050
[3,]  0.716  0.484 -0.496 -0.082
[4,]  0.624 -0.125  0.768  0.073

Na primeira CP os coeficientes das variáveis roubo e roubo e furto de veículos são os maiores, pois as variâncias destas varáveis são maiores que as demais.

# A proporção de variação retida pelos componentes principais (CP) pode ser extraída da seguinte forma
round(res.pca.cov$eig,2)
# A importância dos CP pode ser visualizada usando o scree plot :
fviz_screeplot(res.pca.cov, ncp=4)+ theme_minimal()

# A correlação entre uma variável e um CP é chamada de carga (loadings). 
round(res.pca.cov$var$cor,4)
                       Dim.1   Dim.2   Dim.3   Dim.4
homicidio_doloso      0.8749  0.0956 -0.3933  0.2661
furto                -0.5624  0.8231  0.0784  0.0008
roubo                 0.9401  0.3331 -0.0723 -0.0010
roubo_furto_veiculos  0.9855 -0.1037  0.1347  0.0010

As CP também podem ser obtidas a partir as variáveis padronizadas

# PCA com a matriz de cor
res.pca.cor <- PCA(dados, scale.unit = T, graph = FALSE)
# matriz de covariância
round(cor(dados),4)
                     homicidio_doloso   furto   roubo roubo_furto_veiculos
homicidio_doloso               1.0000 -0.4440  0.8825               0.7995
furto                         -0.4440  1.0000 -0.2602              -0.6290
roubo                          0.8825 -0.2602  1.0000               0.8822
roubo_furto_veiculos           0.7995 -0.6290  0.8822               1.0000
# autovalores
round(res.pca.cor$eig,3)
# autovetores
round(res.pca.cor$svd$V,3)
       [,1]   [,2]   [,3]   [,4]
[1,]  0.533  0.213 -0.769  0.283
[2,] -0.361  0.870  0.108  0.317
[3,]  0.526  0.440  0.233 -0.690
[4,]  0.557 -0.056  0.586  0.586
# A proporção de variação retida pelos componentes principais (CP) pode ser extraída da seguinte forma
res.pca.cor$eig
# A importância dos CP pode ser visualizada usando o scree plot :
fviz_screeplot(res.pca.cor, ncp=4)+ theme_minimal()

# A correlação entre uma variável e um CP é chamada de carga (loadings). 
round(res.pca.cor$var$cor,4)
                       Dim.1   Dim.2   Dim.3   Dim.4
homicidio_doloso      0.9238  0.1904 -0.3312  0.0248
furto                -0.6252  0.7786  0.0465  0.0279
roubo                 0.9116  0.3939  0.1003 -0.0605
roubo_furto_veiculos  0.9649 -0.0501  0.2525  0.0515

O quadrado da correlação entre a variável e a CP representa a porcentagem de variância de uma das variáveis originais explicada por uma das CP

Conceito de Comunalidade

a comunalidade é a soma dos quadrados das correlações entre cada variável i e a componente principal j (ou o mesmo que o índice cos2). A soma limite-se ao número do componenentes retidos. Em nosso exemplo ilustrativo retemos todos os componentes que é igual ao número de variáveis.

# banseando-se na matriz de cov
round(res.pca.cov$var$cor^2,4)
                      Dim.1  Dim.2  Dim.3  Dim.4
homicidio_doloso     0.7654 0.0091 0.1547 0.0708
furto                0.3163 0.6775 0.0061 0.0000
roubo                0.8838 0.1110 0.0052 0.0000
roubo_furto_veiculos 0.9711 0.0107 0.0181 0.0000
# ou  round(res.pca.cov$var$cos2,4)
# veja que reter apens um CP é suficiente para explicar cerca de 76,5% da variabilidade do homicidio_doloso, e 31,6% da variável furto.
# a soma é igual a 100%
sum((res.pca.cov$var$cor^2)[1,])
[1] 1
# sum(res.pca.cov$var$cos2[1,])
# banseando-se na matriz de cor
round(res.pca.cor$var$cor^2,4)
                      Dim.1  Dim.2  Dim.3  Dim.4
homicidio_doloso     0.8534 0.0363 0.1097 0.0006
furto                0.3908 0.6062 0.0022 0.0008
roubo                0.8311 0.1552 0.0101 0.0037
roubo_furto_veiculos 0.9311 0.0025 0.0637 0.0026
# ou  round(res.pca.cor$var$cos2,4)
# veja que reter apens um CP é suficiente para explicar cerca de 85,3% da variabilidade do homicidio_doloso, e 39,1% da variável furto.

Mapa Fatorial

Quando um subespaço projetivo bidimensional determinado por duas direções principais escolhidas (CP), sua imagem geométrica plana com os pontos projetados e o círculo de correlações é denominada MAPA FATORIAL

# Quanto mais próxima uma variável for do círculo de correlações, melhor sua representação no mapa fatorial (e mais importante é a variável para a interpretação desses componentes)
# As variáveis próximas ao centro do gráfico são menos importantes para os primeiros componentes.
# No gráfico abaixo os componentes são coloridas de acordo com os valores do coseno quadrado:
fviz_pca_var(res.pca.cor, col.var="cos2") +
scale_color_gradient2(low="white", mid="blue", 
                    high="red", midpoint=0.5) + theme_minimal()

# Coordenadas de variáveis
round(res.pca.cor$var$coord,2)
                     Dim.1 Dim.2 Dim.3 Dim.4
homicidio_doloso      0.92  0.19 -0.33  0.02
furto                -0.63  0.78  0.05  0.03
roubo                 0.91  0.39  0.10 -0.06
roubo_furto_veiculos  0.96 -0.05  0.25  0.05
# Cos2: é uma medida que indica a qualidade da representação para variáveis no mapa fatorial
round(res.pca.cor$var$cos2,2)
                     Dim.1 Dim.2 Dim.3 Dim.4
homicidio_doloso      0.85  0.04  0.11     0
furto                 0.39  0.61  0.00     0
roubo                 0.83  0.16  0.01     0
roubo_furto_veiculos  0.93  0.00  0.06     0

Contribuições das variáveis para os componentes principais

As variáveis que são correlacionadas com PC1 e PC2 são as mais importantes para explicar a variabilidade no conjunto de dados. Variáveis que não se correlacionam com nenhum PC ou correlacionadas com as últimas dimensões são variáveis com baixa contribuição e podem ser removidas para simplificar a análise geral. As contribuições das variáveis na contabilização da variabilidade em uma determinada componente principal são (em porcentagem): (variável.cos2 * 100) / (cos2 total da componente)

# A contribuição das variáveis pode ser extraída da seguinte forma:
round(res.pca.cor$var$contrib,2)
                     Dim.1 Dim.2 Dim.3 Dim.4
homicidio_doloso     28.39  4.53 59.08  8.00
furto                13.00 75.76  1.17 10.07
roubo                27.64 19.39  5.42 47.55
roubo_furto_veiculos 30.97  0.31 34.34 34.38
# veja que a soma é igual a 100%
sum (res.pca.cor$var$contrib[,1])  
[1] 100
# Quanto maior o valor da contribuição, mais a variável contribui para o componente.
# As variáveis mais importantes associadas a um determinado PC podem ser visualizadas, usando a função fviz_contrib () [factoextra package], da seguinte forma:
# Contribuições de variáveis no PC1
fviz_contrib(res.pca.cor, choice = "var", axes = 1)+ theme_minimal()

# Contribuições de variáveis no PC2
fviz_contrib(res.pca.cor, choice = "var", axes = 2)+ theme_minimal()

# Contribuição total nos PC1 e PC2
fviz_contrib(res.pca.cor, choice = "var", axes = 1:2)+ theme_minimal()

# Controle as cores das variáveis usando suas contribuições
# a cor representa a contribuição conjunta dim1-dim2
fviz_pca_var(res.pca.cor, col.var="contrib")+ theme_minimal()

# Alterar a cor 
fviz_pca_var(res.pca.cor, col.var="contrib") +
scale_color_gradient2(low="white", mid="blue", 
                  high="red", midpoint=50) + theme_minimal()

# A função dimdesc () [em FactoMineR] pode ser usada para identificar as variáveis mais correlacionadas com uma determinada componente principal.
res.desc <- dimdesc(res.pca.cor, axes = c(1,2))
# Descrição da dimensão 1
res.desc$Dim.1
$quanti
                     correlation      p.value
roubo_furto_veiculos   0.9649332 2.569051e-05
homicidio_doloso       0.9238085 3.729002e-04
roubo                  0.9116461 6.186133e-04
# Descrição da dimensão 2
res.desc$Dim.2
$quanti
      correlation    p.value
furto   0.7786169 0.01343302
# Descrição da dimensão 3
res.desc$Dim.3
NULL

Se a análise for baseada na matriz de correlação, a primeira componente pode ser interpretada como a média de homicídio doloso, roubo e roubo e furto de veículos, os três crimes que incluem a presença da vítima na ocorrência do mesmo. A Segunda componente principal seria interpretada como a variável furto.

Análise de pontos (escores, objetos, indivíduos)

# Gráfico de escores (indivíduos ou pontos objetos)
# As coordenadas dos escores nos componentes principais são:
round(res.pca.cor$ind$coord,2)
         Dim.1 Dim.2 Dim.3 Dim.4
SJRP     -1.82  0.16  0.19  0.07
RP       -1.60  0.25  0.05  0.07
Bauru    -1.94 -0.09  0.20 -0.09
Campinas  0.18 -0.19  0.34  0.15
Sorocaba -0.82 -0.83  0.03 -0.16
SP        3.36  0.71  0.73 -0.05
SJC      -0.22 -0.15 -0.21 -0.02
Santos    0.62  1.78 -0.78 -0.02
GSP       2.24 -1.64 -0.55  0.04
fviz_pca_ind(res.pca.cor)+ theme_minimal()

#Cos2: qualidade da representação para escores nos componentes principais
# O coseno quadrado mostra a importância de um componente para uma determinada observação.
round(res.pca.cor$ind$cos2,3)
         Dim.1 Dim.2 Dim.3 Dim.4
SJRP     0.980 0.008 0.011 0.002
RP       0.974 0.023 0.001 0.002
Bauru    0.986 0.002 0.010 0.002
Campinas 0.163 0.175 0.559 0.103
Sorocaba 0.485 0.497 0.001 0.017
SP       0.916 0.041 0.043 0.000
SJC      0.414 0.195 0.390 0.002
Santos   0.093 0.763 0.144 0.000
GSP      0.627 0.335 0.038 0.000
fviz_pca_ind(res.pca.cor, col.ind="cos2") +
scale_color_gradient2(low="white", mid="blue", 
   high="red", midpoint=0.50) + theme_minimal()

# Contribuição dos escores para os componentes principais 
round(res.pca.cor$ind$contrib,2)
         Dim.1 Dim.2 Dim.3 Dim.4
SJRP     12.25  0.36  2.25  7.91
RP        9.47  0.85  0.17  6.91
Bauru    13.89  0.12  2.28 12.17
Campinas  0.12  0.50  6.93 30.64
Sorocaba  2.49  9.59  0.05 34.79
SP       41.66  6.98 31.60  4.01
SJC       0.18  0.32  2.74  0.33
Santos    1.43 44.15 35.97  0.46
GSP      18.51 37.13 18.02  2.77
# Contribuições de escores para PC1
fviz_contrib(res.pca.cor, choice = "ind", axes = 1)+ theme_minimal()

# Contribuições de escores para PC2
fviz_contrib(res.pca.cor, choice = "ind", axes = 2)+ theme_minimal()

# Contribuição total em PC1 e PC2
fviz_contrib(res.pca.cor, choice = "ind", axes = 1:2)+ theme_minimal()

# Contribuições dos escores para PC1  (apenas os "top")
fviz_contrib(res.pca.cor, choice = "ind", axes = 1:2, top = 5)+ theme_minimal()

# Mundando a cor
fviz_pca_ind(res.pca.cor, col.ind="contrib") +
scale_color_gradient2(low="white", mid="blue", 
                  high="red", midpoint=50) + theme_minimal()

O gráfico de dispersão dos escores dos dois primeiros componentes baseados na matriz de correlações juntamente com os respectivos autovetores

Este gráfico é chamado de biplot. É uma representação bidimensional de dados multivariados.

fviz_pca_biplot(res.pca.cor) + theme_minimal()

sumário

# sumário
facto_summarize(res.pca.cor, "var") # para variáveis
facto_summarize(res.pca.cor, "ind") # para escores
LS0tDQp0aXRsZTogJ0Fuw6FsaXNlIGRlIENvbXBvbmVudGVzIFByaW5jaXBhaXMgLSBBQ1AnDQphdXRob3I6ICJMZW9uaSwgUi4gQy4gUHJvZmVzc29yIERyLiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCioqKg0KDQojIyMgRXhlbXBsbyAxIC0gVGF4YSBkZSBEZWxpdG9zIHBvciAxMDAwMDAgaGFiaXRhbnRlcyBwb3IgZGl2aXPDo28gdGVycml0b3JpYWwgZGFzIHBvbMOtY2lhcyBkbyBFc3RhZG8gZGUgU1AgIChEZWludGVyKSBlbSAyMDAyLg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2djb3JycGxvdCkNCmxpYnJhcnkocHN5Y2gpDQpgYGANCg0KDQpgYGB7cn0NCiMgRGVpbnRlcg0KZGVpbnRlciAgPC0gYygiU0pSUCIsICJSUCIsICJCYXVydSIsICJDYW1waW5hcyIsICJTb3JvY2FiYSIsICJTUCIsICJTSkMiLCAiU2FudG9zIiwgIkdTUCIpDQojIFgxDQpob21pY2lkaW9fZG9sb3NvIDwtIGMoMTAuODUsMTQuMTMsOC42MiwyMy4wNCwxNi4wNCw0My43NCwyNS4zOSw0Mi44Niw0Mi41NSkNCiMgWDINCmZ1cnRvIDwtIGMoMTUwMC44MCwxNDk2LjA3LDE0NDguNzksMTI3Ny4zMywxMjA0LjAyLDExOTAuOTQsMTI5Mi45MSwxNTkwLjY2LDc5Ny4xNikNCiMgWDMNCnJvdWJvIDwtIGMoMTQ5LjM1LDE4Ny45OSwxMzAuOTcsNDI0Ljg3LDIxNC4zNiwxMTM5LjUyLDM1OC4zOSw3MjEuOTAsNTIwLjczKQ0KDQpyb3Vib19mdXJ0b192ZWljdWxvcyA8LSBjKDEwOC4zOCwxMTYuNjYsNjkuOTgsNDM1Ljc1LDIwNy4wNiw5MDkuMjEsMjY4LjI0LDI3NS44OSw2MDIuNjMpDQoNCmRhZG9zIDwtIGRhdGEuZnJhbWUoaG9taWNpZGlvX2RvbG9zbyxmdXJ0byxyb3Vibyxyb3Vib19mdXJ0b192ZWljdWxvcykNCg0Kcm93Lm5hbWVzKGRhZG9zKSA8LSBkZWludGVyDQpzdHIoZGFkb3MpDQpkYWRvcw0KI3RhaWwoZGFkb3MpDQoNCiMgc3Vtw6FyaW8gZXN0YXTDrXN0aWNvIA0KZGVzY3JpYmUoZGFkb3MpDQojIGdyw6FmaWNvIGJveHBsb3QgDQpib3hwbG90KGRhZG9zKSAjIGRhZG9zIG9yaWdpbmFpcw0KYm94cGxvdChzY2FsZShkYWRvcykpICMgZGFkb3MgcGFkcm9uaXphZG9zDQpgYGANCg0KIyMjIGNvcnJlbGHDp8O1ZXMNCmBgYHtyfQ0KIyBDb3JyZWxhdGlvbiBtYXRyaXgNCm1hdGNvciA8LSByb3VuZChjb3IoZGFkb3MpLCAyKQ0KbWF0Y29yDQoNCiMgUGxvdA0KZ2djb3JycGxvdChtYXRjb3IsIGhjLm9yZGVyID0gVFJVRSwgDQogICAgICAgICAgIHR5cGUgPSAibG93ZXIiLCANCiAgICAgICAgICAgbGFiID0gVFJVRSwgDQogICAgICAgICAgIGxhYl9zaXplID0gMywgDQogICAgICAgICAgIG1ldGhvZD0iY2lyY2xlIiwgDQogICAgICAgICAgIGNvbG9ycyA9IGMoInRvbWF0bzIiLCAid2hpdGUiLCAic3ByaW5nZ3JlZW4zIiksIA0KICAgICAgICAgICB0aXRsZT0iQ29ycmVsb2dyYW1hIiwgDQogICAgICAgICAgIGdndGhlbWU9dGhlbWVfYncpDQpgYGANCg0KDQojIyMgdGVzdGUgZGUgQmFydGxldHQNCiMjIyBCYXJ0bGV0dC5zcGhlcmljaXR5LnRlc3QNCg0KYGBge3J9DQpCYXJ0bGV0dC5zcGhlcmljaXR5LnRlc3QgPC0gZnVuY3Rpb24oeCkNCnsNCiAgbWV0aG9kIDwtICJCYXJ0bGV0dCdzIHRlc3Qgb2Ygc3BoZXJpY2l0eSINCiAgZGF0YS5uYW1lIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZSh4KSkNCiAgeCA8LSBzdWJzZXQoeCwgY29tcGxldGUuY2FzZXMoeCkpICMgT21pdCBtaXNzaW5nIHZhbHVlcw0KICBuIDwtIG5yb3coeCkNCiAgcCA8LSBuY29sKHgpDQogIGNoaXNxIDwtICgxLW4rKDIqcCs1KS82KSpsb2coZGV0KGNvcih4KSkpDQogIGRmIDwtIHAqKHAtMSkvMg0KICBwLnZhbHVlIDwtIHBjaGlzcShjaGlzcSwgZGYsIGxvd2VyLnRhaWw9RkFMU0UpDQogIG5hbWVzKGNoaXNxKSA8LSAiWC1zcXVhcmVkIg0KICBuYW1lcyhkZikgPC0gImRmIg0KICByZXR1cm4oc3RydWN0dXJlKGxpc3Qoc3RhdGlzdGljPWNoaXNxLCBwYXJhbWV0ZXI9ZGYsIHAudmFsdWU9cC52YWx1ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD1tZXRob2QsIGRhdGEubmFtZT1kYXRhLm5hbWUpLCBjbGFzcz0iaHRlc3QiKSkNCn0NCg0KQmFydGxldHQuc3BoZXJpY2l0eS50ZXN0KGRhZG9zKQ0KYGBgDQoNCiMjIyBQQ0ENCg0KYGBge3J9DQojIFBDQSBjb20gYSBtYXRyaXogZGUgY292DQpyZXMucGNhLmNvdiA8LSBQQ0EoZGFkb3MsIHNjYWxlLnVuaXQgPSBGLCBncmFwaCA9IEZBTFNFKQ0KIyBtYXRyaXogZGUgY292YXJpw6JuY2lhDQpyb3VuZChjb3YoZGFkb3MpLDIpDQojIGF1dG92YWxvcmVzDQpyb3VuZChyZXMucGNhLmNvdiRlaWcsMykNCiMgYXV0b3ZldG9yZXMNCnJvdW5kKHJlcy5wY2EuY292JHN2ZCRWLDMpDQpgYGANCg0KPiBOYSBwcmltZWlyYSBDUCBvcyBjb2VmaWNpZW50ZXMgZGFzIHZhcmnDoXZlaXMgcm91Ym8gZSByb3VibyBlIGZ1cnRvIGRlIHZlw61jdWxvcyBzw6NvIG9zIG1haW9yZXMsIHBvaXMgYXMgdmFyacOibmNpYXMgZGVzdGFzIHZhcsOhdmVpcyBzw6NvIG1haW9yZXMgcXVlIGFzIGRlbWFpcy4NCg0KYGBge3J9DQojIEEgcHJvcG9yw6fDo28gZGUgdmFyaWHDp8OjbyByZXRpZGEgcGVsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFpcyAoQ1ApIHBvZGUgc2VyIGV4dHJhw61kYSBkYSBzZWd1aW50ZSBmb3JtYQ0Kcm91bmQocmVzLnBjYS5jb3YkZWlnLDIpDQpgYGANCg0KDQpgYGB7cn0NCiMgQSBpbXBvcnTDom5jaWEgZG9zIENQIHBvZGUgc2VyIHZpc3VhbGl6YWRhIHVzYW5kbyBvIHNjcmVlIHBsb3QgOg0KZnZpel9zY3JlZXBsb3QocmVzLnBjYS5jb3YsIG5jcD00KSsgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBBIGNvcnJlbGHDp8OjbyBlbnRyZSB1bWEgdmFyacOhdmVsIGUgdW0gQ1Agw6kgY2hhbWFkYSBkZSBjYXJnYSAobG9hZGluZ3MpLiANCnJvdW5kKHJlcy5wY2EuY292JHZhciRjb3IsNCkNCmBgYA0KDQojIyMgQXMgQ1AgdGFtYsOpbSBwb2RlbSBzZXIgb2J0aWRhcyBhIHBhcnRpciBhcyB2YXJpw6F2ZWlzIHBhZHJvbml6YWRhcw0KDQpgYGB7cn0NCiMgUENBIGNvbSBhIG1hdHJpeiBkZSBjb3INCnJlcy5wY2EuY29yIDwtIFBDQShkYWRvcywgc2NhbGUudW5pdCA9IFQsIGdyYXBoID0gRkFMU0UpDQojIG1hdHJpeiBkZSBjb3ZhcmnDom5jaWENCnJvdW5kKGNvcihkYWRvcyksNCkNCiMgYXV0b3ZhbG9yZXMNCnJvdW5kKHJlcy5wY2EuY29yJGVpZywzKQ0KIyBhdXRvdmV0b3Jlcw0Kcm91bmQocmVzLnBjYS5jb3Ikc3ZkJFYsMykNCiMgQSBwcm9wb3LDp8OjbyBkZSB2YXJpYcOnw6NvIHJldGlkYSBwZWxvcyBjb21wb25lbnRlcyBwcmluY2lwYWlzIChDUCkgcG9kZSBzZXIgZXh0cmHDrWRhIGRhIHNlZ3VpbnRlIGZvcm1hDQpyZXMucGNhLmNvciRlaWcNCiMgQSBpbXBvcnTDom5jaWEgZG9zIENQIHBvZGUgc2VyIHZpc3VhbGl6YWRhIHVzYW5kbyBvIHNjcmVlIHBsb3QgOg0KZnZpel9zY3JlZXBsb3QocmVzLnBjYS5jb3IsIG5jcD00KSsgdGhlbWVfbWluaW1hbCgpDQojIEEgY29ycmVsYcOnw6NvIGVudHJlIHVtYSB2YXJpw6F2ZWwgZSB1bSBDUCDDqSBjaGFtYWRhIGRlIGNhcmdhIChsb2FkaW5ncykuIA0Kcm91bmQocmVzLnBjYS5jb3IkdmFyJGNvciw0KQ0KYGBgDQoNCg0KIyMjIE8gcXVhZHJhZG8gZGEgY29ycmVsYcOnw6NvIGVudHJlIGEgdmFyacOhdmVsIGUgYSBDUCByZXByZXNlbnRhIGEgcG9yY2VudGFnZW0gZGUgdmFyacOibmNpYSBkZSB1bWEgZGFzIHZhcmnDoXZlaXMgb3JpZ2luYWlzIGV4cGxpY2FkYSBwb3IgdW1hIGRhcyBDUA0KDQojIyBDb25jZWl0byBkZSBDb211bmFsaWRhZGUNCj4gYSBjb211bmFsaWRhZGUgw6kgYSBzb21hIGRvcyBxdWFkcmFkb3MgZGFzIGNvcnJlbGHDp8O1ZXMgZW50cmUgY2FkYSB2YXJpw6F2ZWwgaSBlIGEgY29tcG9uZW50ZSBwcmluY2lwYWwgaiAob3UgbyBtZXNtbyBxdWUgbyDDrW5kaWNlIGNvczIpLiBBIHNvbWEgbGltaXRlLXNlIGFvIG7Dum1lcm8gZG8gY29tcG9uZW5lbnRlcyByZXRpZG9zLiBFbSBub3NzbyBleGVtcGxvIGlsdXN0cmF0aXZvIHJldGVtb3MgdG9kb3Mgb3MgY29tcG9uZW50ZXMgcXVlIMOpIGlndWFsIGFvIG7Dum1lcm8gZGUgdmFyacOhdmVpcy4gDQoNCg0KYGBge3J9DQojIGJhbnNlYW5kby1zZSBuYSBtYXRyaXogZGUgY292DQpyb3VuZChyZXMucGNhLmNvdiR2YXIkY29yXjIsNCkNCiMgb3UgIHJvdW5kKHJlcy5wY2EuY292JHZhciRjb3MyLDQpDQoNCiMgdmVqYSBxdWUgcmV0ZXIgYXBlbnMgdW0gQ1Agw6kgc3VmaWNpZW50ZSBwYXJhIGV4cGxpY2FyIGNlcmNhIGRlIDc2LDUlIGRhIHZhcmlhYmlsaWRhZGUgZG8gaG9taWNpZGlvX2RvbG9zbywgZSAzMSw2JSBkYSB2YXJpw6F2ZWwgZnVydG8uDQoNCiMgYSBzb21hIMOpIGlndWFsIGEgMTAwJQ0Kc3VtKChyZXMucGNhLmNvdiR2YXIkY29yXjIpWzEsXSkNCiMgc3VtKHJlcy5wY2EuY292JHZhciRjb3MyWzEsXSkNCg0KIyBiYW5zZWFuZG8tc2UgbmEgbWF0cml6IGRlIGNvcg0Kcm91bmQocmVzLnBjYS5jb3IkdmFyJGNvcl4yLDQpDQojIG91ICByb3VuZChyZXMucGNhLmNvciR2YXIkY29zMiw0KQ0KIyB2ZWphIHF1ZSByZXRlciBhcGVucyB1bSBDUCDDqSBzdWZpY2llbnRlIHBhcmEgZXhwbGljYXIgY2VyY2EgZGUgODUsMyUgZGEgdmFyaWFiaWxpZGFkZSBkbyBob21pY2lkaW9fZG9sb3NvLCBlIDM5LDElIGRhIHZhcmnDoXZlbCBmdXJ0by4NCmBgYA0KDQoNCiMjIyBNYXBhIEZhdG9yaWFsIA0KDQo+IFF1YW5kbyB1bSBzdWJlc3Bhw6dvIHByb2pldGl2byBiaWRpbWVuc2lvbmFsIGRldGVybWluYWRvIHBvciBkdWFzIGRpcmXDp8O1ZXMgcHJpbmNpcGFpcyBlc2NvbGhpZGFzIChDUCksIHN1YSBpbWFnZW0gZ2VvbcOpdHJpY2EgcGxhbmEgY29tIG9zIHBvbnRvcyBwcm9qZXRhZG9zIGUgbyBjw61yY3VsbyBkZSBjb3JyZWxhw6fDtWVzIMOpIGRlbm9taW5hZGEgTUFQQSBGQVRPUklBTCAgIA0KDQpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OX0NCiMgUXVhbnRvIG1haXMgcHLDs3hpbWEgdW1hIHZhcmnDoXZlbCBmb3IgZG8gY8OtcmN1bG8gZGUgY29ycmVsYcOnw7VlcywgbWVsaG9yIHN1YSByZXByZXNlbnRhw6fDo28gbm8gbWFwYSBmYXRvcmlhbCAoZSBtYWlzIGltcG9ydGFudGUgw6kgYSB2YXJpw6F2ZWwgcGFyYSBhIGludGVycHJldGHDp8OjbyBkZXNzZXMgY29tcG9uZW50ZXMpDQojIEFzIHZhcmnDoXZlaXMgcHLDs3hpbWFzIGFvIGNlbnRybyBkbyBncsOhZmljbyBzw6NvIG1lbm9zIGltcG9ydGFudGVzIHBhcmEgb3MgcHJpbWVpcm9zIGNvbXBvbmVudGVzLg0KIyBObyBncsOhZmljbyBhYmFpeG8gb3MgY29tcG9uZW50ZXMgc8OjbyBjb2xvcmlkYXMgZGUgYWNvcmRvIGNvbSBvcyB2YWxvcmVzIGRvIGNvc2VubyBxdWFkcmFkbzoNCg0KZnZpel9wY2FfdmFyKHJlcy5wY2EuY29yLCBjb2wudmFyPSJjb3MyIikgKw0Kc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdz0id2hpdGUiLCBtaWQ9ImJsdWUiLCANCiAgICAgICAgICAgICAgICAgICAgaGlnaD0icmVkIiwgbWlkcG9pbnQ9MC41KSArIHRoZW1lX21pbmltYWwoKQ0KDQojIENvb3JkZW5hZGFzIGRlIHZhcmnDoXZlaXMNCnJvdW5kKHJlcy5wY2EuY29yJHZhciRjb29yZCwyKQ0KDQojIENvczI6IMOpIHVtYSBtZWRpZGEgcXVlIGluZGljYSBhIHF1YWxpZGFkZSBkYSByZXByZXNlbnRhw6fDo28gcGFyYSB2YXJpw6F2ZWlzIG5vIG1hcGEgZmF0b3JpYWwNCnJvdW5kKHJlcy5wY2EuY29yJHZhciRjb3MyLDIpDQpgYGANCg0KDQojIyMgQ29udHJpYnVpw6fDtWVzIGRhcyB2YXJpw6F2ZWlzIHBhcmEgb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFpcw0KDQo+IEFzIHZhcmnDoXZlaXMgcXVlIHPDo28gY29ycmVsYWNpb25hZGFzIGNvbSBQQzEgZSBQQzIgc8OjbyBhcyBtYWlzIGltcG9ydGFudGVzIHBhcmEgZXhwbGljYXIgYSB2YXJpYWJpbGlkYWRlIG5vIGNvbmp1bnRvIGRlIGRhZG9zLiBWYXJpw6F2ZWlzIHF1ZSBuw6NvIHNlIGNvcnJlbGFjaW9uYW0gY29tIG5lbmh1bSBQQyBvdSBjb3JyZWxhY2lvbmFkYXMgY29tIGFzIMO6bHRpbWFzIGRpbWVuc8O1ZXMgc8OjbyB2YXJpw6F2ZWlzIGNvbSBiYWl4YSBjb250cmlidWnDp8OjbyBlIHBvZGVtIHNlciByZW1vdmlkYXMgcGFyYSBzaW1wbGlmaWNhciBhIGFuw6FsaXNlIGdlcmFsLiBBcyBjb250cmlidWnDp8O1ZXMgZGFzIHZhcmnDoXZlaXMgbmEgY29udGFiaWxpemHDp8OjbyBkYSB2YXJpYWJpbGlkYWRlIGVtIHVtYSBkZXRlcm1pbmFkYSBjb21wb25lbnRlIHByaW5jaXBhbCBzw6NvIChlbSBwb3JjZW50YWdlbSk6ICh2YXJpw6F2ZWwuY29zMiAqIDEwMCkgLyAoY29zMiB0b3RhbCBkYSBjb21wb25lbnRlKQ0KDQpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OX0NCiMgQSBjb250cmlidWnDp8OjbyBkYXMgdmFyacOhdmVpcyBwb2RlIHNlciBleHRyYcOtZGEgZGEgc2VndWludGUgZm9ybWE6DQpyb3VuZChyZXMucGNhLmNvciR2YXIkY29udHJpYiwyKQ0KIyB2ZWphIHF1ZSBhIHNvbWEgw6kgaWd1YWwgYSAxMDAlDQpzdW0gKHJlcy5wY2EuY29yJHZhciRjb250cmliWywxXSkgIA0KDQojIFF1YW50byBtYWlvciBvIHZhbG9yIGRhIGNvbnRyaWJ1acOnw6NvLCBtYWlzIGEgdmFyacOhdmVsIGNvbnRyaWJ1aSBwYXJhIG8gY29tcG9uZW50ZS4NCiMgQXMgdmFyacOhdmVpcyBtYWlzIGltcG9ydGFudGVzIGFzc29jaWFkYXMgYSB1bSBkZXRlcm1pbmFkbyBQQyBwb2RlbSBzZXIgdmlzdWFsaXphZGFzLCB1c2FuZG8gYSBmdW7Dp8OjbyBmdml6X2NvbnRyaWIgKCkgW2ZhY3RvZXh0cmEgcGFja2FnZV0sIGRhIHNlZ3VpbnRlIGZvcm1hOg0KDQojIENvbnRyaWJ1acOnw7VlcyBkZSB2YXJpw6F2ZWlzIG5vIFBDMQ0KZnZpel9jb250cmliKHJlcy5wY2EuY29yLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDEpKyB0aGVtZV9taW5pbWFsKCkNCg0KIyBDb250cmlidWnDp8O1ZXMgZGUgdmFyacOhdmVpcyBubyBQQzINCmZ2aXpfY29udHJpYihyZXMucGNhLmNvciwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAyKSsgdGhlbWVfbWluaW1hbCgpDQoNCiMgQ29udHJpYnVpw6fDo28gdG90YWwgbm9zIFBDMSBlIFBDMg0KZnZpel9jb250cmliKHJlcy5wY2EuY29yLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDE6MikrIHRoZW1lX21pbmltYWwoKQ0KDQojIENvbnRyb2xlIGFzIGNvcmVzIGRhcyB2YXJpw6F2ZWlzIHVzYW5kbyBzdWFzIGNvbnRyaWJ1acOnw7Vlcw0KIyBhIGNvciByZXByZXNlbnRhIGEgY29udHJpYnVpw6fDo28gY29uanVudGEgZGltMS1kaW0yDQpmdml6X3BjYV92YXIocmVzLnBjYS5jb3IsIGNvbC52YXI9ImNvbnRyaWIiKSsgdGhlbWVfbWluaW1hbCgpDQoNCiMgQWx0ZXJhciBhIGNvciANCmZ2aXpfcGNhX3ZhcihyZXMucGNhLmNvciwgY29sLnZhcj0iY29udHJpYiIpICsNCnNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3c9IndoaXRlIiwgbWlkPSJibHVlIiwgDQogICAgICAgICAgICAgICAgICBoaWdoPSJyZWQiLCBtaWRwb2ludD01MCkgKyB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCg0KYGBge3J9DQojIEEgZnVuw6fDo28gZGltZGVzYyAoKSBbZW0gRmFjdG9NaW5lUl0gcG9kZSBzZXIgdXNhZGEgcGFyYSBpZGVudGlmaWNhciBhcyB2YXJpw6F2ZWlzIG1haXMgY29ycmVsYWNpb25hZGFzIGNvbSB1bWEgZGV0ZXJtaW5hZGEgY29tcG9uZW50ZSBwcmluY2lwYWwuDQpyZXMuZGVzYyA8LSBkaW1kZXNjKHJlcy5wY2EuY29yLCBheGVzID0gYygxLDIpKQ0KIyBEZXNjcmnDp8OjbyBkYSBkaW1lbnPDo28gMQ0KcmVzLmRlc2MkRGltLjENCiMgRGVzY3Jpw6fDo28gZGEgZGltZW5zw6NvIDINCnJlcy5kZXNjJERpbS4yDQojIERlc2NyacOnw6NvIGRhIGRpbWVuc8OjbyAzDQpyZXMuZGVzYyREaW0uMw0KYGBgDQoNCiMjIFNlIGEgYW7DoWxpc2UgZm9yIGJhc2VhZGEgbmEgbWF0cml6IGRlIGNvcnJlbGHDp8OjbywgYSBwcmltZWlyYSBjb21wb25lbnRlIHBvZGUgc2VyIGludGVycHJldGFkYSBjb21vIGEgbcOpZGlhIGRlIGhvbWljw61kaW8gZG9sb3NvLCByb3VibyBlIHJvdWJvIGUgZnVydG8gZGUgdmXDrWN1bG9zLCBvcyB0csOqcyBjcmltZXMgcXVlIGluY2x1ZW0gYSBwcmVzZW7Dp2EgZGEgdsOtdGltYSBuYSBvY29ycsOqbmNpYSBkbyBtZXNtby4gQSBTZWd1bmRhIGNvbXBvbmVudGUgcHJpbmNpcGFsIHNlcmlhIGludGVycHJldGFkYSBjb21vIGEgdmFyacOhdmVsIGZ1cnRvLiAgICANCg0KDQojIyMgQW7DoWxpc2UgZGUgcG9udG9zIChlc2NvcmVzLCBvYmpldG9zLCBpbmRpdsOtZHVvcykNCg0KDQpgYGB7cn0NCiMgR3LDoWZpY28gZGUgZXNjb3JlcyAoaW5kaXbDrWR1b3Mgb3UgcG9udG9zIG9iamV0b3MpDQojIEFzIGNvb3JkZW5hZGFzIGRvcyBlc2NvcmVzIG5vcyBjb21wb25lbnRlcyBwcmluY2lwYWlzIHPDo286DQpyb3VuZChyZXMucGNhLmNvciRpbmQkY29vcmQsMikNCmZ2aXpfcGNhX2luZChyZXMucGNhLmNvcikrIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KI0NvczI6IHF1YWxpZGFkZSBkYSByZXByZXNlbnRhw6fDo28gcGFyYSBlc2NvcmVzIG5vcyBjb21wb25lbnRlcyBwcmluY2lwYWlzDQojIE8gY29zZW5vIHF1YWRyYWRvIG1vc3RyYSBhIGltcG9ydMOibmNpYSBkZSB1bSBjb21wb25lbnRlIHBhcmEgdW1hIGRldGVybWluYWRhIG9ic2VydmHDp8Ojby4NCnJvdW5kKHJlcy5wY2EuY29yJGluZCRjb3MyLDMpDQoNCmZ2aXpfcGNhX2luZChyZXMucGNhLmNvciwgY29sLmluZD0iY29zMiIpICsNCnNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3c9IndoaXRlIiwgbWlkPSJibHVlIiwgDQogICBoaWdoPSJyZWQiLCBtaWRwb2ludD0wLjUwKSArIHRoZW1lX21pbmltYWwoKQ0KDQojIENvbnRyaWJ1acOnw6NvIGRvcyBlc2NvcmVzIHBhcmEgb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFpcyANCnJvdW5kKHJlcy5wY2EuY29yJGluZCRjb250cmliLDIpDQojIENvbnRyaWJ1acOnw7VlcyBkZSBlc2NvcmVzIHBhcmEgUEMxDQpmdml6X2NvbnRyaWIocmVzLnBjYS5jb3IsIGNob2ljZSA9ICJpbmQiLCBheGVzID0gMSkrIHRoZW1lX21pbmltYWwoKQ0KIyBDb250cmlidWnDp8O1ZXMgZGUgZXNjb3JlcyBwYXJhIFBDMg0KZnZpel9jb250cmliKHJlcy5wY2EuY29yLCBjaG9pY2UgPSAiaW5kIiwgYXhlcyA9IDIpKyB0aGVtZV9taW5pbWFsKCkNCiMgQ29udHJpYnVpw6fDo28gdG90YWwgZW0gUEMxIGUgUEMyDQpmdml6X2NvbnRyaWIocmVzLnBjYS5jb3IsIGNob2ljZSA9ICJpbmQiLCBheGVzID0gMToyKSsgdGhlbWVfbWluaW1hbCgpDQojIENvbnRyaWJ1acOnw7VlcyBkb3MgZXNjb3JlcyBwYXJhIFBDMSAgKGFwZW5hcyBvcyAidG9wIikNCmZ2aXpfY29udHJpYihyZXMucGNhLmNvciwgY2hvaWNlID0gImluZCIsIGF4ZXMgPSAxOjIsIHRvcCA9IDUpKyB0aGVtZV9taW5pbWFsKCkNCiMgTXVuZGFuZG8gYSBjb3INCmZ2aXpfcGNhX2luZChyZXMucGNhLmNvciwgY29sLmluZD0iY29udHJpYiIpICsNCnNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3c9IndoaXRlIiwgbWlkPSJibHVlIiwgDQogICAgICAgICAgICAgICAgICBoaWdoPSJyZWQiLCBtaWRwb2ludD01MCkgKyB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyMgTyBncsOhZmljbyBkZSBkaXNwZXJzw6NvIGRvcyBlc2NvcmVzIGRvcyBkb2lzIHByaW1laXJvcyBjb21wb25lbnRlcyBiYXNlYWRvcyBuYSBtYXRyaXogZGUgY29ycmVsYcOnw7VlcyBqdW50YW1lbnRlIGNvbSBvcyByZXNwZWN0aXZvcyBhdXRvdmV0b3JlcyANCiMjIyBFc3RlIGdyw6FmaWNvIMOpIGNoYW1hZG8gZGUgYmlwbG90LiDDiSB1bWEgcmVwcmVzZW50YcOnw6NvIGJpZGltZW5zaW9uYWwgZGUgZGFkb3MgbXVsdGl2YXJpYWRvcy4NCg0KYGBge3J9DQpmdml6X3BjYV9iaXBsb3QocmVzLnBjYS5jb3IpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMjIHN1bcOhcmlvDQoNCmBgYHtyfQ0KIyBzdW3DoXJpbw0KZmFjdG9fc3VtbWFyaXplKHJlcy5wY2EuY29yLCAidmFyIikgIyBwYXJhIHZhcmnDoXZlaXMNCmZhY3RvX3N1bW1hcml6ZShyZXMucGNhLmNvciwgImluZCIpICMgcGFyYSBlc2NvcmVzDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=