This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

En este capitulo exploramos la clasificacion no supervisada. Existen varios algoritmos de clasificación no supervisados, y la eleccion del algoritmo puede afectar los resultados. Exploraremos un solo algoritmo (k-means) para ilustrar el principio general
Para este ejemplo, seguiremos el esquema de clasificacion de la -Base de datos nacional de cobertura de la tierra 2011 (NLCD 2011)- para un subconjunto de las regiones del Valle Central. Utilizamos imagenes compuestas sin nubes de Landsat 5 con 6 bandas.
Sibate, Imagen LandSat 8 2015, utilizando 7 bandas
library(raster)
landsat8 = stack(b2,b3,b4,b5,b6,b7)
names(landsat8) = c ('blue', 'green', 'red', 'NIR', 'SWIR1','SWIR2')
plot(landsat8)

Pregunta 1 : Haga una trama compuesta de 3 bandas de falso color de `` landsat8 ’’.

landsat8FCC_imagen = stack(b5, b6, b4)
plotRGB(landsat8FCC_imagen, axes=TRUE, stretch="lin", main="Landsat composicion de color falsa - Agua / Tierra")


# recortando a sibate

sibatextend = shapefile('C:/Users/David-PC/Desktop/ESCRITORIO/SIBATE_RURAL/rural.shp')

ext = extent(sibatextend)

# crop landsat by the extent

landsatfcc = crop(landsat8FCC_imagen, ext)

plotRGB(landsatfcc, axes = TRUE, stretch = "lin", main = "Landsat True Color Composite")

NA
NA
En la clasificacion no supervisada, utilizamos los datos de reflectancia, pero no proporcionamos ningun dato de respuesta (es decir, no identificamos ningun pixel como perteneciente a una clase en particular). Esto puede parecer extraño, pero puede ser util cuando no tenemos mucho conocimiento previo de un area de estudio. O si tiene un amplio conocimiento de la distribucion de las clases de interes de la cobertura del suelo, pero no tiene datos especificos
El algoritmo agrupa pixeles con caracteristicas espectrales similares en grupos.
Obtenga mas informacion sobre K-means y otros algoritmos supervisados sin supervision -aqui- .
Realizaremos una clasificacion no supervisada en un subconjunto espacial de la -ndvi- capa. Aqui hay otra forma de calcular -ndvi-. En este caso, no usamos una funcion separada, sino una notacion algebraica directa.
ndviLandSat8=(landsat8[['NIR']]-landsat8[['red']])/(landsat8[['NIR']]+landsat8[['red']])
plot(ndviLandSat8)

NA
NA
Haremos un -kmeans- agrupamiento de los -ndvi- datos. Primero usamos -crop- para hacer un subconjunto espacial de -ndvi-, para permitir un procesamiento mas rapido (puede seleccionar cualquiera -extent- usando la -drawExtent()- función).

TITULO: CLASIFICACION KMEANS

# recortando a sibate

extent(landsat8)
class      : Extent 
xmin       : 446085 
xmax       : 673515 
ymin       : 362985 
ymax       : 595215 
landsat8crop2015 = crop(ndviLandSat8, ext)
landsat8crop2015
class      : RasterLayer 
dimensions : 617, 351, 216567  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 576795, 587325, 484005, 502515  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : -0.1625031, 0.6681765  (min, max)
plot(landsat8crop2015)


# convertir el raster a vector / matriz
nr=getValues(landsat8crop2015)
str(nr)
 num [1:216567] 0.471 0.441 0.435 0.396 0.378 ...
Tenga en cuenta que -getValues- convirtio el -ndvi- RasterLayer en una matriz (matriz). Ahora realizaremos el -kmeans- agrupamiento en la matriz e inspeccionaremos la salida.

# Es importante configurar el generador de semillas porque `kmeans` inicia los centros en ubicaciones aleatorias, para eso utilizaremos set.seed

set.seed (99)

# Queremos crear 10 grupos, permitir 500 iteraciones, comenzar con 5 conjuntos aleatorios utilizando el método "Lloyd"

kmncluster = kmeans(na.omit(nr), centers = 10, iter.max = 500, nstart = 5, algorithm = "Lloyd")

