A continuacion se muestra como puede acceder a varias propiedades desde un objeto Raster * (esto es lo mismo para cualquier conjunto de datos raster).
# coordinate reference system (CRS)
crs(b2)
CRS arguments:
+proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## CRS arguments:
## +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84
## +towgs84=0,0,0
# Number of cells, rows, columns
ncell(b2)
[1] 58684521
## [1] 58684521
dim(b2)
[1] 7741 7581 1
## [1] 7741 7581 1
# spatial resolution
res(b2)
[1] 30 30
## [1] 30 30
# Number of bands
nlayers(b2)
[1] 1
## [1] 1
# Do the bands have the same extent, number of rows and columns, projection, resolution, and origin
compareRaster(b2,b3)
[1] TRUE
## [1] TRUE
Puede crear un RasterStack (un objeto con varias capas) a partir de los objetos RasterLayer (banda unica) existentes
Las bandas que llamos son las mismas que hemos llamadodo arriba como RasterLayer
s2015 = stack(b5, b4, b3)
# Check the properties of the RasterStack
s2015
class : RasterStack
dimensions : 7741, 7581, 58684521, 3 (nrow, ncol, ncell, nlayers)
resolution : 30, 30 (x, y)
extent : 446085, 673515, 362985, 595215 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
names : LC08_L1TP_008057_20150104_20170415_01_T1_B5, LC08_L1TP_008057_20150104_20170415_01_T1_B4, LC08_L1TP_008057_20150104_20170415_01_T1_B3
min values : 0, 0, 0
max values : 65535, 65535, 65535
## class : RasterStack
## dimensions : 7741, 7581, 58684521, 3 (nrow, ncol, ncell, nlayers)
## resolution : 30, 30 (x, y)
## extent : 446085, 673515, 362985, 595215 (xmin, xmax, ymin, ymax)
## crs : ++proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## names : LC08_L1TP_008057_20180317_20180403_01_T1_B5, LC08_L1TP_008057_20180317_20180403_01_T1_B4, LC08_L1TP_008057_20180317_20180403_01_T1_B3
## min values : 0, 0, 0
## max values : 65535, 65535, 65535
Tambien puede crear el RasterStack usando los nombres de archivo
# first create a list of raster layers to use
filenames = paste0('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B', 1:7, ".tif")
filenames
[1] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B1.tif"
[2] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B2.tif"
[3] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B3.tif"
[4] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B4.tif"
[5] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B5.tif"
[6] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B6.tif"
[7] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B7.tif"
## [1] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B1.tif"
## [2] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B2.tif"
## [3] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B3.tif"
## [4] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B4.tif"
## [5] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B5.tif"
## [6] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B6.tif"
## [7] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B7.tif"
###### no lee la banda 8 porque tiene diferente extension
## [8] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B8.tif"
## [9] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B9.tif"
## [10] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B10.tif"
## [11] "./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B11.tif"
landsat2015= stack(filenames)
landsat2015
class : RasterStack
dimensions : 7741, 7581, 58684521, 7 (nrow, ncol, ncell, nlayers)
resolution : 30, 30 (x, y)
extent : 446085, 673515, 362985, 595215 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
names : LC08_L1TP//5_01_T1_B1, LC08_L1TP//5_01_T1_B2, LC08_L1TP//5_01_T1_B3, LC08_L1TP//5_01_T1_B4, LC08_L1TP//5_01_T1_B5, LC08_L1TP//5_01_T1_B6, LC08_L1TP//5_01_T1_B7
min values : 0, 0, 0, 0, 0, 0, 0
max values : 65535, 65535, 65535, 65535, 65535, 65535, 65535
## class : RasterStack
## dimensions : 7741, 7581, 58684521, 7 (nrow, ncol, ncell, nlayers)
## resolution : 30, 30 (x, y)
## extent : 446085, 673515, 362985, 595215 (xmin, xmax, ymin, ymax)
## crs : +proj=utm +zone=10 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
## names : LC08_L1TP//5_01_T1_B1, LC08_L1TP//5_01_T1_B2, LC08_L1TP//5_01_T1_B3, LC08_L1TP//5_01_T1_B4, LC08_L1TP//5_01_T1_B5, LC08_L1TP//5_01_T1_B6, LC08_L1TP//5_01_T1_B7
## min values : 0, 0, 0, 0, 0, 0, 0
## max values : 65535, 65535, 65535, 65535, 65535, 65535, 65535
Arriba creamos un RasterStack con 11 capas. Las capas representan la intensidad de la reflexion en las siguientes longitudes de onda: Ultra azul, azul, verde, rojo, infrarrojo cercano (NIR), infrarrojo de onda corta (SWIR) 1, infrarrojo de onda corta (SWIR) 2, pancromatico, cirro, infrarrojo termico (TIRS) 1, Infrarrojo termico (TIRS) 2. No utilizaremos las ultimas cuatro capas y vera como eliminarlas en las siguientes secciones.
TITULO: BANDA UNICA Y MAPAS COMPUESTOS
Puede trazar capas individuales de un RasterStack de una imagen multiespectral.
par(mfrow = c(2,2))
plot(b2, main = "Blue", col = gray(0:100 / 100))
plot(b3, main = "Green", col = gray(0:100 / 100))
plot(b4, main = "Red", col = gray(0:100 / 100))
plot(b5, main = "NIR", col = gray(0:100 / 100))

Echa un vistazo a las leyendas de los mapas creados anteriormente. Pueden variar entre 0 y 1. Observe la diferencia en el sombreado y el rango de leyendas entre las diferentes bandas. Esto se debe a que las diferentes caracteristicas de la superficie reflejan la radiacion solar incidente de manera diferente. Cada capa representa la cantidad de radiacion solar incidente que se refleja para un rango de longitud de onda particular. Por ejemplo, la vegetacion refleja mas energia en NIR que otras longitudes de onda y, por lo tanto, parece mas brillante. Por el contrario, el agua absorbe la mayor parte de la energia en la longitud de onda NIR y parece oscura.
Para hacer una imagen de “color verdadero (o natural)”, es decir, algo que se parece a una fotografia normal (vegetacion en verde, azul agua, etc.), necesitamos bandas en las regiones roja, verde y azul. Para esta imagen Landsat, se pueden usar las bandas 4 (rojo), 3 (verde) y 2 (azul). El - plotRGB - metodo se puede utilizar para combinarlos en un solo compuesto. Tambien puede proporcionar argumentos adicionales - plotRGB - para mejorar la visualizacion (por ejemplo, un estiramiento lineal de los valores, utilizando ).- strecth = “lin” -
landsatRGB2015 = stack(b4, b3, b2)
plotRGB(landsatRGB2015, axes = TRUE, stretch = "lin", main = "Landsat True Color Composite")

El compuesto de color verdadero revela mucho mas sobre el paisaje que las imagenes grises anteriores. Otro metodo popular de visualizacion de imagenes en la teledeteccion es la imagen conocida de “color falso” en la que se combinan las bandas NIR, rojo y verde. Esta representacion es popular ya que hace que sea facil ver la vegetacion (en rojo).
par(mfrow = c(1,2))
plotRGB(landsatRGB2015, axes=TRUE, stretch="lin", main="Landsat True Color Composite")
landsatFCC2015 = stack(b5, b4, b3)
plotRGB(landsatFCC2015, axes=TRUE, stretch="lin", main="Landsat False Color Composite")

