Procesamiento de Datos
library(raster)
band1 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B1.TIF")
band2 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B2.TIF")
band3 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B3.TIF")
band4 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B4.TIF")
band5 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B5.TIF")
band6 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B6.TIF")
band7 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B7.TIF")
band10 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B10.TIF")
band11 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B11.TIF")
roma_rst_lan <- brick(band1,band2,band3,band4,band5,band6,band7,band10,band11)
names(roma_rst_lan) <- c(paste("Banda",1:7,sep=""),"Banda10","Banda11")
plot(roma_rst_lan)

Algoritmo K-means y CLARA
library(cluster)
rstDF <- values(roma_rst_lan)
idx <- complete.cases(rstDF)
# Inicializamos los objetos raster finales
rstKM <- raster(roma_rst_lan[[1]])
rstCLARA <- raster(roma_rst_lan[[1]])
for(nClust in 2:10){
cat("-> Agrupación con nClust =",nClust,"......")
# Aplicamos k-means
km <- kmeans(rstDF[idx,], centers = nClust, iter.max = 50)
# Aplicamos CLARA (Distancia manhattan y subconjunto de 50)
cla <- clara(rstDF[idx, ], k = nClust, metric = "manhattan", pamLike = TRUE)
kmClust <- vector(mode = "integer", length = ncell(roma_rst_lan))
claClust <- vector(mode = "integer", length = ncell(roma_rst_lan))
kmClust[!idx] <- NA
kmClust[idx] <- km$cluster
claClust[!idx] <- NA
claClust[idx] <- cla$clustering
tmpRstKM <- raster(roma_rst_lan[[1]])
tmpRstCLARA <- raster(roma_rst_lan[[1]])
values(tmpRstKM) <- kmClust
values(tmpRstCLARA) <- claClust
# Apilamos resultados
if(nClust==2){
rstKM <- tmpRstKM
rstCLARA <- tmpRstCLARA
}else{
rstKM <- stack(rstKM, tmpRstKM)
rstCLARA <- stack(rstCLARA, tmpRstCLARA)
}
cat(" Fin!\n\n")
}
-> Agrupación con nClust = 2 ...... Fin!
-> Agrupación con nClust = 3 ...... Fin!
-> Agrupación con nClust = 4 ...... Fin!
-> Agrupación con nClust = 5 ...... Fin!
-> Agrupación con nClust = 6 ...... Fin!
-> Agrupación con nClust = 7 ......
Warning: Quick-TRANSfer stage steps exceeded maximum (= 8425950)
Fin!
-> Agrupación con nClust = 8 ......
Warning: Quick-TRANSfer stage steps exceeded maximum (= 8425950)
Fin!
-> Agrupación con nClust = 9 ...... Fin!
-> Agrupación con nClust = 10 ......
Warning: Quick-TRANSfer stage steps exceeded maximum (= 8425950)
Fin!
# Write the clustering solutions for each algorithm
writeRaster(rstKM,"/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/TFG-For-Github/hongkong_KMeans.tif", overwrite=TRUE)
writeRaster(rstCLARA,"/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/TFG-For-Github/hongkong_CLARA.tif", overwrite=TRUE)
# Cambiamos los nombres
names(rstKM) <- c(paste("Cluster",2:10,sep=""))
names(rstCLARA) <- c(paste("Cluster",2:10,sep=""))
plot(rstKM)

plot(rstCLARA)

