Resumen

La radiación solar resulta de gran interés agronómico debido a que es el factor que más influye en la fotosíntesis de las plantas, para obtener altas tasas de fotosíntesis se encuentra necesario maximizar la intercepción de la luz encontrando lugares idóneos de radiación solar, su máxima intercepción por parte de las plantas se observa en una mayor cantidad de materia seca, sobre todo en cultivos extensos y un crecimiento optimo en todas las etapas de crecimiento de la planta. La presente evalúa 3 métodos de interpolación espacial en R usando datos de radiación solar suministrados por World Clim donde se destacan metodos como kriging ordinal, ponderación de la distancia inversa (IDW) y poligonos de thieseen aplicados al departamento de Arauca en Colombia; Finalmente encontrara una muestra de los resultados y la interpretación de ellos para denotar la necesidad de radiación solar para los cultivos mas destacados del departamento.

Palabras clave: Radiación, distribución espacial, interpolación, kriging, IDW, poligonos de Thiessen.

1. Introducción

La energía que determina la dinámica de los procesos atmosféricos y climáticos emitida por el sol es conocida como radiación solar, la energía producida por el sol es radiación electromagnética proporcionada por reacciones de hidrogeno en el núcleo del sol por fusión nuclear y luego emitidas por la superficie solar, la radiación solar es esencial para los procesos productivos de un cultivo, sin embargo la exposición excesiva a esta fuente de energía resulta en estrés térmico que afecta notoriamente su desarrollo, afectando la planta desde su periodo vegetativo y de crecimiento, hasta su estado de cosecha;El sol emite energía en forma de radiación de onda corta principalmente en la banda del ultravioleta visible y el infrarrojo cercano, con longitudes de onda entre 0,2 y 3,0 micrómetros, el espectro electromagnético de este no tiene definidos limites superiores ni inferiores, y la energía de una fracción de radiación (fotón) es inversamente proporcional a su longitud de onda, por lo que a menor longitud de onda mayor contenido energético .

Para determinar que datos de radiación solar tenemos en Arauca es menester realizar una interpolación debido a que tomaremos unos datos distribuidos espacialmente en formato raster; Los objetos con una distribución espacial tienden a tener características similares entre más cerca se encuentren, es decir, sí tenemos un valor de radiación solar en un punto espacial de Arauca podemos proveer con un alto nivel de confianza, que este valor es similar o sigue una tendencia en un punto cercano al punto de muestra.

La presente evalua 3 métodos de interpolación espacial en R, usando datos de radiación solar suministrados por World Clim donde se destacan metodos como kriging ordinal, ponderación de la distancia inversa (IDW) y poligonos de thieseen aplicados al departamento de Arauca en Colombia; Finalmente encontrara una interpretación de los resultados y la interpretación de ellos para denotar la necesidad de radiación solar para los cultivos mas destacados del departamento.

2. Datos y metodos

2.1 Zona de estudio

En el norte de los llanos orientales, entre la cordillera oriental y la zona limítrofe con Venezuela se encuentra ubicado el departamento de Arauca, se localiza entre los 06°, 02’ 40” y 07° 06’ 13” de latitud norte y los 69° 25’ 54” y 72° 22’ 23” de longitud oeste, en el extremo norte de la Orinoquía colombiana, territorio denotado por la sierra nevada del cocuy y atravesado por los ríos meta, Arauca y Casanare. El epicentro agrícola, ganadero y petrolero del oriente colombiano comprende sistemas de selva, sabana y afluentes; Comprende los municipios de Tame, Arauquita, Fortul, Puerto Rondón, Saravena, Cravo Norte y Arauca como capital.Esta tierra ubicada en el extremo nororiental de la Orinoquia colombiana, posee un relieve mixto donde encontramos zonas montañosas las cuales no superan los 5000 m.s.n.m, sabanas que se levantan sobre los 1000 m.s.n.m y una temperatura entre los 28° y 30°.

Arauca posee tres conjuntos morfológicos: la cordillera oriental que cubre una quinta parte del departamento y comprende elevaciones de 500 hasta 5380 m.s.n.m; pie de monte cubierta de sabana y áreas ampliamente vegetativas, bosque ecuatorial y conformada por conos, abanicos, aluviales, terrazas de relieve plano e inclinado y la llanura aluvial; La formación orográfica mas destacada es la sierra nevada del cocuy la cual cuenta con accidentes geográficos como la piedra, el diamante, los altos nievecitas, osos y las cuchillas de Altamira y el salitre. Debido a su ubicación latitudinal, Arauca presenta un clima ecuatorial lluvioso, con influencia de los vientos alisios y la cordillera oriental; Presentando dos periodos climáticos: Entre abril y noviembre el clima predominante es lluvioso y entre noviembre y marzo predomina un clima seco sin llegar a alcanzar los 35°C.

library(sf)
library(cartography)

opar <- par(mar = c(0,0,1.2,0))

par(bg="grey75")
# plot municipalities
plot(st_geometry(nbi_munic_2), col = "#e4e9de", border = "red", 
     bg = "grey75", lwd = 0.5)

# plot labels
labelLayer(
  x = nbi_munic_2, 
  txt = "MUNICIPIO", 
  col= "yellow", 
  cex = 0.4, 
  font = 4,
  halo = TRUE, 
  bg = "grey25", 
  r = 0.1, 
  overlap = FALSE, 
  show.lines = FALSE
)
# map layout
layoutLayer(
  title = "Departamento de Arauca con sus respectivos municipios", 
  author = "Daniel Cortés", 
  frame = TRUE,
  north = TRUE, 
  tabtitle = TRUE, 
  theme = "taupe.pal"
) 

2.2 Datos

En la presente se tomaran datos de radiación solar suministrados por WorldClim, usaremos la versión lanzada en enero del 2020 donde se encontraran 19 variables bioclimáticas a 4 resoluciones espaciales, cada descarga contiene un archivo zip donde se encontraran 12 archivos GeoTiff, cada archivo corresponde a un mes del año; Para este informe se usaron datos de radiación solar medidos en kJ m -2 día -1 ,a una resolución espacial de 5 minutos y se tomara un archivo Geotiff que contiene el promedio de radiación solar global para el mes de diciembre.

La medición de la radiación solar es de gran valor para un amplio rango de aplicaciones, en las áreas de ingeniería, arquitectura, agricultura, ganadería, salud humana y meteorología dentro de las cuales se destaca fundamentalmente el uso como fuente de energía alternativa. La luz solar es esencial para los mecanismos de crecimiento de las plantas, pero la exposición excesiva a esta fuente de energía resulta en estrés térmico que afecta su desarrollo, crecimiento y periodo productivo de la planta, especialmente en periodos de siembra y en plantas maduras durante todo el periodo vegetativo, afectando negativamente la etapa de cosecha del producto.

Arauca al ser una región caracterizada por su potencial productivo de plátano y tubérculos, se encuentran influenciados estos sistemas de producción por factores bióticos y abióticos, las altas y bajas temperaturas y la radiación solar son factores que afectan considerablemente la producción, para el caso del plátano, este es sembrado en condiciones muy variadas de radiación solar, sin embargo la falta de luz no interrumpe la emisión y desarrollo de las hojas, pero los limbos quedan blanquecidos debido a la ausencia de síntesis de clorofila, como consecuencia las vainas foliares y pseudotallos se alargan demasiado, la radiación también influye directamente en el proceso de maduración y composición química de los frutos de plátano.

A continuacion trataremos los datos que usaremos para interpolar: Iniciaremos limpiando la memoria

#rm(list=ls())

Cargaremos las librerias que necesitaremos para tratar los datos y interpolar

library(knitr)
library(rgdal)
library(raster)
library(sf)
library(tidyverse)
library(tmap)
library(gstat)
library(sp)
library(spatstat.data)
library(nlme)
library(rpart)
library(spatstat)

Leemos el conjunto de datos de radiación solar en formato ráster

## Leyendo el conjunto de datos de radiación solar en formato raster
carborg <- raster("C:\\Users\\johnedisoncortes\\Documents\\Inf3GMB\\rad.tif")

Carborg sera nuestros datos de radiación solar

