library(tidyverse)
library(readr)
library(scales)
library(ggthemes)
library(reshape2)
library(ggplot2)
library(factoextra)
library(psych)
library(cluster)
library(NbClust)
library(readxl)
library(robustX)
library(dendextend)
library(corrplot)
library(RColorBrewer)
#display.brewer.all()
library(readxl)
covidcluster <- read_excel("covidcluster_worldometers.xlsx", sheet="worldometers", col_types = c("text",
"numeric", "numeric", "numeric",
"numeric", "numeric", "numeric",
"numeric", "numeric", "numeric"))
covidcluster
Preparação dos dados
dados1 <- as.data.frame(covidcluster)
#head(dados)
#is(dados)
# só países com mais de 100 mortes
dados1 <- dados1 %>% filter(total_deaths>=300)
#nomes dos países
nomes <- dados1$country
dados1 <- dados1[,-1]
row.names(dados1) <- c(nomes)
head(dados1)
#selecionar variáveis
dados1 <-dados1[,-c(3,5,8,9)]
# retirar NA
dados <- na.omit(dados1) #df2 <- df[complete.cases(df),]
#describe(dados)
#padronizar dados
dados <- scale(dados)
head(dados)
total_cases total_deaths active_cases totcases_1Mpop deaths_1Mpop
USA 5.6668836 4.9070492 5.80643473 1.6302248 0.5748437
Spain 0.7376955 1.2925839 0.02186621 2.6339134 2.3152996
UK 0.5339503 1.6424269 0.76051366 1.0457738 1.7797747
Italy 0.5334440 1.5558685 0.14982946 1.3030629 1.9725636
Russia 0.4914138 -0.3587768 0.68088200 -0.1244343 -0.6622188
France 0.3443794 1.2764753 0.21431479 0.7068575 1.4316835
# Compute dissimilarity matrix
d <- dist(dados, method = "euclidean")
#d <-d^2 # dist quad Euclidiana
# O pacote vegan apresenta muitas opções de distâncias para dados não métricos; inclusive a quadrática euclidiana.
# library(vegan)
# ?designdist
# d <- designdist(dados, method = "A+B-2*J", terms = c("quadratic"))
# d
# Hierarchical clustering using complete method
hc <- hclust(d, method = "ward.D2" )
plot(hc,cex=0.6,labels=rownames(dados), hang = -1) # display dendogram

# ou
# plot(hc,cex=0.6,labels=rownames(dados)) # display dendogram
# outliers
#outliers <- BACON(dados)
# outliers
# há obs discrepante?
#table(outliers$subset)
#rownames(dados)[outliers$subset== F]
k=4
# Cut tree into 4 groups
grupos <- cutree(hc, k)
#grupos
#rownames(dados)[grupos == 1]
#rownames(dados)[grupos == 2]
#rownames(dados)[grupos == 3]
#rownames(dados)[grupos == 4]
#rownames(dados)[grupos == 5]
# Algoritmo Hierárquico - Usando o pacote factoextra
# ?hcut
# este pacote não tem dist quad Euclidiana
#res <- hcut(dados, k , stand = TRUE,
# hc_func = "hclust",
# hc_method = "ward.D2",
# hc_metric = "euclidean")
#fviz_dend(res, rect = T, cex = 0.7, horiz = F, palette = brewer.pal(n=k,name="Dark2"))
#fviz_cluster(res,repel = T, kcolors=brewer.pal(n=k,name="Dark2")) + theme_bw()
#fviz_silhouette(res)+theme_bw()+ theme(axis.text.x = element_text(angle=90))
Algoritmo Hierárquico
dados_dist <- daisy(dados, metric = "euclidean")
res.hc <- hclust(d = dados_dist, method = "ward.D2")
#Ward’s minimum variance method: It minimizes the total within-cluster variance. At each step the pair of clusters with minimum between-cluster distance are merged.
#fviz_dend(res.hc, cex = 0.5)
# Cut tree into k groups
#k=7
grp <- cutree(res.hc, k )
#grp
#table(grp)
#colors()
# Cut in k groups and color by groups
fviz_dend(res.hc, k , # Cut in k groups
cex = 0.5, # label size
k_colors = brewer.pal(n=k,name="Dark2"),
color_labels_by_k = TRUE, # color labels by groups
rect = TRUE # Add rectangle around groups
, ggtheme = theme_bw(18))

