Landsat 8 recopilada el 04 de enero de 2015. El subconjunto cubre el area de Sibate, departamento de Cundinamarca, en Colombia

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Seleccionar la carpeta de destino
#"C:/Users/David/Desktop/Landsat_procesamiento"
getwd()
[1] "C:/Users/David/Desktop/Landsat_procesamiento"

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

Crear objetos RasterLayer para capas individuales Landsat (bandas) y las llamamos enrutandolas como por ejemplo (‘./data/LC08_L1TP_008057_20180317_20180403_01_T1_B2.tif’)
IMPORTANTE: instalar paquetes: raster, sp, rgdal
En este capitulo se describe la forma de acceder y explorar por satelite datos de teledeteccion con R . Tambien mostramos como usarlos para hacer mapas.
Utilizaremos principalmente un subconjunto espacial de una escena Landsat 8 recopilada el 14 de junio de 2017. El subconjunto cubre el area entre Concord y Stockton , en California, EE. UU.
Todas las escenas de imagenes de Landsat tienen una identificacion de producto y metadatos unicos. Puede encontrar la informacion sobre el sensor Landsat, el satelite, la ubicacion en la Tierra (ruta WRS, fila WRS) y la fecha de adquisicion a partir de la ID del producto. Por ejemplo, el identificador de producto de los datos que utilizaremos es ‘LC08_044034_20170614’. Con base en esta guia , puede ver que el Sensor-Satelite es OLI / TIRS combinados Landsat 8, WRS Path 44, WRS Row 34 y recopilados el 14 de junio de 2017. Las escenas de Landsat se entregan mas comunmente como un archivo comprimido, que contiene archivos separados para cada banda
Comenzaremos explorando y visualizando los datos (consulte las instrucciones en el Capitulo 1 para obtener instrucciones de descarga de datos si aun no lo ha hecho).

TITULO: PROPIEDADES DE IMAGEN

Crear objetos RasterLayer para capas individuales Landsat (bandas)
library(raster)
b1 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B1.tif')
# azul
b2 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B2.tif')
# verde
b3 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B3.tif')
# rojo
b4 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B4.tif')
# Infrarojo cercano (NIR)
b5 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B5.tif')
b6 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B6.tif')
b7 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B7.tif')
b8 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B8.tif')
b9 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B9.tif')
b10 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B10.tif')
b11 = raster('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B11.tif')
se inserta un nuevo bloque de codigo ctrl+alt+i: imprimir las variables para verificar, por ejemplo:
b2
class      : RasterLayer 
dimensions : 7741, 7581, 58684521  (nrow, ncol, ncell)
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 
source     : C:/Users/David/Desktop/Landsat_procesamiento/data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B2.tif 
names      : LC08_L1TP_008057_20150104_20170415_01_T1_B2 
values     : 0, 65535  (min, max)
Puede ver la resolucion espacial, la extension, el numero de capas, el sistema de referencia de coordenadas y mas.

TITULO: INFORMACION DE IMAGEN Y ESTADISTICAS

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.
No obtenemos tanta informacion de estas parcelas en escala de grises; a menudo se combinan en un “compuesto” para crear tramas mas interesantes. Puede obtener mas informacion sobre los compuestos de color en la teledeteccion aqui y tambien en la seccion a continuacion.
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")

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).
## solucion a la pregunta 1
landsatFCC2015_p1 = stack(b5, b6, b4)
plotRGB(landsatFCC2015_p1, axes=TRUE, stretch="lin", main="Landsat composicion de color falsa - Agua / Tierra")

TITULO: SUBCONJUNTO Y RENOMBRAR BANDAS

Puede seleccionar capas (bandas) especificas mediante la - subset - funcion o mediante indexacion.
# select first 3 bands only
landsat2015sub01 = subset(landsat2015, 1:3)
# same
landsat2015sub02 = landsat2015[[1:3]]
# Number of bands in the original and new data
nlayers(landsat2015)
[1] 7
## [1] 7
nlayers(landsat2015sub01)
[1] 3
## [1] 3
nlayers(landsat2015sub02)
[1] 3
## [1] 3
No usaremos las ultimas cuatro bandas - landsat -. Puedes eliminar aquellos usando:
landsat2015 = subset(landsat2015, 1:7)
plot(landsat2015)

Para mayor claridad, es util establecer los nombres de las bandas.
names(landsat2015)
[1] "LC08_L1TP_008057_20150104_20170415_01_T1_B1" "LC08_L1TP_008057_20150104_20170415_01_T1_B2"
[3] "LC08_L1TP_008057_20150104_20170415_01_T1_B3" "LC08_L1TP_008057_20150104_20170415_01_T1_B4"
[5] "LC08_L1TP_008057_20150104_20170415_01_T1_B5" "LC08_L1TP_008057_20150104_20170415_01_T1_B6"
[7] "LC08_L1TP_008057_20150104_20170415_01_T1_B7"
## [1] "LC08_L1TP_008057_20180317_20180403_01_T1_B1" "LC08_L1TP_008057_20180317_20180403_01_T1_B2"
## [3] "LC08_L1TP_008057_20180317_20180403_01_T1_B3" "LC08_L1TP_008057_20180317_20180403_01_T1_B4"
## [5] "LC08_L1TP_008057_20180317_20180403_01_T1_B5" "LC08_L1TP_008057_20180317_20180403_01_T1_B6"
## [7] "LC08_L1TP_008057_20180317_20180403_01_T1_B7"
names(landsat2015) = c('ultra-blue', 'blue', 'green', 'red', 'NIR', 'SWIR1', 'SWIR2')
names(landsat2015)
[1] "ultra.blue" "blue"       "green"      "red"        "NIR"        "SWIR1"      "SWIR2"     
## [1] "ultra.blue" "blue"       "green"      "red"        "NIR"
## [6] "SWIR1"      "SWIR2"

TITULO: SUBCONJUNTO ESPACIAL O RECORTE

El subconjunto espacial se puede usar para limitar el analisis a un subconjunto geografico de la imagen. Los subconjuntos espaciales se pueden crear con la - crop - funcion, utilizando un - extent - objeto u otro objeto espacial del que se puede extraer una Extension.
# Using extent
extent(landsat2015)
class      : Extent 
xmin       : 446085 
xmax       : 673515 
ymin       : 362985 
ymax       : 595215 
## class      : Extent
## xmin       : 446085 
## xmax       : 673515
## ymin       : 362985
## ymax       : 595215
sibate2015 = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
e = extent(sibate2015)
# crop landsat by the extent
landsatcrop2015 = crop(landsat2015, e)
plotRGB(landsatcrop2015, axes = TRUE, stretch = "lin", main = "Landsat True Color Composite")

Pregunta 2 : Tambien es posible la seleccion interactiva de la imagen. Use drawExtent y drawPoly para seleccionar un area de interes

se da respuesta a esta pregunta con el ejercicio anterior

Pregunta 3 : Use el `` Landsatcrop ’’ de RasterStack para crear un compuesto de color verdadero y falso
landsatcrop2015pregunta = crop(stack(b4, b3, b2), e)
plotRGB(landsatcrop2015pregunta, axes = TRUE, stretch = "lin", main = "Landsat Sibate 2015 - Color Verdadero")

TITULO: GUARDANDO RESULTADOS EN EL DISCO

En esta etapa, es posible que queramos guardar el raster en el disco usando la funcion - writeRaster -. Se admiten multiples tipos de archivos. Utilizaremos el formato GeoTiff de uso comun. Mientras se conserva el orden de las capas, los nombres de las capas se pierden desafortunadamente en el formato GeoTiff
x = writeRaster(landsatcrop2015, filename="cropped-landsat.tif", overwrite=TRUE)
plot(x)

Alternativamente, puede utilizar el formato ‘raster-grd’.
writeRaster(landsatcrop2015, filename="cropped-landsat.grd", overwrite=TRUE)
Una ventaja de este formato es que guarda los nombres de las capas. La desventaja de este formato es que no muchos otros programas pueden leer los datos, en contraste con el formato GeoTiff.
Nota: Consulte la documentacion del paquete (- help(writeRaster) -) para ver argumentos utiles adicionales que se pueden agregar

TITULO: RELACION ENTRE BANDAS

Una matriz de diagrama de dispersion puede ser util para explorar las relaciones entre capas raster. Esto se puede hacer con la funcion pares () del paquete raster.
Trazado de reflejo en la longitud de onda ultra azul contra el reflejo en la longitud de onda azul.
pairs(landsatcrop2015[[1:2]], main = "Ultra-blue versus Blue")

Trazado de reflejo en la longitud de onda roja contra reflejo en la longitud de onda NIR.
pairs(landsatcrop2015[[4:5]], main = "Red versus NIR")

La primera grafica revela altas correlaciones entre las regiones de longitud de onda azul. Debido a la alta correlacion, podemos usar una de las bandas azules sin perder mucha informacion.
Esta distribucion de puntos en la segunda grafica (entre NIR y rojo) es unica debido a su forma triangular. La vegetacion se refleja muy bien en el rango NIR que el rojo y crea la esquina superior cerca del eje NIR (y). El agua absorbe energia de todas las bandas y ocupa el lugar cercano al origen. El rincon mas alejado se crea debido a las caracteristicas superficiales altamente reflectantes, como el suelo brillante o el hormigon.

TITULO: EXTRAER VALORES DE PIXELES

A menudo, queremos obtener los valores de las celdas raster para ubicaciones geograficas o areas especificas. La - extract - funcion se utiliza para obtener valores raster en las ubicaciones de otros datos espaciales. Puede usar puntos, lineas, poligonos o un objeto de extension (rectangulo). Tambien puede usar numeros de celda para extraer valores. Al usar puntos, - extract - devuelve los valores de un - Raster* - objeto para las celdas en las que se ubica un conjunto de puntos.
# load the polygons with land use land cover information
sibatecobert = shapefile ('C:/Users/David/Desktop/PERCEPCION REMOTA/TRABAJO_COBERTURAS/cobertu.shp')
Z-dimension discarded
    # samp = readRDS('data/rs/samples.rds')              **en la guia esta asi**
# generate 300 point samples from the polygons
ptsibatecobert = spsample(sibatecobert,300, type='regular')
    # ptsamp = spsample(samp, 300, type='regular')       **en la guia esta asi**
# add the land cover class to the points
ptsibatecobert$Name = over(ptsibatecobert, sibatecobert)$Name
    # ptsamp$class = over(ptsamp, samp)$class            **en la guia esta asi**
# extract values with points
df = extract(landsat2015, ptsibatecobert)
   # df = extract(landsat1, ptsamp)                      **en la guia esta asi**
# To see some of the reflectance values
head(df)
     ultra.blue blue green  red   NIR SWIR1 SWIR2
