Objetivo

  1. Mostrar el resultado del perfíl espectral generado por los píxeles de las diferentes categorías de clasificación y la correlación entre las bandas de las imagenes empleadas para el análisis multitemporal.

  2. Generar los procesos de cálculo de los diferentes parámetros definidos por Pontius, Quantity, Exchange y Shift a partír de la matriz de confusión, para los modelos de clasificación CART y Random Forest.

library(knitr)
library(sp)
library(raster)
library(rgdal)
rgdal: version: 1.4-8, (SVN revision 845)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
 Path to GDAL shared files: C:/Users/Elkin/Documents/R/win-library/3.6/rgdal/gdal
 GDAL binary built with GEOS: TRUE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/Elkin/Documents/R/win-library/3.6/rgdal/proj
 Linking to sp version: 1.4-1 
library(diffeR)
Loading required package: ggplot2
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Loading required package: reshape2

Área de estudio

library(leaflet)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
tenjo <- data.frame(
    lat = c(4.871973,4.876513,4.904042,4.890152,4.812393,4.841831,4.857221,4.815281,4.871385),
    lng = c(-74.145082,-74.128094,-74.128364,-74.147039,-74.175483,-74.137124,-74.129088,-74.119443,-74.083082))
 
tenjo_popup = popup = c("Parque Principal","Casa","Peña de Juaica","Cerro Churugüaco Alto","Quebrada Socha","Quebrada Socha","Río Chicú","Serranía del Majuy","Alto de la Cruz")
 
tenjo %>% 
    leaflet() %>%
    addTiles() %>%
    addMarkers(popup = tenjo_popup, clusterOptions = markerClusterOptions())%>%
      addProviderTiles(providers$Esri.WorldStreetMap) %>%
      addMiniMap(
        tiles = providers$Esri.WorldStreetMap,
        toggleDisplay = TRUE)

NA
library(raster)
MOT <- shapefile("MOT.shp")
proj4string(MOT)
[1] "+proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs"
MOTr <- spTransform(MOT, CRS("+init=epsg:4326"))
MOTr
class       : SpatialPolygonsDataFrame 
features    : 38 
extent      : -74.21967, -74.08091, 4.749226, 4.904683  (xmin, xmax, ymin, ymax)
crs         : +init=epsg:4326 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 10
names       : objectid, tipo_avalu, sector_cat,                                    reporte,    shape_Leng,    shape_Area,                                CATEGORIA,       SUELO,       AREA_ha,        area 
min values  :        0,         00,          2, Area de Actividad Agropecuaria Tradicional,             0, 28.1855385081, Area de Actividad Agropecuaria Intensiva,  PROTECCION, 0.01814860016,  0.02013345 
max values  :    70061,         00,          2,                                         ZU, 72441.4088517, 11767763.4469,                              Zona Urbana, ZONA URBANA, 7111.09671597, 53607182.05 

Polígono del MODELO DE ORDENAMIENTO TERRITORIAL, si se hace click sobre cualquier zona del polígono, se mostrará la categoría de uso de suelo a la que corresponde

par(mfrow = c(1,2))
leaflet() %>%
  addProviderTiles(providers$Esri.WorldImagery, options= providerTileOptions(opacity = 0.99)) %>%addPolygons(data = MOTr, popup = MOTr$SUELO,
    stroke = FALSE, fillOpacity = 0.3, smoothFactor = 0,
   )

Tabla de atributos del MOT

head(MOT)
#Composición en color verdadero
tenjo2 <- stack('tenjo/olitirs/TENJO_2020_ALLBANDS.tif')
tenjo1 <- stack('tenjo/olitirs/TENJO_2018_ALLBANDS.tif')
#tenjolist <- stack(bcr1,bcr2,bcr3,bcr4,bcr5,bcr6,bcr7,bcr9,bcr10,bcr11)
sen1 <- tenjo1[[c(3,2,1)]]
sen2 <- tenjo2[[c(3,2,1)]]
par(mfrow = c(1,2))
plotRGB(sen1, axes = TRUE, stretch = "lin", main = "Imagen Color Verdadero 2018")
plotRGB(sen2, axes = TRUE, stretch = "lin", main = "Imagen Color Verdadero 2020")

