Librerias aplicadas

library(caret)
Loading required package: ggplot2
Loading required package: lattice
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)

NA
NA

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 Random Forest

# Definiendo el control del entrenamiento
fitControl <- trainControl(method = "repeatedcv", # repeated cross-validation of the training data
                   number = 10, # number of folds
                   repeats = 5) # view the training iterations


# Entrenamiento con rf
rf_model_roma<- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
                        method = "rf", 
                        metric="Accuracy", 
                        trControl = fitControl,
                        preProcess = c("center", "scale"),
                        tuneLength  = 8)

rf_grid <- expand.grid(mtry=1:20)

rf_model_roma2<- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
                        method = "rf", 
                        metric="Accuracy", 
                        trControl = fitControl,
                        preProcess = c("center", "scale"),
                        tuneGrid = rf_grid)

Exploración del modelo

#Información modelo rf
print(rf_model_roma)
Random Forest 

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, repeated 5 times) 
Summary of sample sizes: 4050, 4054, 4051, 4053, 4053, 4050, ... 
Resampling results across tuning parameters:

  mtry  Accuracy   Kappa    
  2     0.7745059  0.7295556
  3     0.7741051  0.7291448
  4     0.7738406  0.7288910
  5     0.7754840  0.7309457
  6     0.7734405  0.7284506
  7     0.7733511  0.7283656
  8     0.7726836  0.7276080
  9     0.7705513  0.7250804

Accuracy was used to select the optimal model using the largest value.
The final value used for the model was mtry = 5.
print(rf_model_roma$finalModel)

Call:
 randomForest(x = x, y = y, mtry = min(param$mtry, ncol(x))) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 5

        OOB estimate of  error rate: 22.48%
Confusion matrix:
     2  3   5   6   8 10  11  12  14  17 class.error
2  847 12 199  10  14  1   0   0   2   0  0.21935484
3   32 20  15   4   1  0   0   0   0   0  0.72222222
5  206  4 713  54  25  4   1  16  23   0  0.31835564
6   11  2  63 198   0  1   0  42  19   0  0.41071429
8   14  0  38   1 247  0   0   0   4   0  0.18750000
10  11  0   9   3   0 12   0   0   0   0  0.65714286
11   0  0   1   0   0  0 191   5   1   0  0.03535354
12   1  0  35  19   0  1   5 292  35   0  0.24742268
14   0  0  23  15   2  0   0  28 620   0  0.09883721
17   0  0   0   0   0  0   0   0   0 350  0.00000000
#Gráfica del modelo rf
plot(rf_model_roma)


print(rf_model_roma2) #modelo 2
Random Forest 

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, repeated 5 times) 
Summary of sample sizes: 4051, 4049, 4051, 4050, 4052, 4053, ... 
Resampling results across tuning parameters:

  mtry  Accuracy   Kappa    
   1    0.7728575  0.7273050
   2    0.7760999  0.7314324
   3    0.7777427  0.7335153
   4    0.7776546  0.7334634
   5    0.7773410  0.7330797
   6    0.7759660  0.7314695
   7    0.7761865  0.7317788
   8    0.7751712  0.7305626
   9    0.7745039  0.7297882
  10    0.7738802  0.7290222
  11    0.7744128  0.7296807
  12    0.7737875  0.7289090
  13    0.7753915  0.7308690
  14    0.7738345  0.7289740
  15    0.7733431  0.7283518
  16    0.7742819  0.7295094
  17    0.7740562  0.7292300
  18    0.7747702  0.7300851
  19    0.7739248  0.7290817
  20    0.7740556  0.7292078

Accuracy was used to select the optimal model using the largest value.
The final value used for the model was mtry = 3.
print(rf_model_roma2$finalModel)

Call:
 randomForest(x = x, y = y, mtry = min(param$mtry, ncol(x))) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 3

        OOB estimate of  error rate: 22.12%