Evaluación de los resultados
library(clusterCrit)
# Dataframe en conjunto guarda los resultados de inddice de silueta de k-means y clara
clustPerfSI <- data.frame(nClust = 2:10, SI_KM = NA, SI_CLARA = NA)
for(i in 1:nlayers(rstKM)){ # Itera
cat("-> Evaluando agrupaciones para nClust =",(2:10)[i],"......")
# Extrae muestra aleatoria , de tamaño 1100
cellIdx_RstKM <- sampleStratified(rstKM[[i]], size = 1500)
cellIdx_rstCLARA <- sampleStratified(rstCLARA[[i]], size = 1500)
rstDFStRS_KM <- rstDF[cellIdx_RstKM[,1], ]
rstDFStRS_CLARA <- rstDF[cellIdx_rstCLARA[,1], ]
rstDFStRS_KM[] <- sapply(rstDFStRS_KM, as.numeric)
rstDFStRS_CLARA[] <- sapply(rstDFStRS_CLARA, as.numeric)
# Calculo del indice de silueta para:
#
# K-means
clCritKM <- intCriteria(traj = rstDFStRS_KM,
part = as.integer(cellIdx_RstKM[,2]),
crit = "Silhouette")
# CLARA
clCritCLARA <- intCriteria(traj = rstDFStRS_CLARA,
part = as.integer(cellIdx_rstCLARA[,2]),
crit = "Silhouette")
# Se escriben los resultados
clustPerfSI[i, "SI_KM"] <- clCritKM[[1]][1]
clustPerfSI[i, "SI_CLARA"] <- clCritCLARA[[1]][1]
cat(" Fin!\n\n")
}
-> Evaluando agrupaciones para nClust = 2 ...... Fin!
-> Evaluando agrupaciones para nClust = 3 ...... Fin!
-> Evaluando agrupaciones para nClust = 4 ...... Fin!
-> Evaluando agrupaciones para nClust = 5 ...... Fin!
-> Evaluando agrupaciones para nClust = 6 ......
Warning in .local(x, size, ...) : only 1172 cells found for stratum 6
Warning in .local(x, size, ...) :
fewer samples than requested found for stratum: 6
Fin!
-> Evaluando agrupaciones para nClust = 7 ...... Fin!
-> Evaluando agrupaciones para nClust = 8 ......
Warning in .local(x, size, ...) : only 1224 cells found for stratum 8
Warning in .local(x, size, ...) :
fewer samples than requested found for stratum: 8
Fin!
-> Evaluando agrupaciones para nClust = 9 ......
Warning in .local(x, size, ...) : only 1142 cells found for stratum 9
Warning in .local(x, size, ...) :
fewer samples than requested found for stratum: 9
Fin!
-> Evaluando agrupaciones para nClust = 10 ......
Warning in .local(x, size, ...) : only 1202 cells found for stratum 10
Warning in .local(x, size, ...) :
fewer samples than requested found for stratum: 10
Fin!
Análisis de resultados
##guardariamos en un csv
write.csv(clustPerfSI, file = "/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/clustPerfSI.csv", row.names = FALSE)
#tabla de resultados
knitr::kable(clustPerfSI, digits = 3, align = "c",
col.names = c("#clusters","Avg. Silhouette (k-means)","Avg. Silhouette (CLARA)"))
| 2 |
0.336 |
0.326 |
| 3 |
0.263 |
0.204 |
| 4 |
0.374 |
0.193 |
| 5 |
0.351 |
0.321 |
| 6 |
0.338 |
0.362 |
| 7 |
0.279 |
0.294 |
| 8 |
0.288 |
0.284 |
| 9 |
0.283 |
0.277 |
| 10 |
0.267 |
0.260 |
#grafico de comparacion entre los algoritmos
plot(clustPerfSI[,1], clustPerfSI[,2],
xlim = c(2,10), ylim = range(clustPerfSI[,2:3]), type = "n",
ylab="Avg. Silhouette Index", xlab="# of clusters",
main="Silhouette index by # of clusters")
# Plot Avg Silhouette values across # of clusters for K-means
lines(clustPerfSI[,1], clustPerfSI[,2], col="red")
# Plot Avg Silhouette values across # of clusters for CLARA
lines(clustPerfSI[,1], clustPerfSI[,3], col="blue")
# Grid lines
abline(v = 1:13, lty=2, col="light grey")
abline(h = seq(0.30,0.44,0.02), lty=2, col="light grey")
legend("topright", legend=c("K-means","CLARA"), col=c("red","blue"), lty=1, lwd=1)

Visualización de mejores agrupamientos
plot(rstKM[[3]])
title("K-mean (4 clusters) mejor agrupamiento")

plot(rstCLARA[[3]])
title("CLARA (4 clusters)")

plot(rstCLARA[[5]])
title("CLARA (6 clusters) mejor agrupamiento")

plot(rstKM[[5]])
title("K-mean (6 clusters)")