tenjo2
class      : RasterStack 
dimensions : 1721, 1538, 2646898, 6  (nrow, ncol, ncell, nlayers)
resolution : 10, 10  (x, y)
extent     : 586530, 601910, 524990, 542200  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
names      :    B2,    B3,    B4,    B8,   B11,   B12 
min values :     0,     0,     0,     0,     0,     0 
max values : 65535, 65535, 65535, 65535, 65535, 65535 
tenjo1
class      : RasterStack 
dimensions : 1721, 1538, 2646898, 6  (nrow, ncol, ncell, nlayers)
resolution : 10, 10  (x, y)
extent     : 586530, 601910, 524990, 542200  (xmin, xmax, ymin, ymax)
crs        : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
names      :    B2,    B3,    B4,    B8,   B11,   B12 
min values :     0,     0,     0,     0,     0,     0 
max values : 65535, 65535, 65535, 65535, 65535, 65535 

Correlación entre bandas

Correlación

pairs(tenjo1[[1:6]], main = "Correlación entre bandas Sentinel 2 - Reflectancia BOA 2018")

pairs(tenjo2[[1:6]], main = "Correlación entre bandas Sentinel 2 - Reflectancia BOA 2019")

Extracción de píxeles para perfil espectral - imagen de 2018

lc_samples <-shapefile('usodesuelo.shp')
class(lc_samples)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
proj4string(lc_samples)
[1] "+proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0"
ptsamp <- spsample(lc_samples, 300, type='regular')
ptsamp$code <- over(ptsamp, lc_samples)$code
df <- extract(tenjolist, ptsamp)
head(df)
       B2   B3   B4   B8  B11  B12
[1,] 2764 2822 2652 2236 1886 2389
[2,] 4488 4608 4508 4145 4019 4038
[3,] 3946 4144 4062 3654 3801 4121
[4,] 4090 4112 4140 3846 4735 4690
[5,] 1530 2250 2812 3208 4030 3346
[6,] 1750 2530 2964 3553 4289 3604
ms <- aggregate(df, list(ptsamp$code), mean)
rownames(ms) <- ms[,1]
ms <- ms[,-1]
ms

Perfil espectral - imagen de 2018

mycolor <- c('green', 'red', 'burlywood', 'cyan', 'black', 'pink')
ms <- as.matrix(ms)
plot(0, ylim=c(0,6000), xlim = c(1,6), type='n', xlab="Bandas", ylab = "Reflectancia")
for (i in 1:nrow(ms)){
  lines(ms[i,], type = "l", lwd = 3, lty = 1, col = mycolor[i])
}
title(main="Perfil Espectral de Sentinel 2_SR - Tenjo", font.main = 2)
legend("topleft", rownames(ms),
       cex=0.8, col=mycolor, lty = 1, lwd =3, bty = "n")

Análisis matriz de confusión

Clasificaciones

lc18CART <- raster('CART_2018.tif')
lc20CART <- raster('CART_2020.tif')
lc18RF <- raster('RF_2018.tif')
lc20RF <- raster('RF_2020.tif')
plot(stretch(lc18CART, minq=0, maxq=6), main = "CART 2018", ylab="Coordenada Y", xlab="Coordenada X", col = grey(0:6 / 6))

plot(stretch(lc20CART, minq=0, maxq=6), main = "CART 2020", ylab="Coordenada Y", xlab="Coordenada X", col = grey(0:6 / 6))

plot(stretch(lc18RF, minq=0, maxq=6), main = "RF 2018", ylab="Coordenada Y", xlab="Coordenada X", col = grey(0:6 / 6))

