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 Redes neuronales
# Definiendo el control del entrenamiento
fitControl <- trainControl(method = "repeatedcv", # repeated cross-validation of the training data
number = 10, # number of folds
repeats = 3) # view the training iterations
# Entrenamiento con Redes Neuronales
nnet_grid <- expand.grid(size = c(5, 10, 15),
decay = c(0.001, 0.01, 0.1))
nnet_model_roma <- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
method = "nnet", metric="Accuracy",
maxit = 100,
tuneGrid = nnet_grid,
preProcess = c("center", "scale"),
trControl = fitControl,
trace = FALSE)
nnet_grid2 = expand.grid(size = seq(from = 2, to = 10, by = 2),
decay = seq(from = 0.1, to = 0.5, by = 0.1))
nnet_model_roma2 <- caret::train(x = trn[,(2:ncol(trn))], y = as.factor(trn$layer),
method = "nnet", metric="Accuracy",
maxit = 100,
tuneGrid = nnet_grid2,
preProcess = c("center", "scale"),
trControl = fitControl,
trace = FALSE)
Estructura de la red
library(NeuralNetTools)
plotnet(nnet_model_roma$finalModel)

#modelo 2
plotnet(nnet_model_roma2$finalModel)

Exploración del modelo
#Información modelo nnet
print(nnet_model_roma)
Neural Network
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 3 times)
Summary of sample sizes: 4051, 4052, 4054, 4050, 4052, 4052, ...
Resampling results across tuning parameters:
size decay Accuracy Kappa
5 0.001 0.7892113 0.7474936
5 0.010 0.7864620 0.7441364
5 0.100 0.7852068 0.7422215
10 0.001 0.8109036 0.7739284
10 0.010 0.8115595 0.7747506
10 0.100 0.8074964 0.7697054
15 0.001 0.8173485 0.7818004
15 0.010 0.8158028 0.7799476
15 0.100 0.8162342 0.7802712
Accuracy was used to select the optimal model using the largest value.
The final values used for the model were size = 15 and decay = 0.001.
print(nnet_model_roma2)
Neural Network
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 3 times)
Summary of sample sizes: 4051, 4052, 4052, 4051, 4053, 4052, ...
Resampling results across tuning parameters:
size decay Accuracy Kappa
2 0.1 0.7056884 0.6428292
2 0.2 0.7033307 0.6397061
2 0.3 0.6973017 0.6317135
2 0.4 0.7033842 0.6392924
2 0.5 0.6879770 0.6189391
4 0.1 0.7688343 0.7222316
4 0.2 0.7647635 0.7172468
4 0.3 0.7568483 0.7073791
4 0.4 0.7555907 0.7056245
4 0.5 0.7553609 0.7054173
6 0.1 0.7941506 0.7533604
6 0.2 0.7902373 0.7484191
6 0.3 0.7884554 0.7461338
6 0.4 0.7871946 0.7446072
6 0.5 0.7837177 0.7402162
8 0.1 0.8028976 0.7641201
8 0.2 0.7968212 0.7564817
8 0.3 0.7931874 0.7519018
8 0.4 0.7923107 0.7507579
8 0.5 0.7917109 0.7499887
10 0.1 0.8051750 0.7668082
10 0.2 0.8014789 0.7621894
10 0.3 0.7974046 0.7571338
10 0.4 0.7968178 0.7562008
10 0.5 0.7928177 0.7512634
Accuracy was used to select the optimal model using the largest value.
The final values used for the model were size = 10 and decay = 0.1.
#Gráfica del modelo nnet
plot(nnet_model_roma)

plot(nnet_model_roma2)