[1,]       8484 7800  7528 6931 14777 10879  8167
[2,]       8816 8265  8694 8181 21024 16753 11313
[3,]       8577 7887  8185 7206 22881 12103  8138
[4,]       8399 7745  8087 6775 24775 12160  8012
[5,]       8204 7535  7134 6580 12286  9489  7410
[6,]       9797 9209  8825 8046 13806  9671  7765
#     ultra.blue blue green  red   NIR SWIR1 SWIR2
#[1,]       8484 7800  7528 6931 14777 10879  8167
#[2,]       8816 8265  8694 8181 21024 16753 11313
#[3,]       8419 7791  8206 6847 24761 11801  7962
#[4,]       8399 7745  8087 6775 24775 12160  8012
#[5,]       8072 7394  6904 6273 11207  8098  6621
#[6,]       8072 7380  6827 6231 10728  8084  6654

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] 296
df_samples = as (ptsibatecobert, "SpatialPointsDataFrame")
df_samples
class       : SpatialPointsDataFrame 
features    : 296 
extent      : 577369.2, 585652.4, 493591.4, 501100.5  (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    : 296 
extent      : 577369.2, 585652.4, 493591.4, 501100.5  (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  : 296,    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    : 296 
extent      : 577369.2, 585652.4, 493591.4, 501100.5  (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  : 296,    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.

TITULO: OPERACIONES MATEMATICAS BASICAS

El - raster- paquete admite muchas operaciones matematicas. Las operaciones matematicas generalmente se realizan por pixel (celda de cuadricula). Primero haremos algunas operaciones aritmeticas basicas para combinar bandas. En el primer ejemplo, escribimos una funcion matematica personalizada para calcular el indice de vegetacion de diferencia normalizada (NDVI).
### solo puedo cargar las bandas de la 1 a la 7 porque la 8 no tiene la misma extension de las demas
raslistp3 = paste0('./data2015/LC08_L1TP_008057_20150104_20170415_01_T1_B', 1:7, ".tif")
##raslistp3= practica 3
landsatp3 = stack(raslistp3)
plot(landsatp3)

landsatRGBp3 = landsatp3[[c(4,3,2)]]
## landsatRGBp3 = practica 3
plot(landsatRGBp3)

landsatFCCp3 = landsatp3[[c(5,4,3)]]
## landsatFCCp3 = practica 3
plot(landsatFCCp3)

TITULO: INDICES DE VEGETACION

Definamos una funciOn general para un Indice basado en razOn (vegetaciOn). En la funcion a continuacion, -img- es un objeto Raster * de multiples capas -i- y -k- son los indices de las capas (numeros de capa) utilizados para calcular el indice de vegetacion.
## vi2015= indice de vegetacion para la imagen 2015
vi2015 = function(img, k, i) {
  
  bk = img [[k]]
  bi = img [[i]]
  vi2015=(bk-bi)/(bk+bi)
  return(vi2015)
}
## para landsat NIR = 5, red = 4
## ndvi2015= indice de vegetacion de direfencia normalizada (NDVI) para la imagen landsat 2015
ndvi2015 = vi2015(landsatp3, 5, 4) 
plot(ndvi2015, col=rev(terrain.colors(9)), main= "Landsat 2015 - NVDI")

NDVI1_sibate_2015 = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
eNDVI1_sibate = extent(NDVI1_sibate_2015)
# crop landsat by the extent
NDVI_recorte_1 = crop(ndvi2015, eNDVI1_sibate)
plot(NDVI_recorte_1, col=rev(terrain.colors(10)), main = "Landsat 2015 - NDVI")

Puedes ver la variacion en el verdor desde la trama.
Una forma alternativa de lograr esto es asi
vi2_2015 = function(x, y) {
  (x-y)/(x+y)
}
ndvi2_2015 = overlay(landsatp3[[5]], landsatp3[[4]], fun = vi2_2015)
plot(ndvi2_2015, col=rev(terrain.colors(10)), main = "Landsat 2015 - NDVI v2")

NDVI2_sibate_2015 = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
eNDVI2_sibate = extent(NDVI2_sibate_2015)
# crop landsat by the extent
NDVI_recorte_2 = crop(ndvi2_2015, eNDVI2_sibate)
plot(NDVI_recorte_2, col=rev(terrain.colors(10)), main = "Landsat 2015 - NDVI")

Pregunta 1 : Adapte el codigo que se muestra arriba para calcular los indices para identificar i) agua y ii) acumulados. Sugerencia: Use el diagrama del perfil espectral para encontrar las bandas que tienen reflectancia maxima y minima para estas dos clases.
## p1 es pregunta 1
ndvi2015_p1 = vi2015(landsatp3, 3, 6) 
plot(ndvi2015_p1, col=rev(terrain.colors(10)), main= "Landsat 2015 - NDWI")

vi2_2015_p1 = function(x, y) {
  (x-y)/(x+y)
}
ndvi2_2015_p1 = overlay(landsatp3[[3]], landsatp3[[6]], fun = vi2_2015_p1)
plot(ndvi2_2015_p1, col=rev(topo.colors(10)), main = "Landsat 2015 - NDWI")

### PARA INDICE DE AGUA DE DIFERENCIA NORMALIZADA - NDWI
NDWI_sibate = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
eNDWI = extent(NDWI_sibate)
# crop landsat by the extent
NDWI_recorte = crop(ndvi2_2015_p1, eNDWI)
plot(NDWI_recorte, col=rev(topo.colors(10)), main = "Landsat 2015 - NDWI")

### PARA INDICE INCORPORADO DE DIFERENCIA NORMALIZADA - NDBI
ndbi1_2015_p1 = overlay(landsatp3[[6]], landsatp3[[5]], fun = vi2_2015_p1)
plot(ndbi1_2015_p1, col=rev(heat.colors(10)), main = "Landsat 2015 - NDBI")

## recortado a sibate
NDBI_sibate = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
eNDBI = extent(NDBI_sibate)
# crop landsat by the extent
NDBI_recorte = crop(ndbi1_2015_p1, eNDBI)
plot(NDBI_recorte, col=rev(heat.colors(10)), main = "Landsat 2015 - NDWI")

TITULO: HISTOGRAMA

Podemos explorar la distribucion de valores contenidos en nuestro raster utilizando la funcion -hist ()- que produce un histograma. Los histogramas a menudo son utiles para identificar valores atipicos y valores de datos incorrectos en nuestros datos raster
## ver histograma de datos
hist(NDVI_recorte_1,
     main= "Dsitribucion de valores del NDVI",
     xlab= "NDVI",
     ylab= "Frecuencia",
     col= terrain.colors(50),
     xlim= c (-0.1,0.7),
     breaks = 30,
     xaxt= 'n')
axis(side = 1, at=seq(-0.5,1,0.05), labels = seq(-0.5,1,0.05))

Nos referiremos a este histograma para la siguiente subseccion sobre umbralizacion.
Pregunta 2 : Haga histogramas de los valores que los indices de vegetacion desarrollaron en la pregunta 1
## respuesta a la pregunta 2: ver histograma de datos
hist(NDWI_recorte,
     main= "Dsitribucion de valores del NDWI",
     xlab= "NDWI",
     ylab= "Frecuencia",
     col= topo.colors(50),
     xlim= c (-0.5,0.3),
     breaks = 30,
     xaxt= 'n')
axis(side = 1, at=seq(-0.5,1,0.05), labels = seq(-0.5,1,0.05))

## respuesta a la pregunta 2: ver histograma de datos
hist(NDBI_recorte,
     main= "Dsitribucion de valores del NDBI",
     xlab= "NDBI",
     ylab= "Frecuencia",
     col= heat.colors(50),
     xlim= c (-0.5,0.3),
     breaks = 30,
     xaxt= 'n')
axis(side = 1, at=seq(-0.5,1,0.05), labels = seq(-0.5,1,0.05))

TITULO: UMBRALIZACION

Podemos aplicar reglas basicas para obtener una estimacion de la extension espacial de diferentes caracteristicas de la superficie terrestre. Tenga en cuenta que los valores NDVI estan estandarizados y varian entre -1 y +1. Los valores mas altos indican mas cobertura verde.
Las celdas con valores de NDVI superiores a 0.4 son definitivamente vegetacion. La siguiente operacion enmascara todas las celdas que tal vez no sean vegetacion.
veg = reclassify(NDVI_recorte_1, cbind(-Inf, 0.4, NA))
plot(veg, main = "Vegetacion")

Vamos a mapear el area que corresponde al pico entre 0.25 y 0.3 en el histograma NDVI.
land = reclassify(NDVI_recorte_1, c(-Inf, 0.25, NA, 0.25, 0.3, 1, 0.3, Inf, NA))
plot(land, main = " Que es esto?")

Estas pueden ser las areas abiertas. Puede trazar -land- sobre el -landsatFCC- raster original para obtener mas informacion

plotRGB(landsatcrop2015, r=1, b=2, g=3, axes = TRUE, stretch="lin", main = "Landsat Sibate composicion en falso color")
plot(land, add = TRUE, legend= FALSE)

Tambien puede crear clases para diferentes cantidades de presencia de vegetacion.
vegc = reclassify(NDVI_recorte_1, c(-Inf,0.25,1, 0.25,0.3,2, 0.3,0.4,3, 0.4,0.5,4, 0.5,Inf, 5))
plot(vegc, col = rev(terrain.colors(4)), main = 'Umbral basado en NDVI')

Pregunta 3 : Es posible encontrar agua usando el umbral de NDVI o cualquier otro indice
agua = reclassify(NDWI_recorte, cbind(-Inf, 0.1, NA))
plot(agua, main = "Agua", col= topo.colors(10))

aguac = reclassify(NDWI_recorte, c(-Inf,0.025,1, 0.025,0.03,2, 0.03,0.1,3, 0.1,0.2,4, 0.2,Inf, 5))
plot(aguac, col = rev(topo.colors(10)), main = 'Umbral basado en NDwI')

TITULO: ANALISIS DE COMPONENTES PRINCIPALES

Los datos multiespectrales a veces se transforman para ayudar a reducir la dimensionalidad y el ruido en los datos. La transformacion de componentes principales es un metodo generico de reduccion de datos que se puede utilizar para crear algunas bandas no correlacionadas a partir de un conjunto mas grande de bandas correlacionadas.
Puede calcular el mismo numero de componentes principales que el numero de bandas de entrada. El primer componente principal (PC) explica el mayor porcentaje de varianza y otras PC explican la varianza adicional en orden decreciente.
set.seed(1)
sr = sampleRandom(landsatp3, 10000)
plot(sr[,c(4,5)], main = "NIR - Red plot")

Esto se conoce como diagrama de vegetacion y linea de suelo (igual que el diagrama de dispersion en la seccion anterior).
pca = prcomp(sr, scale = TRUE)
pca
Standard deviations (1, .., p=7):
[1] 2.59320781 0.42283706 0.28432083 0.10272416 0.06739963 0.02013456 0.01197457

Rotation (n x k) = (7 x 7):
                                                   PC1         PC2         PC3         PC4         PC5
LC08_L1TP_008057_20150104_20170415_01_T1_B1 -0.3827161  0.13951992 -0.29577337  0.64426612 -0.09248285
LC08_L1TP_008057_20150104_20170415_01_T1_B2 -0.3823702  0.24607769 -0.25399056  0.24551600 -0.03813431
LC08_L1TP_008057_20150104_20170415_01_T1_B3 -0.3830553  0.23811360 -0.16711614 -0.23489380 -0.03847541
LC08_L1TP_008057_20150104_20170415_01_T1_B4 -0.3785436  0.42429526  0.00253034 -0.62149875 -0.06620595
LC08_L1TP_008057_20150104_20170415_01_T1_B5 -0.3624394 -0.75242358 -0.42394861 -0.24244188  0.23460165
LC08_L1TP_008057_20150104_20170415_01_T1_B6 -0.3767577 -0.34216544  0.52654673  0.04094435 -0.67771841
LC08_L1TP_008057_20150104_20170415_01_T1_B7 -0.3794551  0.00608041  0.60256852  0.15084020  0.68541151
                                                     PC6           PC7
LC08_L1TP_008057_20150104_20170415_01_T1_B1  0.070397514 -0.5639086914
LC08_L1TP_008057_20150104_20170415_01_T1_B2  0.262981944  0.7731983872
LC08_L1TP_008057_20150104_20170415_01_T1_B3 -0.842879576  0.0392600097
LC08_L1TP_008057_20150104_20170415_01_T1_B4  0.454485570 -0.2819057041
LC08_L1TP_008057_20150104_20170415_01_T1_B5  0.092049830 -0.0217900795
LC08_L1TP_008057_20150104_20170415_01_T1_B6 -0.007898927  0.0518065166
LC08_L1TP_008057_20150104_20170415_01_T1_B7 -0.018601359  0.0005871392
screeplot(pca)

pci = predict(landsatp3, pca, index = 1:2)
Warning in .Internal(gc(verbose, reset, full)) :
  closing unused connection 3 (C:/Users/David/AppData/Local/Temp/Rtmpw1HOgY/raster/r_tmp_2020-03-29_143139_208_24915.gri)
plot(pci[[1]])

## recortado a sibate
pci_sibate = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
epci = extent(pci_sibate)
# crop landsat by the extent
pci_recorte = crop(pci, epci)
plot(pci_recorte, col=rev(terrain.colors(20)), main = "pci Sibate")

El primer componente principal resalta los limites entre las clases de uso de la tierra o los detalles espaciales, que es la informacion mas comun entre todas las longitudes de onda. Es dificil entender lo que destaca el segundo componente principal. Vamos a intentar umbral de nuevo:
landsatFCC2015 = stack(b5, b4, b3)
# plotRGB(landsatFCC2015, axes=TRUE, stretch="lin", main="Landsat False Color Composite")
## recortado a sibate
pc2 = shapefile('C:/Users/David/Desktop/SIBATE_RURAL/rural.shp')
epc2 = extent(pc2)
# crop landsat by the extent
pc2_rec= crop(landsatFCC2015, epc2)
# plot(pc2_rec, col=rev(terrain.colors(20)), main = "pci Sibate")
pc2 = reclassify(pci_recorte[[2]], c(-Inf,0,1,0,Inf,NA))
par(mfrow = c(1,2))
plotRGB(pc2_rec, r = 1, g = 2, b = 3, axes = TRUE, stretch = "lin", main = "Landsat False Color Composite")
plotRGB(pc2_rec, r = 1, g = 2, b = 3, axes = TRUE, stretch = "lin", main = "Landsat False Color Composite")
plot(pc2, legend = FALSE, add = TRUE)

Para obtener mas informacion acerca de la informacion contenida en las parcelas de vegetacion y lineas de suelo, lea este documento de -Gitelson et al- . Una extension de PCA en la teledeteccion se conoce como Transformacion -Tasseled-cap- .

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.

LS0tDQp0aXRsZTogIioqSW1hZ2VuIExhbmRTYXQgOCwgU2liYXRlIDIwMTUqKiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQoNCiMjIyMjICoqTGFuZHNhdCA4IHJlY29waWxhZGEgZWwgMDQgZGUgZW5lcm8gZGUgMjAxNS4gRWwgc3ViY29uanVudG8gY3VicmUgZWwgYXJlYSBkZSBTaWJhdGUsIGRlcGFydGFtZW50byBkZSBDdW5kaW5hbWFyY2EsIGVuIENvbG9tYmlhKioNCg0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KDQojIyMjIyBTZWxlY2Npb25hciBsYSBjYXJwZXRhIGRlIGRlc3Rpbm8gDQoNCg0KYGBge3J9DQojIkM6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvTGFuZHNhdF9wcm9jZXNhbWllbnRvIg0KZ2V0d2QoKQ0KYGBgDQoNCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykgeSBsYXMgbGxhbWFtb3MgZW5ydXRhbmRvbGFzIGNvbW8gcG9yIGVqZW1wbG8gKCcuL2RhdGEvTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CMi50aWYnKQ0KDQojIyMjIypJTVBPUlRBTlRFOiBpbnN0YWxhciBwYXF1ZXRlczogcmFzdGVyLCBzcCwgcmdkYWwqDQoNCiMjIyMjIEVuIGVzdGUgY2FwaXR1bG8gc2UgZGVzY3JpYmUgbGEgZm9ybWEgZGUgYWNjZWRlciB5IGV4cGxvcmFyIHBvciBzYXRlbGl0ZSBkYXRvcyBkZSB0ZWxlZGV0ZWNjaW9uIGNvbiBSIC4gVGFtYmllbiBtb3N0cmFtb3MgY29tbyB1c2FybG9zIHBhcmEgaGFjZXIgbWFwYXMuDQoNCiMjIyMjIFV0aWxpemFyZW1vcyBwcmluY2lwYWxtZW50ZSB1biBzdWJjb25qdW50byBlc3BhY2lhbCBkZSB1bmEgZXNjZW5hIExhbmRzYXQgOCByZWNvcGlsYWRhIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIEVsIHN1YmNvbmp1bnRvIGN1YnJlIGVsIGFyZWEgZW50cmUgQ29uY29yZCB5IFN0b2NrdG9uICwgZW4gQ2FsaWZvcm5pYSwgRUUuIFVVLg0KDQojIyMjIyBUb2RhcyBsYXMgZXNjZW5hcyBkZSBpbWFnZW5lcyBkZSBMYW5kc2F0IHRpZW5lbiB1bmEgaWRlbnRpZmljYWNpb24gZGUgcHJvZHVjdG8geSBtZXRhZGF0b3MgdW5pY29zLiBQdWVkZSBlbmNvbnRyYXIgbGEgaW5mb3JtYWNpb24gc29icmUgZWwgc2Vuc29yIExhbmRzYXQsIGVsIHNhdGVsaXRlLCBsYSB1YmljYWNpb24gZW4gbGEgVGllcnJhIChydXRhIFdSUywgZmlsYSBXUlMpIHkgbGEgZmVjaGEgZGUgYWRxdWlzaWNpb24gYSBwYXJ0aXIgZGUgbGEgSUQgZGVsIHByb2R1Y3RvLiBQb3IgZWplbXBsbywgZWwgaWRlbnRpZmljYWRvciBkZSBwcm9kdWN0byBkZSBsb3MgZGF0b3MgcXVlIHV0aWxpemFyZW1vcyBlcyAnTEMwOF8wNDQwMzRfMjAxNzA2MTQnLiBDb24gYmFzZSBlbiBlc3RhIGd1aWEgLCBwdWVkZSB2ZXIgcXVlIGVsIFNlbnNvci1TYXRlbGl0ZSBlcyBPTEkgLyBUSVJTIGNvbWJpbmFkb3MgTGFuZHNhdCA4LCBXUlMgUGF0aCA0NCwgV1JTIFJvdyAzNCB5IHJlY29waWxhZG9zIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIExhcyBlc2NlbmFzIGRlIExhbmRzYXQgc2UgZW50cmVnYW4gbWFzIGNvbXVubWVudGUgY29tbyB1biBhcmNoaXZvIGNvbXByaW1pZG8sIHF1ZSBjb250aWVuZSBhcmNoaXZvcyBzZXBhcmFkb3MgcGFyYSBjYWRhIGJhbmRhDQoNCiMjIyMjIENvbWVuemFyZW1vcyBleHBsb3JhbmRvIHkgdmlzdWFsaXphbmRvIGxvcyBkYXRvcyAoY29uc3VsdGUgbGFzIGluc3RydWNjaW9uZXMgZW4gZWwgQ2FwaXR1bG8gMSBwYXJhIG9idGVuZXIgaW5zdHJ1Y2Npb25lcyBkZSBkZXNjYXJnYSBkZSBkYXRvcyBzaSBhdW4gbm8gbG8gaGEgaGVjaG8pLg0KDQoNCg0KIyMjICoqVElUVUxPOiBQUk9QSUVEQURFUyBERSBJTUFHRU4qKg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykNCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCg0KYjEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMS50aWYnKQ0KDQoNCiMgYXp1bA0KYjIgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYnKQ0KIyB2ZXJkZQ0KYjMgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMy50aWYnKQ0KIyByb2pvDQpiNCA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZicpDQojIEluZnJhcm9qbyBjZXJjYW5vIChOSVIpDQpiNSA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I1LnRpZicpDQoNCg0KYjYgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNi50aWYnKQ0KYjcgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNy50aWYnKQ0KYjggPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYnKQ0KYjkgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COS50aWYnKQ0KYjEwID0gcmFzdGVyKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjEwLnRpZicpDQpiMTEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTEudGlmJykNCg0KYGBgDQoNCg0KIyMjIyMgc2UgaW5zZXJ0YSB1biBudWV2byBibG9xdWUgZGUgY29kaWdvIGN0cmwrYWx0K2k6IGltcHJpbWlyIGxhcyB2YXJpYWJsZXMgcGFyYSB2ZXJpZmljYXIsIHBvciBlamVtcGxvOg0KDQoNCmBgYHtyfQ0KYjINCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIHZlciBsYSByZXNvbHVjaW9uIGVzcGFjaWFsLCBsYSBleHRlbnNpb24sIGVsIG51bWVybyBkZSBjYXBhcywgZWwgc2lzdGVtYSBkZSByZWZlcmVuY2lhIGRlIGNvb3JkZW5hZGFzIHkgbWFzLg0KDQoNCg0KIyMjICoqVElUVUxPOiBJTkZPUk1BQ0lPTiBERSBJTUFHRU4gWSBFU1RBRElTVElDQVMqKg0KDQoNCiMjIyBBIGNvbnRpbnVhY2lvbiBzZSBtdWVzdHJhIGNvbW8gcHVlZGUgYWNjZWRlciBhIHZhcmlhcyBwcm9waWVkYWRlcyBkZXNkZSB1biBvYmpldG8gUmFzdGVyICogKGVzdG8gZXMgbG8gbWlzbW8gcGFyYSBjdWFscXVpZXIgY29uanVudG8gZGUgZGF0b3MgcmFzdGVyKS4NCg0KDQpgYGB7cn0NCiMgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtIChDUlMpDQpjcnMoYjIpDQojIyBDUlMgYXJndW1lbnRzOg0KIyMgK3Byb2o9dXRtICt6b25lPTE4ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyArZWxscHM9V0dTODQNCiMjICt0b3dnczg0PTAsMCwwDQojIE51bWJlciBvZiBjZWxscywgcm93cywgY29sdW1ucw0KbmNlbGwoYjIpDQojIyBbMV0gNTg2ODQ1MjENCmRpbShiMikNCiMjIFsxXSA3NzQxIDc1ODEgICAgMQ0KIyBzcGF0aWFsIHJlc29sdXRpb24NCnJlcyhiMikNCiMjIFsxXSAzMCAzMA0KIyBOdW1iZXIgb2YgYmFuZHMNCm5sYXllcnMoYjIpDQojIyBbMV0gMQ0KIyBEbyB0aGUgYmFuZHMgaGF2ZSB0aGUgc2FtZSBleHRlbnQsIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLCBwcm9qZWN0aW9uLCByZXNvbHV0aW9uLCBhbmQgb3JpZ2luDQpjb21wYXJlUmFzdGVyKGIyLGIzKQ0KIyMgWzFdIFRSVUUNCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIGNyZWFyIHVuIFJhc3RlclN0YWNrICh1biBvYmpldG8gY29uIHZhcmlhcyBjYXBhcykgYSBwYXJ0aXIgZGUgbG9zIG9iamV0b3MgUmFzdGVyTGF5ZXIgKGJhbmRhIHVuaWNhKSBleGlzdGVudGVzIA0KDQoNCiMjIyMjIExhcyBiYW5kYXMgcXVlIGxsYW1vcyBzb24gbGFzIG1pc21hcyBxdWUgaGVtb3MgbGxhbWFkb2RvIGFycmliYSBjb21vIFJhc3RlckxheWVyDQoNCmBgYHtyfQ0KczIwMTUgPSBzdGFjayhiNSwgYjQsIGIzKQ0KDQojIENoZWNrIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBSYXN0ZXJTdGFjaw0KczIwMTUNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCAzICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICsrcHJvaj11dG0gK3pvbmU9MTggK2RhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzICtlbGxwcz1XR1M4NCArdG93Z3M4ND0wLDAsMA0KIyMgbmFtZXMgICAgICA6IExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjUsIExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjQsICAgICBMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IzDQojIyBtaW4gdmFsdWVzIDogIDAsIDAsIDAgDQojIyBtYXggdmFsdWVzIDogIDY1NTM1LCA2NTUzNSwgNjU1MzUNCmBgYA0KDQoNCiMjIyMjIFRhbWJpZW4gcHVlZGUgY3JlYXIgZWwgUmFzdGVyU3RhY2sgdXNhbmRvIGxvcyBub21icmVzIGRlIGFyY2hpdm8gDQoNCg0KYGBge3J9DQoNCiMgZmlyc3QgY3JlYXRlIGEgbGlzdCBvZiByYXN0ZXIgbGF5ZXJzIHRvIHVzZQ0KZmlsZW5hbWVzID0gcGFzdGUwKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQicsIDE6NywgIi50aWYiKQ0KZmlsZW5hbWVzDQoNCiMjIFsxXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxLnRpZiIgDQojIyBbMl0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYiIA0KIyMgWzNdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjMudGlmIiANCiMjIFs0XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZiIgDQojIyBbNV0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNS50aWYiIA0KIyMgWzZdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjYudGlmIiANCiMjIFs3XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I3LnRpZiIgDQoNCiMjIyMjIyBubyBsZWUgbGEgYmFuZGEgOCBwb3JxdWUgdGllbmUgZGlmZXJlbnRlIGV4dGVuc2lvbg0KDQojIyBbOF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYiIA0KIyMgWzldICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjkudGlmIiANCiMjIFsxMF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTAudGlmIg0KIyMgWzExXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxMS50aWYiDQoNCg0KbGFuZHNhdDIwMTU9IHN0YWNrKGZpbGVuYW1lcykNCmxhbmRzYXQyMDE1DQoNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCA3ICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICtwcm9qPXV0bSArem9uZT0xMCArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwDQojIyBuYW1lcyAgICAgIDogTEMwOF9MMVRQLy81XzAxX1QxX0IxLCBMQzA4X0wxVFAvLzVfMDFfVDFfQjIsIExDMDhfTDFUUC8vNV8wMV9UMV9CMywgTEMwOF9MMVRQLy81XzAxX1QxX0I0LCBMQzA4X0wxVFAvLzVfMDFfVDFfQjUsIExDMDhfTDFUUC8vNV8wMV9UMV9CNiwgTEMwOF9MMVRQLy81XzAxX1QxX0I3DQojIyBtaW4gdmFsdWVzIDogICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwIA0KIyMgbWF4IHZhbHVlcyA6ICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSANCg0KDQpgYGANCg0KDQojIyMjIyBBcnJpYmEgY3JlYW1vcyB1biBSYXN0ZXJTdGFjayBjb24gMTEgY2FwYXMuIExhcyBjYXBhcyByZXByZXNlbnRhbiBsYSBpbnRlbnNpZGFkIGRlIGxhIHJlZmxleGlvbiBlbiBsYXMgc2lndWllbnRlcyBsb25naXR1ZGVzIGRlIG9uZGE6IFVsdHJhIGF6dWwsIGF6dWwsIHZlcmRlLCByb2pvLCBpbmZyYXJyb2pvIGNlcmNhbm8gKE5JUiksIGluZnJhcnJvam8gZGUgb25kYSBjb3J0YSAoU1dJUikgMSwgaW5mcmFycm9qbyBkZSBvbmRhIGNvcnRhIChTV0lSKSAyLCBwYW5jcm9tYXRpY28sIGNpcnJvLCBpbmZyYXJyb2pvIHRlcm1pY28gKFRJUlMpIDEsIEluZnJhcnJvam8gdGVybWljbyAoVElSUykgMi4gTm8gdXRpbGl6YXJlbW9zIGxhcyB1bHRpbWFzIGN1YXRybyBjYXBhcyB5IHZlcmEgY29tbyBlbGltaW5hcmxhcyBlbiBsYXMgc2lndWllbnRlcyBzZWNjaW9uZXMuDQoNCg0KDQojIyMgKipUSVRVTE86IEJBTkRBIFVOSUNBIFkgTUFQQVMgQ09NUFVFU1RPUyoqDQoNCg0KIyMjIyMgUHVlZGUgdHJhemFyIGNhcGFzIGluZGl2aWR1YWxlcyBkZSB1biBSYXN0ZXJTdGFjayBkZSB1bmEgaW1hZ2VuIG11bHRpZXNwZWN0cmFsLg0KDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3cgPSBjKDIsMikpDQpwbG90KGIyLCBtYWluID0gIkJsdWUiLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjMsIG1haW4gPSAiR3JlZW4iLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjQsIG1haW4gPSAiUmVkIiwgY29sID0gZ3JheSgwOjEwMCAvIDEwMCkpDQpwbG90KGI1LCBtYWluID0gIk5JUiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KDQpgYGANCg0KIyMjIyMgRWNoYSB1biB2aXN0YXpvIGEgbGFzIGxleWVuZGFzIGRlIGxvcyBtYXBhcyBjcmVhZG9zIGFudGVyaW9ybWVudGUuIFB1ZWRlbiB2YXJpYXIgZW50cmUgMCB5IDEuIE9ic2VydmUgbGEgZGlmZXJlbmNpYSBlbiBlbCBzb21icmVhZG8geSBlbCByYW5nbyBkZSBsZXllbmRhcyBlbnRyZSBsYXMgZGlmZXJlbnRlcyBiYW5kYXMuIEVzdG8gc2UgZGViZSBhIHF1ZSBsYXMgZGlmZXJlbnRlcyBjYXJhY3RlcmlzdGljYXMgZGUgbGEgc3VwZXJmaWNpZSByZWZsZWphbiBsYSByYWRpYWNpb24gc29sYXIgaW5jaWRlbnRlIGRlIG1hbmVyYSBkaWZlcmVudGUuIENhZGEgY2FwYSByZXByZXNlbnRhIGxhIGNhbnRpZGFkIGRlIHJhZGlhY2lvbiBzb2xhciBpbmNpZGVudGUgcXVlIHNlIHJlZmxlamEgcGFyYSB1biByYW5nbyBkZSBsb25naXR1ZCBkZSBvbmRhIHBhcnRpY3VsYXIuIFBvciBlamVtcGxvLCBsYSB2ZWdldGFjaW9uIHJlZmxlamEgbWFzIGVuZXJnaWEgZW4gTklSIHF1ZSBvdHJhcyBsb25naXR1ZGVzIGRlIG9uZGEgeSwgcG9yIGxvIHRhbnRvLCBwYXJlY2UgbWFzIGJyaWxsYW50ZS4gUG9yIGVsIGNvbnRyYXJpbywgZWwgYWd1YSBhYnNvcmJlIGxhIG1heW9yIHBhcnRlIGRlIGxhIGVuZXJnaWEgZW4gbGEgbG9uZ2l0dWQgZGUgb25kYSBOSVIgeSBwYXJlY2Ugb3NjdXJhLg0KDQoNCiMjIyMjIE5vIG9idGVuZW1vcyB0YW50YSBpbmZvcm1hY2lvbiBkZSBlc3RhcyBwYXJjZWxhcyBlbiBlc2NhbGEgZGUgZ3Jpc2VzOyBhIG1lbnVkbyBzZSBjb21iaW5hbiBlbiB1biAiY29tcHVlc3RvIiBwYXJhIGNyZWFyIHRyYW1hcyBtYXMgaW50ZXJlc2FudGVzLiBQdWVkZSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbiBzb2JyZSBsb3MgY29tcHVlc3RvcyBkZSBjb2xvciBlbiBsYSB0ZWxlZGV0ZWNjaW9uIGFxdWkgeSB0YW1iaWVuIGVuIGxhIHNlY2Npb24gYSBjb250aW51YWNpb24uDQoNCg0KIyMjIyMgUGFyYSBoYWNlciB1bmEgaW1hZ2VuIGRlICJjb2xvciB2ZXJkYWRlcm8gKG8gbmF0dXJhbCkiLCBlcyBkZWNpciwgYWxnbyBxdWUgc2UgcGFyZWNlIGEgdW5hIGZvdG9ncmFmaWEgbm9ybWFsICh2ZWdldGFjaW9uIGVuIHZlcmRlLCBhenVsIGFndWEsIGV0Yy4pLCBuZWNlc2l0YW1vcyBiYW5kYXMgZW4gbGFzIHJlZ2lvbmVzIHJvamEsIHZlcmRlIHkgYXp1bC4gUGFyYSBlc3RhIGltYWdlbiBMYW5kc2F0LCBzZSBwdWVkZW4gdXNhciBsYXMgYmFuZGFzIDQgKHJvam8pLCAzICh2ZXJkZSkgeSAyIChhenVsKS4gRWwgLSBwbG90UkdCIC0gbWV0b2RvIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY29tYmluYXJsb3MgZW4gdW4gc29sbyBjb21wdWVzdG8uIFRhbWJpZW4gcHVlZGUgcHJvcG9yY2lvbmFyIGFyZ3VtZW50b3MgYWRpY2lvbmFsZXMgLSBwbG90UkdCIC0gcGFyYSBtZWpvcmFyIGxhIHZpc3VhbGl6YWNpb24gKHBvciBlamVtcGxvLCB1biBlc3RpcmFtaWVudG8gbGluZWFsIGRlIGxvcyB2YWxvcmVzLCB1dGlsaXphbmRvICkuLSBzdHJlY3RoID0gImxpbiIgLQ0KDQoNCmBgYHtyfQ0KbGFuZHNhdFJHQjIwMTUgPSBzdGFjayhiNCwgYjMsIGIyKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCg0KYGBgDQoNCg0KIyMjIyMgRWwgY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyByZXZlbGEgbXVjaG8gbWFzIHNvYnJlIGVsIHBhaXNhamUgcXVlIGxhcyBpbWFnZW5lcyBncmlzZXMgYW50ZXJpb3Jlcy4gT3RybyBtZXRvZG8gcG9wdWxhciBkZSB2aXN1YWxpemFjaW9uIGRlIGltYWdlbmVzIGVuIGxhIHRlbGVkZXRlY2Npb24gZXMgbGEgaW1hZ2VuIGNvbm9jaWRhIGRlICJjb2xvciBmYWxzbyIgZW4gbGEgcXVlIHNlIGNvbWJpbmFuIGxhcyBiYW5kYXMgTklSLCByb2pvIHkgdmVyZGUuIEVzdGEgcmVwcmVzZW50YWNpb24gZXMgcG9wdWxhciB5YSBxdWUgaGFjZSBxdWUgc2VhIGZhY2lsIHZlciBsYSB2ZWdldGFjaW9uIChlbiByb2pvKS4NCg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93ID0gYygxLDIpKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCmxhbmRzYXRGQ0MyMDE1ID0gc3RhY2soYjUsIGI0LCBiMykNCnBsb3RSR0IobGFuZHNhdEZDQzIwMTUsIGF4ZXM9VFJVRSwgc3RyZXRjaD0ibGluIiwgbWFpbj0iTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUiKQ0KDQpgYGANCg0KIyMjIyMgKk5vdGEgOiBDb21wcnVlYmUgc2llbXByZSBsYSBkb2N1bWVudGFjaW9uIGRlbCBwYXF1ZXRlICgtIGhlbHAocGxvdFJHQikgLSkgcGFyYSB2ZXIgb3Ryb3MgYXJndW1lbnRvcyBxdWUgc2UgcHVlZGVuIGFncmVnYXIgKGNvbW8gbGEgZXNjYWxhKSBwYXJhIG1lam9yYXIgbyBtb2RpZmljYXIgbGEgaW1hZ2VuLioNCg0KIyMjIyMgKlByZWd1bnRhIDEgOiBVc2UgbGEgZnVuY2lvbiBwbG90UkdCIGNvbiBSYXN0ZXJTdGFjayBgYCBsYW5kc2F0ICcnIHBhcmEgY3JlYXIgdW4gY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyB5IGZhbHNvIChyZWN1ZXJkZSBsYSBwb3NpY2lvbiBkZSBsYXMgYmFuZGFzIGVuIGxhIHBpbGEpLioNCg0KYGBge3J9DQoNCiMjIHNvbHVjaW9uIGEgbGEgcHJlZ3VudGEgMQ0KbGFuZHNhdEZDQzIwMTVfcDEgPSBzdGFjayhiNSwgYjYsIGI0KQ0KcGxvdFJHQihsYW5kc2F0RkNDMjAxNV9wMSwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IGNvbXBvc2ljaW9uIGRlIGNvbG9yIGZhbHNhIC0gQWd1YSAvIFRpZXJyYSIpDQoNCg0KYGBgDQoNCg0KDQojIyMgKipUSVRVTE86IFNVQkNPTkpVTlRPIFkgUkVOT01CUkFSIEJBTkRBUyoqDQoNCg0KIyMjIyMgUHVlZGUgc2VsZWNjaW9uYXIgY2FwYXMgKGJhbmRhcykgZXNwZWNpZmljYXMgbWVkaWFudGUgbGEgLSBzdWJzZXQgLSBmdW5jaW9uIG8gbWVkaWFudGUgaW5kZXhhY2lvbi4NCg0KDQpgYGB7cn0NCg0KIyBzZWxlY3QgZmlyc3QgMyBiYW5kcyBvbmx5DQpsYW5kc2F0MjAxNXN1YjAxID0gc3Vic2V0KGxhbmRzYXQyMDE1LCAxOjMpDQojIHNhbWUNCmxhbmRzYXQyMDE1c3ViMDIgPSBsYW5kc2F0MjAxNVtbMTozXV0NCiMgTnVtYmVyIG9mIGJhbmRzIGluIHRoZSBvcmlnaW5hbCBhbmQgbmV3IGRhdGENCm5sYXllcnMobGFuZHNhdDIwMTUpDQojIyBbMV0gNw0KbmxheWVycyhsYW5kc2F0MjAxNXN1YjAxKQ0KIyMgWzFdIDMNCm5sYXllcnMobGFuZHNhdDIwMTVzdWIwMikNCiMjIFsxXSAzDQoNCmBgYA0KDQoNCiMjIyMjIE5vIHVzYXJlbW9zIGxhcyB1bHRpbWFzIGN1YXRybyBiYW5kYXMgLSBsYW5kc2F0IC0uIFB1ZWRlcyBlbGltaW5hciBhcXVlbGxvcyB1c2FuZG86DQoNCg0KYGBge3J9DQoNCmxhbmRzYXQyMDE1ID0gc3Vic2V0KGxhbmRzYXQyMDE1LCAxOjcpDQpwbG90KGxhbmRzYXQyMDE1KQ0KYGBgDQoNCg0KIyMjIyMgUGFyYSBtYXlvciBjbGFyaWRhZCwgZXMgdXRpbCBlc3RhYmxlY2VyIGxvcyBub21icmVzIGRlIGxhcyBiYW5kYXMuDQoNCg0KYGBge3J9DQoNCm5hbWVzKGxhbmRzYXQyMDE1KQ0KDQojIyBbMV0gIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjEiICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IyIg0KIyMgWzNdICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IzIiAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNCINCiMjIFs1XSAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNSIgIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjYiDQojIyBbN10gIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjciDQpuYW1lcyhsYW5kc2F0MjAxNSkgPSBjKCd1bHRyYS1ibHVlJywgJ2JsdWUnLCAnZ3JlZW4nLCAncmVkJywgJ05JUicsICdTV0lSMScsICdTV0lSMicpDQpuYW1lcyhsYW5kc2F0MjAxNSkNCiMjIFsxXSAidWx0cmEuYmx1ZSIgImJsdWUiICAgICAgICJncmVlbiIgICAgICAicmVkIiAgICAgICAgIk5JUiINCiMjIFs2XSAiU1dJUjEiICAgICAgIlNXSVIyIg0KDQpgYGANCg0KDQoNCiMjIyAqKlRJVFVMTzogU1VCQ09OSlVOVE8gRVNQQUNJQUwgTyBSRUNPUlRFKioNCg0KDQojIyMjIyBFbCBzdWJjb25qdW50byBlc3BhY2lhbCBzZSBwdWVkZSB1c2FyIHBhcmEgbGltaXRhciBlbCBhbmFsaXNpcyBhIHVuIHN1YmNvbmp1bnRvIGdlb2dyYWZpY28gZGUgbGEgaW1hZ2VuLiBMb3Mgc3ViY29uanVudG9zIGVzcGFjaWFsZXMgc2UgcHVlZGVuIGNyZWFyIGNvbiBsYSAtIGNyb3AgLSBmdW5jaW9uLCB1dGlsaXphbmRvIHVuIC0gZXh0ZW50IC0gb2JqZXRvIHUgb3RybyBvYmpldG8gZXNwYWNpYWwgZGVsIHF1ZSBzZSBwdWVkZSBleHRyYWVyIHVuYSBFeHRlbnNpb24uDQoNCmBgYHtyfQ0KDQojIFVzaW5nIGV4dGVudA0KZXh0ZW50KGxhbmRzYXQyMDE1KQ0KIyMgY2xhc3MgICAgICA6IEV4dGVudA0KIyMgeG1pbiAgICAgICA6IDQ0NjA4NSANCiMjIHhtYXggICAgICAgOiA2NzM1MTUNCiMjIHltaW4gICAgICAgOiAzNjI5ODUNCiMjIHltYXggICAgICAgOiA1OTUyMTUNCg0Kc2liYXRlMjAxNSA9IHNoYXBlZmlsZSgnQzovVXNlcnMvRGF2aWQvRGVza3RvcC9TSUJBVEVfUlVSQUwvcnVyYWwuc2hwJykNCg0KZSA9IGV4dGVudChzaWJhdGUyMDE1KQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpsYW5kc2F0Y3JvcDIwMTUgPSBjcm9wKGxhbmRzYXQyMDE1LCBlKQ0KDQoNCnBsb3RSR0IobGFuZHNhdGNyb3AyMDE1LCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgVHJ1ZSBDb2xvciBDb21wb3NpdGUiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgKlByZWd1bnRhIDIgOiBUYW1iaWVuIGVzIHBvc2libGUgbGEgc2VsZWNjaW9uIGludGVyYWN0aXZhIGRlIGxhIGltYWdlbi4gVXNlIGBgIGRyYXdFeHRlbnRgYCB5IGBgIGRyYXdQb2x5YGAgcGFyYSBzZWxlY2Npb25hciB1biBhcmVhIGRlIGludGVyZXMqDQoNCiMjIyMgc2UgZGEgcmVzcHVlc3RhIGEgZXN0YSBwcmVndW50YSBjb24gZWwgZWplcmNpY2lvIGFudGVyaW9yDQoNCg0KIyMjIyMgKlByZWd1bnRhIDMgOiBVc2UgZWwgYGAgTGFuZHNhdGNyb3AgJycgZGUgUmFzdGVyU3RhY2sgcGFyYSBjcmVhciB1biBjb21wdWVzdG8gZGUgY29sb3IgdmVyZGFkZXJvIHkgZmFsc28qDQoNCmBgYHtyfQ0KDQpsYW5kc2F0Y3JvcDIwMTVwcmVndW50YSA9IGNyb3Aoc3RhY2soYjQsIGIzLCBiMiksIGUpDQoNCg0KcGxvdFJHQihsYW5kc2F0Y3JvcDIwMTVwcmVndW50YSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFNpYmF0ZSAyMDE1IC0gQ29sb3IgVmVyZGFkZXJvIikNCg0KDQoNCmBgYA0KDQoNCiMjIyAqKlRJVFVMTzogR1VBUkRBTkRPIFJFU1VMVEFET1MgRU4gRUwgRElTQ08qKg0KDQoNCiMjIyMjIEVuIGVzdGEgZXRhcGEsIGVzIHBvc2libGUgcXVlIHF1ZXJhbW9zIGd1YXJkYXIgZWwgcmFzdGVyIGVuIGVsIGRpc2NvIHVzYW5kbyBsYSBmdW5jaW9uIC0gd3JpdGVSYXN0ZXIgLS4gU2UgYWRtaXRlbiBtdWx0aXBsZXMgdGlwb3MgZGUgYXJjaGl2b3MuIFV0aWxpemFyZW1vcyBlbCBmb3JtYXRvIEdlb1RpZmYgZGUgdXNvIGNvbXVuLiBNaWVudHJhcyBzZSBjb25zZXJ2YSBlbCBvcmRlbiBkZSBsYXMgY2FwYXMsIGxvcyBub21icmVzIGRlIGxhcyBjYXBhcyBzZSBwaWVyZGVuIGRlc2Fmb3J0dW5hZGFtZW50ZSBlbiBlbCBmb3JtYXRvIEdlb1RpZmYNCg0KYGBge3J9DQoNCnggPSB3cml0ZVJhc3RlcihsYW5kc2F0Y3JvcDIwMTUsIGZpbGVuYW1lPSJjcm9wcGVkLWxhbmRzYXQudGlmIiwgb3ZlcndyaXRlPVRSVUUpDQpwbG90KHgpDQoNCmBgYA0KDQoNCiMjIyMjIEFsdGVybmF0aXZhbWVudGUsIHB1ZWRlIHV0aWxpemFyIGVsIGZvcm1hdG8gJ3Jhc3Rlci1ncmQnLg0KDQoNCmBgYHtyfQ0KDQp3cml0ZVJhc3RlcihsYW5kc2F0Y3JvcDIwMTUsIGZpbGVuYW1lPSJjcm9wcGVkLWxhbmRzYXQuZ3JkIiwgb3ZlcndyaXRlPVRSVUUpDQoNCmBgYA0KDQoNCiMjIyMjIFVuYSB2ZW50YWphIGRlIGVzdGUgZm9ybWF0byBlcyBxdWUgZ3VhcmRhIGxvcyBub21icmVzIGRlIGxhcyBjYXBhcy4gTGEgZGVzdmVudGFqYSBkZSBlc3RlIGZvcm1hdG8gZXMgcXVlIG5vIG11Y2hvcyBvdHJvcyBwcm9ncmFtYXMgcHVlZGVuIGxlZXIgbG9zIGRhdG9zLCBlbiBjb250cmFzdGUgY29uIGVsIGZvcm1hdG8gR2VvVGlmZi4NCg0KIyMjIyMgKk5vdGE6IENvbnN1bHRlIGxhIGRvY3VtZW50YWNpb24gZGVsIHBhcXVldGUgKC0gaGVscCh3cml0ZVJhc3RlcikgLSkgcGFyYSB2ZXIgYXJndW1lbnRvcyB1dGlsZXMgYWRpY2lvbmFsZXMgcXVlIHNlIHB1ZWRlbiBhZ3JlZ2FyKg0KDQoNCg0KIyMjICoqVElUVUxPOiBSRUxBQ0lPTiBFTlRSRSBCQU5EQVMqKg0KDQoNCiMjIyMjIFVuYSBtYXRyaXogZGUgZGlhZ3JhbWEgZGUgZGlzcGVyc2lvbiBwdWVkZSBzZXIgdXRpbCBwYXJhIGV4cGxvcmFyIGxhcyByZWxhY2lvbmVzIGVudHJlIGNhcGFzIHJhc3Rlci4gRXN0byBzZSBwdWVkZSBoYWNlciBjb24gbGEgZnVuY2lvbiBwYXJlcyAoKSBkZWwgcGFxdWV0ZSByYXN0ZXIuDQoNCg0KIyMjIyMgVHJhemFkbyBkZSByZWZsZWpvIGVuIGxhIGxvbmdpdHVkIGRlIG9uZGEgdWx0cmEgYXp1bCBjb250cmEgZWwgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIGF6dWwuDQoNCg0KYGBge3J9DQpwYWlycyhsYW5kc2F0Y3JvcDIwMTVbWzE6Ml1dLCBtYWluID0gIlVsdHJhLWJsdWUgdmVyc3VzIEJsdWUiKQ0KYGBgDQoNCg0KIyMjIyMgVHJhemFkbyBkZSByZWZsZWpvIGVuIGxhIGxvbmdpdHVkIGRlIG9uZGEgcm9qYSBjb250cmEgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIE5JUi4NCg0KDQpgYGB7cn0NCnBhaXJzKGxhbmRzYXRjcm9wMjAxNVtbNDo1XV0sIG1haW4gPSAiUmVkIHZlcnN1cyBOSVIiKQ0KYGBgDQoNCg0KIyMjIyMgTGEgcHJpbWVyYSBncmFmaWNhIHJldmVsYSBhbHRhcyBjb3JyZWxhY2lvbmVzIGVudHJlIGxhcyByZWdpb25lcyBkZSBsb25naXR1ZCBkZSBvbmRhIGF6dWwuIERlYmlkbyBhIGxhIGFsdGEgY29ycmVsYWNpb24sIHBvZGVtb3MgdXNhciB1bmEgZGUgbGFzIGJhbmRhcyBhenVsZXMgc2luIHBlcmRlciBtdWNoYSBpbmZvcm1hY2lvbi4NCg0KIyMjIyMgRXN0YSBkaXN0cmlidWNpb24gZGUgcHVudG9zIGVuIGxhIHNlZ3VuZGEgZ3JhZmljYSAoZW50cmUgTklSIHkgcm9qbykgZXMgdW5pY2EgZGViaWRvIGEgc3UgZm9ybWEgdHJpYW5ndWxhci4gTGEgdmVnZXRhY2lvbiBzZSByZWZsZWphIG11eSBiaWVuIGVuIGVsIHJhbmdvIE5JUiBxdWUgZWwgcm9qbyB5IGNyZWEgbGEgZXNxdWluYSBzdXBlcmlvciBjZXJjYSBkZWwgZWplIE5JUiAoeSkuIEVsIGFndWEgYWJzb3JiZSBlbmVyZ2lhIGRlIHRvZGFzIGxhcyBiYW5kYXMgeSBvY3VwYSBlbCBsdWdhciBjZXJjYW5vIGFsIG9yaWdlbi4gRWwgcmluY29uIG1hcyBhbGVqYWRvIHNlIGNyZWEgZGViaWRvIGEgbGFzIGNhcmFjdGVyaXN0aWNhcyBzdXBlcmZpY2lhbGVzIGFsdGFtZW50ZSByZWZsZWN0YW50ZXMsIGNvbW8gZWwgc3VlbG8gYnJpbGxhbnRlIG8gZWwgaG9ybWlnb24uDQoNCg0KIyMjICoqVElUVUxPOiBFWFRSQUVSIFZBTE9SRVMgREUgUElYRUxFUyAqKg0KDQoNCiMjIyMjIEEgbWVudWRvLCBxdWVyZW1vcyBvYnRlbmVyIGxvcyB2YWxvcmVzIGRlIGxhcyBjZWxkYXMgcmFzdGVyIHBhcmEgdWJpY2FjaW9uZXMgZ2VvZ3JhZmljYXMgbyBhcmVhcyBlc3BlY2lmaWNhcy4gTGEgLSBleHRyYWN0IC0gZnVuY2lvbiBzZSB1dGlsaXphIHBhcmEgb2J0ZW5lciB2YWxvcmVzIHJhc3RlciBlbiBsYXMgdWJpY2FjaW9uZXMgZGUgb3Ryb3MgZGF0b3MgZXNwYWNpYWxlcy4gUHVlZGUgdXNhciBwdW50b3MsIGxpbmVhcywgcG9saWdvbm9zIG8gdW4gb2JqZXRvIGRlIGV4dGVuc2lvbiAocmVjdGFuZ3VsbykuIFRhbWJpZW4gcHVlZGUgdXNhciBudW1lcm9zIGRlIGNlbGRhIHBhcmEgZXh0cmFlciB2YWxvcmVzLiBBbCB1c2FyIHB1bnRvcywgLSBleHRyYWN0IC0gZGV2dWVsdmUgbG9zIHZhbG9yZXMgZGUgdW4gLSBSYXN0ZXIqIC0gb2JqZXRvIHBhcmEgbGFzIGNlbGRhcyBlbiBsYXMgcXVlIHNlIHViaWNhIHVuIGNvbmp1bnRvIGRlIHB1bnRvcy4NCg0KDQpgYGB7cn0NCiMgbG9hZCB0aGUgcG9seWdvbnMgd2l0aCBsYW5kIHVzZSBsYW5kIGNvdmVyIGluZm9ybWF0aW9uDQoNCnNpYmF0ZWNvYmVydCA9IHNoYXBlZmlsZSAoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvUEVSQ0VQQ0lPTiBSRU1PVEEvVFJBQkFKT19DT0JFUlRVUkFTL2NvYmVydHUuc2hwJykNCiAgICAjIHNhbXAgPSByZWFkUkRTKCdkYXRhL3JzL3NhbXBsZXMucmRzJykgICAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgZ2VuZXJhdGUgMzAwIHBvaW50IHNhbXBsZXMgZnJvbSB0aGUgcG9seWdvbnMNCg0KcHRzaWJhdGVjb2JlcnQgPSBzcHNhbXBsZShzaWJhdGVjb2JlcnQsMzAwLCB0eXBlPSdyZWd1bGFyJykNCiAgICAjIHB0c2FtcCA9IHNwc2FtcGxlKHNhbXAsIDMwMCwgdHlwZT0ncmVndWxhcicpICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgYWRkIHRoZSBsYW5kIGNvdmVyIGNsYXNzIHRvIHRoZSBwb2ludHMNCnB0c2liYXRlY29iZXJ0JE5hbWUgPSBvdmVyKHB0c2liYXRlY29iZXJ0LCBzaWJhdGVjb2JlcnQpJE5hbWUNCiAgICAjIHB0c2FtcCRjbGFzcyA9IG92ZXIocHRzYW1wLCBzYW1wKSRjbGFzcyAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCg0KIyBleHRyYWN0IHZhbHVlcyB3aXRoIHBvaW50cw0KZGYgPSBleHRyYWN0KGxhbmRzYXQyMDE1LCBwdHNpYmF0ZWNvYmVydCkNCiAgICMgZGYgPSBleHRyYWN0KGxhbmRzYXQxLCBwdHNhbXApICAgICAgICAgICAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgVG8gc2VlIHNvbWUgb2YgdGhlIHJlZmxlY3RhbmNlIHZhbHVlcw0KaGVhZChkZikNCg0KIyAgICAgdWx0cmEuYmx1ZSBibHVlIGdyZWVuICByZWQgICBOSVIgU1dJUjEgU1dJUjINCiNbMSxdICAgICAgIDg0ODQgNzgwMCAgNzUyOCA2OTMxIDE0Nzc3IDEwODc5ICA4MTY3DQojWzIsXSAgICAgICA4ODE2IDgyNjUgIDg2OTQgODE4MSAyMTAyNCAxNjc1MyAxMTMxMw0KI1szLF0gICAgICAgODQxOSA3NzkxICA4MjA2IDY4NDcgMjQ3NjEgMTE4MDEgIDc5NjINCiNbNCxdICAgICAgIDgzOTkgNzc0NSAgODA4NyA2Nzc1IDI0Nzc1IDEyMTYwICA4MDEyDQojWzUsXSAgICAgICA4MDcyIDczOTQgIDY5MDQgNjI3MyAxMTIwNyAgODA5OCAgNjYyMQ0KI1s2LF0gICAgICAgODA3MiA3MzgwICA2ODI3IDYyMzEgMTA3MjggIDgwODQgIDY2NTQNCmBgYA0KDQoNCg0KIyMjICoqVElUVUxPOiBQRVJGSUxFUyBFU1BFQ1RSQUxFUyoqDQoNCg0KIyMjIyMgVW5hIGdyYWZpY2EgZGVsIGVzcGVjdHJvICh0b2RhcyBsYXMgYmFuZGFzKSBwYXJhIGxvcyBwaXhlbGVzIHF1ZSByZXByZXNlbnRhbiBjaWVydGFzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZSAocC4gRWouIEFndWEpIHNlIGNvbm9jZSBjb21vIHBlcmZpbCBlc3BlY3RyYWwuIERpY2hvcyBwZXJmaWxlcyBkZW11ZXN0cmFuIGxhcyBkaWZlcmVuY2lhcyBlbiBsYXMgcHJvcGllZGFkZXMgZXNwZWN0cmFsZXMgZGUgdmFyaWFzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZSB5IGNvbnN0aXR1eWVuIGxhIGJhc2UgcGFyYSBlbCBhbmFsaXNpcyBkZSBpbWFnZW5lcy4gTG9zIHZhbG9yZXMgZXNwZWN0cmFsZXMgc2UgcHVlZGVuIGV4dHJhZXIgZGUgY3VhbHF1aWVyIGNvbmp1bnRvIGRlIGRhdG9zIG11bHRpZXNwZWN0cmFsZXMgdXRpbGl6YW5kbyBsYSAtIGV4dHJhY3QgLSBmdW5jaW9uLiBFbiBlbCBlamVtcGxvIGFudGVyaW9yLCBleHRyYWppbW9zIHZhbG9yZXMgZGUgZGF0b3MgZGUgTGFuZHNhdCBwYXJhIGxhcyBtdWVzdHJhcy4gRXN0YXMgbXVlc3RyYXMgaW5jbHV5ZW46IHRpZXJyYXMgZGUgY3VsdGl2bywgYWd1YSwgYmFyYmVjaG8sIGNvbnN0cnVpZG8geSBhYmllcnRvLiBQcmltZXJvIGNhbGN1bGFtb3MgbG9zIHZhbG9yZXMgbWVkaW9zIGRlIHJlZmxlY3RhbmNpYSBwYXJhIGNhZGEgY2xhc2UgeSBjYWRhIGJhbmRhLg0KDQoNCmBgYHtyfQ0KDQpudW1lcm89IGxlbmd0aChwdHNpYmF0ZWNvYmVydCkNCm51bWVybw0KDQpkZl9zYW1wbGVzID0gYXMgKHB0c2liYXRlY29iZXJ0LCAiU3BhdGlhbFBvaW50c0RhdGFGcmFtZSIpDQpkZl9zYW1wbGVzDQpkZl9zYW1wbGVzQGRhdGE9ZGF0YS5mcmFtZShJRD0xOm51bWVybyxzaXplPTEpDQpkZl9zYW1wbGVzDQoNCg0KcGxvdChsYW5kc2F0Y3JvcDIwMTUpDQpwbG90KHNpYmF0ZWNvYmVydCwgYWRkPSBUUlVFKQ0KcGxvdChkZl9zYW1wbGVzLHBjaD0xLCBjZXg9KGRmX3NhbXBsZXMkc2l6ZSkvNCwgYWRkPVRSVUUpDQoNCg0KZGZfc2FtcGxlcyROYW1lID1vdmVyKGRmX3NhbXBsZXMsc2liYXRlY29iZXJ0KSROYW1lDQpkZl9zYW1wbGVzDQpkZjE9cmFzdGVyOjpleHRyYWN0KGxhbmRzYXRjcm9wMjAxNSwgZGZfc2FtcGxlcykNCg0KDQptcyA9IGFnZ3JlZ2F0ZShkZjEsIGxpc3QocHRzaWJhdGVjb2JlcnQkTmFtZSksIG1lYW4pDQojIyBtcyA9IGFnZ3JlZ2F0ZShkZiwgbGlzdChwdHNhbXAkY2xhc3MpLCBtZWFuKSAgICAgICAgICoqIGFzaSBlc3RhIGVuIGxhIGd1aWEqKg0KDQojIGluc3RlYWQgb2YgdGhlIGZpcnN0IGNvbHVtbiwgd2UgdXNlIHJvdyBuYW1lcw0Kcm93bmFtZXMobXMpID0gbXNbLDFdDQptcyA9IG1zWywtMV0NCm1zDQoNCg0KIyMgICAgICAgICAgdWx0cmEuYmx1ZSAgICAgIGJsdWUgICAgICBncmVlbiAgICAgICByZWQgICAgICAgIE5JUiAgICAgIFNXSVIxDQojIyBidWlsdCAgICAgMC4xODY0OTI1IDAuMTc5NTM3MSAwLjE3OTUzMzE3IDAuMTk1ODQxNCAwLjI1NDQ4NDQ3IDAuMjQ4NTAxOTcNCiMjIGNyb3BsYW5kICAwLjExMjk4MTMgMC4wOTA5NjQ1IDAuMDg1OTY3MjIgMC4wNTUwMzQ0IDAuNDgzMzU0NjIgMC4xNjE0MjA4NQ0KIyMgZmFsbG93ICAgIDAuMTMxOTE5OCAwLjExNjQ4NjkgMC4xMDQ1Mzc2NCAwLjExNTEyNDMgMC4xODAxMjk2MiAwLjIzMTM5MjI4DQojIyBvcGVuICAgICAgMC4xMzg4MDE0IDAuMTM3NTIzNSAwLjE1MjczMTYzIDAuMjA2NjQyNSAwLjM0NDc2NjcwIDAuMzU4MjA4NzcNCiMjIHdhdGVyICAgICAwLjEzMzYyNDIgMC4xMTY1NzI4IDAuMDk5MjI3MjYgMC4wNzg1OTQ3IDAuMDQ5MDkyMDEgMC4wMzM2MDA0Nw0KIyMgICAgICAgICAgICAgICBTV0lSMg0KIyMgYnVpbHQgICAgMC4yMDAwMTMwNg0KIyMgY3JvcGxhbmQgMC4wNzMxNDE4Ng0KIyMgZmFsbG93ICAgMC4xOTE0MzAzMA0KIyMgb3BlbiAgICAgMC4yMTM0NjM0Mw0KIyMgd2F0ZXIgICAgMC4wMjcyMzM5OA0KDQpgYGANCg0KDQojIyMjIyBBaG9yYSB0cmF6YW1vcyBlbCBlc3BlY3RybyBtZWRpbyBkZSBlc3RhcyBjYXJhY3RlcmlzdGljYXMuDQoNCg0KYGBge3J9DQojIENyZWF0ZSBhIHZlY3RvciBvZiBjb2xvciBmb3IgdGhlIGxhbmQgY292ZXIgY2xhc3NlcyBmb3IgdXNlIGluIHBsb3R0aW5nDQpteWNvbG9yID0gYygnZGFya3JlZCcsICd5ZWxsb3cnLCAnYnVybHl3b29kJywgJ2N5YW4nLCAnYmx1ZScsICdncmVlbicsJ3BpbmsnKQ0KI3RyYW5zZm9ybSBtcyBmcm9tIGEgZGF0YS5mcmFtZSB0byBhIG1hdHJpeA0KbXMgPSBhcy5tYXRyaXgobXMpDQojIEZpcnN0IGNyZWF0ZSBhbiBlbXB0eSBwbG90DQpwbG90KDAsIHlsaW09YygwLDI1MDAwKSwgeGxpbSA9IGMoMSw3KSwgdHlwZT0nbicsIHhsYWI9IkJhbmRzIiwgeWxhYiA9ICJSZWZsZWN0YW5jZSIpDQojIGFkZCB0aGUgZGlmZmVyZW50IGNsYXNzZXMNCmZvciAoaSBpbiAxOm5yb3cobXMpKXsNCiAgbGluZXMobXNbaSxdLCB0eXBlID0gImwiLCBsd2QgPSAzLCBsdHkgPSAxLCBjb2wgPSBteWNvbG9yW2ldKQ0KfQ0KIyBUaXRsZQ0KdGl0bGUobWFpbj0iU3BlY3RyYWwgUHJvZmlsZSBmcm9tIExhbmRzYXQiLCBmb250Lm1haW4gPSAyKQ0KIyBMZWdlbmQNCmxlZ2VuZCgidG9wbGVmdCIsIHJvd25hbWVzKG1zKSwNCiAgICAgICBjZXg9MC44LCBjb2w9bXljb2xvciwgbHR5ID0gMSwgbHdkID0zLCBidHkgPSAibiIpDQpgYGANCg0KDQojIyMjIyBFbCBwZXJmaWwgZXNwZWN0cmFsIG11ZXN0cmEgKGRlcykgc2ltaWxpdHVkIGVuIGxhIHJlZmxlY3RhbmNpYSBkZSBkaWZlcmVudGVzIGNhcmFjdGVyaXN0aWNhcyBlbiBsYSBzdXBlcmZpY2llIGRlIGxhIHRpZXJyYSAobyBwb3IgZW5jaW1hIGRlIGVsbGEpLiAnQWd1YScgbXVlc3RyYSB1bmEgcmVmbGV4aW9uIHJlbGF0aXZhbWVudGUgYmFqYSBlbiB0b2RhcyBsYXMgbG9uZ2l0dWRlcyBkZSBvbmRhLCB5ICdjb25zdHJ1aWRvJywgJ2VuIGJhcmJlY2hvJyB5ICdhYmllcnRvJyB0aWVuZW4gdW5hIHJlZmxlY3RhbmNpYSByZWxhdGl2YW1lbnRlIGFsdGEgZW4gbGFzIGxvbmdpdHVkZXMgZGUgb25kYSBtYXMgbGFyZ2FzLg0KDQoNCiMgVElUVUxPOiBPUEVSQUNJT05FUyBNQVRFTUFUSUNBUyBCQVNJQ0FTICMNCg0KDQojIyMjIyBFbCAtIHJhc3Rlci0gcGFxdWV0ZSBhZG1pdGUgbXVjaGFzIG9wZXJhY2lvbmVzIG1hdGVtYXRpY2FzLiBMYXMgb3BlcmFjaW9uZXMgbWF0ZW1hdGljYXMgZ2VuZXJhbG1lbnRlIHNlIHJlYWxpemFuIHBvciBwaXhlbCAoY2VsZGEgZGUgY3VhZHJpY3VsYSkuIFByaW1lcm8gaGFyZW1vcyBhbGd1bmFzIG9wZXJhY2lvbmVzIGFyaXRtZXRpY2FzIGJhc2ljYXMgcGFyYSBjb21iaW5hciBiYW5kYXMuIEVuIGVsIHByaW1lciBlamVtcGxvLCBlc2NyaWJpbW9zIHVuYSBmdW5jaW9uIG1hdGVtYXRpY2EgcGVyc29uYWxpemFkYSBwYXJhIGNhbGN1bGFyIGVsIGluZGljZSBkZSB2ZWdldGFjaW9uIGRlIGRpZmVyZW5jaWEgbm9ybWFsaXphZGEgKE5EVkkpLg0KDQpgYGB7cn0NCg0KIyMjIHNvbG8gcHVlZG8gY2FyZ2FyIGxhcyBiYW5kYXMgZGUgbGEgMSBhIGxhIDcgcG9ycXVlIGxhIDggbm8gdGllbmUgbGEgbWlzbWEgZXh0ZW5zaW9uIGRlIGxhcyBkZW1hcw0KDQpyYXNsaXN0cDMgPSBwYXN0ZTAoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CJywgMTo3LCAiLnRpZiIpDQojI3Jhc2xpc3RwMz0gcHJhY3RpY2EgMw0KDQoNCmxhbmRzYXRwMyA9IHN0YWNrKHJhc2xpc3RwMykNCg0KcGxvdChsYW5kc2F0cDMpDQoNCg0KbGFuZHNhdFJHQnAzID0gbGFuZHNhdHAzW1tjKDQsMywyKV1dDQojIyBsYW5kc2F0UkdCcDMgPSBwcmFjdGljYSAzDQpwbG90KGxhbmRzYXRSR0JwMykNCg0KbGFuZHNhdEZDQ3AzID0gbGFuZHNhdHAzW1tjKDUsNCwzKV1dDQojIyBsYW5kc2F0RkNDcDMgPSBwcmFjdGljYSAzDQpwbG90KGxhbmRzYXRGQ0NwMykNCg0KDQoNCg0KYGBgDQoNCg0KIyMjIFRJVFVMTzogSU5ESUNFUyBERSBWRUdFVEFDSU9OICMjIw0KDQojIyMjIyBEZWZpbmFtb3MgdW5hIGZ1bmNpT24gZ2VuZXJhbCBwYXJhIHVuIEluZGljZSBiYXNhZG8gZW4gcmF6T24gKHZlZ2V0YWNpT24pLiBFbiBsYSBmdW5jaW9uIGEgY29udGludWFjaW9uLCAtaW1nLSBlcyB1biBvYmpldG8gUmFzdGVyICogZGUgbXVsdGlwbGVzIGNhcGFzIC1pLSB5IC1rLSBzb24gbG9zIGluZGljZXMgZGUgbGFzIGNhcGFzIChudW1lcm9zIGRlIGNhcGEpIHV0aWxpemFkb3MgcGFyYSBjYWxjdWxhciBlbCBpbmRpY2UgZGUgdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCiMjIHZpMjAxNT0gaW5kaWNlIGRlIHZlZ2V0YWNpb24gcGFyYSBsYSBpbWFnZW4gMjAxNQ0KDQp2aTIwMTUgPSBmdW5jdGlvbihpbWcsIGssIGkpIHsNCiAgDQogIGJrID0gaW1nIFtba11dDQogIGJpID0gaW1nIFtbaV1dDQogIHZpMjAxNT0oYmstYmkpLyhiaytiaSkNCiAgcmV0dXJuKHZpMjAxNSkNCn0NCg0KDQpgYGANCg0KYGBge3J9DQoNCiMjIHBhcmEgbGFuZHNhdCBOSVIgPSA1LCByZWQgPSA0DQojIyBuZHZpMjAxNT0gaW5kaWNlIGRlIHZlZ2V0YWNpb24gZGUgZGlyZWZlbmNpYSBub3JtYWxpemFkYSAoTkRWSSkgcGFyYSBsYSBpbWFnZW4gbGFuZHNhdCAyMDE1DQoNCm5kdmkyMDE1ID0gdmkyMDE1KGxhbmRzYXRwMywgNSwgNCkgDQpwbG90KG5kdmkyMDE1LCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDkpKSwgbWFpbj0gIkxhbmRzYXQgMjAxNSAtIE5WREkiKQ0KDQoNCk5EVkkxX3NpYmF0ZV8yMDE1ID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplTkRWSTFfc2liYXRlID0gZXh0ZW50KE5EVkkxX3NpYmF0ZV8yMDE1KQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpORFZJX3JlY29ydGVfMSA9IGNyb3AobmR2aTIwMTUsIGVORFZJMV9zaWJhdGUpDQpwbG90KE5EVklfcmVjb3J0ZV8xLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRWSSIpDQoNCg0KYGBgDQoNCg0KIyMjIyMgUHVlZGVzIHZlciBsYSB2YXJpYWNpb24gZW4gZWwgdmVyZG9yIGRlc2RlIGxhIHRyYW1hLg0KDQoNCiMjIyMjIFVuYSBmb3JtYSBhbHRlcm5hdGl2YSBkZSBsb2dyYXIgZXN0byBlcyBhc2kNCg0KDQpgYGB7cn0NCg0KdmkyXzIwMTUgPSBmdW5jdGlvbih4LCB5KSB7DQogICh4LXkpLyh4K3kpDQp9DQoNCg0KbmR2aTJfMjAxNSA9IG92ZXJsYXkobGFuZHNhdHAzW1s1XV0sIGxhbmRzYXRwM1tbNF1dLCBmdW4gPSB2aTJfMjAxNSkNCg0KcGxvdChuZHZpMl8yMDE1LCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRWSSB2MiIpDQoNCg0KTkRWSTJfc2liYXRlXzIwMTUgPSBzaGFwZWZpbGUoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvU0lCQVRFX1JVUkFML3J1cmFsLnNocCcpDQoNCmVORFZJMl9zaWJhdGUgPSBleHRlbnQoTkRWSTJfc2liYXRlXzIwMTUpDQojIGNyb3AgbGFuZHNhdCBieSB0aGUgZXh0ZW50DQoNCk5EVklfcmVjb3J0ZV8yID0gY3JvcChuZHZpMl8yMDE1LCBlTkRWSTJfc2liYXRlKQ0KcGxvdChORFZJX3JlY29ydGVfMiwgY29sPXJldih0ZXJyYWluLmNvbG9ycygxMCkpLCBtYWluID0gIkxhbmRzYXQgMjAxNSAtIE5EVkkiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgUHJlZ3VudGEgMSA6IEFkYXB0ZSBlbCBjb2RpZ28gcXVlIHNlIG11ZXN0cmEgYXJyaWJhIHBhcmEgY2FsY3VsYXIgbG9zIGluZGljZXMgcGFyYSBpZGVudGlmaWNhciBpKSBhZ3VhIHkgaWkpIGFjdW11bGFkb3MuIFN1Z2VyZW5jaWE6IFVzZSBlbCBkaWFncmFtYSBkZWwgcGVyZmlsIGVzcGVjdHJhbCBwYXJhIGVuY29udHJhciBsYXMgYmFuZGFzIHF1ZSB0aWVuZW4gcmVmbGVjdGFuY2lhIG1heGltYSB5IG1pbmltYSBwYXJhIGVzdGFzIGRvcyBjbGFzZXMuDQoNCg0KDQoNCmBgYHtyfQ0KIyMgcDEgZXMgcHJlZ3VudGEgMQ0KDQpuZHZpMjAxNV9wMSA9IHZpMjAxNShsYW5kc2F0cDMsIDMsIDYpIA0KDQpwbG90KG5kdmkyMDE1X3AxLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW49ICJMYW5kc2F0IDIwMTUgLSBORFdJIikNCg0KdmkyXzIwMTVfcDEgPSBmdW5jdGlvbih4LCB5KSB7DQogICh4LXkpLyh4K3kpDQp9DQoNCg0KbmR2aTJfMjAxNV9wMSA9IG92ZXJsYXkobGFuZHNhdHAzW1szXV0sIGxhbmRzYXRwM1tbNl1dLCBmdW4gPSB2aTJfMjAxNV9wMSkNCg0KcGxvdChuZHZpMl8yMDE1X3AxLCBjb2w9cmV2KHRvcG8uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRXSSIpDQoNCg0KIyMjIFBBUkEgSU5ESUNFIERFIEFHVUEgREUgRElGRVJFTkNJQSBOT1JNQUxJWkFEQSAtIE5EV0kNCg0KTkRXSV9zaWJhdGUgPSBzaGFwZWZpbGUoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvU0lCQVRFX1JVUkFML3J1cmFsLnNocCcpDQoNCmVORFdJID0gZXh0ZW50KE5EV0lfc2liYXRlKQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpORFdJX3JlY29ydGUgPSBjcm9wKG5kdmkyXzIwMTVfcDEsIGVORFdJKQ0KcGxvdChORFdJX3JlY29ydGUsIGNvbD1yZXYodG9wby5jb2xvcnMoMTApKSwgbWFpbiA9ICJMYW5kc2F0IDIwMTUgLSBORFdJIikNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KDQojIyMgUEFSQSBJTkRJQ0UgSU5DT1JQT1JBRE8gREUgRElGRVJFTkNJQSBOT1JNQUxJWkFEQSAtIE5EQkkNCg0KbmRiaTFfMjAxNV9wMSA9IG92ZXJsYXkobGFuZHNhdHAzW1s2XV0sIGxhbmRzYXRwM1tbNV1dLCBmdW4gPSB2aTJfMjAxNV9wMSkNCg0KcGxvdChuZGJpMV8yMDE1X3AxLCBjb2w9cmV2KGhlYXQuY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRCSSIpDQoNCg0KIyMgcmVjb3J0YWRvIGEgc2liYXRlDQoNCk5EQklfc2liYXRlID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplTkRCSSA9IGV4dGVudChOREJJX3NpYmF0ZSkNCiMgY3JvcCBsYW5kc2F0IGJ5IHRoZSBleHRlbnQNCg0KTkRCSV9yZWNvcnRlID0gY3JvcChuZGJpMV8yMDE1X3AxLCBlTkRCSSkNCnBsb3QoTkRCSV9yZWNvcnRlLCBjb2w9cmV2KGhlYXQuY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRXSSIpDQoNCg0KYGBgDQoNCg0KDQojIyMgVElUVUxPOiBISVNUT0dSQU1BDQoNCiMjIyMjIFBvZGVtb3MgZXhwbG9yYXIgbGEgZGlzdHJpYnVjaW9uIGRlIHZhbG9yZXMgY29udGVuaWRvcyBlbiBudWVzdHJvIHJhc3RlciB1dGlsaXphbmRvIGxhIGZ1bmNpb24gLWhpc3QgKCktIHF1ZSBwcm9kdWNlIHVuIGhpc3RvZ3JhbWEuIExvcyBoaXN0b2dyYW1hcyBhIG1lbnVkbyBzb24gdXRpbGVzIHBhcmEgaWRlbnRpZmljYXIgdmFsb3JlcyBhdGlwaWNvcyB5IHZhbG9yZXMgZGUgZGF0b3MgaW5jb3JyZWN0b3MgZW4gbnVlc3Ryb3MgZGF0b3MgcmFzdGVyDQoNCg0KYGBge3J9DQoNCiMjIHZlciBoaXN0b2dyYW1hIGRlIGRhdG9zDQoNCmhpc3QoTkRWSV9yZWNvcnRlXzEsDQogICAgIG1haW49ICJEc2l0cmlidWNpb24gZGUgdmFsb3JlcyBkZWwgTkRWSSIsDQogICAgIHhsYWI9ICJORFZJIiwNCiAgICAgeWxhYj0gIkZyZWN1ZW5jaWEiLA0KICAgICBjb2w9IHRlcnJhaW4uY29sb3JzKDUwKSwNCiAgICAgeGxpbT0gYyAoLTAuMSwwLjcpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dD0gJ24nKQ0KDQpheGlzKHNpZGUgPSAxLCBhdD1zZXEoLTAuNSwxLDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLDAuMDUpKQ0KDQpgYGANCg0KDQojIyMjIyBOb3MgcmVmZXJpcmVtb3MgYSBlc3RlIGhpc3RvZ3JhbWEgcGFyYSBsYSBzaWd1aWVudGUgc3Vic2VjY2lvbiBzb2JyZSB1bWJyYWxpemFjaW9uLg0KDQoNCiMjIyMjIFByZWd1bnRhIDIgOiBIYWdhIGhpc3RvZ3JhbWFzIGRlIGxvcyB2YWxvcmVzIHF1ZSBsb3MgaW5kaWNlcyBkZSB2ZWdldGFjaW9uIGRlc2Fycm9sbGFyb24gZW4gbGEgcHJlZ3VudGEgMQ0KDQoNCmBgYHtyfQ0KDQojIyByZXNwdWVzdGEgYSBsYSBwcmVndW50YSAyOiB2ZXIgaGlzdG9ncmFtYSBkZSBkYXRvcw0KDQpoaXN0KE5EV0lfcmVjb3J0ZSwNCiAgICAgbWFpbj0gIkRzaXRyaWJ1Y2lvbiBkZSB2YWxvcmVzIGRlbCBORFdJIiwNCiAgICAgeGxhYj0gIk5EV0kiLA0KICAgICB5bGFiPSAiRnJlY3VlbmNpYSIsDQogICAgIGNvbD0gdG9wby5jb2xvcnMoNTApLA0KICAgICB4bGltPSBjICgtMC41LDAuMyksDQogICAgIGJyZWFrcyA9IDMwLA0KICAgICB4YXh0PSAnbicpDQoNCmF4aXMoc2lkZSA9IDEsIGF0PXNlcSgtMC41LDEsMC4wNSksIGxhYmVscyA9IHNlcSgtMC41LDEsMC4wNSkpDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyMgcmVzcHVlc3RhIGEgbGEgcHJlZ3VudGEgMjogdmVyIGhpc3RvZ3JhbWEgZGUgZGF0b3MNCg0KaGlzdChOREJJX3JlY29ydGUsDQogICAgIG1haW49ICJEc2l0cmlidWNpb24gZGUgdmFsb3JlcyBkZWwgTkRCSSIsDQogICAgIHhsYWI9ICJOREJJIiwNCiAgICAgeWxhYj0gIkZyZWN1ZW5jaWEiLA0KICAgICBjb2w9IGhlYXQuY29sb3JzKDUwKSwNCiAgICAgeGxpbT0gYyAoLTAuNSwwLjMpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dD0gJ24nKQ0KDQpheGlzKHNpZGUgPSAxLCBhdD1zZXEoLTAuNSwxLDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLDAuMDUpKQ0KDQpgYGANCg0KDQojIyBUSVRVTE86IFVNQlJBTElaQUNJT04NCg0KDQojIyMjIyBQb2RlbW9zIGFwbGljYXIgcmVnbGFzIGJhc2ljYXMgcGFyYSBvYnRlbmVyIHVuYSBlc3RpbWFjaW9uIGRlIGxhIGV4dGVuc2lvbiBlc3BhY2lhbCBkZSBkaWZlcmVudGVzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZS4gVGVuZ2EgZW4gY3VlbnRhIHF1ZSBsb3MgdmFsb3JlcyBORFZJIGVzdGFuIGVzdGFuZGFyaXphZG9zIHkgdmFyaWFuIGVudHJlIC0xIHkgKzEuIExvcyB2YWxvcmVzIG1hcyBhbHRvcyBpbmRpY2FuIG1hcyBjb2JlcnR1cmEgdmVyZGUuDQoNCg0KIyMjIyMgTGFzIGNlbGRhcyBjb24gdmFsb3JlcyBkZSBORFZJIHN1cGVyaW9yZXMgYSAwLjQgc29uIGRlZmluaXRpdmFtZW50ZSB2ZWdldGFjaW9uLiBMYSBzaWd1aWVudGUgb3BlcmFjaW9uIGVubWFzY2FyYSB0b2RhcyBsYXMgY2VsZGFzIHF1ZSB0YWwgdmV6IG5vIHNlYW4gdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCg0KdmVnID0gcmVjbGFzc2lmeShORFZJX3JlY29ydGVfMSwgY2JpbmQoLUluZiwgMC40LCBOQSkpDQpwbG90KHZlZywgbWFpbiA9ICJWZWdldGFjaW9uIikNCg0KDQpgYGANCg0KDQojIyMjIyBWYW1vcyBhIG1hcGVhciBlbCBhcmVhIHF1ZSBjb3JyZXNwb25kZSBhbCBwaWNvIGVudHJlIDAuMjUgeSAwLjMgZW4gZWwgaGlzdG9ncmFtYSBORFZJLg0KDQoNCmBgYHtyfQ0KDQpsYW5kID0gcmVjbGFzc2lmeShORFZJX3JlY29ydGVfMSwgYygtSW5mLCAwLjI1LCBOQSwgMC4yNSwgMC4zLCAxLCAwLjMsIEluZiwgTkEpKQ0KcGxvdChsYW5kLCBtYWluID0gIiBRdWUgZXMgZXN0bz8iKQ0KDQoNCmBgYA0KDQoNCiMjIEVzdGFzIHB1ZWRlbiBzZXIgbGFzIGFyZWFzIGFiaWVydGFzLiBQdWVkZSB0cmF6YXIgLWxhbmQtIHNvYnJlIGVsIC1sYW5kc2F0RkNDLSByYXN0ZXIgb3JpZ2luYWwgcGFyYSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbg0KDQoNCmBgYHtyfQ0KDQpwbG90UkdCKGxhbmRzYXRjcm9wMjAxNSwgcj0xLCBiPTIsIGc9MywgYXhlcyA9IFRSVUUsIHN0cmV0Y2g9ImxpbiIsIG1haW4gPSAiTGFuZHNhdCBTaWJhdGUgY29tcG9zaWNpb24gZW4gZmFsc28gY29sb3IiKQ0KDQpwbG90KGxhbmQsIGFkZCA9IFRSVUUsIGxlZ2VuZD0gRkFMU0UpDQoNCg0KDQpgYGANCg0KDQojIyMjIyBUYW1iaWVuIHB1ZWRlIGNyZWFyIGNsYXNlcyBwYXJhIGRpZmVyZW50ZXMgY2FudGlkYWRlcyBkZSBwcmVzZW5jaWEgZGUgdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCnZlZ2MgPSByZWNsYXNzaWZ5KE5EVklfcmVjb3J0ZV8xLCBjKC1JbmYsMC4yNSwxLCAwLjI1LDAuMywyLCAwLjMsMC40LDMsIDAuNCwwLjUsNCwgMC41LEluZiwgNSkpDQpwbG90KHZlZ2MsIGNvbCA9IHJldih0ZXJyYWluLmNvbG9ycyg0KSksIG1haW4gPSAnVW1icmFsIGJhc2FkbyBlbiBORFZJJykNCg0KDQpgYGANCg0KDQojIyMjIyBQcmVndW50YSAzIDogRXMgcG9zaWJsZSBlbmNvbnRyYXIgYWd1YSB1c2FuZG8gZWwgdW1icmFsIGRlIE5EVkkgbyBjdWFscXVpZXIgb3RybyBpbmRpY2UNCg0KYGBge3J9DQphZ3VhID0gcmVjbGFzc2lmeShORFdJX3JlY29ydGUsIGNiaW5kKC1JbmYsIDAuMSwgTkEpKQ0KcGxvdChhZ3VhLCBtYWluID0gIkFndWEiLCBjb2w9IHRvcG8uY29sb3JzKDEwKSkNCg0KDQphZ3VhYyA9IHJlY2xhc3NpZnkoTkRXSV9yZWNvcnRlLCBjKC1JbmYsMC4wMjUsMSwgMC4wMjUsMC4wMywyLCAwLjAzLDAuMSwzLCAwLjEsMC4yLDQsIDAuMixJbmYsIDUpKQ0KcGxvdChhZ3VhYywgY29sID0gcmV2KHRvcG8uY29sb3JzKDEwKSksIG1haW4gPSAnVW1icmFsIGJhc2FkbyBlbiBORHdJJykNCg0KDQoNCmBgYA0KDQoNCiMjIFRJVFVMTzogQU5BTElTSVMgREUgQ09NUE9ORU5URVMgUFJJTkNJUEFMRVMNCg0KDQojIyMjIyBMb3MgZGF0b3MgbXVsdGllc3BlY3RyYWxlcyBhIHZlY2VzIHNlIHRyYW5zZm9ybWFuIHBhcmEgYXl1ZGFyIGEgcmVkdWNpciBsYSBkaW1lbnNpb25hbGlkYWQgeSBlbCBydWlkbyBlbiBsb3MgZGF0b3MuIExhIHRyYW5zZm9ybWFjaW9uIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGVzIHVuIG1ldG9kbyBnZW5lcmljbyBkZSByZWR1Y2Npb24gZGUgZGF0b3MgcXVlIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY3JlYXIgYWxndW5hcyBiYW5kYXMgbm8gY29ycmVsYWNpb25hZGFzIGEgcGFydGlyIGRlIHVuIGNvbmp1bnRvIG1hcyBncmFuZGUgZGUgYmFuZGFzIGNvcnJlbGFjaW9uYWRhcy4NCg0KIyMjIyMgUHVlZGUgY2FsY3VsYXIgZWwgbWlzbW8gbnVtZXJvIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIHF1ZSBlbCBudW1lcm8gZGUgYmFuZGFzIGRlIGVudHJhZGEuIEVsIHByaW1lciBjb21wb25lbnRlIHByaW5jaXBhbCAoUEMpIGV4cGxpY2EgZWwgbWF5b3IgcG9yY2VudGFqZSBkZSB2YXJpYW56YSB5IG90cmFzIFBDIGV4cGxpY2FuIGxhIHZhcmlhbnphIGFkaWNpb25hbCBlbiBvcmRlbiBkZWNyZWNpZW50ZS4NCg0KDQpgYGB7cn0NCg0Kc2V0LnNlZWQoMSkNCg0Kc3IgPSBzYW1wbGVSYW5kb20obGFuZHNhdHAzLCAxMDAwMCkNCnBsb3Qoc3JbLGMoNCw1KV0sIG1haW4gPSAiTklSIC0gUmVkIHBsb3QiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgRXN0byBzZSBjb25vY2UgY29tbyBkaWFncmFtYSBkZSB2ZWdldGFjaW9uIHkgbGluZWEgZGUgc3VlbG8gKGlndWFsIHF1ZSBlbCBkaWFncmFtYSBkZSBkaXNwZXJzaW9uIGVuIGxhIHNlY2Npb24gYW50ZXJpb3IpLg0KDQoNCmBgYHtyfQ0KDQpwY2EgPSBwcmNvbXAoc3IsIHNjYWxlID0gVFJVRSkNCnBjYQ0KDQpzY3JlZXBsb3QocGNhKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCnBjaSA9IHByZWRpY3QobGFuZHNhdHAzLCBwY2EsIGluZGV4ID0gMToyKQ0KDQpwbG90KHBjaVtbMV1dKQ0KDQojIyByZWNvcnRhZG8gYSBzaWJhdGUNCg0KcGNpX3NpYmF0ZSA9IHNoYXBlZmlsZSgnQzovVXNlcnMvRGF2aWQvRGVza3RvcC9TSUJBVEVfUlVSQUwvcnVyYWwuc2hwJykNCg0KZXBjaSA9IGV4dGVudChwY2lfc2liYXRlKQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpwY2lfcmVjb3J0ZSA9IGNyb3AocGNpLCBlcGNpKQ0KcGxvdChwY2lfcmVjb3J0ZSwgY29sPXJldih0ZXJyYWluLmNvbG9ycygyMCkpLCBtYWluID0gInBjaSBTaWJhdGUiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgRWwgcHJpbWVyIGNvbXBvbmVudGUgcHJpbmNpcGFsIHJlc2FsdGEgbG9zIGxpbWl0ZXMgZW50cmUgbGFzIGNsYXNlcyBkZSB1c28gZGUgbGEgdGllcnJhIG8gbG9zIGRldGFsbGVzIGVzcGFjaWFsZXMsIHF1ZSBlcyBsYSBpbmZvcm1hY2lvbiBtYXMgY29tdW4gZW50cmUgdG9kYXMgbGFzIGxvbmdpdHVkZXMgZGUgb25kYS4gRXMgZGlmaWNpbCBlbnRlbmRlciBsbyBxdWUgZGVzdGFjYSBlbCBzZWd1bmRvIGNvbXBvbmVudGUgcHJpbmNpcGFsLiBWYW1vcyBhIGludGVudGFyIHVtYnJhbCBkZSBudWV2bzoNCg0KDQpgYGB7cn0NCg0KbGFuZHNhdEZDQzIwMTUgPSBzdGFjayhiNSwgYjQsIGIzKQ0KIyBwbG90UkdCKGxhbmRzYXRGQ0MyMDE1LCBheGVzPVRSVUUsIHN0cmV0Y2g9ImxpbiIsIG1haW49IkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlIikNCg0KDQojIyByZWNvcnRhZG8gYSBzaWJhdGUNCg0KcGMyID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplcGMyID0gZXh0ZW50KHBjMikNCiMgY3JvcCBsYW5kc2F0IGJ5IHRoZSBleHRlbnQNCg0KcGMyX3JlYz0gY3JvcChsYW5kc2F0RkNDMjAxNSwgZXBjMikNCiMgcGxvdChwYzJfcmVjLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDIwKSksIG1haW4gPSAicGNpIFNpYmF0ZSIpDQoNCg0KDQoNCnBjMiA9IHJlY2xhc3NpZnkocGNpX3JlY29ydGVbWzJdXSwgYygtSW5mLDAsMSwwLEluZixOQSkpDQpwYXIobWZyb3cgPSBjKDEsMikpDQpwbG90UkdCKHBjMl9yZWMsIHIgPSAxLCBnID0gMiwgYiA9IDMsIGF4ZXMgPSBUUlVFLCBzdHJldGNoID0gImxpbiIsIG1haW4gPSAiTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUiKQ0KcGxvdFJHQihwYzJfcmVjLCByID0gMSwgZyA9IDIsIGIgPSAzLCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlIikNCnBsb3QocGMyLCBsZWdlbmQgPSBGQUxTRSwgYWRkID0gVFJVRSkNCg0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgUGFyYSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbiBhY2VyY2EgZGUgbGEgaW5mb3JtYWNpb24gY29udGVuaWRhIGVuIGxhcyBwYXJjZWxhcyBkZSB2ZWdldGFjaW9uIHkgbGluZWFzIGRlIHN1ZWxvLCBsZWEgZXN0ZSBkb2N1bWVudG8gZGUgLUdpdGVsc29uIGV0IGFsLSAuIFVuYSBleHRlbnNpb24gZGUgUENBIGVuIGxhIHRlbGVkZXRlY2Npb24gc2UgY29ub2NlIGNvbW8gVHJhbnNmb3JtYWNpb24gLVRhc3NlbGVkLWNhcC0gLg0KDQpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ3RybCtBbHQrSSouDQoNCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLg0KDQpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuDQo=