INTRODUCCIÓN

Las imágenes aéreas de alta resolución admiten una amplia gama de campos de aplicación como la estimación de diferentes parámetros como la estimación de biomasa a partir de las coberturas vegetales que se puedan determinar, contenido de agua, entre otras características que pueden ser extraídas a partir de la información que brindan las bandas según el sensor que registre las fotografías.

Hay dos tipos de clasificación de imágenes, las cuales son: clasificación supervisada y clasificación no supervisada, las cuales permiten explorar los diferentes parámetros según las clases que se definan, mediante la identificación visual por parte del investigador, de los pixeles de una o de varias de las bandas de una imagen raster para que posteriormente se pueda dar categorías y realizar la clasificación de acuerdo a las probabilidades de cada clase, por lo que para este trabajo se realizó el análisis preliminar para obtener una clasificación de coberturas en un lote de cacao ubicado en Granada, Meta, logrando discriminar entre las diferentes coberturas que se presentaron en el lote seleccionado.

DATOS Y MÉTODOS

El área de estudio corresponde a un lote de cacao (Theobroma cacao) ubicado en la finca “El triunfo” en el municipio de Granada (Meta), el lote tiene un área de 9.5 ha aproximadamente, con coordenadas 73.788178 W; 3.622491 N.

Las fotografías fueron tomadas con el uso de una cámara Canon S110, la cual tiene un sensor CMOS de alta sensibilidad de 12.1 Mpx para la toma de las bandas RGB, y una cámara S100 de 12 Mpx, con una modificación la cual se le extrajo el filtro justo delante del sensor CMOS que impide el paso de la radiación IR para la captura de esta banda del espectro, las imágenes tuvieron una resolución radiométrica de 8 bits (256 ND). Las cámaras fueron transportadas en un drone hexacóptero DJI F550, con previa configuración de la misión de vuelo para tomar las fotografías a una altura de 80 metros sobre el terreno, con un overlap y sidelap del 60%. Con las imágenes se realizó el procesamiento para la obtención del ortomosaico y georreferenciación mediante el uso del software Photoscan 1.3 (Agisoft, Devices) obteniendo una única imagen con una resolución espacial de 3 cm píxel-1.

Llamado de las carpetas
Armado de archivos raster, imágenes que cuentan con una resolucion espacial de 3cm

## Banda Azul
banda_azul <- raster("CAPABLUEproy.tif")
banda_azul
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : C:/Users/BLACK SQUARE/Desktop/BLACKSQUARE_FOLDER/ANDRES/1_Personal/MAESTRIA/PERCEPCION_REMOTA/CACAO_PR/CAPABLUEproy.tif 
names      : CAPABLUEproy 
values     : 0, 255  (min, max)
## Banda Verde
banda_verde <- raster("CAPAGREENproy.tif")
banda_verde
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : C:/Users/BLACK SQUARE/Desktop/BLACKSQUARE_FOLDER/ANDRES/1_Personal/MAESTRIA/PERCEPCION_REMOTA/CACAO_PR/CAPAGREENproy.tif 
names      : CAPAGREENproy 
values     : 0, 255  (min, max)
## Banda Roja
banda_roja <- raster("CAPAREDproy.tif")
banda_roja
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : C:/Users/BLACK SQUARE/Desktop/BLACKSQUARE_FOLDER/ANDRES/1_Personal/MAESTRIA/PERCEPCION_REMOTA/CACAO_PR/CAPAREDproy.tif 
names      : CAPAREDproy 
values     : 0, 255  (min, max)
## Banda IR
banda_NIR <- raster("CAPAIRproy.tif")
banda_NIR
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : C:/Users/BLACK SQUARE/Desktop/BLACKSQUARE_FOLDER/ANDRES/1_Personal/MAESTRIA/PERCEPCION_REMOTA/CACAO_PR/CAPAIRproy.tif 
names      : CAPAIRproy 
values     : 16, 255  (min, max)
### Se genera el Stack de bandas con las 4 que se va a trabajar
lote_cacao <- stack(banda_azul, banda_verde, banda_roja, banda_NIR)
lote_cacao
class      : RasterStack 
dimensions : 1184, 1642, 1944128, 4  (nrow, ncol, ncell, nlayers)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
names      : CAPABLUEproy, CAPAGREENproy, CAPAREDproy, CAPAIRproy 
min values :            0,             0,           0,         16 
max values :          255,           255,         255,        255 
# Cambio de nombre de las bandas espectrales
names(lote_cacao) <- paste("Banda ", 1:4,sep = "")
lote_cacao
class      : RasterStack 
dimensions : 1184, 1642, 1944128, 4  (nrow, ncol, ncell, nlayers)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
names      : Banda.1, Banda.2, Banda.3, Banda.4 
min values :       0,       0,       0,      16 
max values :     255,     255,     255,     255 
plot(lote_cacao)

hist(lote_cacao, main="Plot histograma por banda espectral", maxpixels=ncell(lote_cacao), 
ylab='Frecuencia', xlab = 'Valor de luminosidad')

par(mfrow = c(2,2))

plot(lote_cacao[[1]], main = "Blue", col = gray(0:100 / 100), axes=TRUE, ylab='Norte', xlab = 'Este')
plot(lote_cacao[[2]], main = "Green", col = gray(0:100 / 100), axes=TRUE, ylab='Norte', xlab = 'Este')
plot(lote_cacao[[3]], main = "Red", col = gray(0:100 / 100), axes=TRUE, ylab='Norte', xlab = 'Este')
plot(lote_cacao[[4]], main = "NIR", col = gray(0:100 / 100), axes=TRUE, ylab='Norte', xlab = 'Este')

Generación de las estadisticas unibanda para la imágen raster
## Media
print("Media")
[1] "Media"
cellStats(lote_cacao, 'mean')
 Banda.1  Banda.2  Banda.3  Banda.4 
111.9130 155.7412 151.5823 178.8796 
## Desviación estandar
print("Desviación estandar")
[1] "Desviación estandar"
cellStats(lote_cacao, 'sd')
 Banda.1  Banda.2  Banda.3  Banda.4 
52.07704 43.76693 55.08276 31.68573 
## Varianza
print("Varianza")
[1] "Varianza"
cellStats(lote_cacao, 'var')
 Banda.1  Banda.2  Banda.3  Banda.4 
2712.018 1915.544 3034.110 1003.986 
## Mínimos
print("Mínimos")
[1] "Mínimos"
cellStats(lote_cacao, 'min')
[1]  0  0  0 16
## Máximos
print("Máximos")
[1] "Máximos"
cellStats(lote_cacao, 'max')
[1] 255 255 255 255
## Asimetría
print("Asimetría")
[1] "Asimetría"
cellStats(lote_cacao, 'skew')
   Banda.1    Banda.2    Banda.3    Banda.4 
 0.1507564 -0.4598528 -0.2629572 -1.7663963 
## Curtosis
print("Curtosis")
[1] "Curtosis"
cellStats(lote_cacao, 'kurtosis')
 Banda.1  Banda.2  Banda.3  Banda.4 
2.191182 2.835664 2.059116 7.104256 
Generación de las estadisticas multibanda
azul <- raster("CAPABLUE.tif")
verde <- raster("CAPAGREEN.tif")
rojo <- raster("CAPARED.tif")
nir <- raster("CAPAIR.tif")
bandas <- stack(azul, verde, rojo, nir)
## Covarianza
print("Covarianza presente entre las bandas")
[1] "Covarianza presente entre las bandas"
layerStats(bandas, 'cov')
$covariance
           CAPABLUE CAPAGREEN   CAPARED    CAPAIR
CAPABLUE  2709.7552 2032.5574 2605.8503  376.2718
CAPAGREEN 2032.5574 1914.6969 1998.5990  619.5462
CAPARED   2605.8503 1998.5990 3033.0292  719.0478
CAPAIR     376.2718  619.5462  719.0478 1004.6319

$mean
 CAPABLUE CAPAGREEN   CAPARED    CAPAIR 
 111.8997  155.7298  151.5623  178.8694 
## Coeficiente de Correlación
print("Coeficiente de Correlación presente entre las bandas")
[1] "Coeficiente de Correlación presente entre las bandas"
layerStats(bandas, 'pearson')
$`pearson correlation coefficient`
           CAPABLUE CAPAGREEN   CAPARED    CAPAIR
CAPABLUE  1.0000000 0.8923347 0.9089629 0.2280516
CAPAGREEN 0.8923347 1.0000000 0.8293490 0.4467044
CAPARED   0.9089629 0.8293490 1.0000000 0.4119229
CAPAIR    0.2280516 0.4467044 0.4119229 1.0000000

$mean
 CAPABLUE CAPAGREEN   CAPARED    CAPAIR 
 111.8997  155.7298  151.5623  178.8694 
Generación de las salidas de la imágen a color
plotRGB(lote_cacao,r=3, g=2, b=1 , main="Lote de cacao: Composición de color verdadero", maxpixels=ncell(lote_cacao),  axes=TRUE, ylab="NORTE", xlab= "ESTE")


plotRGB(lote_cacao,r=3, g=2, b=1 , main="Lote de cacao: Composición de color verdadero (hist)",stretch="hist",  axes=TRUE, ylab="NORTE", xlab= "ESTE")


plotRGB(lote_cacao,r=3, g=2, b=1 , main="Lote de cacao: Composición de color verdadero (lin)",stretch="lin",  axes=TRUE, ylab="NORTE", xlab= "ESTE")

Generación de las salidas de la imágen en falso color



# En este momento se oprocede a realizar la composicion en falso color realizando el cambio de la banda azul por la banda NIR
plotRGB(lote_cacao,r=3, g=2, b=4 , main="Lote de cacao: Composición en falso color (hist)",stretch="hist",  axes=TRUE, ylab="NORTE", xlab= "ESTE")


plotRGB(lote_cacao,r=3, g=2, b=4 , main="Lote de cacao: Composición en falso color (lin)",stretch="lin",  axes=TRUE, ylab="NORTE", xlab= "ESTE")

Generación de la relacion que se presenta entre las bandas
pairs(lote_cacao[[1:4]], main = "Lote de cacao: Relacion entre las bandas")

Realización del cálculo de índices de vegetación (NDVI)

El uso de índices de vegetación


NDVI <- function(img, k, i) {
    bk <- img[[k]]
    bi <- img[[i]]
    NDVI <- ((bk - bi) / (bk + bi ))
return(NDVI)
}
ndvi_indice <- NDVI  (lote_cacao,4,3)
ndvi_indice
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : layer 
values     : -0.755102, 1  (min, max)
plot(ndvi_indice, col = rev(terrain.colors(10)), main = "Lote cacao: Indice de Vegetacion - NDVI", axes=TRUE, ylab="NORTE", xlab= "ESTE")

     
vegNDVI <- reclassify(ndvi_indice, cbind(-Inf, 0.0, NA))

plot(vegNDVI, main="Lote cacao: Indice de Vegetacion NDVI - Discriminación de zonas de NO vegetación", axes=TRUE, ylab="NORTE", xlab= "ESTE")


vegNDVIthres <- reclassify(vegNDVI, c(-Inf,0.2,0, 0.2,0.3,1, 0.3,0.4,2, 0.4,0.5,3, 0.5, Inf, 4))

plot(vegNDVIthres,col = rev(terrain.colors(4)), main = 'NDVI based thresholding')

En cuanto al índice de vegetación de diferencia normalizado (NDVI), se puede evidenciar que se puede destacar con mayor claridad la frondosidad y vigorosidad de la vegetación que se presenta en el área seleccionada, presentándose, en este caso, con un color verde más intenso, ya que, al momento de incluir explícitamente el factor del suelo, éste se puede discriminar con mayor facilidad, mostrando en la imagen con colores claros, mientras que las zonas donde se presentan construcciones, carreteras y suelo desnudo o algún porcentaje de deforestación, se pueden denotar con color rosado, pixeles que se presentan con valores bajos o menores a 0, según este índice de vegetación.

CLASIFICACIONES

Procedimiento para la clasificación supervisada y no supervisada

Para la clasificación de la imagen se tuvo en cuenta el tamaño y peso de ésta al momento del procesamiento, por lo que se intentó realizar la clasificación con la totalidad de la imágen (9,5 ha), pero no fue posible, por lo que fue necesario reducir el tamaño y así realiazr los procesos. Se difinió el área que tuviera el mayor número de clases posible, en el caso de la clasificación supervisada, se definieron las coberturas que se encontraban en la zona de estudio. Una vez calibrados los algoritmos a utilizar se realiza la clasificacion de la imagen y se evalúa la calidad de la clasificación realizada, se verifica los resultados. Este proceso se repite y luego se calcula el valor promedio de los índices de validación, mediante el uso del algoritmo Random Forest (RF), se permitió un aprendizaje para clasificación, mediante la construcción de árboles de decisión durante la etapa de entrenamiento, que permitirán la salida de la clasificación

CLASIFICACION NO SUPERVISADA

Se asume que no se tiene conocimiento del área de estudio, los resultados que genera el algoritmo con esta clasificación, teniendo en cuenta de los valores de los pixeles, formaran agrupaciones según la información de las bandas del raster. Los resultados de la clasificación no supervisada generaron 8 clases, destacándose las diferencias que hay entre lo que es vegetación y lo que corresponde a suelo y otras estructuras y construcciones.

# convertir el raster a matriz de vector
nr <- getValues(bandas)
str(nr)
 num [1:1938660, 1:4] 41 49 61 72 53 46 52 72 71 66 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:4] "CAPABLUE" "CAPAGREEN" "CAPARED" "CAPAIR"
# Aquí se realizó el análisis mediante el uso del algoritmo de kmeans
# localizaciones al azar 
set.seed(99)
#Se quiso crear 8 grupos, permitir 500 iteraciones, comenzar con 5 conjuntos aleatorios usando el Método "Lloyd"
kmncluster <- kmeans(na.omit(nr), centers = 8, iter.max = 500, nstart = 5, algorithm="Lloyd")

str(kmncluster)
List of 9
 $ cluster     : int [1:1938660] 8 8 5 5 5 8 8 5 5 5 ...
 $ centers     : num [1:8, 1:4] 93.5 197.8 38.7 121.4 71.8 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:8] "1" "2" "3" "4" ...
  .. ..$ : chr [1:4] "CAPABLUE" "CAPAGREEN" "CAPARED" "CAPAIR"
 $ totss       : num 1.68e+10
 $ withinss    : num [1:8] 1.91e+08 2.17e+08 1.77e+08 1.09e+08 2.99e+08 ...
 $ tot.withinss: num 1.86e+09
 $ betweenss   : num 1.49e+10
 $ size        : int [1:8] 84986 251599 96246 74902 400299 453995 356321 220312
 $ iter        : int 126
 $ ifault      : NULL
 - attr(*, "class")= chr "kmeans"
