Librerias aplicadas

library(caret)
library(raster)

Carga de las bandas de imágenes satelitales.

band1 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B1.TIF")
band2 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B2.TIF")
band3 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B3.TIF")
band4 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B4.TIF")
band5 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B5.TIF")
band6 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B6.TIF")
band7 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B7.TIF")
band10 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B10.TIF")
band11 <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/capturas-landsat/roma/LC81910312013208LGN00/LC81910312013208LGN00_B11.TIF")

roma_rst_lan <- brick(band1,band2,band3,band4,band5,band6,band7,band10,band11)
names(roma_rst_lan) <- c(paste("Banda",1:7,sep=""),"Banda10","Banda11")

Procesado de datos

#Carga de muestras de entrenamiento
rstTrainroma <- raster("/Users/elianaalizchuquillanquijulcapari/Documents/workspace-r/demos/DataTraining/rome_lcz_GT.tif")

# Remover ceros (fondo NA)
rstTrainroma[rstTrainroma==0] <- NA

# Convertir a tipo discreto
rstTrainroma <- ratify(rstTrainroma)

# Cambiamos el nombre
names(rstTrainroma) <- "layer"

#Muestras de valores
table(values(rstTrainroma))

   2    3    5    6    8   10   11   12   14   17 
1551  104 1495  480  435   51  284  555  984  500 
# Eliminación de NAs 
rstDFlanroma.df <- na.omit(values(stack(rstTrainroma, roma_rst_lan)))

# Viualizamos las muestras
cols <- c("#fde725","#b5de2b", "#6ece58","#35b779", "#1f9e89","#26828e", "#31688e", "#3e4989", "#482878", "#440154")
plot(rstTrainroma, main="Muestras de entrenamiento de Roma", col = cols)

Fase de Clasificación

#Si es la primera vez se ejecuta, sino ya esta guardado los datos del dataframe.
#write.csv(rstDFlanroma.df,"rstDFRoma.csv", row.names = FALSE)

#Leemos los datos
samplesLanroma = read.csv("rstDFRoma.csv")

# Se divide las muestras en 70 y 30
trainx = list(0)
evalx = list(0)
for (i in 1:17){ # se itera en todas las posibles categorías
  cls = samplesLanroma[samplesLanroma$layer == i,]
  smpl <- floor(0.70 * nrow(cls))
  tt <- sample(seq_len(nrow(cls)), size = smpl)
  trainx[[i]] <- cls[tt,]
  evalx[[i]] <- cls[-tt,]
}


# Se combina en dataframe referenciados s entrenamiento y evaluación
trn = do.call(rbind, trainx) 
eva = do.call(rbind, evalx)

Algoritmo KNN

# Definiendo el control del entrenamiento
fitControl2 <- trainControl(method = "cv", # cross-validation of the training data
                   number = 10)

kknn.grid <- expand.grid(kmax = c(3, 5, 7 ,9, 11), distance = c(1, 2),
                         kernel = "optimal")
# Entrenamiento con Knn
knn_model1<- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
               method = "kknn",
               metric="Accuracy",
               tuneGrid = kknn.grid,
               preProcess = c("center", "scale"),
               trControl = fitControl2)

# Entrenamiento con Knn
knn_model2<- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
               method = "kknn",
               metric="Accuracy",
               tuneLength = 10,
               preProcess = c("center", "scale"),
               trControl = fitControl2)

Exploración del modelo

#Información modelo knn
print(knn_model1)
k-Nearest Neighbors 

4502 samples
   9 predictor
  10 classes: '2', '3', '5', '6', '8', '10', '11', '12', '14', '17' 

Pre-processing: centered (9), scaled (9) 
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 4050, 4053, 4055, 4053, 4052, 4052, ... 
Resampling results across tuning parameters:

  kmax  distance  Accuracy   Kappa    
   3    1         0.7347554  0.6837141
   3    2         0.7342916  0.6833186
   5    1         0.7529774  0.7052921
   5    2         0.7545141  0.7072748
   7    1         0.7598525  0.7131221
   7    2         0.7645113  0.7189057
   9    1         0.7665108  0.7209409
   9    2         0.7693993  0.7245885
  11    1         0.7696280  0.7243541
  11    2         0.7722739  0.7279195