Confusion matrix:
     2  3   5   6   8 10  11  12  14  17 class.error
2  862 12 183  10  15  1   0   0   2   0  0.20552995
3   38 17  13   4   0  0   0   0   0   0  0.76388889
5  207  3 717  51  23  4   1  16  24   0  0.31453155
6   12  2  56 197   0  1   0  43  25   0  0.41369048
8   12  0  39   1 250  0   0   0   2   0  0.17763158
10  11  0  11   3   0 10   0   0   0   0  0.71428571
11   0  0   1   0   0  0 190   6   1   0  0.04040404
12   1  0  34  17   0  1   4 295  36   0  0.23969072
14   0  0  23  15   1  0   0  31 618   0  0.10174419
17   0  0   0   0   0  0   0   0   0 350  0.00000000
plot(rf_model_roma2) #modelo 2

Evaluación del modelo 1.

pred_rf_model_roma<- predict(rf_model_roma,newdata = eva[,-1])


cm <- confusionMatrix(data = pred_rf_model_roma, as.factor(eva$layer))
cm
Confusion Matrix and Statistics

          Reference
Prediction   2   3   5   6   8  10  11  12  14  17
        2  374  14  77   3   7   2   0   0   1   0
        3    1  14   1   3   0   0   0   0   0   0
        5   85   3 320  19  18  10   1  14   3   0
        6    2   1  23 101   1   1   0   9   6   0
        8    3   0   8   0 105   0   0   0   0   0
        10   0   0   0   0   0   2   0   0   0   0
        11   0   0   0   0   0   0  80   2   0   0
        12   0   0  14  11   0   0   3 122  13   0
        14   1   0   6   7   0   1   2  20 273   0
        17   0   0   0   0   0   0   0   0   0 150

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

Statistics by Class:

                     Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity            0.8026 0.437500   0.7127  0.70139  0.80153  0.125000
Specificity            0.9293 0.997375   0.8972  0.97602  0.99391  1.000000
Pos Pred Value         0.7824 0.736842   0.6765  0.70139  0.90517  1.000000
Neg Pred Value         0.9369 0.990615   0.9119  0.97602  0.98572  0.992765
Prevalence             0.2406 0.016520   0.2318  0.07434  0.06763  0.008260
Detection Rate         0.1931 0.007228   0.1652  0.05214  0.05421  0.001033
Detection Prevalence   0.2468 0.009809   0.2442  0.07434  0.05989  0.001033
Balanced Accuracy      0.8659 0.717438   0.8049  0.83870  0.89772  0.562500
                     Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity            0.93023   0.73054    0.9223   1.00000
Specificity            0.99892   0.97684    0.9775   1.00000
Pos Pred Value         0.97561   0.74847    0.8806   1.00000
Neg Pred Value         0.99677   0.97463    0.9859   1.00000
Prevalence             0.04440   0.08622    0.1528   0.07744
Detection Rate         0.04130   0.06298    0.1409   0.07744
Detection Prevalence   0.04233   0.08415    0.1600   0.07744
Balanced Accuracy      0.96458   0.85369    0.9499   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_rf_model_roma2<- predict(rf_model_roma2,newdata = eva[,-1])


cm <- confusionMatrix(data = pred_rf_model_roma2, as.factor(eva$layer))
cm
Confusion Matrix and Statistics

          Reference
Prediction   2   3   5   6   8  10  11  12  14  17
        2  375  17  78   4   6   2   0   0   2   0
        3    0  11   0   1   0   0   0   0   0   0
        5   85   3 320  21  20  10   1  14   2   0
        6    2   1  24 101   1   1   0  10   4   0
        8    3   0   8   0 104   0   0   0   0   0
        10   0   0   0   0   0   2   0   0   0   0
        11   0   0   0   0   0   0  80   2   0   0
        12   0   0  13  12   0   0   3 120  13   0
        14   1   0   6   5   0   1   2  21 275   0
        17   0   0   0   0   0   0   0   0   0 150

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

