Agrupar objetos em clusters é uma tarefa frequentemente empregada na análise de dados. Esta atividade apresenta uma aplicação da técnica de análise de conglomerados (cluster analisys) para agrupar estados brasileiros. Usaremos agrupamento hierárquico para agrupar estados brasileiros com base na latitude e longitude. Certifique-se de que está familiarizado com as seguintes funções: dist, hlcust, cutree, rect.hclust
Antes de começar… O procedimento aqui é meramente ilustrativo. Há somente a intenção de aplicar o método com base na latitude e longitude.
Antes de iniciar o exercício execute o código a seguir para obter as localizações dos estados brasileiros (observe que você precisará ter a biblioteca ggmap instalada):
library(ggmap)
estados <- c(
"Brazil, Rondonia",
"Brazil, Acre",
"Brazil, Amazonas",
"Brazil, Roraima",
"Brazil, Para",
"Brazil, Amapa",
"Brazil, Tocantins",
"Brazil, Maranhao",
"Brazil, Piaui",
"Brazil, Ceara",
"Brazil, Rio Grande do Norte",
"Brazil, Paraiba",
"Brazil, Pernambuco",
"Brazil, Alagoas",
"Brazil, Sergipe",
"Brazil, Bahia",
"Brazil, Minas Gerais",
"Brazil, Espirito Santo",
"Brazil, Rio de Janeiro",
"Brazil, Sao Paulo",
"Brazil, Parana",
"Brazil, Santa Catarina",
"Brazil, Rio Grande do Sul",
"Brazil, Mato Grosso do Sul",
"Brazil, Mato Grosso",
"Brazil, Goias",
"Brazil, Distrito Federal")
theData <- geocode(estados)
siglas <- c('RO','AC','AM','RR','PA','AP',
'TO','MA','PI','CE','RN','PB','PE','AL',
'SE','BA','MG','ES','RJ','SP','PR','SC',
'RS','MS','MT','GO','DF')
rownames(theData) <- siglas
theData
Exercício 1
Calcule as distâncias euclidianas de latitude / longitude entre todos os pares de capitais.
distances <- dist(theData)
Exercício 2
Use as distâncias obtidas para produzir o objeto de dendrograma de agrupamento hierárquico. Use todos os parâmetros padrão. NOTA: Por padrão, os clusters serão unidos usando a máxima distância possível entre todos os pares de seus elementos (este fato será útil mais tarde).
dendrogram <- hclust(distances)
Exercício 3
Visualize o dendrograma de agrupamento hierárquico obtido.
plot(dendrogram)

Exercício 4
No passo anterior as folhas de nosso dendrograma foram colocadas em diferentes alturas. Vamos refazer de modo que todos os estados sejam escritos no mesmo nível.
plot(dendrogram, hang=-1)

Exercício 5
O procedimento hierárquico de cluster cria uma hierarquia de clusters. Uma vantagem deste método é que podemos usar o mesmo dendrograma para obter números diferentes de grupos. Agrupar os estados brasileiros em 5 grupos.
cutree(dendrogram, k=5)
RO AC AM RR PA AP TO MA PI CE RN PB PE AL SE BA MG ES RJ SP PR SC RS MS MT GO DF
1 1 2 2 2 2 3 4 4 4 4 4 4 4 4 3 3 3 5 5 5 5 5 5 1 3 3
Exercício 6
Em vez de especificar o número de grupos desejados, podemos selecionar a altura do dendrograma onde a árvore será dividida em grupos. Uma vez que usamos a função de ligação máxima (padrão no exercício 2), esta altura tem uma interpretação útil - garante que todos os elementos dentro de um cluster não sejam mais do que a distância selecionada. A) Agrupe os estados brasileiros cortando a árvore em altura = 20. B) Traçar o dendrograma e visualizar a altura em que a árvore foi cortada em grupos usando uma linha.
cutree(dendrogram, h=20)
RO AC AM RR PA AP TO MA PI CE RN PB PE AL SE BA MG ES RJ SP PR SC RS MS MT GO DF
1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 1 3 3
plot(dendrogram, hang=-1)
abline(h=20, col="red", lty=2)