Tuning parameter 'kernel' was held constant at a value of optimal
Accuracy was used to select the optimal model using the largest value.
The final values used for the model were kmax = 11, distance = 2 and kernel = optimal.
print(knn_model2)
k-Nearest Neighbors 

4502 samples
   9 predictor
  10 classes: '2', '3', '5', '6', '8', '10', '11', '12', '14', '17' 

Pre-processing: centered (9), scaled (9) 
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 4051, 4051, 4054, 4054, 4053, 4050, ... 
Resampling results across tuning parameters:

  kmax  Accuracy   Kappa    
   5    0.7527758  0.7051197
   7    0.7596569  0.7130361
   9    0.7638792  0.7178881
  11    0.7661039  0.7204611
  13    0.7696585  0.7245084
  15    0.7729959  0.7283432
  17    0.7729959  0.7283385
  19    0.7729978  0.7283203
  21    0.7729978  0.7283203
  23    0.7725524  0.7277814

Tuning parameter 'distance' was held constant at a value of 2
Tuning parameter 'kernel' was
 held constant at a value of optimal
Accuracy was used to select the optimal model using the largest value.
The final values used for the model were kmax = 21, distance = 2 and kernel = optimal.
#Gráfica del modelo knn
plot(knn_model1)


plot(knn_model2)

Evaluación del modelo 1.

pred_knn_model1<- predict(knn_model1,
                           newdata = eva)

cm <- confusionMatrix(data = pred_knn_model1, as.factor(eva$layer))

cm
Confusion Matrix and Statistics

          Reference
Prediction   2   3   5   6   8  10  11  12  14  17
        2  398   9  54   2   4   9   0   0   0   0
        3    3  21   1   1   0   0   0   0   0   0
        5   54   2 359  14  14   5   0   9   1   0
        6    4   0  14 114   0   0   0   4   7   0
        8    7   0   8   0 113   0   0   0   0   0
        10   0   0   1   0   0   2   0   0   0   0
        11   0   0   2   0   0   0  83   3   0   0
        12   0   0   7   9   0   0   2 138   8   0
        14   0   0   3   4   0   0   1  13 280   0
        17   0   0   0   0   0   0   0   0   0 150

Overall Statistics
                                          
               Accuracy : 0.856           
                 95% CI : (0.8395, 0.8713)
    No Information Rate : 0.2406          
    P-Value [Acc > NIR] : < 2.2e-16       
                                          
                  Kappa : 0.8279          
                                          
 Mcnemar's Test P-Value : NA              

Statistics by Class:

                     Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity            0.8541  0.65625   0.7996  0.79167  0.86260  0.125000
Specificity            0.9470  0.99738   0.9335  0.98383  0.99169  0.999479
Pos Pred Value         0.8361  0.80769   0.7838  0.79720  0.88281  0.666667
Neg Pred Value         0.9535  0.99424   0.9391  0.98328  0.99005  0.992761
Prevalence             0.2406  0.01652   0.2318  0.07434  0.06763  0.008260
Detection Rate         0.2055  0.01084   0.1853  0.05885  0.05834  0.001033
Detection Prevalence   0.2457  0.01342   0.2364  0.07383  0.06608  0.001549
Balanced Accuracy      0.9005  0.82681   0.8665  0.88775  0.92714  0.562240
                     Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity            0.96512   0.82635    0.9459   1.00000
Specificity            0.99730   0.98531    0.9872   1.00000
Pos Pred Value         0.94318   0.84146    0.9302   1.00000
Neg Pred Value         0.99838   0.98364    0.9902   1.00000
Prevalence             0.04440   0.08622    0.1528   0.07744
Detection Rate         0.04285   0.07124    0.1446   0.07744
Detection Prevalence   0.04543   0.08467    0.1554   0.07744
Balanced Accuracy      0.98121   0.90583    0.9666   1.00000

Representación de Matriz de confusión

cm_d <- as.data.frame(cm$table)

cm_st <-data.frame(cm$overall)

cm_st$cm.overall <- round(cm_st$cm.overall,2)

cm_p <- as.data.frame(prop.table(cm$table))
cm_d$Perc <- round(cm_p$Freq*100,2)

# dibujando la matriz
ggplot(data = cm_d, aes(x = Prediction , y =  Reference, fill = Freq))+
  geom_tile(color = "white", lwd = 0.5) +
  geom_text(aes(label = paste("",Freq)), color = 'white', size = 3.5)+ 
  theme_minimal() +
  ggtitle("Matriz de Confusión")