Statistics by Class:

                     Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity            0.8047 0.343750   0.7127  0.70139  0.79389  0.125000
Specificity            0.9259 0.999475   0.8952  0.97602  0.99391  1.000000
Pos Pred Value         0.7748 0.916667   0.6723  0.70139  0.90435  1.000000
Neg Pred Value         0.9374 0.989091   0.9117  0.97602  0.98518  0.992765
Prevalence             0.2406 0.016520   0.2318  0.07434  0.06763  0.008260
Detection Rate         0.1936 0.005679   0.1652  0.05214  0.05369  0.001033
Detection Prevalence   0.2499 0.006195   0.2457  0.07434  0.05937  0.001033
Balanced Accuracy      0.8653 0.671613   0.8039  0.83870  0.89390  0.562500
                     Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity            0.93023   0.71856    0.9291   1.00000
Specificity            0.99892   0.97684    0.9781   1.00000
Pos Pred Value         0.97561   0.74534    0.8842   1.00000
Neg Pred Value         0.99677   0.97354    0.9871   1.00000
Prevalence             0.04440   0.08622    0.1528   0.07744
Detection Rate         0.04130   0.06195    0.1420   0.07744
Detection Prevalence   0.04233   0.08312    0.1606   0.07744
Balanced Accuracy      0.96458   0.84770    0.9536   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 del modelo 1.

classi_rf_model_roma <- raster::predict(roma_rst_lan, model=rf_model_roma)
plot(classi_rf_model_roma, main="Clasificación Random Forest Modelo 1",col = cols)

Predicción y visualización del modelo 2.

classi_rf_model_roma2 <- raster::predict(roma_rst_lan, model=rf_model_roma2)
plot(classi_rf_model_roma2, main="Clasificación Random Forest Modelo 2",col = cols)