# como fazer com as dist? só lançar data como matriz de distâncias
fviz_cluster(list(data = dados_dist, cluster = grp),
palette = brewer.pal(n=k,name="Dark2"),
#ellipse.type = "confidence", # Concentration ellipse
repel = TRUE, # Avoid label overplotting (slow)
show.clust.cent = T, ggtheme = theme_bw(18), labelsize=18)

NA
NA
NA
# It’s possible to compare simultaneously multiple dendrograms.
# A chaining operator %>% (available in dendextend) is used to run multiple function at the same time. It’s useful for simplifying the code:
# Create multiple dendrograms by chaining
dend1 <- dados %>% dist("euclidean") %>% hclust("complete") %>% as.dendrogram
dend2 <- dados %>% dist("euclidean") %>% hclust("single") %>% as.dendrogram
dend3 <- dados %>% dist("euclidean") %>% hclust("average") %>% as.dendrogram
dend4 <- dados %>% dist("euclidean") %>% hclust("centroid") %>% as.dendrogram
dend5 <- dados %>% dist("euclidean") %>% hclust("ward.D2") %>% as.dendrogram
#?hclust
# Compute correlation matrix
dend_list <- dendlist("Complete" = dend1, "Single" = dend2,
"Average" = dend3, "Centroid" = dend4,
"ward"= dend5)
#Computes the cophenetic distances for a hierarchical clustering.
# ?cor.dendlist
cors <- cor.dendlist(dend_list)
# Print correlation matrix
round(cors, 2)
Complete Single Average Centroid ward
Complete 1.00 0.83 0.92 0.88 0.88
Single 0.83 1.00 0.96 0.99 0.59
Average 0.92 0.96 1.00 0.99 0.74
Centroid 0.88 0.99 0.99 1.00 0.66
ward 0.88 0.59 0.74 0.66 1.00
# Visualize the correlation matrix using corrplot package
corrplot(cors, "number", "lower")

corrplot(cors, "pie", "lower")

algoritmo não hierárquico PAM
# Calculate silhouette width for many k using PAM
#gower_dist - matriz com as distâncias
sil_width <- c(NA)
for(i in 2:8){
pam_fit <- pam(dados_dist,
diss = TRUE,
k = i)
sil_width[i] <- pam_fit$silinfo$avg.width
}
# Plot sihouette width (higher is better)
plot(1:8, sil_width,
xlab = "Number of clusters",
ylab = "Silhouette Width")
lines(1:8, sil_width)

library(fpc)
package 㤼㸱fpc㤼㸲 was built under R version 3.6.3
pamk(dados_dist, diss=T,krange=2:7,criterion="asw", usepam=TRUE)
$pamobject
Medoids:
ID
[1,] "4" "Italy"
[2,] "28" "Romania"
Clustering vector:
USA Spain UK Italy Russia France Germany
1 1 1 1 2 1 2
Brazil Turkey Iran China Canada Peru India
2 2 2 2 2 2 2
Belgium Netherlands Mexico Pakistan Switzerland Ecuador Chile
1 2 2 2 2 2 2
Portugal Sweden Ireland Poland Austria Japan Romania
2 2 1 2 2 2 2
Ukraine Indonesia Philippines Colombia Denmark Dominican Republic Egypt
2 2 2 2 2 2 2
Argentina Algeria Hungary
2 2 2
Objective function:
build swap
1.037593 1.037593
Available components:
[1] "medoids" "id.med" "clustering" "objective" "isolation" "clusinfo" "silinfo" "diss" "call"
$nc
[1] 2
$crit
[1] 0.0000000 0.6397794 0.6267032 0.4721142 0.4919354 0.4902504 0.4559666
Cluster plot PAM
pam_fit <- pam(dados_dist, diss = TRUE, k)
#dados[pam_fit$medoids, ]
#print(pam_fit)
grp = pam_fit$clustering
# como fazer com as dist? só lançar data como matriz de distâncias
fviz_cluster(list(data = dados_dist, cluster = grp),
palette = brewer.pal(n=k,name="Dark2"),
repel = TRUE, # Avoid label overplotting (slow)
show.clust.cent = T, ggtheme = theme_bw(16))