Evaluación del modelo 1.
pred_nnet_model_roma<- predict(nnet_model_roma,
newdata = eva)
cm <- confusionMatrix(data = pred_nnet_model_roma, as.factor(eva$layer))
cm
Confusion Matrix and Statistics
Reference
Prediction 2 3 5 6 8 10 11 12 14 17
2 376 13 79 4 3 2 0 0 0 0
3 4 13 3 2 0 0 0 0 0 0
5 80 3 321 28 10 8 1 8 1 0
6 3 3 22 99 0 0 1 3 3 0
8 2 0 9 0 117 1 0 0 0 0
10 0 0 0 0 0 4 0 0 0 0
11 0 0 0 0 0 0 80 2 0 0
12 0 0 10 5 0 0 4 146 6 0
14 1 0 5 6 1 1 0 8 286 0
17 0 0 0 0 0 0 0 0 0 150
Overall Statistics
Accuracy : 0.8219
95% CI : (0.8041, 0.8387)
No Information Rate : 0.2406
P-Value [Acc > NIR] : < 2.2e-16
Kappa : 0.787
Mcnemar's Test P-Value : NA
Statistics by Class:
Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity 0.8069 0.406250 0.7149 0.68750 0.89313 0.250000
Specificity 0.9313 0.995276 0.9066 0.98048 0.99336 1.000000
Pos Pred Value 0.7883 0.590909 0.6978 0.73881 0.90698 1.000000
Neg Pred Value 0.9384 0.990078 0.9133 0.97504 0.99226 0.993792
Prevalence 0.2406 0.016520 0.2318 0.07434 0.06763 0.008260
Detection Rate 0.1941 0.006711 0.1657 0.05111 0.06040 0.002065
Detection Prevalence 0.2463 0.011358 0.2375 0.06918 0.06660 0.002065
Balanced Accuracy 0.8691 0.700763 0.8108 0.83399 0.94324 0.625000
Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity 0.93023 0.87425 0.9662 1.00000
Specificity 0.99892 0.98588 0.9866 1.00000
Pos Pred Value 0.97561 0.85380 0.9286 1.00000
Neg Pred Value 0.99677 0.98811 0.9939 1.00000
Prevalence 0.04440 0.08622 0.1528 0.07744
Detection Rate 0.04130 0.07537 0.1477 0.07744
Detection Prevalence 0.04233 0.08828 0.1590 0.07744
Balanced Accuracy 0.96458 0.93006 0.9764 1.00000
Matriz de confusión modelo 1
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_nnet_model_roma2<- predict(nnet_model_roma2,
newdata = eva)
cm <- confusionMatrix(data = pred_nnet_model_roma2, as.factor(eva$layer))
cm
Confusion Matrix and Statistics
Reference
Prediction 2 3 5 6 8 10 11 12 14 17
2 394 13 91 3 4 2 0 0 0 0
3 1 14 2 6 0 0 0 0 0 0
5 66 2 313 27 12 7 2 12 3 0
6 3 3 19 95 1 0 0 1 4 0
8 2 0 10 0 113 0 0 0 0 0
10 0 0 1 0 1 5 0 0 0 0
11 0 0 1 0 0 0 79 3 0 0
12 0 0 5 9 0 0 4 136 11 0
14 0 0 7 4 0 2 1 15 278 0
17 0 0 0 0 0 0 0 0 0 150
Overall Statistics
Accuracy : 0.8141
95% CI : (0.7961, 0.8312)
No Information Rate : 0.2406
P-Value [Acc > NIR] : < 2.2e-16
Kappa : 0.7774
Mcnemar's Test P-Value : NA
Statistics by Class:
Class: 2 Class: 3 Class: 5 Class: 6 Class: 8 Class: 10
Sensitivity 0.8455 0.437500 0.6971 0.65972 0.86260 0.312500
Specificity 0.9232 0.995276 0.9120 0.98271 0.99336 0.998959
Pos Pred Value 0.7771 0.608696 0.7050 0.75397 0.90400 0.714286
Neg Pred Value 0.9497 0.990596 0.9089 0.97294 0.99007 0.994301
Prevalence 0.2406 0.016520 0.2318 0.07434 0.06763 0.008260
Detection Rate 0.2034 0.007228 0.1616 0.04904 0.05834 0.002581
Detection Prevalence 0.2617 0.011874 0.2292 0.06505 0.06453 0.003614
Balanced Accuracy 0.8843 0.716388 0.8045 0.82122 0.92798 0.655729
Class: 11 Class: 12 Class: 14 Class: 17
Sensitivity 0.91860 0.81437 0.9392 1.00000
Specificity 0.99784 0.98362 0.9823 1.00000
Pos Pred Value 0.95181 0.82424 0.9055 1.00000
Neg Pred Value 0.99622 0.98251 0.9890 1.00000
Prevalence 0.04440 0.08622 0.1528 0.07744
Detection Rate 0.04078 0.07021 0.1435 0.07744
Detection Prevalence 0.04285 0.08518 0.1585 0.07744
Balanced Accuracy 0.95822 0.89899 0.9608 1.00000
Matriz de confusión modelo 2
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_nnet_model_roma <- raster::predict(roma_rst_lan, model=nnet_model_roma)
plot(classi_nnet_model_roma, main="Clasificación Redes neuronales Modelo 1",col = cols)