knr <- setValues(bandas, kmncluster$cluster)
knr
class      : RasterBrick 
dimensions : 1185, 1636, 1938660, 4  (nrow, ncol, ncell, nlayers)
resolution : 2.709071e-07, 2.709072e-07  (x, y)
extent     : -73.78741, -73.78697, 3.623138, 3.623459  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer.1, layer.2, layer.3, layer.4 
min values :       1,       1,       1,       1 
max values :       8,       8,       8,       8 
# Se define el color para cada uno de los 8 custeres definidos
#mycolor <- c("#ff0000", "#daa520","#0000ff","#00ff00","#cbbeb5",
#"#c3ff5b", "#ff7373", "#808080")

mycolor <- c("#808080","#ff0000","#0000ff","#00ff00","#cbbeb5",
"#c3ff5b", "#ff7373","#fef65b")
par(mfrow = c(1,1))
plot(bandas, col = rev(terrain.colors(8)), main = "Lote cacao", axes=TRUE, ylab="NORTE", xlab= "ESTE")

nc <- plot(knr, main = 'LOTE CACAO: CLASIFICACIÓN NO SUPERVISADA', col = mycolor )

library(raster)
library(randomForest)
library(caret)
library(ggplot2)
library(lattice)

CLASIFICACION SUPERVISADA

Dentro de los algoritmos que se desarrollan dentro del software Rstudio®, está el de Random Forest (RF), el cual permite un aprendizaje para clasificación, mediante la construcción de árboles de decisión durante la etapa de entrenamiento, que permitirán la salida de la clasificación (Del Toro et al., 2015). Para este caso se utilizó un archivo de entrenamiento con 8 clases dadas así: 1: Plástico, 2: Tejado, 3: Pastos, 4: Plantas de plátano, 5: Plantas de cacao, 6: Coberturas o superficies negras, 7: Suelo desnudo, y 8: Árboles (otros), con el cual se le dieron los insumos al algoritmo para que realizara la clasificación solicitada, obteniendo resultados aceptables, teniendo en cuanta las diferencias que existían entre cada una de las clases determinadas.

datostraining <- read.csv("C:\\Users\\BLACK SQUARE\\Desktop\\BLACKSQUARE_FOLDER\\ANDRES\\1_Personal\\MAESTRIA\\PERCEPCION_REMOTA\\CACAO_PR\\TABLA_TRAINING.csv")

datostraining
knitr::kable(datostraining)

OID_ VALUE COUNT COBERTURA
NA 1 23463 Plastico
NA 2 5570 Tejado
NA 3 11097 Pastos
NA 4 1576 Platano
NA 5 15917 Cacao
NA 6 4627 CobNegra
NA 7 46451 Suelos
NA 8 31877 Arbol


fl <- list.files("C:\\Users\\BLACK SQUARE\\Desktop\\BLACKSQUARE_FOLDER\\ANDRES\\1_Personal\\MAESTRIA\\PERCEPCION_REMOTA\\CACAO_PR\\Nueva carpeta", pattern = ".tif$", full.names = TRUE)

rst <- stack(fl)
names(rst) <- c(paste("b",2:4,sep=""))
plotRGB(rst, r=3, g=2, b=1, scale=1E5, stretch="lin", main = "Lote cacao", axes=TRUE, ylab="NORTE", xlab= "ESTE")

rstTrain <- raster("C:\\Users\\BLACK SQUARE\\Desktop\\BLACKSQUARE_FOLDER\\ANDRES\\1_Personal\\MAESTRIA\\PERCEPCION_REMOTA\\CACAO_PR\\entrenamiento.tif")

rstTrain[rstTrain==0] <- NA

# Se convierte a una representacion del tipo discreto
rstTrain <- ratify(rstTrain)
rstTrain
class      : RasterLayer 
dimensions : 1184, 1642, 1944128  (nrow, ncol, ncell)
resolution : 0.03, 0.03  (x, y)
extent     : 1032229, 1032278, 892403.9, 892439.5  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : entrenamiento 
values     : 1, 8  (min, max)
attributes :
# Cambio de nombre de la capa
names(rstTrain) <- "trainClass"

# Se visualiza el raster de entrenamiento
plot(rstTrain, col = rev(topo.colors(8)), main="Áreas de entrenamiento")

tab <- table(values(rstTrain))
print(tab)

    1     2     3     4     5     6     7     8 
23531  5731 11021  1412 15468  4563 46450 30917 
rstDF <- na.omit(values(stack(rstTrain, rst)))
rstDF[,"trainClass"] <- as.factor(as.character(rstDF[,"trainClass"]))


rstDF <- na.omit(values(stack(rstTrain, rst)))
rstDF[,"trainClass"] <- as.factor(as.character(rstDF[,"trainClass"]))

nEvalRounds <- 20

pTrain <- 0.5
n <- nrow(rstDF)
nClasses <- length(unique(rstDF[,"trainClass"]))

# Initialize objects

confMats <- array(NA, dim = c(nClasses,nClasses,nEvalRounds))

evalMatrix<-matrix(NA, nrow=nEvalRounds, ncol=3,dimnames=list(paste("R_",1:nEvalRounds,sep=""),c("Accuracy","Kappa","PSS")))

pb <- txtProgressBar(1, nEvalRounds, style = 3)
# Evaluation function
source(url("https://raw.githubusercontent.com/joaofgoncalves/Evaluation/master/eval.R"))

# Se hace correr el clasificador

for(i in 1:nEvalRounds){
 
  # Crear un  índice que es aleatorio que permite la seleccion de las filas 
  sampIdx <- sample(1:n, size = round(n*pTrain))

  # Se calibra el arbol de decisiones 
  rf <- randomForest (y = as.factor(rstDF[sampIdx, "trainClass"]),x = rstDF[sampIdx, -1], ntree = 100)

  # vector que ayuda a predecir el conjunto de prueba
  testSetPred <- predict(rf, newdata = rstDF[-sampIdx,], type = "response")

  # Obtener el vector de las clases observadas de la muestra realizada
  testSetObs <- rstDF[-sampIdx,"trainClass"]
 
  # Se evalua la clasificacion realizada de la muestra
  evalData <- Evaluate(testSetObs, testSetPred)
 
  evalMatrix[i,] <- c(evalData$Metrics["Accuracy",1],evalData$Metrics["Kappa",1],evalData$Metrics["PSS",1])
 
  # Se almacena la matrix y se realiza su evaluación
  confMats[,,i] <- evalData$ConfusionMatrix
 
  # Se clasifica toda la imagen completa
  rstPredClassTMP <- predict(rst, model = rf,factors = levels(rstDF[,"trainClass"]))
 
  if(i==1){
    # Se realiza el raster predicho
    rstPredClass <- rstPredClassTMP
   
    # Se Obtiene la  precisión para cada  clase.
    Precision <- evalData$Metrics["Precision",,drop=FALSE]
    Recall <- evalData$Metrics["Recall",,drop=FALSE]
   
  }else{
    # Se unen todos los raster que se predijeron
    rstPredClass <- stack(rstPredClass, rstPredClassTMP)
   
    # Obtenga precisión que se obtuvo para cada clase
    Precision <- rbind(Precision,evalData$Metrics["Precision",,drop=FALSE])
    Recall <- rbind(Recall,evalData$Metrics["Recall",,drop=FALSE])
  }
   setTxtProgressBar(pb,i)
 }

  |                                                                                                             
  |                                                                                                       |   0%
  |                                                                                                             
  |=====                                                                                                  |   5%
  |                                                                                                             
  |===========                                                                                            |  11%
  |                                                                                                             
  |================                                                                                       |  16%
  |                                                                                                             
  |======================                                                                                 |  21%
  |                                                                                                             
  |===========================                                                                            |  26%
  |                                                                                                             
  |=================================                                                                      |  32%
  |                                                                                                             
  |======================================                                                                 |  37%
  |                                                                                                             
  |===========================================                                                            |  42%
  |                                                                                                             
  |=================================================                                                      |  47%
  |                                                                                                             
  |======================================================                                                 |  53%
  |                                                                                                             
  |============================================================                                           |  58%
  |                                                                                                             
  |=================================================================                                      |  63%
  |                                                                                                             
  |======================================================================                                 |  68%
  |                                                                                                             
  |============================================================================                           |  74%
  |                                                                                                             
  |=================================================================================                      |  79%
  |                                                                                                             
  |=======================================================================================                |  84%
  |                                                                                                             
  |============================================================================================           |  89%
  |                                                                                                             
  |==================================================================================================     |  95%
  |                                                                                                             
  |=======================================================================================================| 100%
knitr::kable(evalMatrix, digits = 3)

Accuracy Kappa PSS
R_1 0.895 0.866 0.860
R_2 0.896 0.867 0.861
R_3 0.893 0.864 0.857
R_4 0.895 0.865 0.859
R_5 0.894 0.864 0.858
R_6 0.893 0.863 0.857
R_7 0.894 0.864 0.858
R_8 0.895 0.866 0.860
R_9 0.893 0.864 0.858
R_10 0.894 0.865 0.858
R_11 0.894 0.865 0.859
R_12 0.894 0.865 0.859
R_13 0.895 0.866 0.860
R_14 0.895 0.866 0.860
R_15 0.894 0.865 0.859
R_16 0.895 0.865 0.859
R_17 0.894 0.864 0.858
R_18 0.894 0.864 0.858
R_19 0.893 0.863 0.857
R_20 0.895 0.866 0.860


round(apply(evalMatrix,2,FUN = function(x,...) c(mean(x,...), sd(x,...))), 3)
     Accuracy Kappa   PSS
[1,]    0.894 0.865 0.859
[2,]    0.001 0.001 0.001
avgPrecision <- apply(Precision,2,mean)
print("Exactitud")
[1] "Exactitud"
print(round(avgPrecision, 3))
    1     2     3     4     5     6     7     8 
0.991 1.000 0.788 0.494 0.689 0.998 0.989 0.774 
print("Exhaustividad")
[1] "Exhaustividad"
avgRecall <- apply(Recall,2,mean)
print(round(avgRecall, 3))
    1     2     3     4     5     6     7     8 
0.981 1.000 0.859 0.062 0.447 1.000 0.995 0.915 
print("Valor F")
[1] "Valor F"
avgF1 <- (2 * avgPrecision * avgRecall) / (avgPrecision+avgRecall)
print(round(avgF1, 3))
    1     2     3     4     5     6     7     8 
0.986 1.000 0.822 0.110 0.542 0.999 0.992 0.839 
evalMatrix[which.max(evalMatrix[,"Kappa"]), , drop=FALSE]
     Accuracy     Kappa       PSS
R_2 0.8959984 0.8672183 0.8611254
# esta sentencia muestra los mejores resultados de la variable kappa
cm <- as.data.frame(confMats[,,which.max(evalMatrix[,"Kappa"])])

# Cambio de nombre filas/columnas
colnames(cm) <- rownames(cm) <- paste(as.factor("c"),levels(as.factor(rstDF[,"trainClass"])),sep="_")

knitr::kable(cm)
c_1 c_2 c_3 c_4 c_5 c_6 c_7 c_8
c_1 11504 0 0 0 1 6 235 0
c_2 0 2905 0 0 0 0 0 0
c_3 0 0 4782 0 503 0 17 229
c_4 0 0 43 53 96 0 0 494
c_5 0 0 856 16 3458 0 12 3333
c_6 2 0 0 0 0 2231 0 0
c_7 82 0 8 0 8 0 23069 0
c_8 1 0 363 31 897 0 0 14312
rstModalClass <- modal(rstPredClass)

rstModalClassFreq <- modal(rstPredClass, freq=TRUE)

medFreq <- zonal(rstModalClassFreq, rstTrain, fun=median)
colnames(medFreq) <- c("Codigo","frecuencia modal")

medFreq[order(medFreq[,2],decreasing = TRUE),]
     Codigo frecuencia modal
[1,]      1               20
[2,]      2               20
[3,]      3               20
[4,]      5               20
[5,]      6               20
[6,]      7               20
[7,]      8               20
[8,]      4               18
par(mfrow=c(1,2), cex.main=0.8, cex.axis=0.8)

plot(rstModalClass, main = "Clasificación Supervisada por arbol de decisiones")
plot(rstModalClassFreq, main = "Clases con mayor problema de Clasificación")

mycolor1 <- c("#808080","#ff0000","#0000ff","#00ff00","#cbbeb5",
"#c3ff5b", "#ff7373","#fef65b")
par(mfrow = c(1,1))

plot(rstModalClassFreq, col = rev(terrain.colors(8)), main = "Lote cacao", axes=TRUE, ylab="NORTE", xlab= "ESTE")

plot(rstModalClass, main = 'LOTE CACAO: CLASIFICACIÓN SUPERVISADA', col = mycolor1 )

NA
NA
cs <- plot(rstModalClass, main = "Clasificación Supervisada por árbol de decisiones")

DISCUSIÓN

Los resultados obtenidos en el análisis estadístico unibanda evidencian que se presenta una alta correlación entre las bandas del espectro visible tomadas por la cámara sin modificar con afinidad promedio del 86%, mientras que la banda del NIR que fue tomada por la cámara modificada presenta una baja correlación con las demás con un valor promedio de 36%, esto se puede deber dado que, al presentarse un cambio en las características propias del equipo fotográfico, puede presentar y generar ruido en dicha banda. Estos resultados difieren a los presentados por Fan et al., (2018), donde aseguran que utilizaron una configuración de similares características y obtuvieron una correlación de los datos provenientes de las 4 bandas, previa calibración con un panel con reflectancia conocida.

En cuanto al índice espectral generado para este caso, el NDVI, se presenta una congruencia con respecto a las superficies o coberturas que se presentan en el área determinada, ya que se obtuvieron valores menores a 0 en superficies como suelo, estructuras y construcciones, mientras que la vegetación tuvo valores mayores a 0, en este caso, los pastos obtuvieron un valor cercano a 0.2, haciendo énfasis en las plantas arbóreas como el cacao y algunos árboles que se presentan en la zona, los cuales obtuvieron valores alrededor de 0.6 y mayores, datos que tiene similitud al estudio realizado por Olukayode et al., (2018), donde evaluaron el estado fisiológico de plantas de cacao mediante sensoramiento remoto con el uso de un espectrorradiómetro y obtuvieron como resultados para las plantas valores del NDVI en promedio de 0.5.