# Descrição dos grupos pelo PAM
#pam_results <- dados %>%
# dplyr::mutate(cluster = pam_fit$clustering) %>%
# group_by(cluster) %>%
# do(the_summary = summary(.))
#pam_results$the_summary
LS0tDQp0aXRsZTogIkNvdmlkLTE5LSB3b3JsZG9tZXRlcnMtY2x1c3RlcnMiDQphdXRob3I6ICJQcm9mZXNzb3IgRHIuIExlb25pLCBSLiBDLiAtIEFNQU4gLSBSZXNlbmRlIC0gUkouIg0KZGF0ZTogJ1JlbGF0w7NyaW8gZ2VyYWRvIGVtOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVkIGRlICVCIGRlICVZIilgJw0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICB0aGVtZTogam91cm5hbA0KICAgIHRvYzogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCmVtYWlsOiBsZW9uaS5yb2JlcnRvQGFtYW4uZWIubWlsLmJyDQotLS0NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShyZXNoYXBlMikNCg0KbGlicmFyeShnZ3Bsb3QyKSAgDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeShjbHVzdGVyKQ0KbGlicmFyeShOYkNsdXN0KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHJvYnVzdFgpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCiNkaXNwbGF5LmJyZXdlci5hbGwoKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHJlYWR4bCkNCmNvdmlkY2x1c3RlciA8LSByZWFkX2V4Y2VsKCJjb3ZpZGNsdXN0ZXJfd29ybGRvbWV0ZXJzLnhsc3giLCBzaGVldD0id29ybGRvbWV0ZXJzIiwgY29sX3R5cGVzID0gYygidGV4dCIsIA0KICAgICAgICAibnVtZXJpYyIsICJudW1lcmljIiwgIm51bWVyaWMiLCANCiAgICAgICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgICAgICJudW1lcmljIiwgIm51bWVyaWMiLCAibnVtZXJpYyIpKSANCmNvdmlkY2x1c3Rlcg0KYGBgDQoNCg0KIyBQcmVwYXJhw6fDo28gZG9zIGRhZG9zDQpgYGB7cn0NCmRhZG9zMSA8LSBhcy5kYXRhLmZyYW1lKGNvdmlkY2x1c3RlcikNCiNoZWFkKGRhZG9zKQ0KI2lzKGRhZG9zKQ0KIyBzw7MgcGHDrXNlcyBjb20gbWFpcyBkZSAxMDAgbW9ydGVzDQoNCmRhZG9zMSA8LSBkYWRvczEgJT4lIGZpbHRlcih0b3RhbF9kZWF0aHM+PTMwMCkNCg0KI25vbWVzIGRvcyBwYcOtc2VzDQpub21lcyA8LSBkYWRvczEkY291bnRyeQ0KZGFkb3MxIDwtIGRhZG9zMVssLTFdDQpyb3cubmFtZXMoZGFkb3MxKSA8LSBjKG5vbWVzKQ0KaGVhZChkYWRvczEpDQoNCiNzZWxlY2lvbmFyIHZhcmnDoXZlaXMNCmRhZG9zMSA8LWRhZG9zMVssLWMoMyw1LDgsOSldDQoNCiMgcmV0aXJhciBOQQ0KZGFkb3MgPC0gbmEub21pdChkYWRvczEpICAjZGYyIDwtIGRmW2NvbXBsZXRlLmNhc2VzKGRmKSxdDQojZGVzY3JpYmUoZGFkb3MpDQojcGFkcm9uaXphciBkYWRvcw0KZGFkb3MgPC0gc2NhbGUoZGFkb3MpDQpoZWFkKGRhZG9zKQ0KDQpgYGANCg0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEyfQ0KIyBDb21wdXRlIGRpc3NpbWlsYXJpdHkgbWF0cml4DQpkIDwtIGRpc3QoZGFkb3MsIG1ldGhvZCA9ICJldWNsaWRlYW4iKQ0KI2QgPC1kXjIgIyBkaXN0IHF1YWQgRXVjbGlkaWFuYQ0KDQojIE8gcGFjb3RlIHZlZ2FuIGFwcmVzZW50YSBtdWl0YXMgb3DDp8O1ZXMgZGUgZGlzdMOibmNpYXMgcGFyYSBkYWRvcyBuw6NvIG3DqXRyaWNvczsgaW5jbHVzaXZlIGEgcXVhZHLDoXRpY2EgZXVjbGlkaWFuYS4gDQojIGxpYnJhcnkodmVnYW4pDQojID9kZXNpZ25kaXN0DQojIGQgPC0gZGVzaWduZGlzdChkYWRvcywgbWV0aG9kID0gIkErQi0yKkoiLCB0ZXJtcyA9IGMoInF1YWRyYXRpYyIpKQ0KIyBkDQoNCiMgSGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgdXNpbmcgY29tcGxldGUgbWV0aG9kDQpoYyA8LSBoY2x1c3QoZCwgbWV0aG9kID0gIndhcmQuRDIiICkNCg0KcGxvdChoYyxjZXg9MC42LGxhYmVscz1yb3duYW1lcyhkYWRvcyksIGhhbmcgPSAtMSkgIyBkaXNwbGF5IGRlbmRvZ3JhbQ0KIyBvdQ0KIyBwbG90KGhjLGNleD0wLjYsbGFiZWxzPXJvd25hbWVzKGRhZG9zKSkgIyBkaXNwbGF5IGRlbmRvZ3JhbQ0KDQpgYGANCg0KYGBge3J9DQojIG91dGxpZXJzDQoNCiNvdXRsaWVycyA8LSBCQUNPTihkYWRvcykNCiMgb3V0bGllcnMNCg0KDQojIGjDoSBvYnMgZGlzY3JlcGFudGU/DQojdGFibGUob3V0bGllcnMkc3Vic2V0KQ0KI3Jvd25hbWVzKGRhZG9zKVtvdXRsaWVycyRzdWJzZXQ9PSBGXQ0KYGBgDQoNCg0KYGBge3J9DQprPTQNCiMgQ3V0IHRyZWUgaW50byA0IGdyb3Vwcw0KZ3J1cG9zIDwtIGN1dHJlZShoYywgaykNCiNncnVwb3MNCg0KI3Jvd25hbWVzKGRhZG9zKVtncnVwb3MgPT0gMV0NCiNyb3duYW1lcyhkYWRvcylbZ3J1cG9zID09IDJdDQojcm93bmFtZXMoZGFkb3MpW2dydXBvcyA9PSAzXQ0KI3Jvd25hbWVzKGRhZG9zKVtncnVwb3MgPT0gNF0NCiNyb3duYW1lcyhkYWRvcylbZ3J1cG9zID09IDVdDQoNCmBgYA0KDQoNCg0KDQpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTR9DQojIEFsZ29yaXRtbyBIaWVyw6FycXVpY28gLSBVc2FuZG8gbyBwYWNvdGUgZmFjdG9leHRyYQ0KDQojID9oY3V0DQojIGVzdGUgcGFjb3RlIG7Do28gdGVtIGRpc3QgcXVhZCBFdWNsaWRpYW5hDQoNCiNyZXMgPC0gaGN1dChkYWRvcywgayAsIHN0YW5kID0gVFJVRSwgDQojICAgICAgICAgICAgaGNfZnVuYyA9ICJoY2x1c3QiLCANCiMgICAgICAgICAgICBoY19tZXRob2QgPSAid2FyZC5EMiIsIA0KIyAgICAgICAgICAgIGhjX21ldHJpYyA9ICJldWNsaWRlYW4iKQ0KDQojZnZpel9kZW5kKHJlcywgcmVjdCA9IFQsIGNleCA9IDAuNywgaG9yaXogPSBGLCBwYWxldHRlID0gYnJld2VyLnBhbChuPWssbmFtZT0iRGFyazIiKSkNCiNmdml6X2NsdXN0ZXIocmVzLHJlcGVsID0gVCwga2NvbG9ycz1icmV3ZXIucGFsKG49ayxuYW1lPSJEYXJrMiIpKSArIHRoZW1lX2J3KCkgDQojZnZpel9zaWxob3VldHRlKHJlcykrdGhlbWVfYncoKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApKSANCmBgYA0KDQoNCiMgQWxnb3JpdG1vIEhpZXLDoXJxdWljbyANCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0fQ0KDQpkYWRvc19kaXN0IDwtIGRhaXN5KGRhZG9zLCBtZXRyaWMgPSAiZXVjbGlkZWFuIikNCg0KcmVzLmhjIDwtIGhjbHVzdChkID0gZGFkb3NfZGlzdCwgbWV0aG9kID0gIndhcmQuRDIiKQ0KI1dhcmTigJlzIG1pbmltdW0gdmFyaWFuY2UgbWV0aG9kOiBJdCBtaW5pbWl6ZXMgdGhlIHRvdGFsIHdpdGhpbi1jbHVzdGVyIHZhcmlhbmNlLiBBdCBlYWNoIHN0ZXAgdGhlIHBhaXIgb2YgY2x1c3RlcnMgd2l0aCBtaW5pbXVtIGJldHdlZW4tY2x1c3RlciBkaXN0YW5jZSBhcmUgbWVyZ2VkLg0KDQojZnZpel9kZW5kKHJlcy5oYywgY2V4ID0gMC41KQ0KDQojIEN1dCB0cmVlIGludG8gayBncm91cHMNCiNrPTcNCmdycCA8LSBjdXRyZWUocmVzLmhjLCBrICkNCiNncnANCiN0YWJsZShncnApDQoNCg0KI2NvbG9ycygpIA0KDQojIEN1dCBpbiBrIGdyb3VwcyBhbmQgY29sb3IgYnkgZ3JvdXBzDQpmdml6X2RlbmQocmVzLmhjLCBrICwgIyBDdXQgaW4gayBncm91cHMNCmNleCA9IDAuNSwgIyBsYWJlbCBzaXplDQprX2NvbG9ycyA9IGJyZXdlci5wYWwobj1rLG5hbWU9IkRhcmsyIiksDQpjb2xvcl9sYWJlbHNfYnlfayA9IFRSVUUsICMgY29sb3IgbGFiZWxzIGJ5IGdyb3Vwcw0KcmVjdCA9IFRSVUUgIyBBZGQgcmVjdGFuZ2xlIGFyb3VuZCBncm91cHMNCiwgZ2d0aGVtZSA9IHRoZW1lX2J3KDE4KSkNCg0KIyAgY29tbyBmYXplciBjb20gYXMgZGlzdD8gIHPDsyBsYW7Dp2FyIGRhdGEgY29tbyBtYXRyaXogZGUgZGlzdMOibmNpYXMNCmZ2aXpfY2x1c3RlcihsaXN0KGRhdGEgPSBkYWRvc19kaXN0LCBjbHVzdGVyID0gZ3JwKSwNCnBhbGV0dGUgPSBicmV3ZXIucGFsKG49ayxuYW1lPSJEYXJrMiIpLA0KI2VsbGlwc2UudHlwZSA9ICJjb25maWRlbmNlIiwgIyBDb25jZW50cmF0aW9uIGVsbGlwc2UNCnJlcGVsID0gVFJVRSwgIyBBdm9pZCBsYWJlbCBvdmVycGxvdHRpbmcgKHNsb3cpDQpzaG93LmNsdXN0LmNlbnQgPSBULCBnZ3RoZW1lID0gdGhlbWVfYncoMTgpLCBsYWJlbHNpemU9MTgpDQoNCg0KDQpgYGANCg0KDQoNCg0KDQoNCg0KYGBge3J9DQoNCiMgSXTigJlzIHBvc3NpYmxlIHRvIGNvbXBhcmUgc2ltdWx0YW5lb3VzbHkgbXVsdGlwbGUgZGVuZHJvZ3JhbXMuDQojIEEgY2hhaW5pbmcgb3BlcmF0b3IgJT4lIChhdmFpbGFibGUgaW4gZGVuZGV4dGVuZCkgaXMgdXNlZCB0byBydW4gbXVsdGlwbGUgZnVuY3Rpb24gYXQgdGhlIHNhbWUgdGltZS4gSXTigJlzIHVzZWZ1bCBmb3Igc2ltcGxpZnlpbmcgdGhlIGNvZGU6DQoNCiMgQ3JlYXRlIG11bHRpcGxlIGRlbmRyb2dyYW1zIGJ5IGNoYWluaW5nDQpkZW5kMSA8LSBkYWRvcyAlPiUgZGlzdCgiZXVjbGlkZWFuIikgJT4lIGhjbHVzdCgiY29tcGxldGUiKSAlPiUgYXMuZGVuZHJvZ3JhbQ0KZGVuZDIgPC0gZGFkb3MgJT4lIGRpc3QoImV1Y2xpZGVhbiIpICU+JSBoY2x1c3QoInNpbmdsZSIpICU+JSBhcy5kZW5kcm9ncmFtDQpkZW5kMyA8LSBkYWRvcyAlPiUgZGlzdCgiZXVjbGlkZWFuIikgJT4lIGhjbHVzdCgiYXZlcmFnZSIpICU+JSBhcy5kZW5kcm9ncmFtDQpkZW5kNCA8LSBkYWRvcyAlPiUgZGlzdCgiZXVjbGlkZWFuIikgJT4lIGhjbHVzdCgiY2VudHJvaWQiKSAlPiUgYXMuZGVuZHJvZ3JhbQ0KZGVuZDUgPC0gZGFkb3MgJT4lIGRpc3QoImV1Y2xpZGVhbiIpICU+JSBoY2x1c3QoIndhcmQuRDIiKSAlPiUgYXMuZGVuZHJvZ3JhbQ0KDQojP2hjbHVzdA0KIyBDb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KZGVuZF9saXN0IDwtIGRlbmRsaXN0KCJDb21wbGV0ZSIgPSBkZW5kMSwgIlNpbmdsZSIgPSBkZW5kMiwNCiAgICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSIgPSBkZW5kMywgIkNlbnRyb2lkIiA9IGRlbmQ0LA0KICAgICAgICAgICAgICAgICAgICAgICJ3YXJkIj0gZGVuZDUpDQoNCiNDb21wdXRlcyB0aGUgY29waGVuZXRpYyBkaXN0YW5jZXMgZm9yIGEgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcuDQojID9jb3IuZGVuZGxpc3QNCg0KY29ycyA8LSBjb3IuZGVuZGxpc3QoZGVuZF9saXN0KQ0KDQojIFByaW50IGNvcnJlbGF0aW9uIG1hdHJpeA0Kcm91bmQoY29ycywgMikNCg0KIyBWaXN1YWxpemUgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCB1c2luZyBjb3JycGxvdCBwYWNrYWdlDQpjb3JycGxvdChjb3JzLCAibnVtYmVyIiwgImxvd2VyIikNCmNvcnJwbG90KGNvcnMsICJwaWUiLCAibG93ZXIiKQ0KYGBgDQoNCg0KDQojIGFsZ29yaXRtbyBuw6NvIGhpZXLDoXJxdWljbyBQQU0NCg0KYGBge3J9DQojIENhbGN1bGF0ZSBzaWxob3VldHRlIHdpZHRoIGZvciBtYW55IGsgdXNpbmcgUEFNDQojZ293ZXJfZGlzdCAtIG1hdHJpeiBjb20gYXMgZGlzdMOibmNpYXMNCnNpbF93aWR0aCA8LSBjKE5BKQ0KZm9yKGkgaW4gMjo4KXsNCiAgcGFtX2ZpdCA8LSBwYW0oZGFkb3NfZGlzdCwNCiAgICAgICAgICAgICAgICAgZGlzcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgIGsgPSBpKQ0KICBzaWxfd2lkdGhbaV0gPC0gcGFtX2ZpdCRzaWxpbmZvJGF2Zy53aWR0aA0KfQ0KIyBQbG90IHNpaG91ZXR0ZSB3aWR0aCAoaGlnaGVyIGlzIGJldHRlcikNCg0KcGxvdCgxOjgsIHNpbF93aWR0aCwNCiAgICAgeGxhYiA9ICJOdW1iZXIgb2YgY2x1c3RlcnMiLA0KICAgICB5bGFiID0gIlNpbGhvdWV0dGUgV2lkdGgiKQ0KbGluZXMoMTo4LCBzaWxfd2lkdGgpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZnBjKQ0KDQpwYW1rKGRhZG9zX2Rpc3QsIGRpc3M9VCxrcmFuZ2U9Mjo3LGNyaXRlcmlvbj0iYXN3IiwgdXNlcGFtPVRSVUUpDQoNCg0KYGBgDQoNCg0KDQojIENsdXN0ZXIgcGxvdCBQQU0NCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEyfQ0KDQpwYW1fZml0IDwtIHBhbShkYWRvc19kaXN0LCBkaXNzID0gVFJVRSwgaykNCg0KI2RhZG9zW3BhbV9maXQkbWVkb2lkcywgXQ0KI3ByaW50KHBhbV9maXQpDQoNCmdycCA9IHBhbV9maXQkY2x1c3RlcmluZw0KDQojICBjb21vIGZhemVyIGNvbSBhcyBkaXN0PyAgc8OzIGxhbsOnYXIgZGF0YSBjb21vIG1hdHJpeiBkZSBkaXN0w6JuY2lhcw0KDQpmdml6X2NsdXN0ZXIobGlzdChkYXRhID0gZGFkb3NfZGlzdCwgY2x1c3RlciA9IGdycCksDQpwYWxldHRlID0gYnJld2VyLnBhbChuPWssbmFtZT0iRGFyazIiKSwNCnJlcGVsID0gVFJVRSwgIyBBdm9pZCBsYWJlbCBvdmVycGxvdHRpbmcgKHNsb3cpDQpzaG93LmNsdXN0LmNlbnQgPSBULCBnZ3RoZW1lID0gdGhlbWVfYncoMTYpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBEZXNjcmnDp8OjbyBkb3MgZ3J1cG9zIHBlbG8gUEFNDQoNCiNwYW1fcmVzdWx0cyA8LSBkYWRvcyAlPiUNCiMgIGRwbHlyOjptdXRhdGUoY2x1c3RlciA9IHBhbV9maXQkY2x1c3RlcmluZykgJT4lDQojICBncm91cF9ieShjbHVzdGVyKSAlPiUNCiMgIGRvKHRoZV9zdW1tYXJ5ID0gc3VtbWFyeSguKSkNCg0KI3BhbV9yZXN1bHRzJHRoZV9zdW1tYXJ5DQoNCmBgYA0KDQoNCg==