Exercício 7
Agora visualize a solução de agrupamento obtida no 5º exercício. Isso deve ser feito desenhando um retângulo em torno de todas os estados brasileiros que pertencem ao mesmo grupo. Use cores diferentes para grupos diferentes.
plot(dendrogram, hang=-1)
rect.hclust(dendrogram, k=5, border=1:3)

Exercício 8
Visualize o dendrograma novamente, mas desta vez apresente as duas versões de cluster obtidas no exercício 5 e exercício 6 na mesma parcela. Use a cor vermelha para representar clusters do exercício 5 e azul para representar clusters do exercício 6.
plot(dendrogram, hang=-1)
rect.hclust(dendrogram, k=5, border="red")
rect.hclust(dendrogram, h=20, border="blue")

Exercício 9
A função hclust apresenta métodos de ligação diferentes (métodos usados para mesclar dois clusters ao construir o dendrograma). Produza um dendrograma, com 5 grupos e vizualize usando retângulos de cores diferentes. Repita este procedimento para todos os métodos de ligação disponíveis na função hclust.
# ward.D
plot(hclust(distances, method="ward.D"), main="ward.D", hang=-1)
rect.hclust(hclust(distances, method="ward.D"), k=5, border=1:5)

# ward.D2
plot(hclust(distances, method="ward.D2"), main="ward.D2", hang=-1)
rect.hclust(hclust(distances, method="ward.D2"), k=5, border=1:5)

# single
plot(hclust(distances, method="single"), main="single", hang=-1)
rect.hclust(hclust(distances, method="single"), k=5, border=1:5)

# complete
plot(hclust(distances, method="complete"), main="complete", hang=-1)
rect.hclust(hclust(distances, method="complete"), k=5, border=1:5)

# average
plot(hclust(distances, method="average"), main="average", hang=-1)
rect.hclust(hclust(distances, method="average"), k=5, border=1:5)

# mcquitty
plot(hclust(distances, method="mcquitty"), main="mcquitty", hang=-1)
rect.hclust(hclust(distances, method="mcquitty"), k=5, border=1:5)

# median
plot(hclust(distances, method="median"), main="median", hang=-1)
rect.hclust(hclust(distances, method="median"), k=5, border=1:5)

# centroid
plot(hclust(distances, method="centroid"), main="centroid", hang=-1)
rect.hclust(hclust(distances, method="centroid"), k=5, border=1:5)

Exercício 10
Crie sua própria solução de cluster com base no que aprendeu neste exercício e visualize-a como um mapa. Traçar coordenadas dos estados brasileiros com longitude no eixo x e latitude no eixo y e colori-las com base nos grupos obtidos usando sua versão hierárquica de cluster.
library(maps)
library(mapproj)
par(mar=c(1,1,1,1))
m <- map("world","Brazil", fill=T, col="grey95")
map.axes()
map.scale(ratio=F, cex=0.7)
abline(h=0, lty = 2)
map.grid(m, nx = 5, ny = 5, col="grey50", font=1, cex=0.7 , pretty = T)#library(mapproj)
myVersion <- hclust(distances, method="complete")
groups <- cutree(myVersion, 5)
par(new=TRUE)
plot(theData, cex=6, xlim=c(-80,-30),axes=F, ann=T)
text(theData, rownames(theData), cex=1.5, col=groups)