Evaluación del modelo 2.

pred_knn_model2<- predict(knn_model2,
                           newdata = eva)

cm <- confusionMatrix(data = pred_knn_model2, as.factor(eva$layer))

cm
Confusion Matrix and Statistics

          Reference
Prediction   2   3   5   6   8  10  11  12  14  17
        2  395  13  63   1   6   9   0   0   0   0
        3    3  17   2   1   0   0   0   0   0   0
        5   57   2 342  16  20   5   0  11   1   0
        6    4   0  21 111   0   0   0   4   9   0
        8    7   0   9   0 105   1   0   0   0   0
        10   0   0   1   0   0   1   0   0   0   0
        11   0   0   2   0   0   0  83   3   0   0
        12   0   0   7  10   0   0   2 134   8   0
        14   0   0   2   5   0   0   1  15 278   0
        17   0   0   0   0   0   0   0   0   0 150

Overall Statistics
                                         
               Accuracy : 0.8343         
                 95% CI : (0.817, 0.8506)
    No Information Rate : 0.2406         
    P-Value [Acc > NIR] : < 2.2e-16      
                                         
                  Kappa : 0.8018         
                                         
 Mcnemar's Test P-Value : NA             

Statistics by Class:

                     Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity            0.8476 0.531250   0.7617  0.77083  0.80153 0.0625000
Specificity            0.9375 0.996850   0.9247  0.97881  0.99059 0.9994794
Pos Pred Value         0.8111 0.739130   0.7533  0.74497  0.86066 0.5000000
Neg Pred Value         0.9510 0.992163   0.9278  0.98154  0.98567 0.9922481
Prevalence             0.2406 0.016520   0.2318  0.07434  0.06763 0.0082602
Detection Rate         0.2039 0.008776   0.1766  0.05731  0.05421 0.0005163
Detection Prevalence   0.2514 0.011874   0.2344  0.07692  0.06298 0.0010325
Balanced Accuracy      0.8925 0.764050   0.8432  0.87482  0.89606 0.5309897
                     Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity            0.96512   0.80240    0.9392   1.00000
Specificity            0.99730   0.98475    0.9860   1.00000
Pos Pred Value         0.94318   0.83230    0.9236   1.00000
Neg Pred Value         0.99838   0.98142    0.9890   1.00000
Prevalence             0.04440   0.08622    0.1528   0.07744
Detection Rate         0.04285   0.06918    0.1435   0.07744
Detection Prevalence   0.04543   0.08312    0.1554   0.07744
Balanced Accuracy      0.98121   0.89357    0.9626   1.00000

Representación de Matriz de confusión

cm_d <- as.data.frame(cm$table)

cm_st <-data.frame(cm$overall)

cm_st$cm.overall <- round(cm_st$cm.overall,2)

cm_p <- as.data.frame(prop.table(cm$table))
cm_d$Perc <- round(cm_p$Freq*100,2)

# dibujando la matriz
ggplot(data = cm_d, aes(x = Prediction , y =  Reference, fill = Freq))+
  geom_tile(color = "white", lwd = 0.5) +
  geom_text(aes(label = paste("",Freq)), color = 'white', size = 3.5)+ 
  theme_minimal() +
  ggtitle("Matriz de Confusión")

Predicción y visualización Modelo 1.

classi_knn_model1 <- raster::predict(roma_rst_lan, model=knn_model1)
plot(classi_knn_model1, main="Clasificación KNN Modelo 1", col = cols)

Predicción y visualización Modelo 2.

classi_knn_model2 <- raster::predict(roma_rst_lan, model=knn_model2)
plot(classi_knn_model2, main="Clasificación KNN Modelo 2",col = cols)