Predicción y visualización Modelo 2.
classi_nnet_model_roma2 <- raster::predict(roma_rst_lan, model=nnet_model_roma2)
plot(classi_nnet_model_roma2, main="Clasificación Redes neuronales Modelo 2", col = cols)

LS0tCnRpdGxlOiAiQ2xhc2lmaWNhY2nDs24gZGUgaW3DoWdlbmVzIGNvbiBSZWRlcyBOZXVyb25hbGVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIExpYnJlcmlhcyBhcGxpY2FkYXMKCmBgYHtyfQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHJhc3RlcikKYGBgCgojIENhcmdhIGRlIGxhcyBiYW5kYXMgZGUgaW3DoWdlbmVzIHNhdGVsaXRhbGVzLgoKYGBge3J9CmJhbmQxIDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CMS5USUYiKQpiYW5kMiA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjIuVElGIikKYmFuZDMgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IzLlRJRiIpCmJhbmQ0IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNC5USUYiKQpiYW5kNSA8LSByYXN0ZXIoIi9Vc2Vycy9lbGlhbmFhbGl6Y2h1cXVpbGxhbnF1aWp1bGNhcGFyaS9Eb2N1bWVudHMvd29ya3NwYWNlLXIvZGVtb3MvY2FwdHVyYXMtbGFuZHNhdC9yb21hL0xDODE5MTAzMTIwMTMyMDhMR04wMC9MQzgxOTEwMzEyMDEzMjA4TEdOMDBfQjUuVElGIikKYmFuZDYgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0I2LlRJRiIpCmJhbmQ3IDwtIHJhc3RlcigiL1VzZXJzL2VsaWFuYWFsaXpjaHVxdWlsbGFucXVpanVsY2FwYXJpL0RvY3VtZW50cy93b3Jrc3BhY2Utci9kZW1vcy9jYXB0dXJhcy1sYW5kc2F0L3JvbWEvTEM4MTkxMDMxMjAxMzIwOExHTjAwL0xDODE5MTAzMTIwMTMyMDhMR04wMF9CNy5USUYiKQpiYW5kMTAgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMC5USUYiKQpiYW5kMTEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL2NhcHR1cmFzLWxhbmRzYXQvcm9tYS9MQzgxOTEwMzEyMDEzMjA4TEdOMDAvTEM4MTkxMDMxMjAxMzIwOExHTjAwX0IxMS5USUYiKQoKcm9tYV9yc3RfbGFuIDwtIGJyaWNrKGJhbmQxLGJhbmQyLGJhbmQzLGJhbmQ0LGJhbmQ1LGJhbmQ2LGJhbmQ3LGJhbmQxMCxiYW5kMTEpCm5hbWVzKHJvbWFfcnN0X2xhbikgPC0gYyhwYXN0ZSgiQmFuZGEiLDE6NyxzZXA9IiIpLCJCYW5kYTEwIiwiQmFuZGExMSIpCmBgYAoKIyBQcm9jZXNhZG8gZGUgZGF0b3MKCmBgYHtyfQojQ2FyZ2EgZGUgbXVlc3RyYXMgZGUgZW50cmVuYW1pZW50bwpyc3RUcmFpbnJvbWEgPC0gcmFzdGVyKCIvVXNlcnMvZWxpYW5hYWxpemNodXF1aWxsYW5xdWlqdWxjYXBhcmkvRG9jdW1lbnRzL3dvcmtzcGFjZS1yL2RlbW9zL0RhdGFUcmFpbmluZy9yb21lX2xjel9HVC50aWYiKQoKIyBSZW1vdmVyIGNlcm9zIChmb25kbyBOQSkKcnN0VHJhaW5yb21hW3JzdFRyYWlucm9tYT09MF0gPC0gTkEKCiMgQ29udmVydGlyIGEgdGlwbyBkaXNjcmV0bwpyc3RUcmFpbnJvbWEgPC0gcmF0aWZ5KHJzdFRyYWlucm9tYSkKCiMgQ2FtYmlhbW9zIGVsIG5vbWJyZQpuYW1lcyhyc3RUcmFpbnJvbWEpIDwtICJsYXllciIKCiNNdWVzdHJhcyBkZSB2YWxvcmVzCnRhYmxlKHZhbHVlcyhyc3RUcmFpbnJvbWEpKQoKIyBFbGltaW5hY2nDs24gZGUgTkFzIApyc3RERmxhbnJvbWEuZGYgPC0gbmEub21pdCh2YWx1ZXMoc3RhY2socnN0VHJhaW5yb21hLCByb21hX3JzdF9sYW4pKSkKCiMgVml1YWxpemFtb3MgbGFzIG11ZXN0cmFzCmNvbHMgPC0gYygiI2ZkZTcyNSIsIiNiNWRlMmIiLCAiIzZlY2U1OCIsIiMzNWI3NzkiLCAiIzFmOWU4OSIsIiMyNjgyOGUiLCAiIzMxNjg4ZSIsICIjM2U0OTg5IiwgIiM0ODI4NzgiLCAiIzQ0MDE1NCIpCnBsb3QocnN0VHJhaW5yb21hLCBtYWluPSJNdWVzdHJhcyBkZSBlbnRyZW5hbWllbnRvIGRlIFJvbWEiLCBjb2wgPSBjb2xzKQoKYGBgCgojIEZhc2UgZGUgQ2xhc2lmaWNhY2nDs24KCmBgYHtyfQojU2kgZXMgbGEgcHJpbWVyYSB2ZXogc2UgZWplY3V0YSwgc2lubyB5YSBlc3RhIGd1YXJkYWRvIGxvcyBkYXRvcyBkZWwgZGF0YWZyYW1lLgp3cml0ZS5jc3YocnN0REZsYW5yb21hLmRmLCJyc3RERlJvbWEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgojTGVlbW9zIGxvcyBkYXRvcwpzYW1wbGVzTGFucm9tYSA9IHJlYWQuY3N2KCJyc3RERlJvbWEuY3N2IikKCiMgU2UgZGl2aWRlIGxhcyBtdWVzdHJhcyBlbiA3MCB5IDMwCnRyYWlueCA9IGxpc3QoMCkKZXZhbHggPSBsaXN0KDApCmZvciAoaSBpbiAxOjE3KXsgIyBzZSBpdGVyYSBlbiB0b2RhcyBsYXMgcG9zaWJsZXMgY2F0ZWdvcsOtYXMKICBjbHMgPSBzYW1wbGVzTGFucm9tYVtzYW1wbGVzTGFucm9tYSRsYXllciA9PSBpLF0KICBzbXBsIDwtIGZsb29yKDAuNzAgKiBucm93KGNscykpCiAgdHQgPC0gc2FtcGxlKHNlcV9sZW4obnJvdyhjbHMpKSwgc2l6ZSA9IHNtcGwpCiAgdHJhaW54W1tpXV0gPC0gY2xzW3R0LF0KICBldmFseFtbaV1dIDwtIGNsc1stdHQsXQp9CgoKIyBTZSBjb21iaW5hIGVuIGRhdGFmcmFtZSByZWZlcmVuY2lhZG9zIHMgZW50cmVuYW1pZW50byB5IGV2YWx1YWNpw7NuCnRybiA9IGRvLmNhbGwocmJpbmQsIHRyYWlueCkgCmV2YSA9IGRvLmNhbGwocmJpbmQsIGV2YWx4KQpgYGAKCiMgQWxnb3JpdG1vIFJlZGVzIG5ldXJvbmFsZXMKCmBgYHtyfQojIERlZmluaWVuZG8gZWwgY29udHJvbCBkZWwgZW50cmVuYW1pZW50bwpmaXRDb250cm9sIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAicmVwZWF0ZWRjdiIsICMgcmVwZWF0ZWQgY3Jvc3MtdmFsaWRhdGlvbiBvZiB0aGUgdHJhaW5pbmcgZGF0YQogICAgICAgICAgICAgICAgICAgbnVtYmVyID0gMTAsICMgbnVtYmVyIG9mIGZvbGRzCiAgICAgICAgICAgICAgICAgICByZXBlYXRzID0gMykgIyB2aWV3IHRoZSB0cmFpbmluZyBpdGVyYXRpb25zCgoKIyBFbnRyZW5hbWllbnRvIGNvbiBSZWRlcyBOZXVyb25hbGVzCm5uZXRfZ3JpZCA8LSBleHBhbmQuZ3JpZChzaXplID0gYyg1LCAxMCwgMTUpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGVjYXkgPSBjKDAuMDAxLCAwLjAxLCAwLjEpKQoKbm5ldF9tb2RlbF9yb21hIDwtIGNhcmV0Ojp0cmFpbih4ID0gdHJuWywoMjpuY29sKHRybikpXSwgeSA9IGFzLmZhY3Rvcih0cm4kbGF5ZXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIm5uZXQiLCBtZXRyaWM9IkFjY3VyYWN5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhpdCA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR1bmVHcmlkID0gbm5ldF9ncmlkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoImNlbnRlciIsICJzY2FsZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCgpubmV0X2dyaWQyID0gZXhwYW5kLmdyaWQoc2l6ZSA9IHNlcShmcm9tID0gMiwgdG8gPSAxMCwgYnkgPSAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGRlY2F5ID0gc2VxKGZyb20gPSAwLjEsIHRvID0gMC41LCBieSA9IDAuMSkpCgpubmV0X21vZGVsX3JvbWEyIDwtIGNhcmV0Ojp0cmFpbih4ID0gdHJuWywoMjpuY29sKHRybikpXSwgeSA9IGFzLmZhY3Rvcih0cm4kbGF5ZXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIm5uZXQiLCBtZXRyaWM9IkFjY3VyYWN5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGl0ID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSBubmV0X2dyaWQyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoImNlbnRlciIsICJzY2FsZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gZml0Q29udHJvbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UpCgpgYGAKCiMgRXN0cnVjdHVyYSBkZSBsYSByZWQKCmBgYHtyfQpsaWJyYXJ5KE5ldXJhbE5ldFRvb2xzKQpwbG90bmV0KG5uZXRfbW9kZWxfcm9tYSRmaW5hbE1vZGVsKQoKI21vZGVsbyAyCnBsb3RuZXQobm5ldF9tb2RlbF9yb21hMiRmaW5hbE1vZGVsKQpgYGAKCiMgRXhwbG9yYWNpw7NuIGRlbCBtb2RlbG8KCmBgYHtyfQojSW5mb3JtYWNpw7NuIG1vZGVsbyBubmV0CnByaW50KG5uZXRfbW9kZWxfcm9tYSkKCnByaW50KG5uZXRfbW9kZWxfcm9tYTIpCgojR3LDoWZpY2EgZGVsIG1vZGVsbyBubmV0CnBsb3Qobm5ldF9tb2RlbF9yb21hKQoKcGxvdChubmV0X21vZGVsX3JvbWEyKQpgYGAKCiMgRXZhbHVhY2nDs24gZGVsIG1vZGVsbyAxLgoKYGBge3J9CnByZWRfbm5ldF9tb2RlbF9yb21hPC0gcHJlZGljdChubmV0X21vZGVsX3JvbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBldmEpCgpjbSA8LSBjb25mdXNpb25NYXRyaXgoZGF0YSA9IHByZWRfbm5ldF9tb2RlbF9yb21hLCBhcy5mYWN0b3IoZXZhJGxheWVyKSkKY20KYGBgCgojIE1hdHJpeiBkZSBjb25mdXNpw7NuIG1vZGVsbyAxCgpgYGB7cn0KY21fZCA8LSBhcy5kYXRhLmZyYW1lKGNtJHRhYmxlKQoKY21fc3QgPC1kYXRhLmZyYW1lKGNtJG92ZXJhbGwpCgpjbV9zdCRjbS5vdmVyYWxsIDwtIHJvdW5kKGNtX3N0JGNtLm92ZXJhbGwsMikKCmNtX3AgPC0gYXMuZGF0YS5mcmFtZShwcm9wLnRhYmxlKGNtJHRhYmxlKSkKY21fZCRQZXJjIDwtIHJvdW5kKGNtX3AkRnJlcSoxMDAsMikKCiMgZGlidWphbmRvIGxhIG1hdHJpegpnZ3Bsb3QoZGF0YSA9IGNtX2QsIGFlcyh4ID0gUHJlZGljdGlvbiAsIHkgPSAgUmVmZXJlbmNlLCBmaWxsID0gRnJlcSkpKwogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIsIGx3ZCA9IDAuNSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZSgiIixGcmVxKSksIGNvbG9yID0gJ3doaXRlJywgc2l6ZSA9IDMuNSkrIAogIHRoZW1lX21pbmltYWwoKSArCiAgZ2d0aXRsZSgiTWF0cml6IGRlIENvbmZ1c2nDs24iKQpgYGAKCiMgRXZhbHVhY2nDs24gZGVsIG1vZGVsbyAyCgpgYGB7cn0KcHJlZF9ubmV0X21vZGVsX3JvbWEyPC0gcHJlZGljdChubmV0X21vZGVsX3JvbWEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gZXZhKQoKY20gPC0gY29uZnVzaW9uTWF0cml4KGRhdGEgPSBwcmVkX25uZXRfbW9kZWxfcm9tYTIsIGFzLmZhY3RvcihldmEkbGF5ZXIpKQpjbQpgYGAKCiMgTWF0cml6IGRlIGNvbmZ1c2nDs24gbW9kZWxvIDIKCmBgYHtyfQpjbV9kIDwtIGFzLmRhdGEuZnJhbWUoY20kdGFibGUpCgpjbV9zdCA8LWRhdGEuZnJhbWUoY20kb3ZlcmFsbCkKCmNtX3N0JGNtLm92ZXJhbGwgPC0gcm91bmQoY21fc3QkY20ub3ZlcmFsbCwyKQoKY21fcCA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUoY20kdGFibGUpKQpjbV9kJFBlcmMgPC0gcm91bmQoY21fcCRGcmVxKjEwMCwyKQoKIyBkaWJ1amFuZG8gbGEgbWF0cml6CmdncGxvdChkYXRhID0gY21fZCwgYWVzKHggPSBQcmVkaWN0aW9uICwgeSA9ICBSZWZlcmVuY2UsIGZpbGwgPSBGcmVxKSkrCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIiwgbHdkID0gMC41KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlKCIiLEZyZXEpKSwgY29sb3IgPSAnd2hpdGUnLCBzaXplID0gMy41KSsgCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZ3RpdGxlKCJNYXRyaXogZGUgQ29uZnVzacOzbiIpCmBgYAoKIyBQcmVkaWNjacOzbiB5IHZpc3VhbGl6YWNpw7NuIE1vZGVsbyAxLgoKYGBge3J9CmNsYXNzaV9ubmV0X21vZGVsX3JvbWEgPC0gcmFzdGVyOjpwcmVkaWN0KHJvbWFfcnN0X2xhbiwgbW9kZWw9bm5ldF9tb2RlbF9yb21hKQpwbG90KGNsYXNzaV9ubmV0X21vZGVsX3JvbWEsIG1haW49IkNsYXNpZmljYWNpw7NuIFJlZGVzIG5ldXJvbmFsZXMgTW9kZWxvIDEiLGNvbCA9IGNvbHMpCmBgYAoKIyBQcmVkaWNjacOzbiB5IHZpc3VhbGl6YWNpw7NuIE1vZGVsbyAyLgoKYGBge3J9CmNsYXNzaV9ubmV0X21vZGVsX3JvbWEyIDwtIHJhc3Rlcjo6cHJlZGljdChyb21hX3JzdF9sYW4sIG1vZGVsPW5uZXRfbW9kZWxfcm9tYTIpCnBsb3QoY2xhc3NpX25uZXRfbW9kZWxfcm9tYTIsIG1haW49IkNsYXNpZmljYWNpw7NuIFJlZGVzIG5ldXJvbmFsZXMgTW9kZWxvIDIiLCBjb2wgPSBjb2xzKQpgYGAKCg==