Nota : Compruebe siempre la documentacion del paquete (- help(plotRGB) -) para ver otros argumentos que se pueden agregar (como la escala) para mejorar o modificar la imagen.
Pregunta 1 : Use la funcion plotRGB con RasterStack `` landsat ’’ para crear un compuesto de color verdadero y falso (recuerde la posicion de las bandas en la pila).
TITULO: PERFILES ESPECTRALES
Una grafica del espectro (todas las bandas) para los pixeles que representan ciertas caracteristicas de la superficie terrestre (p. Ej. Agua) se conoce como perfil espectral. Dichos perfiles demuestran las diferencias en las propiedades espectrales de varias caracteristicas de la superficie terrestre y constituyen la base para el analisis de imagenes. Los valores espectrales se pueden extraer de cualquier conjunto de datos multiespectrales utilizando la - extract - funcion. En el ejemplo anterior, extrajimos valores de datos de Landsat para las muestras. Estas muestras incluyen: tierras de cultivo, agua, barbecho, construido y abierto. Primero calculamos los valores medios de reflectancia para cada clase y cada banda.
numero= length(ptsibatecobert)
numero
[1] 297
df_samples = as (ptsibatecobert, "SpatialPointsDataFrame")
df_samples
class : SpatialPointsDataFrame
features : 297
extent : 577356.4, 585717, 493599.1, 501108.2 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 1
names : Name
min values : Agua
max values : zona desnuda
df_samples@data=data.frame(ID=1:numero,size=1)
df_samples
class : SpatialPointsDataFrame
features : 297
extent : 577356.4, 585717, 493599.1, 501108.2 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 2
names : ID, size
min values : 1, 1
max values : 297, 1
plot(landsatcrop2015)
plot(sibatecobert, add= TRUE)
plot(df_samples,pch=1, cex=(df_samples$size)/4, add=TRUE)

df_samples$Name =over(df_samples,sibatecobert)$Name
df_samples
class : SpatialPointsDataFrame
features : 297
extent : 577356.4, 585717, 493599.1, 501108.2 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
variables : 3
names : ID, size, Name
min values : 1, 1, Agua
max values : 297, 1, zona desnuda
df1=raster::extract(landsatcrop2015, df_samples)
ms = aggregate(df1, list(ptsibatecobert$Name), mean)
## ms = aggregate(df, list(ptsamp$class), mean) ** asi esta en la guia**
# instead of the first column, we use row names
rownames(ms) = ms[,1]
ms = ms[,-1]
ms
## ultra.blue blue green red NIR SWIR1
## built 0.1864925 0.1795371 0.17953317 0.1958414 0.25448447 0.24850197
## cropland 0.1129813 0.0909645 0.08596722 0.0550344 0.48335462 0.16142085
## fallow 0.1319198 0.1164869 0.10453764 0.1151243 0.18012962 0.23139228
## open 0.1388014 0.1375235 0.15273163 0.2066425 0.34476670 0.35820877
## water 0.1336242 0.1165728 0.09922726 0.0785947 0.04909201 0.03360047
## SWIR2
## built 0.20001306
## cropland 0.07314186
## fallow 0.19143030
## open 0.21346343
## water 0.02723398
Ahora trazamos el espectro medio de estas caracteristicas.
# Create a vector of color for the land cover classes for use in plotting
mycolor = c('darkred', 'yellow', 'burlywood', 'cyan', 'blue', 'green','pink')
#transform ms from a data.frame to a matrix
ms = as.matrix(ms)
# First create an empty plot
plot(0, ylim=c(0,25000), xlim = c(1,7), type='n', xlab="Bands", ylab = "Reflectance")
# add the different classes
for (i in 1:nrow(ms)){
lines(ms[i,], type = "l", lwd = 3, lty = 1, col = mycolor[i])
}
# Title
title(main="Spectral Profile from Landsat", font.main = 2)
# Legend
legend("topleft", rownames(ms),
cex=0.8, col=mycolor, lty = 1, lwd =3, bty = "n")

