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==