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)"))
#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