# kmeans devuelve un objeto de la clase "kmeans"

str(kmncluster)
List of 9
 $ cluster     : int [1:216567] 10 4 4 8 8 8 8 4 10 8 ...
 $ centers     : num [1:10, 1] 0.181 0.285 0.548 0.425 0.236 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:10] "1" "2" "3" "4" ...
  .. ..$ : NULL
 $ totss       : num 3096
 $ withinss    : num [1:10] 6.4 6 7.92 6.11 5.84 ...
 $ tot.withinss: num 57.6
 $ betweenss   : num 3039
 $ size        : int [1:10] 19149 32049 9132 28567 25928 34882 5743 33820 6570 20727
 $ iter        : int 103
 $ ifault      : NULL
 - attr(*, "class")= chr "kmeans"
-kmeans-devuelve un objeto con 9 elementos. La longitud del -cluster- elemento dentro -kmncluster- es 216567 que es igual a la longitud de -nr- creado desde -ndvi-. Los valores de celda de -kmncluster\(cluster- rango entre 1 a 10 correspondientes al numero de entrada del cluster que proporcionamos en la -kmeans- funcion. -kmncluster\)cluster- indica la etiqueta del cluster para el pixel correspondiente. Necesitamos convertir los -kmncluster$cluster- valores nuevamente a RasterLayer de la misma dimension que -ndvi-.
# Use el objeto ndvi (en este caso se llama "landsat8crop2015") para establecer los valores del cluster en un nuevo raster

knr = setValues(landsat8crop2015, kmncluster$cluster)

# Tambien puedes hacerlo asi

knr= raster(landsat8crop2015)
values(knr) = kmncluster$cluster
knr
class      : RasterLayer 
dimensions : 617, 351, 216567  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 576795, 587325, 484005, 502515  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : 1, 10  (min, max)
Podemos ver que -knr- es un RasterLayer, pero no sabemos que grupo (1-10) pertenece a que clase de cobertura terrestre (y si pertenece a una clase que reconoceriamos). Puede averiguarlo trazandolos lado a lado con capas de referencia y usando un color unico para cada grupo.
#Defina un vector de color para 10 grupos (mas informacion sobre como configurar el color mas adelante)

mycolor = c ("#fef65b","#ff0000", "#daa520","#0000ff","#0000ff","#00ff00","#cbbeb5",
             "#c3ff5b", "#ff7373", "#00ff00", "#808080")
par(mfrow = c(1,2))
plot(landsat8crop2015, col = rev(terrain.colors(10)), main = 'Landsat-NDVI')
plot(knr, main = 'Unsupervised classification', col = mycolor )

Si bien para otros fines suele ser mejor definir mas clases (y posiblemente fusionar clases mas adelante), una clasificacion simple como esta podria ser util, por ejemplo, fusionar los grupos 4 y 5 para construir una mascara de agua para el año 2015.
Puedes cambiar los colores en mi -mycolor-. Obtenga mas informacion sobre la seleccion de colores en R -aqui- y -aqui- .
Pregunta 2 : Grafique el RGB de 3 bandas de “landsat8” para el subconjunto (extensión “ext”) y el resultado de la agrupacion “kmeans” lado a lado y haga una tabla de cobertura del suelo para el uso del suelo Etiquetas para los grupos. Por ejemplo, los grupos 4 y 5 son agua.

landsat8p2 = stack(b6, b3, b2)
#plotRGB(landsat8p2, axes=TRUE, stretch="lin", main="Landsat composicion de color falsa ")

#crop landsat by the extent

landsatsibatep2 = crop(landsat8p2, ext)

plotRGB(landsatsibatep2, axes = TRUE, stretch = "lin", main = "Landsat FCC - SIBATE")





# convertir el raster a vector / matriz
nr_p2=getValues(landsatsibatep2)
str(nr_p2)
 int [1:216567, 1:3] 13348 12473 12269 13387 14576 14992 14842 12425 11290 9894 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:3] "LC08_L1TP_008057_20150104_20170415_01_T1_B6" "LC08_L1TP_008057_20150104_20170415_01_T1_B3" "LC08_L1TP_008057_20150104_20170415_01_T1_B2"
# Es importante configurar el generador de semillas porque `kmeans` inicia los centros en ubicaciones aleatorias, para eso utilizaremos set.seed

set.seed (99)

# Queremos crear 10 grupos, permitir 500 iteraciones, comenzar con 5 conjuntos aleatorios utilizando el método "Lloyd"

kmncluster_p2 = kmeans(na.omit(nr), centers = 10, iter.max = 500, nstart = 5, algorithm = "Lloyd")

# kmeans devuelve un objeto de la clase "kmeans"

str(kmncluster_p2)
List of 9
 $ cluster     : int [1:216567] 10 4 4 8 8 8 8 4 10 8 ...
 $ centers     : num [1:10, 1] 0.181 0.285 0.548 0.425 0.236 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:10] "1" "2" "3" "4" ...
  .. ..$ : NULL
 $ totss       : num 3096
 $ withinss    : num [1:10] 6.4 6 7.92 6.11 5.84 ...
 $ tot.withinss: num 57.6
 $ betweenss   : num 3039
 $ size        : int [1:10] 19149 32049 9132 28567 25928 34882 5743 33820 6570 20727
 $ iter        : int 103
 $ ifault      : NULL
 - attr(*, "class")= chr "kmeans"
# Use el objeto ndvi (en este caso se llama "landsatsibatep2") para establecer los valores del cluster en un nuevo raster

knr_p2 = setValues(landsatsibatep2, kmncluster_p2$cluster)

# Tambien puedes hacerlo asi

knr_p2= raster(landsatsibatep2)
values(knr_p2) = kmncluster_p2$cluster
knr_p2
class      : RasterLayer 
dimensions : 617, 351, 216567  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 576795, 587325, 484005, 502515  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : 1, 10  (min, max)
#Defina un vector de color para 10 grupos (mas informacion sobre como configurar el color mas adelante)

#mycolor_p2 = c (topo.colors(10))

plot(knr_p2, main = 'Unsupervised classification', col = rev(topo.colors(10))) 