#axis(4)
LS0tDQp0aXRsZTogIkNsdXN0ZXJzIChoaWVyYXJjaGljYWwtY2x1c3RlcmluZy1leGVyY2lzZXMpIC0gQlJBU0lMIg0KYXV0aG9yOiBQcm9mIERyLiBSb2JlcnRvIENhbXBvcyBMZW9uaSAoTGVvbmksIFIuQy4pDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KX19fDQo+IEFncnVwYXIgb2JqZXRvcyBlbSBjbHVzdGVycyDDqSB1bWEgdGFyZWZhIGZyZXF1ZW50ZW1lbnRlIGVtcHJlZ2FkYSBuYSBhbsOhbGlzZSBkZSBkYWRvcy4gRXN0YSBhdGl2aWRhZGUgYXByZXNlbnRhIHVtYSBhcGxpY2HDp8OjbyBkYSB0w6ljbmljYSBkZSBhbsOhbGlzZSBkZSBjb25nbG9tZXJhZG9zIChjbHVzdGVyIGFuYWxpc3lzKSBwYXJhIGFncnVwYXIgZXN0YWRvcyBicmFzaWxlaXJvcy4gVXNhcmVtb3MgYWdydXBhbWVudG8gaGllcsOhcnF1aWNvIHBhcmEgYWdydXBhciBlc3RhZG9zIGJyYXNpbGVpcm9zIGNvbSBiYXNlIG5hIGxhdGl0dWRlIGUgbG9uZ2l0dWRlLiBDZXJ0aWZpcXVlLXNlIGRlIHF1ZSBlc3TDoSBmYW1pbGlhcml6YWRvIGNvbSBhcyBzZWd1aW50ZXMgZnVuw6fDtWVzOiBkaXN0LCBobGN1c3QsIGN1dHJlZSwgcmVjdC5oY2x1c3QNCg0KPiBBbnRlcyBkZSBjb21lw6dhci4uLiBPIHByb2NlZGltZW50byBhcXVpIMOpIG1lcmFtZW50ZSBpbHVzdHJhdGl2by4gSMOhIHNvbWVudGUgYSBpbnRlbsOnw6NvIGRlIGFwbGljYXIgbyBtw6l0b2RvIGNvbSBiYXNlIG5hIGxhdGl0dWRlIGUgbG9uZ2l0dWRlLiANCg0KX19fDQoNCg0KPiBBbnRlcyBkZSBpbmljaWFyIG8gZXhlcmPDrWNpbyBleGVjdXRlIG8gY8OzZGlnbyBhIHNlZ3VpciBwYXJhIG9idGVyIGFzIGxvY2FsaXphw6fDtWVzIGRvcyBlc3RhZG9zIGJyYXNpbGVpcm9zIChvYnNlcnZlIHF1ZSB2b2PDqiBwcmVjaXNhcsOhIHRlciBhIGJpYmxpb3RlY2EgKmdnbWFwKiBpbnN0YWxhZGEpOiANCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoZ2dtYXApDQplc3RhZG9zIDwtIGMoDQoiQnJhemlsLCBSb25kb25pYSIsDQoiQnJhemlsLCBBY3JlIiwNCiJCcmF6aWwsIEFtYXpvbmFzIiwNCiJCcmF6aWwsIFJvcmFpbWEiLA0KIkJyYXppbCwgUGFyYSIsDQoiQnJhemlsLCBBbWFwYSIsDQoiQnJhemlsLCBUb2NhbnRpbnMiLA0KIkJyYXppbCwgTWFyYW5oYW8iLA0KIkJyYXppbCwgUGlhdWkiLA0KIkJyYXppbCwgQ2VhcmEiLA0KIkJyYXppbCwgUmlvIEdyYW5kZSBkbyBOb3J0ZSIsDQoiQnJhemlsLCBQYXJhaWJhIiwNCiJCcmF6aWwsIFBlcm5hbWJ1Y28iLA0KIkJyYXppbCwgQWxhZ29hcyIsDQoiQnJhemlsLCBTZXJnaXBlIiwNCiJCcmF6aWwsIEJhaGlhIiwNCiJCcmF6aWwsIE1pbmFzIEdlcmFpcyIsDQoiQnJhemlsLCBFc3Bpcml0byBTYW50byIsDQoiQnJhemlsLCBSaW8gZGUgSmFuZWlybyIsDQoiQnJhemlsLCBTYW8gUGF1bG8iLA0KIkJyYXppbCwgUGFyYW5hIiwNCiJCcmF6aWwsIFNhbnRhIENhdGFyaW5hIiwNCiJCcmF6aWwsIFJpbyBHcmFuZGUgZG8gU3VsIiwNCiJCcmF6aWwsIE1hdG8gR3Jvc3NvIGRvIFN1bCIsDQoiQnJhemlsLCBNYXRvIEdyb3NzbyIsDQoiQnJhemlsLCBHb2lhcyIsDQoiQnJhemlsLCBEaXN0cml0byBGZWRlcmFsIikNCg0KdGhlRGF0YSA8LSBnZW9jb2RlKGVzdGFkb3MpDQpzaWdsYXMgPC0gYygnUk8nLCdBQycsJ0FNJywnUlInLCdQQScsJ0FQJywNCidUTycsJ01BJywnUEknLCdDRScsJ1JOJywnUEInLCdQRScsJ0FMJywNCidTRScsJ0JBJywnTUcnLCdFUycsJ1JKJywnU1AnLCdQUicsJ1NDJywNCidSUycsJ01TJywnTVQnLCdHTycsJ0RGJykNCnJvd25hbWVzKHRoZURhdGEpIDwtIHNpZ2xhcw0KdGhlRGF0YQ0KDQpgYGANCg0KDQojIEV4ZXJjw61jaW8gMQ0KPiBDYWxjdWxlIGFzIGRpc3TDom5jaWFzIGV1Y2xpZGlhbmFzIGRlIGxhdGl0dWRlIC8gbG9uZ2l0dWRlIGVudHJlIHRvZG9zIG9zIHBhcmVzIGRlIGNhcGl0YWlzLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpkaXN0YW5jZXMgPC0gZGlzdCh0aGVEYXRhKQ0KYGBgDQoNCiMgRXhlcmPDrWNpbyAyDQo+IFVzZSBhcyBkaXN0w6JuY2lhcyBvYnRpZGFzIHBhcmEgcHJvZHV6aXIgbyBvYmpldG8gZGUgZGVuZHJvZ3JhbWEgZGUgYWdydXBhbWVudG8gaGllcsOhcnF1aWNvLiBVc2UgdG9kb3Mgb3MgcGFyw6JtZXRyb3MgcGFkcsOjby4gTk9UQTogUG9yIHBhZHLDo28sIG9zIGNsdXN0ZXJzIHNlcsOjbyB1bmlkb3MgdXNhbmRvIGEgbcOheGltYSBkaXN0w6JuY2lhIHBvc3PDrXZlbCBlbnRyZSB0b2RvcyBvcyBwYXJlcyBkZSBzZXVzIGVsZW1lbnRvcyAoZXN0ZSBmYXRvIHNlcsOhIMO6dGlsIG1haXMgdGFyZGUpLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpkZW5kcm9ncmFtIDwtIGhjbHVzdChkaXN0YW5jZXMpDQpgYGANCg0KIyBFeGVyY8OtY2lvIDMNCj4gVmlzdWFsaXplIG8gZGVuZHJvZ3JhbWEgZGUgYWdydXBhbWVudG8gaGllcsOhcnF1aWNvIG9idGlkby4NCg0KYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQ0KcGxvdChkZW5kcm9ncmFtKQ0KYGBgDQoNCiMgRXhlcmPDrWNpbyA0DQo+IE5vIHBhc3NvIGFudGVyaW9yIGFzIGZvbGhhcyBkZSBub3NzbyBkZW5kcm9ncmFtYSBmb3JhbSBjb2xvY2FkYXMgZW0gZGlmZXJlbnRlcyBhbHR1cmFzLiBWYW1vcyByZWZhemVyIGRlIG1vZG8gcXVlIHRvZG9zIG9zIGVzdGFkb3Mgc2VqYW0gZXNjcml0b3Mgbm8gbWVzbW8gbsOtdmVsLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpwbG90KGRlbmRyb2dyYW0sIGhhbmc9LTEpDQpgYGANCg0KIyBFeGVyY8OtY2lvIDUNCj4gTyBwcm9jZWRpbWVudG8gaGllcsOhcnF1aWNvIGRlIGNsdXN0ZXIgY3JpYSB1bWEgaGllcmFycXVpYSBkZSBjbHVzdGVycy4gVW1hIHZhbnRhZ2VtIGRlc3RlIG3DqXRvZG8gw6kgcXVlIHBvZGVtb3MgdXNhciBvIG1lc21vIGRlbmRyb2dyYW1hIHBhcmEgb2J0ZXIgbsO6bWVyb3MgZGlmZXJlbnRlcyBkZSBncnVwb3MuIEFncnVwYXIgb3MgZXN0YWRvcyBicmFzaWxlaXJvcyBlbSA1IGdydXBvcy4NCg0KYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQ0KY3V0cmVlKGRlbmRyb2dyYW0sIGs9NSkNCmBgYA0KDQojIEV4ZXJjw61jaW8gNg0KPiBFbSB2ZXogZGUgZXNwZWNpZmljYXIgbyBuw7ptZXJvIGRlIGdydXBvcyBkZXNlamFkb3MsIHBvZGVtb3Mgc2VsZWNpb25hciBhIGFsdHVyYSBkbyBkZW5kcm9ncmFtYSBvbmRlIGEgw6Fydm9yZSBzZXLDoSBkaXZpZGlkYSBlbSBncnVwb3MuIFVtYSB2ZXogcXVlIHVzYW1vcyBhIGZ1bsOnw6NvIGRlIGxpZ2HDp8OjbyBtw6F4aW1hIChwYWRyw6NvIG5vIGV4ZXJjw61jaW8gMiksIGVzdGEgYWx0dXJhIHRlbSB1bWEgaW50ZXJwcmV0YcOnw6NvIMO6dGlsIC0gZ2FyYW50ZSBxdWUgdG9kb3Mgb3MgZWxlbWVudG9zIGRlbnRybyBkZSB1bSBjbHVzdGVyIG7Do28gc2VqYW0gbWFpcyBkbyBxdWUgYSBkaXN0w6JuY2lhIHNlbGVjaW9uYWRhLg0KQSkgQWdydXBlIG9zIGVzdGFkb3MgYnJhc2lsZWlyb3MgY29ydGFuZG8gYSDDoXJ2b3JlIGVtIGFsdHVyYSA9IDIwLg0KQikgVHJhw6dhciBvIGRlbmRyb2dyYW1hIGUgdmlzdWFsaXphciBhIGFsdHVyYSBlbSBxdWUgYSDDoXJ2b3JlIGZvaSBjb3J0YWRhIGVtIGdydXBvcyB1c2FuZG8gdW1hIGxpbmhhLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpjdXRyZWUoZGVuZHJvZ3JhbSwgaD0yMCkNCnBsb3QoZGVuZHJvZ3JhbSwgaGFuZz0tMSkNCmFibGluZShoPTIwLCBjb2w9InJlZCIsIGx0eT0yKQ0KYGBgDQoNCiMgRXhlcmPDrWNpbyA3DQo+IEFnb3JhIHZpc3VhbGl6ZSBhIHNvbHXDp8OjbyBkZSBhZ3J1cGFtZW50byBvYnRpZGEgbm8gNcK6IGV4ZXJjw61jaW8uIElzc28gZGV2ZSBzZXIgZmVpdG8gZGVzZW5oYW5kbyB1bSByZXTDom5ndWxvIGVtIHRvcm5vIGRlIHRvZGFzIG9zIGVzdGFkb3MgYnJhc2lsZWlyb3MgcXVlIHBlcnRlbmNlbSBhbyBtZXNtbyBncnVwby4gVXNlIGNvcmVzIGRpZmVyZW50ZXMgcGFyYSBncnVwb3MgZGlmZXJlbnRlcy4NCg0KYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQ0KDQpwbG90KGRlbmRyb2dyYW0sIGhhbmc9LTEpDQpyZWN0LmhjbHVzdChkZW5kcm9ncmFtLCBrPTUsIGJvcmRlcj0xOjMpDQoNCmBgYA0KDQojIEV4ZXJjw61jaW8gOA0KPiBWaXN1YWxpemUgbyBkZW5kcm9ncmFtYSBub3ZhbWVudGUsIG1hcyBkZXN0YSB2ZXogYXByZXNlbnRlIGFzIGR1YXMgdmVyc8O1ZXMgZGUgY2x1c3RlciBvYnRpZGFzIG5vIGV4ZXJjw61jaW8gNSBlIGV4ZXJjw61jaW8gNiBuYSBtZXNtYSBwYXJjZWxhLiBVc2UgYSBjb3IgdmVybWVsaGEgcGFyYSByZXByZXNlbnRhciBjbHVzdGVycyBkbyBleGVyY8OtY2lvIDUgZSBhenVsIHBhcmEgcmVwcmVzZW50YXIgY2x1c3RlcnMgZG8gZXhlcmPDrWNpbyA2Lg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpwbG90KGRlbmRyb2dyYW0sIGhhbmc9LTEpDQpyZWN0LmhjbHVzdChkZW5kcm9ncmFtLCBrPTUsIGJvcmRlcj0icmVkIikNCnJlY3QuaGNsdXN0KGRlbmRyb2dyYW0sIGg9MjAsIGJvcmRlcj0iYmx1ZSIpDQpgYGANCg0KIyBFeGVyY8OtY2lvIDkNCj4gQSBmdW7Dp8OjbyBoY2x1c3QgYXByZXNlbnRhIG3DqXRvZG9zIGRlIGxpZ2HDp8OjbyBkaWZlcmVudGVzIChtw6l0b2RvcyB1c2Fkb3MgcGFyYSBtZXNjbGFyIGRvaXMgY2x1c3RlcnMgYW8gY29uc3RydWlyIG8gZGVuZHJvZ3JhbWEpLiBQcm9kdXphIHVtIGRlbmRyb2dyYW1hLCBjb20gNSBncnVwb3MgZSB2aXp1YWxpemUgdXNhbmRvIHJldMOibmd1bG9zIGRlIGNvcmVzIGRpZmVyZW50ZXMuIFJlcGl0YSBlc3RlIHByb2NlZGltZW50byBwYXJhIHRvZG9zIG9zIG3DqXRvZG9zIGRlIGxpZ2HDp8OjbyBkaXNwb27DrXZlaXMgbmEgZnVuw6fDo28gaGNsdXN0Lg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQojIHdhcmQuRA0KcGxvdChoY2x1c3QoZGlzdGFuY2VzLCBtZXRob2Q9IndhcmQuRCIpLCBtYWluPSJ3YXJkLkQiLCBoYW5nPS0xKQ0KcmVjdC5oY2x1c3QoaGNsdXN0KGRpc3RhbmNlcywgbWV0aG9kPSJ3YXJkLkQiKSwgaz01LCBib3JkZXI9MTo1KQ0KIyB3YXJkLkQyDQpwbG90KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0id2FyZC5EMiIpLCBtYWluPSJ3YXJkLkQyIiwgaGFuZz0tMSkNCnJlY3QuaGNsdXN0KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0id2FyZC5EMiIpLCBrPTUsIGJvcmRlcj0xOjUpDQojIHNpbmdsZQ0KcGxvdChoY2x1c3QoZGlzdGFuY2VzLCBtZXRob2Q9InNpbmdsZSIpLCBtYWluPSJzaW5nbGUiLCBoYW5nPS0xKQ0KcmVjdC5oY2x1c3QoaGNsdXN0KGRpc3RhbmNlcywgbWV0aG9kPSJzaW5nbGUiKSwgaz01LCBib3JkZXI9MTo1KQ0KIyBjb21wbGV0ZQ0KcGxvdChoY2x1c3QoZGlzdGFuY2VzLCBtZXRob2Q9ImNvbXBsZXRlIiksIG1haW49ImNvbXBsZXRlIiwgaGFuZz0tMSkNCnJlY3QuaGNsdXN0KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0iY29tcGxldGUiKSwgaz01LCBib3JkZXI9MTo1KQ0KIyBhdmVyYWdlDQpwbG90KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0iYXZlcmFnZSIpLCBtYWluPSJhdmVyYWdlIiwgaGFuZz0tMSkNCnJlY3QuaGNsdXN0KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0iYXZlcmFnZSIpLCBrPTUsIGJvcmRlcj0xOjUpDQojIG1jcXVpdHR5DQpwbG90KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0ibWNxdWl0dHkiKSwgbWFpbj0ibWNxdWl0dHkiLCBoYW5nPS0xKQ0KcmVjdC5oY2x1c3QoaGNsdXN0KGRpc3RhbmNlcywgbWV0aG9kPSJtY3F1aXR0eSIpLCBrPTUsIGJvcmRlcj0xOjUpDQojIG1lZGlhbg0KcGxvdChoY2x1c3QoZGlzdGFuY2VzLCBtZXRob2Q9Im1lZGlhbiIpLCBtYWluPSJtZWRpYW4iLCBoYW5nPS0xKQ0KcmVjdC5oY2x1c3QoaGNsdXN0KGRpc3RhbmNlcywgbWV0aG9kPSJtZWRpYW4iKSwgaz01LCBib3JkZXI9MTo1KQ0KIyBjZW50cm9pZA0KcGxvdChoY2x1c3QoZGlzdGFuY2VzLCBtZXRob2Q9ImNlbnRyb2lkIiksIG1haW49ImNlbnRyb2lkIiwgaGFuZz0tMSkNCnJlY3QuaGNsdXN0KGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0iY2VudHJvaWQiKSwgaz01LCBib3JkZXI9MTo1KQ0KDQpgYGANCg0KIyBFeGVyY8OtY2lvIDEwDQo+IENyaWUgc3VhIHByw7NwcmlhIHNvbHXDp8OjbyBkZSBjbHVzdGVyIGNvbSBiYXNlIG5vIHF1ZSBhcHJlbmRldSBuZXN0ZSBleGVyY8OtY2lvIGUgdmlzdWFsaXplLWEgY29tbyB1bSBtYXBhLiBUcmHDp2FyIGNvb3JkZW5hZGFzIGRvcyBlc3RhZG9zIGJyYXNpbGVpcm9zIGNvbSBsb25naXR1ZGUgbm8gZWl4byB4IGUgbGF0aXR1ZGUgbm8gZWl4byB5IGUgY29sb3JpLWxhcyBjb20gYmFzZSBub3MgZ3J1cG9zIG9idGlkb3MgdXNhbmRvIHN1YSB2ZXJzw6NvIGhpZXLDoXJxdWljYSBkZSBjbHVzdGVyLg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTR9DQpsaWJyYXJ5KG1hcHMpDQpsaWJyYXJ5KG1hcHByb2opDQpwYXIobWFyPWMoMSwxLDEsMSkpDQptIDwtIG1hcCgid29ybGQiLCJCcmF6aWwiLCBmaWxsPVQsIGNvbD0iZ3JleTk1IikNCm1hcC5heGVzKCkNCm1hcC5zY2FsZShyYXRpbz1GLCBjZXg9MC43KQ0KYWJsaW5lKGg9MCwgbHR5ID0gMikNCm1hcC5ncmlkKG0sIG54ID0gNSwgbnkgPSA1LCBjb2w9ImdyZXk1MCIsIGZvbnQ9MSwgY2V4PTAuNyAsIHByZXR0eSA9IFQpI2xpYnJhcnkobWFwcHJvaikNCg0KbXlWZXJzaW9uIDwtIGhjbHVzdChkaXN0YW5jZXMsIG1ldGhvZD0iY29tcGxldGUiKQ0KZ3JvdXBzICAgIDwtIGN1dHJlZShteVZlcnNpb24sIDUpDQoNCnBhcihuZXc9VFJVRSkNCnBsb3QodGhlRGF0YSwgY2V4PTYsIHhsaW09YygtODAsLTMwKSxheGVzPUYsIGFubj1UKQ0KdGV4dCh0aGVEYXRhLCByb3duYW1lcyh0aGVEYXRhKSwgY2V4PTEuNSwgY29sPWdyb3VwcykNCiNheGlzKDQpDQpgYGANCg0K