LS0tCnRpdGxlOiAiQ2xhc2lmaWNhY2nDs24gTm8gU3VwZXJ2aXNhZGEoSy1tZWFucyB5IENMQVJBKSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBQcm9jZXNhbWllbnRvIGRlIERhdG9zCgpgYGB7cn0KbGlicmFyeShyYXN0ZXIpCmJhbmQxIDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CMS5USUYiKQpiYW5kMiA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjIuVElGIikKYmFuZDMgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IzLlRJRiIpCmJhbmQ0IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNC5USUYiKQpiYW5kNSA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjUuVElGIikKYmFuZDYgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0I2LlRJRiIpCmJhbmQ3IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNy5USUYiKQpiYW5kMTAgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMC5USUYiKQpiYW5kMTEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMS5USUYiKQoKcm9tYV9yc3RfbGFuIDwtIGJyaWNrKGJhbmQxLGJhbmQyLGJhbmQzLGJhbmQ0LGJhbmQ1LGJhbmQ2LGJhbmQ3LGJhbmQxMCxiYW5kMTEpCm5hbWVzKHJvbWFfcnN0X2xhbikgPC0gYyhwYXN0ZSgiQmFuZGEiLDE6NyxzZXA9IiIpLCJCYW5kYTEwIiwiQmFuZGExMSIpCgpwbG90KHJvbWFfcnN0X2xhbikKYGBgCgojIEFsZ29yaXRtbyBLLW1lYW5zIHkgQ0xBUkEKYGBge3J9CmxpYnJhcnkoY2x1c3RlcikKCnJzdERGIDwtIHZhbHVlcyhyb21hX3JzdF9sYW4pCmlkeCA8LSBjb21wbGV0ZS5jYXNlcyhyc3RERikKCiMgSW5pY2lhbGl6YW1vcyBsb3Mgb2JqZXRvcyByYXN0ZXIgZmluYWxlcwpyc3RLTSA8LSByYXN0ZXIocm9tYV9yc3RfbGFuW1sxXV0pCnJzdENMQVJBIDwtIHJhc3Rlcihyb21hX3JzdF9sYW5bWzFdXSkKCmZvcihuQ2x1c3QgaW4gMjoxMCl7CiAgCiAgY2F0KCItPiBBZ3J1cGFjacOzbiBjb24gbkNsdXN0ID0iLG5DbHVzdCwiLi4uLi4uIikKICAKICAjIEFwbGljYW1vcyBrLW1lYW5zCiAga20gPC0ga21lYW5zKHJzdERGW2lkeCxdLCBjZW50ZXJzID0gbkNsdXN0LCBpdGVyLm1heCA9IDUwKQogIAogICMgQXBsaWNhbW9zIENMQVJBIChEaXN0YW5jaWEgbWFuaGF0dGFuKQogIGNsYSA8LSBjbGFyYShyc3RERltpZHgsIF0sIGsgPSBuQ2x1c3QsIG1ldHJpYyA9ICJtYW5oYXR0YW4iLCBwYW1MaWtlID0gVFJVRSkKICAKICBrbUNsdXN0IDwtIHZlY3Rvcihtb2RlID0gImludGVnZXIiLCBsZW5ndGggPSBuY2VsbChyb21hX3JzdF9sYW4pKQogIGNsYUNsdXN0IDwtIHZlY3Rvcihtb2RlID0gImludGVnZXIiLCBsZW5ndGggPSBuY2VsbChyb21hX3JzdF9sYW4pKQogIAogIGttQ2x1c3RbIWlkeF0gPC0gTkEKICBrbUNsdXN0W2lkeF0gPC0ga20kY2x1c3RlcgogIAogIGNsYUNsdXN0WyFpZHhdIDwtIE5BCiAgY2xhQ2x1c3RbaWR4XSA8LSBjbGEkY2x1c3RlcmluZwogIAogIHRtcFJzdEtNIDwtIHJhc3Rlcihyb21hX3JzdF9sYW5bWzFdXSkKICB0bXBSc3RDTEFSQSA8LSByYXN0ZXIocm9tYV9yc3RfbGFuW1sxXV0pCgogIHZhbHVlcyh0bXBSc3RLTSkgPC0ga21DbHVzdAogIHZhbHVlcyh0bXBSc3RDTEFSQSkgPC0gY2xhQ2x1c3QKICAKICAjIEFwaWxhbW9zIHJlc3VsdGFkb3MKICBpZihuQ2x1c3Q9PTIpewogICAgcnN0S00gICAgPC0gdG1wUnN0S00KICAgIHJzdENMQVJBIDwtIHRtcFJzdENMQVJBCiAgfWVsc2V7CiAgICByc3RLTSAgICA8LSBzdGFjayhyc3RLTSwgdG1wUnN0S00pCiAgICByc3RDTEFSQSA8LSBzdGFjayhyc3RDTEFSQSwgdG1wUnN0Q0xBUkEpCiAgfQogIAogIGNhdCgiIEZpbiFcblxuIikKfQoKIyBXcml0ZSB0aGUgY2x1c3RlcmluZyBzb2x1dGlvbnMgZm9yIGVhY2ggYWxnb3JpdGhtCndyaXRlUmFzdGVyKHJzdEtNLCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL1RGRy1Gb3ItR2l0aHViL2hvbmdrb25nX0tNZWFucy50aWYiLCBvdmVyd3JpdGU9VFJVRSkKd3JpdGVSYXN0ZXIocnN0Q0xBUkEsIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvVEZHLUZvci1HaXRodWIvaG9uZ2tvbmdfQ0xBUkEudGlmIiwgb3ZlcndyaXRlPVRSVUUpCgojIENhbWJpYW1vcyBsb3Mgbm9tYnJlcwpuYW1lcyhyc3RLTSkgPC0gYyhwYXN0ZSgiQ2x1c3RlciIsMjoxMCxzZXA9IiIpKQpuYW1lcyhyc3RDTEFSQSkgPC0gYyhwYXN0ZSgiQ2x1c3RlciIsMjoxMCxzZXA9IiIpKQpwbG90KHJzdEtNKQpwbG90KHJzdENMQVJBKQpgYGAKCiMgRXZhbHVhY2nDs24gZGUgbG9zIHJlc3VsdGFkb3MKCmBgYHtyfQpsaWJyYXJ5KGNsdXN0ZXJDcml0KQoKCiMgRGF0YWZyYW1lIGVuIGNvbmp1bnRvIGd1YXJkYSBsb3MgcmVzdWx0YWRvcyBkZSBpbmRkaWNlIGRlIHNpbHVldGEgZGUgay1tZWFucyB5IGNsYXJhIApjbHVzdFBlcmZTSSA8LSBkYXRhLmZyYW1lKG5DbHVzdCA9IDI6MTAsIFNJX0tNID0gTkEsIFNJX0NMQVJBID0gTkEpCgoKZm9yKGkgaW4gMTpubGF5ZXJzKHJzdEtNKSl7ICMgSXRlcmEKICAKICBjYXQoIi0+IEV2YWx1YW5kbyBhZ3J1cGFjaW9uZXMgcGFyYSBuQ2x1c3QgPSIsKDI6MTApW2ldLCIuLi4uLi4iKQogIAogICMgRXh0cmFlIG11ZXN0cmEgYWxlYXRvcmlhICwgZGUgdGFtYcOxbyAxNTAwCiAgY2VsbElkeF9Sc3RLTSA8LSBzYW1wbGVTdHJhdGlmaWVkKHJzdEtNW1tpXV0sIHNpemUgPSAxNTAwKQogIGNlbGxJZHhfcnN0Q0xBUkEgPC0gc2FtcGxlU3RyYXRpZmllZChyc3RDTEFSQVtbaV1dLCBzaXplID0gMTUwMCkKICAKCiAgcnN0REZTdFJTX0tNIDwtIHJzdERGW2NlbGxJZHhfUnN0S01bLDFdLCBdCiAgcnN0REZTdFJTX0NMQVJBIDwtIHJzdERGW2NlbGxJZHhfcnN0Q0xBUkFbLDFdLCBdCiAgCiAgcnN0REZTdFJTX0tNW10gPC0gc2FwcGx5KHJzdERGU3RSU19LTSwgYXMubnVtZXJpYykKICByc3RERlN0UlNfQ0xBUkFbXSA8LSBzYXBwbHkocnN0REZTdFJTX0NMQVJBLCBhcy5udW1lcmljKQogIAogICMgQ2FsY3VsbyBkZWwgaW5kaWNlIGRlIHNpbHVldGEgcGFyYTogCiAgIyAgICAKICAjIEstbWVhbnMKICBjbENyaXRLTSA8LSBpbnRDcml0ZXJpYSh0cmFqID0gcnN0REZTdFJTX0tNLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJ0ID0gYXMuaW50ZWdlcihjZWxsSWR4X1JzdEtNWywyXSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNyaXQgPSAiU2lsaG91ZXR0ZSIpCiAgIyBDTEFSQQogIGNsQ3JpdENMQVJBIDwtIGludENyaXRlcmlhKHRyYWogPSByc3RERlN0UlNfQ0xBUkEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnQgPSBhcy5pbnRlZ2VyKGNlbGxJZHhfcnN0Q0xBUkFbLDJdKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JpdCA9ICJTaWxob3VldHRlIikKICAKICAjIFNlIGVzY3JpYmVuIGxvcyByZXN1bHRhZG9zCiAgY2x1c3RQZXJmU0lbaSwgIlNJX0tNIl0gICAgPC0gY2xDcml0S01bWzFdXVsxXQogIGNsdXN0UGVyZlNJW2ksICJTSV9DTEFSQSJdIDwtIGNsQ3JpdENMQVJBW1sxXV1bMV0KICAKICBjYXQoIiBGaW4hXG5cbiIpCiAgCn0KCmBgYAoKIyBBbsOhbGlzaXMgZGUgcmVzdWx0YWRvcwpgYGB7cn0KIyNndWFyZGFyaWFtb3MgZW4gdW4gY3N2CndyaXRlLmNzdihjbHVzdFBlcmZTSSwgZmlsZSA9ICIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NsdXN0UGVyZlNJLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCiN0YWJsYSBkZSByZXN1bHRhZG9zCmtuaXRyOjprYWJsZShjbHVzdFBlcmZTSSwgZGlnaXRzID0gMywgYWxpZ24gPSAiYyIsIAogICAgICAgICAgICAgY29sLm5hbWVzID0gYygiI2NsdXN0ZXJzIiwiQXZnLiBTaWxob3VldHRlIChrLW1lYW5zKSIsIkF2Zy4gU2lsaG91ZXR0ZSAoQ0xBUkEpIikpCgoKI2dyYWZpY28gZGUgY29tcGFyYWNpb24gZW50cmUgbG9zIGFsZ29yaXRtb3MKcGxvdChjbHVzdFBlcmZTSVssMV0sIGNsdXN0UGVyZlNJWywyXSwgCiAgICAgeGxpbSA9IGMoMiwxMCksIHlsaW0gPSByYW5nZShjbHVzdFBlcmZTSVssMjozXSksIHR5cGUgPSAibiIsIAogICAgIHlsYWI9IkF2Zy4gU2lsaG91ZXR0ZSBJbmRleCIsIHhsYWI9IiMgb2YgY2x1c3RlcnMiLAogICAgIG1haW49IlNpbGhvdWV0dGUgaW5kZXggYnkgIyBvZiBjbHVzdGVycyIpCgojIFBsb3QgQXZnIFNpbGhvdWV0dGUgdmFsdWVzIGFjcm9zcyAjIG9mIGNsdXN0ZXJzIGZvciBLLW1lYW5zCmxpbmVzKGNsdXN0UGVyZlNJWywxXSwgY2x1c3RQZXJmU0lbLDJdLCBjb2w9InJlZCIpCiMgUGxvdCBBdmcgU2lsaG91ZXR0ZSB2YWx1ZXMgYWNyb3NzICMgb2YgY2x1c3RlcnMgZm9yIENMQVJBCmxpbmVzKGNsdXN0UGVyZlNJWywxXSwgY2x1c3RQZXJmU0lbLDNdLCBjb2w9ImJsdWUiKQoKIyBHcmlkIGxpbmVzCmFibGluZSh2ID0gMToxMywgbHR5PTIsIGNvbD0ibGlnaHQgZ3JleSIpCmFibGluZShoID0gc2VxKDAuMzAsMC40NCwwLjAyKSwgbHR5PTIsIGNvbD0ibGlnaHQgZ3JleSIpCgpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoIkstbWVhbnMiLCJDTEFSQSIpLCBjb2w9YygicmVkIiwiYmx1ZSIpLCBsdHk9MSwgbHdkPTEpCmBgYAoKIyBWaXN1YWxpemFjacOzbiBkZSBtZWpvcmVzIGFncnVwYW1pZW50b3MKCmBgYHtyfQoKcGxvdChyc3RLTVtbM11dKQp0aXRsZSgiSy1tZWFuICg0IGNsdXN0ZXJzKSBtZWpvciBhZ3J1cGFtaWVudG8iKQoKcGxvdChyc3RDTEFSQVtbM11dKQp0aXRsZSgiQ0xBUkEgKDQgY2x1c3RlcnMpIikKCgpwbG90KHJzdENMQVJBW1s1XV0pCnRpdGxlKCJDTEFSQSAoNiBjbHVzdGVycykgbWVqb3IgYWdydXBhbWllbnRvIikKCnBsb3QocnN0S01bWzVdXSkKdGl0bGUoIkstbWVhbiAoNiBjbHVzdGVycykiKQoKYGBg