LS0tCnRpdGxlOiAiQ2xhc2lmaWNhY2nDs24gZGUgaW3DoWdlbmVzIGNvbiBSYW5kb20gRm9yZXN0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIExpYnJlcmlhcyBhcGxpY2FkYXMKCmBgYHtyfQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHJhc3RlcikKYGBgCgojIENhcmdhIGRlIGxhcyBiYW5kYXMgZGUgaW3DoWdlbmVzIHNhdGVsaXRhbGVzLgoKYGBge3J9CmJhbmQxIDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CMS5USUYiKQpiYW5kMiA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjIuVElGIikKYmFuZDMgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IzLlRJRiIpCmJhbmQ0IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNC5USUYiKQpiYW5kNSA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjUuVElGIikKYmFuZDYgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0I2LlRJRiIpCmJhbmQ3IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNy5USUYiKQpiYW5kMTAgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMC5USUYiKQpiYW5kMTEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMS5USUYiKQoKcm9tYV9yc3RfbGFuIDwtIGJyaWNrKGJhbmQxLGJhbmQyLGJhbmQzLGJhbmQ0LGJhbmQ1LGJhbmQ2LGJhbmQ3LGJhbmQxMCxiYW5kMTEpCm5hbWVzKHJvbWFfcnN0X2xhbikgPC0gYyhwYXN0ZSgiQmFuZGEiLDE6NyxzZXA9IiIpLCJCYW5kYTEwIiwiQmFuZGExMSIpCmBgYAoKIyBQcm9jZXNhZG8gZGUgZGF0b3MKCmBgYHtyfQojQ2FyZ2EgZGUgbXVlc3RyYXMgZGUgZW50cmVuYW1pZW50bwpyc3RUcmFpbnJvbWEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL0RhdGFUcmFpbmluZy9yb21lX2xjel9HVC50aWYiKQoKIyBSZW1vdmVyIGNlcm9zIChmb25kbyBOQSkKcnN0VHJhaW5yb21hW3JzdFRyYWlucm9tYT09MF0gPC0gTkEKCiMgQ29udmVydGlyIGEgdGlwbyBkaXNjcmV0bwpyc3RUcmFpbnJvbWEgPC0gcmF0aWZ5KHJzdFRyYWlucm9tYSkKCiMgQ2FtYmlhbW9zIGVsIG5vbWJyZQpuYW1lcyhyc3RUcmFpbnJvbWEpIDwtICJsYXllciIKCiNNdWVzdHJhcyBkZSB2YWxvcmVzCnRhYmxlKHZhbHVlcyhyc3RUcmFpbnJvbWEpKQoKIyBFbGltaW5hY2nDs24gZGUgTkFzIApyc3RERmxhbnJvbWEuZGYgPC0gbmEub21pdCh2YWx1ZXMoc3RhY2socnN0VHJhaW5yb21hLCByb21hX3JzdF9sYW4pKSkKCiMgVml1YWxpemFtb3MgbGFzIG11ZXN0cmFzCmNvbHMgPC0gYygiI2ZkZTcyNSIsIiNiNWRlMmIiLCAiIzZlY2U1OCIsIiMzNWI3NzkiLCAiIzFmOWU4OSIsIiMyNjgyOGUiLCAiIzMxNjg4ZSIsICIjM2U0OTg5IiwgIiM0ODI4NzgiLCAiIzQ0MDE1NCIpCnBsb3QocnN0VHJhaW5yb21hLCBtYWluPSJNdWVzdHJhcyBkZSBlbnRyZW5hbWllbnRvIGRlIFJvbWEiLCBjb2wgPSBjb2xzKQoKCmBgYAoKIyBGYXNlIGRlIENsYXNpZmljYWNpw7NuCgpgYGB7cn0KI1NpIGVzIGxhIHByaW1lcmEgdmV6IHNlIGVqZWN1dGEsIHNpbm8geWEgZXN0YSBndWFyZGFkbyBsb3MgZGF0b3MgZGVsIGRhdGFmcmFtZS4KI3dyaXRlLmNzdihyc3RERmxhbnJvbWEuZGYsInJzdERGUm9tYS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCiNMZWVtb3MgbG9zIGRhdG9zCnNhbXBsZXNMYW5yb21hID0gcmVhZC5jc3YoInJzdERGUm9tYS5jc3YiKQoKIyBTZSBkaXZpZGUgbGFzIG11ZXN0cmFzIGVuIDcwIHkgMzAKdHJhaW54ID0gbGlzdCgwKQpldmFseCA9IGxpc3QoMCkKZm9yIChpIGluIDE6MTcpeyAjIHNlIGl0ZXJhIGVuIHRvZGFzIGxhcyBwb3NpYmxlcyBjYXRlZ29yw61hcwogIGNscyA9IHNhbXBsZXNMYW5yb21hW3NhbXBsZXNMYW5yb21hJGxheWVyID09IGksXQogIHNtcGwgPC0gZmxvb3IoMC43MCAqIG5yb3coY2xzKSkKICB0dCA8LSBzYW1wbGUoc2VxX2xlbihucm93KGNscykpLCBzaXplID0gc21wbCkKICB0cmFpbnhbW2ldXSA8LSBjbHNbdHQsXQogIGV2YWx4W1tpXV0gPC0gY2xzWy10dCxdCn0KCgojIFNlIGNvbWJpbmEgZW4gZGF0YWZyYW1lIHJlZmVyZW5jaWFkb3MgcyBlbnRyZW5hbWllbnRvIHkgZXZhbHVhY2nDs24KdHJuID0gZG8uY2FsbChyYmluZCwgdHJhaW54KSAKZXZhID0gZG8uY2FsbChyYmluZCwgZXZhbHgpCmBgYAoKIyBBbGdvcml0bW8gUmFuZG9tIEZvcmVzdAoKYGBge3J9CiMgRGVmaW5pZW5kbyBlbCBjb250cm9sIGRlbCBlbnRyZW5hbWllbnRvCmZpdENvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgIyByZXBlYXRlZCBjcm9zcy12YWxpZGF0aW9uIG9mIHRoZSB0cmFpbmluZyBkYXRhCiAgICAgICAgICAgICAgICAgICBudW1iZXIgPSAxMCwgIyBudW1iZXIgb2YgZm9sZHMKICAgICAgICAgICAgICAgICAgIHJlcGVhdHMgPSA1KSAjIHZpZXcgdGhlIHRyYWluaW5nIGl0ZXJhdGlvbnMKCgojIEVudHJlbmFtaWVudG8gY29uIHJmCnJmX21vZGVsX3JvbWE8LSBjYXJldDo6dHJhaW4oeCA9IHRyblssKDI6bmNvbCh0cm4pKV0sIHkgPSBhcy5mYWN0b3IodHJuJGxheWVyKSwKICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpYz0iQWNjdXJhY3kiLCAKICAgICAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoImNlbnRlciIsICJzY2FsZSIpLAogICAgICAgICAgICAgICAgICAgICAgICB0dW5lTGVuZ3RoICA9IDgpCgpyZl9ncmlkIDwtIGV4cGFuZC5ncmlkKG10cnk9MToyMCkKCnJmX21vZGVsX3JvbWEyPC0gY2FyZXQ6OnRyYWluKHggPSB0cm5bLCgyOm5jb2wodHJuKSldLCB5ID0gYXMuZmFjdG9yKHRybiRsYXllciksCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsIAogICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWM9IkFjY3VyYWN5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IGZpdENvbnRyb2wsCiAgICAgICAgICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJjZW50ZXIiLCAic2NhbGUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSByZl9ncmlkKQoKYGBgCgojIEV4cGxvcmFjacOzbiBkZWwgbW9kZWxvCgpgYGB7cn0KI0luZm9ybWFjacOzbiBtb2RlbG8gcmYKcHJpbnQocmZfbW9kZWxfcm9tYSkKCnByaW50KHJmX21vZGVsX3JvbWEkZmluYWxNb2RlbCkKCiNHcsOhZmljYSBkZWwgbW9kZWxvIHJmCnBsb3QocmZfbW9kZWxfcm9tYSkKCnByaW50KHJmX21vZGVsX3JvbWEyKSAjbW9kZWxvIDIKCnByaW50KHJmX21vZGVsX3JvbWEyJGZpbmFsTW9kZWwpCgpwbG90KHJmX21vZGVsX3JvbWEyKSAjbW9kZWxvIDIKYGBgCgoKIyBFdmFsdWFjacOzbiBkZWwgbW9kZWxvIDEuCgpgYGB7cn0KcHJlZF9yZl9tb2RlbF9yb21hPC0gcHJlZGljdChyZl9tb2RlbF9yb21hLG5ld2RhdGEgPSBldmFbLC0xXSkKCgpjbSA8LSBjb25mdXNpb25NYXRyaXgoZGF0YSA9IHByZWRfcmZfbW9kZWxfcm9tYSwgYXMuZmFjdG9yKGV2YSRsYXllcikpCmNtCmBgYAoKIyBSZXByZXNlbnRhY2nDs24gZGUgTWF0cml6IGRlIGNvbmZ1c2nDs24KCmBgYHtyfQpjbV9kIDwtIGFzLmRhdGEuZnJhbWUoY20kdGFibGUpCgpjbV9zdCA8LWRhdGEuZnJhbWUoY20kb3ZlcmFsbCkKCmNtX3N0JGNtLm92ZXJhbGwgPC0gcm91bmQoY21fc3QkY20ub3ZlcmFsbCwyKQoKY21fcCA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUoY20kdGFibGUpKQpjbV9kJFBlcmMgPC0gcm91bmQoY21fcCRGcmVxKjEwMCwyKQoKIyBkaWJ1amFuZG8gbGEgbWF0cml6CmdncGxvdChkYXRhID0gY21fZCwgYWVzKHggPSBQcmVkaWN0aW9uICwgeSA9ICBSZWZlcmVuY2UsIGZpbGwgPSBGcmVxKSkrCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIiwgbHdkID0gMC41KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCIiLEZyZXEpKSwgY29sb3IgPSAnd2hpdGUnLCBzaXplID0gMy41KSsgCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZ3RpdGxlKCJNYXRyaXogZGUgQ29uZnVzacOzbiIpCmBgYAoKIyBFdmFsdWFjacOzbiBkZWwgbW9kZWxvIDIKCmBgYHtyfQpwcmVkX3JmX21vZGVsX3JvbWEyPC0gcHJlZGljdChyZl9tb2RlbF9yb21hMixuZXdkYXRhID0gZXZhWywtMV0pCgoKY20gPC0gY29uZnVzaW9uTWF0cml4KGRhdGEgPSBwcmVkX3JmX21vZGVsX3JvbWEyLCBhcy5mYWN0b3IoZXZhJGxheWVyKSkKY20KYGBgCgojIFJlcHJlc2VudGFjacOzbiBkZSBNYXRyaXogZGUgY29uZnVzacOzbgoKYGBge3J9CmNtX2QgPC0gYXMuZGF0YS5mcmFtZShjbSR0YWJsZSkKCmNtX3N0IDwtZGF0YS5mcmFtZShjbSRvdmVyYWxsKQoKY21fc3QkY20ub3ZlcmFsbCA8LSByb3VuZChjbV9zdCRjbS5vdmVyYWxsLDIpCgpjbV9wIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZShjbSR0YWJsZSkpCmNtX2QkUGVyYyA8LSByb3VuZChjbV9wJEZyZXEqMTAwLDIpCgojIGRpYnVqYW5kbyBsYSBtYXRyaXoKZ2dwbG90KGRhdGEgPSBjbV9kLCBhZXMoeCA9IFByZWRpY3Rpb24gLCB5ID0gIFJlZmVyZW5jZSwgZmlsbCA9IEZyZXEpKSsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiLCBsd2QgPSAwLjUpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUoIiIsRnJlcSkpLCBjb2xvciA9ICd3aGl0ZScsIHNpemUgPSAzLjUpKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIGdndGl0bGUoIk1hdHJpeiBkZSBDb25mdXNpw7NuIikKYGBgCgojIFByZWRpY2Npw7NuIHkgdmlzdWFsaXphY2nDs24gZGVsIG1vZGVsbyAxLgoKYGBge3J9CmNsYXNzaV9yZl9tb2RlbF9yb21hIDwtIHJhc3Rlcjo6cHJlZGljdChyb21hX3JzdF9sYW4sIG1vZGVsPXJmX21vZGVsX3JvbWEpCnBsb3QoY2xhc3NpX3JmX21vZGVsX3JvbWEsIG1haW49IkNsYXNpZmljYWNpw7NuIFJhbmRvbSBGb3Jlc3QgTW9kZWxvIDEiLGNvbCA9IGNvbHMpCmBgYAojIFByZWRpY2Npw7NuIHkgdmlzdWFsaXphY2nDs24gZGVsIG1vZGVsbyAyLgoKYGBge3J9CmNsYXNzaV9yZl9tb2RlbF9yb21hMiA8LSByYXN0ZXI6OnByZWRpY3Qocm9tYV9yc3RfbGFuLCBtb2RlbD1yZl9tb2RlbF9yb21hMikKcGxvdChjbGFzc2lfcmZfbW9kZWxfcm9tYTIsIG1haW49IkNsYXNpZmljYWNpw7NuIFJhbmRvbSBGb3Jlc3QgTW9kZWxvIDIiLGNvbCA9IGNvbHMpCmBgYAoKCg==