plot(stretch(lc20RF, minq=0, maxq=6), main = "RF 2020", ylab="Coordenada Y", xlab="Coordenada X", col = grey(0:6 / 6))

Cálculos matriz de confusión

ctmatCompRefCART <- crosstabm(lc20CART, lc18CART)
ctmatCompRefRF <- crosstabm(lc20RF, lc18RF)

La matriz de confusión resultante de los datos descargados de Google Earth Engine cuenta con una columna de datos vacíos o ceros, que se evidencia en los mapas previos con el color negro, procedemos a corregír esta información

ctmatCompRef2CART <- ctmatCompRefCART[-1,-1]
ctmatCompRef2RF <- ctmatCompRefRF[-1,-1]

matriz de confusión para modelo CART

ctmatCompRef2CART
       1     2      3     4     5      6
1 165994  1310  14616  1872  1160  32549
2   6822 19766  12656  6753  1805  42153
3   6990  5334  78265  5751   884  54901
4   2863  6549   8203 33919  9327  21196
5   1788  1167   1130  7414 28577  10781
6  65409 32113 111804 19877 11146 311154

matriz de confusión para modelo RF

ctmatCompRef2RF
       1     2      3     4     5      6
1 162493  1216  11649   765  1497  28370
2   5899 18367  12851  5257   668  42125
3   5567  5796  65905  3282   399  55304
4   1505  5148   4828 40183  7275  19063
5   2617   492    706  5443 27341  10165
6  60799 34556 114344 17679 10974 353470
differenceMR(lc20CART, lc18CART, eval='original', percent=TRUE)
differenceMR(lc20RF, lc18RF, eval='original', percent=TRUE)

Métricas CART

diffTablej(ctmatCompRef2CART)
NA

Métricas RF

diffTablej(ctmatCompRef2RF)

Diagrama de componentes CART


categoryComponentsPlot(ctmatrix = ctmatCompRef2CART, units = "pixels")

Diagrama de componentes RF

categoryComponentsPlot(ctmatrix = ctmatCompRef2RF, units = "pixels")