LS0tCnRpdGxlOiAiQ2xhc2lmaWNhY2nDs24gZGUgaW3DoWdlbmVzIGNvbiBLTk4iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTGlicmVyaWFzIGFwbGljYWRhcwoKYGBge3J9CmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkocmFzdGVyKQpgYGAKCiMgQ2FyZ2EgZGUgbGFzIGJhbmRhcyBkZSBpbcOhZ2VuZXMgc2F0ZWxpdGFsZXMuCgpgYGB7cn0KYmFuZDEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxLlRJRiIpCmJhbmQyIDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CMi5USUYiKQpiYW5kMyA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjMuVElGIikKYmFuZDQgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0I0LlRJRiIpCmJhbmQ1IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNS5USUYiKQpiYW5kNiA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjYuVElGIikKYmFuZDcgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0I3LlRJRiIpCmJhbmQxMCA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjEwLlRJRiIpCmJhbmQxMSA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjExLlRJRiIpCgpyb21hX3JzdF9sYW4gPC0gYnJpY2soYmFuZDEsYmFuZDIsYmFuZDMsYmFuZDQsYmFuZDUsYmFuZDYsYmFuZDcsYmFuZDEwLGJhbmQxMSkKbmFtZXMocm9tYV9yc3RfbGFuKSA8LSBjKHBhc3RlKCJCYW5kYSIsMTo3LHNlcD0iIiksIkJhbmRhMTAiLCJCYW5kYTExIikKYGBgCgojIFByb2Nlc2FkbyBkZSBkYXRvcwoKYGBge3J9CiNDYXJnYSBkZSBtdWVzdHJhcyBkZSBlbnRyZW5hbWllbnRvCnJzdFRyYWlucm9tYSA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvRGF0YVRyYWluaW5nL3JvbWVfbGN6X0dULnRpZiIpCgojIFJlbW92ZXIgY2Vyb3MgKGZvbmRvIE5BKQpyc3RUcmFpbnJvbWFbcnN0VHJhaW5yb21hPT0wXSA8LSBOQQoKIyBDb252ZXJ0aXIgYSB0aXBvIGRpc2NyZXRvCnJzdFRyYWlucm9tYSA8LSByYXRpZnkocnN0VHJhaW5yb21hKQoKIyBDYW1iaWFtb3MgZWwgbm9tYnJlCm5hbWVzKHJzdFRyYWlucm9tYSkgPC0gImxheWVyIgoKI011ZXN0cmFzIGRlIHZhbG9yZXMKdGFibGUodmFsdWVzKHJzdFRyYWlucm9tYSkpCgojIEVsaW1pbmFjacOzbiBkZSBOQXMgCnJzdERGbGFucm9tYS5kZiA8LSBuYS5vbWl0KHZhbHVlcyhzdGFjayhyc3RUcmFpbnJvbWEsIHJvbWFfcnN0X2xhbikpKQoKIyBWaXVhbGl6YW1vcyBsYXMgbXVlc3RyYXMKY29scyA8LSBjKCIjZmRlNzI1IiwiI2I1ZGUyYiIsICIjNmVjZTU4IiwiIzM1Yjc3OSIsICIjMWY5ZTg5IiwiIzI2ODI4ZSIsICIjMzE2ODhlIiwgIiMzZTQ5ODkiLCAiIzQ4Mjg3OCIsICIjNDQwMTU0IikKcGxvdChyc3RUcmFpbnJvbWEsIG1haW49Ik11ZXN0cmFzIGRlIGVudHJlbmFtaWVudG8gZGUgUm9tYSIsIGNvbCA9IGNvbHMpCgpgYGAKCiMgRmFzZSBkZSBDbGFzaWZpY2FjacOzbgoKYGBge3J9CiNTaSBlcyBsYSBwcmltZXJhIHZleiBzZSBlamVjdXRhLCBzaW5vIHlhIGVzdGEgZ3VhcmRhZG8gbG9zIGRhdG9zIGRlbCBkYXRhZnJhbWUuCiN3cml0ZS5jc3YocnN0REZsYW5yb21hLmRmLCJyc3RERlJvbWEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojTGVlbW9zIGxvcyBkYXRvcwpzYW1wbGVzTGFucm9tYSA9IHJlYWQuY3N2KCJyc3RERlJvbWEuY3N2IikKCiMgU2UgZGl2aWRlIGxhcyBtdWVzdHJhcyBlbiA3MCB5IDMwCnRyYWlueCA9IGxpc3QoMCkKZXZhbHggPSBsaXN0KDApCmZvciAoaSBpbiAxOjE3KXsgIyBzZSBpdGVyYSBlbiB0b2RhcyBsYXMgcG9zaWJsZXMgY2F0ZWdvcsOtYXMKICBjbHMgPSBzYW1wbGVzTGFucm9tYVtzYW1wbGVzTGFucm9tYSRsYXllciA9PSBpLF0KICBzbXBsIDwtIGZsb29yKDAuNzAgKiBucm93KGNscykpCiAgdHQgPC0gc2FtcGxlKHNlcV9sZW4obnJvdyhjbHMpKSwgc2l6ZSA9IHNtcGwpCiAgdHJhaW54W1tpXV0gPC0gY2xzW3R0LF0KICBldmFseFtbaV1dIDwtIGNsc1stdHQsXQp9CgoKIyBTZSBjb21iaW5hIGVuIGRhdGFmcmFtZSByZWZlcmVuY2lhZG9zIHMgZW50cmVuYW1pZW50byB5IGV2YWx1YWNpw7NuCnRybiA9IGRvLmNhbGwocmJpbmQsIHRyYWlueCkgCmV2YSA9IGRvLmNhbGwocmJpbmQsIGV2YWx4KQpgYGAKCiMgQWxnb3JpdG1vIEtOTgoKYGBge3J9CiMgRGVmaW5pZW5kbyBlbCBjb250cm9sIGRlbCBlbnRyZW5hbWllbnRvCmZpdENvbnRyb2wyIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCAjIGNyb3NzLXZhbGlkYXRpb24gb2YgdGhlIHRyYWluaW5nIGRhdGEKICAgICAgICAgICAgICAgICAgIG51bWJlciA9IDEwKQoKa2tubi5ncmlkIDwtIGV4cGFuZC5ncmlkKGttYXggPSBjKDMsIDUsIDcgLDksIDExKSwgZGlzdGFuY2UgPSBjKDEsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAga2VybmVsID0gIm9wdGltYWwiKQojIEVudHJlbmFtaWVudG8gY29uIEtubgprbm5fbW9kZWwxPC0gY2FyZXQ6OnRyYWluKHggPSB0cm5bLCgyOm5jb2wodHJuKSldLCB5ID0gYXMuZmFjdG9yKHRybiRsYXllciksCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJra25uIiwKICAgICAgICAgICAgICAgbWV0cmljPSJBY2N1cmFjeSIsCiAgICAgICAgICAgICAgIHR1bmVHcmlkID0ga2tubi5ncmlkLAogICAgICAgICAgICAgICBwcmVQcm9jZXNzID0gYygiY2VudGVyIiwgInNjYWxlIiksCiAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGZpdENvbnRyb2wyKQoKIyBFbnRyZW5hbWllbnRvIGNvbiBLbm4Ka25uX21vZGVsMjwtIGNhcmV0Ojp0cmFpbih4ID0gdHJuWywoMjpuY29sKHRybikpXSwgeSA9IGFzLmZhY3Rvcih0cm4kbGF5ZXIpLAogICAgICAgICAgICAgICBtZXRob2QgPSAia2tubiIsCiAgICAgICAgICAgICAgIG1ldHJpYz0iQWNjdXJhY3kiLAogICAgICAgICAgICAgICB0dW5lTGVuZ3RoID0gMTAsCiAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJjZW50ZXIiLCAic2NhbGUiKSwKICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbDIpCgpgYGAKCiMgRXhwbG9yYWNpw7NuIGRlbCBtb2RlbG8KCmBgYHtyfQojSW5mb3JtYWNpw7NuIG1vZGVsbyBrbm4KcHJpbnQoa25uX21vZGVsMSkKCnByaW50KGtubl9tb2RlbDIpCgoKI0dyw6FmaWNhIGRlbCBtb2RlbG8ga25uCnBsb3Qoa25uX21vZGVsMSkKCnBsb3Qoa25uX21vZGVsMikKCmBgYAoKIyBFdmFsdWFjacOzbiBkZWwgbW9kZWxvIDEuCgpgYGB7cn0KcHJlZF9rbm5fbW9kZWwxPC0gcHJlZGljdChrbm5fbW9kZWwxLAogICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gZXZhKQoKY20gPC0gY29uZnVzaW9uTWF0cml4KGRhdGEgPSBwcmVkX2tubl9tb2RlbDEsIGFzLmZhY3RvcihldmEkbGF5ZXIpKQoKY20KYGBgCgojIFJlcHJlc2VudGFjacOzbiBkZSBNYXRyaXogZGUgY29uZnVzacOzbgoKYGBge3J9CmNtX2QgPC0gYXMuZGF0YS5mcmFtZShjbSR0YWJsZSkKCmNtX3N0IDwtZGF0YS5mcmFtZShjbSRvdmVyYWxsKQoKY21fc3QkY20ub3ZlcmFsbCA8LSByb3VuZChjbV9zdCRjbS5vdmVyYWxsLDIpCgpjbV9wIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZShjbSR0YWJsZSkpCmNtX2QkUGVyYyA8LSByb3VuZChjbV9wJEZyZXEqMTAwLDIpCgojIGRpYnVqYW5kbyBsYSBtYXRyaXoKZ2dwbG90KGRhdGEgPSBjbV9kLCBhZXMoeCA9IFByZWRpY3Rpb24gLCB5ID0gIFJlZmVyZW5jZSwgZmlsbCA9IEZyZXEpKSsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiLCBsd2QgPSAwLjUpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIiIsRnJlcSkpLCBjb2xvciA9ICd3aGl0ZScsIHNpemUgPSAzLjUpKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIGdndGl0bGUoIk1hdHJpeiBkZSBDb25mdXNpw7NuIikKYGBgCgojIEV2YWx1YWNpw7NuIGRlbCBtb2RlbG8gMi4KCmBgYHtyfQpwcmVkX2tubl9tb2RlbDI8LSBwcmVkaWN0KGtubl9tb2RlbDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBldmEpCgpjbSA8LSBjb25mdXNpb25NYXRyaXgoZGF0YSA9IHByZWRfa25uX21vZGVsMiwgYXMuZmFjdG9yKGV2YSRsYXllcikpCgpjbQpgYGAKCiMgUmVwcmVzZW50YWNpw7NuIGRlIE1hdHJpeiBkZSBjb25mdXNpw7NuCgpgYGB7cn0KY21fZCA8LSBhcy5kYXRhLmZyYW1lKGNtJHRhYmxlKQoKY21fc3QgPC1kYXRhLmZyYW1lKGNtJG92ZXJhbGwpCgpjbV9zdCRjbS5vdmVyYWxsIDwtIHJvdW5kKGNtX3N0JGNtLm92ZXJhbGwsMikKCmNtX3AgPC0gYXMuZGF0YS5mcmFtZShwcm9wLnRhYmxlKGNtJHRhYmxlKSkKY21fZCRQZXJjIDwtIHJvdW5kKGNtX3AkRnJlcSoxMDAsMikKCiMgZGlidWphbmRvIGxhIG1hdHJpegpnZ3Bsb3QoZGF0YSA9IGNtX2QsIGFlcyh4ID0gUHJlZGljdGlvbiAsIHkgPSAgUmVmZXJlbmNlLCBmaWxsID0gRnJlcSkpKwogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIsIGx3ZCA9IDAuNSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgiIixGcmVxKSksIGNvbG9yID0gJ3doaXRlJywgc2l6ZSA9IDMuNSkrIAogIHRoZW1lX21pbmltYWwoKSArCiAgZ2d0aXRsZSgiTWF0cml6IGRlIENvbmZ1c2nDs24iKQpgYGAKCiMgUHJlZGljY2nDs24geSB2aXN1YWxpemFjacOzbiBNb2RlbG8gMS4KCmBgYHtyfQpjbGFzc2lfa25uX21vZGVsMSA8LSByYXN0ZXI6OnByZWRpY3Qocm9tYV9yc3RfbGFuLCBtb2RlbD1rbm5fbW9kZWwxKQpwbG90KGNsYXNzaV9rbm5fbW9kZWwxLCBtYWluPSJDbGFzaWZpY2FjacOzbiBLTk4gTW9kZWxvIDEiLCBjb2wgPSBjb2xzKQpgYGAKIyBQcmVkaWNjacOzbiB5IHZpc3VhbGl6YWNpw7NuIE1vZGVsbyAyLgoKYGBge3J9CmNsYXNzaV9rbm5fbW9kZWwyIDwtIHJhc3Rlcjo6cHJlZGljdChyb21hX3JzdF9sYW4sIG1vZGVsPWtubl9tb2RlbDIpCnBsb3QoY2xhc3NpX2tubl9tb2RlbDIsIG1haW49IkNsYXNpZmljYWNpw7NuIEtOTiBNb2RlbG8gMiIsY29sID0gY29scykKYGBgCgoK