En cuanto a la clasificación no supervisada, los resultados obtenidos fueron aceptables ya que a grandes rasgos, se realizó con claridad la discriminación entre las zonas que presentaban vegetación y las construcciones y suelo desnudo, teniendo en cuenta que al generar el procesamiento por medio de K-means el cual realiza el agrupamiento en clústeres particionando las observaciones en K agrupaciones en las que cada pixel que posee la imagen raster pertenece a la agrupación con la media más cercana, lo que hace que funciones como prototipo de la agrupación que realiza el algoritmo.

Con respecto a las coberturas vegetales, en especial donde se encontraban las especies perennes, el algoritmo de clasificación no supervisada, catalogó cada uno de los individuos con una mezcla entre las categorías Árboles, cacao y plátano, teniendo en cuenta que dependiendo el sombreamiento que tenía cada planta, asignaba la categoría, y en algunas ocasiones los pastos también fueron catalogados en las categorías de vegetación, por lo que este tipo de datos que se generan con las sombras de los objetos que se tengan en la escena, pueden influenciar notoriamente en la clasificación cuando no es supervisada, además, en este caso teniendo en cuenta las diferentes clases de vegetaciones presentes en el lote analizado, no fue adecuadamente clasificado haciendo discriminación entre ellas, por lo que este tipo de clasificación, si bien caracteriza superficies que son totalmente diferentes, no es tan robusto para la discriminación entre especies vegetales.

Con relación a la clasificación supervisada, donde se tuvieron en cuenta variables como la exactitud (accuracy), la exhaustividad (kappa) y la precisión de la clasificación (PSS) para determinar la calidad que presentó el procesamiento y la clasificación, donde se analiza cual es la relación de las distribuciones de probabilidad de la clasificación antes y durante el procesamiento del evento (Sastoque y Gutiérrez, 2016), se tiene en cuenta el archivo de entrenamiento generado previamente para realizar esta clasificación, definiendo que del total de muestras, un 50% fuera de entrenamiento y el restante fuera de validación del proceso, calculando los valores promedio a partir de la información cada clase y las desviaciones estándar en cada una de las rondas de iteración sobre los datos, y con las variables ya mencionadas, se determinó el valor F que nos permite medir la precisión que tiene la clasificación, previa generación de la matriz de confusión entre las clases, lo que permite la visualización del desempeño de algoritmo que se empleó en la clasificación.

Teniendo en cuenta esta información, y según las características que presentan las plantas y la vegetación en general, para este estudio no es conveniente realizar la caracterización y discriminación de plantas de cacao a partir de los datos que se tienen, ya que, por la similitud de las plantas al ser especies leñosas perennes de porte alto, de alta frondosidad y morfológicamente similares, no es posible diferenciar entre la especie de interés y los árboles presente en la finca “el triunfo”. Espectralmente pueden tener características similares en la región del espectro visible y por la calidad de las imágenes, en especial enfatizando en la banda NIR, se debe tener en cuenta que esta información espectral no logra percibir y denotar diferencias que por medio de los algoritmos aplicados puedan destacarse.

CONCLUSIONES

Aunque los resultados del análisis de la exhaustividad, la exactitud y de la precisión de la clasificación supervisada arrojaron un 86% de precisión, los resultados en general presentan una aceptable discriminación entre las diferentes coberturas, sin embargo al realizar el análisis sobre el cacao como especie de interés, un 45% de muestras que fueron clasificadas acertadamente como cacao, no permite establecer un alto rango de confianza alto para realizar la discriminación de esta especie de interés económico y social para la región, lo que no permitiría generar un posible censo de estas plantas de manera eficiente utilizando los datos que se tuvieron para este ejercicio.

Teniendo en cuenta esto, es posible que mediante un aumento en el número de muestras dentro del archivo de entrenamiento, se pueda mejorar el desempeño de clasificación, sin embargo, se evidencia que algunos algoritmos tiene alguna incertidumbre por lo que genera datos que pueden ser incorrectos al momento de hacer la clasificación, sumado a que cuando se maneja gran volumen de información, el procesamiento de esta puede verse limitado a las características que posea el hardware donde se realice el procedimiento, por lo que es necesario recurrir a equipos de mayor capacidad o limitar el tamaño de las imágenes que se trabajan por parte del usuario.

Al comparar los dos tipos de clasificaciones empleadas, se evidencia que la clasificación supervisada obtuvo mejores resultados al realizar un mayor énfasis en cada una de las clases, definiendo mas claramente los limites de y bordes, lo que genera menos distorsión y más calidad en los datos obtenidos, en comparación a la clasificación no supervisada, en la que se percibe mayor confusión al definir las clases en la zona de estudio, en especial en las coberturas de especies vegetales en general.

REFERENCIAS