LS0tDQp0aXRsZTogIkFwb3lvIGRlIEPDs2RpZ28gLSBSZXBvcnRlIE7CsDMiDQphdXRob3I6ICJFbGtpbiBBbGJlcnRvIEFwb250ZSBHb21leiINCmRhdGU6ICIyNi8wNi8yMDIwIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KIyAqKk9iamV0aXZvKioNCg0KMS4gTW9zdHJhciBlbCByZXN1bHRhZG8gZGVsIHBlcmbDrWwgZXNwZWN0cmFsIGdlbmVyYWRvIHBvciBsb3MgcMOteGVsZXMgZGUgbGFzIGRpZmVyZW50ZXMgY2F0ZWdvcsOtYXMgZGUgY2xhc2lmaWNhY2nDs24geSBsYSBjb3JyZWxhY2nDs24gZW50cmUgbGFzIGJhbmRhcyBkZSBsYXMgaW1hZ2VuZXMgZW1wbGVhZGFzIHBhcmEgZWwgYW7DoWxpc2lzIG11bHRpdGVtcG9yYWwuDQoNCg0KMi4gR2VuZXJhciBsb3MgcHJvY2Vzb3MgZGUgY8OhbGN1bG8gZGUgbG9zIGRpZmVyZW50ZXMgcGFyw6FtZXRyb3MgZGVmaW5pZG9zIHBvciBQb250aXVzLCBRdWFudGl0eSwgRXhjaGFuZ2UgeSBTaGlmdCBhIHBhcnTDrXIgZGUgbGEgbWF0cml6IGRlIGNvbmZ1c2nDs24sIHBhcmEgbG9zIG1vZGVsb3MgZGUgY2xhc2lmaWNhY2nDs24gQ0FSVCB5IFJhbmRvbSBGb3Jlc3QuDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkoa25pdHIpDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShyYXN0ZXIpDQpsaWJyYXJ5KHJnZGFsKQ0KbGlicmFyeShkaWZmZVIpDQpgYGANCg0KIyAqKsOBcmVhIGRlIGVzdHVkaW8qKg0KDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCnRlbmpvIDwtIGRhdGEuZnJhbWUoDQogICAgbGF0ID0gYyg0Ljg3MTk3Myw0Ljg3NjUxMyw0LjkwNDA0Miw0Ljg5MDE1Miw0LjgxMjM5Myw0Ljg0MTgzMSw0Ljg1NzIyMSw0LjgxNTI4MSw0Ljg3MTM4NSksDQogICAgbG5nID0gYygtNzQuMTQ1MDgyLC03NC4xMjgwOTQsLTc0LjEyODM2NCwtNzQuMTQ3MDM5LC03NC4xNzU0ODMsLTc0LjEzNzEyNCwtNzQuMTI5MDg4LC03NC4xMTk0NDMsLTc0LjA4MzA4MikpDQogDQp0ZW5qb19wb3B1cCA9IHBvcHVwID0gYygiUGFycXVlIFByaW5jaXBhbCIsIkNhc2EiLCJQZcOxYSBkZSBKdWFpY2EiLCJDZXJybyBDaHVydWfDvGFjbyBBbHRvIiwiUXVlYnJhZGEgU29jaGEiLCJRdWVicmFkYSBTb2NoYSIsIlLDrW8gQ2hpY8O6IiwiU2VycmFuw61hIGRlbCBNYWp1eSIsIkFsdG8gZGUgbGEgQ3J1eiIpDQogDQp0ZW5qbyAlPiUgDQogICAgbGVhZmxldCgpICU+JQ0KICAgIGFkZFRpbGVzKCkgJT4lDQogICAgYWRkTWFya2Vycyhwb3B1cCA9IHRlbmpvX3BvcHVwLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCkpJT4lDQoJICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkU3RyZWV0TWFwKSAlPiUNCgkgIGFkZE1pbmlNYXAoDQoJCXRpbGVzID0gcHJvdmlkZXJzJEVzcmkuV29ybGRTdHJlZXRNYXAsDQoJCXRvZ2dsZURpc3BsYXkgPSBUUlVFKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkocmFzdGVyKQ0KTU9UIDwtIHNoYXBlZmlsZSgiTU9ULnNocCIpDQpwcm9qNHN0cmluZyhNT1QpDQpNT1RyIDwtIHNwVHJhbnNmb3JtKE1PVCwgQ1JTKCIraW5pdD1lcHNnOjQzMjYiKSkNCk1PVHINCmBgYA0KDQoNClBvbMOtZ29ubyBkZWwgTU9ERUxPIERFIE9SREVOQU1JRU5UTyBURVJSSVRPUklBTCwgc2kgc2UgaGFjZSBjbGljayBzb2JyZSBjdWFscXVpZXIgem9uYSBkZWwgcG9sw61nb25vLCBzZSBtb3N0cmFyw6EgbGEgY2F0ZWdvcsOtYSBkZSB1c28gZGUgc3VlbG8gYSBsYSBxdWUgY29ycmVzcG9uZGUNCg0KDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMSwyKSkNCmxlYWZsZXQoKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5Xb3JsZEltYWdlcnksIG9wdGlvbnM9IHByb3ZpZGVyVGlsZU9wdGlvbnMob3BhY2l0eSA9IDAuOTkpKSAlPiVhZGRQb2x5Z29ucyhkYXRhID0gTU9UciwgcG9wdXAgPSBNT1RyJFNVRUxPLA0KICAgIHN0cm9rZSA9IEZBTFNFLCBmaWxsT3BhY2l0eSA9IDAuMywgc21vb3RoRmFjdG9yID0gMCwNCiAgICkNCmBgYA0KDQpUYWJsYSBkZSBhdHJpYnV0b3MgZGVsIE1PVA0KYGBge3J9DQpoZWFkKE1PVCkNCmBgYA0KDQoNCmBgYHtyfQ0KI0NvbXBvc2ljacOzbiBlbiBjb2xvciB2ZXJkYWRlcm8NCnRlbmpvMiA8LSBzdGFjaygndGVuam8vb2xpdGlycy9URU5KT18yMDIwX0FMTEJBTkRTLnRpZicpDQp0ZW5qbzEgPC0gc3RhY2soJ3RlbmpvL29saXRpcnMvVEVOSk9fMjAxOF9BTExCQU5EUy50aWYnKQ0KI3RlbmpvbGlzdCA8LSBzdGFjayhiY3IxLGJjcjIsYmNyMyxiY3I0LGJjcjUsYmNyNixiY3I3LGJjcjksYmNyMTAsYmNyMTEpDQpzZW4xIDwtIHRlbmpvMVtbYygzLDIsMSldXQ0Kc2VuMiA8LSB0ZW5qbzJbW2MoMywyLDEpXV0NCnBhcihtZnJvdyA9IGMoMSwyKSkNCnBsb3RSR0Ioc2VuMSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJJbWFnZW4gQ29sb3IgVmVyZGFkZXJvIDIwMTgiKQ0KcGxvdFJHQihzZW4yLCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkltYWdlbiBDb2xvciBWZXJkYWRlcm8gMjAyMCIpDQpgYGANCg0KYGBge3J9DQp0ZW5qbzINCnRlbmpvMQ0KYGBgDQoNCiMgKipDb3JyZWxhY2nDs24gZW50cmUgYmFuZGFzKioNCg0KIyMgQ29ycmVsYWNpw7NuIHsudGFic2V0fQ0KDQoNCg0KYGBge3J9DQpwYWlycyh0ZW5qbzFbWzE6Nl1dLCBtYWluID0gIkNvcnJlbGFjacOzbiBlbnRyZSBiYW5kYXMgU2VudGluZWwgMiAtIFJlZmxlY3RhbmNpYSBCT0EgMjAxOCIpDQpwYWlycyh0ZW5qbzJbWzE6Nl1dLCBtYWluID0gIkNvcnJlbGFjacOzbiBlbnRyZSBiYW5kYXMgU2VudGluZWwgMiAtIFJlZmxlY3RhbmNpYSBCT0EgMjAxOSIpDQpgYGANCg0KIyAqKkV4dHJhY2Npw7NuIGRlIHDDrXhlbGVzIHBhcmEgcGVyZmlsIGVzcGVjdHJhbCAtIGltYWdlbiBkZSAyMDE4KioNCg0KYGBge3J9DQpsY19zYW1wbGVzIDwtc2hhcGVmaWxlKCd1c29kZXN1ZWxvLnNocCcpDQpjbGFzcyhsY19zYW1wbGVzKQ0KcHJvajRzdHJpbmcobGNfc2FtcGxlcykNCnB0c2FtcCA8LSBzcHNhbXBsZShsY19zYW1wbGVzLCAzMDAsIHR5cGU9J3JlZ3VsYXInKQ0KcHRzYW1wJGNvZGUgPC0gb3ZlcihwdHNhbXAsIGxjX3NhbXBsZXMpJGNvZGUNCmRmIDwtIGV4dHJhY3QodGVuam9saXN0LCBwdHNhbXApDQpoZWFkKGRmKQ0KYGBgDQoNCg0KYGBge3J9DQptcyA8LSBhZ2dyZWdhdGUoZGYsIGxpc3QocHRzYW1wJGNvZGUpLCBtZWFuKQ0Kcm93bmFtZXMobXMpIDwtIG1zWywxXQ0KbXMgPC0gbXNbLC0xXQ0KbXMNCmBgYA0KDQojICoqUGVyZmlsIGVzcGVjdHJhbCAtIGltYWdlbiBkZSAyMDE4KioNCg0KYGBge3J9DQpteWNvbG9yIDwtIGMoJ2dyZWVuJywgJ3JlZCcsICdidXJseXdvb2QnLCAnY3lhbicsICdibGFjaycsICdwaW5rJykNCm1zIDwtIGFzLm1hdHJpeChtcykNCnBsb3QoMCwgeWxpbT1jKDAsNjAwMCksIHhsaW0gPSBjKDEsNiksIHR5cGU9J24nLCB4bGFiPSJCYW5kYXMiLCB5bGFiID0gIlJlZmxlY3RhbmNpYSIpDQpmb3IgKGkgaW4gMTpucm93KG1zKSl7DQogIGxpbmVzKG1zW2ksXSwgdHlwZSA9ICJsIiwgbHdkID0gMywgbHR5ID0gMSwgY29sID0gbXljb2xvcltpXSkNCn0NCnRpdGxlKG1haW49IlBlcmZpbCBFc3BlY3RyYWwgZGUgU2VudGluZWwgMl9TUiAtIFRlbmpvIiwgZm9udC5tYWluID0gMikNCmxlZ2VuZCgidG9wbGVmdCIsIHJvd25hbWVzKG1zKSwNCiAgICAgICBjZXg9MC44LCBjb2w9bXljb2xvciwgbHR5ID0gMSwgbHdkID0zLCBidHkgPSAibiIpDQpgYGANCg0KDQoNCiMgKipBbsOhbGlzaXMgbWF0cml6IGRlIGNvbmZ1c2nDs24qKg0KDQojIyBDbGFzaWZpY2FjaW9uZXMgey50YWJzZXR9DQoNCmBgYHtyfQ0KbGMxOENBUlQgPC0gcmFzdGVyKCdDQVJUXzIwMTgudGlmJykNCmxjMjBDQVJUIDwtIHJhc3RlcignQ0FSVF8yMDIwLnRpZicpDQpsYzE4UkYgPC0gcmFzdGVyKCdSRl8yMDE4LnRpZicpDQpsYzIwUkYgPC0gcmFzdGVyKCdSRl8yMDIwLnRpZicpDQpgYGANCg0KYGBge3J9DQpwbG90KHN0cmV0Y2gobGMxOENBUlQsIG1pbnE9MCwgbWF4cT02KSwgbWFpbiA9ICJDQVJUIDIwMTgiLCB5bGFiPSJDb29yZGVuYWRhIFkiLCB4bGFiPSJDb29yZGVuYWRhIFgiLCBjb2wgPSBncmV5KDA6NiAvIDYpKQ0KDQpgYGANCg0KYGBge3J9DQpwbG90KHN0cmV0Y2gobGMyMENBUlQsIG1pbnE9MCwgbWF4cT02KSwgbWFpbiA9ICJDQVJUIDIwMjAiLCB5bGFiPSJDb29yZGVuYWRhIFkiLCB4bGFiPSJDb29yZGVuYWRhIFgiLCBjb2wgPSBncmV5KDA6NiAvIDYpKQ0KYGBgDQpgYGB7cn0NCnBsb3Qoc3RyZXRjaChsYzE4UkYsIG1pbnE9MCwgbWF4cT02KSwgbWFpbiA9ICJSRiAyMDE4IiwgeWxhYj0iQ29vcmRlbmFkYSBZIiwgeGxhYj0iQ29vcmRlbmFkYSBYIiwgY29sID0gZ3JleSgwOjYgLyA2KSkNCmBgYA0KYGBge3J9DQpwbG90KHN0cmV0Y2gobGMyMFJGLCBtaW5xPTAsIG1heHE9NiksIG1haW4gPSAiUkYgMjAyMCIsIHlsYWI9IkNvb3JkZW5hZGEgWSIsIHhsYWI9IkNvb3JkZW5hZGEgWCIsIGNvbCA9IGdyZXkoMDo2IC8gNikpDQpgYGANCg0KIyAqKkPDoWxjdWxvcyBtYXRyaXogZGUgY29uZnVzacOzbioqDQoNCg0KYGBge3J9DQpjdG1hdENvbXBSZWZDQVJUIDwtIGNyb3NzdGFibShsYzIwQ0FSVCwgbGMxOENBUlQpDQpjdG1hdENvbXBSZWZSRiA8LSBjcm9zc3RhYm0obGMyMFJGLCBsYzE4UkYpDQpgYGANCg0KTGEgbWF0cml6IGRlIGNvbmZ1c2nDs24gcmVzdWx0YW50ZSBkZSBsb3MgZGF0b3MgZGVzY2FyZ2Fkb3MgZGUgR29vZ2xlIEVhcnRoIEVuZ2luZSBjdWVudGEgY29uIHVuYSBjb2x1bW5hIGRlIGRhdG9zIHZhY8Otb3MgbyBjZXJvcywgcXVlIHNlIGV2aWRlbmNpYSBlbiBsb3MgbWFwYXMgcHJldmlvcyBjb24gZWwgY29sb3IgbmVncm8sIHByb2NlZGVtb3MgYSBjb3JyZWfDrXIgZXN0YSBpbmZvcm1hY2nDs24NCg0KYGBge3J9DQpjdG1hdENvbXBSZWYyQ0FSVCA8LSBjdG1hdENvbXBSZWZDQVJUWy0xLC0xXQ0KY3RtYXRDb21wUmVmMlJGIDwtIGN0bWF0Q29tcFJlZlJGWy0xLC0xXQ0KYGBgDQoNCg0KIyAqKm1hdHJpeiBkZSBjb25mdXNpw7NuIHBhcmEgbW9kZWxvIENBUlQqKg0KYGBge3J9DQpjdG1hdENvbXBSZWYyQ0FSVA0KDQpgYGANCg0KDQojICoqbWF0cml6IGRlIGNvbmZ1c2nDs24gcGFyYSBtb2RlbG8gUkYqKg0KYGBge3J9DQpjdG1hdENvbXBSZWYyUkYNCmBgYA0KDQoNCmBgYHtyfQ0KZGlmZmVyZW5jZU1SKGxjMjBDQVJULCBsYzE4Q0FSVCwgZXZhbD0nb3JpZ2luYWwnLCBwZXJjZW50PVRSVUUpDQpkaWZmZXJlbmNlTVIobGMyMFJGLCBsYzE4UkYsIGV2YWw9J29yaWdpbmFsJywgcGVyY2VudD1UUlVFKQ0KYGBgDQoNCiMgKipNw6l0cmljYXMgQ0FSVCoqIA0KDQpgYGB7cn0NCmRpZmZUYWJsZWooY3RtYXRDb21wUmVmMkNBUlQpDQoNCmBgYA0KDQoNCiMgKipNw6l0cmljYXMgUkYqKg0KYGBge3J9DQpkaWZmVGFibGVqKGN0bWF0Q29tcFJlZjJSRikNCmBgYA0KDQojICoqRGlhZ3JhbWEgZGUgY29tcG9uZW50ZXMgQ0FSVCoqDQpgYGB7cn0NCg0KY2F0ZWdvcnlDb21wb25lbnRzUGxvdChjdG1hdHJpeCA9IGN0bWF0Q29tcFJlZjJDQVJULCB1bml0cyA9ICJwaXhlbHMiKQ0KDQpgYGANCg0KDQojICoqRGlhZ3JhbWEgZGUgY29tcG9uZW50ZXMgUkYqKg0KYGBge3J9DQpjYXRlZ29yeUNvbXBvbmVudHNQbG90KGN0bWF0cml4ID0gY3RtYXRDb21wUmVmMlJGLCB1bml0cyA9ICJwaXhlbHMiKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==