El perfil espectral muestra (des) similitud en la reflectancia de diferentes caracteristicas en la superficie de la tierra (o por encima de ella). ‘Agua’ muestra una reflexion relativamente baja en todas las longitudes de onda, y ‘construido’, ‘en barbecho’ y ‘abierto’ tienen una reflectancia relativamente alta en las longitudes de onda mas largas.
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.
LS0tDQp0aXRsZTogIioqSW1hZ2VuIExhbmRTYXQgOCwgU2liYXRlIDIwMTUqKiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQoNCiMjIyMjICoqTGFuZHNhdCA4IHJlY29waWxhZGEgZWwgMDQgZGUgZW5lcm8gZGUgMjAxNS4gRWwgc3ViY29uanVudG8gY3VicmUgZWwgYXJlYSBkZSBTaWJhdGUsIGRlcGFydGFtZW50byBkZSBDdW5kaW5hbWFyY2EsIGVuIENvbG9tYmlhKioNCg0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KDQojIyMjIyBTZWxlY2Npb25hciBsYSBjYXJwZXRhIGRlIGRlc3Rpbm8gDQoNCg0KYGBge3J9DQojIkM6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvTGFuZHNhdF9wcm9jZXNhbWllbnRvIg0KZ2V0d2QoKQ0KYGBgDQoNCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykgeSBsYXMgbGxhbWFtb3MgZW5ydXRhbmRvbGFzIGNvbW8gcG9yIGVqZW1wbG8gKCcuL2RhdGEvTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CMi50aWYnKQ0KDQojIyMjIypJTVBPUlRBTlRFOiBpbnN0YWxhciBwYXF1ZXRlczogcmFzdGVyLCBzcCwgcmdkYWwqDQoNCiMjIyMjIEVuIGVzdGUgY2FwaXR1bG8gc2UgZGVzY3JpYmUgbGEgZm9ybWEgZGUgYWNjZWRlciB5IGV4cGxvcmFyIHBvciBzYXRlbGl0ZSBkYXRvcyBkZSB0ZWxlZGV0ZWNjaW9uIGNvbiBSIC4gVGFtYmllbiBtb3N0cmFtb3MgY29tbyB1c2FybG9zIHBhcmEgaGFjZXIgbWFwYXMuDQoNCiMjIyMjIFV0aWxpemFyZW1vcyBwcmluY2lwYWxtZW50ZSB1biBzdWJjb25qdW50byBlc3BhY2lhbCBkZSB1bmEgZXNjZW5hIExhbmRzYXQgOCByZWNvcGlsYWRhIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIEVsIHN1YmNvbmp1bnRvIGN1YnJlIGVsIGFyZWEgZW50cmUgQ29uY29yZCB5IFN0b2NrdG9uICwgZW4gQ2FsaWZvcm5pYSwgRUUuIFVVLg0KDQojIyMjIyBUb2RhcyBsYXMgZXNjZW5hcyBkZSBpbWFnZW5lcyBkZSBMYW5kc2F0IHRpZW5lbiB1bmEgaWRlbnRpZmljYWNpb24gZGUgcHJvZHVjdG8geSBtZXRhZGF0b3MgdW5pY29zLiBQdWVkZSBlbmNvbnRyYXIgbGEgaW5mb3JtYWNpb24gc29icmUgZWwgc2Vuc29yIExhbmRzYXQsIGVsIHNhdGVsaXRlLCBsYSB1YmljYWNpb24gZW4gbGEgVGllcnJhIChydXRhIFdSUywgZmlsYSBXUlMpIHkgbGEgZmVjaGEgZGUgYWRxdWlzaWNpb24gYSBwYXJ0aXIgZGUgbGEgSUQgZGVsIHByb2R1Y3RvLiBQb3IgZWplbXBsbywgZWwgaWRlbnRpZmljYWRvciBkZSBwcm9kdWN0byBkZSBsb3MgZGF0b3MgcXVlIHV0aWxpemFyZW1vcyBlcyAnTEMwOF8wNDQwMzRfMjAxNzA2MTQnLiBDb24gYmFzZSBlbiBlc3RhIGd1aWEgLCBwdWVkZSB2ZXIgcXVlIGVsIFNlbnNvci1TYXRlbGl0ZSBlcyBPTEkgLyBUSVJTIGNvbWJpbmFkb3MgTGFuZHNhdCA4LCBXUlMgUGF0aCA0NCwgV1JTIFJvdyAzNCB5IHJlY29waWxhZG9zIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIExhcyBlc2NlbmFzIGRlIExhbmRzYXQgc2UgZW50cmVnYW4gbWFzIGNvbXVubWVudGUgY29tbyB1biBhcmNoaXZvIGNvbXByaW1pZG8sIHF1ZSBjb250aWVuZSBhcmNoaXZvcyBzZXBhcmFkb3MgcGFyYSBjYWRhIGJhbmRhDQoNCiMjIyMjIENvbWVuemFyZW1vcyBleHBsb3JhbmRvIHkgdmlzdWFsaXphbmRvIGxvcyBkYXRvcyAoY29uc3VsdGUgbGFzIGluc3RydWNjaW9uZXMgZW4gZWwgQ2FwaXR1bG8gMSBwYXJhIG9idGVuZXIgaW5zdHJ1Y2Npb25lcyBkZSBkZXNjYXJnYSBkZSBkYXRvcyBzaSBhdW4gbm8gbG8gaGEgaGVjaG8pLg0KDQoNCg0KIyMjICoqVElUVUxPOiBQUk9QSUVEQURFUyBERSBJTUFHRU4qKg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykNCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCg0KYjEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMS50aWYnKQ0KDQoNCiMgYXp1bA0KYjIgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYnKQ0KIyB2ZXJkZQ0KYjMgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMy50aWYnKQ0KIyByb2pvDQpiNCA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZicpDQojIEluZnJhcm9qbyBjZXJjYW5vIChOSVIpDQpiNSA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I1LnRpZicpDQoNCg0KYjYgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNi50aWYnKQ0KYjcgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNy50aWYnKQ0KYjggPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYnKQ0KYjkgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COS50aWYnKQ0KYjEwID0gcmFzdGVyKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjEwLnRpZicpDQpiMTEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTEudGlmJykNCg0KYGBgDQoNCg0KIyMjIyMgc2UgaW5zZXJ0YSB1biBudWV2byBibG9xdWUgZGUgY29kaWdvIGN0cmwrYWx0K2k6IGltcHJpbWlyIGxhcyB2YXJpYWJsZXMgcGFyYSB2ZXJpZmljYXIsIHBvciBlamVtcGxvOg0KDQoNCmBgYHtyfQ0KYjINCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIHZlciBsYSByZXNvbHVjaW9uIGVzcGFjaWFsLCBsYSBleHRlbnNpb24sIGVsIG51bWVybyBkZSBjYXBhcywgZWwgc2lzdGVtYSBkZSByZWZlcmVuY2lhIGRlIGNvb3JkZW5hZGFzIHkgbWFzLg0KDQoNCg0KIyMjICoqVElUVUxPOiBJTkZPUk1BQ0lPTiBERSBJTUFHRU4gWSBFU1RBRElTVElDQVMqKg0KDQoNCiMjIyBBIGNvbnRpbnVhY2lvbiBzZSBtdWVzdHJhIGNvbW8gcHVlZGUgYWNjZWRlciBhIHZhcmlhcyBwcm9waWVkYWRlcyBkZXNkZSB1biBvYmpldG8gUmFzdGVyICogKGVzdG8gZXMgbG8gbWlzbW8gcGFyYSBjdWFscXVpZXIgY29uanVudG8gZGUgZGF0b3MgcmFzdGVyKS4NCg0KDQpgYGB7cn0NCiMgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtIChDUlMpDQpjcnMoYjIpDQojIyBDUlMgYXJndW1lbnRzOg0KIyMgK3Byb2o9dXRtICt6b25lPTE4ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyArZWxscHM9V0dTODQNCiMjICt0b3dnczg0PTAsMCwwDQojIE51bWJlciBvZiBjZWxscywgcm93cywgY29sdW1ucw0KbmNlbGwoYjIpDQojIyBbMV0gNTg2ODQ1MjENCmRpbShiMikNCiMjIFsxXSA3NzQxIDc1ODEgICAgMQ0KIyBzcGF0aWFsIHJlc29sdXRpb24NCnJlcyhiMikNCiMjIFsxXSAzMCAzMA0KIyBOdW1iZXIgb2YgYmFuZHMNCm5sYXllcnMoYjIpDQojIyBbMV0gMQ0KIyBEbyB0aGUgYmFuZHMgaGF2ZSB0aGUgc2FtZSBleHRlbnQsIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLCBwcm9qZWN0aW9uLCByZXNvbHV0aW9uLCBhbmQgb3JpZ2luDQpjb21wYXJlUmFzdGVyKGIyLGIzKQ0KIyMgWzFdIFRSVUUNCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIGNyZWFyIHVuIFJhc3RlclN0YWNrICh1biBvYmpldG8gY29uIHZhcmlhcyBjYXBhcykgYSBwYXJ0aXIgZGUgbG9zIG9iamV0b3MgUmFzdGVyTGF5ZXIgKGJhbmRhIHVuaWNhKSBleGlzdGVudGVzIA0KDQoNCiMjIyMjIExhcyBiYW5kYXMgcXVlIGxsYW1vcyBzb24gbGFzIG1pc21hcyBxdWUgaGVtb3MgbGxhbWFkb2RvIGFycmliYSBjb21vIFJhc3RlckxheWVyDQoNCmBgYHtyfQ0KczIwMTUgPSBzdGFjayhiNSwgYjQsIGIzKQ0KDQojIENoZWNrIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBSYXN0ZXJTdGFjaw0KczIwMTUNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCAzICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICsrcHJvaj11dG0gK3pvbmU9MTggK2RhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzICtlbGxwcz1XR1M4NCArdG93Z3M4ND0wLDAsMA0KIyMgbmFtZXMgICAgICA6IExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjUsIExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjQsICAgICBMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IzDQojIyBtaW4gdmFsdWVzIDogIDAsIDAsIDAgDQojIyBtYXggdmFsdWVzIDogIDY1NTM1LCA2NTUzNSwgNjU1MzUNCmBgYA0KDQoNCiMjIyMjIFRhbWJpZW4gcHVlZGUgY3JlYXIgZWwgUmFzdGVyU3RhY2sgdXNhbmRvIGxvcyBub21icmVzIGRlIGFyY2hpdm8gDQoNCg0KYGBge3J9DQoNCiMgZmlyc3QgY3JlYXRlIGEgbGlzdCBvZiByYXN0ZXIgbGF5ZXJzIHRvIHVzZQ0KZmlsZW5hbWVzID0gcGFzdGUwKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQicsIDE6NywgIi50aWYiKQ0KZmlsZW5hbWVzDQoNCiMjIFsxXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxLnRpZiIgDQojIyBbMl0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYiIA0KIyMgWzNdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjMudGlmIiANCiMjIFs0XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZiIgDQojIyBbNV0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNS50aWYiIA0KIyMgWzZdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjYudGlmIiANCiMjIFs3XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I3LnRpZiIgDQoNCiMjIyMjIyBubyBsZWUgbGEgYmFuZGEgOCBwb3JxdWUgdGllbmUgZGlmZXJlbnRlIGV4dGVuc2lvbg0KDQojIyBbOF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYiIA0KIyMgWzldICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjkudGlmIiANCiMjIFsxMF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTAudGlmIg0KIyMgWzExXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxMS50aWYiDQoNCg0KbGFuZHNhdDIwMTU9IHN0YWNrKGZpbGVuYW1lcykNCmxhbmRzYXQyMDE1DQoNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCA3ICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICtwcm9qPXV0bSArem9uZT0xMCArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwDQojIyBuYW1lcyAgICAgIDogTEMwOF9MMVRQLy81XzAxX1QxX0IxLCBMQzA4X0wxVFAvLzVfMDFfVDFfQjIsIExDMDhfTDFUUC8vNV8wMV9UMV9CMywgTEMwOF9MMVRQLy81XzAxX1QxX0I0LCBMQzA4X0wxVFAvLzVfMDFfVDFfQjUsIExDMDhfTDFUUC8vNV8wMV9UMV9CNiwgTEMwOF9MMVRQLy81XzAxX1QxX0I3DQojIyBtaW4gdmFsdWVzIDogICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwIA0KIyMgbWF4IHZhbHVlcyA6ICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSANCg0KDQpgYGANCg0KDQojIyMjIyBBcnJpYmEgY3JlYW1vcyB1biBSYXN0ZXJTdGFjayBjb24gMTEgY2FwYXMuIExhcyBjYXBhcyByZXByZXNlbnRhbiBsYSBpbnRlbnNpZGFkIGRlIGxhIHJlZmxleGlvbiBlbiBsYXMgc2lndWllbnRlcyBsb25naXR1ZGVzIGRlIG9uZGE6IFVsdHJhIGF6dWwsIGF6dWwsIHZlcmRlLCByb2pvLCBpbmZyYXJyb2pvIGNlcmNhbm8gKE5JUiksIGluZnJhcnJvam8gZGUgb25kYSBjb3J0YSAoU1dJUikgMSwgaW5mcmFycm9qbyBkZSBvbmRhIGNvcnRhIChTV0lSKSAyLCBwYW5jcm9tYXRpY28sIGNpcnJvLCBpbmZyYXJyb2pvIHRlcm1pY28gKFRJUlMpIDEsIEluZnJhcnJvam8gdGVybWljbyAoVElSUykgMi4gTm8gdXRpbGl6YXJlbW9zIGxhcyB1bHRpbWFzIGN1YXRybyBjYXBhcyB5IHZlcmEgY29tbyBlbGltaW5hcmxhcyBlbiBsYXMgc2lndWllbnRlcyBzZWNjaW9uZXMuDQoNCg0KDQojIyMgKipUSVRVTE86IEJBTkRBIFVOSUNBIFkgTUFQQVMgQ09NUFVFU1RPUyoqDQoNCg0KIyMjIyMgUHVlZGUgdHJhemFyIGNhcGFzIGluZGl2aWR1YWxlcyBkZSB1biBSYXN0ZXJTdGFjayBkZSB1bmEgaW1hZ2VuIG11bHRpZXNwZWN0cmFsLg0KDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3cgPSBjKDIsMikpDQpwbG90KGIyLCBtYWluID0gIkJsdWUiLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjMsIG1haW4gPSAiR3JlZW4iLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjQsIG1haW4gPSAiUmVkIiwgY29sID0gZ3JheSgwOjEwMCAvIDEwMCkpDQpwbG90KGI1LCBtYWluID0gIk5JUiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KDQpgYGANCg0KIyMjIyMgRWNoYSB1biB2aXN0YXpvIGEgbGFzIGxleWVuZGFzIGRlIGxvcyBtYXBhcyBjcmVhZG9zIGFudGVyaW9ybWVudGUuIFB1ZWRlbiB2YXJpYXIgZW50cmUgMCB5IDEuIE9ic2VydmUgbGEgZGlmZXJlbmNpYSBlbiBlbCBzb21icmVhZG8geSBlbCByYW5nbyBkZSBsZXllbmRhcyBlbnRyZSBsYXMgZGlmZXJlbnRlcyBiYW5kYXMuIEVzdG8gc2UgZGViZSBhIHF1ZSBsYXMgZGlmZXJlbnRlcyBjYXJhY3RlcmlzdGljYXMgZGUgbGEgc3VwZXJmaWNpZSByZWZsZWphbiBsYSByYWRpYWNpb24gc29sYXIgaW5jaWRlbnRlIGRlIG1hbmVyYSBkaWZlcmVudGUuIENhZGEgY2FwYSByZXByZXNlbnRhIGxhIGNhbnRpZGFkIGRlIHJhZGlhY2lvbiBzb2xhciBpbmNpZGVudGUgcXVlIHNlIHJlZmxlamEgcGFyYSB1biByYW5nbyBkZSBsb25naXR1ZCBkZSBvbmRhIHBhcnRpY3VsYXIuIFBvciBlamVtcGxvLCBsYSB2ZWdldGFjaW9uIHJlZmxlamEgbWFzIGVuZXJnaWEgZW4gTklSIHF1ZSBvdHJhcyBsb25naXR1ZGVzIGRlIG9uZGEgeSwgcG9yIGxvIHRhbnRvLCBwYXJlY2UgbWFzIGJyaWxsYW50ZS4gUG9yIGVsIGNvbnRyYXJpbywgZWwgYWd1YSBhYnNvcmJlIGxhIG1heW9yIHBhcnRlIGRlIGxhIGVuZXJnaWEgZW4gbGEgbG9uZ2l0dWQgZGUgb25kYSBOSVIgeSBwYXJlY2Ugb3NjdXJhLg0KDQoNCiMjIyMjIE5vIG9idGVuZW1vcyB0YW50YSBpbmZvcm1hY2lvbiBkZSBlc3RhcyBwYXJjZWxhcyBlbiBlc2NhbGEgZGUgZ3Jpc2VzOyBhIG1lbnVkbyBzZSBjb21iaW5hbiBlbiB1biAiY29tcHVlc3RvIiBwYXJhIGNyZWFyIHRyYW1hcyBtYXMgaW50ZXJlc2FudGVzLiBQdWVkZSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbiBzb2JyZSBsb3MgY29tcHVlc3RvcyBkZSBjb2xvciBlbiBsYSB0ZWxlZGV0ZWNjaW9uIGFxdWkgeSB0YW1iaWVuIGVuIGxhIHNlY2Npb24gYSBjb250aW51YWNpb24uDQoNCg0KIyMjIyMgUGFyYSBoYWNlciB1bmEgaW1hZ2VuIGRlICJjb2xvciB2ZXJkYWRlcm8gKG8gbmF0dXJhbCkiLCBlcyBkZWNpciwgYWxnbyBxdWUgc2UgcGFyZWNlIGEgdW5hIGZvdG9ncmFmaWEgbm9ybWFsICh2ZWdldGFjaW9uIGVuIHZlcmRlLCBhenVsIGFndWEsIGV0Yy4pLCBuZWNlc2l0YW1vcyBiYW5kYXMgZW4gbGFzIHJlZ2lvbmVzIHJvamEsIHZlcmRlIHkgYXp1bC4gUGFyYSBlc3RhIGltYWdlbiBMYW5kc2F0LCBzZSBwdWVkZW4gdXNhciBsYXMgYmFuZGFzIDQgKHJvam8pLCAzICh2ZXJkZSkgeSAyIChhenVsKS4gRWwgLSBwbG90UkdCIC0gbWV0b2RvIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY29tYmluYXJsb3MgZW4gdW4gc29sbyBjb21wdWVzdG8uIFRhbWJpZW4gcHVlZGUgcHJvcG9yY2lvbmFyIGFyZ3VtZW50b3MgYWRpY2lvbmFsZXMgLSBwbG90UkdCIC0gcGFyYSBtZWpvcmFyIGxhIHZpc3VhbGl6YWNpb24gKHBvciBlamVtcGxvLCB1biBlc3RpcmFtaWVudG8gbGluZWFsIGRlIGxvcyB2YWxvcmVzLCB1dGlsaXphbmRvICkuLSBzdHJlY3RoID0gImxpbiIgLQ0KDQoNCmBgYHtyfQ0KbGFuZHNhdFJHQjIwMTUgPSBzdGFjayhiNCwgYjMsIGIyKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCg0KYGBgDQoNCg0KIyMjIyMgRWwgY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyByZXZlbGEgbXVjaG8gbWFzIHNvYnJlIGVsIHBhaXNhamUgcXVlIGxhcyBpbWFnZW5lcyBncmlzZXMgYW50ZXJpb3Jlcy4gT3RybyBtZXRvZG8gcG9wdWxhciBkZSB2aXN1YWxpemFjaW9uIGRlIGltYWdlbmVzIGVuIGxhIHRlbGVkZXRlY2Npb24gZXMgbGEgaW1hZ2VuIGNvbm9jaWRhIGRlICJjb2xvciBmYWxzbyIgZW4gbGEgcXVlIHNlIGNvbWJpbmFuIGxhcyBiYW5kYXMgTklSLCByb2pvIHkgdmVyZGUuIEVzdGEgcmVwcmVzZW50YWNpb24gZXMgcG9wdWxhciB5YSBxdWUgaGFjZSBxdWUgc2VhIGZhY2lsIHZlciBsYSB2ZWdldGFjaW9uIChlbiByb2pvKS4NCg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93ID0gYygxLDIpKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCmxhbmRzYXRGQ0MyMDE1ID0gc3RhY2soYjUsIGI0LCBiMykNCnBsb3RSR0IobGFuZHNhdEZDQzIwMTUsIGF4ZXM9VFJVRSwgc3RyZXRjaD0ibGluIiwgbWFpbj0iTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUiKQ0KDQpgYGANCg0KIyMjIyMgKk5vdGEgOiBDb21wcnVlYmUgc2llbXByZSBsYSBkb2N1bWVudGFjaW9uIGRlbCBwYXF1ZXRlICgtIGhlbHAocGxvdFJHQikgLSkgcGFyYSB2ZXIgb3Ryb3MgYXJndW1lbnRvcyBxdWUgc2UgcHVlZGVuIGFncmVnYXIgKGNvbW8gbGEgZXNjYWxhKSBwYXJhIG1lam9yYXIgbyBtb2RpZmljYXIgbGEgaW1hZ2VuLioNCg0KIyMjIyMgKlByZWd1bnRhIDEgOiBVc2UgbGEgZnVuY2lvbiBwbG90UkdCIGNvbiBSYXN0ZXJTdGFjayBgYCBsYW5kc2F0ICcnIHBhcmEgY3JlYXIgdW4gY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyB5IGZhbHNvIChyZWN1ZXJkZSBsYSBwb3NpY2lvbiBkZSBsYXMgYmFuZGFzIGVuIGxhIHBpbGEpLioNCg0KDQoNCiMjIyAqKlRJVFVMTzogU1VCQ09OSlVOVE8gWSBSRU5PTUJSQVIgQkFOREFTKioNCg0KDQojIyMjIyBQdWVkZSBzZWxlY2Npb25hciBjYXBhcyAoYmFuZGFzKSBlc3BlY2lmaWNhcyBtZWRpYW50ZSBsYSAtIHN1YnNldCAtIGZ1bmNpb24gbyBtZWRpYW50ZSBpbmRleGFjaW9uLg0KDQoNCmBgYHtyfQ0KDQojIHNlbGVjdCBmaXJzdCAzIGJhbmRzIG9ubHkNCmxhbmRzYXQyMDE1c3ViMDEgPSBzdWJzZXQobGFuZHNhdDIwMTUsIDE6MykNCiMgc2FtZQ0KbGFuZHNhdDIwMTVzdWIwMiA9IGxhbmRzYXQyMDE1W1sxOjNdXQ0KIyBOdW1iZXIgb2YgYmFuZHMgaW4gdGhlIG9yaWdpbmFsIGFuZCBuZXcgZGF0YQ0KbmxheWVycyhsYW5kc2F0MjAxNSkNCiMjIFsxXSA3DQpubGF5ZXJzKGxhbmRzYXQyMDE1c3ViMDEpDQojIyBbMV0gMw0KbmxheWVycyhsYW5kc2F0MjAxNXN1YjAyKQ0KIyMgWzFdIDMNCg0KYGBgDQoNCg0KIyMjIyMgTm8gdXNhcmVtb3MgbGFzIHVsdGltYXMgY3VhdHJvIGJhbmRhcyAtIGxhbmRzYXQgLS4gUHVlZGVzIGVsaW1pbmFyIGFxdWVsbG9zIHVzYW5kbzoNCg0KDQpgYGB7cn0NCg0KbGFuZHNhdDIwMTUgPSBzdWJzZXQobGFuZHNhdDIwMTUsIDE6NykNCnBsb3QobGFuZHNhdDIwMTUpDQpgYGANCg0KDQojIyMjIyBQYXJhIG1heW9yIGNsYXJpZGFkLCBlcyB1dGlsIGVzdGFibGVjZXIgbG9zIG5vbWJyZXMgZGUgbGFzIGJhbmRhcy4NCg0KDQpgYGB7cn0NCg0KbmFtZXMobGFuZHNhdDIwMTUpDQoNCiMjIFsxXSAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CMSIgIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjIiDQojIyBbM10gIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjMiICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0I0Ig0KIyMgWzVdICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0I1IiAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNiINCiMjIFs3XSAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNyINCm5hbWVzKGxhbmRzYXQyMDE1KSA9IGMoJ3VsdHJhLWJsdWUnLCAnYmx1ZScsICdncmVlbicsICdyZWQnLCAnTklSJywgJ1NXSVIxJywgJ1NXSVIyJykNCm5hbWVzKGxhbmRzYXQyMDE1KQ0KIyMgWzFdICJ1bHRyYS5ibHVlIiAiYmx1ZSIgICAgICAgImdyZWVuIiAgICAgICJyZWQiICAgICAgICAiTklSIg0KIyMgWzZdICJTV0lSMSIgICAgICAiU1dJUjIiDQoNCmBgYA0KDQoNCg0KIyMjICoqVElUVUxPOiBTVUJDT05KVU5UTyBFU1BBQ0lBTCBPIFJFQ09SVEUqKg0KDQoNCiMjIyMjIEVsIHN1YmNvbmp1bnRvIGVzcGFjaWFsIHNlIHB1ZWRlIHVzYXIgcGFyYSBsaW1pdGFyIGVsIGFuYWxpc2lzIGEgdW4gc3ViY29uanVudG8gZ2VvZ3JhZmljbyBkZSBsYSBpbWFnZW4uIExvcyBzdWJjb25qdW50b3MgZXNwYWNpYWxlcyBzZSBwdWVkZW4gY3JlYXIgY29uIGxhIC0gY3JvcCAtIGZ1bmNpb24sIHV0aWxpemFuZG8gdW4gLSBleHRlbnQgLSBvYmpldG8gdSBvdHJvIG9iamV0byBlc3BhY2lhbCBkZWwgcXVlIHNlIHB1ZWRlIGV4dHJhZXIgdW5hIEV4dGVuc2lvbi4NCg0KYGBge3J9DQoNCiMgVXNpbmcgZXh0ZW50DQpleHRlbnQobGFuZHNhdDIwMTUpDQojIyBjbGFzcyAgICAgIDogRXh0ZW50DQojIyB4bWluICAgICAgIDogNDQ2MDg1IA0KIyMgeG1heCAgICAgICA6IDY3MzUxNQ0KIyMgeW1pbiAgICAgICA6IDM2Mjk4NQ0KIyMgeW1heCAgICAgICA6IDU5NTIxNQ0KDQpzaWJhdGUyMDE1ID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplID0gZXh0ZW50KHNpYmF0ZTIwMTUpDQojIGNyb3AgbGFuZHNhdCBieSB0aGUgZXh0ZW50DQoNCmxhbmRzYXRjcm9wMjAxNSA9IGNyb3AobGFuZHNhdDIwMTUsIGUpDQoNCg0KcGxvdFJHQihsYW5kc2F0Y3JvcDIwMTUsIGF4ZXMgPSBUUlVFLCBzdHJldGNoID0gImxpbiIsIG1haW4gPSAiTGFuZHNhdCBUcnVlIENvbG9yIENvbXBvc2l0ZSIpDQoNCg0KDQpgYGANCg0KDQojIyMjIyAqUHJlZ3VudGEgMiA6IFRhbWJpZW4gZXMgcG9zaWJsZSBsYSBzZWxlY2Npb24gaW50ZXJhY3RpdmEgZGUgbGEgaW1hZ2VuLiBVc2UgYGAgZHJhd0V4dGVudGBgIHkgYGAgZHJhd1BvbHlgYCBwYXJhIHNlbGVjY2lvbmFyIHVuIGFyZWEgZGUgaW50ZXJlcyoNCg0KIyMjIyMgKlByZWd1bnRhIDMgOiBVc2UgZWwgYGAgTGFuZHNhdGNyb3AgJycgZGUgUmFzdGVyU3RhY2sgcGFyYSBjcmVhciB1biBjb21wdWVzdG8gZGUgY29sb3IgdmVyZGFkZXJvIHkgZmFsc28qDQoNCg0KDQojIyMgKipUSVRVTE86IEdVQVJEQU5ETyBSRVNVTFRBRE9TIEVOIEVMIERJU0NPKioNCg0KDQojIyMjIyBFbiBlc3RhIGV0YXBhLCBlcyBwb3NpYmxlIHF1ZSBxdWVyYW1vcyBndWFyZGFyIGVsIHJhc3RlciBlbiBlbCBkaXNjbyB1c2FuZG8gbGEgZnVuY2lvbiAtIHdyaXRlUmFzdGVyIC0uIFNlIGFkbWl0ZW4gbXVsdGlwbGVzIHRpcG9zIGRlIGFyY2hpdm9zLiBVdGlsaXphcmVtb3MgZWwgZm9ybWF0byBHZW9UaWZmIGRlIHVzbyBjb211bi4gTWllbnRyYXMgc2UgY29uc2VydmEgZWwgb3JkZW4gZGUgbGFzIGNhcGFzLCBsb3Mgbm9tYnJlcyBkZSBsYXMgY2FwYXMgc2UgcGllcmRlbiBkZXNhZm9ydHVuYWRhbWVudGUgZW4gZWwgZm9ybWF0byBHZW9UaWZmDQoNCmBgYHtyfQ0KDQp4ID0gd3JpdGVSYXN0ZXIobGFuZHNhdGNyb3AyMDE1LCBmaWxlbmFtZT0iY3JvcHBlZC1sYW5kc2F0LnRpZiIsIG92ZXJ3cml0ZT1UUlVFKQ0KcGxvdCh4KQ0KDQpgYGANCg0KDQojIyMjIyBBbHRlcm5hdGl2YW1lbnRlLCBwdWVkZSB1dGlsaXphciBlbCBmb3JtYXRvICdyYXN0ZXItZ3JkJy4NCg0KDQpgYGB7cn0NCg0Kd3JpdGVSYXN0ZXIobGFuZHNhdGNyb3AyMDE1LCBmaWxlbmFtZT0iY3JvcHBlZC1sYW5kc2F0LmdyZCIsIG92ZXJ3cml0ZT1UUlVFKQ0KDQpgYGANCg0KDQojIyMjIyBVbmEgdmVudGFqYSBkZSBlc3RlIGZvcm1hdG8gZXMgcXVlIGd1YXJkYSBsb3Mgbm9tYnJlcyBkZSBsYXMgY2FwYXMuIExhIGRlc3ZlbnRhamEgZGUgZXN0ZSBmb3JtYXRvIGVzIHF1ZSBubyBtdWNob3Mgb3Ryb3MgcHJvZ3JhbWFzIHB1ZWRlbiBsZWVyIGxvcyBkYXRvcywgZW4gY29udHJhc3RlIGNvbiBlbCBmb3JtYXRvIEdlb1RpZmYuDQoNCiMjIyMjICpOb3RhOiBDb25zdWx0ZSBsYSBkb2N1bWVudGFjaW9uIGRlbCBwYXF1ZXRlICgtIGhlbHAod3JpdGVSYXN0ZXIpIC0pIHBhcmEgdmVyIGFyZ3VtZW50b3MgdXRpbGVzIGFkaWNpb25hbGVzIHF1ZSBzZSBwdWVkZW4gYWdyZWdhcioNCg0KDQoNCiMjIyAqKlRJVFVMTzogUkVMQUNJT04gRU5UUkUgQkFOREFTKioNCg0KDQojIyMjIyBVbmEgbWF0cml6IGRlIGRpYWdyYW1hIGRlIGRpc3BlcnNpb24gcHVlZGUgc2VyIHV0aWwgcGFyYSBleHBsb3JhciBsYXMgcmVsYWNpb25lcyBlbnRyZSBjYXBhcyByYXN0ZXIuIEVzdG8gc2UgcHVlZGUgaGFjZXIgY29uIGxhIGZ1bmNpb24gcGFyZXMgKCkgZGVsIHBhcXVldGUgcmFzdGVyLg0KDQoNCiMjIyMjIFRyYXphZG8gZGUgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIHVsdHJhIGF6dWwgY29udHJhIGVsIHJlZmxlam8gZW4gbGEgbG9uZ2l0dWQgZGUgb25kYSBhenVsLg0KDQoNCmBgYHtyfQ0KcGFpcnMobGFuZHNhdGNyb3AyMDE1W1sxOjJdXSwgbWFpbiA9ICJVbHRyYS1ibHVlIHZlcnN1cyBCbHVlIikNCmBgYA0KDQoNCiMjIyMjIFRyYXphZG8gZGUgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIHJvamEgY29udHJhIHJlZmxlam8gZW4gbGEgbG9uZ2l0dWQgZGUgb25kYSBOSVIuDQoNCg0KYGBge3J9DQpwYWlycyhsYW5kc2F0Y3JvcDIwMTVbWzQ6NV1dLCBtYWluID0gIlJlZCB2ZXJzdXMgTklSIikNCmBgYA0KDQoNCiMjIyMjIExhIHByaW1lcmEgZ3JhZmljYSByZXZlbGEgYWx0YXMgY29ycmVsYWNpb25lcyBlbnRyZSBsYXMgcmVnaW9uZXMgZGUgbG9uZ2l0dWQgZGUgb25kYSBhenVsLiBEZWJpZG8gYSBsYSBhbHRhIGNvcnJlbGFjaW9uLCBwb2RlbW9zIHVzYXIgdW5hIGRlIGxhcyBiYW5kYXMgYXp1bGVzIHNpbiBwZXJkZXIgbXVjaGEgaW5mb3JtYWNpb24uDQoNCiMjIyMjIEVzdGEgZGlzdHJpYnVjaW9uIGRlIHB1bnRvcyBlbiBsYSBzZWd1bmRhIGdyYWZpY2EgKGVudHJlIE5JUiB5IHJvam8pIGVzIHVuaWNhIGRlYmlkbyBhIHN1IGZvcm1hIHRyaWFuZ3VsYXIuIExhIHZlZ2V0YWNpb24gc2UgcmVmbGVqYSBtdXkgYmllbiBlbiBlbCByYW5nbyBOSVIgcXVlIGVsIHJvam8geSBjcmVhIGxhIGVzcXVpbmEgc3VwZXJpb3IgY2VyY2EgZGVsIGVqZSBOSVIgKHkpLiBFbCBhZ3VhIGFic29yYmUgZW5lcmdpYSBkZSB0b2RhcyBsYXMgYmFuZGFzIHkgb2N1cGEgZWwgbHVnYXIgY2VyY2FubyBhbCBvcmlnZW4uIEVsIHJpbmNvbiBtYXMgYWxlamFkbyBzZSBjcmVhIGRlYmlkbyBhIGxhcyBjYXJhY3RlcmlzdGljYXMgc3VwZXJmaWNpYWxlcyBhbHRhbWVudGUgcmVmbGVjdGFudGVzLCBjb21vIGVsIHN1ZWxvIGJyaWxsYW50ZSBvIGVsIGhvcm1pZ29uLg0KDQoNCiMjIyAqKlRJVFVMTzogRVhUUkFFUiBWQUxPUkVTIERFIFBJWEVMRVMgKioNCg0KDQojIyMjIyBBIG1lbnVkbywgcXVlcmVtb3Mgb2J0ZW5lciBsb3MgdmFsb3JlcyBkZSBsYXMgY2VsZGFzIHJhc3RlciBwYXJhIHViaWNhY2lvbmVzIGdlb2dyYWZpY2FzIG8gYXJlYXMgZXNwZWNpZmljYXMuIExhIC0gZXh0cmFjdCAtIGZ1bmNpb24gc2UgdXRpbGl6YSBwYXJhIG9idGVuZXIgdmFsb3JlcyByYXN0ZXIgZW4gbGFzIHViaWNhY2lvbmVzIGRlIG90cm9zIGRhdG9zIGVzcGFjaWFsZXMuIFB1ZWRlIHVzYXIgcHVudG9zLCBsaW5lYXMsIHBvbGlnb25vcyBvIHVuIG9iamV0byBkZSBleHRlbnNpb24gKHJlY3Rhbmd1bG8pLiBUYW1iaWVuIHB1ZWRlIHVzYXIgbnVtZXJvcyBkZSBjZWxkYSBwYXJhIGV4dHJhZXIgdmFsb3Jlcy4gQWwgdXNhciBwdW50b3MsIC0gZXh0cmFjdCAtIGRldnVlbHZlIGxvcyB2YWxvcmVzIGRlIHVuIC0gUmFzdGVyKiAtIG9iamV0byBwYXJhIGxhcyBjZWxkYXMgZW4gbGFzIHF1ZSBzZSB1YmljYSB1biBjb25qdW50byBkZSBwdW50b3MuDQoNCg0KDQpgYGB7cn0NCiMgbG9hZCB0aGUgcG9seWdvbnMgd2l0aCBsYW5kIHVzZSBsYW5kIGNvdmVyIGluZm9ybWF0aW9uDQoNCnNpYmF0ZWNvYmVydCA9IHNoYXBlZmlsZSAoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvUEVSQ0VQQ0lPTiBSRU1PVEEvVFJBQkFKT19DT0JFUlRVUkFTL2NvYmVydHUuc2hwJykNCiAgICAjIHNhbXAgPSByZWFkUkRTKCdkYXRhL3JzL3NhbXBsZXMucmRzJykgICAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgZ2VuZXJhdGUgMzAwIHBvaW50IHNhbXBsZXMgZnJvbSB0aGUgcG9seWdvbnMNCg0KcHRzaWJhdGVjb2JlcnQyMDE1ID0gc3BzYW1wbGUoc2liYXRlY29iZXJ0LDMwMCwgdHlwZT0ncmVndWxhcicpDQogICAgIyBwdHNhbXAgPSBzcHNhbXBsZShzYW1wLCAzMDAsIHR5cGU9J3JlZ3VsYXInKSAgICAgICAqKmVuIGxhIGd1aWEgZXN0YSBhc2kqKg0KDQojIGFkZCB0aGUgbGFuZCBjb3ZlciBjbGFzcyB0byB0aGUgcG9pbnRzDQpwdHNpYmF0ZWNvYmVydCROYW1lID0gb3ZlcihwdHNpYmF0ZWNvYmVydCwgc2liYXRlY29iZXJ0KSROYW1lDQogICAgIyBwdHNhbXAkY2xhc3MgPSBvdmVyKHB0c2FtcCwgc2FtcCkkY2xhc3MgICAgICAgICAgICAqKmVuIGxhIGd1aWEgZXN0YSBhc2kqKg0KDQoNCiMgZXh0cmFjdCB2YWx1ZXMgd2l0aCBwb2ludHMNCmRmID0gZXh0cmFjdChsYW5kc2F0MjAxNSwgcHRzaWJhdGVjb2JlcnQyMDE1KQ0KICAgIyBkZiA9IGV4dHJhY3QobGFuZHNhdDEsIHB0c2FtcCkgICAgICAgICAgICAgICAgICAgICAgKiplbiBsYSBndWlhIGVzdGEgYXNpKioNCg0KIyBUbyBzZWUgc29tZSBvZiB0aGUgcmVmbGVjdGFuY2UgdmFsdWVzDQpoZWFkKGRmKQ0KDQojICAgICB1bHRyYS5ibHVlIGJsdWUgZ3JlZW4gIHJlZCAgIE5JUiBTV0lSMSBTV0lSMg0KI1sxLF0gICAgICAgODQ4NCA3ODAwICA3NTI4IDY5MzEgMTQ3NzcgMTA4NzkgIDgxNjcNCiNbMixdICAgICAgIDg4MTYgODI2NSAgODY5NCA4MTgxIDIxMDI0IDE2NzUzIDExMzEzDQojWzMsXSAgICAgICA4NDE5IDc3OTEgIDgyMDYgNjg0NyAyNDc2MSAxMTgwMSAgNzk2Mg0KI1s0LF0gICAgICAgODM5OSA3NzQ1ICA4MDg3IDY3NzUgMjQ3NzUgMTIxNjAgIDgwMTINCiNbNSxdICAgICAgIDgwNzIgNzM5NCAgNjkwNCA2MjczIDExMjA3ICA4MDk4ICA2NjIxDQojWzYsXSAgICAgICA4MDcyIDczODAgIDY4MjcgNjIzMSAxMDcyOCAgODA4NCAgNjY1NA0KYGBgDQoNCg0KDQojIyMgKipUSVRVTE86IFBFUkZJTEVTIEVTUEVDVFJBTEVTKioNCg0KDQojIyMjIyBVbmEgZ3JhZmljYSBkZWwgZXNwZWN0cm8gKHRvZGFzIGxhcyBiYW5kYXMpIHBhcmEgbG9zIHBpeGVsZXMgcXVlIHJlcHJlc2VudGFuIGNpZXJ0YXMgY2FyYWN0ZXJpc3RpY2FzIGRlIGxhIHN1cGVyZmljaWUgdGVycmVzdHJlIChwLiBFai4gQWd1YSkgc2UgY29ub2NlIGNvbW8gcGVyZmlsIGVzcGVjdHJhbC4gRGljaG9zIHBlcmZpbGVzIGRlbXVlc3RyYW4gbGFzIGRpZmVyZW5jaWFzIGVuIGxhcyBwcm9waWVkYWRlcyBlc3BlY3RyYWxlcyBkZSB2YXJpYXMgY2FyYWN0ZXJpc3RpY2FzIGRlIGxhIHN1cGVyZmljaWUgdGVycmVzdHJlIHkgY29uc3RpdHV5ZW4gbGEgYmFzZSBwYXJhIGVsIGFuYWxpc2lzIGRlIGltYWdlbmVzLiBMb3MgdmFsb3JlcyBlc3BlY3RyYWxlcyBzZSBwdWVkZW4gZXh0cmFlciBkZSBjdWFscXVpZXIgY29uanVudG8gZGUgZGF0b3MgbXVsdGllc3BlY3RyYWxlcyB1dGlsaXphbmRvIGxhIC0gZXh0cmFjdCAtIGZ1bmNpb24uIEVuIGVsIGVqZW1wbG8gYW50ZXJpb3IsIGV4dHJhamltb3MgdmFsb3JlcyBkZSBkYXRvcyBkZSBMYW5kc2F0IHBhcmEgbGFzIG11ZXN0cmFzLiBFc3RhcyBtdWVzdHJhcyBpbmNsdXllbjogdGllcnJhcyBkZSBjdWx0aXZvLCBhZ3VhLCBiYXJiZWNobywgY29uc3RydWlkbyB5IGFiaWVydG8uIFByaW1lcm8gY2FsY3VsYW1vcyBsb3MgdmFsb3JlcyBtZWRpb3MgZGUgcmVmbGVjdGFuY2lhIHBhcmEgY2FkYSBjbGFzZSB5IGNhZGEgYmFuZGEuDQoNCg0KYGBge3J9DQoNCm51bWVybz0gbGVuZ3RoKHB0c2liYXRlY29iZXJ0KQ0KbnVtZXJvDQoNCmRmX3NhbXBsZXMgPSBhcyAocHRzaWJhdGVjb2JlcnQsICJTcGF0aWFsUG9pbnRzRGF0YUZyYW1lIikNCmRmX3NhbXBsZXMNCmRmX3NhbXBsZXNAZGF0YT1kYXRhLmZyYW1lKElEPTE6bnVtZXJvLHNpemU9MSkNCmRmX3NhbXBsZXMNCg0KDQpwbG90KGxhbmRzYXRjcm9wMjAxNSkNCnBsb3Qoc2liYXRlY29iZXJ0LCBhZGQ9IFRSVUUpDQpwbG90KGRmX3NhbXBsZXMscGNoPTEsIGNleD0oZGZfc2FtcGxlcyRzaXplKS80LCBhZGQ9VFJVRSkNCg0KDQpkZl9zYW1wbGVzJE5hbWUgPW92ZXIoZGZfc2FtcGxlcyxzaWJhdGVjb2JlcnQpJE5hbWUNCmRmX3NhbXBsZXMNCmRmMT1yYXN0ZXI6OmV4dHJhY3QobGFuZHNhdGNyb3AyMDE1LCBkZl9zYW1wbGVzKQ0KDQoNCm1zID0gYWdncmVnYXRlKGRmMSwgbGlzdChwdHNpYmF0ZWNvYmVydCROYW1lKSwgbWVhbikNCiMjIG1zID0gYWdncmVnYXRlKGRmLCBsaXN0KHB0c2FtcCRjbGFzcyksIG1lYW4pICAgICAgICAgKiogYXNpIGVzdGEgZW4gbGEgZ3VpYSoqDQoNCiMgaW5zdGVhZCBvZiB0aGUgZmlyc3QgY29sdW1uLCB3ZSB1c2Ugcm93IG5hbWVzDQpyb3duYW1lcyhtcykgPSBtc1ssMV0NCm1zID0gbXNbLC0xXQ0KbXMNCg0KDQojIyAgICAgICAgICB1bHRyYS5ibHVlICAgICAgYmx1ZSAgICAgIGdyZWVuICAgICAgIHJlZCAgICAgICAgTklSICAgICAgU1dJUjENCiMjIGJ1aWx0ICAgICAwLjE4NjQ5MjUgMC4xNzk1MzcxIDAuMTc5NTMzMTcgMC4xOTU4NDE0IDAuMjU0NDg0NDcgMC4yNDg1MDE5Nw0KIyMgY3JvcGxhbmQgIDAuMTEyOTgxMyAwLjA5MDk2NDUgMC4wODU5NjcyMiAwLjA1NTAzNDQgMC40ODMzNTQ2MiAwLjE2MTQyMDg1DQojIyBmYWxsb3cgICAgMC4xMzE5MTk4IDAuMTE2NDg2OSAwLjEwNDUzNzY0IDAuMTE1MTI0MyAwLjE4MDEyOTYyIDAuMjMxMzkyMjgNCiMjIG9wZW4gICAgICAwLjEzODgwMTQgMC4xMzc1MjM1IDAuMTUyNzMxNjMgMC4yMDY2NDI1IDAuMzQ0NzY2NzAgMC4zNTgyMDg3Nw0KIyMgd2F0ZXIgICAgIDAuMTMzNjI0MiAwLjExNjU3MjggMC4wOTkyMjcyNiAwLjA3ODU5NDcgMC4wNDkwOTIwMSAwLjAzMzYwMDQ3DQojIyAgICAgICAgICAgICAgIFNXSVIyDQojIyBidWlsdCAgICAwLjIwMDAxMzA2DQojIyBjcm9wbGFuZCAwLjA3MzE0MTg2DQojIyBmYWxsb3cgICAwLjE5MTQzMDMwDQojIyBvcGVuICAgICAwLjIxMzQ2MzQzDQojIyB3YXRlciAgICAwLjAyNzIzMzk4DQoNCmBgYA0KDQoNCiMjIyMjIEFob3JhIHRyYXphbW9zIGVsIGVzcGVjdHJvIG1lZGlvIGRlIGVzdGFzIGNhcmFjdGVyaXN0aWNhcy4NCg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgdmVjdG9yIG9mIGNvbG9yIGZvciB0aGUgbGFuZCBjb3ZlciBjbGFzc2VzIGZvciB1c2UgaW4gcGxvdHRpbmcNCm15Y29sb3IgPSBjKCdkYXJrcmVkJywgJ3llbGxvdycsICdidXJseXdvb2QnLCAnY3lhbicsICdibHVlJywgJ2dyZWVuJywncGluaycpDQojdHJhbnNmb3JtIG1zIGZyb20gYSBkYXRhLmZyYW1lIHRvIGEgbWF0cml4DQptcyA9IGFzLm1hdHJpeChtcykNCiMgRmlyc3QgY3JlYXRlIGFuIGVtcHR5IHBsb3QNCnBsb3QoMCwgeWxpbT1jKDAsMjUwMDApLCB4bGltID0gYygxLDcpLCB0eXBlPSduJywgeGxhYj0iQmFuZHMiLCB5bGFiID0gIlJlZmxlY3RhbmNlIikNCiMgYWRkIHRoZSBkaWZmZXJlbnQgY2xhc3Nlcw0KZm9yIChpIGluIDE6bnJvdyhtcykpew0KICBsaW5lcyhtc1tpLF0sIHR5cGUgPSAibCIsIGx3ZCA9IDMsIGx0eSA9IDEsIGNvbCA9IG15Y29sb3JbaV0pDQp9DQojIFRpdGxlDQp0aXRsZShtYWluPSJTcGVjdHJhbCBQcm9maWxlIGZyb20gTGFuZHNhdCIsIGZvbnQubWFpbiA9IDIpDQojIExlZ2VuZA0KbGVnZW5kKCJ0b3BsZWZ0Iiwgcm93bmFtZXMobXMpLA0KICAgICAgIGNleD0wLjgsIGNvbD1teWNvbG9yLCBsdHkgPSAxLCBsd2QgPTMsIGJ0eSA9ICJuIikNCmBgYA0KDQoNCiMjIyMjIEVsIHBlcmZpbCBlc3BlY3RyYWwgbXVlc3RyYSAoZGVzKSBzaW1pbGl0dWQgZW4gbGEgcmVmbGVjdGFuY2lhIGRlIGRpZmVyZW50ZXMgY2FyYWN0ZXJpc3RpY2FzIGVuIGxhIHN1cGVyZmljaWUgZGUgbGEgdGllcnJhIChvIHBvciBlbmNpbWEgZGUgZWxsYSkuICdBZ3VhJyBtdWVzdHJhIHVuYSByZWZsZXhpb24gcmVsYXRpdmFtZW50ZSBiYWphIGVuIHRvZGFzIGxhcyBsb25naXR1ZGVzIGRlIG9uZGEsIHkgJ2NvbnN0cnVpZG8nLCAnZW4gYmFyYmVjaG8nIHkgJ2FiaWVydG8nIHRpZW5lbiB1bmEgcmVmbGVjdGFuY2lhIHJlbGF0aXZhbWVudGUgYWx0YSBlbiBsYXMgbG9uZ2l0dWRlcyBkZSBvbmRhIG1hcyBsYXJnYXMuDQoNCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0K