LS0tDQp0aXRsZTogIkNMQVNJRklDQUNJw5NOIERFIENPQkVSVFVSQVMgQ09OIElNw4FHRU5FUyBERSBEUk9OIg0KYXV0aG9yOiAiQU5EUsOJUyBWRUxBTkRJQSBTLiINCmRhdGU6ICIxNS8xMC8yMDE5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMgSU5UUk9EVUNDScOTTg0KTGFzIGltw6FnZW5lcyBhw6lyZWFzIGRlIGFsdGEgcmVzb2x1Y2nDs24gYWRtaXRlbiB1bmEgYW1wbGlhIGdhbWEgZGUgY2FtcG9zIGRlIGFwbGljYWNpw7NuIGNvbW8gbGEgZXN0aW1hY2nDs24gZGUgZGlmZXJlbnRlcyBwYXLDoW1ldHJvcyBjb21vIGxhIGVzdGltYWNpw7NuIGRlIGJpb21hc2EgYSBwYXJ0aXIgZGUgbGFzIGNvYmVydHVyYXMgdmVnZXRhbGVzIHF1ZSBzZSBwdWVkYW4gZGV0ZXJtaW5hciwgY29udGVuaWRvIGRlIGFndWEsIGVudHJlIG90cmFzIGNhcmFjdGVyw61zdGljYXMgcXVlIHB1ZWRlbiBzZXIgZXh0cmHDrWRhcyBhIHBhcnRpciBkZSBsYSBpbmZvcm1hY2nDs24gcXVlIGJyaW5kYW4gbGFzIGJhbmRhcyBzZWfDum4gZWwgc2Vuc29yIHF1ZSByZWdpc3RyZSBsYXMgZm90b2dyYWbDrWFzLg0KDQpIYXkgZG9zIHRpcG9zIGRlIGNsYXNpZmljYWNpw7NuIGRlIGltw6FnZW5lcywgbGFzIGN1YWxlcyBzb246IGNsYXNpZmljYWNpw7NuIHN1cGVydmlzYWRhIHkgY2xhc2lmaWNhY2nDs24gbm8gc3VwZXJ2aXNhZGEsIGxhcyBjdWFsZXMgcGVybWl0ZW4gZXhwbG9yYXIgbG9zIGRpZmVyZW50ZXMgcGFyw6FtZXRyb3Mgc2Vnw7puIGxhcyBjbGFzZXMgcXVlIHNlIGRlZmluYW4sIG1lZGlhbnRlIGxhIGlkZW50aWZpY2FjacOzbiB2aXN1YWwgcG9yIHBhcnRlIGRlbCBpbnZlc3RpZ2Fkb3IsIGRlIGxvcyBwaXhlbGVzIGRlIHVuYSBvIGRlIHZhcmlhcyBkZSBsYXMgYmFuZGFzIGRlIHVuYSBpbWFnZW4gcmFzdGVyIHBhcmEgcXVlIHBvc3Rlcmlvcm1lbnRlIHNlIHB1ZWRhIGRhciBjYXRlZ29yw61hcyB5IHJlYWxpemFyIGxhIGNsYXNpZmljYWNpw7NuIGRlIGFjdWVyZG8gYSBsYXMgcHJvYmFiaWxpZGFkZXMgZGUgY2FkYSBjbGFzZSwgcG9yIGxvIHF1ZSBwYXJhIGVzdGUgdHJhYmFqbyBzZSByZWFsaXrDsyBlbCBhbsOhbGlzaXMgcHJlbGltaW5hciBwYXJhIG9idGVuZXIgdW5hIGNsYXNpZmljYWNpw7NuIGRlIGNvYmVydHVyYXMgZW4gdW4gbG90ZSBkZSBjYWNhbyB1YmljYWRvIGVuIEdyYW5hZGEsIE1ldGEsIGxvZ3JhbmRvIGRpc2NyaW1pbmFyIGVudHJlIGxhcyBkaWZlcmVudGVzIGNvYmVydHVyYXMgcXVlIHNlIHByZXNlbnRhcm9uIGVuIGVsIGxvdGUgc2VsZWNjaW9uYWRvLg0KDQojIyBEQVRPUyBZIE3DiVRPRE9TDQpFbCDDoXJlYSBkZSBlc3R1ZGlvIGNvcnJlc3BvbmRlIGEgdW4gbG90ZSBkZSBjYWNhbyAoX1RoZW9icm9tYSBjYWNhb18pIHViaWNhZG8gZW4gbGEgZmluY2Eg4oCcRWwgdHJpdW5mb+KAnSBlbiBlbCBtdW5pY2lwaW8gZGUgR3JhbmFkYSAoTWV0YSksIGVsIGxvdGUgdGllbmUgdW4gw6FyZWEgZGUgOS41IGhhIGFwcm94aW1hZGFtZW50ZSwgY29uIGNvb3JkZW5hZGFzIDczLjc4ODE3OCBXOyAzLjYyMjQ5MSBOLg0KDQpMYXMgZm90b2dyYWbDrWFzIGZ1ZXJvbiB0b21hZGFzIGNvbiBlbCB1c28gZGUgdW5hIGPDoW1hcmEgQ2Fub24gUzExMCwgbGEgY3VhbCB0aWVuZSB1biBzZW5zb3IgQ01PUyBkZSBhbHRhIHNlbnNpYmlsaWRhZCBkZSAxMi4xIE1weCBwYXJhIGxhIHRvbWEgZGUgbGFzIGJhbmRhcyBSR0IsIHkgdW5hIGPDoW1hcmEgUzEwMCBkZSAxMiBNcHgsIGNvbiB1bmEgbW9kaWZpY2FjacOzbiBsYSBjdWFsIHNlIGxlIGV4dHJham8gZWwgZmlsdHJvIGp1c3RvIGRlbGFudGUgZGVsIHNlbnNvciBDTU9TIHF1ZSBpbXBpZGUgZWwgcGFzbyBkZSBsYSByYWRpYWNpw7NuIElSIHBhcmEgbGEgY2FwdHVyYSBkZSBlc3RhIGJhbmRhIGRlbCBlc3BlY3RybywgbGFzIGltw6FnZW5lcyB0dXZpZXJvbiB1bmEgcmVzb2x1Y2nDs24gcmFkaW9tw6l0cmljYSBkZSA4IGJpdHMgKDI1NiBORCkuIExhcyBjw6FtYXJhcyBmdWVyb24gdHJhbnNwb3J0YWRhcyBlbiB1biBkcm9uZSBoZXhhY8OzcHRlcm8gREpJIEY1NTAsIGNvbiBwcmV2aWEgY29uZmlndXJhY2nDs24gZGUgbGEgbWlzacOzbiBkZSB2dWVsbyBwYXJhIHRvbWFyIGxhcyBmb3RvZ3JhZsOtYXMgYSB1bmEgYWx0dXJhIGRlIDgwIG1ldHJvcyBzb2JyZSBlbCB0ZXJyZW5vLCBjb24gdW4gb3ZlcmxhcCB5IHNpZGVsYXAgZGVsIDYwJS4gQ29uIGxhcyBpbcOhZ2VuZXMgc2UgcmVhbGl6w7MgZWwgcHJvY2VzYW1pZW50byBwYXJhIGxhIG9idGVuY2nDs24gZGVsIG9ydG9tb3NhaWNvIHkgZ2VvcnJlZmVyZW5jaWFjacOzbiBtZWRpYW50ZSBlbCB1c28gZGVsIHNvZnR3YXJlIFBob3Rvc2NhbiAxLjMgKEFnaXNvZnQsIERldmljZXMpIG9idGVuaWVuZG8gdW5hIMO6bmljYSBpbWFnZW4gY29uIHVuYSByZXNvbHVjacOzbiBlc3BhY2lhbCBkZSAzIGNtIHDDrXhlbF4tMV4uDQoNCiMjIyMjIExsYW1hZG8gZGUgbGFzIGNhcnBldGFzDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY2FjaGUgPSBGfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID1GQUxTRSwgbWVzc2FnZSA9RkFMU0UgLCBjYWNoZS5sYXp5PUZBTFNFLCBlcnJvciA9IFRSVUUpDQpyZXF1aXJlKCJrbml0ciIpDQpvcHRzX2tuaXQkc2V0IChyb290LmRpciA9ICJDOlxcVXNlcnNcXEJMQUNLIFNRVUFSRVxcRGVza3RvcFxcQkxBQ0tTUVVBUkVfRk9MREVSXFxBTkRSRVNcXDFfUGVyc29uYWxcXE1BRVNUUklBXFxQRVJDRVBDSU9OX1JFTU9UQVxcQ0FDQU9fUFIiKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzID0gbGlzdCh3aWR0aC5jdXRvZmY9NjApLHRpZHk9IFRSVUUpDQpsaWJyYXJ5KHJhc3RlcikNCmxpYnJhcnkoUlN0b29sYm94KQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkobW9tZW50cykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0YXRzKQ0KbGlicmFyeShzcCkNCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQojIyMjIyBBcm1hZG8gZGUgYXJjaGl2b3MgcmFzdGVyLCBpbcOhZ2VuZXMgcXVlIGN1ZW50YW4gY29uIHVuYSByZXNvbHVjaW9uIGVzcGFjaWFsIGRlIDNjbQ0KYGBge3IgY2FyZ2FyIGJhbmRhcywgY2FjaGU9VFJVRX0NCg0KIyMgQmFuZGEgQXp1bA0KYmFuZGFfYXp1bCA8LSByYXN0ZXIoIkNBUEFCTFVFcHJveS50aWYiKQ0KYmFuZGFfYXp1bA0KDQojIyBCYW5kYSBWZXJkZQ0KYmFuZGFfdmVyZGUgPC0gcmFzdGVyKCJDQVBBR1JFRU5wcm95LnRpZiIpDQpiYW5kYV92ZXJkZQ0KDQojIyBCYW5kYSBSb2phDQpiYW5kYV9yb2phIDwtIHJhc3RlcigiQ0FQQVJFRHByb3kudGlmIikNCmJhbmRhX3JvamENCg0KIyMgQmFuZGEgSVINCmJhbmRhX05JUiA8LSByYXN0ZXIoIkNBUEFJUnByb3kudGlmIikNCmJhbmRhX05JUg0KDQojIyMgU2UgZ2VuZXJhIGVsIFN0YWNrIGRlIGJhbmRhcyBjb24gbGFzIDQgcXVlIHNlIHZhIGEgdHJhYmFqYXINCmxvdGVfY2FjYW8gPC0gc3RhY2soYmFuZGFfYXp1bCwgYmFuZGFfdmVyZGUsIGJhbmRhX3JvamEsIGJhbmRhX05JUikNCmxvdGVfY2FjYW8NCg0KIyBDYW1iaW8gZGUgbm9tYnJlIGRlIGxhcyBiYW5kYXMgZXNwZWN0cmFsZXMNCm5hbWVzKGxvdGVfY2FjYW8pIDwtIHBhc3RlKCJCYW5kYSAiLCAxOjQsc2VwID0gIiIpDQpsb3RlX2NhY2FvDQoNCnBsb3QobG90ZV9jYWNhbykNCmBgYA0KDQpgYGB7ciBWaXN1YWxpemFjacOzbiwgY2FjaGU9VFJVRSwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01LCBkcGk9MzAwfQ0KaGlzdChsb3RlX2NhY2FvLCBtYWluPSJQbG90IGhpc3RvZ3JhbWEgcG9yIGJhbmRhIGVzcGVjdHJhbCIsIG1heHBpeGVscz1uY2VsbChsb3RlX2NhY2FvKSwgDQp5bGFiPSdGcmVjdWVuY2lhJywgeGxhYiA9ICdWYWxvciBkZSBsdW1pbm9zaWRhZCcpDQoNCnBhcihtZnJvdyA9IGMoMiwyKSkNCnBsb3QobG90ZV9jYWNhb1tbMV1dLCBtYWluID0gIkJsdWUiLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSwgYXhlcz1UUlVFLCB5bGFiPSdOb3J0ZScsIHhsYWIgPSAnRXN0ZScpDQpwbG90KGxvdGVfY2FjYW9bWzJdXSwgbWFpbiA9ICJHcmVlbiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApLCBheGVzPVRSVUUsIHlsYWI9J05vcnRlJywgeGxhYiA9ICdFc3RlJykNCnBsb3QobG90ZV9jYWNhb1tbM11dLCBtYWluID0gIlJlZCIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApLCBheGVzPVRSVUUsIHlsYWI9J05vcnRlJywgeGxhYiA9ICdFc3RlJykNCnBsb3QobG90ZV9jYWNhb1tbNF1dLCBtYWluID0gIk5JUiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApLCBheGVzPVRSVUUsIHlsYWI9J05vcnRlJywgeGxhYiA9ICdFc3RlJykNCmBgYA0KDQoNCiMjIyMjIEdlbmVyYWNpw7NuIGRlIGxhcyBlc3RhZGlzdGljYXMgdW5pYmFuZGEgcGFyYSBsYSBpbcOhZ2VuIHJhc3Rlcg0KDQpgYGB7ciBlc3RhZGlzdGljYXMgdW5pdmFyaWFkYXMsIGNhY2hlPVRSVUV9DQojIyBNZWRpYQ0KcHJpbnQoIk1lZGlhIikNCmNlbGxTdGF0cyhsb3RlX2NhY2FvLCAnbWVhbicpDQoNCiMjIERlc3ZpYWNpw7NuIGVzdGFuZGFyDQpwcmludCgiRGVzdmlhY2nDs24gZXN0YW5kYXIiKQ0KY2VsbFN0YXRzKGxvdGVfY2FjYW8sICdzZCcpDQoNCiMjIFZhcmlhbnphDQpwcmludCgiVmFyaWFuemEiKQ0KY2VsbFN0YXRzKGxvdGVfY2FjYW8sICd2YXInKQ0KDQojIyBNw61uaW1vcw0KcHJpbnQoIk3DrW5pbW9zIikNCmNlbGxTdGF0cyhsb3RlX2NhY2FvLCAnbWluJykNCg0KIyMgTcOheGltb3MNCnByaW50KCJNw6F4aW1vcyIpDQpjZWxsU3RhdHMobG90ZV9jYWNhbywgJ21heCcpDQoNCiMjIEFzaW1ldHLDrWENCnByaW50KCJBc2ltZXRyw61hIikNCmNlbGxTdGF0cyhsb3RlX2NhY2FvLCAnc2tldycpDQoNCiMjIEN1cnRvc2lzDQpwcmludCgiQ3VydG9zaXMiKQ0KY2VsbFN0YXRzKGxvdGVfY2FjYW8sICdrdXJ0b3NpcycpDQpgYGANCg0KIyMjIyMgR2VuZXJhY2nDs24gZGUgbGFzIGVzdGFkaXN0aWNhcyBtdWx0aWJhbmRhDQoNCmBgYHtyIGVzdGFkaXN0aWNhIG11bHRpdmFyaWFkYSwgY2FjaGU9VFJVRX0NCmF6dWwgPC0gcmFzdGVyKCJDQVBBQkxVRS50aWYiKQ0KdmVyZGUgPC0gcmFzdGVyKCJDQVBBR1JFRU4udGlmIikNCnJvam8gPC0gcmFzdGVyKCJDQVBBUkVELnRpZiIpDQpuaXIgPC0gcmFzdGVyKCJDQVBBSVIudGlmIikNCmJhbmRhcyA8LSBzdGFjayhhenVsLCB2ZXJkZSwgcm9qbywgbmlyKQ0KIyMgQ292YXJpYW56YQ0KcHJpbnQoIkNvdmFyaWFuemEgcHJlc2VudGUgZW50cmUgbGFzIGJhbmRhcyIpDQpsYXllclN0YXRzKGJhbmRhcywgJ2NvdicpDQoNCiMjIENvZWZpY2llbnRlIGRlIENvcnJlbGFjacOzbg0KcHJpbnQoIkNvZWZpY2llbnRlIGRlIENvcnJlbGFjacOzbiBwcmVzZW50ZSBlbnRyZSBsYXMgYmFuZGFzIikNCmxheWVyU3RhdHMoYmFuZGFzLCAncGVhcnNvbicpDQpgYGANCg0KIyMjIyMgR2VuZXJhY2nDs24gZGUgbGFzIHNhbGlkYXMgZGUgbGEgaW3DoWdlbiBhIGNvbG9yDQpgYGB7ciBTYWxpZGFHcmFmaWNhLCBjYWNoZT1UUlVFLCBmaWcuYWxpZ249J2NlbnRlcicsZmlnLmhlaWdodD01LGZpZy53aWR0aD01LCBkcGk9MzAwfQ0KcGxvdFJHQihsb3RlX2NhY2FvLHI9MywgZz0yLCBiPTEgLCBtYWluPSJMb3RlIGRlIGNhY2FvOiBDb21wb3NpY2nDs24gZGUgY29sb3IgdmVyZGFkZXJvIiwgbWF4cGl4ZWxzPW5jZWxsKGxvdGVfY2FjYW8pLCAgYXhlcz1UUlVFLCB5bGFiPSJOT1JURSIsIHhsYWI9ICJFU1RFIikNCg0KcGxvdFJHQihsb3RlX2NhY2FvLHI9MywgZz0yLCBiPTEgLCBtYWluPSJMb3RlIGRlIGNhY2FvOiBDb21wb3NpY2nDs24gZGUgY29sb3IgdmVyZGFkZXJvIChoaXN0KSIsc3RyZXRjaD0iaGlzdCIsICBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KDQpwbG90UkdCKGxvdGVfY2FjYW8scj0zLCBnPTIsIGI9MSAsIG1haW49IkxvdGUgZGUgY2FjYW86IENvbXBvc2ljacOzbiBkZSBjb2xvciB2ZXJkYWRlcm8gKGxpbikiLHN0cmV0Y2g9ImxpbiIsICBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KYGBgDQoNCiMjIyMjIEdlbmVyYWNpw7NuIGRlIGxhcyBzYWxpZGFzIGRlIGxhIGltw6FnZW4gZW4gZmFsc28gY29sb3INCmBgYHtyIFNhbGlkYSBGYWxzbyBjb2xvciwgY2FjaGU9VFJVRSwgZmlnLmFsaWduPSdjZW50ZXInLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9NSwgZHBpPTMwMH0NCg0KDQoNCiMgRW4gZXN0ZSBtb21lbnRvIHNlIG9wcm9jZWRlIGEgcmVhbGl6YXIgbGEgY29tcG9zaWNpb24gZW4gZmFsc28gY29sb3IgcmVhbGl6YW5kbyBlbCBjYW1iaW8gZGUgbGEgYmFuZGEgYXp1bCBwb3IgbGEgYmFuZGEgTklSDQpwbG90UkdCKGxvdGVfY2FjYW8scj0zLCBnPTIsIGI9NCAsIG1haW49IkxvdGUgZGUgY2FjYW86IENvbXBvc2ljacOzbiBlbiBmYWxzbyBjb2xvciAoaGlzdCkiLHN0cmV0Y2g9Imhpc3QiLCAgYXhlcz1UUlVFLCB5bGFiPSJOT1JURSIsIHhsYWI9ICJFU1RFIikNCg0KcGxvdFJHQihsb3RlX2NhY2FvLHI9MywgZz0yLCBiPTQgLCBtYWluPSJMb3RlIGRlIGNhY2FvOiBDb21wb3NpY2nDs24gZW4gZmFsc28gY29sb3IgKGxpbikiLHN0cmV0Y2g9ImxpbiIsICBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KYGBgDQoNCiMjIyMjIEdlbmVyYWNpw7NuIGRlIGxhIHJlbGFjaW9uIHF1ZSBzZSBwcmVzZW50YSBlbnRyZSBsYXMgYmFuZGFzIA0KYGBge3IgcmVsYWNpb24gZW50cmUgYmFuZGFzLCBjYWNoZT1UUlVFLCBmaWcuYWxpZ249J2NlbnRlcicsZmlnLmhlaWdodD01LGZpZy53aWR0aD01LCBkcGk9MzAwfQ0KcGFpcnMobG90ZV9jYWNhb1tbMTo0XV0sIG1haW4gPSAiTG90ZSBkZSBjYWNhbzogUmVsYWNpb24gZW50cmUgbGFzIGJhbmRhcyIpDQpgYGANCg0KIyMjIyMgUmVhbGl6YWNpw7NuIGRlbCBjw6FsY3VsbyBkZSDDrW5kaWNlcyBkZSB2ZWdldGFjacOzbiAoTkRWSSkNCkVsIHVzbyBkZSDDrW5kaWNlcyBkZSB2ZWdldGFjacOzbiANCmBgYHtyIGZ1bmNpb25lcyBpbmRpY2VzIChORFZJKSwgY2FjaGU9VFJVRX0NCg0KTkRWSSA8LSBmdW5jdGlvbihpbWcsIGssIGkpIHsNCiAgICBiayA8LSBpbWdbW2tdXQ0KICAgIGJpIDwtIGltZ1tbaV1dDQogICAgTkRWSSA8LSAoKGJrIC0gYmkpIC8gKGJrICsgYmkgKSkNCnJldHVybihORFZJKQ0KfQ0KYGBgDQoNCmBgYHtyIGNhbGN1bG9zIGluZGljZXMgKE5EVkkpLCBjYWNoZT1UUlVFLCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTUsIGNhY2hlPVRSVUUsIGRwaT0zMDB9DQpuZHZpX2luZGljZSA8LSBORFZJICAobG90ZV9jYWNhbyw0LDMpDQpuZHZpX2luZGljZQ0KDQpwbG90KG5kdmlfaW5kaWNlLCBjb2wgPSByZXYodGVycmFpbi5jb2xvcnMoMTApKSwgbWFpbiA9ICJMb3RlIGNhY2FvOiBJbmRpY2UgZGUgVmVnZXRhY2lvbiAtIE5EVkkiLCBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KICAgICANCnZlZ05EVkkgPC0gcmVjbGFzc2lmeShuZHZpX2luZGljZSwgY2JpbmQoLUluZiwgMC4wLCBOQSkpDQoNCnBsb3QodmVnTkRWSSwgbWFpbj0iTG90ZSBjYWNhbzogSW5kaWNlIGRlIFZlZ2V0YWNpb24gTkRWSSAtIERpc2NyaW1pbmFjacOzbiBkZSB6b25hcyBkZSBOTyB2ZWdldGFjacOzbiIsIGF4ZXM9VFJVRSwgeWxhYj0iTk9SVEUiLCB4bGFiPSAiRVNURSIpDQoNCnZlZ05EVkl0aHJlcyA8LSByZWNsYXNzaWZ5KHZlZ05EVkksIGMoLUluZiwwLjIsMCwgMC4yLDAuMywxLCAwLjMsMC40LDIsIDAuNCwwLjUsMywgMC41LCBJbmYsIDQpKQ0KDQpwbG90KHZlZ05EVkl0aHJlcyxjb2wgPSByZXYodGVycmFpbi5jb2xvcnMoNCkpLCBtYWluID0gJ05EVkkgYmFzZWQgdGhyZXNob2xkaW5nJykNCmBgYA0KDQpFbiBjdWFudG8gYWwgw61uZGljZSBkZSB2ZWdldGFjacOzbiBkZSBkaWZlcmVuY2lhIG5vcm1hbGl6YWRvIChORFZJKSwgc2UgcHVlZGUgZXZpZGVuY2lhciBxdWUgc2UgcHVlZGUgZGVzdGFjYXIgY29uIG1heW9yIGNsYXJpZGFkIGxhIGZyb25kb3NpZGFkIHkgdmlnb3Jvc2lkYWQgZGUgbGEgdmVnZXRhY2nDs24gcXVlIHNlIHByZXNlbnRhIGVuIGVsIMOhcmVhIHNlbGVjY2lvbmFkYSwgcHJlc2VudMOhbmRvc2UsIGVuIGVzdGUgY2FzbywgY29uIHVuIGNvbG9yIHZlcmRlIG3DoXMgaW50ZW5zbywgeWEgcXVlLCBhbCBtb21lbnRvIGRlIGluY2x1aXIgZXhwbMOtY2l0YW1lbnRlIGVsIGZhY3RvciBkZWwgc3VlbG8sIMOpc3RlIHNlIHB1ZWRlIGRpc2NyaW1pbmFyIGNvbiBtYXlvciBmYWNpbGlkYWQsIG1vc3RyYW5kbyBlbiBsYSBpbWFnZW4gY29uIGNvbG9yZXMgY2xhcm9zLCBtaWVudHJhcyBxdWUgbGFzIHpvbmFzIGRvbmRlIHNlIHByZXNlbnRhbiBjb25zdHJ1Y2Npb25lcywgY2FycmV0ZXJhcyB5IHN1ZWxvIGRlc251ZG8gbyBhbGfDum4gcG9yY2VudGFqZSBkZSBkZWZvcmVzdGFjacOzbiwgc2UgcHVlZGVuIGRlbm90YXIgY29uIGNvbG9yIHJvc2FkbywgcGl4ZWxlcyBxdWUgc2UgcHJlc2VudGFuIGNvbiB2YWxvcmVzIGJham9zIG8gbWVub3JlcyBhIDAsIHNlZ8O6biBlc3RlIMOtbmRpY2UgZGUgdmVnZXRhY2nDs24uDQoNCiMjIyBDTEFTSUZJQ0FDSU9ORVMNCiMjIyMgUHJvY2VkaW1pZW50byBwYXJhIGxhIGNsYXNpZmljYWNpw7NuIHN1cGVydmlzYWRhIHkgbm8gc3VwZXJ2aXNhZGENClBhcmEgbGEgY2xhc2lmaWNhY2nDs24gZGUgbGEgaW1hZ2VuIHNlIHR1dm8gZW4gY3VlbnRhIGVsIHRhbWHDsW8geSBwZXNvIGRlIMOpc3RhIGFsIG1vbWVudG8gZGVsIHByb2Nlc2FtaWVudG8sIHBvciBsbyBxdWUgc2UgaW50ZW50w7MgcmVhbGl6YXIgbGEgY2xhc2lmaWNhY2nDs24gY29uIGxhIHRvdGFsaWRhZCBkZSBsYSBpbcOhZ2VuICg5LDUgaGEpLCBwZXJvIG5vIGZ1ZSBwb3NpYmxlLCBwb3IgbG8gcXVlIGZ1ZSBuZWNlc2FyaW8gcmVkdWNpciBlbCB0YW1hw7FvIHkgYXPDrSByZWFsaWF6ciBsb3MgcHJvY2Vzb3MuIFNlIGRpZmluacOzIGVsIMOhcmVhIHF1ZSB0dXZpZXJhIGVsIG1heW9yIG7Dum1lcm8gZGUgY2xhc2VzIHBvc2libGUsIGVuIGVsIGNhc28gZGUgbGEgY2xhc2lmaWNhY2nDs24gc3VwZXJ2aXNhZGEsIHNlIGRlZmluaWVyb24gbGFzIGNvYmVydHVyYXMgcXVlIHNlIGVuY29udHJhYmFuIGVuIGxhIHpvbmEgZGUgZXN0dWRpby4gVW5hIHZleiBjYWxpYnJhZG9zIGxvcyBhbGdvcml0bW9zIGEgdXRpbGl6YXIgc2UgcmVhbGl6YSBsYSBjbGFzaWZpY2FjaW9uIGRlIGxhIGltYWdlbiB5IHNlIGV2YWzDumEgbGEgY2FsaWRhZCBkZSBsYSBjbGFzaWZpY2FjacOzbiByZWFsaXphZGEsIHNlIHZlcmlmaWNhIGxvcyByZXN1bHRhZG9zLiBFc3RlIHByb2Nlc28gc2UgcmVwaXRlIHkgbHVlZ28gc2UgY2FsY3VsYSBlbCB2YWxvciBwcm9tZWRpbyBkZSBsb3Mgw61uZGljZXMgZGUgdmFsaWRhY2nDs24sIG1lZGlhbnRlIGVsIHVzbyBkZWwgYWxnb3JpdG1vIFJhbmRvbSBGb3Jlc3QgKFJGKSwgc2UgcGVybWl0acOzIHVuIGFwcmVuZGl6YWplIHBhcmEgY2xhc2lmaWNhY2nDs24sIG1lZGlhbnRlIGxhIGNvbnN0cnVjY2nDs24gZGUgw6FyYm9sZXMgZGUgZGVjaXNpw7NuIGR1cmFudGUgbGEgZXRhcGEgZGUgZW50cmVuYW1pZW50bywgcXVlIHBlcm1pdGlyw6FuIGxhIHNhbGlkYSBkZSBsYSBjbGFzaWZpY2FjacOzbg0KDQojIyMgQ0xBU0lGSUNBQ0lPTiBOTyBTVVBFUlZJU0FEQQ0KU2UgYXN1bWUgcXVlIG5vIHNlIHRpZW5lIGNvbm9jaW1pZW50byBkZWwgw6FyZWEgZGUgZXN0dWRpbywgbG9zIHJlc3VsdGFkb3MgcXVlIGdlbmVyYSBlbCBhbGdvcml0bW8gY29uIGVzdGEgY2xhc2lmaWNhY2nDs24sIHRlbmllbmRvIGVuIGN1ZW50YSBkZSBsb3MgdmFsb3JlcyBkZSBsb3MgcGl4ZWxlcywgZm9ybWFyYW4gYWdydXBhY2lvbmVzIHNlZ8O6biBsYSBpbmZvcm1hY2nDs24gZGUgbGFzIGJhbmRhcyBkZWwgcmFzdGVyLiBMb3MgcmVzdWx0YWRvcyBkZSBsYSBjbGFzaWZpY2FjacOzbiBubyBzdXBlcnZpc2FkYSBnZW5lcmFyb24gOCBjbGFzZXMsIGRlc3RhY8OhbmRvc2UgbGFzIGRpZmVyZW5jaWFzIHF1ZSBoYXkgZW50cmUgbG8gcXVlIGVzIHZlZ2V0YWNpw7NuIHkgbG8gcXVlIGNvcnJlc3BvbmRlIGEgc3VlbG8geSBvdHJhcyBlc3RydWN0dXJhcyB5IGNvbnN0cnVjY2lvbmVzLiANCg0KYGBge3IgY2xhc2lmaWNhY2nDs24gTm8gU1VQRVJWSVNBREEsIGNhY2hlPVRSVUV9DQojIGNvbnZlcnRpciBlbCByYXN0ZXIgYSBtYXRyaXogZGUgdmVjdG9yDQpuciA8LSBnZXRWYWx1ZXMoYmFuZGFzKQ0Kc3RyKG5yKQ0KYGBgDQoNCmBgYHtyIGFqdXN0ZXMgQ05TLCBjYWNoZT1UUlVFfQ0KIyBBcXXDrSBzZSByZWFsaXrDsyBlbCBhbsOhbGlzaXMgbWVkaWFudGUgZWwgdXNvIGRlbCBhbGdvcml0bW8gZGUga21lYW5zDQojIGxvY2FsaXphY2lvbmVzIGFsIGF6YXIgDQpzZXQuc2VlZCg5OSkNCiNTZSBxdWlzbyBjcmVhciA4IGdydXBvcywgcGVybWl0aXIgNTAwIGl0ZXJhY2lvbmVzLCBjb21lbnphciBjb24gNSBjb25qdW50b3MgYWxlYXRvcmlvcyB1c2FuZG8gZWwgTcOpdG9kbyAiTGxveWQiDQprbW5jbHVzdGVyIDwtIGttZWFucyhuYS5vbWl0KG5yKSwgY2VudGVycyA9IDgsIGl0ZXIubWF4ID0gNTAwLCBuc3RhcnQgPSA1LCBhbGdvcml0aG09Ikxsb3lkIikNCg0Kc3RyKGttbmNsdXN0ZXIpDQpgYGANCg0KYGBge3IgYWp1c3RlczIgQ05TLCBjYWNoZT1UUlVFfQ0Ka25yIDwtIHNldFZhbHVlcyhiYW5kYXMsIGttbmNsdXN0ZXIkY2x1c3RlcikNCmtucg0KYGBgDQoNCmBgYHtyIGNsYXNpZiBOTyBTVVBFUlZJU0FEQSBQTE9UUywgY2FjaGU9VFJVRSwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01LCBjYWNoZT1UUlVFLCBkcGk9MzAwfQ0KIyBTZSBkZWZpbmUgZWwgY29sb3IgcGFyYSBjYWRhIHVubyBkZSBsb3MgOCBjdXN0ZXJlcyBkZWZpbmlkb3MNCiNteWNvbG9yIDwtIGMoIiNmZjAwMDAiLCAiI2RhYTUyMCIsIiMwMDAwZmYiLCIjMDBmZjAwIiwiI2NiYmViNSIsDQojIiNjM2ZmNWIiLCAiI2ZmNzM3MyIsICIjODA4MDgwIikNCg0KbXljb2xvciA8LSBjKCIjODA4MDgwIiwiI2ZmMDAwMCIsIiMwMDAwZmYiLCIjMDBmZjAwIiwiI2NiYmViNSIsDQoiI2MzZmY1YiIsICIjZmY3MzczIiwiI2ZlZjY1YiIpDQpwYXIobWZyb3cgPSBjKDEsMSkpDQpwbG90KGJhbmRhcywgY29sID0gcmV2KHRlcnJhaW4uY29sb3JzKDgpKSwgbWFpbiA9ICJMb3RlIGNhY2FvIiwgYXhlcz1UUlVFLCB5bGFiPSJOT1JURSIsIHhsYWI9ICJFU1RFIikNCm5jIDwtIHBsb3Qoa25yLCBtYWluID0gJ0xPVEUgQ0FDQU86IENMQVNJRklDQUNJw5NOIE5PIFNVUEVSVklTQURBJywgY29sID0gbXljb2xvciApDQpgYGANCg0KYGBge3IgbGxhbWFkbyBkZSBudWV2YXMgbGlicmVyaWFzLCAgY2FjaGU9VFJVRX0NCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsYXR0aWNlKQ0KYGBgDQoNCiMjIyBDTEFTSUZJQ0FDSU9OIFNVUEVSVklTQURBDQpEZW50cm8gZGUgbG9zIGFsZ29yaXRtb3MgcXVlIHNlIGRlc2Fycm9sbGFuIGRlbnRybyBkZWwgc29mdHdhcmUgUnN0dWRpb8KuLCBlc3TDoSBlbCBkZSBSYW5kb20gRm9yZXN0IChSRiksIGVsIGN1YWwgcGVybWl0ZSB1biBhcHJlbmRpemFqZSBwYXJhIGNsYXNpZmljYWNpw7NuLCBtZWRpYW50ZSBsYSBjb25zdHJ1Y2Npw7NuIGRlIMOhcmJvbGVzIGRlIGRlY2lzacOzbiBkdXJhbnRlIGxhIGV0YXBhIGRlIGVudHJlbmFtaWVudG8sIHF1ZSBwZXJtaXRpcsOhbiBsYSBzYWxpZGEgZGUgbGEgY2xhc2lmaWNhY2nDs24gKERlbCBUb3JvIGV0IGFsLiwgMjAxNSkuIFBhcmEgZXN0ZSBjYXNvIHNlIHV0aWxpesOzIHVuIGFyY2hpdm8gZGUgZW50cmVuYW1pZW50byBjb24gOCBjbGFzZXMgZGFkYXMgYXPDrTogMTogUGzDoXN0aWNvLCAyOiBUZWphZG8sIDM6IFBhc3RvcywgNDogUGxhbnRhcyBkZSBwbMOhdGFubywgNTogUGxhbnRhcyBkZSBjYWNhbywgNjogQ29iZXJ0dXJhcyBvIHN1cGVyZmljaWVzIG5lZ3JhcywgNzogU3VlbG8gZGVzbnVkbywgeSA4OiDDgXJib2xlcyAob3Ryb3MpLCBjb24gZWwgY3VhbCBzZSBsZSBkaWVyb24gbG9zIGluc3Vtb3MgYWwgYWxnb3JpdG1vIHBhcmEgcXVlIHJlYWxpemFyYSBsYSBjbGFzaWZpY2FjacOzbiBzb2xpY2l0YWRhLCBvYnRlbmllbmRvIHJlc3VsdGFkb3MgYWNlcHRhYmxlcywgdGVuaWVuZG8gZW4gY3VhbnRhIGxhcyBkaWZlcmVuY2lhcyBxdWUgZXhpc3TDrWFuIGVudHJlIGNhZGEgdW5hIGRlIGxhcyBjbGFzZXMgZGV0ZXJtaW5hZGFzLg0KDQpgYGB7ciBMbGFtYXIgZWwgcmFzdGVyIGRlIGVudHJlbmFtaWVudG8sIGNhY2hlPVRSVUV9DQpkYXRvc3RyYWluaW5nIDwtIHJlYWQuY3N2KCJDOlxcVXNlcnNcXEJMQUNLIFNRVUFSRVxcRGVza3RvcFxcQkxBQ0tTUVVBUkVfRk9MREVSXFxBTkRSRVNcXDFfUGVyc29uYWxcXE1BRVNUUklBXFxQRVJDRVBDSU9OX1JFTU9UQVxcQ0FDQU9fUFJcXFRBQkxBX1RSQUlOSU5HLmNzdiIpDQoNCmRhdG9zdHJhaW5pbmcNCmtuaXRyOjprYWJsZShkYXRvc3RyYWluaW5nKQ0KDQpmbCA8LSBsaXN0LmZpbGVzKCJDOlxcVXNlcnNcXEJMQUNLIFNRVUFSRVxcRGVza3RvcFxcQkxBQ0tTUVVBUkVfRk9MREVSXFxBTkRSRVNcXDFfUGVyc29uYWxcXE1BRVNUUklBXFxQRVJDRVBDSU9OX1JFTU9UQVxcQ0FDQU9fUFJcXE51ZXZhIGNhcnBldGEiLCBwYXR0ZXJuID0gIi50aWYkIiwgZnVsbC5uYW1lcyA9IFRSVUUpDQoNCnJzdCA8LSBzdGFjayhmbCkNCm5hbWVzKHJzdCkgPC0gYyhwYXN0ZSgiYiIsMjo0LHNlcD0iIikpDQpwbG90UkdCKHJzdCwgcj0zLCBnPTIsIGI9MSwgc2NhbGU9MUU1LCBzdHJldGNoPSJsaW4iLCBtYWluID0gIkxvdGUgY2FjYW8iLCBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KYGBgDQoNCmBgYHtyIGNhcmdhciBlbCBhcmNoaXZvIGRlIHRyYWluaW5nLCBjYWNoZT1UUlVFfQ0KcnN0VHJhaW4gPC0gcmFzdGVyKCJDOlxcVXNlcnNcXEJMQUNLIFNRVUFSRVxcRGVza3RvcFxcQkxBQ0tTUVVBUkVfRk9MREVSXFxBTkRSRVNcXDFfUGVyc29uYWxcXE1BRVNUUklBXFxQRVJDRVBDSU9OX1JFTU9UQVxcQ0FDQU9fUFJcXGVudHJlbmFtaWVudG8udGlmIikNCmBgYA0KDQpgYGB7ciB2aXN1YWxpemFjaW9uIGRlIGFyZWFzIGRlIHRyYWluaW5nLCBjYWNoZT1UUlVFfQ0KDQpyc3RUcmFpbltyc3RUcmFpbj09MF0gPC0gTkENCg0KIyBTZSBjb252aWVydGUgYSB1bmEgcmVwcmVzZW50YWNpb24gZGVsIHRpcG8gZGlzY3JldG8NCnJzdFRyYWluIDwtIHJhdGlmeShyc3RUcmFpbikNCnJzdFRyYWluDQoNCiMgQ2FtYmlvIGRlIG5vbWJyZSBkZSBsYSBjYXBhDQpuYW1lcyhyc3RUcmFpbikgPC0gInRyYWluQ2xhc3MiDQoNCiMgU2UgdmlzdWFsaXphIGVsIHJhc3RlciBkZSBlbnRyZW5hbWllbnRvDQpwbG90KHJzdFRyYWluLCBjb2wgPSByZXYodG9wby5jb2xvcnMoOCkpLCBtYWluPSLDgXJlYXMgZGUgZW50cmVuYW1pZW50byIpDQpgYGANCg0KYGBge3IgdGFibGEgZGUgZGF0b3MgZGUgdHJhaW5pZywgY2FjaGU9VFJVRX0NCnRhYiA8LSB0YWJsZSh2YWx1ZXMocnN0VHJhaW4pKQ0KcHJpbnQodGFiKQ0KYGBgDQoNCmBgYHtyIG9taXNpb24gZGUgdmFsb3JlcywgY2FjaGU9VFJVRX0NCnJzdERGIDwtIG5hLm9taXQodmFsdWVzKHN0YWNrKHJzdFRyYWluLCByc3QpKSkNCnJzdERGWywidHJhaW5DbGFzcyJdIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIocnN0REZbLCJ0cmFpbkNsYXNzIl0pKQ0KDQoNCnJzdERGIDwtIG5hLm9taXQodmFsdWVzKHN0YWNrKHJzdFRyYWluLCByc3QpKSkNCnJzdERGWywidHJhaW5DbGFzcyJdIDwtIGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIocnN0REZbLCJ0cmFpbkNsYXNzIl0pKQ0KDQpuRXZhbFJvdW5kcyA8LSAyMA0KDQpwVHJhaW4gPC0gMC41DQpgYGANCg0KYGBge3IgZXZhbHVhY2lvbiBkZSBtYXRyaXosIGNhY2hlPVRSVUV9DQpuIDwtIG5yb3cocnN0REYpDQpuQ2xhc3NlcyA8LSBsZW5ndGgodW5pcXVlKHJzdERGWywidHJhaW5DbGFzcyJdKSkNCg0KIyBJbml0aWFsaXplIG9iamVjdHMNCg0KY29uZk1hdHMgPC0gYXJyYXkoTkEsIGRpbSA9IGMobkNsYXNzZXMsbkNsYXNzZXMsbkV2YWxSb3VuZHMpKQ0KDQpldmFsTWF0cml4PC1tYXRyaXgoTkEsIG5yb3c9bkV2YWxSb3VuZHMsIG5jb2w9MyxkaW1uYW1lcz1saXN0KHBhc3RlKCJSXyIsMTpuRXZhbFJvdW5kcyxzZXA9IiIpLGMoIkFjY3VyYWN5IiwiS2FwcGEiLCJQU1MiKSkpDQoNCnBiIDwtIHR4dFByb2dyZXNzQmFyKDEsIG5FdmFsUm91bmRzLCBzdHlsZSA9IDMpDQpgYGANCg0KYGBge3IgZXZhbHVhY2lvbiBkZSBmdW5jacOzbiwgY2FjaGU9VFJVRX0NCiMgRXZhbHVhdGlvbiBmdW5jdGlvbg0Kc291cmNlKHVybCgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2pvYW9mZ29uY2FsdmVzL0V2YWx1YXRpb24vbWFzdGVyL2V2YWwuUiIpKQ0KDQojIFNlIGhhY2UgY29ycmVyIGVsIGNsYXNpZmljYWRvcg0KDQpmb3IoaSBpbiAxOm5FdmFsUm91bmRzKXsNCiANCiAgIyBDcmVhciB1biAgw61uZGljZSBxdWUgZXMgYWxlYXRvcmlvIHF1ZSBwZXJtaXRlIGxhIHNlbGVjY2lvbiBkZSBsYXMgZmlsYXMgDQogIHNhbXBJZHggPC0gc2FtcGxlKDE6biwgc2l6ZSA9IHJvdW5kKG4qcFRyYWluKSkNCg0KICAjIFNlIGNhbGlicmEgZWwgYXJib2wgZGUgZGVjaXNpb25lcyANCiAgcmYgPC0gcmFuZG9tRm9yZXN0ICh5ID0gYXMuZmFjdG9yKHJzdERGW3NhbXBJZHgsICJ0cmFpbkNsYXNzIl0pLHggPSByc3RERltzYW1wSWR4LCAtMV0sIG50cmVlID0gMTAwKQ0KDQogICMgdmVjdG9yIHF1ZSBheXVkYSBhIHByZWRlY2lyIGVsIGNvbmp1bnRvIGRlIHBydWViYQ0KICB0ZXN0U2V0UHJlZCA8LSBwcmVkaWN0KHJmLCBuZXdkYXRhID0gcnN0REZbLXNhbXBJZHgsXSwgdHlwZSA9ICJyZXNwb25zZSIpDQoNCiAgIyBPYnRlbmVyIGVsIHZlY3RvciBkZSBsYXMgY2xhc2VzIG9ic2VydmFkYXMgZGUgbGEgbXVlc3RyYSByZWFsaXphZGENCiAgdGVzdFNldE9icyA8LSByc3RERlstc2FtcElkeCwidHJhaW5DbGFzcyJdDQogDQogICMgU2UgZXZhbHVhIGxhIGNsYXNpZmljYWNpb24gcmVhbGl6YWRhIGRlIGxhIG11ZXN0cmENCiAgZXZhbERhdGEgPC0gRXZhbHVhdGUodGVzdFNldE9icywgdGVzdFNldFByZWQpDQogDQogIGV2YWxNYXRyaXhbaSxdIDwtIGMoZXZhbERhdGEkTWV0cmljc1siQWNjdXJhY3kiLDFdLGV2YWxEYXRhJE1ldHJpY3NbIkthcHBhIiwxXSxldmFsRGF0YSRNZXRyaWNzWyJQU1MiLDFdKQ0KIA0KICAjIFNlIGFsbWFjZW5hIGxhIG1hdHJpeCB5IHNlIHJlYWxpemEgc3UgZXZhbHVhY2nDs24NCiAgY29uZk1hdHNbLCxpXSA8LSBldmFsRGF0YSRDb25mdXNpb25NYXRyaXgNCiANCiAgIyBTZSBjbGFzaWZpY2EgdG9kYSBsYSBpbWFnZW4gY29tcGxldGENCiAgcnN0UHJlZENsYXNzVE1QIDwtIHByZWRpY3QocnN0LCBtb2RlbCA9IHJmLGZhY3RvcnMgPSBsZXZlbHMocnN0REZbLCJ0cmFpbkNsYXNzIl0pKQ0KIA0KICBpZihpPT0xKXsNCiAgICAjIFNlIHJlYWxpemEgZWwgcmFzdGVyIHByZWRpY2hvDQogICAgcnN0UHJlZENsYXNzIDwtIHJzdFByZWRDbGFzc1RNUA0KICAgDQogICAgIyBTZSBPYnRpZW5lIGxhICBwcmVjaXNpw7NuIHBhcmEgY2FkYSAgY2xhc2UuDQogICAgUHJlY2lzaW9uIDwtIGV2YWxEYXRhJE1ldHJpY3NbIlByZWNpc2lvbiIsLGRyb3A9RkFMU0VdDQogICAgUmVjYWxsIDwtIGV2YWxEYXRhJE1ldHJpY3NbIlJlY2FsbCIsLGRyb3A9RkFMU0VdDQogICANCiAgfWVsc2V7DQogICAgIyBTZSB1bmVuIHRvZG9zIGxvcyByYXN0ZXIgcXVlIHNlIHByZWRpamVyb24NCiAgICByc3RQcmVkQ2xhc3MgPC0gc3RhY2socnN0UHJlZENsYXNzLCByc3RQcmVkQ2xhc3NUTVApDQogICANCiAgICAjIE9idGVuZ2EgcHJlY2lzacOzbiBxdWUgc2Ugb2J0dXZvIHBhcmEgY2FkYSBjbGFzZQ0KICAgIFByZWNpc2lvbiA8LSByYmluZChQcmVjaXNpb24sZXZhbERhdGEkTWV0cmljc1siUHJlY2lzaW9uIiwsZHJvcD1GQUxTRV0pDQogICAgUmVjYWxsIDwtIHJiaW5kKFJlY2FsbCxldmFsRGF0YSRNZXRyaWNzWyJSZWNhbGwiLCxkcm9wPUZBTFNFXSkNCiAgfQ0KICAgc2V0VHh0UHJvZ3Jlc3NCYXIocGIsaSkNCiB9DQpgYGANCg0KYGBge3IgYXBsaWNhY2nDs24gZGUgbWF0cml6LCBjYWNoZT1UUlVFfQ0Ka25pdHI6OmthYmxlKGV2YWxNYXRyaXgsIGRpZ2l0cyA9IDMpDQoNCnJvdW5kKGFwcGx5KGV2YWxNYXRyaXgsMixGVU4gPSBmdW5jdGlvbih4LC4uLikgYyhtZWFuKHgsLi4uKSwgc2QoeCwuLi4pKSksIDMpDQpgYGANCg0KYGBge3IgZGF0b3MgZGUgbGEgcHJlY2lzacOzbiwgY2FjaGU9VFJVRX0NCmF2Z1ByZWNpc2lvbiA8LSBhcHBseShQcmVjaXNpb24sMixtZWFuKQ0KcHJpbnQoIkV4YWN0aXR1ZCIpDQpgYGANCg0KYGBge3IgcHJpbnQsIGNhY2hlPVRSVUV9DQpwcmludChyb3VuZChhdmdQcmVjaXNpb24sIDMpKQ0KcHJpbnQoIkV4aGF1c3RpdmlkYWQiKQ0KYXZnUmVjYWxsIDwtIGFwcGx5KFJlY2FsbCwyLG1lYW4pDQpwcmludChyb3VuZChhdmdSZWNhbGwsIDMpKQ0KcHJpbnQoIlZhbG9yIEYiKQ0KDQphdmdGMSA8LSAoMiAqIGF2Z1ByZWNpc2lvbiAqIGF2Z1JlY2FsbCkgLyAoYXZnUHJlY2lzaW9uK2F2Z1JlY2FsbCkNCnByaW50KHJvdW5kKGF2Z0YxLCAzKSkNCg0KZXZhbE1hdHJpeFt3aGljaC5tYXgoZXZhbE1hdHJpeFssIkthcHBhIl0pLCAsIGRyb3A9RkFMU0VdDQoNCiMgZXN0YSBzZW50ZW5jaWEgbXVlc3RyYSBsb3MgbWVqb3JlcyByZXN1bHRhZG9zIGRlIGxhIHZhcmlhYmxlIGthcHBhDQpjbSA8LSBhcy5kYXRhLmZyYW1lKGNvbmZNYXRzWywsd2hpY2gubWF4KGV2YWxNYXRyaXhbLCJLYXBwYSJdKV0pDQoNCiMgQ2FtYmlvIGRlIG5vbWJyZSBmaWxhcy9jb2x1bW5hcw0KY29sbmFtZXMoY20pIDwtIHJvd25hbWVzKGNtKSA8LSBwYXN0ZShhcy5mYWN0b3IoImMiKSxsZXZlbHMoYXMuZmFjdG9yKHJzdERGWywidHJhaW5DbGFzcyJdKSksc2VwPSJfIikNCg0Ka25pdHI6OmthYmxlKGNtKQ0KYGBgDQoNCmBgYHtyIGRhdG9zIGRlIHpvbmFsLCBjYWNoZT1UUlVFfQ0KcnN0TW9kYWxDbGFzcyA8LSBtb2RhbChyc3RQcmVkQ2xhc3MpDQoNCnJzdE1vZGFsQ2xhc3NGcmVxIDwtIG1vZGFsKHJzdFByZWRDbGFzcywgZnJlcT1UUlVFKQ0KDQptZWRGcmVxIDwtIHpvbmFsKHJzdE1vZGFsQ2xhc3NGcmVxLCByc3RUcmFpbiwgZnVuPW1lZGlhbikNCmBgYA0KDQpgYGB7ciBmcmVjdWVuY2lhIG1vZGFsLCBjYWNoZT1UUlVFfQ0KY29sbmFtZXMobWVkRnJlcSkgPC0gYygiQ29kaWdvIiwiZnJlY3VlbmNpYSBtb2RhbCIpDQoNCm1lZEZyZXFbb3JkZXIobWVkRnJlcVssMl0sZGVjcmVhc2luZyA9IFRSVUUpLF0NCmBgYA0KDQpgYGB7ciBwbG90IGRlIGxhIGNsYXNpZmljYWNpw7NuIHN1cGVydmlzYWRhLCBjYWNoZT1UUlVFfQ0KcGFyKG1mcm93PWMoMSwyKSwgY2V4Lm1haW49MC44LCBjZXguYXhpcz0wLjgpDQoNCnBsb3QocnN0TW9kYWxDbGFzcywgbWFpbiA9ICJDbGFzaWZpY2FjacOzbiBTdXBlcnZpc2FkYSBwb3IgYXJib2wgZGUgZGVjaXNpb25lcyIpDQpwbG90KHJzdE1vZGFsQ2xhc3NGcmVxLCBtYWluID0gIkNsYXNlcyBjb24gbWF5b3IgcHJvYmxlbWEgZGUgQ2xhc2lmaWNhY2nDs24iKQ0KDQpteWNvbG9yMSA8LSBjKCIjODA4MDgwIiwiI2ZmMDAwMCIsIiMwMDAwZmYiLCIjMDBmZjAwIiwiI2NiYmViNSIsDQoiI2MzZmY1YiIsICIjZmY3MzczIiwiI2ZlZjY1YiIpDQpwYXIobWZyb3cgPSBjKDEsMSkpDQpwbG90KHJzdE1vZGFsQ2xhc3NGcmVxLCBjb2wgPSByZXYodGVycmFpbi5jb2xvcnMoOCkpLCBtYWluID0gIkxvdGUgY2FjYW8iLCBheGVzPVRSVUUsIHlsYWI9Ik5PUlRFIiwgeGxhYj0gIkVTVEUiKQ0KcGxvdChyc3RNb2RhbENsYXNzLCBtYWluID0gJ0xPVEUgQ0FDQU86IENMQVNJRklDQUNJw5NOIFNVUEVSVklTQURBJywgY29sID0gbXljb2xvcjEgKQ0KDQoNCmBgYA0KDQpgYGB7ciBwbG90IGZpbmFsIHBvciBhcmJvbCBkZSBkZWNpc2lvbmVzLCBjYWNoZT1UUlVFfQ0KY3MgPC0gcGxvdChyc3RNb2RhbENsYXNzLCBtYWluID0gIkNsYXNpZmljYWNpw7NuIFN1cGVydmlzYWRhIHBvciDDoXJib2wgZGUgZGVjaXNpb25lcyIpDQpgYGANCg0KIyMgRElTQ1VTScOTTg0KTG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGVuIGVsIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28gdW5pYmFuZGEgZXZpZGVuY2lhbiBxdWUgc2UgcHJlc2VudGEgdW5hIGFsdGEgY29ycmVsYWNpw7NuIGVudHJlIGxhcyBiYW5kYXMgZGVsIGVzcGVjdHJvIHZpc2libGUgdG9tYWRhcyBwb3IgbGEgY8OhbWFyYSBzaW4gbW9kaWZpY2FyIGNvbiBhZmluaWRhZCBwcm9tZWRpbyBkZWwgODYlLCBtaWVudHJhcyBxdWUgbGEgYmFuZGEgZGVsIE5JUiBxdWUgZnVlIHRvbWFkYSBwb3IgbGEgY8OhbWFyYSBtb2RpZmljYWRhIHByZXNlbnRhIHVuYSBiYWphIGNvcnJlbGFjacOzbiBjb24gbGFzIGRlbcOhcyBjb24gdW4gdmFsb3IgcHJvbWVkaW8gZGUgMzYlLCBlc3RvIHNlIHB1ZWRlIGRlYmVyIGRhZG8gcXVlLCBhbCBwcmVzZW50YXJzZSB1biBjYW1iaW8gZW4gbGFzIGNhcmFjdGVyw61zdGljYXMgcHJvcGlhcyBkZWwgZXF1aXBvIGZvdG9ncsOhZmljbywgcHVlZGUgcHJlc2VudGFyIHkgZ2VuZXJhciBydWlkbyBlbiBkaWNoYSBiYW5kYS4gRXN0b3MgcmVzdWx0YWRvcyBkaWZpZXJlbiBhIGxvcyBwcmVzZW50YWRvcyBwb3IgRmFuIGV0IGFsLiwgKDIwMTgpLCBkb25kZSBhc2VndXJhbiBxdWUgdXRpbGl6YXJvbiB1bmEgY29uZmlndXJhY2nDs24gZGUgc2ltaWxhcmVzIGNhcmFjdGVyw61zdGljYXMgeSBvYnR1dmllcm9uIHVuYSBjb3JyZWxhY2nDs24gZGUgbG9zIGRhdG9zIHByb3ZlbmllbnRlcyBkZSBsYXMgNCBiYW5kYXMsIHByZXZpYSBjYWxpYnJhY2nDs24gY29uIHVuIHBhbmVsIGNvbiByZWZsZWN0YW5jaWEgY29ub2NpZGEuDQoNCkVuIGN1YW50byBhbCDDrW5kaWNlIGVzcGVjdHJhbCBnZW5lcmFkbyBwYXJhIGVzdGUgY2FzbywgZWwgTkRWSSwgc2UgcHJlc2VudGEgdW5hIGNvbmdydWVuY2lhIGNvbiByZXNwZWN0byBhIGxhcyBzdXBlcmZpY2llcyBvIGNvYmVydHVyYXMgcXVlIHNlIHByZXNlbnRhbiBlbiBlbCDDoXJlYSBkZXRlcm1pbmFkYSwgeWEgcXVlIHNlIG9idHV2aWVyb24gdmFsb3JlcyBtZW5vcmVzIGEgMCBlbiBzdXBlcmZpY2llcyBjb21vIHN1ZWxvLCBlc3RydWN0dXJhcyB5IGNvbnN0cnVjY2lvbmVzLCBtaWVudHJhcyBxdWUgbGEgdmVnZXRhY2nDs24gdHV2byB2YWxvcmVzIG1heW9yZXMgYSAwLCBlbiBlc3RlIGNhc28sIGxvcyBwYXN0b3Mgb2J0dXZpZXJvbiB1biB2YWxvciBjZXJjYW5vIGEgMC4yLCBoYWNpZW5kbyDDqW5mYXNpcyBlbiBsYXMgcGxhbnRhcyBhcmLDs3JlYXMgY29tbyBlbCBjYWNhbyB5IGFsZ3Vub3Mgw6FyYm9sZXMgcXVlIHNlIHByZXNlbnRhbiBlbiBsYSB6b25hLCBsb3MgY3VhbGVzIG9idHV2aWVyb24gdmFsb3JlcyBhbHJlZGVkb3IgZGUgMC42IHkgbWF5b3JlcywgZGF0b3MgcXVlIHRpZW5lIHNpbWlsaXR1ZCBhbCBlc3R1ZGlvIHJlYWxpemFkbyBwb3IgT2x1a2F5b2RlIGV0IGFsLiwgKDIwMTgpLCBkb25kZSBldmFsdWFyb24gZWwgZXN0YWRvIGZpc2lvbMOzZ2ljbyBkZSBwbGFudGFzIGRlIGNhY2FvIG1lZGlhbnRlIHNlbnNvcmFtaWVudG8gcmVtb3RvIGNvbiBlbCB1c28gZGUgdW4gZXNwZWN0cm9ycmFkacOzbWV0cm8geSBvYnR1dmllcm9uIGNvbW8gcmVzdWx0YWRvcyBwYXJhIGxhcyBwbGFudGFzIHZhbG9yZXMgZGVsIE5EVkkgZW4gcHJvbWVkaW8gZGUgMC41Lg0KDQpFbiBjdWFudG8gYSBsYSBjbGFzaWZpY2FjacOzbiBubyBzdXBlcnZpc2FkYSwgbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGZ1ZXJvbiBhY2VwdGFibGVzIHlhIHF1ZSBhIGdyYW5kZXMgcmFzZ29zLCBzZSByZWFsaXrDsyBjb24gY2xhcmlkYWQgbGEgZGlzY3JpbWluYWNpw7NuIGVudHJlIGxhcyB6b25hcyBxdWUgcHJlc2VudGFiYW4gdmVnZXRhY2nDs24geSBsYXMgY29uc3RydWNjaW9uZXMgeSBzdWVsbyBkZXNudWRvLCB0ZW5pZW5kbyBlbiBjdWVudGEgcXVlIGFsIGdlbmVyYXIgZWwgcHJvY2VzYW1pZW50byBwb3IgbWVkaW8gZGUgSy1tZWFucyBlbCBjdWFsIHJlYWxpemEgZWwgYWdydXBhbWllbnRvIGVuIGNsw7pzdGVyZXMgcGFydGljaW9uYW5kbyBsYXMgb2JzZXJ2YWNpb25lcyBlbiBLIGFncnVwYWNpb25lcyBlbiBsYXMgcXVlIGNhZGEgcGl4ZWwgcXVlIHBvc2VlIGxhIGltYWdlbiByYXN0ZXIgcGVydGVuZWNlIGEgbGEgYWdydXBhY2nDs24gY29uIGxhIG1lZGlhIG3DoXMgY2VyY2FuYSwgbG8gcXVlIGhhY2UgcXVlIGZ1bmNpb25lcyBjb21vIHByb3RvdGlwbyBkZSBsYSBhZ3J1cGFjacOzbiBxdWUgcmVhbGl6YSBlbCBhbGdvcml0bW8uDQoNCkNvbiByZXNwZWN0byBhIGxhcyBjb2JlcnR1cmFzIHZlZ2V0YWxlcywgZW4gZXNwZWNpYWwgZG9uZGUgc2UgZW5jb250cmFiYW4gbGFzIGVzcGVjaWVzIHBlcmVubmVzLCBlbCBhbGdvcml0bW8gZGUgY2xhc2lmaWNhY2nDs24gbm8gc3VwZXJ2aXNhZGEsIGNhdGFsb2fDsyBjYWRhIHVubyBkZSBsb3MgaW5kaXZpZHVvcyBjb24gdW5hIG1lemNsYSBlbnRyZSBsYXMgY2F0ZWdvcsOtYXMgw4FyYm9sZXMsIGNhY2FvIHkgcGzDoXRhbm8sIHRlbmllbmRvIGVuIGN1ZW50YSBxdWUgZGVwZW5kaWVuZG8gZWwgc29tYnJlYW1pZW50byBxdWUgdGVuw61hIGNhZGEgcGxhbnRhLCBhc2lnbmFiYSBsYSBjYXRlZ29yw61hLCB5IGVuIGFsZ3VuYXMgb2Nhc2lvbmVzIGxvcyBwYXN0b3MgdGFtYmnDqW4gZnVlcm9uIGNhdGFsb2dhZG9zIGVuIGxhcyBjYXRlZ29yw61hcyBkZSB2ZWdldGFjacOzbiwgcG9yIGxvIHF1ZSBlc3RlIHRpcG8gZGUgZGF0b3MgcXVlIHNlIGdlbmVyYW4gY29uIGxhcyBzb21icmFzIGRlIGxvcyBvYmpldG9zIHF1ZSBzZSB0ZW5nYW4gZW4gbGEgZXNjZW5hLCBwdWVkZW4gaW5mbHVlbmNpYXIgbm90b3JpYW1lbnRlIGVuIGxhIGNsYXNpZmljYWNpw7NuIGN1YW5kbyBubyBlcyBzdXBlcnZpc2FkYSwgYWRlbcOhcywgZW4gZXN0ZSBjYXNvIHRlbmllbmRvIGVuIGN1ZW50YSBsYXMgZGlmZXJlbnRlcyBjbGFzZXMgZGUgdmVnZXRhY2lvbmVzIHByZXNlbnRlcyBlbiBlbCBsb3RlIGFuYWxpemFkbywgbm8gZnVlIGFkZWN1YWRhbWVudGUgY2xhc2lmaWNhZG8gaGFjaWVuZG8gZGlzY3JpbWluYWNpw7NuIGVudHJlIGVsbGFzLCBwb3IgbG8gcXVlIGVzdGUgdGlwbyBkZSBjbGFzaWZpY2FjacOzbiwgc2kgYmllbiBjYXJhY3Rlcml6YSBzdXBlcmZpY2llcyBxdWUgc29uIHRvdGFsbWVudGUgZGlmZXJlbnRlcywgbm8gZXMgdGFuIHJvYnVzdG8gcGFyYSBsYSBkaXNjcmltaW5hY2nDs24gZW50cmUgZXNwZWNpZXMgdmVnZXRhbGVzLg0KDQpDb24gcmVsYWNpw7NuIGEgbGEgY2xhc2lmaWNhY2nDs24gc3VwZXJ2aXNhZGEsIGRvbmRlIHNlIHR1dmllcm9uIGVuIGN1ZW50YSB2YXJpYWJsZXMgY29tbyBsYSBleGFjdGl0dWQgKGFjY3VyYWN5KSwgbGEgZXhoYXVzdGl2aWRhZCAoa2FwcGEpIHkgbGEgcHJlY2lzacOzbiBkZSBsYSBjbGFzaWZpY2FjacOzbiAoUFNTKSBwYXJhIGRldGVybWluYXIgbGEgY2FsaWRhZCBxdWUgcHJlc2VudMOzIGVsIHByb2Nlc2FtaWVudG8geSBsYSBjbGFzaWZpY2FjacOzbiwgZG9uZGUgc2UgYW5hbGl6YSBjdWFsIGVzIGxhIHJlbGFjacOzbiBkZSBsYXMgZGlzdHJpYnVjaW9uZXMgZGUgcHJvYmFiaWxpZGFkIGRlIGxhIGNsYXNpZmljYWNpw7NuIGFudGVzIHkgZHVyYW50ZSBlbCBwcm9jZXNhbWllbnRvIGRlbCBldmVudG8gKFNhc3RvcXVlIHkgR3V0acOpcnJleiwgMjAxNiksIHNlIHRpZW5lIGVuIGN1ZW50YSBlbCBhcmNoaXZvIGRlIGVudHJlbmFtaWVudG8gZ2VuZXJhZG8gcHJldmlhbWVudGUgcGFyYSByZWFsaXphciBlc3RhIGNsYXNpZmljYWNpw7NuLCBkZWZpbmllbmRvIHF1ZSBkZWwgdG90YWwgZGUgbXVlc3RyYXMsIHVuIDUwJSBmdWVyYSBkZSBlbnRyZW5hbWllbnRvIHkgZWwgcmVzdGFudGUgZnVlcmEgZGUgdmFsaWRhY2nDs24gZGVsIHByb2Nlc28sIGNhbGN1bGFuZG8gbG9zIHZhbG9yZXMgcHJvbWVkaW8gYSBwYXJ0aXIgZGUgbGEgaW5mb3JtYWNpw7NuIGNhZGEgY2xhc2UgeSBsYXMgZGVzdmlhY2lvbmVzIGVzdMOhbmRhciBlbiBjYWRhIHVuYSBkZSBsYXMgcm9uZGFzIGRlIGl0ZXJhY2nDs24gc29icmUgbG9zIGRhdG9zLCB5IGNvbiBsYXMgdmFyaWFibGVzIHlhIG1lbmNpb25hZGFzLCBzZSBkZXRlcm1pbsOzIGVsIHZhbG9yIEYgcXVlIG5vcyBwZXJtaXRlIG1lZGlyIGxhIHByZWNpc2nDs24gcXVlIHRpZW5lIGxhIGNsYXNpZmljYWNpw7NuLCBwcmV2aWEgZ2VuZXJhY2nDs24gZGUgbGEgbWF0cml6IGRlIGNvbmZ1c2nDs24gZW50cmUgbGFzIGNsYXNlcywgbG8gcXVlIHBlcm1pdGUgbGEgdmlzdWFsaXphY2nDs24gZGVsIGRlc2VtcGXDsW8gZGUgYWxnb3JpdG1vIHF1ZSBzZSBlbXBsZcOzIGVuIGxhIGNsYXNpZmljYWNpw7NuLg0KDQpUZW5pZW5kbyBlbiBjdWVudGEgZXN0YSBpbmZvcm1hY2nDs24sIHkgc2Vnw7puIGxhcyBjYXJhY3RlcsOtc3RpY2FzIHF1ZSBwcmVzZW50YW4gbGFzIHBsYW50YXMgeSBsYSB2ZWdldGFjacOzbiBlbiBnZW5lcmFsLCBwYXJhIGVzdGUgZXN0dWRpbyBubyBlcyBjb252ZW5pZW50ZSByZWFsaXphciBsYSBjYXJhY3Rlcml6YWNpw7NuIHkgZGlzY3JpbWluYWNpw7NuIGRlIHBsYW50YXMgZGUgY2FjYW8gYSBwYXJ0aXIgZGUgbG9zIGRhdG9zIHF1ZSBzZSB0aWVuZW4sIHlhIHF1ZSwgcG9yIGxhIHNpbWlsaXR1ZCBkZSBsYXMgcGxhbnRhcyBhbCBzZXIgZXNwZWNpZXMgbGXDsW9zYXMgcGVyZW5uZXMgZGUgcG9ydGUgYWx0bywgZGUgYWx0YSBmcm9uZG9zaWRhZCB5IG1vcmZvbMOzZ2ljYW1lbnRlIHNpbWlsYXJlcywgbm8gZXMgcG9zaWJsZSBkaWZlcmVuY2lhciBlbnRyZSBsYSBlc3BlY2llIGRlIGludGVyw6lzIHkgbG9zIMOhcmJvbGVzIHByZXNlbnRlIGVuIGxhIGZpbmNhIOKAnGVsIHRyaXVuZm/igJ0uIEVzcGVjdHJhbG1lbnRlIHB1ZWRlbiB0ZW5lciBjYXJhY3RlcsOtc3RpY2FzIHNpbWlsYXJlcyBlbiBsYSByZWdpw7NuIGRlbCBlc3BlY3RybyB2aXNpYmxlIHkgcG9yIGxhIGNhbGlkYWQgZGUgbGFzIGltw6FnZW5lcywgZW4gZXNwZWNpYWwgZW5mYXRpemFuZG8gZW4gbGEgYmFuZGEgTklSLCBzZSBkZWJlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZXN0YSBpbmZvcm1hY2nDs24gZXNwZWN0cmFsIG5vIGxvZ3JhIHBlcmNpYmlyIHkgZGVub3RhciBkaWZlcmVuY2lhcyBxdWUgcG9yIG1lZGlvIGRlIGxvcyBhbGdvcml0bW9zIGFwbGljYWRvcyBwdWVkYW4gZGVzdGFjYXJzZS4NCg0KIyMgQ09OQ0xVU0lPTkVTDQpBdW5xdWUgbG9zIHJlc3VsdGFkb3MgZGVsIGFuw6FsaXNpcyBkZSBsYSBleGhhdXN0aXZpZGFkLCBsYSBleGFjdGl0dWQgeSBkZSBsYSBwcmVjaXNpw7NuIGRlIGxhIGNsYXNpZmljYWNpw7NuIHN1cGVydmlzYWRhIGFycm9qYXJvbiB1biA4NiUgZGUgcHJlY2lzacOzbiwgbG9zIHJlc3VsdGFkb3MgZW4gZ2VuZXJhbCBwcmVzZW50YW4gdW5hIGFjZXB0YWJsZSBkaXNjcmltaW5hY2nDs24gZW50cmUgbGFzIGRpZmVyZW50ZXMgY29iZXJ0dXJhcywgc2luIGVtYmFyZ28gYWwgcmVhbGl6YXIgZWwgYW7DoWxpc2lzIHNvYnJlIGVsIGNhY2FvIGNvbW8gZXNwZWNpZSBkZSBpbnRlcsOpcywgdW4gNDUlIGRlIG11ZXN0cmFzIHF1ZSBmdWVyb24gY2xhc2lmaWNhZGFzIGFjZXJ0YWRhbWVudGUgY29tbyBjYWNhbywgbm8gcGVybWl0ZSBlc3RhYmxlY2VyIHVuIGFsdG8gcmFuZ28gZGUgY29uZmlhbnphIGFsdG8gcGFyYSByZWFsaXphciBsYSBkaXNjcmltaW5hY2nDs24gZGUgZXN0YSBlc3BlY2llIGRlIGludGVyw6lzIGVjb27Ds21pY28geSBzb2NpYWwgcGFyYSBsYSByZWdpw7NuLCBsbyBxdWUgbm8gcGVybWl0aXLDrWEgZ2VuZXJhciB1biBwb3NpYmxlIGNlbnNvIGRlIGVzdGFzIHBsYW50YXMgZGUgbWFuZXJhIGVmaWNpZW50ZSB1dGlsaXphbmRvIGxvcyBkYXRvcyBxdWUgc2UgdHV2aWVyb24gcGFyYSBlc3RlIGVqZXJjaWNpby4NCg0KVGVuaWVuZG8gZW4gY3VlbnRhIGVzdG8sIGVzIHBvc2libGUgcXVlIG1lZGlhbnRlIHVuIGF1bWVudG8gZW4gZWwgbsO6bWVybyBkZSBtdWVzdHJhcyBkZW50cm8gZGVsIGFyY2hpdm8gZGUgZW50cmVuYW1pZW50bywgc2UgcHVlZGEgbWVqb3JhciBlbCBkZXNlbXBlw7FvIGRlIGNsYXNpZmljYWNpw7NuLCBzaW4gZW1iYXJnbywgc2UgZXZpZGVuY2lhIHF1ZSBhbGd1bm9zIGFsZ29yaXRtb3MgdGllbmUgYWxndW5hIGluY2VydGlkdW1icmUgcG9yIGxvIHF1ZSBnZW5lcmEgZGF0b3MgcXVlIHB1ZWRlbiBzZXIgaW5jb3JyZWN0b3MgYWwgbW9tZW50byBkZSBoYWNlciBsYSBjbGFzaWZpY2FjacOzbiwgc3VtYWRvIGEgcXVlIGN1YW5kbyBzZSBtYW5lamEgZ3JhbiB2b2x1bWVuIGRlIGluZm9ybWFjacOzbiwgZWwgcHJvY2VzYW1pZW50byBkZSBlc3RhIHB1ZWRlIHZlcnNlIGxpbWl0YWRvIGEgbGFzIGNhcmFjdGVyw61zdGljYXMgcXVlIHBvc2VhIGVsIGhhcmR3YXJlIGRvbmRlIHNlIHJlYWxpY2UgZWwgcHJvY2VkaW1pZW50bywgcG9yIGxvIHF1ZSBlcyBuZWNlc2FyaW8gcmVjdXJyaXIgYSBlcXVpcG9zIGRlIG1heW9yIGNhcGFjaWRhZCBvIGxpbWl0YXIgZWwgdGFtYcOxbyBkZSBsYXMgaW3DoWdlbmVzIHF1ZSBzZSB0cmFiYWphbiBwb3IgcGFydGUgZGVsIHVzdWFyaW8uDQoNCkFsIGNvbXBhcmFyIGxvcyBkb3MgdGlwb3MgZGUgY2xhc2lmaWNhY2lvbmVzIGVtcGxlYWRhcywgc2UgZXZpZGVuY2lhIHF1ZSBsYSBjbGFzaWZpY2FjacOzbiBzdXBlcnZpc2FkYSBvYnR1dm8gbWVqb3JlcyByZXN1bHRhZG9zIGFsIHJlYWxpemFyIHVuIG1heW9yIMOpbmZhc2lzIGVuIGNhZGEgdW5hIGRlIGxhcyBjbGFzZXMsIGRlZmluaWVuZG8gbWFzIGNsYXJhbWVudGUgbG9zIGxpbWl0ZXMgZGUgeSBib3JkZXMsIGxvIHF1ZSBnZW5lcmEgbWVub3MgZGlzdG9yc2nDs24geSBtw6FzIGNhbGlkYWQgZW4gbG9zIGRhdG9zIG9idGVuaWRvcywgZW4gY29tcGFyYWNpw7NuIGEgbGEgY2xhc2lmaWNhY2nDs24gbm8gc3VwZXJ2aXNhZGEsIGVuIGxhIHF1ZSBzZSBwZXJjaWJlIG1heW9yIGNvbmZ1c2nDs24gYWwgZGVmaW5pciBsYXMgY2xhc2VzIGVuIGxhIHpvbmEgZGUgZXN0dWRpbywgZW4gZXNwZWNpYWwgZW4gbGFzIGNvYmVydHVyYXMgZGUgZXNwZWNpZXMgdmVnZXRhbGVzIGVuIGdlbmVyYWwuDQoNCiMjIFJFRkVSRU5DSUFTDQotIEJvcmRlc2UsIE0uIHkgQWxpbmksIFcuICgyMDA3KS4gYmlPcHM6IHVuIHBhcXVldGUgZGUgcHJvY2VzYW1pZW50byBkZSBpbcOhZ2VuZXMgZW4gUi4gRmFjdWx0YWQgZGUgTWF0ZW3DoXRpY2EsIEFzdHJvbm9tw61hIHkgRsOtc2ljYS4gVW5pdmVyc2lkYWQgTmFjaW9uYWwgZGUgQ8OzcmRvYmEuIEVzcGHDsWEuIA0KLSBEZWwgVG9ybywgTi4sIEdvbcOhcml6LCBGLiwgQ8Ohbm92YXMsIEYuLCBBbG9uc28sIEYuICgyMDE1KS4gQ29tcGFyYWNpw7NuIGRlIG3DqXRvZG9zIGRlIGNsYXNpZmljYWNpw7NuIGRlIGltw6FnZW5lcyBkZSBzYXTDqWxpdGUgZW4gbGEgY3VlbmNhIGRlbCByw61vIGFyZ29zIChyZWdpw7NuIGRlIE11cmNpYSkuIEJvbGV0w61uIGRlIGxhIGFzb2NpYWNpw7NuIGRlIGdlw7NncmFmb3MgZXNwYcOxb2xlcyBObyA2Ny4gUMOhZy4gMzI3LTM0Ny4NCi0gRmFuLCBYLiwgS2F3YW11cmEsIEsuLCBHdW8sIFcuLCBYdWFuLCBULiwgTGltLCBKLiwgWXViYSwgTi4sIEt1cm9rYXdhLCBZLiwgT2JpdHN1LCBULiwgTHYsIFIuLCBUc3VtaXlhbWEsIFkuLCBZYXN1ZGFpLCBULiwgV2FuZ2osIFouICgyMDE4KS4gQSBzaW1wbGUgdmlzaWJsZSBhbmQgbmVhci1pbmZyYXJlZCAoVi1OSVIpIGNhbWVyYSBzeXN0ZW0gZm9yIG1vbml0b3JpbmcgdGhlIGxlYWYgYXJlYSBpbmRleCBhbmQgZ3Jvd3RoIHN0YWdlIG9mIEl0YWxpYW4gcnllZ3Jhc3MuIENvbXB1dGVycyBhbmQgRWxlY3Ryb25pY3MgaW4gQWdyaWN1bHR1cmUuIFZvbHVtZSAxNDQsIHDDoWdpbmFzIDMxNC0zMjMuDQotIE1hY2VkbywgQS4sIFBhamFyZXMsIEcuLCBTYW50b3MsIE0uICgyMDEwKS4gQ2xhc2lmaWNhY2nDs24gbm8gc3VwZXJ2aXNhZGEgY29uIGltw6FnZW5lcyBhIGNvbG9yIGRlIGNvYmVydHVyYSB0ZXJyZXN0cmUuIEFncm9jaWVuY2lhIHZvbC40NCBuby42IE3DqXhpY28uDQotIE9sdWtheW9kZSwgTy4sIE9sYW1pZG90dW4sIEwuLCBSb3RpbWksIEEuLCBBeW9kZWppLCBFLiAoMjAxOCkuIEFzc2Vzc21lbnQgb2YgcGxhbnQgaGVhbHRoIHN0YXR1cyB1c2luZyByZW1vdGUgc2Vuc2luZyBhbmQgR0lTIHRlY2huaXF1ZXMuIFJlc2VhcmNoIEFydGljbGUuIEFkdmFuY2VzIGluIFBsYW50cyAmIEFncmljdWx0dXJlIFJlc2VhcmNoLiBWb2x1bWUgOCBJc3N1ZSA2Lg0KLSBTYXN0b3F1ZSwgTC4geSBHdXRpw6lycmV6LCBGLiAoMjAxNikuIEVzcGFjaWFsaXphY2nDs24gZGVsIGVzdHLDqXMgYmnDs3RpY28gZW4gbG9zIGZyYWlsZWpvbmVzIGRlYmlkbyBhbCBjYW1iaW8gY2xpbcOhdGljbyBlbiBlbCBwYXJxdWUgbmF0dXJhbCBDaGluZ2F6YSBtZWRpYW50ZSBVQVbCtHMuIFByb3llY3RvIGRlIGdyYWRvIGNvbW8gcmVxdWlzaXRvIHBhcmNpYWwgcGFyYSBvcHRhciBhbCB0w610dWxvIGRlIGluZ2VuaWVybyBjYXRhc3RyYWwgeSBnZW9kZXN0YS4gVW5pdmVyc2lkYWQgRGlzdHJpdGFsIEZyYW5jaXNjbyBKb3PDqSBEZSBDYWxkYXMuIEJvZ290w6EuDQo=