## Qué adjuntamos en la variable carborg?
carborg
class      : RasterLayer 
dimensions : 2160, 4320, 9331200  (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333  (x, y)
extent     : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs 
source     : C:/Users/johnedisoncortes/Documents/Inf3GMB/rad.tif 
names      : rad 
values     : 0, 45397  (min, max)

La variable “aoi” contiene el shapefile de nuestra área de interés, para este caso el departamento de Arauca.

(aoi <- shapefile("C:\\Users\\johnedisoncortes\\Documents\\Inf2GMB\\MGN2017_81_ARAUCA\\81_ARAUCA\\ADMINISTRATIVO\\MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 7 
extent      : -72.36662, -69.42756, 6.036228, 7.104381  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR,                           MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO, DPTO_CNMBR,    Shape_Leng,      Shape_Area 
min values  :         81,      81001,     ARAUCA,                                 1959,  945.13540708,      2017,     ARAUCA, 1.29412603421, 0.0772141267598 
max values  :         81,      81794,       TAME, Decreto Nal 677 de Abril 13 de  1987, 5787.94213047,      2017,     ARAUCA, 4.66801606458,  0.471626116664 

Datos de radiación solar para nuestra area de interes

carborg.crop <- raster::crop(carborg, extent(aoi))

Enmascaramos nuestra capa raster para nuestra area de interes

carborg.mask <- mask(x = carborg.crop, mask = aoi)
carborg.mask 
class      : RasterLayer 
dimensions : 13, 35, 455  (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333  (x, y)
extent     : -72.33333, -69.41667, 6, 7.083333  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs 
source     : memory
names      : rad 
values     : 14780, 16991  (min, max)

Trazamos la capa raster

plot(carborg.mask, main=  "wordclim radiación solar para el departamento de Arauca [kj m^-2 dia^-1]")
plot(aoi, add=TRUE)

Plotearemos un mapa para obtener una mejor visualización de nuestros datos:

library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("darkblue", "blue", "yellow", "orange", "red"), values(carborg.mask),
  na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(carborg.mask, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(carborg.mask),
    title = "wordclim sobre radiación solar para el departamento de Arauca [kj m^-2 dia^-1]")
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definition

Con la funcion rasterToPoints de la libreria raster podemos convertir el raster a puntos

carborg.points <- rasterToPoints(carborg.mask, spatial = TRUE)
carborg.points
class       : SpatialPointsDataFrame 
features    : 278 
extent      : -72.29167, -69.45833, 6.041667, 7.041667  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :   rad 
min values  : 14780 
max values  : 16991 
str(carborg.points)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 278 obs. of  1 variable:
  .. ..$ rad: num [1:278] 14933 15421 16890 16854 16833 ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:278, 1:2] -71.8 -71.6 -70.9 -70.8 -70.7 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "x" "y"
  ..@ bbox       : num [1:2, 1:2] -72.29 6.04 -69.46 7.04
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +no_defs"

Ploteamos nuestra conversión de raster a puntos

plot(carborg.mask, main= "wordclim radiación solar para el departamento de Arauca [kj m^-2 dia^-1]")
plot(aoi, add=TRUE)
points(carborg.points$x, carborg.points$y, col = "blue", cex = 0.6)

Escribamos el objeto espacial de puntos en un archivo de disco. Solo para ahorrar tiempo y trabajo en caso de que algo salga mal.

Usaremos la biblioteca rgdal como se ilustra

geojsonio::geojson_write(carborg.points, file = "./Inf3GMB")
Success! File is at ./Inf3GMB.geojson
<geojson-file>
  Path:       ./Inf3GMB
  From class: SpatialPointsDataFrame

Leamos los puntos de precipitación. Consulte la documentación de geojsonio para comprender qué parámetros deben pasarse a la función geojson_read

carborg.points <- geojsonio::geojson_read("./Inf3GMB.geojson", what="sp")
carborg.points
class       : SpatialPointsDataFrame 
features    : 278 
extent      : -72.29167, -69.45833, 6.041667, 7.041667  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :   rad 
min values  : 14780 
max values  : 16991 

Preparación adicional de nuestros datos del area de interes (aoi)

(aoi <- shapefile("C:\\Users\\johnedisoncortes\\Documents\\Inf2GMB\\MGN2017_81_ARAUCA\\81_ARAUCA\\ADMINISTRATIVO\\MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 7 
extent      : -72.36662, -69.42756, 6.036228, 7.104381  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR,                           MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO, DPTO_CNMBR,    Shape_Leng,      Shape_Area 
min values  :         81,      81001,     ARAUCA,                                 1959,  945.13540708,      2017,     ARAUCA, 1.29412603421, 0.0772141267598 
max values  :         81,      81794,       TAME, Decreto Nal 677 de Abril 13 de  1987, 5787.94213047,      2017,     ARAUCA, 4.66801606458,  0.471626116664 

Necesitamos convertir nuestros datos en una caracteristica espacial

arauca_sf <-  sf::st_as_sf(aoi)

Disolveremos los limites internos

(border_sf <-
  arauca_sf %>%
  summarise(area = sum(MPIO_NAREA)))
Simple feature collection with 1 feature and 1 field
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -72.36662 ymin: 6.036228 xmax: -69.42756 ymax: 7.104381
geographic CRS: WGS 84
      area                       geometry
1 23851.41 POLYGON ((-69.76161 6.53034...

Convertimos nuestra caracteristica espacial en datos espaciales

(border <- as(border_sf, 'Spatial')) 
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : -72.36662, -69.42756, 6.036228, 7.104381  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :           area 
value       : 23851.40798475 
(arauca.sf <- st_as_sf(aoi) %>% mutate(MUNIC = MPIO_CNMBR, CODIGO = MPIO_CCDGO) %>% select(MUNIC, CODIGO))
Simple feature collection with 7 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -72.36662 ymin: 6.036228 xmax: -69.42756 ymax: 7.104381
geographic CRS: WGS 84
           MUNIC CODIGO                       geometry
1         ARAUCA  81001 POLYGON ((-70.68038 7.09393...
2 PUERTO RONDÓN  81591 POLYGON ((-70.87879 6.62133...
3    CRAVO NORTE  81220 POLYGON ((-70.40276 6.64639...
4      ARAUQUITA  81065 POLYGON ((-71.58441 7.04298...
5         FORTUL  81300 POLYGON ((-71.54473 6.75924...
6       SARAVENA  81736 POLYGON ((-71.76224 7.06602...
7           TAME  81794 POLYGON ((-71.73216 6.70303...

Realizamos la conversión

# conversion
p.sf <- st_as_sf(carborg.points)

Realizaremos una intersección de poligonos con puntos, conservando la información de ambos en un mismo lugar.

(carborg.sf = st_intersection(arauca.sf, p.sf))
although coordinates are longitude/latitude, st_intersection assumes that they are planar
attribute variables are assumed to be spatially constant throughout all geometries
Simple feature collection with 278 features and 3 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -72.29167 ymin: 6.041667 xmax: -69.45833 ymax: 7.041667
geographic CRS: WGS 84
First 10 features:
        MUNIC CODIGO   rad                   geometry
6    SARAVENA  81736 14933 POINT (-71.79167 7.041667)
4   ARAUQUITA  81065 15421   POINT (-71.625 7.041667)
1      ARAUCA  81001 16890   POINT (-70.875 7.041667)
1.1    ARAUCA  81001 16854 POINT (-70.79167 7.041667)
1.2    ARAUCA  81001 16833 POINT (-70.70833 7.041667)
1.3    ARAUCA  81001 16876   POINT (-70.625 7.041667)
1.4    ARAUCA  81001 16893 POINT (-70.54167 7.041667)
6.1  SARAVENA  81736 16486 POINT (-71.95833 6.958333)
6.2  SARAVENA  81736 15884   POINT (-71.875 6.958333)
6.3  SARAVENA  81736 14996 POINT (-71.79167 6.958333)

Realizaremos dos reproyecciones, una de nuestros datos y otra de nuestro sitio de interes.

p.sf.magna <- st_transform(carborg.sf, crs=3116)
arauca.sf.magna <- st_transform(arauca.sf, crs=3116)
(carborg2 <- as(p.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definitionDiscarded datum Marco Geocentrico Nacional de Referencia in CRS definition
class       : SpatialPointsDataFrame 
features    : 278 
extent      : 1197609, 1511834, 1161866, 1271914  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
variables   : 3
names       :  MUNIC, CODIGO,   rad 
min values  : ARAUCA,  81001, 14780 
max values  :   TAME,  81794, 16991 
shapefile(carborg2, filename='C:\\Users\\johnedisoncortes\\Documents\\Inf3GMB\\carborg2.shp', layer= "carborg2", overwrite=TRUE)
carborg2
class       : SpatialPointsDataFrame 
features    : 278 
extent      : 1197609, 1511834, 1161866, 1271914  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
variables   : 3
names       :  MUNIC, CODIGO,   rad 
min values  : ARAUCA,  81001, 14780 
max values  :   TAME,  81794, 16991 
(arauca2 <- as(arauca.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definitionDiscarded datum Marco Geocentrico Nacional de Referencia in CRS definition
class       : SpatialPolygonsDataFrame 
features    : 7 
extent      : 1189337, 1515269, 1161263, 1278742  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
variables   : 2
names       :  MUNIC, CODIGO 
min values  : ARAUCA,  81001 
max values  :   TAME,  81794 
shapefile(arauca2, filename='C:\\Users\\johnedisoncortes\\Documents\\Inf3GMB\\arauca2.shp', layer= "arauca2", overwrite=TRUE)

Reemplazamos la extensión del límite del punto con la de Arauca

carborg2@bbox <- arauca2@bbox

Graficamos nuestra area de interes con los datos espaciales de radiación solar.

tm_shape(arauca2) + tm_polygons() +
  tm_shape(carborg2) +
  tm_dots(col="rad", palette = "RdBu", midpoint = 3.0,
             title="Muestreo de radiación solar [kj m^-2 dia^-1]", size=0.2) +
  tm_text("rad", just="center", xmod=.6, size = 0.5) +
  tm_legend(legend.outside=TRUE)
CRS object has comment, which is lost in output

2.3 Metodos

IDW

La ponderación de distancia inversa (IDW) es un método determinístico de interpolado en donde se da por hecho que la variable representada cartográficamente tiende a disminuir su influencia a mayor distancia desde la ubicación del punto de muestra, esto se logra a través de una combinación ponderada linealmente de un conjunto de puntos de muestreo, que generalmente suelen aplicarse a datos muy variables.

La potencia es la variable con la que podemos controlar la importancia de los puntos conocidos sobre los valores que queremos interpolar en función de su distancia desde su punto de salida.Es la variable que determina la tasa exponencial de caída de la influencia de los puntos vecinos cuanto mas lejos se encuentran del nodo de la cuadricula. Los valores asignados oscilan entre 1 y 10, especificando un valor más bajo dará mas importancia a los puntos que están mas lejos, obteniendo superficies mas suaves, por otro lado si asignamos una potencia alta se pone mas énfasis en los puntos mas cercanos por lo que el resultado será mas detallado y menos suave.

Krigin

Es un procedimiento geoestadístico que trabaja a partir de un conjunto de puntos dispersos para generar una superficie estimada, su principal diferencia de los otros métodos de interpolación es que se encuentra necesaria una investigación interactiva del comportamiento espacial de la variable representada. Interpolar con kriging presupone que la distancia entre los puntos de muestra refleja correlación espacial que se utiliza para explicar la variación en la superficie, al aplicar kriging ajustamos una función matemática a una cantidad especifica de puntos dentro de un radio determinado para conocer el valor de salida para cada ubicación.

Kriging esta basado en modelos estadísticos de autocorrelación, es decir, las relaciones estadísticas entre los puntos medidos, gracias a esto, podemos proporcionar alguna medida de certeza o precisión a la hora de realizar una estimación de un valor. Aplicando este método generamos una serie de procesos de análisis estadístico exploratorio, modelos de variogramas, creaciones de superficie, entre otros. Este método es adecuado cuando se sabe que hay una influencia de la distancia correlacionada espacialmente con los datos.

Poligonos de Thiessen

Los polígonos de Thiessen permiten establecer relaciones matemáticas entre elementos generando zonas de influencia con unas premisas matemáticas específicas, la relación parte de una nube de puntos sobe los que se generan una serie de polígonos, estos puntos se unen entre si y se proyectan mediatrices entre los segmentos de unión, siendo dichas mediatrices, los lados de los polígonos resultantes. La principal regla que se establece es que los lados de los polígonos generados, son equidistantes a los puntos vecinos y tratan de encontrar la menor distancia posible. Los lados de cada polígono se encuentran a la misma distancia de un punto que otro

3.Resultados

IDW

La función IDW se encuentra disponible en Spatstat como en Gstat, es importante mencionar que la función Dirichlet usada en esta interpolación (como la mayoría de las funciones del paquete spatstat) requiere un formato ppp, de allí la sintaxis as.ppp

La salida IDW es un raster. Requerimos crear una cuadricula ráster vacía, para luego interpolar los valores de radiación solar en cada celda de la cuadricula sin muestrear.

Utilizaremos un valor de potencia IDW de 2 (idp=2)

# Crearemos una cuadricula vacía donde n será el numero total de celdas
grd              <- as.data.frame(spsample(carborg2, "regular", n=100000))
# Necesita averiguar cuál es el tamaño esperado del grd de salida
names(grd)       <- c("X", "Y")
coordinates(grd) <- c("X", "Y")
gridded(grd)     <- TRUE  # Create SpatialPixel object
fullgrid(grd)    <- TRUE  # Create SpatialGrid object

# Agregamos la información de proyección de C a la cuadrícula vacía
proj4string(grd) <- proj4string(carborg2)
CRS object has comment, which is lost in outputDiscarded datum Unknown based on GRS80 ellipsoid in CRS definition
# Interpolamos las celdas de la cuadrícula usando un valor de potencia de 2 (idp = 2.0)
P.idw <- gstat::idw(rad ~ 1, carborg2, newdata=grd, idp=2.0)
CRS object has comment, which is lost in outputCRS object has comment, which is lost in output
[inverse distance weighted interpolation]
CRS object has comment, which is lost in outputDiscarded datum Unknown based on GRS80 ellipsoid in CRS definition
# Convertimos a raster y limitamos nuestra area de estudio
r       <- raster(P.idw)
r
class      : RasterLayer 
dimensions : 190, 527, 100130  (nrow, ncol, ncell)
resolution : 618.7907, 618.7907  (x, y)
extent     : 1189078, 1515181, 1161195, 1278765  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 14783.96, 16987.71  (min, max)
arauca2
class       : SpatialPolygonsDataFrame 
features    : 7 
extent      : 1189337, 1515269, 1161263, 1278742  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
variables   : 2
names       :  MUNIC, CODIGO 
min values  : ARAUCA,  81001 
max values  :   TAME,  81794 
r.m   <- raster::mask(r, arauca2)
r.m
class      : RasterLayer 
dimensions : 190, 527, 100130  (nrow, ncol, ncell)
resolution : 618.7907, 618.7907  (x, y)
extent     : 1189078, 1515181, 1161195, 1278765  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 14783.96, 16987.71  (min, max)
# Plot
tm_shape(r.m) + 
  tm_raster(n=10,palette = "OrRd", auto.palette.mapping = FALSE,
            title="IDW de radiación solar prevista en [kj m^-2 dia^-1] ") + 
  tm_shape(carborg2) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

Una mejor visualización de nuestro campo de interpolado

library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("darkblue", "blue", "yellow", "orange", "red"), values(carborg.mask),
  na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(r.m, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(r.m),
    title = "IDW: Radiacíon solar interpolada en arauca medida en [kj m^-2 dia^-1] ")
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definition

Ajustamos la interpolación

La elección de la función de potencia puede ser subjetiva. Para ajustar la elección del parámetro de potencia, puede realizar una rutina de validación de dejar uno fuera para medir el error en los valores interpolados.

carborg2
class       : SpatialPointsDataFrame 
features    : 278 
extent      : 1189337, 1515269, 1161263, 1278742  (xmin, xmax, ymin, ymax)
crs         : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
variables   : 3
names       :  MUNIC, CODIGO,   rad 
min values  : ARAUCA,  81001, 14780 
max values  :   TAME,  81794, 16991 
c <- carborg2
IDW.out <- vector(length = length(c))
for (i in 1:length(c)) {
  IDW.out[i] <- gstat::idw(rad ~ 1, c[-i,], c[i,], idp=2.0)$var1.pred
}

Graficamos la diferencia entre los datos estimados y los datos observados

# Graficamos la diferencia
OP <- par(pty="s", mar=c(4,3,0,0))
  plot(IDW.out ~ c$rad, asp=1, xlab="Observed", ylab="Predicted", pch=16,
       col=rgb(0,0,0,0.5))
  abline(lm(IDW.out ~ c$rad), col="red", lw=2,lty=2)
  abline(0,1)

par(OP)

El error cuadrático medio (RMSE) se puede calcular a partir de IDW.out de la siguiente manera:

# Computar RMSE
sqrt( sum((IDW.out - c$rad)^2) / length(c))
[1] 251.2121

Validación cruzada

Además de generar una superficie interpolada, puede crear un mapa de intervalo de confianza del 95% del modelo de interpolación. Aquí crearemos un mapa de IC del 95% a partir de una interpolación IDW que usa un parámetro de potencia de 2 (idp = 2.0). Encontrará en el codigo aplicado los metodos usados para realizar el proceso de interpolado.

# Implementamos una tecnica de navaja
# Estimando un intervalo de confianza en cada punto no muestreado

# Creamos la superficie de interpolado
img <- gstat::idw(rad~1, c, newdata=grd, idp=2.0)
n   <- length(c)
Zi  <- matrix(nrow = length(img$var1.pred), ncol = n)

# Removemos un punto para luego interpolar 
st <- stack()
for (i in 1:n){
  Z1 <- gstat::idw(rad~1, c[-i,], newdata=grd, idp=2.0)
  st <- addLayer(st,raster(Z1,layer=1))
  # calculamos la pseudovariable Z at j
  Zi[,i] <- n * img$var1.pred - (n-1) * Z1$var1.pred
}

# Estimador tipo navaja para el parametro z en la locación j
Zj <- as.matrix(apply(Zi, 1, sum, na.rm=T) / n )

# Calculamos (Zi* - Zj)^2
c1 <- apply(Zi,2,'-',Zj)            # Compute the difference
c1 <- apply(c1^2, 1, sum, na.rm=T ) # Sum the square of the difference

# Calculamos el intervalo de confianza
CI <- sqrt( 1/(n*(n-1)) * c1)

# Creamos (CI / Interpolación de la variable) raster
img.sig   <- img
img.sig$v <- CI /img$var1.pred 

Limitamos el raster de confianza a nuestra area de estudio

# Limitamos el raster de confianza a nuestra area de estudio
r <- raster(img.sig, layer="v")
r.m <- raster::mask(r, arauca2)

# Ploteamos nuestro mapa
tm_shape(r.m) + tm_raster(n=7,title="IDW\n95% confidence interval \n(in mm)") +
  tm_shape(c) + tm_dots(size=0.2) +
  
  tm_legend(legend.outside=TRUE)

Polinomio de primer orden

Este metodo sera incluido debido a que lo necesitaremos para generar nuestro interpolado por el metodo kriging.

# Define the 1st order polynomial equation
f.1 <- as.formula(rad ~ X + Y) 
 
# Add X and Y to P
c$X <- coordinates(c)[,1]
c$Y <- coordinates(c)[,2]

# Run the regression model
lm.1 <- lm( f.1, data=c)

# Use the regression model output to interpolate the surface
dat.1st <- SpatialGridDataFrame(grd, data.frame(var1.pred = predict(lm.1, newdata=grd))) 
# Clip the interpolated raster to Texas
r   <- raster(dat.1st)
r.m <- raster::mask(r, arauca2)

# Plot the map
tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE, 
            title="1st order polinomial fir \nPredicted precipitation \n(in mm)") +
  tm_shape(c) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

Ajuste polinomial de segundo orden

Para ajustar un modelo polinomial de segundo orden de la forma radsun = intersección + aX + bY + dX2 + eY2 + fXY

# Define the 2nd order polynomial equation
f.2 <- as.formula(rad ~ X + Y + I(X*X)+I(Y*Y) + I(X*Y))

# Add X and Y to P
c$X <- coordinates(c)[,1]
c$Y <- coordinates(c)[,2]
 
# Run the regression model
lm.2 <- lm( f.2, data=c)

# Use the regression model output to interpolate the surface
dat.2nd <- SpatialGridDataFrame(grd, data.frame(var1.pred = predict(lm.2, newdata=grd))) 
# Clip the interpolated raster to Texas
r   <- raster(dat.2nd)
r.m <- raster::mask(r, arauca2)

# Plot the map
tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE,midpoint = NA,
            title="2nd order polinomial fit\nPredicted precipitation \n(in mm)") +
  tm_shape(c) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

KRIGING

Definiremos la ecuación polinomial de primer orden, para luego calcular el variograma de muestra y posterior a ello ajustar nuestro variograma a travez de la funcion vgm()

# Definimos la ecuación polinomial de primer orden
f.1 <- as.formula(rad ~ X + Y) 

# Calculamos el variograma de muestra
# Esto le dice a la función que cree el variograma sobre los datos sin tendencia.
var.smpl <- variogram(f.1, c, cloud = FALSE, cutoff=120000, width=10000)

# Calcule el modelo de variograma pasando los valores de nugget, umbral y rango
# para ajustar.variogram () a través de la función vgm ().
dat.fit  <- fit.variogram(var.smpl, fit.ranges = TRUE, fit.sills = TRUE,
                          vgm(psill=3, model="Mat", range=80000, nugget=0.0))
No convergence after 200 iterations: try different initial values?
dat.fit
# La siguiente grafica nos permite determinar el ajuste
plot(var.smpl, dat.fit, xlim=c(0,130000))

Generamos una superficie Kriged

A continuación, utilizaremos el modelo de variograma dat.fit para generar una superficie interpolada kriged. La función krige nos permite incluir el modelo de tendencia, lo que nos ahorra tener que eliminar la tendencia de los datos, krige los residuos y luego combinar los dos rásteres. En cambio, todo lo que tenemos que hacer es pasar a krige la fórmula de tendencia f.1.

# Definimos el modelo de tendencia
f.1 <- as.formula(rad ~ X + Y) 

# Realizamos la interpolación de krige 
dat.krg <- krige( f.1, c, grd, dat.fit)

Convertiremos la superficie kriged en un objeto raster para recortar

# Conviertimos la superficie kriged en un objeto ráster para recortar
r <- raster(dat.krg)
r.m <- raster::mask(r, arauca2)
r.m
class      : RasterLayer 
dimensions : 190, 527, 100130  (nrow, ncol, ncell)
resolution : 618.7907, 618.7907  (x, y)
extent     : 1189078, 1515181, 1161195, 1278765  (xmin, xmax, ymin, ymax)
crs        : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 15312.72, 16968.03  (min, max)
# Plot the map
tm_shape(r.m) + 
  tm_raster(n=10, palette="Reds", auto.palette.mapping=FALSE, 
            title="K.O universal para Radiación solar [kj m^-2 dia^-1]") +
  tm_shape(c) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)
The argument auto.palette.mapping is deprecated. Please use midpoint for numeric data and stretch.palette for categorical data to control the palette mapping.

Una mejor visualización de nuestra superficie de interpolado

library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("darkblue", "blue", "yellow", "orange", "red"), values(carborg.mask),
  na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(r.m, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(r.m),
    title = "Interpolación por K.O en Arauca medido en [kj m^-2 dia^-1] ")
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definition

Generamos los mapas de intervalo de confianza y varianza

El objeto dat.krg almacena no solo los valores interpolados, sino también los valores de varianza. Estos se pueden pasar al objeto ráster para el mapeo de la siguiente manera:

r   <- raster(dat.krg, layer="var1.var")
r.m <- raster::mask(r, arauca2)

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Interpolación por K.O/Mapa de varianza en n[kj m^-2 dia^-1] )") +tm_shape(c) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)

Un mapa más fácilmente interpretable es el mapa del intervalo de confianza del 95% que se puede generar a partir del objeto de varianza de la siguiente manera (los valores del mapa deben interpretarse como el número de [kj m^-2 dia^-1] por encima y por debajo de la cantidad de radiación solar estimada).

r   <- sqrt(raster(dat.krg, layer="var1.var")) * 1.96
r.m <- raster::mask(r, arauca2)

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Kriging Interpolation\n95% CI map \n(en [kj m^-2 dia^-1] )") +tm_shape(c) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)

Thiessen poligonos

Los poligonos de Thiessen pueden ser creados usando la funcion dirichlet de spatstat

Primero crearemos una superficie teselada

# Create a tessellated surface
th  <-  as(dirichlet(as.ppp(carborg2)), "SpatialPolygons")

# The dirichlet function does not carry over projection information
# requiring that this information be added manually
crs(th) <- crs(carborg2)
crs(arauca2) <- crs(carborg2)
crs(th)
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000
+ellps=GRS80 +units=m +no_defs 
crs(carborg2)
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000
+ellps=GRS80 +units=m +no_defs 

La superficie teselada no almacena información de atributos de la capa de datos de puntos. Usaremos la función over () (del paquete sp) para unir los atributos de punto a la superficie teselada mediante una unión espacial. La función over () crea un marco de datos que necesitará ser agregado al objeto th creando así un objeto

th.z     <- over(th, carborg2, fn=mean)
th.spdf  <-  SpatialPolygonsDataFrame(th, th.z)

#Recortaremos la superficie teselada
th.clp   <- raster::intersect(arauca2,th.spdf)
# Mapeamos los datos
tm_shape(th.clp) + 
  tm_polygons(col="rad", palette="Reds", midpoint=3.0,
              title="Thiessen Polygons \nEstimación radiación solar \n(en [kj m^-2 dia^-1])") +
  tm_legend(legend.outside=TRUE)
CRS object has comment, which is lost in output

4.Interpretación de resultados

Los procesos de interpolación trabajados en la presente a partir de R lograron aclarar y denotar la concepción de análisis de datos geoespaciales, Aunque los 3 métodos de interpolación trabajados lograron arrojar resultados símiles, podemos afirmar que ciertos métodos fueron más precisos que otros. Los datos interpolados de radiación solar lograron mostrar como existen unos valores de radiación mas altos en los municipios de Arauquita, puerto rondón, Arauca y Cravo norte, en donde destaca el municipio cravo norte, el cual posee los valores más altos de radiación solar y es de los municipios donde la producción de plátano y tubérculos es mínima; Por otro lado, los municipios donde se concentra la mayor producción de plátano en el departamento de Arauca tienen valores más bajos de radiación solar como lo es Tame y Fortul.

4.1 IDW

Al aplicar el método IDW evidenciamos un proceso vigoroso de interpolado en cuanto este método fue capas de arrojar ploteos con transiciones de valores entre celdas no tan abruptos, es decir, siguen una tendencia clara, pese a usar un valor de potencia de 2. Nuestra diferencia de los valores estimados sobre los observados indica un cierto grado de precisión, sin embargo, la desviación de estos genera un valor de incertidumbre considerable; Sí bien puede verse que entre los dos hay una tendencia línea creciente, no existe una exactitud total puesto que se esta haciendo un proceso de interpolado en un área muy grande para los pocos puntos de muestra tomados.

4.2 Kriging

El método kriging a partir del semivariograma y el modelo de ajuste, lograron mostrar con eficacia que las observaciones estimadas tienen una correlación alta con las observaciones propuestas en campo, lo que lo hace de los mejores métodos de interpolado usados en este informe, gracias al algoritmo propuesto por kriging se generaron representaciones a escalas de colores que permitían ver fácilmente que zonas del departamento tenían valores más altos de radiación solar. El variograma suministrado para nuestros datos de radiación solar presenta un comportamiento logarítmico, pese a que este método de interpolado fue eficaz, el mapa de nivel de incertidumbre arrojo valores más altos en comparación al método IDW con valores oscilantes entre 2 y 3.

4.3 Poligonos de Thiessen

Interpolando con el método de polígonos de Thiessen podemos ver que los polígonos se encuentran a una misma medida, debido a que los puntos de muestra se encuentran uniformemente distribuidos espacialmente, pese a que no tenemos un indicativo de incertidumbre, podemos concluir que fue el método menos exacto de los trabajados, no es un método con una complejidad alta y presenta transiciones entre polígonos abruptas y poco sutiles.

Conclusiones

Finalmente podemos concluir que lo interesante de interpolar se encuentra en que los datos con una distribución espacial, se encuentran correlacionados entre si, es decir, los valores que están cerca tienden a tener características similares. El provecho de interpolar en cuanto a su precisión depende no solo del método que usaremos, sino además, de su resolución espacial y la densidad de puntos de muestra que tengamos. La presente evaluó 3 métodos de interpolación donde se destaca IDW, Kriging y polígonos de Thiessen, usando datos de radiación solar para el departamento de Arauca; Donde se pudo observar que el método mas fiable para los datos tratados fue el método de la ponderación de distancia inversa (IDW) puesto que nos suministró información de la distribución de valores de radiación solar a lo largo del departamento con el valor más bajo de incertidumbre respecto de los demás métodos trabajados. En el proceso se evidencio que los municipios de Tame, Fortul y Saravena poseen valores mas bajos de Radiación solar, estos departamentos, son quienes predominan productivamente en el departamento, mientras que los departamentos de Puerto rondón, Arauquita, Cravo norte y Arauca poseen los valores mas altos de radiación solar y a su vez son los municipios con una menor tasa de productividad agraria.

Referencias

Cuencar, J. Arauca Colombia guía turística. Adaptado de: https://ceo.uniandes.edu.co/images/Documentos/Gu%C3%ADa%20tur%C3%ADstica%20Arauca.pdf

IDEAM. (2014). La importancia de la radiación solar. Adaptado de: http://www.ideam.gov.co/web/tiempo-y-clima/radiacion-solar-ultravioleta

Barrera, J. Cardona, C. Cayón, D. (2011). El cultivo de plátano (MUSA AAB SIMMONDS) ecofisiología y manejo cultural sostenible. Adaptado de: https://editorialzenu.com/images/1467833541.pdf

ArcGIS. (2016). Vista general del conjunto de herramientas Interpolación. Adaptado de: https://desktop.arcgis.com/es/arcmap/10.3/tools/spatial-analyst-toolbox/an-overview-of-the-interpolation-tools.htm

LS0tDQp0aXRsZTogIkludGVycG9sYWNpw7NuIGRlIGRhdG9zIGRlIHJhZGlhY2nDs24gc29sYXIgcGFyYSBlbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIg0KYXV0aG9yOiAiRGFuaWVsIEVzdGViYW4gQ29ydMOpcyBFY2hldmVycnkiDQpkYXRlOiAiMTAvMTIvMjAyMCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIFJlc3VtZW4NCg0KTGEgcmFkaWFjacOzbiBzb2xhciByZXN1bHRhIGRlIGdyYW4gaW50ZXLDqXMgYWdyb27Ds21pY28gZGViaWRvIGEgcXVlIGVzIGVsIGZhY3RvciBxdWUgbcOhcyBpbmZsdXllIGVuIGxhIGZvdG9zw61udGVzaXMgZGUgbGFzIHBsYW50YXMsIHBhcmEgb2J0ZW5lciBhbHRhcyB0YXNhcyBkZSBmb3Rvc8OtbnRlc2lzIHNlIGVuY3VlbnRyYSBuZWNlc2FyaW8gbWF4aW1pemFyIGxhIGludGVyY2VwY2nDs24gZGUgbGEgbHV6IGVuY29udHJhbmRvIGx1Z2FyZXMgaWTDs25lb3MgZGUgcmFkaWFjacOzbiBzb2xhciwgc3UgbcOheGltYSBpbnRlcmNlcGNpw7NuIHBvciBwYXJ0ZSBkZSBsYXMgcGxhbnRhcyBzZSBvYnNlcnZhIGVuIHVuYSBtYXlvciBjYW50aWRhZCBkZSBtYXRlcmlhIHNlY2EsIHNvYnJlIHRvZG8gZW4gY3VsdGl2b3MgZXh0ZW5zb3MgeSB1biBjcmVjaW1pZW50byBvcHRpbW8gZW4gdG9kYXMgbGFzIGV0YXBhcyBkZSBjcmVjaW1pZW50byBkZSBsYSBwbGFudGEuIExhIHByZXNlbnRlIGV2YWzDumEgMyBtw6l0b2RvcyBkZSBpbnRlcnBvbGFjacOzbiBlc3BhY2lhbCBlbiBSIHVzYW5kbyBkYXRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHN1bWluaXN0cmFkb3MgcG9yIFdvcmxkIENsaW0gZG9uZGUgc2UgZGVzdGFjYW4gbWV0b2RvcyBjb21vIGtyaWdpbmcgb3JkaW5hbCwgcG9uZGVyYWNpw7NuIGRlIGxhIGRpc3RhbmNpYSBpbnZlcnNhIChJRFcpIHkgcG9saWdvbm9zIGRlIHRoaWVzZWVuIGFwbGljYWRvcyBhbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIGVuIENvbG9tYmlhOyBGaW5hbG1lbnRlIGVuY29udHJhcmEgdW5hIG11ZXN0cmEgZGUgbG9zIHJlc3VsdGFkb3MgeSBsYSBpbnRlcnByZXRhY2nDs24gZGUgZWxsb3MgcGFyYSBkZW5vdGFyIGxhIG5lY2VzaWRhZCBkZSByYWRpYWNpw7NuIHNvbGFyIHBhcmEgbG9zIGN1bHRpdm9zIG1hcyBkZXN0YWNhZG9zIGRlbCBkZXBhcnRhbWVudG8uDQoNCioqKlBhbGFicmFzIGNsYXZlOioqKiBSYWRpYWNpw7NuLCBkaXN0cmlidWNpw7NuIGVzcGFjaWFsLCBpbnRlcnBvbGFjacOzbiwga3JpZ2luZywgSURXLCBwb2xpZ29ub3MgZGUgVGhpZXNzZW4uDQoNCiMjIDEuIEludHJvZHVjY2nDs24NCg0KTGEgZW5lcmfDrWEgcXVlIGRldGVybWluYSBsYSBkaW7DoW1pY2EgZGUgbG9zIHByb2Nlc29zIGF0bW9zZsOpcmljb3MgeSBjbGltw6F0aWNvcyBlbWl0aWRhIHBvciBlbCBzb2wgZXMgY29ub2NpZGEgY29tbyByYWRpYWNpw7NuIHNvbGFyLCBsYSBlbmVyZ8OtYSBwcm9kdWNpZGEgcG9yIGVsIHNvbCBlcyByYWRpYWNpw7NuIGVsZWN0cm9tYWduw6l0aWNhIHByb3BvcmNpb25hZGEgcG9yIHJlYWNjaW9uZXMgZGUgaGlkcm9nZW5vIGVuIGVsIG7DumNsZW8gZGVsIHNvbCBwb3IgZnVzacOzbiBudWNsZWFyIHkgbHVlZ28gZW1pdGlkYXMgcG9yIGxhIHN1cGVyZmljaWUgc29sYXIsIGxhIHJhZGlhY2nDs24gc29sYXIgZXMgZXNlbmNpYWwgcGFyYSBsb3MgcHJvY2Vzb3MgcHJvZHVjdGl2b3MgZGUgdW4gY3VsdGl2bywgc2luIGVtYmFyZ28gbGEgZXhwb3NpY2nDs24gZXhjZXNpdmEgYSBlc3RhIGZ1ZW50ZSBkZSBlbmVyZ8OtYSByZXN1bHRhIGVuIGVzdHLDqXMgdMOpcm1pY28gcXVlIGFmZWN0YSBub3RvcmlhbWVudGUgc3UgZGVzYXJyb2xsbywgYWZlY3RhbmRvIGxhIHBsYW50YSBkZXNkZSBzdSBwZXJpb2RvIHZlZ2V0YXRpdm8geSBkZSBjcmVjaW1pZW50bywgaGFzdGEgc3UgZXN0YWRvIGRlIGNvc2VjaGE7RWwgc29sIGVtaXRlIGVuZXJnw61hIGVuIGZvcm1hIGRlIHJhZGlhY2nDs24gZGUgb25kYSBjb3J0YSBwcmluY2lwYWxtZW50ZSBlbiBsYSBiYW5kYSBkZWwgdWx0cmF2aW9sZXRhIHZpc2libGUgeSBlbCBpbmZyYXJyb2pvIGNlcmNhbm8sIGNvbiBsb25naXR1ZGVzIGRlIG9uZGEgZW50cmUgMCwyIHkgMywwIG1pY3LDs21ldHJvcywgZWwgZXNwZWN0cm8gZWxlY3Ryb21hZ27DqXRpY28gZGUgZXN0ZSBubyB0aWVuZSBkZWZpbmlkb3MgbGltaXRlcyBzdXBlcmlvcmVzIG5pIGluZmVyaW9yZXMsIHkgbGEgZW5lcmfDrWEgZGUgdW5hIGZyYWNjacOzbiBkZSByYWRpYWNpw7NuIChmb3TDs24pIGVzIGludmVyc2FtZW50ZSBwcm9wb3JjaW9uYWwgYSBzdSBsb25naXR1ZCBkZSBvbmRhLCBwb3IgbG8gcXVlIGEgbWVub3IgbG9uZ2l0dWQgZGUgb25kYSBtYXlvciBjb250ZW5pZG8gZW5lcmfDqXRpY28gLg0KDQpQYXJhIGRldGVybWluYXIgcXVlIGRhdG9zIGRlIHJhZGlhY2nDs24gc29sYXIgdGVuZW1vcyBlbiBBcmF1Y2EgZXMgbWVuZXN0ZXIgcmVhbGl6YXIgdW5hIGludGVycG9sYWNpw7NuIGRlYmlkbyBhIHF1ZSB0b21hcmVtb3MgdW5vcyBkYXRvcyBkaXN0cmlidWlkb3MgZXNwYWNpYWxtZW50ZSBlbiBmb3JtYXRvIHJhc3RlcjsgTG9zIG9iamV0b3MgY29uIHVuYSBkaXN0cmlidWNpw7NuIGVzcGFjaWFsIHRpZW5kZW4gYSB0ZW5lciBjYXJhY3RlcsOtc3RpY2FzIHNpbWlsYXJlcyBlbnRyZSBtw6FzIGNlcmNhIHNlIGVuY3VlbnRyZW4sIGVzIGRlY2lyLCBzw60gdGVuZW1vcyB1biB2YWxvciBkZSByYWRpYWNpw7NuIHNvbGFyIGVuIHVuIHB1bnRvIGVzcGFjaWFsIGRlIEFyYXVjYSBwb2RlbW9zIHByb3ZlZXIgY29uIHVuIGFsdG8gbml2ZWwgZGUgY29uZmlhbnphLCBxdWUgZXN0ZSB2YWxvciBlcyBzaW1pbGFyIG8gc2lndWUgdW5hIHRlbmRlbmNpYSBlbiB1biBwdW50byBjZXJjYW5vIGFsIHB1bnRvIGRlIG11ZXN0cmEuDQoNCkxhIHByZXNlbnRlIGV2YWx1YSAzIG3DqXRvZG9zIGRlIGludGVycG9sYWNpw7NuIGVzcGFjaWFsIGVuIFIsIHVzYW5kbyBkYXRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHN1bWluaXN0cmFkb3MgcG9yIFdvcmxkIENsaW0gZG9uZGUgc2UgZGVzdGFjYW4gbWV0b2RvcyBjb21vIGtyaWdpbmcgb3JkaW5hbCwgcG9uZGVyYWNpw7NuIGRlIGxhIGRpc3RhbmNpYSBpbnZlcnNhIChJRFcpIHkgcG9saWdvbm9zIGRlIHRoaWVzZWVuIGFwbGljYWRvcyBhbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIGVuIENvbG9tYmlhOyBGaW5hbG1lbnRlIGVuY29udHJhcmEgdW5hIGludGVycHJldGFjacOzbiAgZGUgbG9zIHJlc3VsdGFkb3MgeSBsYSBpbnRlcnByZXRhY2nDs24gZGUgZWxsb3MgcGFyYSBkZW5vdGFyIGxhIG5lY2VzaWRhZCBkZSByYWRpYWNpw7NuIHNvbGFyIHBhcmEgbG9zIGN1bHRpdm9zIG1hcyBkZXN0YWNhZG9zIGRlbCBkZXBhcnRhbWVudG8uDQoNCiMjIDIuIERhdG9zIHkgbWV0b2Rvcw0KDQojIyMgMi4xIFpvbmEgZGUgZXN0dWRpbw0KDQpFbiBlbCBub3J0ZSBkZSBsb3MgbGxhbm9zIG9yaWVudGFsZXMsIGVudHJlIGxhIGNvcmRpbGxlcmEgb3JpZW50YWwgeSBsYSB6b25hIGxpbcOtdHJvZmUgY29uIFZlbmV6dWVsYSBzZSBlbmN1ZW50cmEgdWJpY2FkbyBlbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhLCBzZSBsb2NhbGl6YSBlbnRyZSBsb3MgMDbCsCwgMDLigJkgNDDigJ0geSAwN8KwIDA24oCZIDEz4oCdIGRlIGxhdGl0dWQgbm9ydGUgeSBsb3MgNjnCsCAyNeKAmSA1NOKAnSB5IDcywrAgMjLigJkgMjPigJ0gZGUgbG9uZ2l0dWQgb2VzdGUsIGVuIGVsIGV4dHJlbW8gbm9ydGUgZGUgbGEgT3Jpbm9xdcOtYSBjb2xvbWJpYW5hLCB0ZXJyaXRvcmlvIGRlbm90YWRvIHBvciBsYSBzaWVycmEgbmV2YWRhIGRlbCBjb2N1eSB5IGF0cmF2ZXNhZG8gcG9yIGxvcyByw61vcyBtZXRhLCBBcmF1Y2EgeSBDYXNhbmFyZS4gRWwgZXBpY2VudHJvIGFncsOtY29sYSwgZ2FuYWRlcm8geSBwZXRyb2xlcm8gZGVsIG9yaWVudGUgY29sb21iaWFubyBjb21wcmVuZGUgc2lzdGVtYXMgZGUgc2VsdmEsIHNhYmFuYSB5IGFmbHVlbnRlczsgQ29tcHJlbmRlIGxvcyBtdW5pY2lwaW9zIGRlIFRhbWUsIEFyYXVxdWl0YSwgRm9ydHVsLCBQdWVydG8gUm9uZMOzbiwgU2FyYXZlbmEsIENyYXZvIE5vcnRlIHkgQXJhdWNhIGNvbW8gY2FwaXRhbC5Fc3RhIHRpZXJyYSB1YmljYWRhIGVuIGVsIGV4dHJlbW8gbm9yb3JpZW50YWwgZGUgbGEgT3Jpbm9xdWlhIGNvbG9tYmlhbmEsIHBvc2VlIHVuIHJlbGlldmUgbWl4dG8gZG9uZGUgZW5jb250cmFtb3Mgem9uYXMgbW9udGHDsW9zYXMgbGFzIGN1YWxlcyBubyBzdXBlcmFuIGxvcyA1MDAwIG0ucy5uLm0sIHNhYmFuYXMgcXVlIHNlIGxldmFudGFuIHNvYnJlIGxvcyAxMDAwIG0ucy5uLm0geSB1bmEgdGVtcGVyYXR1cmEgZW50cmUgbG9zIDI4wrAgeSAzMMKwLg0KDQpBcmF1Y2EgcG9zZWUgdHJlcyBjb25qdW50b3MgbW9yZm9sw7NnaWNvczogbGEgY29yZGlsbGVyYSBvcmllbnRhbCBxdWUgY3VicmUgdW5hIHF1aW50YSBwYXJ0ZSBkZWwgZGVwYXJ0YW1lbnRvIHkgY29tcHJlbmRlIGVsZXZhY2lvbmVzIGRlIDUwMCBoYXN0YSA1MzgwIG0ucy5uLm07IHBpZSBkZSBtb250ZSBjdWJpZXJ0YSBkZSBzYWJhbmEgeSDDoXJlYXMgYW1wbGlhbWVudGUgdmVnZXRhdGl2YXMsIGJvc3F1ZSBlY3VhdG9yaWFsIHkgY29uZm9ybWFkYSBwb3IgY29ub3MsIGFiYW5pY29zLCBhbHV2aWFsZXMsIHRlcnJhemFzIGRlIHJlbGlldmUgcGxhbm8gZSBpbmNsaW5hZG8geSBsYSBsbGFudXJhIGFsdXZpYWw7IExhIGZvcm1hY2nDs24gb3JvZ3LDoWZpY2EgbWFzIGRlc3RhY2FkYSBlcyBsYSBzaWVycmEgbmV2YWRhIGRlbCBjb2N1eSAgbGEgY3VhbCBjdWVudGEgY29uIGFjY2lkZW50ZXMgZ2VvZ3LDoWZpY29zIGNvbW8gbGEgcGllZHJhLCBlbCBkaWFtYW50ZSwgbG9zIGFsdG9zIG5pZXZlY2l0YXMsIG9zb3MgeSBsYXMgY3VjaGlsbGFzIGRlIEFsdGFtaXJhIHkgZWwgc2FsaXRyZS4NCkRlYmlkbyBhIHN1IHViaWNhY2nDs24gbGF0aXR1ZGluYWwsIEFyYXVjYSBwcmVzZW50YSB1biBjbGltYSBlY3VhdG9yaWFsIGxsdXZpb3NvLCBjb24gaW5mbHVlbmNpYSBkZSBsb3MgdmllbnRvcyBhbGlzaW9zIHkgbGEgY29yZGlsbGVyYSBvcmllbnRhbDsgUHJlc2VudGFuZG8gZG9zIHBlcmlvZG9zIGNsaW3DoXRpY29zOiBFbnRyZSBhYnJpbCB5IG5vdmllbWJyZSBlbCBjbGltYSBwcmVkb21pbmFudGUgZXMgbGx1dmlvc28geSBlbnRyZSBub3ZpZW1icmUgeSBtYXJ6byBwcmVkb21pbmEgdW4gY2xpbWEgc2VjbyBzaW4gbGxlZ2FyIGEgYWxjYW56YXIgbG9zIDM1wrBDLg0KDQpgYGB7cn0NCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KGNhcnRvZ3JhcGh5KQ0KDQpvcGFyIDwtIHBhcihtYXIgPSBjKDAsMCwxLjIsMCkpDQoNCnBhcihiZz0iZ3JleTc1IikNCiMgcGxvdCBtdW5pY2lwYWxpdGllcw0KcGxvdChzdF9nZW9tZXRyeShuYmlfbXVuaWNfMiksIGNvbCA9ICIjZTRlOWRlIiwgYm9yZGVyID0gInJlZCIsIA0KICAgICBiZyA9ICJncmV5NzUiLCBsd2QgPSAwLjUpDQoNCiMgcGxvdCBsYWJlbHMNCmxhYmVsTGF5ZXIoDQogIHggPSBuYmlfbXVuaWNfMiwgDQogIHR4dCA9ICJNVU5JQ0lQSU8iLCANCiAgY29sPSAieWVsbG93IiwgDQogIGNleCA9IDAuNCwgDQogIGZvbnQgPSA0LA0KICBoYWxvID0gVFJVRSwgDQogIGJnID0gImdyZXkyNSIsIA0KICByID0gMC4xLCANCiAgb3ZlcmxhcCA9IEZBTFNFLCANCiAgc2hvdy5saW5lcyA9IEZBTFNFDQopDQojIG1hcCBsYXlvdXQNCmxheW91dExheWVyKA0KICB0aXRsZSA9ICJEZXBhcnRhbWVudG8gZGUgQXJhdWNhIGNvbiBzdXMgcmVzcGVjdGl2b3MgbXVuaWNpcGlvcyIsIA0KICBhdXRob3IgPSAiRGFuaWVsIENvcnTDqXMiLCANCiAgZnJhbWUgPSBUUlVFLA0KICBub3J0aCA9IFRSVUUsIA0KICB0YWJ0aXRsZSA9IFRSVUUsIA0KICB0aGVtZSA9ICJ0YXVwZS5wYWwiDQopIA0KYGBgDQoNCiMjIyAyLjIgRGF0b3MNCg0KRW4gbGEgcHJlc2VudGUgc2UgdG9tYXJhbiBkYXRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHN1bWluaXN0cmFkb3MgcG9yIFdvcmxkQ2xpbSwgdXNhcmVtb3MgbGEgdmVyc2nDs24gbGFuemFkYSBlbiBlbmVybyBkZWwgMjAyMCBkb25kZSBzZSBlbmNvbnRyYXJhbiAxOSB2YXJpYWJsZXMgYmlvY2xpbcOhdGljYXMgYSA0IHJlc29sdWNpb25lcyBlc3BhY2lhbGVzLCBjYWRhIGRlc2NhcmdhIGNvbnRpZW5lIHVuIGFyY2hpdm8gemlwIGRvbmRlIHNlIGVuY29udHJhcmFuIDEyIGFyY2hpdm9zIEdlb1RpZmYsIGNhZGEgYXJjaGl2byBjb3JyZXNwb25kZSBhIHVuIG1lcyBkZWwgYcOxbzsgUGFyYSBlc3RlIGluZm9ybWUgc2UgdXNhcm9uIGRhdG9zIGRlIHJhZGlhY2nDs24gc29sYXIgbWVkaWRvcyBlbiBrSiBtIC0yIGTDrWEgLTEgLGEgdW5hIHJlc29sdWNpw7NuIGVzcGFjaWFsIGRlIDUgbWludXRvcyB5IHNlIHRvbWFyYSB1biBhcmNoaXZvIEdlb3RpZmYgcXVlIGNvbnRpZW5lIGVsIHByb21lZGlvIGRlIHJhZGlhY2nDs24gc29sYXIgZ2xvYmFsIHBhcmEgZWwgbWVzIGRlIGRpY2llbWJyZS4NCg0KTGEgbWVkaWNpw7NuIGRlIGxhIHJhZGlhY2nDs24gc29sYXIgZXMgZGUgZ3JhbiB2YWxvciBwYXJhIHVuIGFtcGxpbyByYW5nbyBkZSBhcGxpY2FjaW9uZXMsIGVuIGxhcyDDoXJlYXMgZGUgaW5nZW5pZXLDrWEsIGFycXVpdGVjdHVyYSwgYWdyaWN1bHR1cmEsIGdhbmFkZXLDrWEsIHNhbHVkIGh1bWFuYSB5IG1ldGVvcm9sb2fDrWEgZGVudHJvIGRlIGxhcyBjdWFsZXMgc2UgZGVzdGFjYSBmdW5kYW1lbnRhbG1lbnRlIGVsIHVzbyBjb21vIGZ1ZW50ZSBkZSBlbmVyZ8OtYSBhbHRlcm5hdGl2YS4gTGEgbHV6IHNvbGFyIGVzIGVzZW5jaWFsIHBhcmEgbG9zIG1lY2FuaXNtb3MgZGUgY3JlY2ltaWVudG8gZGUgbGFzIHBsYW50YXMsIHBlcm8gbGEgZXhwb3NpY2nDs24gZXhjZXNpdmEgYSBlc3RhIGZ1ZW50ZSBkZSBlbmVyZ8OtYSByZXN1bHRhIGVuIGVzdHLDqXMgdMOpcm1pY28gcXVlIGFmZWN0YSBzdSBkZXNhcnJvbGxvLCBjcmVjaW1pZW50byB5IHBlcmlvZG8gcHJvZHVjdGl2byBkZSBsYSBwbGFudGEsIGVzcGVjaWFsbWVudGUgZW4gcGVyaW9kb3MgZGUgc2llbWJyYSB5IGVuIHBsYW50YXMgbWFkdXJhcyBkdXJhbnRlIHRvZG8gZWwgcGVyaW9kbyB2ZWdldGF0aXZvLCBhZmVjdGFuZG8gbmVnYXRpdmFtZW50ZSBsYSBldGFwYSBkZSBjb3NlY2hhIGRlbCBwcm9kdWN0by4gDQoNCkFyYXVjYSBhbCBzZXIgdW5hIHJlZ2nDs24gY2FyYWN0ZXJpemFkYSBwb3Igc3UgcG90ZW5jaWFsIHByb2R1Y3Rpdm8gZGUgcGzDoXRhbm8geSB0dWLDqXJjdWxvcywgc2UgZW5jdWVudHJhbiBpbmZsdWVuY2lhZG9zIGVzdG9zIHNpc3RlbWFzIGRlIHByb2R1Y2Npw7NuIHBvciBmYWN0b3JlcyBiacOzdGljb3MgeSBhYmnDs3RpY29zLCBsYXMgYWx0YXMgeSBiYWphcyB0ZW1wZXJhdHVyYXMgeSBsYSByYWRpYWNpw7NuIHNvbGFyIHNvbiBmYWN0b3JlcyBxdWUgYWZlY3RhbiBjb25zaWRlcmFibGVtZW50ZSBsYSBwcm9kdWNjacOzbiwgcGFyYSBlbCBjYXNvIGRlbCBwbMOhdGFubywgZXN0ZSBlcyBzZW1icmFkbyBlbiBjb25kaWNpb25lcyBtdXkgdmFyaWFkYXMgZGUgcmFkaWFjacOzbiBzb2xhciwgc2luIGVtYmFyZ28gbGEgZmFsdGEgZGUgbHV6IG5vIGludGVycnVtcGUgbGEgZW1pc2nDs24geSBkZXNhcnJvbGxvIGRlIGxhcyBob2phcywgcGVybyBsb3MgbGltYm9zIHF1ZWRhbiBibGFucXVlY2lkb3MgZGViaWRvIGEgbGEgYXVzZW5jaWEgZGUgc8OtbnRlc2lzIGRlIGNsb3JvZmlsYSwgY29tbyBjb25zZWN1ZW5jaWEgbGFzIHZhaW5hcyBmb2xpYXJlcyB5IHBzZXVkb3RhbGxvcyBzZSBhbGFyZ2FuIGRlbWFzaWFkbywgbGEgcmFkaWFjacOzbiB0YW1iacOpbiBpbmZsdXllIGRpcmVjdGFtZW50ZSBlbiBlbCBwcm9jZXNvIGRlIG1hZHVyYWNpw7NuIHkgY29tcG9zaWNpw7NuIHF1w61taWNhIGRlIGxvcyBmcnV0b3MgZGUgcGzDoXRhbm8uDQoNCioqKkEgY29udGludWFjaW9uIHRyYXRhcmVtb3MgbG9zIGRhdG9zIHF1ZSB1c2FyZW1vcyBwYXJhIGludGVycG9sYXI6KioqDQpJbmljaWFyZW1vcyBsaW1waWFuZG8gbGEgbWVtb3JpYQ0KDQpgYGB7cn0NCiNybShsaXN0PWxzKCkpDQpgYGANCg0KQ2FyZ2FyZW1vcyBsYXMgbGlicmVyaWFzIHF1ZSBuZWNlc2l0YXJlbW9zIHBhcmEgdHJhdGFyIGxvcyBkYXRvcyB5IGludGVycG9sYXINCg0KYGBge3J9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShzZikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShnc3RhdCkNCmxpYnJhcnkoc3ApDQpsaWJyYXJ5KHNwYXRzdGF0LmRhdGEpDQpsaWJyYXJ5KG5sbWUpDQpsaWJyYXJ5KHJwYXJ0KQ0KbGlicmFyeShzcGF0c3RhdCkNCmBgYA0KDQpMZWVtb3MgZWwgY29uanVudG8gZGUgZGF0b3MgZGUgcmFkaWFjacOzbiBzb2xhciBlbiBmb3JtYXRvIHLDoXN0ZXINCg0KYGBge3J9DQojIyBMZXllbmRvIGVsIGNvbmp1bnRvIGRlIGRhdG9zIGRlIHJhZGlhY2nDs24gc29sYXIgZW4gZm9ybWF0byByYXN0ZXINCmNhcmJvcmcgPC0gcmFzdGVyKCJDOlxcVXNlcnNcXGpvaG5lZGlzb25jb3J0ZXNcXERvY3VtZW50c1xcSW5mM0dNQlxccmFkLnRpZiIpDQoNCmBgYA0KDQpDYXJib3JnIHNlcmEgbnVlc3Ryb3MgZGF0b3MgZGUgcmFkaWFjacOzbiBzb2xhcg0KDQpgYGB7cn0NCiMjIFF1w6kgYWRqdW50YW1vcyBlbiBsYSB2YXJpYWJsZSBjYXJib3JnPw0KY2FyYm9yZw0KYGBgDQoNCkxhIHZhcmlhYmxlIOKAnGFvaeKAnSBjb250aWVuZSBlbCBzaGFwZWZpbGUgZGUgbnVlc3RyYSDDoXJlYSBkZSBpbnRlcsOpcywgcGFyYSBlc3RlIGNhc28gZWwgZGVwYXJ0YW1lbnRvIGRlIEFyYXVjYS4NCg0KYGBge3J9DQooYW9pIDwtIHNoYXBlZmlsZSgiQzpcXFVzZXJzXFxqb2huZWRpc29uY29ydGVzXFxEb2N1bWVudHNcXEluZjJHTUJcXE1HTjIwMTdfODFfQVJBVUNBXFw4MV9BUkFVQ0FcXEFETUlOSVNUUkFUSVZPXFxNR05fTVBJT19QT0xJVElDTy5zaHAiKSkNCmBgYA0KDQpEYXRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHBhcmEgbnVlc3RyYSBhcmVhIGRlIGludGVyZXMNCg0KYGBge3J9DQpjYXJib3JnLmNyb3AgPC0gcmFzdGVyOjpjcm9wKGNhcmJvcmcsIGV4dGVudChhb2kpKQ0KYGBgDQoNCkVubWFzY2FyYW1vcyBudWVzdHJhIGNhcGEgcmFzdGVyIHBhcmEgbnVlc3RyYSBhcmVhIGRlIGludGVyZXMNCg0KYGBge3J9DQpjYXJib3JnLm1hc2sgPC0gbWFzayh4ID0gY2FyYm9yZy5jcm9wLCBtYXNrID0gYW9pKQ0KYGBgDQoNCmBgYHtyfQ0KY2FyYm9yZy5tYXNrIA0KYGBgDQpUcmF6YW1vcyBsYSBjYXBhIHJhc3Rlcg0KDQpgYGB7cn0NCnBsb3QoY2FyYm9yZy5tYXNrLCBtYWluPSAgIndvcmRjbGltIHJhZGlhY2nDs24gc29sYXIgcGFyYSBlbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIFtraiBtXi0yIGRpYV4tMV0iKQ0KcGxvdChhb2ksIGFkZD1UUlVFKQ0KYGBgDQpQbG90ZWFyZW1vcyB1biBtYXBhIHBhcmEgb2J0ZW5lciB1bmEgbWVqb3IgdmlzdWFsaXphY2nDs24gZGUgbnVlc3Ryb3MgZGF0b3M6DQoNCmBgYHtyfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpwYWwgPC0gY29sb3JOdW1lcmljKGMoImRhcmtibHVlIiwgImJsdWUiLCAieWVsbG93IiwgIm9yYW5nZSIsICJyZWQiKSwgdmFsdWVzKGNhcmJvcmcubWFzayksDQogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShjYXJib3JnLm1hc2ssIGNvbG9ycyA9IHBhbCwgb3BhY2l0eSA9IDAuNikgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IHZhbHVlcyhjYXJib3JnLm1hc2spLA0KICAgIHRpdGxlID0gIndvcmRjbGltIHNvYnJlIHJhZGlhY2nDs24gc29sYXIgcGFyYSBlbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIFtraiBtXi0yIGRpYV4tMV0iKQ0KYGBgDQoNCkNvbiBsYSBmdW5jaW9uIHJhc3RlclRvUG9pbnRzIGRlIGxhIGxpYnJlcmlhIHJhc3RlciBwb2RlbW9zIGNvbnZlcnRpciBlbCByYXN0ZXIgYSBwdW50b3MNCg0KYGBge3J9DQpjYXJib3JnLnBvaW50cyA8LSByYXN0ZXJUb1BvaW50cyhjYXJib3JnLm1hc2ssIHNwYXRpYWwgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyfQ0KY2FyYm9yZy5wb2ludHMNCmBgYA0KDQpgYGB7cn0NCnN0cihjYXJib3JnLnBvaW50cykNCmBgYA0KDQpQbG90ZWFtb3MgbnVlc3RyYSBjb252ZXJzacOzbiBkZSByYXN0ZXIgYSBwdW50b3MNCg0KYGBge3J9DQpwbG90KGNhcmJvcmcubWFzaywgbWFpbj0gIndvcmRjbGltIHJhZGlhY2nDs24gc29sYXIgcGFyYSBlbCBkZXBhcnRhbWVudG8gZGUgQXJhdWNhIFtraiBtXi0yIGRpYV4tMV0iKQ0KcGxvdChhb2ksIGFkZD1UUlVFKQ0KcG9pbnRzKGNhcmJvcmcucG9pbnRzJHgsIGNhcmJvcmcucG9pbnRzJHksIGNvbCA9ICJibHVlIiwgY2V4ID0gMC42KQ0KYGBgDQoNCkVzY3JpYmFtb3MgZWwgb2JqZXRvIGVzcGFjaWFsIGRlIHB1bnRvcyBlbiB1biBhcmNoaXZvIGRlIGRpc2NvLiBTb2xvIHBhcmEgYWhvcnJhciB0aWVtcG8geSB0cmFiYWpvIGVuIGNhc28gZGUgcXVlIGFsZ28gc2FsZ2EgbWFsLg0KDQpVc2FyZW1vcyBsYSBiaWJsaW90ZWNhIHJnZGFsIGNvbW8gc2UgaWx1c3RyYQ0KDQpgYGB7cn0NCmdlb2pzb25pbzo6Z2VvanNvbl93cml0ZShjYXJib3JnLnBvaW50cywgZmlsZSA9ICIuL0luZjNHTUIiKQ0KYGBgDQoNCkxlYW1vcyBsb3MgcHVudG9zIGRlIHByZWNpcGl0YWNpw7NuLiBDb25zdWx0ZSBsYSBkb2N1bWVudGFjacOzbiBkZSBnZW9qc29uaW8gcGFyYSBjb21wcmVuZGVyIHF1w6kgcGFyw6FtZXRyb3MgZGViZW4gcGFzYXJzZSBhIGxhIGZ1bmNpw7NuIGdlb2pzb25fcmVhZA0KDQpgYGB7cn0NCmNhcmJvcmcucG9pbnRzIDwtIGdlb2pzb25pbzo6Z2VvanNvbl9yZWFkKCIuL0luZjNHTUIuZ2VvanNvbiIsIHdoYXQ9InNwIikNCmBgYA0KDQpgYGB7cn0NCmNhcmJvcmcucG9pbnRzDQpgYGANCg0KUHJlcGFyYWNpw7NuIGFkaWNpb25hbCBkZSBudWVzdHJvcyBkYXRvcyBkZWwgYXJlYSBkZSBpbnRlcmVzIChhb2kpDQoNCmBgYHtyfQ0KKGFvaSA8LSBzaGFwZWZpbGUoIkM6XFxVc2Vyc1xcam9obmVkaXNvbmNvcnRlc1xcRG9jdW1lbnRzXFxJbmYyR01CXFxNR04yMDE3XzgxX0FSQVVDQVxcODFfQVJBVUNBXFxBRE1JTklTVFJBVElWT1xcTUdOX01QSU9fUE9MSVRJQ08uc2hwIikpDQpgYGANCg0KTmVjZXNpdGFtb3MgY29udmVydGlyIG51ZXN0cm9zIGRhdG9zIGVuIHVuYSBjYXJhY3RlcmlzdGljYSBlc3BhY2lhbA0KDQpgYGB7cn0NCmFyYXVjYV9zZiA8LSAgc2Y6OnN0X2FzX3NmKGFvaSkNCmBgYA0KDQpEaXNvbHZlcmVtb3MgbG9zIGxpbWl0ZXMgaW50ZXJub3MNCg0KYGBge3J9DQooYm9yZGVyX3NmIDwtDQogIGFyYXVjYV9zZiAlPiUNCiAgc3VtbWFyaXNlKGFyZWEgPSBzdW0oTVBJT19OQVJFQSkpKQ0KYGBgDQoNCkNvbnZlcnRpbW9zIG51ZXN0cmEgY2FyYWN0ZXJpc3RpY2EgZXNwYWNpYWwgZW4gZGF0b3MgZXNwYWNpYWxlcw0KDQpgYGB7cn0NCihib3JkZXIgPC0gYXMoYm9yZGVyX3NmLCAnU3BhdGlhbCcpKSANCmBgYA0KDQpgYGB7cn0NCihhcmF1Y2Euc2YgPC0gc3RfYXNfc2YoYW9pKSAlPiUgbXV0YXRlKE1VTklDID0gTVBJT19DTk1CUiwgQ09ESUdPID0gTVBJT19DQ0RHTykgJT4lIHNlbGVjdChNVU5JQywgQ09ESUdPKSkNCmBgYA0KDQpSZWFsaXphbW9zIGxhIGNvbnZlcnNpw7NuDQoNCmBgYHtyfQ0KcC5zZiA8LSBzdF9hc19zZihjYXJib3JnLnBvaW50cykNCmBgYA0KDQpSZWFsaXphcmVtb3MgdW5hIGludGVyc2VjY2nDs24gZGUgcG9saWdvbm9zIGNvbiBwdW50b3MsIGNvbnNlcnZhbmRvIGxhIGluZm9ybWFjacOzbiBkZSBhbWJvcyBlbiB1biBtaXNtbyBsdWdhci4NCg0KYGBge3J9DQooY2FyYm9yZy5zZiA9IHN0X2ludGVyc2VjdGlvbihhcmF1Y2Euc2YsIHAuc2YpKQ0KYGBgDQoNClJlYWxpemFyZW1vcyBkb3MgcmVwcm95ZWNjaW9uZXMsIHVuYSBkZSBudWVzdHJvcyBkYXRvcyB5IG90cmEgZGUgbnVlc3RybyBzaXRpbyBkZSBpbnRlcmVzLg0KYGBge3J9DQpwLnNmLm1hZ25hIDwtIHN0X3RyYW5zZm9ybShjYXJib3JnLnNmLCBjcnM9MzExNikNCmBgYA0KDQpgYGB7cn0NCmFyYXVjYS5zZi5tYWduYSA8LSBzdF90cmFuc2Zvcm0oYXJhdWNhLnNmLCBjcnM9MzExNikNCmBgYA0KDQpgYGB7cn0NCihjYXJib3JnMiA8LSBhcyhwLnNmLm1hZ25hLCAnU3BhdGlhbCcpKQ0KYGBgDQoNCmBgYHtyfQ0Kc2hhcGVmaWxlKGNhcmJvcmcyLCBmaWxlbmFtZT0nQzpcXFVzZXJzXFxqb2huZWRpc29uY29ydGVzXFxEb2N1bWVudHNcXEluZjNHTUJcXGNhcmJvcmcyLnNocCcsIGxheWVyPSAiY2FyYm9yZzIiLCBvdmVyd3JpdGU9VFJVRSkNCmBgYA0KDQpgYGB7cn0NCmNhcmJvcmcyDQpgYGANCg0KYGBge3J9DQooYXJhdWNhMiA8LSBhcyhhcmF1Y2Euc2YubWFnbmEsICdTcGF0aWFsJykpDQpgYGANCg0KYGBge3J9DQpzaGFwZWZpbGUoYXJhdWNhMiwgZmlsZW5hbWU9J0M6XFxVc2Vyc1xcam9obmVkaXNvbmNvcnRlc1xcRG9jdW1lbnRzXFxJbmYzR01CXFxhcmF1Y2EyLnNocCcsIGxheWVyPSAiYXJhdWNhMiIsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQoNClJlZW1wbGF6YW1vcyBsYSBleHRlbnNpw7NuIGRlbCBsw61taXRlIGRlbCBwdW50byBjb24gbGEgZGUgQXJhdWNhDQoNCmBgYHtyfQ0KY2FyYm9yZzJAYmJveCA8LSBhcmF1Y2EyQGJib3gNCmBgYA0KDQpHcmFmaWNhbW9zIG51ZXN0cmEgYXJlYSBkZSBpbnRlcmVzIGNvbiBsb3MgZGF0b3MgZXNwYWNpYWxlcyBkZSByYWRpYWNpw7NuIHNvbGFyLg0KDQpgYGB7cn0NCnRtX3NoYXBlKGFyYXVjYTIpICsgdG1fcG9seWdvbnMoKSArDQogIHRtX3NoYXBlKGNhcmJvcmcyKSArDQogIHRtX2RvdHMoY29sPSJyYWQiLCBwYWxldHRlID0gIlJkQnUiLCBtaWRwb2ludCA9IDMuMCwNCiAgICAgICAgICAgICB0aXRsZT0iTXVlc3RyZW8gZGUgcmFkaWFjacOzbiBzb2xhciBba2ogbV4tMiBkaWFeLTFdIiwgc2l6ZT0wLjIpICsNCiAgdG1fdGV4dCgicmFkIiwganVzdD0iY2VudGVyIiwgeG1vZD0uNiwgc2l6ZSA9IDAuNSkgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQojIyMgMi4zIE1ldG9kb3MNCg0KIyMjIyBJRFcNCg0KTGEgcG9uZGVyYWNpw7NuIGRlIGRpc3RhbmNpYSBpbnZlcnNhIChJRFcpIGVzIHVuIG3DqXRvZG8gZGV0ZXJtaW7DrXN0aWNvIGRlIGludGVycG9sYWRvIGVuIGRvbmRlIHNlIGRhIHBvciBoZWNobyBxdWUgbGEgdmFyaWFibGUgcmVwcmVzZW50YWRhIGNhcnRvZ3LDoWZpY2FtZW50ZSB0aWVuZGUgYSBkaXNtaW51aXIgc3UgaW5mbHVlbmNpYSBhIG1heW9yIGRpc3RhbmNpYSBkZXNkZSBsYSB1YmljYWNpw7NuIGRlbCBwdW50byBkZSBtdWVzdHJhLCBlc3RvIHNlIGxvZ3JhIGEgdHJhdsOpcyBkZSB1bmEgY29tYmluYWNpw7NuIHBvbmRlcmFkYSBsaW5lYWxtZW50ZSBkZSB1biBjb25qdW50byBkZSBwdW50b3MgZGUgbXVlc3RyZW8sIHF1ZSBnZW5lcmFsbWVudGUgc3VlbGVuIGFwbGljYXJzZSBhIGRhdG9zIG11eSB2YXJpYWJsZXMuDQoNCioqTGEgcG90ZW5jaWEqKiBlcyBsYSB2YXJpYWJsZSBjb24gbGEgcXVlIHBvZGVtb3MgY29udHJvbGFyIGxhIGltcG9ydGFuY2lhIGRlIGxvcyBwdW50b3MgY29ub2NpZG9zIHNvYnJlIGxvcyB2YWxvcmVzIHF1ZSBxdWVyZW1vcyBpbnRlcnBvbGFyIGVuIGZ1bmNpw7NuIGRlIHN1IGRpc3RhbmNpYSBkZXNkZSBzdSBwdW50byBkZSBzYWxpZGEuRXMgbGEgdmFyaWFibGUgcXVlIGRldGVybWluYSBsYSB0YXNhIGV4cG9uZW5jaWFsIGRlIGNhw61kYSBkZSBsYSBpbmZsdWVuY2lhIGRlIGxvcyBwdW50b3MgdmVjaW5vcyBjdWFudG8gbWFzIGxlam9zIHNlIGVuY3VlbnRyYW4gZGVsIG5vZG8gZGUgbGEgY3VhZHJpY3VsYS4NCkxvcyB2YWxvcmVzIGFzaWduYWRvcyBvc2NpbGFuIGVudHJlIDEgeSAxMCwgZXNwZWNpZmljYW5kbyB1biB2YWxvciBtw6FzIGJham8gZGFyw6EgbWFzIGltcG9ydGFuY2lhIGEgbG9zIHB1bnRvcyBxdWUgZXN0w6FuIG1hcyBsZWpvcywgb2J0ZW5pZW5kbyBzdXBlcmZpY2llcyBtYXMgc3VhdmVzLCBwb3Igb3RybyBsYWRvIHNpIGFzaWduYW1vcyB1bmEgcG90ZW5jaWEgYWx0YSBzZSBwb25lIG1hcyDDqW5mYXNpcyBlbiBsb3MgcHVudG9zIG1hcyBjZXJjYW5vcyBwb3IgbG8gcXVlIGVsIHJlc3VsdGFkbyBzZXLDoSBtYXMgZGV0YWxsYWRvIHkgbWVub3Mgc3VhdmUuDQoNCg0KIyMjIyBLcmlnaW4NCg0KRXMgdW4gcHJvY2VkaW1pZW50byBnZW9lc3RhZMOtc3RpY28gcXVlIHRyYWJhamEgYSBwYXJ0aXIgZGUgdW4gY29uanVudG8gZGUgcHVudG9zIGRpc3BlcnNvcyBwYXJhIGdlbmVyYXIgdW5hIHN1cGVyZmljaWUgZXN0aW1hZGEsIHN1IHByaW5jaXBhbCBkaWZlcmVuY2lhIGRlIGxvcyBvdHJvcyBtw6l0b2RvcyBkZSBpbnRlcnBvbGFjacOzbiBlcyBxdWUgc2UgZW5jdWVudHJhIG5lY2VzYXJpYSB1bmEgaW52ZXN0aWdhY2nDs24gaW50ZXJhY3RpdmEgZGVsIGNvbXBvcnRhbWllbnRvIGVzcGFjaWFsIGRlIGxhIHZhcmlhYmxlIHJlcHJlc2VudGFkYS4gSW50ZXJwb2xhciBjb24ga3JpZ2luZyBwcmVzdXBvbmUgcXVlIGxhIGRpc3RhbmNpYSBlbnRyZSBsb3MgcHVudG9zIGRlIG11ZXN0cmEgcmVmbGVqYSBjb3JyZWxhY2nDs24gZXNwYWNpYWwgcXVlIHNlIHV0aWxpemEgcGFyYSBleHBsaWNhciBsYSB2YXJpYWNpw7NuIGVuIGxhIHN1cGVyZmljaWUsIGFsIGFwbGljYXIga3JpZ2luZyBhanVzdGFtb3MgdW5hIGZ1bmNpw7NuIG1hdGVtw6F0aWNhIGEgdW5hIGNhbnRpZGFkIGVzcGVjaWZpY2EgZGUgcHVudG9zIGRlbnRybyBkZSB1biByYWRpbyBkZXRlcm1pbmFkbyBwYXJhIGNvbm9jZXIgZWwgdmFsb3IgZGUgc2FsaWRhIHBhcmEgY2FkYSB1YmljYWNpw7NuLiANCg0KS3JpZ2luZyBlc3RhIGJhc2FkbyBlbiBtb2RlbG9zIGVzdGFkw61zdGljb3MgZGUgYXV0b2NvcnJlbGFjacOzbiwgZXMgZGVjaXIsIGxhcyByZWxhY2lvbmVzIGVzdGFkw61zdGljYXMgZW50cmUgbG9zIHB1bnRvcyBtZWRpZG9zLCBncmFjaWFzIGEgZXN0bywgcG9kZW1vcyBwcm9wb3JjaW9uYXIgYWxndW5hIG1lZGlkYSBkZSBjZXJ0ZXphIG8gcHJlY2lzacOzbiBhIGxhIGhvcmEgZGUgcmVhbGl6YXIgdW5hIGVzdGltYWNpw7NuIGRlIHVuIHZhbG9yLiBBcGxpY2FuZG8gZXN0ZSBtw6l0b2RvIGdlbmVyYW1vcyB1bmEgc2VyaWUgZGUgcHJvY2Vzb3MgZGUgYW7DoWxpc2lzIGVzdGFkw61zdGljbyBleHBsb3JhdG9yaW8sIG1vZGVsb3MgZGUgdmFyaW9ncmFtYXMsIGNyZWFjaW9uZXMgZGUgc3VwZXJmaWNpZSwgZW50cmUgb3Ryb3MuIEVzdGUgbcOpdG9kbyBlcyBhZGVjdWFkbyBjdWFuZG8gc2Ugc2FiZSBxdWUgaGF5IHVuYSBpbmZsdWVuY2lhIGRlIGxhIGRpc3RhbmNpYSBjb3JyZWxhY2lvbmFkYSBlc3BhY2lhbG1lbnRlIGNvbiBsb3MgZGF0b3MuDQoNCg0KIyMjIyBQb2xpZ29ub3MgZGUgVGhpZXNzZW4NCg0KTG9zIHBvbMOtZ29ub3MgZGUgVGhpZXNzZW4gcGVybWl0ZW4gZXN0YWJsZWNlciByZWxhY2lvbmVzIG1hdGVtw6F0aWNhcyBlbnRyZSBlbGVtZW50b3MgZ2VuZXJhbmRvIHpvbmFzIGRlIGluZmx1ZW5jaWEgY29uIHVuYXMgcHJlbWlzYXMgbWF0ZW3DoXRpY2FzIGVzcGVjw61maWNhcywgbGEgcmVsYWNpw7NuIHBhcnRlIGRlIHVuYSBudWJlIGRlIHB1bnRvcyBzb2JlIGxvcyBxdWUgc2UgZ2VuZXJhbiB1bmEgc2VyaWUgZGUgcG9sw61nb25vcywgZXN0b3MgcHVudG9zIHNlIHVuZW4gZW50cmUgc2kgeSBzZSBwcm95ZWN0YW4gbWVkaWF0cmljZXMgZW50cmUgbG9zIHNlZ21lbnRvcyBkZSB1bmnDs24sIHNpZW5kbyBkaWNoYXMgbWVkaWF0cmljZXMsIGxvcyBsYWRvcyBkZSBsb3MgcG9sw61nb25vcyByZXN1bHRhbnRlcy4NCkxhIHByaW5jaXBhbCByZWdsYSBxdWUgc2UgZXN0YWJsZWNlIGVzIHF1ZSBsb3MgbGFkb3MgZGUgbG9zIHBvbMOtZ29ub3MgZ2VuZXJhZG9zLCBzb24gZXF1aWRpc3RhbnRlcyBhIGxvcyBwdW50b3MgdmVjaW5vcyB5IHRyYXRhbiBkZSBlbmNvbnRyYXIgbGEgbWVub3IgZGlzdGFuY2lhIHBvc2libGUuIExvcyBsYWRvcyBkZSBjYWRhIHBvbMOtZ29ubyBzZSBlbmN1ZW50cmFuIGEgbGEgbWlzbWEgZGlzdGFuY2lhIGRlIHVuIHB1bnRvIHF1ZSBvdHJvDQoNCg0KIyMgMy5SZXN1bHRhZG9zDQoNCiMjIyMgSURXIA0KDQpMYSBmdW5jacOzbiBJRFcgc2UgZW5jdWVudHJhIGRpc3BvbmlibGUgZW4gU3BhdHN0YXQgY29tbyBlbiBHc3RhdCwgZXMgaW1wb3J0YW50ZSBtZW5jaW9uYXIgcXVlIGxhIGZ1bmNpw7NuIERpcmljaGxldCB1c2FkYSBlbiBlc3RhIGludGVycG9sYWNpw7NuIChjb21vIGxhIG1heW9yw61hIGRlIGxhcyBmdW5jaW9uZXMgZGVsIHBhcXVldGUgc3BhdHN0YXQpIHJlcXVpZXJlIHVuIGZvcm1hdG8gcHBwLCBkZSBhbGzDrSBsYSBzaW50YXhpcyBhcy5wcHANCg0KTGEgc2FsaWRhIElEVyBlcyB1biByYXN0ZXIuIFJlcXVlcmltb3MgY3JlYXIgdW5hIGN1YWRyaWN1bGEgcsOhc3RlciB2YWPDrWEsIHBhcmEgbHVlZ28gaW50ZXJwb2xhciBsb3MgdmFsb3JlcyBkZSByYWRpYWNpw7NuIHNvbGFyIGVuIGNhZGEgY2VsZGEgZGUgbGEgY3VhZHJpY3VsYSBzaW4gbXVlc3RyZWFyLg0KDQpVdGlsaXphcmVtb3MgdW4gdmFsb3IgZGUgcG90ZW5jaWEgSURXIGRlIDIgKGlkcD0yKQ0KDQpgYGB7ciBJV0R9DQojIENyZWFyZW1vcyB1bmEgY3VhZHJpY3VsYSB2YWPDrWEgZG9uZGUgbiBzZXLDoSBlbCBudW1lcm8gdG90YWwgZGUgY2VsZGFzDQpncmQgICAgICAgICAgICAgIDwtIGFzLmRhdGEuZnJhbWUoc3BzYW1wbGUoY2FyYm9yZzIsICJyZWd1bGFyIiwgbj0xMDAwMDApKQ0KIyBOZWNlc2l0YSBhdmVyaWd1YXIgY3XDoWwgZXMgZWwgdGFtYcOxbyBlc3BlcmFkbyBkZWwgZ3JkIGRlIHNhbGlkYQ0KbmFtZXMoZ3JkKSAgICAgICA8LSBjKCJYIiwgIlkiKQ0KY29vcmRpbmF0ZXMoZ3JkKSA8LSBjKCJYIiwgIlkiKQ0KZ3JpZGRlZChncmQpICAgICA8LSBUUlVFICAjIENyZWF0ZSBTcGF0aWFsUGl4ZWwgb2JqZWN0DQpmdWxsZ3JpZChncmQpICAgIDwtIFRSVUUgICMgQ3JlYXRlIFNwYXRpYWxHcmlkIG9iamVjdA0KDQojIEFncmVnYW1vcyBsYSBpbmZvcm1hY2nDs24gZGUgcHJveWVjY2nDs24gZGUgQyBhIGxhIGN1YWRyw61jdWxhIHZhY8OtYQ0KcHJvajRzdHJpbmcoZ3JkKSA8LSBwcm9qNHN0cmluZyhjYXJib3JnMikNCg0KIyBJbnRlcnBvbGFtb3MgbGFzIGNlbGRhcyBkZSBsYSBjdWFkcsOtY3VsYSB1c2FuZG8gdW4gdmFsb3IgZGUgcG90ZW5jaWEgZGUgMiAoaWRwID0gMi4wKQ0KUC5pZHcgPC0gZ3N0YXQ6OmlkdyhyYWQgfiAxLCBjYXJib3JnMiwgbmV3ZGF0YT1ncmQsIGlkcD0yLjApDQoNCiMgQ29udmVydGltb3MgYSByYXN0ZXIgeSBsaW1pdGFtb3MgbnVlc3RyYSBhcmVhIGRlIGVzdHVkaW8NCnIgICAgICAgPC0gcmFzdGVyKFAuaWR3KQ0KYGBgDQoNCmBgYHtyfQ0Kcg0KYGBgDQoNCmBgYHtyfQ0KYXJhdWNhMg0KYGBgDQoNCmBgYHtyfQ0Kci5tICAgPC0gcmFzdGVyOjptYXNrKHIsIGFyYXVjYTIpDQpgYGANCg0KYGBge3J9DQpyLm0NCmBgYA0KDQpgYGB7cn0NCiMgUGxvdA0KdG1fc2hhcGUoci5tKSArIA0KICB0bV9yYXN0ZXIobj0xMCxwYWxldHRlID0gIk9yUmQiLCBhdXRvLnBhbGV0dGUubWFwcGluZyA9IEZBTFNFLA0KICAgICAgICAgICAgdGl0bGU9IklEVyBkZSByYWRpYWNpw7NuIHNvbGFyIHByZXZpc3RhIGVuIFtraiBtXi0yIGRpYV4tMV0gIikgKyANCiAgdG1fc2hhcGUoY2FyYm9yZzIpICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQpVbmEgbWVqb3IgdmlzdWFsaXphY2nDs24gZGUgbnVlc3RybyBjYW1wbyBkZSBpbnRlcnBvbGFkbw0KDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KcGFsIDwtIGNvbG9yTnVtZXJpYyhjKCJkYXJrYmx1ZSIsICJibHVlIiwgInllbGxvdyIsICJvcmFuZ2UiLCAicmVkIiksIHZhbHVlcyhjYXJib3JnLm1hc2spLA0KICBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpDQoNCmxlYWZsZXQoKSAlPiUgYWRkVGlsZXMoKSAlPiUNCiAgYWRkUmFzdGVySW1hZ2Uoci5tLCBjb2xvcnMgPSBwYWwsIG9wYWNpdHkgPSAwLjYpICU+JQ0KICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB2YWx1ZXMoci5tKSwNCiAgICB0aXRsZSA9ICJJRFc6IFJhZGlhY8Otb24gc29sYXIgaW50ZXJwb2xhZGEgZW4gYXJhdWNhIG1lZGlkYSBlbiBba2ogbV4tMiBkaWFeLTFdICIpDQpgYGANCg0KQWp1c3RhbW9zIGxhIGludGVycG9sYWNpw7NuDQoNCkxhIGVsZWNjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBwb3RlbmNpYSBwdWVkZSBzZXIgc3ViamV0aXZhLiBQYXJhIGFqdXN0YXIgbGEgZWxlY2Npw7NuIGRlbCBwYXLDoW1ldHJvIGRlIHBvdGVuY2lhLCBwdWVkZSByZWFsaXphciB1bmEgcnV0aW5hIGRlIHZhbGlkYWNpw7NuIGRlIGRlamFyIHVubyBmdWVyYSBwYXJhIG1lZGlyIGVsIGVycm9yIGVuIGxvcyB2YWxvcmVzIGludGVycG9sYWRvcy4NCg0KYGBge3J9DQpjYXJib3JnMg0KYGBgDQoNCmBgYHtyfQ0KYyA8LSBjYXJib3JnMg0KYGBgDQoNCmBgYHtyfQ0KSURXLm91dCA8LSB2ZWN0b3IobGVuZ3RoID0gbGVuZ3RoKGMpKQ0KYGBgDQoNCmBgYHtyfQ0KZm9yIChpIGluIDE6bGVuZ3RoKGMpKSB7DQogIElEVy5vdXRbaV0gPC0gZ3N0YXQ6OmlkdyhyYWQgfiAxLCBjWy1pLF0sIGNbaSxdLCBpZHA9Mi4wKSR2YXIxLnByZWQNCn0NCmBgYA0KDQpHcmFmaWNhbW9zIGxhIGRpZmVyZW5jaWEgZW50cmUgbG9zIGRhdG9zIGVzdGltYWRvcyB5IGxvcyBkYXRvcyBvYnNlcnZhZG9zDQoNCmBgYHtyfQ0KDQpPUCA8LSBwYXIocHR5PSJzIiwgbWFyPWMoNCwzLDAsMCkpDQogIHBsb3QoSURXLm91dCB+IGMkcmFkLCBhc3A9MSwgeGxhYj0iT2JzZXJ2ZWQiLCB5bGFiPSJQcmVkaWN0ZWQiLCBwY2g9MTYsDQogICAgICAgY29sPXJnYigwLDAsMCwwLjUpKQ0KICBhYmxpbmUobG0oSURXLm91dCB+IGMkcmFkKSwgY29sPSJyZWQiLCBsdz0yLGx0eT0yKQ0KICBhYmxpbmUoMCwxKQ0KYGBgDQoNCmBgYHtyfQ0KcGFyKE9QKQ0KYGBgDQoNCkVsIGVycm9yIGN1YWRyw6F0aWNvIG1lZGlvIChSTVNFKSBzZSBwdWVkZSBjYWxjdWxhciBhIHBhcnRpciBkZSBJRFcub3V0IGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCmBgYHtyfQ0KIyBDb21wdXRhciBSTVNFDQpzcXJ0KCBzdW0oKElEVy5vdXQgLSBjJHJhZCleMikgLyBsZW5ndGgoYykpDQpgYGANClZhbGlkYWNpw7NuIGNydXphZGENCg0KQWRlbcOhcyBkZSBnZW5lcmFyIHVuYSBzdXBlcmZpY2llIGludGVycG9sYWRhLCBwdWVkZSBjcmVhciB1biBtYXBhIGRlIGludGVydmFsbyBkZSBjb25maWFuemEgZGVsIDk1JSBkZWwgbW9kZWxvIGRlIGludGVycG9sYWNpw7NuLiBBcXXDrSBjcmVhcmVtb3MgdW4gbWFwYSBkZSBJQyBkZWwgOTUlIGEgcGFydGlyIGRlIHVuYSBpbnRlcnBvbGFjacOzbiBJRFcgcXVlIHVzYSB1biBwYXLDoW1ldHJvIGRlIHBvdGVuY2lhIGRlIDIgKGlkcCA9IDIuMCkuIEVuY29udHJhcsOhIGVuIGVsIGNvZGlnbyBhcGxpY2FkbyBsb3MgbWV0b2RvcyB1c2Fkb3MgcGFyYSByZWFsaXphciBlbCBwcm9jZXNvIGRlIGludGVycG9sYWRvLg0KDQpgYGB7cn0NCiMgSW1wbGVtZW50YW1vcyB1bmEgdGVjbmljYSBkZSBuYXZhamENCiMgRXN0aW1hbmRvIHVuIGludGVydmFsbyBkZSBjb25maWFuemEgZW4gY2FkYSBwdW50byBubyBtdWVzdHJlYWRvDQoNCiMgQ3JlYW1vcyBsYSBzdXBlcmZpY2llIGRlIGludGVycG9sYWRvDQppbWcgPC0gZ3N0YXQ6OmlkdyhyYWR+MSwgYywgbmV3ZGF0YT1ncmQsIGlkcD0yLjApDQpuICAgPC0gbGVuZ3RoKGMpDQpaaSAgPC0gbWF0cml4KG5yb3cgPSBsZW5ndGgoaW1nJHZhcjEucHJlZCksIG5jb2wgPSBuKQ0KDQojIFJlbW92ZW1vcyB1biBwdW50byBwYXJhIGx1ZWdvIGludGVycG9sYXIgDQpzdCA8LSBzdGFjaygpDQpmb3IgKGkgaW4gMTpuKXsNCiAgWjEgPC0gZ3N0YXQ6OmlkdyhyYWR+MSwgY1staSxdLCBuZXdkYXRhPWdyZCwgaWRwPTIuMCkNCiAgc3QgPC0gYWRkTGF5ZXIoc3QscmFzdGVyKFoxLGxheWVyPTEpKQ0KICAjIGNhbGN1bGFtb3MgbGEgcHNldWRvdmFyaWFibGUgWiBhdCBqDQogIFppWyxpXSA8LSBuICogaW1nJHZhcjEucHJlZCAtIChuLTEpICogWjEkdmFyMS5wcmVkDQp9DQoNCiMgRXN0aW1hZG9yIHRpcG8gbmF2YWphIHBhcmEgZWwgcGFyYW1ldHJvIHogZW4gbGEgbG9jYWNpw7NuIGoNClpqIDwtIGFzLm1hdHJpeChhcHBseShaaSwgMSwgc3VtLCBuYS5ybT1UKSAvIG4gKQ0KDQojIENhbGN1bGFtb3MgKFppKiAtIFpqKV4yDQpjMSA8LSBhcHBseShaaSwyLCctJyxaaikgICAgICAgICAgICAjIENvbXB1dGUgdGhlIGRpZmZlcmVuY2UNCmMxIDwtIGFwcGx5KGMxXjIsIDEsIHN1bSwgbmEucm09VCApICMgU3VtIHRoZSBzcXVhcmUgb2YgdGhlIGRpZmZlcmVuY2UNCg0KIyBDYWxjdWxhbW9zIGVsIGludGVydmFsbyBkZSBjb25maWFuemENCkNJIDwtIHNxcnQoIDEvKG4qKG4tMSkpICogYzEpDQoNCiMgQ3JlYW1vcyAoQ0kgLyBJbnRlcnBvbGFjacOzbiBkZSBsYSB2YXJpYWJsZSkgcmFzdGVyDQppbWcuc2lnICAgPC0gaW1nDQppbWcuc2lnJHYgPC0gQ0kgL2ltZyR2YXIxLnByZWQgDQpgYGANCg0KTGltaXRhbW9zIGVsIHJhc3RlciBkZSBjb25maWFuemEgYSBudWVzdHJhIGFyZWEgZGUgZXN0dWRpbw0KDQpgYGB7cn0NCiMgTGltaXRhbW9zIGVsIHJhc3RlciBkZSBjb25maWFuemEgYSBudWVzdHJhIGFyZWEgZGUgZXN0dWRpbw0KciA8LSByYXN0ZXIoaW1nLnNpZywgbGF5ZXI9InYiKQ0Kci5tIDwtIHJhc3Rlcjo6bWFzayhyLCBhcmF1Y2EyKQ0KDQojIFBsb3RlYW1vcyBudWVzdHJvIG1hcGENCnRtX3NoYXBlKHIubSkgKyB0bV9yYXN0ZXIobj03LHRpdGxlPSJJRFdcbjk1JSBjb25maWRlbmNlIGludGVydmFsIFxuKGluIG1tKSIpICsNCiAgdG1fc2hhcGUoYykgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIA0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQojIyMjIFBvbGlub21pbyBkZSBwcmltZXIgb3JkZW4NCg0KRXN0ZSBtZXRvZG8gc2VyYSBpbmNsdWlkbyBkZWJpZG8gYSBxdWUgbG8gbmVjZXNpdGFyZW1vcyBwYXJhIGdlbmVyYXIgbnVlc3RybyBpbnRlcnBvbGFkbyBwb3IgZWwgbWV0b2RvIGtyaWdpbmcuDQoNCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIDFzdCBvcmRlciBwb2x5bm9taWFsIGVxdWF0aW9uDQpmLjEgPC0gYXMuZm9ybXVsYShyYWQgfiBYICsgWSkgDQogDQojIEFkZCBYIGFuZCBZIHRvIFANCmMkWCA8LSBjb29yZGluYXRlcyhjKVssMV0NCmMkWSA8LSBjb29yZGluYXRlcyhjKVssMl0NCg0KIyBSdW4gdGhlIHJlZ3Jlc3Npb24gbW9kZWwNCmxtLjEgPC0gbG0oIGYuMSwgZGF0YT1jKQ0KDQojIFVzZSB0aGUgcmVncmVzc2lvbiBtb2RlbCBvdXRwdXQgdG8gaW50ZXJwb2xhdGUgdGhlIHN1cmZhY2UNCmRhdC4xc3QgPC0gU3BhdGlhbEdyaWREYXRhRnJhbWUoZ3JkLCBkYXRhLmZyYW1lKHZhcjEucHJlZCA9IHByZWRpY3QobG0uMSwgbmV3ZGF0YT1ncmQpKSkgDQpgYGANCg0KDQpgYGB7cn0NCiMgQ2xpcCB0aGUgaW50ZXJwb2xhdGVkIHJhc3RlciB0byBUZXhhcw0KciAgIDwtIHJhc3RlcihkYXQuMXN0KQ0Kci5tIDwtIHJhc3Rlcjo6bWFzayhyLCBhcmF1Y2EyKQ0KDQojIFBsb3QgdGhlIG1hcA0KdG1fc2hhcGUoci5tKSArIA0KICB0bV9yYXN0ZXIobj0xMCwgcGFsZXR0ZT0iUmRCdSIsIGF1dG8ucGFsZXR0ZS5tYXBwaW5nPUZBTFNFLCANCiAgICAgICAgICAgIHRpdGxlPSIxc3Qgb3JkZXIgcG9saW5vbWlhbCBmaXIgXG5QcmVkaWN0ZWQgcHJlY2lwaXRhdGlvbiBcbihpbiBtbSkiKSArDQogIHRtX3NoYXBlKGMpICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQojIyMjIEFqdXN0ZSBwb2xpbm9taWFsIGRlIHNlZ3VuZG8gb3JkZW4NCg0KUGFyYSBhanVzdGFyIHVuIG1vZGVsbyBwb2xpbm9taWFsIGRlIHNlZ3VuZG8gb3JkZW4gZGUgbGEgZm9ybWEgcmFkc3VuID0gaW50ZXJzZWNjacOzbiArIGFYICsgYlkgKyBkWDIgKyBlWTIgKyBmWFkNCg0KYGBge3J9DQojIERlZmluZSB0aGUgMm5kIG9yZGVyIHBvbHlub21pYWwgZXF1YXRpb24NCmYuMiA8LSBhcy5mb3JtdWxhKHJhZCB+IFggKyBZICsgSShYKlgpK0koWSpZKSArIEkoWCpZKSkNCg0KIyBBZGQgWCBhbmQgWSB0byBQDQpjJFggPC0gY29vcmRpbmF0ZXMoYylbLDFdDQpjJFkgPC0gY29vcmRpbmF0ZXMoYylbLDJdDQogDQojIFJ1biB0aGUgcmVncmVzc2lvbiBtb2RlbA0KbG0uMiA8LSBsbSggZi4yLCBkYXRhPWMpDQoNCiMgVXNlIHRoZSByZWdyZXNzaW9uIG1vZGVsIG91dHB1dCB0byBpbnRlcnBvbGF0ZSB0aGUgc3VyZmFjZQ0KZGF0LjJuZCA8LSBTcGF0aWFsR3JpZERhdGFGcmFtZShncmQsIGRhdGEuZnJhbWUodmFyMS5wcmVkID0gcHJlZGljdChsbS4yLCBuZXdkYXRhPWdyZCkpKSANCmBgYA0KDQpgYGB7cn0NCiMgQ2xpcCB0aGUgaW50ZXJwb2xhdGVkIHJhc3RlciB0byBUZXhhcw0KciAgIDwtIHJhc3RlcihkYXQuMm5kKQ0Kci5tIDwtIHJhc3Rlcjo6bWFzayhyLCBhcmF1Y2EyKQ0KDQojIFBsb3QgdGhlIG1hcA0KdG1fc2hhcGUoci5tKSArIA0KICB0bV9yYXN0ZXIobj0xMCwgcGFsZXR0ZT0iUmRCdSIsIGF1dG8ucGFsZXR0ZS5tYXBwaW5nPUZBTFNFLG1pZHBvaW50ID0gTkEsDQogICAgICAgICAgICB0aXRsZT0iMm5kIG9yZGVyIHBvbGlub21pYWwgZml0XG5QcmVkaWN0ZWQgcHJlY2lwaXRhdGlvbiBcbihpbiBtbSkiKSArDQogIHRtX3NoYXBlKGMpICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQojIyMjIEtSSUdJTkcNCg0KRGVmaW5pcmVtb3MgbGEgZWN1YWNpw7NuIHBvbGlub21pYWwgZGUgcHJpbWVyIG9yZGVuLCBwYXJhIGx1ZWdvIGNhbGN1bGFyIGVsIHZhcmlvZ3JhbWEgZGUgbXVlc3RyYSB5IHBvc3RlcmlvciBhIGVsbG8gYWp1c3RhciBudWVzdHJvIHZhcmlvZ3JhbWEgYSB0cmF2ZXogZGUgbGEgZnVuY2lvbiB2Z20oKQ0KDQpgYGB7cn0NCiMgRGVmaW5pbW9zIGxhIGVjdWFjacOzbiBwb2xpbm9taWFsIGRlIHByaW1lciBvcmRlbg0KZi4xIDwtIGFzLmZvcm11bGEocmFkIH4gWCArIFkpIA0KDQojIENhbGN1bGFtb3MgZWwgdmFyaW9ncmFtYSBkZSBtdWVzdHJhDQojIEVzdG8gbGUgZGljZSBhIGxhIGZ1bmNpw7NuIHF1ZSBjcmVlIGVsIHZhcmlvZ3JhbWEgc29icmUgbG9zIGRhdG9zIHNpbiB0ZW5kZW5jaWEuDQp2YXIuc21wbCA8LSB2YXJpb2dyYW0oZi4xLCBjLCBjbG91ZCA9IEZBTFNFLCBjdXRvZmY9MTIwMDAwLCB3aWR0aD0xMDAwMCkNCg0KIyBDYWxjdWxlIGVsIG1vZGVsbyBkZSB2YXJpb2dyYW1hIHBhc2FuZG8gbG9zIHZhbG9yZXMgZGUgbnVnZ2V0LCB1bWJyYWwgeSByYW5nbw0KIyBwYXJhIGFqdXN0YXIudmFyaW9ncmFtICgpIGEgdHJhdsOpcyBkZSBsYSBmdW5jacOzbiB2Z20gKCkuDQpkYXQuZml0ICA8LSBmaXQudmFyaW9ncmFtKHZhci5zbXBsLCBmaXQucmFuZ2VzID0gVFJVRSwgZml0LnNpbGxzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmdtKHBzaWxsPTMsIG1vZGVsPSJNYXQiLCByYW5nZT04MDAwMCwgbnVnZ2V0PTAuMCkpDQoNCmBgYA0KDQpgYGB7cn0NCmRhdC5maXQNCmBgYA0KDQpgYGB7cn0NCiMgTGEgc2lndWllbnRlIGdyYWZpY2Egbm9zIHBlcm1pdGUgZGV0ZXJtaW5hciBlbCBhanVzdGUNCnBsb3QodmFyLnNtcGwsIGRhdC5maXQsIHhsaW09YygwLDEzMDAwMCkpDQpgYGANCg0KR2VuZXJhbW9zIHVuYSBzdXBlcmZpY2llIEtyaWdlZA0KDQpBIGNvbnRpbnVhY2nDs24sIHV0aWxpemFyZW1vcyBlbCBtb2RlbG8gZGUgdmFyaW9ncmFtYSBkYXQuZml0IHBhcmEgZ2VuZXJhciB1bmEgc3VwZXJmaWNpZSBpbnRlcnBvbGFkYSBrcmlnZWQuIExhIGZ1bmNpw7NuIGtyaWdlIG5vcyBwZXJtaXRlIGluY2x1aXIgZWwgbW9kZWxvIGRlIHRlbmRlbmNpYSwgbG8gcXVlIG5vcyBhaG9ycmEgdGVuZXIgcXVlIGVsaW1pbmFyIGxhIHRlbmRlbmNpYSBkZSBsb3MgZGF0b3MsIGtyaWdlIGxvcyByZXNpZHVvcyB5IGx1ZWdvIGNvbWJpbmFyIGxvcyBkb3MgcsOhc3RlcmVzLiBFbiBjYW1iaW8sIHRvZG8gbG8gcXVlIHRlbmVtb3MgcXVlIGhhY2VyIGVzIHBhc2FyIGEga3JpZ2UgbGEgZsOzcm11bGEgZGUgdGVuZGVuY2lhIGYuMS4NCg0KYGBge3J9DQojIERlZmluaW1vcyBlbCBtb2RlbG8gZGUgdGVuZGVuY2lhDQpmLjEgPC0gYXMuZm9ybXVsYShyYWQgfiBYICsgWSkgDQoNCiMgUmVhbGl6YW1vcyBsYSBpbnRlcnBvbGFjacOzbiBkZSBrcmlnZSANCmRhdC5rcmcgPC0ga3JpZ2UoIGYuMSwgYywgZ3JkLCBkYXQuZml0KQ0KYGBgDQoNCkNvbnZlcnRpcmVtb3MgbGEgc3VwZXJmaWNpZSBrcmlnZWQgZW4gdW4gb2JqZXRvIHJhc3RlciBwYXJhIHJlY29ydGFyDQoNCmBgYHtyfQ0KIyBDb252aWVydGltb3MgbGEgc3VwZXJmaWNpZSBrcmlnZWQgZW4gdW4gb2JqZXRvIHLDoXN0ZXIgcGFyYSByZWNvcnRhcg0KciA8LSByYXN0ZXIoZGF0LmtyZykNCnIubSA8LSByYXN0ZXI6Om1hc2sociwgYXJhdWNhMikNCmBgYA0KDQpgYGB7cn0NCnIubQ0KYGBgDQoNCmBgYHtyfQ0KIyBQbG90IHRoZSBtYXANCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49MTAsIHBhbGV0dGU9IlJlZHMiLCBhdXRvLnBhbGV0dGUubWFwcGluZz1GQUxTRSwgDQogICAgICAgICAgICB0aXRsZT0iSy5PIHVuaXZlcnNhbCBwYXJhIFJhZGlhY2nDs24gc29sYXIgW2tqIG1eLTIgZGlhXi0xXSIpICsNCiAgdG1fc2hhcGUoYykgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQoNClVuYSBtZWpvciB2aXN1YWxpemFjacOzbiBkZSBudWVzdHJhIHN1cGVyZmljaWUgZGUgaW50ZXJwb2xhZG8NCg0KYGBge3J9DQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCnBhbCA8LSBjb2xvck51bWVyaWMoYygiZGFya2JsdWUiLCAiYmx1ZSIsICJ5ZWxsb3ciLCAib3JhbmdlIiwgInJlZCIpLCB2YWx1ZXMoY2FyYm9yZy5tYXNrKSwNCiAgbmEuY29sb3IgPSAidHJhbnNwYXJlbnQiKQ0KDQpsZWFmbGV0KCkgJT4lIGFkZFRpbGVzKCkgJT4lDQogIGFkZFJhc3RlckltYWdlKHIubSwgY29sb3JzID0gcGFsLCBvcGFjaXR5ID0gMC42KSAlPiUNCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gdmFsdWVzKHIubSksDQogICAgdGl0bGUgPSAiSW50ZXJwb2xhY2nDs24gcG9yIEsuTyBlbiBBcmF1Y2EgbWVkaWRvIGVuIFtraiBtXi0yIGRpYV4tMV0gIikNCmBgYA0KDQoqKipHZW5lcmFtb3MgbG9zIG1hcGFzIGRlIGludGVydmFsbyBkZSBjb25maWFuemEgeSB2YXJpYW56YSoqKg0KDQpFbCBvYmpldG8gZGF0LmtyZyBhbG1hY2VuYSBubyBzb2xvIGxvcyB2YWxvcmVzIGludGVycG9sYWRvcywgc2lubyB0YW1iacOpbiBsb3MgdmFsb3JlcyBkZSB2YXJpYW56YS4gRXN0b3Mgc2UgcHVlZGVuIHBhc2FyIGFsIG9iamV0byByw6FzdGVyIHBhcmEgZWwgbWFwZW8gZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KYGBge3J9DQpyICAgPC0gcmFzdGVyKGRhdC5rcmcsIGxheWVyPSJ2YXIxLnZhciIpDQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIGFyYXVjYTIpDQoNCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49NywgcGFsZXR0ZSA9IlJlZHMiLA0KICAgICAgICAgICAgdGl0bGU9IkludGVycG9sYWNpw7NuIHBvciBLLk8vTWFwYSBkZSB2YXJpYW56YSBlbiBuW2tqIG1eLTIgZGlhXi0xXSApIikgK3RtX3NoYXBlKGMpICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KDQpVbiBtYXBhIG3DoXMgZsOhY2lsbWVudGUgaW50ZXJwcmV0YWJsZSBlcyBlbCBtYXBhIGRlbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlbCA5NSUgcXVlIHNlIHB1ZWRlIGdlbmVyYXIgYSBwYXJ0aXIgZGVsIG9iamV0byBkZSB2YXJpYW56YSBkZSBsYSBzaWd1aWVudGUgbWFuZXJhIChsb3MgdmFsb3JlcyBkZWwgbWFwYSBkZWJlbiBpbnRlcnByZXRhcnNlIGNvbW8gZWwgbsO6bWVybyBkZSBba2ogbV4tMiBkaWFeLTFdIHBvciBlbmNpbWEgeSBwb3IgZGViYWpvIGRlIGxhIGNhbnRpZGFkIGRlIHJhZGlhY2nDs24gc29sYXIgZXN0aW1hZGEpLg0KDQpgYGB7cn0NCnIgICA8LSBzcXJ0KHJhc3RlcihkYXQua3JnLCBsYXllcj0idmFyMS52YXIiKSkgKiAxLjk2DQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIGFyYXVjYTIpDQoNCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49NywgcGFsZXR0ZSA9IlJlZHMiLA0KICAgICAgICAgICAgdGl0bGU9IktyaWdpbmcgSW50ZXJwb2xhdGlvblxuOTUlIENJIG1hcCBcbihlbiBba2ogbV4tMiBkaWFeLTFdICkiKSArdG1fc2hhcGUoYykgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQoNCiMjIyMgVGhpZXNzZW4gcG9saWdvbm9zDQoNCkxvcyBwb2xpZ29ub3MgZGUgVGhpZXNzZW4gcHVlZGVuIHNlciBjcmVhZG9zIHVzYW5kbyBsYSBmdW5jaW9uIGRpcmljaGxldCBkZSBzcGF0c3RhdA0KDQpQcmltZXJvIGNyZWFyZW1vcyB1bmEgc3VwZXJmaWNpZSB0ZXNlbGFkYQ0KDQpgYGB7cn0NCiMgQ3JlYW1vcyB1bmEgc3VwZXJmaWNpZSB0ZXNlbGFkYQ0KdGggIDwtICBhcyhkaXJpY2hsZXQoYXMucHBwKGNhcmJvcmcyKSksICJTcGF0aWFsUG9seWdvbnMiKQ0KDQojIExhIGZ1bmNpw7NuIGRpcmljaGxldCBubyB0cmFuc2ZpZXJlIGluZm9ybWFjacOzbiBkZSBwcm95ZWNjacOzbg0KIyBFcyBuZWNlc2FyaW8gcXVlIGVzdGEgaW5mb3JtYWNpw7NuIHNlYSBhZ3JlZ2FkYSBtYW51YWxtZW50ZQ0KY3JzKHRoKSA8LSBjcnMoY2FyYm9yZzIpDQpjcnMoYXJhdWNhMikgPC0gY3JzKGNhcmJvcmcyKQ0KYGBgDQoNCmBgYHtyfQ0KY3JzKHRoKQ0KYGBgDQoNCmBgYHtyfQ0KY3JzKGNhcmJvcmcyKQ0KYGBgDQoNCkxhIHN1cGVyZmljaWUgdGVzZWxhZGEgbm8gYWxtYWNlbmEgaW5mb3JtYWNpw7NuIGRlIGF0cmlidXRvcyBkZSBsYSBjYXBhIGRlIGRhdG9zIGRlIHB1bnRvcy4gVXNhcmVtb3MgbGEgZnVuY2nDs24gb3ZlciAoKSAoZGVsIHBhcXVldGUgc3ApIHBhcmEgdW5pciBsb3MgYXRyaWJ1dG9zIGRlIHB1bnRvIGEgbGEgc3VwZXJmaWNpZSB0ZXNlbGFkYSBtZWRpYW50ZSB1bmEgdW5pw7NuIGVzcGFjaWFsLiBMYSBmdW5jacOzbiBvdmVyICgpIGNyZWEgdW4gbWFyY28gZGUgZGF0b3MgcXVlIG5lY2VzaXRhcsOhIHNlciBhZ3JlZ2FkbyBhbCBvYmpldG8gYHRoYCBjcmVhbmRvIGFzw60gdW4gb2JqZXRvDQoNCmBgYHtyfQ0KdGgueiAgICAgPC0gb3Zlcih0aCwgY2FyYm9yZzIsIGZuPW1lYW4pDQp0aC5zcGRmICA8LSAgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lKHRoLCB0aC56KQ0KDQojUmVjb3J0YXJlbW9zIGxhIHN1cGVyZmljaWUgdGVzZWxhZGENCnRoLmNscCAgIDwtIHJhc3Rlcjo6aW50ZXJzZWN0KGFyYXVjYTIsdGguc3BkZikNCmBgYA0KDQpgYGB7cn0NCiMgTWFwZWFtb3MgbG9zIGRhdG9zDQp0bV9zaGFwZSh0aC5jbHApICsgDQogIHRtX3BvbHlnb25zKGNvbD0icmFkIiwgcGFsZXR0ZT0iUmVkcyIsIG1pZHBvaW50PTMuMCwNCiAgICAgICAgICAgICAgdGl0bGU9IlRoaWVzc2VuIFBvbHlnb25zIFxuRXN0aW1hY2nDs24gcmFkaWFjacOzbiBzb2xhciBcbihlbiBba2ogbV4tMiBkaWFeLTFdKSIpICsNCiAgdG1fbGVnZW5kKGxlZ2VuZC5vdXRzaWRlPVRSVUUpDQoNCmBgYA0KDQojIyA0LkludGVycHJldGFjacOzbiBkZSByZXN1bHRhZG9zDQoNCkxvcyBwcm9jZXNvcyBkZSBpbnRlcnBvbGFjacOzbiB0cmFiYWphZG9zIGVuIGxhIHByZXNlbnRlIGEgcGFydGlyIGRlIFIgbG9ncmFyb24gYWNsYXJhciB5IGRlbm90YXIgbGEgY29uY2VwY2nDs24gZGUgYW7DoWxpc2lzIGRlIGRhdG9zIGdlb2VzcGFjaWFsZXMsIEF1bnF1ZSBsb3MgMyBtw6l0b2RvcyBkZSBpbnRlcnBvbGFjacOzbiB0cmFiYWphZG9zIGxvZ3Jhcm9uIGFycm9qYXIgcmVzdWx0YWRvcyBzw61taWxlcywgcG9kZW1vcyBhZmlybWFyIHF1ZSBjaWVydG9zIG3DqXRvZG9zIGZ1ZXJvbiBtw6FzIHByZWNpc29zIHF1ZSBvdHJvcy4gTG9zIGRhdG9zIGludGVycG9sYWRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIGxvZ3Jhcm9uIG1vc3RyYXIgY29tbyBleGlzdGVuIHVub3MgdmFsb3JlcyBkZSByYWRpYWNpw7NuIG1hcyBhbHRvcyBlbiBsb3MgbXVuaWNpcGlvcyBkZSBBcmF1cXVpdGEsIHB1ZXJ0byByb25kw7NuLCBBcmF1Y2EgeSBDcmF2byBub3J0ZSwgZW4gZG9uZGUgZGVzdGFjYSBlbCBtdW5pY2lwaW8gY3Jhdm8gbm9ydGUsIGVsIGN1YWwgcG9zZWUgbG9zIHZhbG9yZXMgbcOhcyBhbHRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHkgZXMgZGUgbG9zIG11bmljaXBpb3MgZG9uZGUgbGEgcHJvZHVjY2nDs24gZGUgcGzDoXRhbm8geSB0dWLDqXJjdWxvcyBlcyBtw61uaW1hOyBQb3Igb3RybyBsYWRvLCBsb3MgbXVuaWNpcGlvcyBkb25kZSBzZSBjb25jZW50cmEgbGEgbWF5b3IgcHJvZHVjY2nDs24gZGUgcGzDoXRhbm8gZW4gZWwgZGVwYXJ0YW1lbnRvIGRlIEFyYXVjYSB0aWVuZW4gdmFsb3JlcyBtw6FzIGJham9zIGRlIHJhZGlhY2nDs24gc29sYXIgY29tbyBsbyBlcyBUYW1lIHkgRm9ydHVsLg0KDQojIyMgNC4xIElEVw0KDQpBbCBhcGxpY2FyIGVsIG3DqXRvZG8gSURXIGV2aWRlbmNpYW1vcyB1biBwcm9jZXNvIHZpZ29yb3NvIGRlIGludGVycG9sYWRvIGVuIGN1YW50byBlc3RlIG3DqXRvZG8gZnVlIGNhcGFzIGRlIGFycm9qYXIgcGxvdGVvcyBjb24gdHJhbnNpY2lvbmVzIGRlIHZhbG9yZXMgZW50cmUgY2VsZGFzIG5vIHRhbiBhYnJ1cHRvcywgZXMgZGVjaXIsIHNpZ3VlbiB1bmEgdGVuZGVuY2lhIGNsYXJhLCBwZXNlIGEgdXNhciB1biB2YWxvciBkZSBwb3RlbmNpYSBkZSAyLiBOdWVzdHJhIGRpZmVyZW5jaWEgZGUgbG9zIHZhbG9yZXMgZXN0aW1hZG9zIHNvYnJlIGxvcyBvYnNlcnZhZG9zIGluZGljYSB1biBjaWVydG8gZ3JhZG8gZGUgcHJlY2lzacOzbiwgc2luIGVtYmFyZ28sIGxhIGRlc3ZpYWNpw7NuIGRlIGVzdG9zIGdlbmVyYSB1biB2YWxvciBkZSBpbmNlcnRpZHVtYnJlIGNvbnNpZGVyYWJsZTsgU8OtIGJpZW4gcHVlZGUgdmVyc2UgcXVlIGVudHJlIGxvcyBkb3MgaGF5IHVuYSB0ZW5kZW5jaWEgbMOtbmVhIGNyZWNpZW50ZSwgbm8gZXhpc3RlIHVuYSBleGFjdGl0dWQgdG90YWwgcHVlc3RvIHF1ZSBzZSBlc3RhIGhhY2llbmRvIHVuIHByb2Nlc28gZGUgaW50ZXJwb2xhZG8gZW4gdW4gw6FyZWEgbXV5IGdyYW5kZSBwYXJhIGxvcyBwb2NvcyBwdW50b3MgZGUgbXVlc3RyYSB0b21hZG9zLg0KDQojIyMgNC4yIEtyaWdpbmcNCg0KRWwgbcOpdG9kbyBrcmlnaW5nIGEgcGFydGlyIGRlbCBzZW1pdmFyaW9ncmFtYSB5IGVsIG1vZGVsbyBkZSBhanVzdGUsIGxvZ3Jhcm9uIG1vc3RyYXIgY29uIGVmaWNhY2lhIHF1ZSBsYXMgb2JzZXJ2YWNpb25lcyBlc3RpbWFkYXMgdGllbmVuIHVuYSBjb3JyZWxhY2nDs24gYWx0YSBjb24gbGFzIG9ic2VydmFjaW9uZXMgcHJvcHVlc3RhcyBlbiBjYW1wbywgbG8gcXVlIGxvIGhhY2UgZGUgbG9zIG1lam9yZXMgbcOpdG9kb3MgZGUgaW50ZXJwb2xhZG8gdXNhZG9zIGVuIGVzdGUgaW5mb3JtZSwgZ3JhY2lhcyBhbCBhbGdvcml0bW8gcHJvcHVlc3RvIHBvciBrcmlnaW5nIHNlIGdlbmVyYXJvbiByZXByZXNlbnRhY2lvbmVzIGEgZXNjYWxhcyBkZSBjb2xvcmVzIHF1ZSBwZXJtaXTDrWFuIHZlciBmw6FjaWxtZW50ZSBxdWUgem9uYXMgZGVsIGRlcGFydGFtZW50byB0ZW7DrWFuIHZhbG9yZXMgbcOhcyBhbHRvcyBkZSByYWRpYWNpw7NuIHNvbGFyLiBFbCB2YXJpb2dyYW1hIHN1bWluaXN0cmFkbyBwYXJhIG51ZXN0cm9zIGRhdG9zIGRlIHJhZGlhY2nDs24gc29sYXIgcHJlc2VudGEgdW4gY29tcG9ydGFtaWVudG8gbG9nYXLDrXRtaWNvLCBwZXNlIGEgcXVlIGVzdGUgbcOpdG9kbyBkZSBpbnRlcnBvbGFkbyBmdWUgZWZpY2F6LCBlbCBtYXBhIGRlIG5pdmVsIGRlIGluY2VydGlkdW1icmUgYXJyb2pvIHZhbG9yZXMgbcOhcyBhbHRvcyBlbiBjb21wYXJhY2nDs24gYWwgbcOpdG9kbyBJRFcgY29uIHZhbG9yZXMgb3NjaWxhbnRlcyBlbnRyZSAyIHkgMy4NCg0KIyMjIDQuMyBQb2xpZ29ub3MgZGUgVGhpZXNzZW4NCg0KSW50ZXJwb2xhbmRvIGNvbiBlbCBtw6l0b2RvIGRlIHBvbMOtZ29ub3MgZGUgVGhpZXNzZW4gcG9kZW1vcyB2ZXIgcXVlIGxvcyBwb2zDrWdvbm9zIHNlIGVuY3VlbnRyYW4gYSB1bmEgbWlzbWEgbWVkaWRhLCBkZWJpZG8gYSBxdWUgbG9zIHB1bnRvcyBkZSBtdWVzdHJhIHNlIGVuY3VlbnRyYW4gdW5pZm9ybWVtZW50ZSBkaXN0cmlidWlkb3MgZXNwYWNpYWxtZW50ZSwgcGVzZSBhIHF1ZSBubyB0ZW5lbW9zIHVuIGluZGljYXRpdm8gZGUgaW5jZXJ0aWR1bWJyZSwgcG9kZW1vcyBjb25jbHVpciBxdWUgZnVlIGVsIG3DqXRvZG8gbWVub3MgZXhhY3RvIGRlIGxvcyB0cmFiYWphZG9zLCBubyBlcyB1biBtw6l0b2RvIGNvbiB1bmEgY29tcGxlamlkYWQgYWx0YSB5IHByZXNlbnRhIHRyYW5zaWNpb25lcyBlbnRyZSBwb2zDrWdvbm9zIGFicnVwdGFzIHkgcG9jbyBzdXRpbGVzLg0KDQojIyBDb25jbHVzaW9uZXMNCg0KRmluYWxtZW50ZSBwb2RlbW9zIGNvbmNsdWlyIHF1ZSBsbyBpbnRlcmVzYW50ZSBkZSBpbnRlcnBvbGFyIHNlIGVuY3VlbnRyYSBlbiBxdWUgbG9zIGRhdG9zIGNvbiB1bmEgZGlzdHJpYnVjacOzbiBlc3BhY2lhbCwgc2UgZW5jdWVudHJhbiBjb3JyZWxhY2lvbmFkb3MgZW50cmUgc2ksIGVzIGRlY2lyLCBsb3MgdmFsb3JlcyBxdWUgZXN0w6FuIGNlcmNhIHRpZW5kZW4gYSB0ZW5lciBjYXJhY3RlcsOtc3RpY2FzIHNpbWlsYXJlcy4gRWwgcHJvdmVjaG8gZGUgaW50ZXJwb2xhciBlbiBjdWFudG8gYSBzdSBwcmVjaXNpw7NuIGRlcGVuZGUgbm8gc29sbyBkZWwgbcOpdG9kbyBxdWUgdXNhcmVtb3MsIHNpbm8gYWRlbcOhcywgZGUgc3UgcmVzb2x1Y2nDs24gZXNwYWNpYWwgeSBsYSBkZW5zaWRhZCBkZSBwdW50b3MgZGUgbXVlc3RyYSBxdWUgdGVuZ2Ftb3MuIExhIHByZXNlbnRlIGV2YWx1w7MgMyBtw6l0b2RvcyBkZSBpbnRlcnBvbGFjacOzbiBkb25kZSBzZSBkZXN0YWNhIElEVywgS3JpZ2luZyB5IHBvbMOtZ29ub3MgZGUgVGhpZXNzZW4sIHVzYW5kbyBkYXRvcyBkZSByYWRpYWNpw7NuIHNvbGFyIHBhcmEgZWwgZGVwYXJ0YW1lbnRvIGRlIEFyYXVjYTsgRG9uZGUgc2UgcHVkbyBvYnNlcnZhciBxdWUgZWwgbcOpdG9kbyBtYXMgZmlhYmxlIHBhcmEgbG9zIGRhdG9zIHRyYXRhZG9zIGZ1ZSBlbCBtw6l0b2RvIGRlIGxhIHBvbmRlcmFjacOzbiBkZSBkaXN0YW5jaWEgaW52ZXJzYSAoSURXKSBwdWVzdG8gcXVlIG5vcyBzdW1pbmlzdHLDsyBpbmZvcm1hY2nDs24gZGUgbGEgZGlzdHJpYnVjacOzbiBkZSB2YWxvcmVzIGRlIHJhZGlhY2nDs24gc29sYXIgYSBsbyBsYXJnbyBkZWwgZGVwYXJ0YW1lbnRvIGNvbiBlbCB2YWxvciBtw6FzIGJham8gZGUgaW5jZXJ0aWR1bWJyZSByZXNwZWN0byBkZSBsb3MgZGVtw6FzIG3DqXRvZG9zIHRyYWJhamFkb3MuDQpFbiBlbCBwcm9jZXNvIHNlIGV2aWRlbmNpbyBxdWUgbG9zIG11bmljaXBpb3MgZGUgVGFtZSwgRm9ydHVsIHkgU2FyYXZlbmEgcG9zZWVuIHZhbG9yZXMgbWFzIGJham9zIGRlIFJhZGlhY2nDs24gc29sYXIsIGVzdG9zIGRlcGFydGFtZW50b3MsIHNvbiBxdWllbmVzIHByZWRvbWluYW4gcHJvZHVjdGl2YW1lbnRlIGVuIGVsIGRlcGFydGFtZW50bywgbWllbnRyYXMgcXVlIGxvcyBkZXBhcnRhbWVudG9zIGRlIFB1ZXJ0byByb25kw7NuLCBBcmF1cXVpdGEsIENyYXZvIG5vcnRlIHkgQXJhdWNhIHBvc2VlbiBsb3MgdmFsb3JlcyBtYXMgYWx0b3MgZGUgcmFkaWFjacOzbiBzb2xhciB5IGEgc3UgdmV6IHNvbiBsb3MgbXVuaWNpcGlvcyBjb24gdW5hIG1lbm9yIHRhc2EgZGUgcHJvZHVjdGl2aWRhZCBhZ3JhcmlhLg0KDQojIyBSZWZlcmVuY2lhcw0KDQpDdWVuY2FyLCBKLiBBcmF1Y2EgQ29sb21iaWEgZ3XDrWEgdHVyw61zdGljYS4gQWRhcHRhZG8gZGU6IGh0dHBzOi8vY2VvLnVuaWFuZGVzLmVkdS5jby9pbWFnZXMvRG9jdW1lbnRvcy9HdSVDMyVBRGElMjB0dXIlQzMlQURzdGljYSUyMEFyYXVjYS5wZGYNCg0KSURFQU0uICgyMDE0KS4gTGEgaW1wb3J0YW5jaWEgZGUgbGEgcmFkaWFjacOzbiBzb2xhci4gQWRhcHRhZG8gZGU6IGh0dHA6Ly93d3cuaWRlYW0uZ292LmNvL3dlYi90aWVtcG8teS1jbGltYS9yYWRpYWNpb24tc29sYXItdWx0cmF2aW9sZXRhDQoNCkJhcnJlcmEsIEouIENhcmRvbmEsIEMuIENhecOzbiwgRC4gKDIwMTEpLiBFbCBjdWx0aXZvIGRlIHBsw6F0YW5vIChNVVNBIEFBQiBTSU1NT05EUykgZWNvZmlzaW9sb2fDrWEgeSBtYW5lam8gY3VsdHVyYWwgc29zdGVuaWJsZS4gQWRhcHRhZG8gZGU6IGh0dHBzOi8vZWRpdG9yaWFsemVudS5jb20vaW1hZ2VzLzE0Njc4MzM1NDEucGRmDQoNCkFyY0dJUy4gKDIwMTYpLiBWaXN0YSBnZW5lcmFsIGRlbCBjb25qdW50byBkZSBoZXJyYW1pZW50YXMgSW50ZXJwb2xhY2nDs24uIEFkYXB0YWRvIGRlOiBodHRwczovL2Rlc2t0b3AuYXJjZ2lzLmNvbS9lcy9hcmNtYXAvMTAuMy90b29scy9zcGF0aWFsLWFuYWx5c3QtdG9vbGJveC9hbi1vdmVydmlldy1vZi10aGUtaW50ZXJwb2xhdGlvbi10b29scy5odG0NCg0KDQo=