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).
## 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: 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.
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?")

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")

LS0tDQp0aXRsZTogIioqSW1hZ2VuIExhbmRTYXQgOCwgU2liYXRlIDIwMTUqKiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQoNCiMjIyMjICoqTGFuZHNhdCA4IHJlY29waWxhZGEgZWwgMDQgZGUgZW5lcm8gZGUgMjAxNS4gRWwgc3ViY29uanVudG8gY3VicmUgZWwgYXJlYSBkZSBTaWJhdGUsIGRlcGFydGFtZW50byBkZSBDdW5kaW5hbWFyY2EsIGVuIENvbG9tYmlhKioNCg0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KDQojIyMjIyBTZWxlY2Npb25hciBsYSBjYXJwZXRhIGRlIGRlc3Rpbm8gDQoNCg0KYGBge3J9DQojIkM6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvTGFuZHNhdF9wcm9jZXNhbWllbnRvIg0KZ2V0d2QoKQ0KYGBgDQoNCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykgeSBsYXMgbGxhbWFtb3MgZW5ydXRhbmRvbGFzIGNvbW8gcG9yIGVqZW1wbG8gKCcuL2RhdGEvTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CMi50aWYnKQ0KDQojIyMjIypJTVBPUlRBTlRFOiBpbnN0YWxhciBwYXF1ZXRlczogcmFzdGVyLCBzcCwgcmdkYWwqDQoNCiMjIyMjIEVuIGVzdGUgY2FwaXR1bG8gc2UgZGVzY3JpYmUgbGEgZm9ybWEgZGUgYWNjZWRlciB5IGV4cGxvcmFyIHBvciBzYXRlbGl0ZSBkYXRvcyBkZSB0ZWxlZGV0ZWNjaW9uIGNvbiBSIC4gVGFtYmllbiBtb3N0cmFtb3MgY29tbyB1c2FybG9zIHBhcmEgaGFjZXIgbWFwYXMuDQoNCiMjIyMjIFV0aWxpemFyZW1vcyBwcmluY2lwYWxtZW50ZSB1biBzdWJjb25qdW50byBlc3BhY2lhbCBkZSB1bmEgZXNjZW5hIExhbmRzYXQgOCByZWNvcGlsYWRhIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIEVsIHN1YmNvbmp1bnRvIGN1YnJlIGVsIGFyZWEgZW50cmUgQ29uY29yZCB5IFN0b2NrdG9uICwgZW4gQ2FsaWZvcm5pYSwgRUUuIFVVLg0KDQojIyMjIyBUb2RhcyBsYXMgZXNjZW5hcyBkZSBpbWFnZW5lcyBkZSBMYW5kc2F0IHRpZW5lbiB1bmEgaWRlbnRpZmljYWNpb24gZGUgcHJvZHVjdG8geSBtZXRhZGF0b3MgdW5pY29zLiBQdWVkZSBlbmNvbnRyYXIgbGEgaW5mb3JtYWNpb24gc29icmUgZWwgc2Vuc29yIExhbmRzYXQsIGVsIHNhdGVsaXRlLCBsYSB1YmljYWNpb24gZW4gbGEgVGllcnJhIChydXRhIFdSUywgZmlsYSBXUlMpIHkgbGEgZmVjaGEgZGUgYWRxdWlzaWNpb24gYSBwYXJ0aXIgZGUgbGEgSUQgZGVsIHByb2R1Y3RvLiBQb3IgZWplbXBsbywgZWwgaWRlbnRpZmljYWRvciBkZSBwcm9kdWN0byBkZSBsb3MgZGF0b3MgcXVlIHV0aWxpemFyZW1vcyBlcyAnTEMwOF8wNDQwMzRfMjAxNzA2MTQnLiBDb24gYmFzZSBlbiBlc3RhIGd1aWEgLCBwdWVkZSB2ZXIgcXVlIGVsIFNlbnNvci1TYXRlbGl0ZSBlcyBPTEkgLyBUSVJTIGNvbWJpbmFkb3MgTGFuZHNhdCA4LCBXUlMgUGF0aCA0NCwgV1JTIFJvdyAzNCB5IHJlY29waWxhZG9zIGVsIDE0IGRlIGp1bmlvIGRlIDIwMTcuIExhcyBlc2NlbmFzIGRlIExhbmRzYXQgc2UgZW50cmVnYW4gbWFzIGNvbXVubWVudGUgY29tbyB1biBhcmNoaXZvIGNvbXByaW1pZG8sIHF1ZSBjb250aWVuZSBhcmNoaXZvcyBzZXBhcmFkb3MgcGFyYSBjYWRhIGJhbmRhDQoNCiMjIyMjIENvbWVuemFyZW1vcyBleHBsb3JhbmRvIHkgdmlzdWFsaXphbmRvIGxvcyBkYXRvcyAoY29uc3VsdGUgbGFzIGluc3RydWNjaW9uZXMgZW4gZWwgQ2FwaXR1bG8gMSBwYXJhIG9idGVuZXIgaW5zdHJ1Y2Npb25lcyBkZSBkZXNjYXJnYSBkZSBkYXRvcyBzaSBhdW4gbm8gbG8gaGEgaGVjaG8pLg0KDQoNCg0KIyMjICoqVElUVUxPOiBQUk9QSUVEQURFUyBERSBJTUFHRU4qKg0KDQojIyMjIyBDcmVhciBvYmpldG9zIFJhc3RlckxheWVyIHBhcmEgY2FwYXMgaW5kaXZpZHVhbGVzIExhbmRzYXQgKGJhbmRhcykNCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCg0KYjEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMS50aWYnKQ0KDQoNCiMgYXp1bA0KYjIgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYnKQ0KIyB2ZXJkZQ0KYjMgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMy50aWYnKQ0KIyByb2pvDQpiNCA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZicpDQojIEluZnJhcm9qbyBjZXJjYW5vIChOSVIpDQpiNSA9IHJhc3RlcignLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I1LnRpZicpDQoNCg0KYjYgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNi50aWYnKQ0KYjcgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNy50aWYnKQ0KYjggPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYnKQ0KYjkgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COS50aWYnKQ0KYjEwID0gcmFzdGVyKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjEwLnRpZicpDQpiMTEgPSByYXN0ZXIoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTEudGlmJykNCg0KYGBgDQoNCg0KIyMjIyMgc2UgaW5zZXJ0YSB1biBudWV2byBibG9xdWUgZGUgY29kaWdvIGN0cmwrYWx0K2k6IGltcHJpbWlyIGxhcyB2YXJpYWJsZXMgcGFyYSB2ZXJpZmljYXIsIHBvciBlamVtcGxvOg0KDQoNCmBgYHtyfQ0KYjINCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIHZlciBsYSByZXNvbHVjaW9uIGVzcGFjaWFsLCBsYSBleHRlbnNpb24sIGVsIG51bWVybyBkZSBjYXBhcywgZWwgc2lzdGVtYSBkZSByZWZlcmVuY2lhIGRlIGNvb3JkZW5hZGFzIHkgbWFzLg0KDQoNCg0KIyMjICoqVElUVUxPOiBJTkZPUk1BQ0lPTiBERSBJTUFHRU4gWSBFU1RBRElTVElDQVMqKg0KDQoNCiMjIyBBIGNvbnRpbnVhY2lvbiBzZSBtdWVzdHJhIGNvbW8gcHVlZGUgYWNjZWRlciBhIHZhcmlhcyBwcm9waWVkYWRlcyBkZXNkZSB1biBvYmpldG8gUmFzdGVyICogKGVzdG8gZXMgbG8gbWlzbW8gcGFyYSBjdWFscXVpZXIgY29uanVudG8gZGUgZGF0b3MgcmFzdGVyKS4NCg0KDQpgYGB7cn0NCiMgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtIChDUlMpDQpjcnMoYjIpDQojIyBDUlMgYXJndW1lbnRzOg0KIyMgK3Byb2o9dXRtICt6b25lPTE4ICtkYXR1bT1XR1M4NCArdW5pdHM9bSArbm9fZGVmcyArZWxscHM9V0dTODQNCiMjICt0b3dnczg0PTAsMCwwDQojIE51bWJlciBvZiBjZWxscywgcm93cywgY29sdW1ucw0KbmNlbGwoYjIpDQojIyBbMV0gNTg2ODQ1MjENCmRpbShiMikNCiMjIFsxXSA3NzQxIDc1ODEgICAgMQ0KIyBzcGF0aWFsIHJlc29sdXRpb24NCnJlcyhiMikNCiMjIFsxXSAzMCAzMA0KIyBOdW1iZXIgb2YgYmFuZHMNCm5sYXllcnMoYjIpDQojIyBbMV0gMQ0KIyBEbyB0aGUgYmFuZHMgaGF2ZSB0aGUgc2FtZSBleHRlbnQsIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLCBwcm9qZWN0aW9uLCByZXNvbHV0aW9uLCBhbmQgb3JpZ2luDQpjb21wYXJlUmFzdGVyKGIyLGIzKQ0KIyMgWzFdIFRSVUUNCmBgYA0KDQoNCiMjIyMjIFB1ZWRlIGNyZWFyIHVuIFJhc3RlclN0YWNrICh1biBvYmpldG8gY29uIHZhcmlhcyBjYXBhcykgYSBwYXJ0aXIgZGUgbG9zIG9iamV0b3MgUmFzdGVyTGF5ZXIgKGJhbmRhIHVuaWNhKSBleGlzdGVudGVzIA0KDQoNCiMjIyMjIExhcyBiYW5kYXMgcXVlIGxsYW1vcyBzb24gbGFzIG1pc21hcyBxdWUgaGVtb3MgbGxhbWFkb2RvIGFycmliYSBjb21vIFJhc3RlckxheWVyDQoNCmBgYHtyfQ0KczIwMTUgPSBzdGFjayhiNSwgYjQsIGIzKQ0KDQojIENoZWNrIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBSYXN0ZXJTdGFjaw0KczIwMTUNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCAzICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICsrcHJvaj11dG0gK3pvbmU9MTggK2RhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzICtlbGxwcz1XR1M4NCArdG93Z3M4ND0wLDAsMA0KIyMgbmFtZXMgICAgICA6IExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjUsIExDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjQsICAgICBMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IzDQojIyBtaW4gdmFsdWVzIDogIDAsIDAsIDAgDQojIyBtYXggdmFsdWVzIDogIDY1NTM1LCA2NTUzNSwgNjU1MzUNCmBgYA0KDQoNCiMjIyMjIFRhbWJpZW4gcHVlZGUgY3JlYXIgZWwgUmFzdGVyU3RhY2sgdXNhbmRvIGxvcyBub21icmVzIGRlIGFyY2hpdm8gDQoNCg0KYGBge3J9DQoNCiMgZmlyc3QgY3JlYXRlIGEgbGlzdCBvZiByYXN0ZXIgbGF5ZXJzIHRvIHVzZQ0KZmlsZW5hbWVzID0gcGFzdGUwKCcuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQicsIDE6NywgIi50aWYiKQ0KZmlsZW5hbWVzDQoNCiMjIFsxXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxLnRpZiIgDQojIyBbMl0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMi50aWYiIA0KIyMgWzNdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjMudGlmIiANCiMjIFs0XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I0LnRpZiIgDQojIyBbNV0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CNS50aWYiIA0KIyMgWzZdICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjYudGlmIiANCiMjIFs3XSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0I3LnRpZiIgDQoNCiMjIyMjIyBubyBsZWUgbGEgYmFuZGEgOCBwb3JxdWUgdGllbmUgZGlmZXJlbnRlIGV4dGVuc2lvbg0KDQojIyBbOF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9COC50aWYiIA0KIyMgWzldICIuL2RhdGEyMDE1L0xDMDhfTDFUUF8wMDgwNTdfMjAxNTAxMDRfMjAxNzA0MTVfMDFfVDFfQjkudGlmIiANCiMjIFsxMF0gIi4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CMTAudGlmIg0KIyMgWzExXSAiLi9kYXRhMjAxNS9MQzA4X0wxVFBfMDA4MDU3XzIwMTUwMTA0XzIwMTcwNDE1XzAxX1QxX0IxMS50aWYiDQoNCg0KbGFuZHNhdDIwMTU9IHN0YWNrKGZpbGVuYW1lcykNCmxhbmRzYXQyMDE1DQoNCiMjIGNsYXNzICAgICAgOiBSYXN0ZXJTdGFjaw0KIyMgZGltZW5zaW9ucyA6IDc3NDEsIDc1ODEsIDU4Njg0NTIxLCA3ICAobnJvdywgbmNvbCwgbmNlbGwsIG5sYXllcnMpDQojIyByZXNvbHV0aW9uIDogMzAsIDMwICAoeCwgeSkNCiMjIGV4dGVudCAgICAgOiA0NDYwODUsIDY3MzUxNSwgMzYyOTg1LCA1OTUyMTUgICh4bWluLCB4bWF4LCB5bWluLCB5bWF4KQ0KIyMgY3JzICAgICAgICA6ICtwcm9qPXV0bSArem9uZT0xMCArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwDQojIyBuYW1lcyAgICAgIDogTEMwOF9MMVRQLy81XzAxX1QxX0IxLCBMQzA4X0wxVFAvLzVfMDFfVDFfQjIsIExDMDhfTDFUUC8vNV8wMV9UMV9CMywgTEMwOF9MMVRQLy81XzAxX1QxX0I0LCBMQzA4X0wxVFAvLzVfMDFfVDFfQjUsIExDMDhfTDFUUC8vNV8wMV9UMV9CNiwgTEMwOF9MMVRQLy81XzAxX1QxX0I3DQojIyBtaW4gdmFsdWVzIDogICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwLCAgICAgICAgICAgICAgICAgICAgIDAsICAgICAgICAgICAgICAgICAgICAgMCwgICAgICAgICAgICAgICAgICAgICAwIA0KIyMgbWF4IHZhbHVlcyA6ICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSwgICAgICAgICAgICAgICAgIDY1NTM1LCAgICAgICAgICAgICAgICAgNjU1MzUsICAgICAgICAgICAgICAgICA2NTUzNSANCg0KDQpgYGANCg0KDQojIyMjIyBBcnJpYmEgY3JlYW1vcyB1biBSYXN0ZXJTdGFjayBjb24gMTEgY2FwYXMuIExhcyBjYXBhcyByZXByZXNlbnRhbiBsYSBpbnRlbnNpZGFkIGRlIGxhIHJlZmxleGlvbiBlbiBsYXMgc2lndWllbnRlcyBsb25naXR1ZGVzIGRlIG9uZGE6IFVsdHJhIGF6dWwsIGF6dWwsIHZlcmRlLCByb2pvLCBpbmZyYXJyb2pvIGNlcmNhbm8gKE5JUiksIGluZnJhcnJvam8gZGUgb25kYSBjb3J0YSAoU1dJUikgMSwgaW5mcmFycm9qbyBkZSBvbmRhIGNvcnRhIChTV0lSKSAyLCBwYW5jcm9tYXRpY28sIGNpcnJvLCBpbmZyYXJyb2pvIHRlcm1pY28gKFRJUlMpIDEsIEluZnJhcnJvam8gdGVybWljbyAoVElSUykgMi4gTm8gdXRpbGl6YXJlbW9zIGxhcyB1bHRpbWFzIGN1YXRybyBjYXBhcyB5IHZlcmEgY29tbyBlbGltaW5hcmxhcyBlbiBsYXMgc2lndWllbnRlcyBzZWNjaW9uZXMuDQoNCg0KDQojIyMgKipUSVRVTE86IEJBTkRBIFVOSUNBIFkgTUFQQVMgQ09NUFVFU1RPUyoqDQoNCg0KIyMjIyMgUHVlZGUgdHJhemFyIGNhcGFzIGluZGl2aWR1YWxlcyBkZSB1biBSYXN0ZXJTdGFjayBkZSB1bmEgaW1hZ2VuIG11bHRpZXNwZWN0cmFsLg0KDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3cgPSBjKDIsMikpDQpwbG90KGIyLCBtYWluID0gIkJsdWUiLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjMsIG1haW4gPSAiR3JlZW4iLCBjb2wgPSBncmF5KDA6MTAwIC8gMTAwKSkNCnBsb3QoYjQsIG1haW4gPSAiUmVkIiwgY29sID0gZ3JheSgwOjEwMCAvIDEwMCkpDQpwbG90KGI1LCBtYWluID0gIk5JUiIsIGNvbCA9IGdyYXkoMDoxMDAgLyAxMDApKQ0KDQpgYGANCg0KIyMjIyMgRWNoYSB1biB2aXN0YXpvIGEgbGFzIGxleWVuZGFzIGRlIGxvcyBtYXBhcyBjcmVhZG9zIGFudGVyaW9ybWVudGUuIFB1ZWRlbiB2YXJpYXIgZW50cmUgMCB5IDEuIE9ic2VydmUgbGEgZGlmZXJlbmNpYSBlbiBlbCBzb21icmVhZG8geSBlbCByYW5nbyBkZSBsZXllbmRhcyBlbnRyZSBsYXMgZGlmZXJlbnRlcyBiYW5kYXMuIEVzdG8gc2UgZGViZSBhIHF1ZSBsYXMgZGlmZXJlbnRlcyBjYXJhY3RlcmlzdGljYXMgZGUgbGEgc3VwZXJmaWNpZSByZWZsZWphbiBsYSByYWRpYWNpb24gc29sYXIgaW5jaWRlbnRlIGRlIG1hbmVyYSBkaWZlcmVudGUuIENhZGEgY2FwYSByZXByZXNlbnRhIGxhIGNhbnRpZGFkIGRlIHJhZGlhY2lvbiBzb2xhciBpbmNpZGVudGUgcXVlIHNlIHJlZmxlamEgcGFyYSB1biByYW5nbyBkZSBsb25naXR1ZCBkZSBvbmRhIHBhcnRpY3VsYXIuIFBvciBlamVtcGxvLCBsYSB2ZWdldGFjaW9uIHJlZmxlamEgbWFzIGVuZXJnaWEgZW4gTklSIHF1ZSBvdHJhcyBsb25naXR1ZGVzIGRlIG9uZGEgeSwgcG9yIGxvIHRhbnRvLCBwYXJlY2UgbWFzIGJyaWxsYW50ZS4gUG9yIGVsIGNvbnRyYXJpbywgZWwgYWd1YSBhYnNvcmJlIGxhIG1heW9yIHBhcnRlIGRlIGxhIGVuZXJnaWEgZW4gbGEgbG9uZ2l0dWQgZGUgb25kYSBOSVIgeSBwYXJlY2Ugb3NjdXJhLg0KDQoNCiMjIyMjIE5vIG9idGVuZW1vcyB0YW50YSBpbmZvcm1hY2lvbiBkZSBlc3RhcyBwYXJjZWxhcyBlbiBlc2NhbGEgZGUgZ3Jpc2VzOyBhIG1lbnVkbyBzZSBjb21iaW5hbiBlbiB1biAiY29tcHVlc3RvIiBwYXJhIGNyZWFyIHRyYW1hcyBtYXMgaW50ZXJlc2FudGVzLiBQdWVkZSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbiBzb2JyZSBsb3MgY29tcHVlc3RvcyBkZSBjb2xvciBlbiBsYSB0ZWxlZGV0ZWNjaW9uIGFxdWkgeSB0YW1iaWVuIGVuIGxhIHNlY2Npb24gYSBjb250aW51YWNpb24uDQoNCg0KIyMjIyMgUGFyYSBoYWNlciB1bmEgaW1hZ2VuIGRlICJjb2xvciB2ZXJkYWRlcm8gKG8gbmF0dXJhbCkiLCBlcyBkZWNpciwgYWxnbyBxdWUgc2UgcGFyZWNlIGEgdW5hIGZvdG9ncmFmaWEgbm9ybWFsICh2ZWdldGFjaW9uIGVuIHZlcmRlLCBhenVsIGFndWEsIGV0Yy4pLCBuZWNlc2l0YW1vcyBiYW5kYXMgZW4gbGFzIHJlZ2lvbmVzIHJvamEsIHZlcmRlIHkgYXp1bC4gUGFyYSBlc3RhIGltYWdlbiBMYW5kc2F0LCBzZSBwdWVkZW4gdXNhciBsYXMgYmFuZGFzIDQgKHJvam8pLCAzICh2ZXJkZSkgeSAyIChhenVsKS4gRWwgLSBwbG90UkdCIC0gbWV0b2RvIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY29tYmluYXJsb3MgZW4gdW4gc29sbyBjb21wdWVzdG8uIFRhbWJpZW4gcHVlZGUgcHJvcG9yY2lvbmFyIGFyZ3VtZW50b3MgYWRpY2lvbmFsZXMgLSBwbG90UkdCIC0gcGFyYSBtZWpvcmFyIGxhIHZpc3VhbGl6YWNpb24gKHBvciBlamVtcGxvLCB1biBlc3RpcmFtaWVudG8gbGluZWFsIGRlIGxvcyB2YWxvcmVzLCB1dGlsaXphbmRvICkuLSBzdHJlY3RoID0gImxpbiIgLQ0KDQoNCmBgYHtyfQ0KbGFuZHNhdFJHQjIwMTUgPSBzdGFjayhiNCwgYjMsIGIyKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCg0KYGBgDQoNCg0KIyMjIyMgRWwgY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyByZXZlbGEgbXVjaG8gbWFzIHNvYnJlIGVsIHBhaXNhamUgcXVlIGxhcyBpbWFnZW5lcyBncmlzZXMgYW50ZXJpb3Jlcy4gT3RybyBtZXRvZG8gcG9wdWxhciBkZSB2aXN1YWxpemFjaW9uIGRlIGltYWdlbmVzIGVuIGxhIHRlbGVkZXRlY2Npb24gZXMgbGEgaW1hZ2VuIGNvbm9jaWRhIGRlICJjb2xvciBmYWxzbyIgZW4gbGEgcXVlIHNlIGNvbWJpbmFuIGxhcyBiYW5kYXMgTklSLCByb2pvIHkgdmVyZGUuIEVzdGEgcmVwcmVzZW50YWNpb24gZXMgcG9wdWxhciB5YSBxdWUgaGFjZSBxdWUgc2VhIGZhY2lsIHZlciBsYSB2ZWdldGFjaW9uIChlbiByb2pvKS4NCg0KDQpgYGB7cn0NCg0KcGFyKG1mcm93ID0gYygxLDIpKQ0KcGxvdFJHQihsYW5kc2F0UkdCMjAxNSwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IFRydWUgQ29sb3IgQ29tcG9zaXRlIikNCmxhbmRzYXRGQ0MyMDE1ID0gc3RhY2soYjUsIGI0LCBiMykNCnBsb3RSR0IobGFuZHNhdEZDQzIwMTUsIGF4ZXM9VFJVRSwgc3RyZXRjaD0ibGluIiwgbWFpbj0iTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUiKQ0KDQpgYGANCg0KIyMjIyMgKk5vdGEgOiBDb21wcnVlYmUgc2llbXByZSBsYSBkb2N1bWVudGFjaW9uIGRlbCBwYXF1ZXRlICgtIGhlbHAocGxvdFJHQikgLSkgcGFyYSB2ZXIgb3Ryb3MgYXJndW1lbnRvcyBxdWUgc2UgcHVlZGVuIGFncmVnYXIgKGNvbW8gbGEgZXNjYWxhKSBwYXJhIG1lam9yYXIgbyBtb2RpZmljYXIgbGEgaW1hZ2VuLioNCg0KIyMjIyMgKlByZWd1bnRhIDEgOiBVc2UgbGEgZnVuY2lvbiBwbG90UkdCIGNvbiBSYXN0ZXJTdGFjayBgYCBsYW5kc2F0ICcnIHBhcmEgY3JlYXIgdW4gY29tcHVlc3RvIGRlIGNvbG9yIHZlcmRhZGVybyB5IGZhbHNvIChyZWN1ZXJkZSBsYSBwb3NpY2lvbiBkZSBsYXMgYmFuZGFzIGVuIGxhIHBpbGEpLioNCg0KYGBge3J9DQoNCiMjIHNvbHVjaW9uIGEgbGEgcHJlZ3VudGEgMQ0KbGFuZHNhdEZDQzIwMTVfcDEgPSBzdGFjayhiNSwgYjYsIGI0KQ0KcGxvdFJHQihsYW5kc2F0RkNDMjAxNV9wMSwgYXhlcz1UUlVFLCBzdHJldGNoPSJsaW4iLCBtYWluPSJMYW5kc2F0IGNvbXBvc2ljaW9uIGRlIGNvbG9yIGZhbHNhIC0gQWd1YSAvIFRpZXJyYSIpDQoNCg0KYGBgDQoNCg0KDQojIyMgKipUSVRVTE86IFNVQkNPTkpVTlRPIFkgUkVOT01CUkFSIEJBTkRBUyoqDQoNCg0KIyMjIyMgUHVlZGUgc2VsZWNjaW9uYXIgY2FwYXMgKGJhbmRhcykgZXNwZWNpZmljYXMgbWVkaWFudGUgbGEgLSBzdWJzZXQgLSBmdW5jaW9uIG8gbWVkaWFudGUgaW5kZXhhY2lvbi4NCg0KDQpgYGB7cn0NCg0KIyBzZWxlY3QgZmlyc3QgMyBiYW5kcyBvbmx5DQpsYW5kc2F0MjAxNXN1YjAxID0gc3Vic2V0KGxhbmRzYXQyMDE1LCAxOjMpDQojIHNhbWUNCmxhbmRzYXQyMDE1c3ViMDIgPSBsYW5kc2F0MjAxNVtbMTozXV0NCiMgTnVtYmVyIG9mIGJhbmRzIGluIHRoZSBvcmlnaW5hbCBhbmQgbmV3IGRhdGENCm5sYXllcnMobGFuZHNhdDIwMTUpDQojIyBbMV0gNw0KbmxheWVycyhsYW5kc2F0MjAxNXN1YjAxKQ0KIyMgWzFdIDMNCm5sYXllcnMobGFuZHNhdDIwMTVzdWIwMikNCiMjIFsxXSAzDQoNCmBgYA0KDQoNCiMjIyMjIE5vIHVzYXJlbW9zIGxhcyB1bHRpbWFzIGN1YXRybyBiYW5kYXMgLSBsYW5kc2F0IC0uIFB1ZWRlcyBlbGltaW5hciBhcXVlbGxvcyB1c2FuZG86DQoNCg0KYGBge3J9DQoNCmxhbmRzYXQyMDE1ID0gc3Vic2V0KGxhbmRzYXQyMDE1LCAxOjcpDQpwbG90KGxhbmRzYXQyMDE1KQ0KYGBgDQoNCg0KIyMjIyMgUGFyYSBtYXlvciBjbGFyaWRhZCwgZXMgdXRpbCBlc3RhYmxlY2VyIGxvcyBub21icmVzIGRlIGxhcyBiYW5kYXMuDQoNCg0KYGBge3J9DQoNCm5hbWVzKGxhbmRzYXQyMDE1KQ0KDQojIyBbMV0gIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjEiICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IyIg0KIyMgWzNdICJMQzA4X0wxVFBfMDA4MDU3XzIwMTgwMzE3XzIwMTgwNDAzXzAxX1QxX0IzIiAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNCINCiMjIFs1XSAiTEMwOF9MMVRQXzAwODA1N18yMDE4MDMxN18yMDE4MDQwM18wMV9UMV9CNSIgIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjYiDQojIyBbN10gIkxDMDhfTDFUUF8wMDgwNTdfMjAxODAzMTdfMjAxODA0MDNfMDFfVDFfQjciDQpuYW1lcyhsYW5kc2F0MjAxNSkgPSBjKCd1bHRyYS1ibHVlJywgJ2JsdWUnLCAnZ3JlZW4nLCAncmVkJywgJ05JUicsICdTV0lSMScsICdTV0lSMicpDQpuYW1lcyhsYW5kc2F0MjAxNSkNCiMjIFsxXSAidWx0cmEuYmx1ZSIgImJsdWUiICAgICAgICJncmVlbiIgICAgICAicmVkIiAgICAgICAgIk5JUiINCiMjIFs2XSAiU1dJUjEiICAgICAgIlNXSVIyIg0KDQpgYGANCg0KDQoNCiMjIyAqKlRJVFVMTzogU1VCQ09OSlVOVE8gRVNQQUNJQUwgTyBSRUNPUlRFKioNCg0KDQojIyMjIyBFbCBzdWJjb25qdW50byBlc3BhY2lhbCBzZSBwdWVkZSB1c2FyIHBhcmEgbGltaXRhciBlbCBhbmFsaXNpcyBhIHVuIHN1YmNvbmp1bnRvIGdlb2dyYWZpY28gZGUgbGEgaW1hZ2VuLiBMb3Mgc3ViY29uanVudG9zIGVzcGFjaWFsZXMgc2UgcHVlZGVuIGNyZWFyIGNvbiBsYSAtIGNyb3AgLSBmdW5jaW9uLCB1dGlsaXphbmRvIHVuIC0gZXh0ZW50IC0gb2JqZXRvIHUgb3RybyBvYmpldG8gZXNwYWNpYWwgZGVsIHF1ZSBzZSBwdWVkZSBleHRyYWVyIHVuYSBFeHRlbnNpb24uDQoNCmBgYHtyfQ0KDQojIFVzaW5nIGV4dGVudA0KZXh0ZW50KGxhbmRzYXQyMDE1KQ0KIyMgY2xhc3MgICAgICA6IEV4dGVudA0KIyMgeG1pbiAgICAgICA6IDQ0NjA4NSANCiMjIHhtYXggICAgICAgOiA2NzM1MTUNCiMjIHltaW4gICAgICAgOiAzNjI5ODUNCiMjIHltYXggICAgICAgOiA1OTUyMTUNCg0Kc2liYXRlMjAxNSA9IHNoYXBlZmlsZSgnQzovVXNlcnMvRGF2aWQvRGVza3RvcC9TSUJBVEVfUlVSQUwvcnVyYWwuc2hwJykNCg0KZSA9IGV4dGVudChzaWJhdGUyMDE1KQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpsYW5kc2F0Y3JvcDIwMTUgPSBjcm9wKGxhbmRzYXQyMDE1LCBlKQ0KDQoNCnBsb3RSR0IobGFuZHNhdGNyb3AyMDE1LCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgVHJ1ZSBDb2xvciBDb21wb3NpdGUiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgKlByZWd1bnRhIDIgOiBUYW1iaWVuIGVzIHBvc2libGUgbGEgc2VsZWNjaW9uIGludGVyYWN0aXZhIGRlIGxhIGltYWdlbi4gVXNlIGBgIGRyYXdFeHRlbnRgYCB5IGBgIGRyYXdQb2x5YGAgcGFyYSBzZWxlY2Npb25hciB1biBhcmVhIGRlIGludGVyZXMqDQoNCiMjIyMgc2UgZGEgcmVzcHVlc3RhIGEgZXN0YSBwcmVndW50YSBjb24gZWwgZWplcmNpY2lvIGFudGVyaW9yDQoNCg0KIyMjIyMgKlByZWd1bnRhIDMgOiBVc2UgZWwgYGAgTGFuZHNhdGNyb3AgJycgZGUgUmFzdGVyU3RhY2sgcGFyYSBjcmVhciB1biBjb21wdWVzdG8gZGUgY29sb3IgdmVyZGFkZXJvIHkgZmFsc28qDQoNCmBgYHtyfQ0KDQpsYW5kc2F0Y3JvcDIwMTVwcmVndW50YSA9IGNyb3Aoc3RhY2soYjQsIGIzLCBiMiksIGUpDQoNCg0KcGxvdFJHQihsYW5kc2F0Y3JvcDIwMTVwcmVndW50YSwgYXhlcyA9IFRSVUUsIHN0cmV0Y2ggPSAibGluIiwgbWFpbiA9ICJMYW5kc2F0IFNpYmF0ZSAyMDE1IC0gQ29sb3IgVmVyZGFkZXJvIikNCg0KDQoNCmBgYA0KDQoNCiMjIyAqKlRJVFVMTzogR1VBUkRBTkRPIFJFU1VMVEFET1MgRU4gRUwgRElTQ08qKg0KDQoNCiMjIyMjIEVuIGVzdGEgZXRhcGEsIGVzIHBvc2libGUgcXVlIHF1ZXJhbW9zIGd1YXJkYXIgZWwgcmFzdGVyIGVuIGVsIGRpc2NvIHVzYW5kbyBsYSBmdW5jaW9uIC0gd3JpdGVSYXN0ZXIgLS4gU2UgYWRtaXRlbiBtdWx0aXBsZXMgdGlwb3MgZGUgYXJjaGl2b3MuIFV0aWxpemFyZW1vcyBlbCBmb3JtYXRvIEdlb1RpZmYgZGUgdXNvIGNvbXVuLiBNaWVudHJhcyBzZSBjb25zZXJ2YSBlbCBvcmRlbiBkZSBsYXMgY2FwYXMsIGxvcyBub21icmVzIGRlIGxhcyBjYXBhcyBzZSBwaWVyZGVuIGRlc2Fmb3J0dW5hZGFtZW50ZSBlbiBlbCBmb3JtYXRvIEdlb1RpZmYNCg0KYGBge3J9DQoNCnggPSB3cml0ZVJhc3RlcihsYW5kc2F0Y3JvcDIwMTUsIGZpbGVuYW1lPSJjcm9wcGVkLWxhbmRzYXQudGlmIiwgb3ZlcndyaXRlPVRSVUUpDQpwbG90KHgpDQoNCmBgYA0KDQoNCiMjIyMjIEFsdGVybmF0aXZhbWVudGUsIHB1ZWRlIHV0aWxpemFyIGVsIGZvcm1hdG8gJ3Jhc3Rlci1ncmQnLg0KDQoNCmBgYHtyfQ0KDQp3cml0ZVJhc3RlcihsYW5kc2F0Y3JvcDIwMTUsIGZpbGVuYW1lPSJjcm9wcGVkLWxhbmRzYXQuZ3JkIiwgb3ZlcndyaXRlPVRSVUUpDQoNCmBgYA0KDQoNCiMjIyMjIFVuYSB2ZW50YWphIGRlIGVzdGUgZm9ybWF0byBlcyBxdWUgZ3VhcmRhIGxvcyBub21icmVzIGRlIGxhcyBjYXBhcy4gTGEgZGVzdmVudGFqYSBkZSBlc3RlIGZvcm1hdG8gZXMgcXVlIG5vIG11Y2hvcyBvdHJvcyBwcm9ncmFtYXMgcHVlZGVuIGxlZXIgbG9zIGRhdG9zLCBlbiBjb250cmFzdGUgY29uIGVsIGZvcm1hdG8gR2VvVGlmZi4NCg0KIyMjIyMgKk5vdGE6IENvbnN1bHRlIGxhIGRvY3VtZW50YWNpb24gZGVsIHBhcXVldGUgKC0gaGVscCh3cml0ZVJhc3RlcikgLSkgcGFyYSB2ZXIgYXJndW1lbnRvcyB1dGlsZXMgYWRpY2lvbmFsZXMgcXVlIHNlIHB1ZWRlbiBhZ3JlZ2FyKg0KDQoNCg0KIyMjICoqVElUVUxPOiBSRUxBQ0lPTiBFTlRSRSBCQU5EQVMqKg0KDQoNCiMjIyMjIFVuYSBtYXRyaXogZGUgZGlhZ3JhbWEgZGUgZGlzcGVyc2lvbiBwdWVkZSBzZXIgdXRpbCBwYXJhIGV4cGxvcmFyIGxhcyByZWxhY2lvbmVzIGVudHJlIGNhcGFzIHJhc3Rlci4gRXN0byBzZSBwdWVkZSBoYWNlciBjb24gbGEgZnVuY2lvbiBwYXJlcyAoKSBkZWwgcGFxdWV0ZSByYXN0ZXIuDQoNCg0KIyMjIyMgVHJhemFkbyBkZSByZWZsZWpvIGVuIGxhIGxvbmdpdHVkIGRlIG9uZGEgdWx0cmEgYXp1bCBjb250cmEgZWwgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIGF6dWwuDQoNCg0KYGBge3J9DQpwYWlycyhsYW5kc2F0Y3JvcDIwMTVbWzE6Ml1dLCBtYWluID0gIlVsdHJhLWJsdWUgdmVyc3VzIEJsdWUiKQ0KYGBgDQoNCg0KIyMjIyMgVHJhemFkbyBkZSByZWZsZWpvIGVuIGxhIGxvbmdpdHVkIGRlIG9uZGEgcm9qYSBjb250cmEgcmVmbGVqbyBlbiBsYSBsb25naXR1ZCBkZSBvbmRhIE5JUi4NCg0KDQpgYGB7cn0NCnBhaXJzKGxhbmRzYXRjcm9wMjAxNVtbNDo1XV0sIG1haW4gPSAiUmVkIHZlcnN1cyBOSVIiKQ0KYGBgDQoNCg0KIyMjIyMgTGEgcHJpbWVyYSBncmFmaWNhIHJldmVsYSBhbHRhcyBjb3JyZWxhY2lvbmVzIGVudHJlIGxhcyByZWdpb25lcyBkZSBsb25naXR1ZCBkZSBvbmRhIGF6dWwuIERlYmlkbyBhIGxhIGFsdGEgY29ycmVsYWNpb24sIHBvZGVtb3MgdXNhciB1bmEgZGUgbGFzIGJhbmRhcyBhenVsZXMgc2luIHBlcmRlciBtdWNoYSBpbmZvcm1hY2lvbi4NCg0KIyMjIyMgRXN0YSBkaXN0cmlidWNpb24gZGUgcHVudG9zIGVuIGxhIHNlZ3VuZGEgZ3JhZmljYSAoZW50cmUgTklSIHkgcm9qbykgZXMgdW5pY2EgZGViaWRvIGEgc3UgZm9ybWEgdHJpYW5ndWxhci4gTGEgdmVnZXRhY2lvbiBzZSByZWZsZWphIG11eSBiaWVuIGVuIGVsIHJhbmdvIE5JUiBxdWUgZWwgcm9qbyB5IGNyZWEgbGEgZXNxdWluYSBzdXBlcmlvciBjZXJjYSBkZWwgZWplIE5JUiAoeSkuIEVsIGFndWEgYWJzb3JiZSBlbmVyZ2lhIGRlIHRvZGFzIGxhcyBiYW5kYXMgeSBvY3VwYSBlbCBsdWdhciBjZXJjYW5vIGFsIG9yaWdlbi4gRWwgcmluY29uIG1hcyBhbGVqYWRvIHNlIGNyZWEgZGViaWRvIGEgbGFzIGNhcmFjdGVyaXN0aWNhcyBzdXBlcmZpY2lhbGVzIGFsdGFtZW50ZSByZWZsZWN0YW50ZXMsIGNvbW8gZWwgc3VlbG8gYnJpbGxhbnRlIG8gZWwgaG9ybWlnb24uDQoNCg0KIyMjICoqVElUVUxPOiBFWFRSQUVSIFZBTE9SRVMgREUgUElYRUxFUyAqKg0KDQoNCiMjIyMjIEEgbWVudWRvLCBxdWVyZW1vcyBvYnRlbmVyIGxvcyB2YWxvcmVzIGRlIGxhcyBjZWxkYXMgcmFzdGVyIHBhcmEgdWJpY2FjaW9uZXMgZ2VvZ3JhZmljYXMgbyBhcmVhcyBlc3BlY2lmaWNhcy4gTGEgLSBleHRyYWN0IC0gZnVuY2lvbiBzZSB1dGlsaXphIHBhcmEgb2J0ZW5lciB2YWxvcmVzIHJhc3RlciBlbiBsYXMgdWJpY2FjaW9uZXMgZGUgb3Ryb3MgZGF0b3MgZXNwYWNpYWxlcy4gUHVlZGUgdXNhciBwdW50b3MsIGxpbmVhcywgcG9saWdvbm9zIG8gdW4gb2JqZXRvIGRlIGV4dGVuc2lvbiAocmVjdGFuZ3VsbykuIFRhbWJpZW4gcHVlZGUgdXNhciBudW1lcm9zIGRlIGNlbGRhIHBhcmEgZXh0cmFlciB2YWxvcmVzLiBBbCB1c2FyIHB1bnRvcywgLSBleHRyYWN0IC0gZGV2dWVsdmUgbG9zIHZhbG9yZXMgZGUgdW4gLSBSYXN0ZXIqIC0gb2JqZXRvIHBhcmEgbGFzIGNlbGRhcyBlbiBsYXMgcXVlIHNlIHViaWNhIHVuIGNvbmp1bnRvIGRlIHB1bnRvcy4NCg0KDQpgYGB7cn0NCiMgbG9hZCB0aGUgcG9seWdvbnMgd2l0aCBsYW5kIHVzZSBsYW5kIGNvdmVyIGluZm9ybWF0aW9uDQoNCnNpYmF0ZWNvYmVydCA9IHNoYXBlZmlsZSAoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvUEVSQ0VQQ0lPTiBSRU1PVEEvVFJBQkFKT19DT0JFUlRVUkFTL2NvYmVydHUuc2hwJykNCiAgICAjIHNhbXAgPSByZWFkUkRTKCdkYXRhL3JzL3NhbXBsZXMucmRzJykgICAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgZ2VuZXJhdGUgMzAwIHBvaW50IHNhbXBsZXMgZnJvbSB0aGUgcG9seWdvbnMNCg0KcHRzaWJhdGVjb2JlcnQgPSBzcHNhbXBsZShzaWJhdGVjb2JlcnQsMzAwLCB0eXBlPSdyZWd1bGFyJykNCiAgICAjIHB0c2FtcCA9IHNwc2FtcGxlKHNhbXAsIDMwMCwgdHlwZT0ncmVndWxhcicpICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgYWRkIHRoZSBsYW5kIGNvdmVyIGNsYXNzIHRvIHRoZSBwb2ludHMNCnB0c2liYXRlY29iZXJ0JE5hbWUgPSBvdmVyKHB0c2liYXRlY29iZXJ0LCBzaWJhdGVjb2JlcnQpJE5hbWUNCiAgICAjIHB0c2FtcCRjbGFzcyA9IG92ZXIocHRzYW1wLCBzYW1wKSRjbGFzcyAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCg0KIyBleHRyYWN0IHZhbHVlcyB3aXRoIHBvaW50cw0KZGYgPSBleHRyYWN0KGxhbmRzYXQyMDE1LCBwdHNpYmF0ZWNvYmVydCkNCiAgICMgZGYgPSBleHRyYWN0KGxhbmRzYXQxLCBwdHNhbXApICAgICAgICAgICAgICAgICAgICAgICoqZW4gbGEgZ3VpYSBlc3RhIGFzaSoqDQoNCiMgVG8gc2VlIHNvbWUgb2YgdGhlIHJlZmxlY3RhbmNlIHZhbHVlcw0KaGVhZChkZikNCg0KIyAgICAgdWx0cmEuYmx1ZSBibHVlIGdyZWVuICByZWQgICBOSVIgU1dJUjEgU1dJUjINCiNbMSxdICAgICAgIDg0ODQgNzgwMCAgNzUyOCA2OTMxIDE0Nzc3IDEwODc5ICA4MTY3DQojWzIsXSAgICAgICA4ODE2IDgyNjUgIDg2OTQgODE4MSAyMTAyNCAxNjc1MyAxMTMxMw0KI1szLF0gICAgICAgODQxOSA3NzkxICA4MjA2IDY4NDcgMjQ3NjEgMTE4MDEgIDc5NjINCiNbNCxdICAgICAgIDgzOTkgNzc0NSAgODA4NyA2Nzc1IDI0Nzc1IDEyMTYwICA4MDEyDQojWzUsXSAgICAgICA4MDcyIDczOTQgIDY5MDQgNjI3MyAxMTIwNyAgODA5OCAgNjYyMQ0KI1s2LF0gICAgICAgODA3MiA3MzgwICA2ODI3IDYyMzEgMTA3MjggIDgwODQgIDY2NTQNCmBgYA0KDQoNCg0KIyMjICoqVElUVUxPOiBQRVJGSUxFUyBFU1BFQ1RSQUxFUyoqDQoNCg0KIyMjIyMgVW5hIGdyYWZpY2EgZGVsIGVzcGVjdHJvICh0b2RhcyBsYXMgYmFuZGFzKSBwYXJhIGxvcyBwaXhlbGVzIHF1ZSByZXByZXNlbnRhbiBjaWVydGFzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZSAocC4gRWouIEFndWEpIHNlIGNvbm9jZSBjb21vIHBlcmZpbCBlc3BlY3RyYWwuIERpY2hvcyBwZXJmaWxlcyBkZW11ZXN0cmFuIGxhcyBkaWZlcmVuY2lhcyBlbiBsYXMgcHJvcGllZGFkZXMgZXNwZWN0cmFsZXMgZGUgdmFyaWFzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZSB5IGNvbnN0aXR1eWVuIGxhIGJhc2UgcGFyYSBlbCBhbmFsaXNpcyBkZSBpbWFnZW5lcy4gTG9zIHZhbG9yZXMgZXNwZWN0cmFsZXMgc2UgcHVlZGVuIGV4dHJhZXIgZGUgY3VhbHF1aWVyIGNvbmp1bnRvIGRlIGRhdG9zIG11bHRpZXNwZWN0cmFsZXMgdXRpbGl6YW5kbyBsYSAtIGV4dHJhY3QgLSBmdW5jaW9uLiBFbiBlbCBlamVtcGxvIGFudGVyaW9yLCBleHRyYWppbW9zIHZhbG9yZXMgZGUgZGF0b3MgZGUgTGFuZHNhdCBwYXJhIGxhcyBtdWVzdHJhcy4gRXN0YXMgbXVlc3RyYXMgaW5jbHV5ZW46IHRpZXJyYXMgZGUgY3VsdGl2bywgYWd1YSwgYmFyYmVjaG8sIGNvbnN0cnVpZG8geSBhYmllcnRvLiBQcmltZXJvIGNhbGN1bGFtb3MgbG9zIHZhbG9yZXMgbWVkaW9zIGRlIHJlZmxlY3RhbmNpYSBwYXJhIGNhZGEgY2xhc2UgeSBjYWRhIGJhbmRhLg0KDQoNCmBgYHtyfQ0KDQpudW1lcm89IGxlbmd0aChwdHNpYmF0ZWNvYmVydCkNCm51bWVybw0KDQpkZl9zYW1wbGVzID0gYXMgKHB0c2liYXRlY29iZXJ0LCAiU3BhdGlhbFBvaW50c0RhdGFGcmFtZSIpDQpkZl9zYW1wbGVzDQpkZl9zYW1wbGVzQGRhdGE9ZGF0YS5mcmFtZShJRD0xOm51bWVybyxzaXplPTEpDQpkZl9zYW1wbGVzDQoNCg0KcGxvdChsYW5kc2F0Y3JvcDIwMTUpDQpwbG90KHNpYmF0ZWNvYmVydCwgYWRkPSBUUlVFKQ0KcGxvdChkZl9zYW1wbGVzLHBjaD0xLCBjZXg9KGRmX3NhbXBsZXMkc2l6ZSkvNCwgYWRkPVRSVUUpDQoNCg0KZGZfc2FtcGxlcyROYW1lID1vdmVyKGRmX3NhbXBsZXMsc2liYXRlY29iZXJ0KSROYW1lDQpkZl9zYW1wbGVzDQpkZjE9cmFzdGVyOjpleHRyYWN0KGxhbmRzYXRjcm9wMjAxNSwgZGZfc2FtcGxlcykNCg0KDQptcyA9IGFnZ3JlZ2F0ZShkZjEsIGxpc3QocHRzaWJhdGVjb2JlcnQkTmFtZSksIG1lYW4pDQojIyBtcyA9IGFnZ3JlZ2F0ZShkZiwgbGlzdChwdHNhbXAkY2xhc3MpLCBtZWFuKSAgICAgICAgICoqIGFzaSBlc3RhIGVuIGxhIGd1aWEqKg0KDQojIGluc3RlYWQgb2YgdGhlIGZpcnN0IGNvbHVtbiwgd2UgdXNlIHJvdyBuYW1lcw0Kcm93bmFtZXMobXMpID0gbXNbLDFdDQptcyA9IG1zWywtMV0NCm1zDQoNCg0KIyMgICAgICAgICAgdWx0cmEuYmx1ZSAgICAgIGJsdWUgICAgICBncmVlbiAgICAgICByZWQgICAgICAgIE5JUiAgICAgIFNXSVIxDQojIyBidWlsdCAgICAgMC4xODY0OTI1IDAuMTc5NTM3MSAwLjE3OTUzMzE3IDAuMTk1ODQxNCAwLjI1NDQ4NDQ3IDAuMjQ4NTAxOTcNCiMjIGNyb3BsYW5kICAwLjExMjk4MTMgMC4wOTA5NjQ1IDAuMDg1OTY3MjIgMC4wNTUwMzQ0IDAuNDgzMzU0NjIgMC4xNjE0MjA4NQ0KIyMgZmFsbG93ICAgIDAuMTMxOTE5OCAwLjExNjQ4NjkgMC4xMDQ1Mzc2NCAwLjExNTEyNDMgMC4xODAxMjk2MiAwLjIzMTM5MjI4DQojIyBvcGVuICAgICAgMC4xMzg4MDE0IDAuMTM3NTIzNSAwLjE1MjczMTYzIDAuMjA2NjQyNSAwLjM0NDc2NjcwIDAuMzU4MjA4NzcNCiMjIHdhdGVyICAgICAwLjEzMzYyNDIgMC4xMTY1NzI4IDAuMDk5MjI3MjYgMC4wNzg1OTQ3IDAuMDQ5MDkyMDEgMC4wMzM2MDA0Nw0KIyMgICAgICAgICAgICAgICBTV0lSMg0KIyMgYnVpbHQgICAgMC4yMDAwMTMwNg0KIyMgY3JvcGxhbmQgMC4wNzMxNDE4Ng0KIyMgZmFsbG93ICAgMC4xOTE0MzAzMA0KIyMgb3BlbiAgICAgMC4yMTM0NjM0Mw0KIyMgd2F0ZXIgICAgMC4wMjcyMzM5OA0KDQpgYGANCg0KDQojIyMjIyBBaG9yYSB0cmF6YW1vcyBlbCBlc3BlY3RybyBtZWRpbyBkZSBlc3RhcyBjYXJhY3RlcmlzdGljYXMuDQoNCg0KYGBge3J9DQojIENyZWF0ZSBhIHZlY3RvciBvZiBjb2xvciBmb3IgdGhlIGxhbmQgY292ZXIgY2xhc3NlcyBmb3IgdXNlIGluIHBsb3R0aW5nDQpteWNvbG9yID0gYygnZGFya3JlZCcsICd5ZWxsb3cnLCAnYnVybHl3b29kJywgJ2N5YW4nLCAnYmx1ZScsICdncmVlbicsJ3BpbmsnKQ0KI3RyYW5zZm9ybSBtcyBmcm9tIGEgZGF0YS5mcmFtZSB0byBhIG1hdHJpeA0KbXMgPSBhcy5tYXRyaXgobXMpDQojIEZpcnN0IGNyZWF0ZSBhbiBlbXB0eSBwbG90DQpwbG90KDAsIHlsaW09YygwLDI1MDAwKSwgeGxpbSA9IGMoMSw3KSwgdHlwZT0nbicsIHhsYWI9IkJhbmRzIiwgeWxhYiA9ICJSZWZsZWN0YW5jZSIpDQojIGFkZCB0aGUgZGlmZmVyZW50IGNsYXNzZXMNCmZvciAoaSBpbiAxOm5yb3cobXMpKXsNCiAgbGluZXMobXNbaSxdLCB0eXBlID0gImwiLCBsd2QgPSAzLCBsdHkgPSAxLCBjb2wgPSBteWNvbG9yW2ldKQ0KfQ0KIyBUaXRsZQ0KdGl0bGUobWFpbj0iU3BlY3RyYWwgUHJvZmlsZSBmcm9tIExhbmRzYXQiLCBmb250Lm1haW4gPSAyKQ0KIyBMZWdlbmQNCmxlZ2VuZCgidG9wbGVmdCIsIHJvd25hbWVzKG1zKSwNCiAgICAgICBjZXg9MC44LCBjb2w9bXljb2xvciwgbHR5ID0gMSwgbHdkID0zLCBidHkgPSAibiIpDQpgYGANCg0KDQojIyMjIyBFbCBwZXJmaWwgZXNwZWN0cmFsIG11ZXN0cmEgKGRlcykgc2ltaWxpdHVkIGVuIGxhIHJlZmxlY3RhbmNpYSBkZSBkaWZlcmVudGVzIGNhcmFjdGVyaXN0aWNhcyBlbiBsYSBzdXBlcmZpY2llIGRlIGxhIHRpZXJyYSAobyBwb3IgZW5jaW1hIGRlIGVsbGEpLiAnQWd1YScgbXVlc3RyYSB1bmEgcmVmbGV4aW9uIHJlbGF0aXZhbWVudGUgYmFqYSBlbiB0b2RhcyBsYXMgbG9uZ2l0dWRlcyBkZSBvbmRhLCB5ICdjb25zdHJ1aWRvJywgJ2VuIGJhcmJlY2hvJyB5ICdhYmllcnRvJyB0aWVuZW4gdW5hIHJlZmxlY3RhbmNpYSByZWxhdGl2YW1lbnRlIGFsdGEgZW4gbGFzIGxvbmdpdHVkZXMgZGUgb25kYSBtYXMgbGFyZ2FzLg0KDQoNCiMgVElUVUxPOiBPUEVSQUNJT05FUyBNQVRFTUFUSUNBUyBCQVNJQ0FTICMNCg0KDQojIyMjIyBFbCAtIHJhc3Rlci0gcGFxdWV0ZSBhZG1pdGUgbXVjaGFzIG9wZXJhY2lvbmVzIG1hdGVtYXRpY2FzLiBMYXMgb3BlcmFjaW9uZXMgbWF0ZW1hdGljYXMgZ2VuZXJhbG1lbnRlIHNlIHJlYWxpemFuIHBvciBwaXhlbCAoY2VsZGEgZGUgY3VhZHJpY3VsYSkuIFByaW1lcm8gaGFyZW1vcyBhbGd1bmFzIG9wZXJhY2lvbmVzIGFyaXRtZXRpY2FzIGJhc2ljYXMgcGFyYSBjb21iaW5hciBiYW5kYXMuIEVuIGVsIHByaW1lciBlamVtcGxvLCBlc2NyaWJpbW9zIHVuYSBmdW5jaW9uIG1hdGVtYXRpY2EgcGVyc29uYWxpemFkYSBwYXJhIGNhbGN1bGFyIGVsIGluZGljZSBkZSB2ZWdldGFjaW9uIGRlIGRpZmVyZW5jaWEgbm9ybWFsaXphZGEgKE5EVkkpLg0KDQpgYGB7cn0NCg0KIyMjIHNvbG8gcHVlZG8gY2FyZ2FyIGxhcyBiYW5kYXMgZGUgbGEgMSBhIGxhIDcgcG9ycXVlIGxhIDggbm8gdGllbmUgbGEgbWlzbWEgZXh0ZW5zaW9uIGRlIGxhcyBkZW1hcw0KDQpyYXNsaXN0cDMgPSBwYXN0ZTAoJy4vZGF0YTIwMTUvTEMwOF9MMVRQXzAwODA1N18yMDE1MDEwNF8yMDE3MDQxNV8wMV9UMV9CJywgMTo3LCAiLnRpZiIpDQojI3Jhc2xpc3RwMz0gcHJhY3RpY2EgMw0KDQoNCmxhbmRzYXRwMyA9IHN0YWNrKHJhc2xpc3RwMykNCg0KcGxvdChsYW5kc2F0cDMpDQoNCg0KbGFuZHNhdFJHQnAzID0gbGFuZHNhdHAzW1tjKDQsMywyKV1dDQojIyBsYW5kc2F0UkdCcDMgPSBwcmFjdGljYSAzDQpwbG90KGxhbmRzYXRSR0JwMykNCg0KbGFuZHNhdEZDQ3AzID0gbGFuZHNhdHAzW1tjKDUsNCwzKV1dDQojIyBsYW5kc2F0RkNDcDMgPSBwcmFjdGljYSAzDQpwbG90KGxhbmRzYXRGQ0NwMykNCg0KDQoNCg0KYGBgDQoNCg0KIyMjIFRJVFVMTzogSU5ESUNFUyBERSBWRUdFVEFDSU9OICMjIw0KDQojIyMjIyBEZWZpbmFtb3MgdW5hIGZ1bmNpT24gZ2VuZXJhbCBwYXJhIHVuIEluZGljZSBiYXNhZG8gZW4gcmF6T24gKHZlZ2V0YWNpT24pLiBFbiBsYSBmdW5jaW9uIGEgY29udGludWFjaW9uLCAtaW1nLSBlcyB1biBvYmpldG8gUmFzdGVyICogZGUgbXVsdGlwbGVzIGNhcGFzIC1pLSB5IC1rLSBzb24gbG9zIGluZGljZXMgZGUgbGFzIGNhcGFzIChudW1lcm9zIGRlIGNhcGEpIHV0aWxpemFkb3MgcGFyYSBjYWxjdWxhciBlbCBpbmRpY2UgZGUgdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCiMjIHZpMjAxNT0gaW5kaWNlIGRlIHZlZ2V0YWNpb24gcGFyYSBsYSBpbWFnZW4gMjAxNQ0KDQp2aTIwMTUgPSBmdW5jdGlvbihpbWcsIGssIGkpIHsNCiAgDQogIGJrID0gaW1nIFtba11dDQogIGJpID0gaW1nIFtbaV1dDQogIHZpMjAxNT0oYmstYmkpLyhiaytiaSkNCiAgcmV0dXJuKHZpMjAxNSkNCn0NCg0KDQpgYGANCg0KYGBge3J9DQoNCiMjIHBhcmEgbGFuZHNhdCBOSVIgPSA1LCByZWQgPSA0DQojIyBuZHZpMjAxNT0gaW5kaWNlIGRlIHZlZ2V0YWNpb24gZGUgZGlyZWZlbmNpYSBub3JtYWxpemFkYSAoTkRWSSkgcGFyYSBsYSBpbWFnZW4gbGFuZHNhdCAyMDE1DQoNCm5kdmkyMDE1ID0gdmkyMDE1KGxhbmRzYXRwMywgNSwgNCkgDQpwbG90KG5kdmkyMDE1LCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDkpKSwgbWFpbj0gIkxhbmRzYXQgMjAxNSAtIE5WREkiKQ0KDQoNCk5EVkkxX3NpYmF0ZV8yMDE1ID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplTkRWSTFfc2liYXRlID0gZXh0ZW50KE5EVkkxX3NpYmF0ZV8yMDE1KQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpORFZJX3JlY29ydGVfMSA9IGNyb3AobmR2aTIwMTUsIGVORFZJMV9zaWJhdGUpDQpwbG90KE5EVklfcmVjb3J0ZV8xLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRWSSIpDQoNCg0KYGBgDQoNCg0KIyMjIyMgUHVlZGVzIHZlciBsYSB2YXJpYWNpb24gZW4gZWwgdmVyZG9yIGRlc2RlIGxhIHRyYW1hLg0KDQoNCiMjIyMjIFVuYSBmb3JtYSBhbHRlcm5hdGl2YSBkZSBsb2dyYXIgZXN0byBlcyBhc2kNCg0KDQpgYGB7cn0NCg0KdmkyXzIwMTUgPSBmdW5jdGlvbih4LCB5KSB7DQogICh4LXkpLyh4K3kpDQp9DQoNCg0KbmR2aTJfMjAxNSA9IG92ZXJsYXkobGFuZHNhdHAzW1s1XV0sIGxhbmRzYXRwM1tbNF1dLCBmdW4gPSB2aTJfMjAxNSkNCg0KcGxvdChuZHZpMl8yMDE1LCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRWSSB2MiIpDQoNCg0KTkRWSTJfc2liYXRlXzIwMTUgPSBzaGFwZWZpbGUoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvU0lCQVRFX1JVUkFML3J1cmFsLnNocCcpDQoNCmVORFZJMl9zaWJhdGUgPSBleHRlbnQoTkRWSTJfc2liYXRlXzIwMTUpDQojIGNyb3AgbGFuZHNhdCBieSB0aGUgZXh0ZW50DQoNCk5EVklfcmVjb3J0ZV8yID0gY3JvcChuZHZpMl8yMDE1LCBlTkRWSTJfc2liYXRlKQ0KcGxvdChORFZJX3JlY29ydGVfMiwgY29sPXJldih0ZXJyYWluLmNvbG9ycygxMCkpLCBtYWluID0gIkxhbmRzYXQgMjAxNSAtIE5EVkkiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgUHJlZ3VudGEgMSA6IEFkYXB0ZSBlbCBjb2RpZ28gcXVlIHNlIG11ZXN0cmEgYXJyaWJhIHBhcmEgY2FsY3VsYXIgbG9zIGluZGljZXMgcGFyYSBpZGVudGlmaWNhciBpKSBhZ3VhIHkgaWkpIGFjdW11bGFkb3MuIFN1Z2VyZW5jaWE6IFVzZSBlbCBkaWFncmFtYSBkZWwgcGVyZmlsIGVzcGVjdHJhbCBwYXJhIGVuY29udHJhciBsYXMgYmFuZGFzIHF1ZSB0aWVuZW4gcmVmbGVjdGFuY2lhIG1heGltYSB5IG1pbmltYSBwYXJhIGVzdGFzIGRvcyBjbGFzZXMuDQoNCg0KDQoNCmBgYHtyfQ0KIyMgcDEgZXMgcHJlZ3VudGEgMQ0KDQpuZHZpMjAxNV9wMSA9IHZpMjAxNShsYW5kc2F0cDMsIDMsIDYpIA0KDQpwbG90KG5kdmkyMDE1X3AxLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDEwKSksIG1haW49ICJMYW5kc2F0IDIwMTUgLSBORFdJIikNCg0KdmkyXzIwMTVfcDEgPSBmdW5jdGlvbih4LCB5KSB7DQogICh4LXkpLyh4K3kpDQp9DQoNCg0KbmR2aTJfMjAxNV9wMSA9IG92ZXJsYXkobGFuZHNhdHAzW1szXV0sIGxhbmRzYXRwM1tbNl1dLCBmdW4gPSB2aTJfMjAxNV9wMSkNCg0KcGxvdChuZHZpMl8yMDE1X3AxLCBjb2w9cmV2KHRvcG8uY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRXSSIpDQoNCg0KIyMjIFBBUkEgSU5ESUNFIERFIEFHVUEgREUgRElGRVJFTkNJQSBOT1JNQUxJWkFEQSAtIE5EV0kNCg0KTkRXSV9zaWJhdGUgPSBzaGFwZWZpbGUoJ0M6L1VzZXJzL0RhdmlkL0Rlc2t0b3AvU0lCQVRFX1JVUkFML3J1cmFsLnNocCcpDQoNCmVORFdJID0gZXh0ZW50KE5EV0lfc2liYXRlKQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpORFdJX3JlY29ydGUgPSBjcm9wKG5kdmkyXzIwMTVfcDEsIGVORFdJKQ0KcGxvdChORFdJX3JlY29ydGUsIGNvbD1yZXYodG9wby5jb2xvcnMoMTApKSwgbWFpbiA9ICJMYW5kc2F0IDIwMTUgLSBORFdJIikNCg0KDQpgYGANCg0KDQpgYGB7cn0NCg0KDQojIyMgUEFSQSBJTkRJQ0UgSU5DT1JQT1JBRE8gREUgRElGRVJFTkNJQSBOT1JNQUxJWkFEQSAtIE5EQkkNCg0KbmRiaTFfMjAxNV9wMSA9IG92ZXJsYXkobGFuZHNhdHAzW1s2XV0sIGxhbmRzYXRwM1tbNV1dLCBmdW4gPSB2aTJfMjAxNV9wMSkNCg0KcGxvdChuZGJpMV8yMDE1X3AxLCBjb2w9cmV2KGhlYXQuY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRCSSIpDQoNCg0KIyMgcmVjb3J0YWRvIGEgc2liYXRlDQoNCk5EQklfc2liYXRlID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplTkRCSSA9IGV4dGVudChOREJJX3NpYmF0ZSkNCiMgY3JvcCBsYW5kc2F0IGJ5IHRoZSBleHRlbnQNCg0KTkRCSV9yZWNvcnRlID0gY3JvcChuZGJpMV8yMDE1X3AxLCBlTkRCSSkNCnBsb3QoTkRCSV9yZWNvcnRlLCBjb2w9cmV2KGhlYXQuY29sb3JzKDEwKSksIG1haW4gPSAiTGFuZHNhdCAyMDE1IC0gTkRXSSIpDQoNCg0KYGBgDQoNCg0KDQojIyMgVElUVUxPOiBISVNUT0dSQU1BDQoNCiMjIyMjIFBvZGVtb3MgZXhwbG9yYXIgbGEgZGlzdHJpYnVjaW9uIGRlIHZhbG9yZXMgY29udGVuaWRvcyBlbiBudWVzdHJvIHJhc3RlciB1dGlsaXphbmRvIGxhIGZ1bmNpb24gLWhpc3QgKCktIHF1ZSBwcm9kdWNlIHVuIGhpc3RvZ3JhbWEuIExvcyBoaXN0b2dyYW1hcyBhIG1lbnVkbyBzb24gdXRpbGVzIHBhcmEgaWRlbnRpZmljYXIgdmFsb3JlcyBhdGlwaWNvcyB5IHZhbG9yZXMgZGUgZGF0b3MgaW5jb3JyZWN0b3MgZW4gbnVlc3Ryb3MgZGF0b3MgcmFzdGVyDQoNCg0KYGBge3J9DQoNCiMjIHZlciBoaXN0b2dyYW1hIGRlIGRhdG9zDQoNCmhpc3QoTkRWSV9yZWNvcnRlXzEsDQogICAgIG1haW49ICJEc2l0cmlidWNpb24gZGUgdmFsb3JlcyBkZWwgTkRWSSIsDQogICAgIHhsYWI9ICJORFZJIiwNCiAgICAgeWxhYj0gIkZyZWN1ZW5jaWEiLA0KICAgICBjb2w9IHRlcnJhaW4uY29sb3JzKDUwKSwNCiAgICAgeGxpbT0gYyAoLTAuMSwwLjcpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dD0gJ24nKQ0KDQpheGlzKHNpZGUgPSAxLCBhdD1zZXEoLTAuNSwxLDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLDAuMDUpKQ0KDQpgYGANCg0KDQojIyMjIyBOb3MgcmVmZXJpcmVtb3MgYSBlc3RlIGhpc3RvZ3JhbWEgcGFyYSBsYSBzaWd1aWVudGUgc3Vic2VjY2lvbiBzb2JyZSB1bWJyYWxpemFjaW9uLg0KDQoNCiMjIyMjIFByZWd1bnRhIDIgOiBIYWdhIGhpc3RvZ3JhbWFzIGRlIGxvcyB2YWxvcmVzIHF1ZSBsb3MgaW5kaWNlcyBkZSB2ZWdldGFjaW9uIGRlc2Fycm9sbGFyb24gZW4gbGEgcHJlZ3VudGEgMQ0KDQoNCmBgYHtyfQ0KDQojIyByZXNwdWVzdGEgYSBsYSBwcmVndW50YSAyOiB2ZXIgaGlzdG9ncmFtYSBkZSBkYXRvcw0KDQpoaXN0KE5EV0lfcmVjb3J0ZSwNCiAgICAgbWFpbj0gIkRzaXRyaWJ1Y2lvbiBkZSB2YWxvcmVzIGRlbCBORFdJIiwNCiAgICAgeGxhYj0gIk5EV0kiLA0KICAgICB5bGFiPSAiRnJlY3VlbmNpYSIsDQogICAgIGNvbD0gdG9wby5jb2xvcnMoNTApLA0KICAgICB4bGltPSBjICgtMC41LDAuMyksDQogICAgIGJyZWFrcyA9IDMwLA0KICAgICB4YXh0PSAnbicpDQoNCmF4aXMoc2lkZSA9IDEsIGF0PXNlcSgtMC41LDEsMC4wNSksIGxhYmVscyA9IHNlcSgtMC41LDEsMC4wNSkpDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyMgcmVzcHVlc3RhIGEgbGEgcHJlZ3VudGEgMjogdmVyIGhpc3RvZ3JhbWEgZGUgZGF0b3MNCg0KaGlzdChOREJJX3JlY29ydGUsDQogICAgIG1haW49ICJEc2l0cmlidWNpb24gZGUgdmFsb3JlcyBkZWwgTkRCSSIsDQogICAgIHhsYWI9ICJOREJJIiwNCiAgICAgeWxhYj0gIkZyZWN1ZW5jaWEiLA0KICAgICBjb2w9IGhlYXQuY29sb3JzKDUwKSwNCiAgICAgeGxpbT0gYyAoLTAuNSwwLjMpLA0KICAgICBicmVha3MgPSAzMCwNCiAgICAgeGF4dD0gJ24nKQ0KDQpheGlzKHNpZGUgPSAxLCBhdD1zZXEoLTAuNSwxLDAuMDUpLCBsYWJlbHMgPSBzZXEoLTAuNSwxLDAuMDUpKQ0KDQpgYGANCg0KDQojIyBUSVRVTE86IFVNQlJBTElaQUNJT04NCg0KDQojIyMjIyBQb2RlbW9zIGFwbGljYXIgcmVnbGFzIGJhc2ljYXMgcGFyYSBvYnRlbmVyIHVuYSBlc3RpbWFjaW9uIGRlIGxhIGV4dGVuc2lvbiBlc3BhY2lhbCBkZSBkaWZlcmVudGVzIGNhcmFjdGVyaXN0aWNhcyBkZSBsYSBzdXBlcmZpY2llIHRlcnJlc3RyZS4gVGVuZ2EgZW4gY3VlbnRhIHF1ZSBsb3MgdmFsb3JlcyBORFZJIGVzdGFuIGVzdGFuZGFyaXphZG9zIHkgdmFyaWFuIGVudHJlIC0xIHkgKzEuIExvcyB2YWxvcmVzIG1hcyBhbHRvcyBpbmRpY2FuIG1hcyBjb2JlcnR1cmEgdmVyZGUuDQoNCg0KIyMjIyMgTGFzIGNlbGRhcyBjb24gdmFsb3JlcyBkZSBORFZJIHN1cGVyaW9yZXMgYSAwLjQgc29uIGRlZmluaXRpdmFtZW50ZSB2ZWdldGFjaW9uLiBMYSBzaWd1aWVudGUgb3BlcmFjaW9uIGVubWFzY2FyYSB0b2RhcyBsYXMgY2VsZGFzIHF1ZSB0YWwgdmV6IG5vIHNlYW4gdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCg0KdmVnID0gcmVjbGFzc2lmeShORFZJX3JlY29ydGVfMSwgY2JpbmQoLUluZiwgMC40LCBOQSkpDQpwbG90KHZlZywgbWFpbiA9ICJWZWdldGFjaW9uIikNCg0KDQpgYGANCg0KDQojIyMjIyBWYW1vcyBhIG1hcGVhciBlbCBhcmVhIHF1ZSBjb3JyZXNwb25kZSBhbCBwaWNvIGVudHJlIDAuMjUgeSAwLjMgZW4gZWwgaGlzdG9ncmFtYSBORFZJLg0KDQoNCmBgYHtyfQ0KDQpsYW5kID0gcmVjbGFzc2lmeShORFZJX3JlY29ydGVfMSwgYygtSW5mLCAwLjI1LCBOQSwgMC4yNSwgMC4zLCAxLCAwLjMsIEluZiwgTkEpKQ0KcGxvdChsYW5kLCBtYWluID0gIiBRdWUgZXMgZXN0bz8iKQ0KDQoNCmBgYA0KDQoNCiMjIEVzdGFzIHB1ZWRlbiBzZXIgbGFzIGFyZWFzIGFiaWVydGFzLiBQdWVkZSB0cmF6YXIgLWxhbmQtIHNvYnJlIGVsIC1sYW5kc2F0RkNDLSByYXN0ZXIgb3JpZ2luYWwgcGFyYSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbg0KDQoNCmBgYHtyfQ0KDQpwbG90UkdCKGxhbmRzYXRjcm9wMjAxNSwgcj0xLCBiPTIsIGc9MywgYXhlcyA9IFRSVUUsIHN0cmV0Y2g9ImxpbiIsIG1haW4gPSAiTGFuZHNhdCBTaWJhdGUgY29tcG9zaWNpb24gZW4gZmFsc28gY29sb3IiKQ0KDQpwbG90KGxhbmQsIGFkZCA9IFRSVUUsIGxlZ2VuZD0gRkFMU0UpDQoNCg0KDQpgYGANCg0KDQojIyMjIyBUYW1iaWVuIHB1ZWRlIGNyZWFyIGNsYXNlcyBwYXJhIGRpZmVyZW50ZXMgY2FudGlkYWRlcyBkZSBwcmVzZW5jaWEgZGUgdmVnZXRhY2lvbi4NCg0KDQpgYGB7cn0NCnZlZ2MgPSByZWNsYXNzaWZ5KE5EVklfcmVjb3J0ZV8xLCBjKC1JbmYsMC4yNSwxLCAwLjI1LDAuMywyLCAwLjMsMC40LDMsIDAuNCwwLjUsNCwgMC41LEluZiwgNSkpDQpwbG90KHZlZ2MsIGNvbCA9IHJldih0ZXJyYWluLmNvbG9ycyg0KSksIG1haW4gPSAnVW1icmFsIGJhc2FkbyBlbiBORFZJJykNCg0KDQpgYGANCg0KDQojIyMjIyBQcmVndW50YSAzIDogRXMgcG9zaWJsZSBlbmNvbnRyYXIgYWd1YSB1c2FuZG8gZWwgdW1icmFsIGRlIE5EVkkgbyBjdWFscXVpZXIgb3RybyBpbmRpY2UNCg0KYGBge3J9DQphZ3VhID0gcmVjbGFzc2lmeShORFdJX3JlY29ydGUsIGNiaW5kKC1JbmYsIDAuMSwgTkEpKQ0KcGxvdChhZ3VhLCBtYWluID0gIkFndWEiLCBjb2w9IHRvcG8uY29sb3JzKDEwKSkNCg0KDQphZ3VhYyA9IHJlY2xhc3NpZnkoTkRXSV9yZWNvcnRlLCBjKC1JbmYsMC4wMjUsMSwgMC4wMjUsMC4wMywyLCAwLjAzLDAuMSwzLCAwLjEsMC4yLDQsIDAuMixJbmYsIDUpKQ0KcGxvdChhZ3VhYywgY29sID0gcmV2KHRvcG8uY29sb3JzKDEwKSksIG1haW4gPSAnVW1icmFsIGJhc2FkbyBlbiBORHdJJykNCg0KDQoNCmBgYA0KDQoNCiMjIFRJVFVMTzogQU5BTElTSVMgREUgQ09NUE9ORU5URVMgUFJJTkNJUEFMRVMNCg0KDQojIyMjIyBMb3MgZGF0b3MgbXVsdGllc3BlY3RyYWxlcyBhIHZlY2VzIHNlIHRyYW5zZm9ybWFuIHBhcmEgYXl1ZGFyIGEgcmVkdWNpciBsYSBkaW1lbnNpb25hbGlkYWQgeSBlbCBydWlkbyBlbiBsb3MgZGF0b3MuIExhIHRyYW5zZm9ybWFjaW9uIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGVzIHVuIG1ldG9kbyBnZW5lcmljbyBkZSByZWR1Y2Npb24gZGUgZGF0b3MgcXVlIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY3JlYXIgYWxndW5hcyBiYW5kYXMgbm8gY29ycmVsYWNpb25hZGFzIGEgcGFydGlyIGRlIHVuIGNvbmp1bnRvIG1hcyBncmFuZGUgZGUgYmFuZGFzIGNvcnJlbGFjaW9uYWRhcy4NCg0KIyMjIyMgUHVlZGUgY2FsY3VsYXIgZWwgbWlzbW8gbnVtZXJvIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIHF1ZSBlbCBudW1lcm8gZGUgYmFuZGFzIGRlIGVudHJhZGEuIEVsIHByaW1lciBjb21wb25lbnRlIHByaW5jaXBhbCAoUEMpIGV4cGxpY2EgZWwgbWF5b3IgcG9yY2VudGFqZSBkZSB2YXJpYW56YSB5IG90cmFzIFBDIGV4cGxpY2FuIGxhIHZhcmlhbnphIGFkaWNpb25hbCBlbiBvcmRlbiBkZWNyZWNpZW50ZS4NCg0KDQpgYGB7cn0NCg0Kc2V0LnNlZWQoMSkNCg0Kc3IgPSBzYW1wbGVSYW5kb20obGFuZHNhdHAzLCAxMDAwMCkNCnBsb3Qoc3JbLGMoNCw1KV0sIG1haW4gPSAiTklSIC0gUmVkIHBsb3QiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgRXN0byBzZSBjb25vY2UgY29tbyBkaWFncmFtYSBkZSB2ZWdldGFjaW9uIHkgbGluZWEgZGUgc3VlbG8gKGlndWFsIHF1ZSBlbCBkaWFncmFtYSBkZSBkaXNwZXJzaW9uIGVuIGxhIHNlY2Npb24gYW50ZXJpb3IpLg0KDQoNCmBgYHtyfQ0KDQpwY2EgPSBwcmNvbXAoc3IsIHNjYWxlID0gVFJVRSkNCnBjYQ0KDQpzY3JlZXBsb3QocGNhKQ0KDQoNCmBgYA0KDQoNCg0KYGBge3J9DQoNCnBjaSA9IHByZWRpY3QobGFuZHNhdHAzLCBwY2EsIGluZGV4ID0gMToyKQ0KDQpwbG90KHBjaVtbMV1dKQ0KDQojIyByZWNvcnRhZG8gYSBzaWJhdGUNCg0KcGNpX3NpYmF0ZSA9IHNoYXBlZmlsZSgnQzovVXNlcnMvRGF2aWQvRGVza3RvcC9TSUJBVEVfUlVSQUwvcnVyYWwuc2hwJykNCg0KZXBjaSA9IGV4dGVudChwY2lfc2liYXRlKQ0KIyBjcm9wIGxhbmRzYXQgYnkgdGhlIGV4dGVudA0KDQpwY2lfcmVjb3J0ZSA9IGNyb3AocGNpLCBlcGNpKQ0KcGxvdChwY2lfcmVjb3J0ZSwgY29sPXJldih0ZXJyYWluLmNvbG9ycygyMCkpLCBtYWluID0gInBjaSBTaWJhdGUiKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgRWwgcHJpbWVyIGNvbXBvbmVudGUgcHJpbmNpcGFsIHJlc2FsdGEgbG9zIGxpbWl0ZXMgZW50cmUgbGFzIGNsYXNlcyBkZSB1c28gZGUgbGEgdGllcnJhIG8gbG9zIGRldGFsbGVzIGVzcGFjaWFsZXMsIHF1ZSBlcyBsYSBpbmZvcm1hY2lvbiBtYXMgY29tdW4gZW50cmUgdG9kYXMgbGFzIGxvbmdpdHVkZXMgZGUgb25kYS4gRXMgZGlmaWNpbCBlbnRlbmRlciBsbyBxdWUgZGVzdGFjYSBlbCBzZWd1bmRvIGNvbXBvbmVudGUgcHJpbmNpcGFsLiBWYW1vcyBhIGludGVudGFyIHVtYnJhbCBkZSBudWV2bzoNCg0KDQpgYGB7cn0NCg0KbGFuZHNhdEZDQzIwMTUgPSBzdGFjayhiNSwgYjQsIGIzKQ0KIyBwbG90UkdCKGxhbmRzYXRGQ0MyMDE1LCBheGVzPVRSVUUsIHN0cmV0Y2g9ImxpbiIsIG1haW49IkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlIikNCg0KDQojIyByZWNvcnRhZG8gYSBzaWJhdGUNCg0KcGMyID0gc2hhcGVmaWxlKCdDOi9Vc2Vycy9EYXZpZC9EZXNrdG9wL1NJQkFURV9SVVJBTC9ydXJhbC5zaHAnKQ0KDQplcGMyID0gZXh0ZW50KHBjMikNCiMgY3JvcCBsYW5kc2F0IGJ5IHRoZSBleHRlbnQNCg0KcGMyX3JlYz0gY3JvcChsYW5kc2F0RkNDMjAxNSwgZXBjMikNCiMgcGxvdChwYzJfcmVjLCBjb2w9cmV2KHRlcnJhaW4uY29sb3JzKDIwKSksIG1haW4gPSAicGNpIFNpYmF0ZSIpDQoNCg0KDQoNCnBjMiA9IHJlY2xhc3NpZnkocGNpX3JlY29ydGVbWzJdXSwgYygtSW5mLDAsMSwwLEluZixOQSkpDQpwYXIobWZyb3cgPSBjKDEsMikpDQpwbG90UkdCKHBjMl9yZWMsIHIgPSAxLCBnID0gMiwgYiA9IDMsIGF4ZXMgPSBUUlVFLCBzdHJldGNoID0gImxpbiIsIG1haW4gPSAiTGFuZHNhdCBGYWxzZSBDb2xvciBDb21wb3NpdGUiKQ0KcGxvdFJHQihwYzJfcmVjLCByID0gMSwgZyA9IDIsIGIgPSAzLCBheGVzID0gVFJVRSwgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIkxhbmRzYXQgRmFsc2UgQ29sb3IgQ29tcG9zaXRlIikNCnBsb3QocGMyLCBsZWdlbmQgPSBGQUxTRSwgYWRkID0gVFJVRSkNCg0KDQoNCg0KYGBgDQoNCg0KIyMjIyMgUGFyYSBvYnRlbmVyIG1hcyBpbmZvcm1hY2lvbiBhY2VyY2EgZGUgbGEgaW5mb3JtYWNpb24gY29udGVuaWRhIGVuIGxhcyBwYXJjZWxhcyBkZSB2ZWdldGFjaW9uIHkgbGluZWFzIGRlIHN1ZWxvLCBsZWEgZXN0ZSBkb2N1bWVudG8gZGUgLUdpdGVsc29uIGV0IGFsLSAuIFVuYSBleHRlbnNpb24gZGUgUENBIGVuIGxhIHRlbGVkZXRlY2Npb24gc2UgY29ub2NlIGNvbW8gVHJhbnNmb3JtYWNpb24gLVRhc3NlbGVkLWNhcC0gLg0KDQpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ3RybCtBbHQrSSouDQoNCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLg0KDQpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuDQo=