library(knitr)

Contenido

  1. Practica 1: Descarga de datos bƔsicos para anƔlisis
  2. Practica 2: Exploración de imÔgenes
    2.1. Cargando imƔgenes a R
    2.2. Información contenida en las variables
    2.3. Otra alternativa para cargar imƔgenes
    2.4. Banda Ćŗnica y mapas compuestos
    2.5. Composición de imÔgenes en color verdadero y falso
    2.6. Subconjuntos de archivos
    2.7. Recortes espaciales de imƔgenes
    2.8. Composición de color verdadero y falso para imÔgenes recortadas
    2.9. Almacenamiento de datos en disco
    2.10. Relación entre bandas
    2.11. Valores de pixeles
    2.12. Perfiles espectrales
  3. Practica 3: Operaciones matemƔticas bƔsicas
    3.1. ƍndice de vegetación NDVI
    3.1.1. Histograma de NDVI
    3.2. ƍndice de agua de diferencia normalizada NDWI
    3.2.1. Mc Feeters (2006)
    3.2.2. Histograma de NDWI – Mc Feeters (2006)
    3.2.3. M-NDWI Xu (2006)
    3.2.4. Histograma de MNDWI – Xu (2006)
    3.3. ƍndice de diferencia normalizada de Ć”rea construida NDBI
    3.3.1. Histograma de NDBI
    3.4. Umbralización
    3.5. AnƔlisis de componentes principales

1. Practica 1: Descarga de datos bƔsicos para anƔlisis

Los datos pueden ser descargados, y guardados directamente en la dirección de preferencia para su posterior anÔlisis, mediante la creación de un directorio (dir.create) y posteriormente descomprimidos (unzip).

dir.create('data', showWarnings = FALSE)
if (!file.exists('data/rs/samples.rds')) {
    download.file('https://biogeo.ucdavis.edu/data/rspatial/rsdata.zip', dest = 'data/rsdata.zip')
    unzip('data/rsdata.zip', exdir='data')
}

2. Practica 2: Exploración de imÔgenes

2.1. Cargando imƔgenes a R

Las imÔgenes previamente descargadas y descomprimidas en la carpeta /data/rs/, se cargan empleando múltiples opciones, mediante las librerías raster y sp, serÔn subidas las primeras 7 bandas de forma individual, las cuales se encuentran identificadas a continuación.

Banda Landsat 8 Codificación
Azul b2
Verde b3
Roja b4
NIR b5
SWIR1 b6
SWIR 2 b7
library(sp)
library (raster)

b2 <- raster('data/rs/LC08_044034_20170614_B2.tif')
b3 <- raster('data/rs/LC08_044034_20170614_B3.tif')
b4 <- raster('data/rs/LC08_044034_20170614_B4.tif')
b5 <- raster('data/rs/LC08_044034_20170614_B5.tif')
b6 <- raster('data/rs/LC08_044034_20170614_B6.tif')
b7 <- raster('data/rs/LC08_044034_20170614_B7.tif')

2.2. Información contenida en las variables

Debido a que las bandas han sido almacenadas como objetos (ya que R emplea un sistema de programación enfocado en objetos), se pueden visualizar la información contenida dentro de estas variables recientemente creadas.

Banda 2

b2
class      : RasterLayer 
dimensions : 1245, 1497, 1863765  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 594090, 639000, 4190190, 4227540  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/Elkin/Documents/R/data/rs/LC08_044034_20170614_B2.tif 
names      : LC08_044034_20170614_B2 
values     : 0.0748399, 0.7177562  (min, max)
crs(b2)
CRS arguments:
 +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
ncell(b2)
[1] 1863765
dim(b2)
[1] 1245 1497    1
res(b2)
[1] 30 30
nlayers(b2)
[1] 1

Banda 3

b3
class      : RasterLayer 
dimensions : 1245, 1497, 1863765  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 594090, 639000, 4190190, 4227540  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/Elkin/Documents/R/data/rs/LC08_044034_20170614_B3.tif 
names      : LC08_044034_20170614_B3 
values     : 0.04259216, 0.6924697  (min, max)
crs(b3)
CRS arguments:
 +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
ncell(b3)
[1] 1863765
dim(b3)
[1] 1245 1497    1
res(b3)
[1] 30 30
nlayers(b3)
[1] 1

Banda 4

b4
class      : RasterLayer 
dimensions : 1245, 1497, 1863765  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 594090, 639000, 4190190, 4227540  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/Elkin/Documents/R/data/rs/LC08_044034_20170614_B4.tif 
names      : LC08_044034_20170614_B4 
values     : 0.02084067, 0.7861769  (min, max)
crs(b4)
CRS arguments:
 +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
ncell(b4)
[1] 1863765
dim(b4)
[1] 1245 1497    1
res(b4)
[1] 30 30
nlayers(b4)
[1] 1

Banda 5

b5
class      : RasterLayer 
dimensions : 1245, 1497, 1863765  (nrow, ncol, ncell)
resolution : 30, 30  (x, y)
extent     : 594090, 639000, 4190190, 4227540  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/Elkin/Documents/R/data/rs/LC08_044034_20170614_B5.tif 
names      : LC08_044034_20170614_B5 
values     : 0.0008457669, 1.012432  (min, max)
crs(b5)
CRS arguments:
 +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
ncell(b5)
[1] 1863765
dim(b5)
[1] 1245 1497    1
res(b5)
[1] 30 30
nlayers(b5)
[1] 1

Comparación entre las diferentes bandas, un valor de TRUE permitirÔ la interacción correcta entre ellas posteriormente.

compareRaster(b2,b3,b4,b5)
[1] TRUE

2.3. Otra alternativa para cargar las imƔgenes

Al crear un objeto que contenga el listado de nombres que serƔn cargados, puede emplearse un (stack) donde estƩn almacenadas las bandas requeridas.

filenames <- paste0('data/rs/LC08_044034_20170614_B', 1:11, ".tif")
landsat <- stack(filenames)
landsat
class      : RasterStack 
dimensions : 1245, 1497, 1863765, 11  (nrow, ncol, ncell, nlayers)
resolution : 30, 30  (x, y)
extent     : 594090, 639000, 4190190, 4227540  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
names      : LC08_044034_20170614_B1, LC08_044034_20170614_B2, LC08_044034_20170614_B3, LC08_044034_20170614_B4, LC08_044034_20170614_B5, LC08_044034_20170614_B6, LC08_044034_20170614_B7, LC08_044034_20170614_B8, LC08_044034_20170614_B9, LC08_044034_20170614_B10, LC08_044034_20170614_B11 
min values :            9.641791e-02,            7.483990e-02,            4.259216e-02,            2.084067e-02,            8.457669e-04,           -7.872183e-03,           -5.052945e-03,            3.931751e-02,           -4.337332e-04,             2.897978e+02,             2.885000e+02 
max values :              0.73462820,              0.71775615,              0.69246972,              0.78617686,              1.01243150,              1.04320455,              1.11793602,              0.82673049,              0.03547901,             322.43139648,             317.99530029 

2.4. Banda Ćŗnica y mapas compuestos

Mediante una variación del código, donde la función (stretch) que da franjas mínimas y mÔximas en forma de cuantiles y estira en este intervalo de salida los valores originales, se logra una mejor resolución de la imagen.

par(mfrow = c(1,2))
plot(b2, main = "Blue", col = gray(0:100 / 100))
plot(stretch(b2, minq=0.5, maxq=0.9), main = "Blue", col = gray(0:100 / 100))

plot(stretch(b3, minq=0.5, maxq=0.9), main = "Green", col = gray(0:100 / 100))

plot(stretch(b4, minq=0.5, maxq=0.9), main = "Red", col = gray(0:100 / 100))

plot(stretch(b5, minq=0.5, maxq=0.9), main = "NIR", col = gray(0:100 / 100))

2.5. Composición de imÔgenes en color verdadero Y falso

Debido a que las imÔgenes proyectadas en blanco y negro de las bandas independientes no arrojan mucha información acerca de la cobertura del suelo, es posible emplear una combinación de bandas que sea procesada por el programa, con el fin de generar una imagen RGB (Red-Green-Blue), lo que permitirÔ en principio emplear las bandas 4, 3 y 2 respectivamente para elaborar una imagen en color verdadero de la superficie del terreno.

landsatRGB <- landsat[[c(4,3,2)]]
plotRGB(landsatRGB, axes =TRUE, stretch = "lin", main = "Landsat True Color Composite")

Sin embargo, reemplazando las bandas anteriormente mencionadas, por otras diferentes, y generando combinaciones adecuadas, es posible identificar información que en color verdadero no son fÔcilmente clasificables, es allí donde las imÔgenes en color falso, donde las bandas no corresponden con el sistema RGB, presentan una gran utilidad.
Debido a que la banda NIR presenta una gran reflectancia de la vegetación, esta es representada por coloraciones rojas intensas.

landsatFCC_veg <- landsat[[c(5,4,3)]]
plotRGB(landsatFCC_veg, axes =TRUE, stretch = "lin", main = "Landsat False Color Composite-Vegetation")

Una opción adicional es clasificar las zonas que tienen reflectancias infrarrojas de onda corta mayores, que por lo general son Ôreas urbanas, con coberturas de concreto.

landsatFCC_urb <- landsat[[c(7,6,4)]]
plotRGB(landsatFCC_urb, axes =TRUE, stretch = "lin", main = "Landsat False Color Composite-Urban Zones")

De igual forma, la vegetación y las zonas en preparación y explotación agrícola pueden resultar identificadas usando las bandas SWIR1, NIR y azul.

landsatFCC_agr <- landsat[[c(6,5,2)]]
plotRGB(landsatFCC_agr, axes =TRUE, stretch = "lin", main = "Landsat False Color Composite-Agriculture")

landsatFCC_veghealt <- landsat[[c(5,6,2)]]
plotRGB(landsatFCC_veghealt, axes =TRUE, stretch = "lin", main = "Landsat False Color Composite-
Healthy Veg.")

2.6. Subconjuntos de archivos

La función (subset) y su variación landsat[[c(x1,x2,x3)]] o landsat[[x1:x3]] ya fue empleada anteriormente para graficar los mapas landsatRGB, landsatFCC y se verÔ posteriormente en los respectivos recortes (landsatcrop), cómoda y practica ya que el orden de enlace puede ser ascendente o descendente teniendo almacenado un solo bloque con todas las variables y no estas independientes y por aparte.

landsatsub1 <- subset(landsat, 1:3)
landsatsub2 <- landsat[[1:3]]
nlayers(landsat)
[1] 11
nlayers(landsatsub2)
[1] 3

Tambien puede ser empleada para sobreescribir un objeto y reemplazar las bandas almacenadas en un bloque, eliminando aquellas que no nos interesan.

landsat <- subset(landsat, 1:7)
names(landsat)
[1] "LC08_044034_20170614_B1" "LC08_044034_20170614_B2" "LC08_044034_20170614_B3" "LC08_044034_20170614_B4" "LC08_044034_20170614_B5"
[6] "LC08_044034_20170614_B6" "LC08_044034_20170614_B7"

Renombrandolas, permitirÔ una facil identificación de estas.

names(landsat) <- c('ultra-blue','blue','green','red','NIR','SWIR1','SWIR2')
names(landsat)
[1] "ultra.blue" "blue"       "green"      "red"        "NIR"        "SWIR1"      "SWIR2"     

2.7. Recortes espaciales de imƔgenes

El caso mÔs común es obtener una imagen satelital de gran tamaño, que abarca el Ôrea de interés y mucho mÔs, por lo que se requiere delimitar únicamente la zona donde se desean conocer las características, evitando así ralentizar los procesos.

(extent) requiere dimensionar previamente el Ôrea de estudio, y empleando coordenadas cartesianas puede ser delimitado un rectÔngulo (Ymin, Ymax, Xmin y Xmax), posteriormente la función (crop) permitirÔ almacenar en un nuevo objeto el recorte realizado entre el raster y el recuadro recientemente creado.

extent(landsat)
class      : Extent 
xmin       : 594090 
xmax       : 639000 
ymin       : 4190190 
ymax       : 4227540 
e <-extent(624384, 635752, 4200047, 4210939)
landsatcrop <- crop(landsat,e)
extent(landsatcrop)
class      : Extent 
xmin       : 624390 
xmax       : 635760 
ymin       : 4200060 
ymax       : 4210950 

2.8. Composición de Colores Verdadero y Falso para las ImÔgenes Recortadas

A continuación se presentan procesos de ploteo con el detalle de las imÔgenes recortadas.

landsatRGBcrop <- landsatcrop[[c(4,3,2)]]
plotRGB(landsatRGBcrop, axes =TRUE, stretch = "lin", main = "Landsat True Color Composite-croped")

landsatFCCcrop_veg <- landsatcrop[[c(5,4,3)]]
plotRGB(landsatFCCcrop_veg, axes =TRUE, stretch = "lin", main = "Landsat False Color Composite-croped-vegetation")

2.9. Almacenamiento de Datos en el Disco

Los diferentes archivos en los que se puede almacenar la información procesada, tienen características que deben ser claras.

Archivos ā€œ.tifā€ archivos ā€œ.grdā€
Los archivos GeoTiff son de uso comĆŗn, conservan el orden de almacenamiento de las capas del raster, pero sus nombres se pierden en este tipo de formato Los archivos de esta caracterĆ­stica, permiten almacenar el nombre de las capas, sin embargo, no muchos programas logran leerlos.
x1 <- writeRaster(landsatcrop, filename="data/rs/cropped-landsat.tif", overwrite=TRUE)


x2 <- writeRaster(landsatcrop, filename="data/rs/cropped-landsat.grd", overwrite=TRUE)

2.10. Relación entre bandas

Encontrar la proporcionalidad de la relación entre algunas bandas permite identificar cuales pueden ser usadas sin perder información, como sucede con la banda 1 y 2 de Landsat 8, mediante la función (pairs), la comparación es llevada a cabo, así mismo, puede darse el caso de las bandas 4 y 5, que generan una nube de puntos cercana al eje Y, donde la reflectancia vegetal es muy marcada, mostrando una baja correlación.

pairs(landsatcrop[[1:2]], main = "Ultra-Blue Vs Blue")

pairs(landsatcrop[[4:5]], main = "Red Vs NIR")

2.11. Valores de los Pixeles

Teniendo un archivo de polígonos que identifiquen fÔcilmente las diferentes Ôreas de explotación agrícola, forestal, urbana entre otras, se pueden extraer coordenadas o puntos mediante la función (spsample), escogiendo la cantidad de puntos y la forma de extracción de estos.

#Esta primera linea, carga el archivo RDS que contiene los polígonos de clasificación de suelo.
lc_samples <- readRDS('data/rs/samples.rds')
#spsample, genera para este caso, 300 puntos de forma regular sobre los polĆ­gonos almacenados en el objeto lc_samples
ptsamp <- spsample(lc_samples, 300, type = 'regular')
#Se agreaga la clase de cobertura de suelo a los puntos extraidos. 
ptsamp$class <- over(ptsamp, lc_samples)$class
#Extraer los valores de radiancia en el raster "landsat"de los puntos
df <- extract(landsat, ptsamp)
head(df)
     ultra.blue      blue     green       red       NIR     SWIR1     SWIR2
[1,]  0.1412655 0.1346294 0.1439546 0.1778288 0.3226725 0.3632045 0.2504567
[2,]  0.1400077 0.1235477 0.1126394 0.1163911 0.1883034 0.2332810 0.1958719
[3,]  0.1360607 0.1181911 0.1034443 0.1039431 0.1727325 0.2174066 0.1815155
[4,]  0.1382511 0.1212055 0.1052660 0.1049841 0.1787830 0.2135247 0.1745975
[5,]  0.1370583 0.1364945 0.1499184 0.2007297 0.3393711 0.3296990 0.1946141
[6,]  0.1383378 0.1363426 0.1537352 0.2059128 0.3326266 0.3665659 0.2251053

2.12. Perfiles espectrales

Una de las herramientas mas importantes es el perfil espectral de las bandas contenidas en un objeto, elaborada con los pixeles extraƭdos anteriormente, donde estƔn representadas algunas caracterƭsticas de la superficie.

ms <- aggregate(df, list(ptsamp$class), mean)
rownames(ms) <- ms[,1]
#La primera columna, tendrĆ” los nombres de las clases
ms <- ms[,-1]
ms
mycolor <- c('darkred','yellow','burlywood','cyan','blue')
ms <- as.matrix(ms)
plot(0, ylim=c(0,0.6), xlim=c(1,7),type='n',xlab="Bands",ylab="Reflectance")
for (i in 1:nrow(ms)){
  lines(ms[i,],type="l", lwd=3,lty=1,col=mycolor[i])
}
title(main="Spectral Profile from Landsat", font.main=2)
legend("topleft",rownames(ms),
       cex=0.8, col=mycolor,lty=1,lwd=3,bty="n")

Practica 3: Operaciones matemƔticas bƔsicas

ƍndices de vegetación

vi <- function(img,k,i){
  bk <- img[[k]]
  bi <- img[[i]]
  vi <- (bk-bi)/(bk+bi)
  return(vi)
}
ndvi <- vi(landsat, 5, 4)
plot(ndvi, col = rev(terrain.colors(10)), main="Landsat-NDVI")

Otra alternativa:

vi2 <- function(x,y){
  (x-y)/(x+y)
}
ndvi2 <- overlay(landsat[[5]], landsat[[4]], fun=vi2)
plot(ndvi2, col=rev(terrain.colors(10)), main="Landsat-NDVI")

Histograma de NDVI

hist(ndvi,
     main = "Distribution of NDVI values",
     xlab = "NDVI",
     ylab= "Frequency",
     col = "green",
     xlim = c(-0.5, 1),
     breaks = 30,
     xaxt = 'n')
axis(side=1, at = seq(-0.5,1, 0.05), labels = seq(-0.5,1, 0.05))

ƍndice de Agua de Diferencia Normalizada

wi <- function(img,k,i){
  bk <- img[[k]]
  bi <- img[[i]]
  wi <- (bk-bi)/(bk+bi)
  return(vi)
}
ndwi <- vi(landsat, 3, 5)
plot(ndwi, col = rev(topo.colors(10)), main="NDWI-Mc Feeters (2006)")

Histograma de NDWI - Mc Feeters (2006)

hist(ndwi,
     main = "Distribution of NDWI values",
     xlab = "NDWI",
     ylab= "Frequency",
     col = "wheat",
     xlim = c(-0.5, 1),
     breaks = 30,
     xaxt = 'n')
axis(side=1, at = seq(-0.5,1, 0.05), labels = seq(-0.5,1, 0.05))

ndwifunc <- function(img, k, i){
  bcrk <- img[[k]]
  bcri <- img[[i]]
  ndwifunc <- (bcrk - bcri) / (bcrk + bcri)
  return(ndwifunc)
}

mndwi <- ndwifunc(landsat, 3, 6)
plot(mndwi, col = rev(topo.colors(10)), main = "M-NDWI - Xu (2006)")

Histograma de MNDWI - Xu (2006)

hist(mndwi,
     main = "Distribution of M-NDWI values",
     xlab = "MNDWI",
     ylab= "Frequency",
     col = "yellow",
     xlim = c(-0.5, 1),
     breaks = 30,
     xaxt = 'n')
axis(side=1, at = seq(-0.5,1, 0.05), labels = seq(-0.5,1, 0.05))

ƍndice de Diferencias Normalizadas de Ɓrea Construida

(Empleando la imagen recortada)

ndbifunc <- function(img, k, i){
  bcrk <- img[[k]]
  bcri <- img[[i]]
  ndbifunc <- (bcrk - bcri) / (bcri + bcrk)
  return(ndbifunc)
}

ndbi <- ndbifunc(landsatcrop, 6, 5)
plot(ndbi, col = rev(topo.colors(10)), main = "NDBI")

Histograma de NDBI

hist(ndbi,
     main = "Distribution of NDBI values",
     xlab = "NDBI",
     ylab= "Frequency",
     col = "blue",
     xlim = c(-0.5, 1),
     breaks = 30,
     xaxt = 'n')
axis(side=1, at = seq(-0.5,1, 0.05), labels = seq(-0.5,1, 0.05))

Umbralización

veg <- reclassify(ndvi, cbind(-Inf,0.4,NA))
plot(veg, main='Vegetation')

land <- reclassify(ndvi, c(-Inf, 0.25, NA,  0.25, 0.3, 1,  0.3, Inf, NA))
plot(land, main = 'Open Areas')

plotRGB(landsatRGB, r=1, g=2, b=3, axes=TRUE, stretch="lin", main="Landsat False Color Composite")
plot(land, add=TRUE, legend=FALSE)

vegc <- reclassify(ndvi, c(-Inf,0.25,1, 0.25,0.3,2, 0.3,0.4,3, 0.4,0.5,4, 0.5,Inf, 5))
plot(vegc,col = rev(terrain.colors(4)), main = 'NDVI based thresholding')

La respuesta del perfil espectral, muestra que para las 7 bandas, la reflectancia del agua es la unica que se encuentra entre 0 y 0.2 como valores mÔximos aproximados, así que acotamos el subconjunto de reclasificación en esta franja.

water <- reclassify(ndwi, cbind(-Inf, 0.1, NA))
#Solo es necesario acotar el limite inferior, ya que todo sobre este valor (0.1) se muestra con clasificación de interés
colors <- colorRampPalette(c("wheat","cyan","blue"))
plot(water,col = colors(10), main = 'water')

Y para el caso de Ɣreas construidas, el nivel de reflectancia muestra el mismo comportamiento sobre los valores de 0.1 o 0.15 hasta 0.2

urbanreclass <- reclassify(ndbi, cbind(-Inf, 0.0, NA))
colors <- colorRampPalette(c("wheat","grey","black"))
plot(urbanreclass,col = colors(50), main = 'Urban zones')

Bajando el lĆ­mite superior hasta 0, se logran evidenciar incluso, lo que parecen ser vias que rodean los cuerpos de agua.

AnƔlisis de componentes Principales

set.seed(1)
sr <- sampleRandom(landsat, 10000)
plot(sr[,c(4,5)], main = "NIR-Red plot")

pca <- prcomp(sr, scale = TRUE)
pca
Standard deviations (1, .., p=7):
[1] 2.20737373 1.17428246 0.73633573 0.42388639 0.12500714 0.09389890 0.04741454

Rotation (n x k) = (7 x 7):
                 PC1           PC2         PC3         PC4         PC5        PC6         PC7
ultra.blue 0.3662344 -0.4524940727 -0.15415991  0.52595682 -0.21276947  0.1337062  0.54550658
blue       0.4125282 -0.3336052918 -0.15782033  0.09509849 -0.21537031  0.0836529 -0.79447772
green      0.4372284 -0.1056685710 -0.26457625 -0.20443752  0.49716419 -0.6553920  0.09570391
red        0.4333279 -0.0003693985 -0.05074204 -0.67055674  0.01651199  0.5619375  0.20966468
NIR        0.1762472  0.6825385571 -0.58744574  0.32192859  0.09371265  0.2090330 -0.04325163
SWIR1      0.3815340  0.4119308383  0.29523433 -0.08811728 -0.65630314 -0.3878540  0.09301774
SWIR2      0.3743258  0.1929889704  0.66820379  0.33388919  0.47051465  0.1889099 -0.08709876
screeplot(pca)

pci <- predict(landsat, pca, index = 1:2)
plot(pci[[1]])

par(mfrow=c(1,2))
pc2 <- reclassify(pci[[2]], c(-Inf,0,1,0,Inf,NA))
plotRGB(landsatFCC_veg, r = 1, g = 2, b = 3, axes = TRUE, stretch = "lin", main = "Landsat False Color Composite")
plotRGB(landsatFCC_veg, r = 1, g = 2, b = 3, axes = TRUE, stretch = "lin", main = "Landsat False Color Composite")
plot(pc2, legend = FALSE, add = TRUE)

LS0tDQp0aXRsZTogJ1ByYWN0aWNhcyAxIGEgMyAtIFBlcmNlcGNpw7NuIFJlbW90YSAgJw0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KYGBge3J9DQpsaWJyYXJ5KGtuaXRyKQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KIyAqKkNvbnRlbmlkbyoqDQoNCjEuIFByYWN0aWNhIDE6IERlc2NhcmdhIGRlIGRhdG9zIGLDoXNpY29zIHBhcmEgYW7DoWxpc2lzDQoyLiBQcmFjdGljYSAyOiBFeHBsb3JhY2nDs24gZGUgaW3DoWdlbmVzICANCjIuMS4gQ2FyZ2FuZG8gaW3DoWdlbmVzIGEgUiAgDQoyLjIuIEluZm9ybWFjacOzbiBjb250ZW5pZGEgZW4gbGFzIHZhcmlhYmxlcyAgDQoyLjMuIE90cmEgYWx0ZXJuYXRpdmEgcGFyYSBjYXJnYXIgaW3DoWdlbmVzICANCjIuNC4gQmFuZGEgw7puaWNhIHkgbWFwYXMgY29tcHVlc3RvcyAgDQoyLjUuIENvbXBvc2ljacOzbiBkZSBpbcOhZ2VuZXMgZW4gY29sb3IgdmVyZGFkZXJvIHkgZmFsc28gIA0KMi42LiBTdWJjb25qdW50b3MgZGUgYXJjaGl2b3MgIA0KMi43LiBSZWNvcnRlcyBlc3BhY2lhbGVzIGRlIGltw6FnZW5lcyAgICANCjIuOC4gQ29tcG9zaWNpw7NuIGRlIGNvbG9yIHZlcmRhZGVybyB5IGZhbHNvIHBhcmEgaW3DoWdlbmVzIHJlY29ydGFkYXMgICANCjIuOS4gQWxtYWNlbmFtaWVudG8gZGUgZGF0b3MgZW4gZGlzY28gICANCjIuMTAuIFJlbGFjacOzbiBlbnRyZSBiYW5kYXMgIA0KMi4xMS4gVmFsb3JlcyBkZSBwaXhlbGVzICANCjIuMTIuIFBlcmZpbGVzIGVzcGVjdHJhbGVzICANCjMuIFByYWN0aWNhIDM6IE9wZXJhY2lvbmVzIG1hdGVtw6F0aWNhcyBiw6FzaWNhcyAgICAgDQozLjEuIMONbmRpY2UgZGUgdmVnZXRhY2nDs24gKk5EVkkqICANCjMuMS4xLiBIaXN0b2dyYW1hIGRlICpORFZJKiAgDQozLjIuIMONbmRpY2UgZGUgYWd1YSBkZSBkaWZlcmVuY2lhIG5vcm1hbGl6YWRhICpORFdJKiAgDQozLjIuMS4gTWMgRmVldGVycyAoMjAwNikgIA0KMy4yLjIuIEhpc3RvZ3JhbWEgZGUgKk5EV0kqIOKAkyBNYyBGZWV0ZXJzICgyMDA2KSAgDQozLjIuMy4gKk0tTkRXSSogWHUgKDIwMDYpICANCjMuMi40LiBIaXN0b2dyYW1hIGRlICpNTkRXSSog4oCTIFh1ICgyMDA2KSAgDQozLjMuIMONbmRpY2UgZGUgZGlmZXJlbmNpYSBub3JtYWxpemFkYSBkZSDDoXJlYSBjb25zdHJ1aWRhICpOREJJKiAgDQozLjMuMS4gSGlzdG9ncmFtYSBkZSAqTkRCSSogIA0KMy40LiBVbWJyYWxpemFjacOzbiAgIA0KMy41LiBBbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgIA0KDQoNCiAgDQojICoqMS4gUHJhY3RpY2EgMTogRGVzY2FyZ2EgZGUgZGF0b3MgYsOhc2ljb3MgcGFyYSBhbsOhbGlzaXMqKiAgDQogIA0KTG9zIGRhdG9zIHB1ZWRlbiBzZXIgZGVzY2FyZ2Fkb3MsIHkgZ3VhcmRhZG9zIGRpcmVjdGFtZW50ZSBlbiBsYSBkaXJlY2Npw7NuIGRlIHByZWZlcmVuY2lhIHBhcmEgc3UgcG9zdGVyaW9yIGFuw6FsaXNpcywgbWVkaWFudGUgbGEgY3JlYWNpw7NuIGRlIHVuIGRpcmVjdG9yaW8gKihkaXIuY3JlYXRlKSogeSBwb3N0ZXJpb3JtZW50ZSBkZXNjb21wcmltaWRvcyAqKHVuemlwKSouICANCg0KYGBge3J9DQpkaXIuY3JlYXRlKCdkYXRhJywgc2hvd1dhcm5pbmdzID0gRkFMU0UpDQppZiAoIWZpbGUuZXhpc3RzKCdkYXRhL3JzL3NhbXBsZXMucmRzJykpIHsNCiAgICBkb3dubG9hZC5maWxlKCdodHRwczovL2Jpb2dlby51Y2RhdmlzLmVkdS9kYXRhL3JzcGF0aWFsL3JzZGF0YS56aXAnLCBkZXN0ID0gJ2RhdGEvcnNkYXRhLnppcCcpDQogICAgdW56aXAoJ2RhdGEvcnNkYXRhLnppcCcsIGV4ZGlyPSdkYXRhJykNCn0NCmBgYA0KDQojICoqMi4gUHJhY3RpY2EgMjogRXhwbG9yYWNpw7NuIGRlIGltw6FnZW5lcyoqDQoNCiMjICoqMi4xLiBDYXJnYW5kbyBpbcOhZ2VuZXMgYSBSKioNCg0KTGFzIGltw6FnZW5lcyBwcmV2aWFtZW50ZSBkZXNjYXJnYWRhcyB5IGRlc2NvbXByaW1pZGFzIGVuIGxhIGNhcnBldGEgKi9kYXRhL3JzLyosIHNlIGNhcmdhbiBlbXBsZWFuZG8gbcO6bHRpcGxlcyBvcGNpb25lcywgbWVkaWFudGUgbGFzIGxpYnJlcsOtYXMgKnJhc3RlciogeSAqc3AqLCBzZXLDoW4gc3ViaWRhcyBsYXMgcHJpbWVyYXMgNyBiYW5kYXMgZGUgZm9ybWEgaW5kaXZpZHVhbCwgbGFzIGN1YWxlcyBzZSBlbmN1ZW50cmFuIGlkZW50aWZpY2FkYXMgYSBjb250aW51YWNpw7NuLiAgDQogIA0KfEJhbmRhIExhbmRzYXQgOCB8IENvZGlmaWNhY2nDs24gfA0KfDotLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLTp8DQp8IEF6dWwgfCBiMiB8DQp8IFZlcmRlIHwgYjMgfA0KfCBSb2phIHwgYjQgfA0KfCBOSVIgfCBiNSB8DQp8IFNXSVIxIHwgYjYgfA0KfCBTV0lSIDIgfCBiNyB8DQoNCg0KYGBge3J9DQpsaWJyYXJ5KHNwKQ0KbGlicmFyeSAocmFzdGVyKQ0KDQpiMiA8LSByYXN0ZXIoJ2RhdGEvcnMvTEMwOF8wNDQwMzRfMjAxNzA2MTRfQjIudGlmJykNCmIzIDwtIHJhc3RlcignZGF0YS9ycy9MQzA4XzA0NDAzNF8yMDE3MDYxNF9CMy50aWYnKQ0KYjQgPC0gcmFzdGVyKCdkYXRhL3JzL0xDMDhfMDQ0MDM0XzIwMTcwNjE0X0I0LnRpZicpDQpiNSA8LSByYXN0ZXIoJ2RhdGEvcnMvTEMwOF8wNDQwMzRfMjAxNzA2MTRfQjUudGlmJykNCmI2IDwtIHJhc3RlcignZGF0YS9ycy9MQzA4XzA0NDAzNF8yMDE3MDYxNF9CNi50aWYnKQ0KYjcgPC0gcmFzdGVyKCdkYXRhL3JzL0xDMDhfMDQ0MDM0XzIwMTcwNjE0X0I3LnRpZicpDQpgYGANCg0KIyMgKioyLjIuIEluZm9ybWFjacOzbiBjb250ZW5pZGEgZW4gbGFzIHZhcmlhYmxlcyoqDQoNCkRlYmlkbyBhIHF1ZSBsYXMgYmFuZGFzIGhhbiBzaWRvIGFsbWFjZW5hZGFzIGNvbW8gb2JqZXRvcyAoeWEgcXVlIFIgZW1wbGVhIHVuIHNpc3RlbWEgZGUgcHJvZ3JhbWFjacOzbiBlbmZvY2FkbyBlbiBvYmpldG9zKSwgc2UgcHVlZGVuIHZpc3VhbGl6YXIgbGEgaW5mb3JtYWNpw7NuIGNvbnRlbmlkYSBkZW50cm8gZGUgZXN0YXMgdmFyaWFibGVzIHJlY2llbnRlbWVudGUgY3JlYWRhcy4gIA0KICANCiMjIyAqKkJhbmRhIDIqKg0KDQpgYGB7cn0NCmIyDQpjcnMoYjIpDQpuY2VsbChiMikNCmRpbShiMikNCnJlcyhiMikNCm5sYXllcnMoYjIpDQpgYGANCg0KIyMjICoqQmFuZGEgMyoqDQoNCmBgYHtyfQ0KYjMNCmNycyhiMykNCm5jZWxsKGIzKQ0KZGltKGIzKQ0KcmVzKGIzKQ0KbmxheWVycyhiMykNCmBgYA0KDQojIyMgKipCYW5kYSA0KioNCg0KYGBge3J9DQpiNA0KY3JzKGI0KQ0KbmNlbGwoYjQpDQpkaW0oYjQpDQpyZXMoYjQpDQpubGF5ZXJzKGI0KQ0KYGBgDQoNCg0KIyMjICoqQmFuZGEgNSoqDQoNCmBgYHtyfQ0KYjUNCmNycyhiNSkNCm5jZWxsKGI1KQ0KZGltKGI1KQ0KcmVzKGI1KQ0KbmxheWVycyhiNSkNCmBgYA0KDQpDb21wYXJhY2nDs24gZW50cmUgbGFzIGRpZmVyZW50ZXMgYmFuZGFzLCB1biB2YWxvciBkZSAqVFJVRSogcGVybWl0aXLDoSBsYSBpbnRlcmFjY2nDs24gY29ycmVjdGEgZW50cmUgZWxsYXMgcG9zdGVyaW9ybWVudGUuDQpgYGB7cn0NCmNvbXBhcmVSYXN0ZXIoYjIsYjMsYjQsYjUpDQpgYGANCg0KIyMgKioyLjMuIE90cmEgYWx0ZXJuYXRpdmEgcGFyYSBjYXJnYXIgbGFzIGltw6FnZW5lcyoqDQogIA0KQWwgY3JlYXIgdW4gb2JqZXRvIHF1ZSBjb250ZW5nYSBlbCBsaXN0YWRvIGRlIG5vbWJyZXMgcXVlIHNlcsOhbiBjYXJnYWRvcywgcHVlZGUgZW1wbGVhcnNlIHVuICooc3RhY2spKiBkb25kZSBlc3TDqW4gYWxtYWNlbmFkYXMgbGFzIGJhbmRhcyByZXF1ZXJpZGFzLiAgDQogIA0KDQpgYGB7cn0NCmZpbGVuYW1lcyA8LSBwYXN0ZTAoJ2RhdGEvcnMvTEMwOF8wNDQwMzRfMjAxNzA2MTRfQicsIDE6MTEsICIudGlmIikNCmxhbmRzYXQgPC0gc3RhY2soZmlsZW5hbWVzKQ0KbGFuZHNhdA0KYGBgDQoNCg0KIyMgKioyLjQuIEJhbmRhIMO6bmljYSB5IG1hcGFzIGNvbXB1ZXN0b3MqKg0KICANCk1lZGlhbnRlIHVuYSB2YXJpYWNpw7NuIGRlbCBjw7NkaWdvLCBkb25kZSBsYSBmdW5jacOzbiAqKHN0cmV0Y2gpKiBxdWUgZGEgZnJhbmphcyBtw61uaW1hcyB5IG3DoXhpbWFzIGVuIGZvcm1hIGRlIGN1YW50aWxlcyB5IGVzdGlyYSBlbiBlc3RlIGludGVydmFsbyBkZSBzYWxpZGEgbG9zIHZhbG9yZXMgb3JpZ2luYWxlcywgc2UgbG9ncmEgdW5hIG1lam9yIHJlc29sdWNpw7NuIGRlIGxhIGltYWdlbi4gIA0KDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMSwyKSkNCnBsb3QoYjIsIG1haW4gPSAiQmx1ZSIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KcGxvdChzdHJldGNoKGIyLCBtaW5xPTAuNSwgbWF4cT0wLjkpLCBtYWluID0gIkJsdWUiLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCmBgYA0KDQpgYGB7cn0NCnBsb3Qoc3RyZXRjaChiMywgbWlucT0wLjUsIG1heHE9MC45KSwgbWFpbiA9ICJHcmVlbiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KcGxvdChzdHJldGNoKGI0LCBtaW5xPTAuNSwgbWF4cT0wLjkpLCBtYWluID0gIlJlZCIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KcGxvdChzdHJldGNoKGI1LCBtaW5xPTAuNSwgbWF4cT0wLjkpLCBtYWluID0gIk5JUiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KYGBgDQoNCg0KIyMgKioyLjUuIENvbXBvc2ljacOzbiBkZSBpbcOhZ2VuZXMgZW4gY29sb3IgdmVyZGFkZXJvIFkgZmFsc28qKg0KICANCkRlYmlkbyBhIHF1ZSBsYXMgaW3DoWdlbmVzIHByb3llY3RhZGFzIGVuIGJsYW5jbyB5IG5lZ3JvIGRlIGxhcyBiYW5kYXMgaW5kZXBlbmRpZW50ZXMgbm8gYXJyb2phbiBtdWNoYSBpbmZvcm1hY2nDs24gYWNlcmNhIGRlIGxhIGNvYmVydHVyYSBkZWwgc3VlbG8sIGVzIHBvc2libGUgZW1wbGVhciB1bmEgY29tYmluYWNpw7NuIGRlIGJhbmRhcyBxdWUgc2VhIHByb2Nlc2FkYSBwb3IgZWwgcHJvZ3JhbWEsIGNvbiBlbCBmaW4gZGUgZ2VuZXJhciB1bmEgaW1hZ2VuIFJHQiAqKFJlZC1HcmVlbi1CbHVlKSosIGxvIHF1ZSBwZXJtaXRpcsOhIGVuIHByaW5jaXBpbyBlbXBsZWFyIGxhcyBiYW5kYXMgNCwgMyB5IDIgcmVzcGVjdGl2YW1lbnRlIHBhcmEgZWxhYm9yYXIgdW5hIGltYWdlbiBlbiBjb2xvciB2ZXJkYWRlcm8gZGUgbGEgc3VwZXJmaWNpZSBkZWwgdGVycmVuby4gIA0KDQpgYGB7cn0NCmxhbmRzYXRSR0IgPC0gbGFuZHNhdFtbYyg0LDMsMildXQ0KcGxvdFJHQihsYW5kc2F0UkdCLCBheGVzID1UUlVFLCBzdHJldGNoID0gImxpbiIsIG1haW4gPSAiTGFuZHNhdCBUcnVlIENvbG9yIENvbXBvc2l0ZSIpDQpgYGANCg0KICANClNpbiBlbWJhcmdvLCByZWVtcGxhemFuZG8gbGFzIGJhbmRhcyBhbnRlcmlvcm1lbnRlIG1lbmNpb25hZGFzLCBwb3Igb3RyYXMgZGlmZXJlbnRlcywgeSBnZW5lcmFuZG8gY29tYmluYWNpb25lcyBhZGVjdWFkYXMsIGVzIHBvc2libGUgaWRlbnRpZmljYXIgaW5mb3JtYWNpw7NuIHF1ZSBlbiBjb2xvciB2ZXJkYWRlcm8gbm8gc29uIGbDoWNpbG1lbnRlIGNsYXNpZmljYWJsZXMsIGVzIGFsbMOtIGRvbmRlIGxhcyBpbcOhZ2VuZXMgZW4gY29sb3IgZmFsc28sIGRvbmRlIGxhcyBiYW5kYXMgbm8gY29ycmVzcG9uZGVuIGNvbiBlbCBzaXN0ZW1hIFJHQiwgcHJlc2VudGFuIHVuYSBncmFuIHV0aWxpZGFkLiAgDQpEZWJpZG8gYSBxdWUgbGEgYmFuZGEgTklSIHByZXNlbnRhIHVuYSBncmFuIHJlZmxlY3RhbmNpYSBkZSBsYSB2ZWdldGFjacOzbiwgZXN0YSBlcyByZXByZXNlbnRhZGEgcG9yIGNvbG9yYWNpb25lcyByb2phcyBpbnRlbnNhcy4gIA0KYGBge3J9DQpsYW5kc2F0RkNDX3ZlZyA8LSBsYW5kc2F0W1tjKDUsNCwzKV1dDQpwbG90UkdCKGxhbmRzYXRGQ0NfdmVnLCBheGVzID1UUlVFLCBzdHJldGNoID0gImxpbiIsIG1haW4gPSAiTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUtVmVnZXRhdGlvbiIpDQpgYGANCiAgDQpVbmEgb3BjacOzbiBhZGljaW9uYWwgZXMgY2xhc2lmaWNhciBsYXMgem9uYXMgcXVlIHRpZW5lbiByZWZsZWN0YW5jaWFzIGluZnJhcnJvamFzIGRlIG9uZGEgY29ydGEgbWF5b3JlcywgcXVlIHBvciBsbyBnZW5lcmFsIHNvbiDDoXJlYXMgdXJiYW5hcywgY29uIGNvYmVydHVyYXMgZGUgY29uY3JldG8uDQoNCmBgYHtyfQ0KbGFuZHNhdEZDQ191cmIgPC0gbGFuZHNhdFtbYyg3LDYsNCldXQ0KcGxvdFJHQihsYW5kc2F0RkNDX3VyYiwgYXhlcyA9VFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlLVVyYmFuIFpvbmVzIikNCmBgYA0KICANCkRlIGlndWFsIGZvcm1hLCBsYSB2ZWdldGFjacOzbiB5IGxhcyB6b25hcyBlbiBwcmVwYXJhY2nDs24geSBleHBsb3RhY2nDs24gYWdyw61jb2xhIHB1ZWRlbiByZXN1bHRhciBpZGVudGlmaWNhZGFzIHVzYW5kbyBsYXMgYmFuZGFzIFNXSVIxLCBOSVIgeSBhenVsLg0KICANCmBgYHtyfQ0KbGFuZHNhdEZDQ19hZ3IgPC0gbGFuZHNhdFtbYyg2LDUsMildXQ0KcGxvdFJHQihsYW5kc2F0RkNDX2FnciwgYXhlcyA9VFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlLUFncmljdWx0dXJlIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGFuZHNhdEZDQ192ZWdoZWFsdCA8LSBsYW5kc2F0W1tjKDUsNiwyKV1dDQpwbG90UkdCKGxhbmRzYXRGQ0NfdmVnaGVhbHQsIGF4ZXMgPVRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IEZhbHNlIENvbG9yIENvbXBvc2l0ZS0NCkhlYWx0aHkgVmVnLiIpDQpgYGANCg0KDQojIyAqKjIuNi4gU3ViY29uanVudG9zIGRlIGFyY2hpdm9zKioNCiAgDQpMYSBmdW5jacOzbiAqKHN1YnNldCkqIHkgc3UgdmFyaWFjacOzbiAqbGFuZHNhdFtbYyh4MSx4Mix4MyldXSogbyAqbGFuZHNhdFtbeDE6eDNdXSogeWEgZnVlIGVtcGxlYWRhIGFudGVyaW9ybWVudGUgcGFyYSBncmFmaWNhciBsb3MgbWFwYXMgKmxhbmRzYXRSR0IqLCAqbGFuZHNhdEZDQyogeSBzZSB2ZXLDoSBwb3N0ZXJpb3JtZW50ZSBlbiBsb3MgcmVzcGVjdGl2b3MgcmVjb3J0ZXMgKihsYW5kc2F0Y3JvcCkqLCBjw7Ntb2RhIHkgcHJhY3RpY2EgeWEgcXVlIGVsIG9yZGVuIGRlIGVubGFjZSBwdWVkZSBzZXIgYXNjZW5kZW50ZSBvIGRlc2NlbmRlbnRlIHRlbmllbmRvIGFsbWFjZW5hZG8gdW4gc29sbyBibG9xdWUgY29uIHRvZGFzIGxhcyB2YXJpYWJsZXMgeSBubyBlc3RhcyBpbmRlcGVuZGllbnRlcyB5IHBvciBhcGFydGUuICAgDQoNCmBgYHtyfQ0KbGFuZHNhdHN1YjEgPC0gc3Vic2V0KGxhbmRzYXQsIDE6MykNCmBgYA0KDQoNCmBgYHtyfQ0KbGFuZHNhdHN1YjIgPC0gbGFuZHNhdFtbMTozXV0NCmBgYA0KDQpgYGB7cn0NCm5sYXllcnMobGFuZHNhdCkNCmBgYA0KDQpgYGB7cn0NCm5sYXllcnMobGFuZHNhdHN1YjIpDQpgYGANCg0KVGFtYmllbiBwdWVkZSBzZXIgZW1wbGVhZGEgcGFyYSBzb2JyZWVzY3JpYmlyIHVuIG9iamV0byB5IHJlZW1wbGF6YXIgbGFzIGJhbmRhcyBhbG1hY2VuYWRhcyBlbiB1biBibG9xdWUsIGVsaW1pbmFuZG8gYXF1ZWxsYXMgcXVlIG5vIG5vcyBpbnRlcmVzYW4uDQoNCmBgYHtyfQ0KbGFuZHNhdCA8LSBzdWJzZXQobGFuZHNhdCwgMTo3KQ0KYGBgDQoNCmBgYHtyfQ0KbmFtZXMobGFuZHNhdCkNCmBgYA0KDQpSZW5vbWJyYW5kb2xhcywgcGVybWl0aXLDoSB1bmEgZmFjaWwgaWRlbnRpZmljYWNpw7NuIGRlIGVzdGFzLg0KDQpgYGB7cn0NCm5hbWVzKGxhbmRzYXQpIDwtIGMoJ3VsdHJhLWJsdWUnLCdibHVlJywnZ3JlZW4nLCdyZWQnLCdOSVInLCdTV0lSMScsJ1NXSVIyJykNCm5hbWVzKGxhbmRzYXQpDQpgYGANCg0KIyMgKioyLjcuIFJlY29ydGVzIGVzcGFjaWFsZXMgZGUgaW3DoWdlbmVzKioNCg0KRWwgY2FzbyBtw6FzIGNvbcO6biBlcyBvYnRlbmVyIHVuYSBpbWFnZW4gc2F0ZWxpdGFsIGRlIGdyYW4gdGFtYcOxbywgcXVlIGFiYXJjYSBlbCDDoXJlYSBkZSBpbnRlcsOpcyB5IG11Y2hvIG3DoXMsIHBvciBsbyBxdWUgc2UgcmVxdWllcmUgZGVsaW1pdGFyIMO6bmljYW1lbnRlIGxhIHpvbmEgZG9uZGUgc2UgZGVzZWFuIGNvbm9jZXIgbGFzIGNhcmFjdGVyw61zdGljYXMsIGV2aXRhbmRvIGFzw60gcmFsZW50aXphciBsb3MgcHJvY2Vzb3MuICANCg0KKihleHRlbnQpKiByZXF1aWVyZSBkaW1lbnNpb25hciBwcmV2aWFtZW50ZSBlbCDDoXJlYSBkZSBlc3R1ZGlvLCB5IGVtcGxlYW5kbyBjb29yZGVuYWRhcyBjYXJ0ZXNpYW5hcyBwdWVkZSBzZXIgZGVsaW1pdGFkbyB1biByZWN0w6FuZ3VsbyAgKihZbWluLCBZbWF4LCBYbWluIHkgWG1heCkqLCBwb3N0ZXJpb3JtZW50ZSBsYSBmdW5jacOzbiAqKGNyb3ApKiBwZXJtaXRpcsOhIGFsbWFjZW5hciBlbiB1biBudWV2byBvYmpldG8gZWwgcmVjb3J0ZSByZWFsaXphZG8gZW50cmUgZWwgcmFzdGVyIHkgZWwgcmVjdWFkcm8gcmVjaWVudGVtZW50ZSBjcmVhZG8uDQoNCg0KYGBge3J9DQpleHRlbnQobGFuZHNhdCkNCmBgYA0KDQpgYGB7cn0NCmUgPC1leHRlbnQoNjI0Mzg0LCA2MzU3NTIsIDQyMDAwNDcsIDQyMTA5MzkpDQpsYW5kc2F0Y3JvcCA8LSBjcm9wKGxhbmRzYXQsZSkNCmV4dGVudChsYW5kc2F0Y3JvcCkNCmBgYA0KDQojIyAqKjIuOC4gQ29tcG9zaWNpw7NuIGRlIENvbG9yZXMgVmVyZGFkZXJvIHkgRmFsc28gcGFyYSBsYXMgSW3DoWdlbmVzIFJlY29ydGFkYXMqKg0KICANCkEgY29udGludWFjacOzbiBzZSBwcmVzZW50YW4gcHJvY2Vzb3MgZGUgcGxvdGVvIGNvbiBlbCBkZXRhbGxlIGRlIGxhcyBpbcOhZ2VuZXMgcmVjb3J0YWRhcy4gICANCg0KYGBge3J9DQpsYW5kc2F0UkdCY3JvcCA8LSBsYW5kc2F0Y3JvcFtbYyg0LDMsMildXQ0KcGxvdFJHQihsYW5kc2F0UkdCY3JvcCwgYXhlcyA9VFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgVHJ1ZSBDb2xvciBDb21wb3NpdGUtY3JvcGVkIikNCmBgYA0KDQpgYGB7cn0NCmxhbmRzYXRGQ0Njcm9wX3ZlZyA8LSBsYW5kc2F0Y3JvcFtbYyg1LDQsMyldXQ0KcGxvdFJHQihsYW5kc2F0RkNDY3JvcF92ZWcsIGF4ZXMgPVRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IEZhbHNlIENvbG9yIENvbXBvc2l0ZS1jcm9wZWQtdmVnZXRhdGlvbiIpDQpgYGANCg0KIyMgKioyLjkuIEFsbWFjZW5hbWllbnRvIGRlIERhdG9zIGVuIGVsIERpc2NvKioNCg0KTG9zIGRpZmVyZW50ZXMgYXJjaGl2b3MgZW4gbG9zIHF1ZSBzZSBwdWVkZSBhbG1hY2VuYXIgbGEgaW5mb3JtYWNpw7NuIHByb2Nlc2FkYSwgdGllbmVuIGNhcmFjdGVyw61zdGljYXMgcXVlIGRlYmVuIHNlciBjbGFyYXMuDQoNCnxBcmNoaXZvcyAqIi50aWYiKiB8IGFyY2hpdm9zICoiLmdyZCIqIHwNCnw6LS0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS06fA0KfCBMb3MgYXJjaGl2b3MgR2VvVGlmZiBzb24gZGUgdXNvIGNvbcO6biwgY29uc2VydmFuIGVsIG9yZGVuIGRlIGFsbWFjZW5hbWllbnRvIGRlIGxhcyBjYXBhcyBkZWwgcmFzdGVyLCBwZXJvIHN1cyBub21icmVzIHNlIHBpZXJkZW4gZW4gZXN0ZSB0aXBvIGRlIGZvcm1hdG98IExvcyBhcmNoaXZvcyBkZSBlc3RhIGNhcmFjdGVyw61zdGljYSwgcGVybWl0ZW4gYWxtYWNlbmFyIGVsIG5vbWJyZSBkZSBsYXMgY2FwYXMsIHNpbiBlbWJhcmdvLCBubyBtdWNob3MgcHJvZ3JhbWFzIGxvZ3JhbiBsZWVybG9zLiB8DQoNCg0KYGBge3J9DQp4MSA8LSB3cml0ZVJhc3RlcihsYW5kc2F0Y3JvcCwgZmlsZW5hbWU9ImRhdGEvcnMvY3JvcHBlZC1sYW5kc2F0LnRpZiIsIG92ZXJ3cml0ZT1UUlVFKQ0KDQoNCngyIDwtIHdyaXRlUmFzdGVyKGxhbmRzYXRjcm9wLCBmaWxlbmFtZT0iZGF0YS9ycy9jcm9wcGVkLWxhbmRzYXQuZ3JkIiwgb3ZlcndyaXRlPVRSVUUpDQoNCmBgYA0KDQojIyAqKjIuMTAuIFJlbGFjacOzbiBlbnRyZSBiYW5kYXMqKg0KICANCg0KRW5jb250cmFyIGxhIHByb3BvcmNpb25hbGlkYWQgZGUgbGEgcmVsYWNpw7NuIGVudHJlIGFsZ3VuYXMgYmFuZGFzIHBlcm1pdGUgaWRlbnRpZmljYXIgY3VhbGVzIHB1ZWRlbiBzZXIgdXNhZGFzIHNpbiBwZXJkZXIgaW5mb3JtYWNpw7NuLCBjb21vIHN1Y2VkZSBjb24gbGEgYmFuZGEgMSB5IDIgZGUgTGFuZHNhdCA4LCBtZWRpYW50ZSBsYSBmdW5jacOzbiAqKHBhaXJzKSosIGxhIGNvbXBhcmFjacOzbiBlcyBsbGV2YWRhIGEgY2FibywgYXPDrSBtaXNtbywgcHVlZGUgZGFyc2UgZWwgY2FzbyBkZSBsYXMgYmFuZGFzIDQgeSA1LCBxdWUgZ2VuZXJhbiB1bmEgbnViZSBkZSBwdW50b3MgY2VyY2FuYSBhbCBlamUgWSwgZG9uZGUgbGEgcmVmbGVjdGFuY2lhIHZlZ2V0YWwgZXMgbXV5IG1hcmNhZGEsIG1vc3RyYW5kbyB1bmEgYmFqYSBjb3JyZWxhY2nDs24uDQogIA0KICANCg0KYGBge3J9DQpwYWlycyhsYW5kc2F0Y3JvcFtbMToyXV0sIG1haW4gPSAiVWx0cmEtQmx1ZSBWcyBCbHVlIikNCmBgYA0KDQpgYGB7cn0NCnBhaXJzKGxhbmRzYXRjcm9wW1s0OjVdXSwgbWFpbiA9ICJSZWQgVnMgTklSIikNCmBgYA0KDQoNCiMjICoqMi4xMS4gVmFsb3JlcyBkZSBsb3MgUGl4ZWxlcyoqDQoNClRlbmllbmRvIHVuIGFyY2hpdm8gZGUgcG9sw61nb25vcyBxdWUgaWRlbnRpZmlxdWVuIGbDoWNpbG1lbnRlIGxhcyBkaWZlcmVudGVzIMOhcmVhcyBkZSBleHBsb3RhY2nDs24gYWdyw61jb2xhLCBmb3Jlc3RhbCwgdXJiYW5hIGVudHJlIG90cmFzLCBzZSBwdWVkZW4gZXh0cmFlciBjb29yZGVuYWRhcyBvIHB1bnRvcyBtZWRpYW50ZSBsYSBmdW5jacOzbiAqKHNwc2FtcGxlKSosIGVzY29naWVuZG8gbGEgY2FudGlkYWQgZGUgcHVudG9zIHkgbGEgZm9ybWEgZGUgZXh0cmFjY2nDs24gZGUgZXN0b3MuICAgDQoNCmBgYHtyfQ0KI0VzdGEgcHJpbWVyYSBsaW5lYSwgY2FyZ2EgZWwgYXJjaGl2byBSRFMgcXVlIGNvbnRpZW5lIGxvcyBwb2zDrWdvbm9zIGRlIGNsYXNpZmljYWNpw7NuIGRlIHN1ZWxvLg0KbGNfc2FtcGxlcyA8LSByZWFkUkRTKCdkYXRhL3JzL3NhbXBsZXMucmRzJykNCiNzcHNhbXBsZSwgZ2VuZXJhIHBhcmEgZXN0ZSBjYXNvLCAzMDAgcHVudG9zIGRlIGZvcm1hIHJlZ3VsYXIgc29icmUgbG9zIHBvbMOtZ29ub3MgYWxtYWNlbmFkb3MgZW4gZWwgb2JqZXRvIGxjX3NhbXBsZXMNCnB0c2FtcCA8LSBzcHNhbXBsZShsY19zYW1wbGVzLCAzMDAsIHR5cGUgPSAncmVndWxhcicpDQojU2UgYWdyZWFnYSBsYSBjbGFzZSBkZSBjb2JlcnR1cmEgZGUgc3VlbG8gYSBsb3MgcHVudG9zIGV4dHJhaWRvcy4gDQpwdHNhbXAkY2xhc3MgPC0gb3ZlcihwdHNhbXAsIGxjX3NhbXBsZXMpJGNsYXNzDQojRXh0cmFlciBsb3MgdmFsb3JlcyBkZSByYWRpYW5jaWEgZW4gZWwgcmFzdGVyICJsYW5kc2F0ImRlIGxvcyBwdW50b3MNCmRmIDwtIGV4dHJhY3QobGFuZHNhdCwgcHRzYW1wKQ0KaGVhZChkZikNCmBgYA0KDQojIyAqKjIuMTIuIFBlcmZpbGVzIGVzcGVjdHJhbGVzKioNCg0KVW5hIGRlIGxhcyBoZXJyYW1pZW50YXMgbWFzIGltcG9ydGFudGVzIGVzIGVsIHBlcmZpbCBlc3BlY3RyYWwgZGUgbGFzIGJhbmRhcyBjb250ZW5pZGFzIGVuIHVuIG9iamV0bywgZWxhYm9yYWRhIGNvbiBsb3MgcGl4ZWxlcyBleHRyYcOtZG9zIGFudGVyaW9ybWVudGUsIGRvbmRlIGVzdMOhbiByZXByZXNlbnRhZGFzIGFsZ3VuYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llLg0KDQoNCmBgYHtyfQ0KbXMgPC0gYWdncmVnYXRlKGRmLCBsaXN0KHB0c2FtcCRjbGFzcyksIG1lYW4pDQpgYGANCg0KDQpgYGB7cn0NCnJvd25hbWVzKG1zKSA8LSBtc1ssMV0NCiNMYSBwcmltZXJhIGNvbHVtbmEsIHRlbmRyw6EgbG9zIG5vbWJyZXMgZGUgbGFzIGNsYXNlcw0KbXMgPC0gbXNbLC0xXQ0KbXMNCmBgYA0KDQoNCmBgYHtyfQ0KbXljb2xvciA8LSBjKCdkYXJrcmVkJywneWVsbG93JywnYnVybHl3b29kJywnY3lhbicsJ2JsdWUnKQ0KbXMgPC0gYXMubWF0cml4KG1zKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdCgwLCB5bGltPWMoMCwwLjYpLCB4bGltPWMoMSw3KSx0eXBlPSduJyx4bGFiPSJCYW5kcyIseWxhYj0iUmVmbGVjdGFuY2UiKQ0KZm9yIChpIGluIDE6bnJvdyhtcykpew0KICBsaW5lcyhtc1tpLF0sdHlwZT0ibCIsIGx3ZD0zLGx0eT0xLGNvbD1teWNvbG9yW2ldKQ0KfQ0KdGl0bGUobWFpbj0iU3BlY3RyYWwgUHJvZmlsZSBmcm9tIExhbmRzYXQiLCBmb250Lm1haW49MikNCmxlZ2VuZCgidG9wbGVmdCIscm93bmFtZXMobXMpLA0KICAgICAgIGNleD0wLjgsIGNvbD1teWNvbG9yLGx0eT0xLGx3ZD0zLGJ0eT0ibiIpDQpgYGANCg0KIyAqKlByYWN0aWNhIDM6IE9wZXJhY2lvbmVzIG1hdGVtw6F0aWNhcyBiw6FzaWNhcyoqDQoNCg0KIyMgKirDjW5kaWNlcyBkZSB2ZWdldGFjacOzbioqDQoNCg0KYGBge3J9DQp2aSA8LSBmdW5jdGlvbihpbWcsayxpKXsNCiAgYmsgPC0gaW1nW1trXV0NCiAgYmkgPC0gaW1nW1tpXV0NCiAgdmkgPC0gKGJrLWJpKS8oYmsrYmkpDQogIHJldHVybih2aSkNCn0NCm5kdmkgPC0gdmkobGFuZHNhdCwgNSwgNCkNCnBsb3QobmR2aSwgY29sID0gcmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW49IkxhbmRzYXQtTkRWSSIpDQpgYGANCg0KDQpPdHJhIGFsdGVybmF0aXZhOg0KDQpgYGB7cn0NCnZpMiA8LSBmdW5jdGlvbih4LHkpew0KICAoeC15KS8oeCt5KQ0KfQ0KbmR2aTIgPC0gb3ZlcmxheShsYW5kc2F0W1s1XV0sIGxhbmRzYXRbWzRdXSwgZnVuPXZpMikNCnBsb3QobmR2aTIsIGNvbD1yZXYodGVycmFpbi5jb2xvcnMoMTApKSwgbWFpbj0iTGFuZHNhdC1ORFZJIikNCmBgYA0KDQoNCiMjIyAqKkhpc3RvZ3JhbWEgZGUgTkRWSSoqDQoNCg0KYGBge3J9DQpoaXN0KG5kdmksDQogICAgIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIE5EVkkgdmFsdWVzIiwNCiAgICAgeGxhYiA9ICJORFZJIiwNCiAgICAgeWxhYj0gIkZyZXF1ZW5jeSIsDQogICAgIGNvbCA9ICJncmVlbiIsDQogICAgIHhsaW0gPSBjKC0wLjUsIDEpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dCA9ICduJykNCmF4aXMoc2lkZT0xLCBhdCA9IHNlcSgtMC41LDEsIDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLCAwLjA1KSkNCmBgYA0KDQojIyAqKsONbmRpY2UgZGUgQWd1YSBkZSBEaWZlcmVuY2lhIE5vcm1hbGl6YWRhKioNCg0KDQpgYGB7cn0NCndpIDwtIGZ1bmN0aW9uKGltZyxrLGkpew0KICBiayA8LSBpbWdbW2tdXQ0KICBiaSA8LSBpbWdbW2ldXQ0KICB3aSA8LSAoYmstYmkpLyhiaytiaSkNCiAgcmV0dXJuKHZpKQ0KfQ0KbmR3aSA8LSB2aShsYW5kc2F0LCAzLCA1KQ0KcGxvdChuZHdpLCBjb2wgPSByZXYodG9wby5jb2xvcnMoMTApKSwgbWFpbj0iTkRXSS1NYyBGZWV0ZXJzICgyMDA2KSIpDQpgYGANCg0KIyMjICoqSGlzdG9ncmFtYSBkZSBORFdJIC0gTWMgRmVldGVycyAoMjAwNikqKg0KDQoNCmBgYHtyfQ0KaGlzdChuZHdpLA0KICAgICBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBORFdJIHZhbHVlcyIsDQogICAgIHhsYWIgPSAiTkRXSSIsDQogICAgIHlsYWI9ICJGcmVxdWVuY3kiLA0KICAgICBjb2wgPSAid2hlYXQiLA0KICAgICB4bGltID0gYygtMC41LCAxKSwNCiAgICAgYnJlYWtzID0gMzAsDQogICAgIHhheHQgPSAnbicpDQpheGlzKHNpZGU9MSwgYXQgPSBzZXEoLTAuNSwxLCAwLjA1KSwgbGFiZWxzID0gc2VxKC0wLjUsMSwgMC4wNSkpDQpgYGANCg0KYGBge3J9DQpuZHdpZnVuYyA8LSBmdW5jdGlvbihpbWcsIGssIGkpew0KICBiY3JrIDwtIGltZ1tba11dDQogIGJjcmkgPC0gaW1nW1tpXV0NCiAgbmR3aWZ1bmMgPC0gKGJjcmsgLSBiY3JpKSAvIChiY3JrICsgYmNyaSkNCiAgcmV0dXJuKG5kd2lmdW5jKQ0KfQ0KDQptbmR3aSA8LSBuZHdpZnVuYyhsYW5kc2F0LCAzLCA2KQ0KcGxvdChtbmR3aSwgY29sID0gcmV2KHRvcG8uY29sb3JzKDEwKSksIG1haW4gPSAiTS1ORFdJIC0gWHUgKDIwMDYpIikNCmBgYA0KDQoNCiMjIyAqKkhpc3RvZ3JhbWEgZGUgTU5EV0kgLSBYdSAoMjAwNikqKg0KDQpgYGB7cn0NCmhpc3QobW5kd2ksDQogICAgIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIE0tTkRXSSB2YWx1ZXMiLA0KICAgICB4bGFiID0gIk1ORFdJIiwNCiAgICAgeWxhYj0gIkZyZXF1ZW5jeSIsDQogICAgIGNvbCA9ICJ5ZWxsb3ciLA0KICAgICB4bGltID0gYygtMC41LCAxKSwNCiAgICAgYnJlYWtzID0gMzAsDQogICAgIHhheHQgPSAnbicpDQpheGlzKHNpZGU9MSwgYXQgPSBzZXEoLTAuNSwxLCAwLjA1KSwgbGFiZWxzID0gc2VxKC0wLjUsMSwgMC4wNSkpDQpgYGANCg0KIyMgKirDjW5kaWNlIGRlIERpZmVyZW5jaWFzIE5vcm1hbGl6YWRhcyBkZSDDgXJlYSBDb25zdHJ1aWRhKioNCg0KKihFbXBsZWFuZG8gbGEgaW1hZ2VuIHJlY29ydGFkYSkqDQpgYGB7cn0NCm5kYmlmdW5jIDwtIGZ1bmN0aW9uKGltZywgaywgaSl7DQogIGJjcmsgPC0gaW1nW1trXV0NCiAgYmNyaSA8LSBpbWdbW2ldXQ0KICBuZGJpZnVuYyA8LSAoYmNyayAtIGJjcmkpIC8gKGJjcmkgKyBiY3JrKQ0KICByZXR1cm4obmRiaWZ1bmMpDQp9DQoNCm5kYmkgPC0gbmRiaWZ1bmMobGFuZHNhdGNyb3AsIDYsIDUpDQpwbG90KG5kYmksIGNvbCA9IHJldih0b3BvLmNvbG9ycygxMCkpLCBtYWluID0gIk5EQkkiKQ0KYGBgDQoNCiMjIyAqKkhpc3RvZ3JhbWEgZGUgTkRCSSoqDQoNCmBgYHtyfQ0KaGlzdChuZGJpLA0KICAgICBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBOREJJIHZhbHVlcyIsDQogICAgIHhsYWIgPSAiTkRCSSIsDQogICAgIHlsYWI9ICJGcmVxdWVuY3kiLA0KICAgICBjb2wgPSAiYmx1ZSIsDQogICAgIHhsaW0gPSBjKC0wLjUsIDEpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dCA9ICduJykNCmF4aXMoc2lkZT0xLCBhdCA9IHNlcSgtMC41LDEsIDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLCAwLjA1KSkNCmBgYA0KDQoNCiMjICoqVW1icmFsaXphY2nDs24qKg0KDQpgYGB7cn0NCnZlZyA8LSByZWNsYXNzaWZ5KG5kdmksIGNiaW5kKC1JbmYsMC40LE5BKSkNCnBsb3QodmVnLCBtYWluPSdWZWdldGF0aW9uJykNCmBgYA0KDQpgYGB7cn0NCmxhbmQgPC0gcmVjbGFzc2lmeShuZHZpLCBjKC1JbmYsIDAuMjUsIE5BLCAgMC4yNSwgMC4zLCAxLCAgMC4zLCBJbmYsIE5BKSkNCnBsb3QobGFuZCwgbWFpbiA9ICdPcGVuIEFyZWFzJykNCmBgYA0KDQpgYGB7cn0NCnBsb3RSR0IobGFuZHNhdFJHQiwgcj0xLCBnPTIsIGI9MywgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IEZhbHNlIENvbG9yIENvbXBvc2l0ZSIpDQpwbG90KGxhbmQsIGFkZD1UUlVFLCBsZWdlbmQ9RkFMU0UpDQpgYGANCg0KDQpgYGB7cn0NCnZlZ2MgPC0gcmVjbGFzc2lmeShuZHZpLCBjKC1JbmYsMC4yNSwxLCAwLjI1LDAuMywyLCAwLjMsMC40LDMsIDAuNCwwLjUsNCwgMC41LEluZiwgNSkpDQpwbG90KHZlZ2MsY29sID0gcmV2KHRlcnJhaW4uY29sb3JzKDQpKSwgbWFpbiA9ICdORFZJIGJhc2VkIHRocmVzaG9sZGluZycpDQpgYGANCg0KTGEgcmVzcHVlc3RhIGRlbCBwZXJmaWwgZXNwZWN0cmFsLCBtdWVzdHJhIHF1ZSBwYXJhIGxhcyA3IGJhbmRhcywgbGEgcmVmbGVjdGFuY2lhIGRlbCBhZ3VhIGVzIGxhIHVuaWNhIHF1ZSBzZSBlbmN1ZW50cmEgZW50cmUgMCB5IDAuMiBjb21vIHZhbG9yZXMgbcOheGltb3MgYXByb3hpbWFkb3MsIGFzw60gcXVlIGFjb3RhbW9zIGVsIHN1YmNvbmp1bnRvIGRlIHJlY2xhc2lmaWNhY2nDs24gZW4gZXN0YSBmcmFuamEuDQoNCmBgYHtyfQ0Kd2F0ZXIgPC0gcmVjbGFzc2lmeShuZHdpLCBjYmluZCgtSW5mLCAwLjEsIE5BKSkNCiNTb2xvIGVzIG5lY2VzYXJpbyBhY290YXIgZWwgbGltaXRlIGluZmVyaW9yLCB5YSBxdWUgdG9kbyBzb2JyZSBlc3RlIHZhbG9yICgwLjEpIHNlIG11ZXN0cmEgY29uIGNsYXNpZmljYWNpw7NuIGRlIGludGVyw6lzDQpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJ3aGVhdCIsImN5YW4iLCJibHVlIikpDQpwbG90KHdhdGVyLGNvbCA9IGNvbG9ycygxMCksIG1haW4gPSAnd2F0ZXInKQ0KYGBgDQoNClkgcGFyYSBlbCBjYXNvIGRlIMOhcmVhcyBjb25zdHJ1aWRhcywgZWwgbml2ZWwgZGUgcmVmbGVjdGFuY2lhIG11ZXN0cmEgZWwgbWlzbW8gY29tcG9ydGFtaWVudG8gc29icmUgbG9zIHZhbG9yZXMgZGUgMC4xIG8gMC4xNSBoYXN0YSAwLjINCg0KYGBge3J9DQp1cmJhbnJlY2xhc3MgPC0gcmVjbGFzc2lmeShuZGJpLCBjYmluZCgtSW5mLCAwLjAsIE5BKSkNCmNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKGMoIndoZWF0IiwiZ3JleSIsImJsYWNrIikpDQpwbG90KHVyYmFucmVjbGFzcyxjb2wgPSBjb2xvcnMoNTApLCBtYWluID0gJ1VyYmFuIHpvbmVzJykNCmBgYA0KQmFqYW5kbyBlbCBsw61taXRlIHN1cGVyaW9yIGhhc3RhIDAsIHNlIGxvZ3JhbiBldmlkZW5jaWFyIGluY2x1c28sIGxvIHF1ZSBwYXJlY2VuIHNlciB2aWFzIHF1ZSByb2RlYW4gbG9zIGN1ZXJwb3MgZGUgYWd1YS4NCg0KIyMgKipBbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgUHJpbmNpcGFsZXMqKg0KDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCnNyIDwtIHNhbXBsZVJhbmRvbShsYW5kc2F0LCAxMDAwMCkNCnBsb3Qoc3JbLGMoNCw1KV0sIG1haW4gPSAiTklSLVJlZCBwbG90IikNCmBgYA0KDQoNCmBgYHtyfQ0KcGNhIDwtIHByY29tcChzciwgc2NhbGUgPSBUUlVFKQ0KcGNhDQpzY3JlZXBsb3QocGNhKQ0KYGBgDQoNCmBgYHtyfQ0KcGNpIDwtIHByZWRpY3QobGFuZHNhdCwgcGNhLCBpbmRleCA9IDE6MikNCnBsb3QocGNpW1sxXV0pDQpgYGANCg0KYGBge3J9DQpwYXIobWZyb3c9YygxLDIpKQ0KcGMyIDwtIHJlY2xhc3NpZnkocGNpW1syXV0sIGMoLUluZiwwLDEsMCxJbmYsTkEpKQ0KcGxvdFJHQihsYW5kc2F0RkNDX3ZlZywgciA9IDEsIGcgPSAyLCBiID0gMywgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IEZhbHNlIENvbG9yIENvbXBvc2l0ZSIpDQpwbG90UkdCKGxhbmRzYXRGQ0NfdmVnLCByID0gMSwgZyA9IDIsIGIgPSAzLCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlIikNCnBsb3QocGMyLCBsZWdlbmQgPSBGQUxTRSwgYWRkID0gVFJVRSkNCmBgYA0KDQoNCg0K