NA
NA

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tDQp0aXRsZTogIioqSW1hZ2VuIExhbmRTYXQgOCwgU2liYXRlIDIwMTUgLSBDbGFzaWZpY2FjaW9uIG5vIHN1cGVydmlzYWRhKioiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KDQoNCiMjIyMjIEVuIGVzdGUgY2FwaXR1bG8gZXhwbG9yYW1vcyBsYSBjbGFzaWZpY2FjaW9uIG5vIHN1cGVydmlzYWRhLiBFeGlzdGVuIHZhcmlvcyBhbGdvcml0bW9zIGRlIGNsYXNpZmljYWNpw7NuIG5vIHN1cGVydmlzYWRvcywgeSBsYSBlbGVjY2lvbiBkZWwgYWxnb3JpdG1vIHB1ZWRlIGFmZWN0YXIgbG9zIHJlc3VsdGFkb3MuIEV4cGxvcmFyZW1vcyB1biBzb2xvIGFsZ29yaXRtbyAoay1tZWFucykgcGFyYSBpbHVzdHJhciBlbCBwcmluY2lwaW8gZ2VuZXJhbA0KDQoNCiMjIyMjIFBhcmEgZXN0ZSBlamVtcGxvLCBzZWd1aXJlbW9zIGVsIGVzcXVlbWEgZGUgY2xhc2lmaWNhY2lvbiBkZSBsYSAtQmFzZSBkZSBkYXRvcyBuYWNpb25hbCBkZSBjb2JlcnR1cmEgZGUgbGEgdGllcnJhIDIwMTEgKE5MQ0QgMjAxMSktIHBhcmEgdW4gc3ViY29uanVudG8gZGUgbGFzIHJlZ2lvbmVzIGRlbCBWYWxsZSBDZW50cmFsLiBVdGlsaXphbW9zIGltYWdlbmVzIGNvbXB1ZXN0YXMgc2luIG51YmVzIGRlIExhbmRzYXQgNSBjb24gNiBiYW5kYXMuDQoNCg0KIyMjIyMgU2liYXRlLCBJbWFnZW4gTGFuZFNhdCA4IDIwMTUsIHV0aWxpemFuZG8gNyBiYW5kYXMNCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCmxhbmRzYXQ4ID0gc3RhY2soYjIsYjMsYjQsYjUsYjYsYjcpDQpuYW1lcyhsYW5kc2F0OCkgPSBjICgnYmx1ZScsICdncmVlbicsICdyZWQnLCAnTklSJywgJ1NXSVIxJywnU1dJUjInKQ0KcGxvdChsYW5kc2F0OCkNCmBgYA0KDQoNCiMjIyMjIFByZWd1bnRhIDEgOiBIYWdhIHVuYSB0cmFtYSBjb21wdWVzdGEgZGUgMyBiYW5kYXMgZGUgZmFsc28gY29sb3IgZGUgYGAgbGFuZHNhdDggJycuDQoNCg0KYGBge3J9DQoNCmxhbmRzYXQ4RkNDX2ltYWdlbiA9IHN0YWNrKGI1LCBiNiwgYjQpDQpwbG90UkdCKGxhbmRzYXQ4RkNDX2ltYWdlbiwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IGNvbXBvc2ljaW9uIGRlIGNvbG9yIGZhbHNhIC0gQWd1YSAvIFRpZXJyYSIpDQoNCiMgcmVjb3J0YW5kbyBhIHNpYmF0ZQ0KDQpzaWJhdGV4dGVuZCA9IHNoYXBlZmlsZSgnQzovVXNlcnMvRGF2aWQtUEMvRGVza3RvcC9FU0NSSVRPUklPL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQpleHQgPSBleHRlbnQoc2liYXRleHRlbmQpDQoNCiMgY3JvcCBsYW5kc2F0IGJ5IHRoZSBleHRlbnQNCg0KbGFuZHNhdGZjYyA9IGNyb3AobGFuZHNhdDhGQ0NfaW1hZ2VuLCBleHQpDQoNCnBsb3RSR0IobGFuZHNhdGZjYywgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCg0KDQpgYGANCg0KDQojIyMjIyBFbiBsYSBjbGFzaWZpY2FjaW9uIG5vIHN1cGVydmlzYWRhLCB1dGlsaXphbW9zIGxvcyBkYXRvcyBkZSByZWZsZWN0YW5jaWEsIHBlcm8gbm8gcHJvcG9yY2lvbmFtb3MgbmluZ3VuIGRhdG8gZGUgcmVzcHVlc3RhIChlcyBkZWNpciwgbm8gaWRlbnRpZmljYW1vcyBuaW5ndW4gcGl4ZWwgY29tbyBwZXJ0ZW5lY2llbnRlIGEgdW5hIGNsYXNlIGVuIHBhcnRpY3VsYXIpLiBFc3RvIHB1ZWRlIHBhcmVjZXIgZXh0cmHDsW8sIHBlcm8gcHVlZGUgc2VyIHV0aWwgY3VhbmRvIG5vIHRlbmVtb3MgbXVjaG8gY29ub2NpbWllbnRvIHByZXZpbyBkZSB1biBhcmVhIGRlIGVzdHVkaW8uIE8gc2kgdGllbmUgdW4gYW1wbGlvIGNvbm9jaW1pZW50byBkZSBsYSBkaXN0cmlidWNpb24gZGUgbGFzIGNsYXNlcyBkZSBpbnRlcmVzIGRlIGxhIGNvYmVydHVyYSBkZWwgc3VlbG8sIHBlcm8gbm8gdGllbmUgZGF0b3MgZXNwZWNpZmljb3MgDQoNCg0KIyMjIyMgRWwgYWxnb3JpdG1vIGFncnVwYSBwaXhlbGVzIGNvbiBjYXJhY3RlcmlzdGljYXMgZXNwZWN0cmFsZXMgc2ltaWxhcmVzIGVuIGdydXBvcy4NCg0KDQojIyMjIyBPYnRlbmdhIG1hcyBpbmZvcm1hY2lvbiBzb2JyZSBLLW1lYW5zIHkgb3Ryb3MgYWxnb3JpdG1vcyBzdXBlcnZpc2Fkb3Mgc2luIHN1cGVydmlzaW9uIC1hcXVpLSAuDQoNCg0KIyMjIyMgUmVhbGl6YXJlbW9zIHVuYSBjbGFzaWZpY2FjaW9uIG5vIHN1cGVydmlzYWRhIGVuIHVuIHN1YmNvbmp1bnRvIGVzcGFjaWFsIGRlIGxhIC1uZHZpLSBjYXBhLiBBcXVpIGhheSBvdHJhIGZvcm1hIGRlIGNhbGN1bGFyIC1uZHZpLS4gRW4gZXN0ZSBjYXNvLCBubyB1c2Ftb3MgdW5hIGZ1bmNpb24gc2VwYXJhZGEsIHNpbm8gdW5hIG5vdGFjaW9uIGFsZ2VicmFpY2EgZGlyZWN0YS4NCg0KDQpgYGB7cn0NCm5kdmlMYW5kU2F0OD0obGFuZHNhdDhbWydOSVInXV0tbGFuZHNhdDhbWydyZWQnXV0pLyhsYW5kc2F0OFtbJ05JUiddXStsYW5kc2F0OFtbJ3JlZCddXSkNCnBsb3QobmR2aUxhbmRTYXQ4KQ0KDQoNCmBgYA0KDQoNCiMjIyMjIEhhcmVtb3MgdW4gLWttZWFucy0gYWdydXBhbWllbnRvIGRlIGxvcyAtbmR2aS0gZGF0b3MuIFByaW1lcm8gdXNhbW9zIC1jcm9wLSBwYXJhIGhhY2VyIHVuIHN1YmNvbmp1bnRvIGVzcGFjaWFsIGRlIC1uZHZpLSwgcGFyYSBwZXJtaXRpciB1biBwcm9jZXNhbWllbnRvIG1hcyByYXBpZG8gKHB1ZWRlIHNlbGVjY2lvbmFyIGN1YWxxdWllcmEgLWV4dGVudC0gdXNhbmRvIGxhIC1kcmF3RXh0ZW50KCktIGZ1bmNpw7NuKS4NCg0KDQojIyMgKipUSVRVTE86IENMQVNJRklDQUNJT04gS01FQU5TKioNCg0KDQpgYGB7cn0NCiMgcmVjb3J0YW5kbyBhIHNpYmF0ZQ0KDQpleHRlbnQobGFuZHNhdDgpDQpsYW5kc2F0OGNyb3AyMDE1ID0gY3JvcChuZHZpTGFuZFNhdDgsIGV4dCkNCmxhbmRzYXQ4Y3JvcDIwMTUNCnBsb3QobGFuZHNhdDhjcm9wMjAxNSkNCg0KIyBjb252ZXJ0aXIgZWwgcmFzdGVyIGEgdmVjdG9yIC8gbWF0cml6DQpucj1nZXRWYWx1ZXMobGFuZHNhdDhjcm9wMjAxNSkNCnN0cihucikNCg0KDQoNCmBgYA0KDQoNCiMjIyMjIFRlbmdhIGVuIGN1ZW50YSBxdWUgLWdldFZhbHVlcy0gY29udmlydGlvIGVsIC1uZHZpLSBSYXN0ZXJMYXllciBlbiB1bmEgbWF0cml6IChtYXRyaXopLiBBaG9yYSByZWFsaXphcmVtb3MgZWwgLWttZWFucy0gYWdydXBhbWllbnRvIGVuIGxhIG1hdHJpeiBlIGluc3BlY2Npb25hcmVtb3MgbGEgc2FsaWRhLg0KDQoNCmBgYHtyfQ0KDQojIEVzIGltcG9ydGFudGUgY29uZmlndXJhciBlbCBnZW5lcmFkb3IgZGUgc2VtaWxsYXMgcG9ycXVlIGBrbWVhbnNgIGluaWNpYSBsb3MgY2VudHJvcyBlbiB1YmljYWNpb25lcyBhbGVhdG9yaWFzLCBwYXJhIGVzbyB1dGlsaXphcmVtb3Mgc2V0LnNlZWQNCg0Kc2V0LnNlZWQgKDk5KQ0KDQojIFF1ZXJlbW9zIGNyZWFyIDEwIGdydXBvcywgcGVybWl0aXIgNTAwIGl0ZXJhY2lvbmVzLCBjb21lbnphciBjb24gNSBjb25qdW50b3MgYWxlYXRvcmlvcyB1dGlsaXphbmRvIGVsIG3DqXRvZG8gIkxsb3lkIg0KDQprbW5jbHVzdGVyID0ga21lYW5zKG5hLm9taXQobnIpLCBjZW50ZXJzID0gMTAsIGl0ZXIubWF4ID0gNTAwLCBuc3RhcnQgPSA1LCBhbGdvcml0aG0gPSAiTGxveWQiKQ0KDQojIGttZWFucyBkZXZ1ZWx2ZSB1biBvYmpldG8gZGUgbGEgY2xhc2UgImttZWFucyINCg0Kc3RyKGttbmNsdXN0ZXIpDQoNCg0KYGBgDQoNCg0KIyMjIyMgLWttZWFucy1kZXZ1ZWx2ZSB1biBvYmpldG8gY29uIDkgZWxlbWVudG9zLiBMYSBsb25naXR1ZCBkZWwgLWNsdXN0ZXItIGVsZW1lbnRvIGRlbnRybyAta21uY2x1c3Rlci0gZXMgMjE2NTY3IHF1ZSBlcyBpZ3VhbCBhIGxhIGxvbmdpdHVkIGRlIC1uci0gY3JlYWRvIGRlc2RlIC1uZHZpLS4gTG9zIHZhbG9yZXMgZGUgY2VsZGEgZGUgLWttbmNsdXN0ZXIkY2x1c3Rlci0gcmFuZ28gZW50cmUgMSBhIDEwIGNvcnJlc3BvbmRpZW50ZXMgYWwgbnVtZXJvIGRlIGVudHJhZGEgZGVsIGNsdXN0ZXIgcXVlIHByb3BvcmNpb25hbW9zIGVuIGxhIC1rbWVhbnMtIGZ1bmNpb24uIC1rbW5jbHVzdGVyJGNsdXN0ZXItIGluZGljYSBsYSBldGlxdWV0YSBkZWwgY2x1c3RlciBwYXJhIGVsIHBpeGVsIGNvcnJlc3BvbmRpZW50ZS4gTmVjZXNpdGFtb3MgY29udmVydGlyIGxvcyAta21uY2x1c3RlciRjbHVzdGVyLSB2YWxvcmVzIG51ZXZhbWVudGUgYSBSYXN0ZXJMYXllciBkZSBsYSBtaXNtYSBkaW1lbnNpb24gcXVlIC1uZHZpLS4NCg0KDQpgYGB7cn0NCiMgVXNlIGVsIG9iamV0byBuZHZpIChlbiBlc3RlIGNhc28gc2UgbGxhbWEgImxhbmRzYXQ4Y3JvcDIwMTUiKSBwYXJhIGVzdGFibGVjZXIgbG9zIHZhbG9yZXMgZGVsIGNsdXN0ZXIgZW4gdW4gbnVldm8gcmFzdGVyDQoNCmtuciA9IHNldFZhbHVlcyhsYW5kc2F0OGNyb3AyMDE1LCBrbW5jbHVzdGVyJGNsdXN0ZXIpDQoNCiMgVGFtYmllbiBwdWVkZXMgaGFjZXJsbyBhc2kNCg0Ka25yPSByYXN0ZXIobGFuZHNhdDhjcm9wMjAxNSkNCnZhbHVlcyhrbnIpID0ga21uY2x1c3RlciRjbHVzdGVyDQprbnINCg0KYGBgDQoNCg0KIyMjIyMgUG9kZW1vcyB2ZXIgcXVlIC1rbnItIGVzIHVuIFJhc3RlckxheWVyLCBwZXJvIG5vIHNhYmVtb3MgcXVlIGdydXBvICgxLTEwKSBwZXJ0ZW5lY2UgYSBxdWUgY2xhc2UgZGUgY29iZXJ0dXJhIHRlcnJlc3RyZSAoeSBzaSBwZXJ0ZW5lY2UgYSB1bmEgY2xhc2UgcXVlIHJlY29ub2NlcmlhbW9zKS4gUHVlZGUgYXZlcmlndWFybG8gdHJhemFuZG9sb3MgbGFkbyBhIGxhZG8gY29uIGNhcGFzIGRlIHJlZmVyZW5jaWEgeSB1c2FuZG8gdW4gY29sb3IgdW5pY28gcGFyYSBjYWRhIGdydXBvLg0KDQoNCmBgYHtyfQ0KI0RlZmluYSB1biB2ZWN0b3IgZGUgY29sb3IgcGFyYSAxMCBncnVwb3MgKG1hcyBpbmZvcm1hY2lvbiBzb2JyZSBjb21vIGNvbmZpZ3VyYXIgZWwgY29sb3IgbWFzIGFkZWxhbnRlKQ0KDQpteWNvbG9yID0gYyAoIiNmZWY2NWIiLCIjZmYwMDAwIiwgIiNkYWE1MjAiLCIjMDAwMGZmIiwiIzAwMDBmZiIsIiMwMGZmMDAiLCIjY2JiZWI1IiwNCiAgICAgICAgICAgICAiI2MzZmY1YiIsICIjZmY3MzczIiwgIiMwMGZmMDAiLCAiIzgwODA4MCIpDQpwYXIobWZyb3cgPSBjKDEsMikpDQpwbG90KGxhbmRzYXQ4Y3JvcDIwMTUsIGNvbCA9IHJldih0ZXJyYWluLmNvbG9ycygxMCkpLCBtYWluID0gJ0xhbmRzYXQtTkRWSScpDQpwbG90KGtuciwgbWFpbiA9ICdVbnN1cGVydmlzZWQgY2xhc3NpZmljYXRpb24nLCBjb2wgPSBteWNvbG9yICkNCg0KYGBgDQoNCg0KIyMjIyMgU2kgYmllbiBwYXJhIG90cm9zIGZpbmVzIHN1ZWxlIHNlciBtZWpvciBkZWZpbmlyIG1hcyBjbGFzZXMgKHkgcG9zaWJsZW1lbnRlIGZ1c2lvbmFyIGNsYXNlcyBtYXMgYWRlbGFudGUpLCB1bmEgY2xhc2lmaWNhY2lvbiBzaW1wbGUgY29tbyBlc3RhIHBvZHJpYSBzZXIgdXRpbCwgcG9yIGVqZW1wbG8sIGZ1c2lvbmFyIGxvcyBncnVwb3MgNCB5IDUgcGFyYSBjb25zdHJ1aXIgdW5hIG1hc2NhcmEgZGUgYWd1YSBwYXJhIGVsIGHDsW8gMjAxNS4NCg0KDQojIyMjIyBQdWVkZXMgY2FtYmlhciBsb3MgY29sb3JlcyBlbiBtaSAtbXljb2xvci0uIE9idGVuZ2EgbWFzIGluZm9ybWFjaW9uIHNvYnJlIGxhIHNlbGVjY2lvbiBkZSBjb2xvcmVzIGVuIFIgLWFxdWktIHkgLWFxdWktIC4NCg0KDQojIyMjIyBQcmVndW50YSAyIDogR3JhZmlxdWUgZWwgUkdCIGRlIDMgYmFuZGFzIGRlICAibGFuZHNhdDgiIHBhcmEgZWwgc3ViY29uanVudG8gKGV4dGVuc2nDs24gImV4dCIpIHkgZWwgcmVzdWx0YWRvIGRlIGxhIGFncnVwYWNpb24gImttZWFucyIgbGFkbyBhIGxhZG8geSBoYWdhIHVuYSB0YWJsYSBkZSBjb2JlcnR1cmEgZGVsIHN1ZWxvIHBhcmEgZWwgdXNvIGRlbCBzdWVsbyBFdGlxdWV0YXMgcGFyYSBsb3MgZ3J1cG9zLiBQb3IgZWplbXBsbywgbG9zIGdydXBvcyA0IHkgNSBzb24gYWd1YS4NCg0KDQpgYGB7cn0NCg0KbGFuZHNhdDhwMiA9IHN0YWNrKGI2LCBiMywgYjIpDQojcGxvdFJHQihsYW5kc2F0OHAyLCBheGVzPVRSVUUsIHN0cmV0Y2g9ImxpbiIsIG1haW49IkxhbmRzYXQgY29tcG9zaWNpb24gZGUgY29sb3IgZmFsc2EgIikNCg0KI2Nyb3AgbGFuZHNhdCBieSB0aGUgZXh0ZW50DQoNCmxhbmRzYXRzaWJhdGVwMiA9IGNyb3AobGFuZHNhdDhwMiwgZXh0KQ0KDQpwbG90UkdCKGxhbmRzYXRzaWJhdGVwMiwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IEZDQyAtIFNJQkFURSIpDQoNCg0KDQoNCiMgY29udmVydGlyIGVsIHJhc3RlciBhIHZlY3RvciAvIG1hdHJpeg0KbnJfcDI9Z2V0VmFsdWVzKGxhbmRzYXRzaWJhdGVwMikNCnN0cihucl9wMikNCg0KDQoNCg0KIyBFcyBpbXBvcnRhbnRlIGNvbmZpZ3VyYXIgZWwgZ2VuZXJhZG9yIGRlIHNlbWlsbGFzIHBvcnF1ZSBga21lYW5zYCBpbmljaWEgbG9zIGNlbnRyb3MgZW4gdWJpY2FjaW9uZXMgYWxlYXRvcmlhcywgcGFyYSBlc28gdXRpbGl6YXJlbW9zIHNldC5zZWVkDQoNCnNldC5zZWVkICg5OSkNCg0KIyBRdWVyZW1vcyBjcmVhciAxMCBncnVwb3MsIHBlcm1pdGlyIDUwMCBpdGVyYWNpb25lcywgY29tZW56YXIgY29uIDUgY29uanVudG9zIGFsZWF0b3Jpb3MgdXRpbGl6YW5kbyBlbCBtw6l0b2RvICJMbG95ZCINCg0Ka21uY2x1c3Rlcl9wMiA9IGttZWFucyhuYS5vbWl0KG5yKSwgY2VudGVycyA9IDEwLCBpdGVyLm1heCA9IDUwMCwgbnN0YXJ0ID0gNSwgYWxnb3JpdGhtID0gIkxsb3lkIikNCg0KIyBrbWVhbnMgZGV2dWVsdmUgdW4gb2JqZXRvIGRlIGxhIGNsYXNlICJrbWVhbnMiDQoNCnN0cihrbW5jbHVzdGVyX3AyKQ0KDQoNCg0KDQojIFVzZSBlbCBvYmpldG8gbmR2aSAoZW4gZXN0ZSBjYXNvIHNlIGxsYW1hICJsYW5kc2F0c2liYXRlcDIiKSBwYXJhIGVzdGFibGVjZXIgbG9zIHZhbG9yZXMgZGVsIGNsdXN0ZXIgZW4gdW4gbnVldm8gcmFzdGVyDQoNCmtucl9wMiA9IHNldFZhbHVlcyhsYW5kc2F0c2liYXRlcDIsIGttbmNsdXN0ZXJfcDIkY2x1c3RlcikNCg0KIyBUYW1iaWVuIHB1ZWRlcyBoYWNlcmxvIGFzaQ0KDQprbnJfcDI9IHJhc3RlcihsYW5kc2F0c2liYXRlcDIpDQp2YWx1ZXMoa25yX3AyKSA9IGttbmNsdXN0ZXJfcDIkY2x1c3Rlcg0Ka25yX3AyDQoNCg0KDQojRGVmaW5hIHVuIHZlY3RvciBkZSBjb2xvciBwYXJhIDEwIGdydXBvcyAobWFzIGluZm9ybWFjaW9uIHNvYnJlIGNvbW8gY29uZmlndXJhciBlbCBjb2xvciBtYXMgYWRlbGFudGUpDQoNCiNteWNvbG9yX3AyID0gYyAodG9wby5jb2xvcnMoMTApKQ0KDQpwbG90KGtucl9wMiwgbWFpbiA9ICdVbnN1cGVydmlzZWQgY2xhc3NpZmljYXRpb24nLCBjb2wgPSByZXYodG9wby5jb2xvcnMoMTApKSkgDQoNCg0KYGBgDQoNCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0K