INTRODUCCIÓN

La interpolación sirve para predecir valores para las celdas de un ráster a partir de una cantidad limitada de puntos de datos de muestra. Esta herramienta se puede utilizar para prever valores que no se conocen de cualquier dato de un punto geográfico como por ejemplo la elevación y precipitación.

Las herramientas de interpolación de superficie crean una superficie continua (o predicción) a partir de valores de punto de muestra. Lo anterior se hace viable cuando se hace la suposición de que los objetos distribuidos espacialmente están correlacionados espacialmente, o sea, las cosas que están cerca, tienden a parecerce. Así, los puntos cercanos a los puntos de muestra, tienen más posibilidades de ser más similares que los que están más alejados. Para esto, existen diferentes maneras de derivar una predicción para cada ubicación; cada método se denomina modelo. Con cada modelo, se realizan diferentes suposiciones acerca de los datos, y algunos modelos son más aplicables para determinados datos y cada uno produce predicciones usando diferentes cálculos.

En el presente trabajo, se realizarán 3 métodos de interpolación los cuales se describen a continuación:

Kriggin: Interpola una superficie de ráster a partir de puntos IDW: Interpola una superficie de ráster a partir de puntos utilizando una técnica de distancia inversa ponderada

IDW: Interpola una superficie de ráster a partir de puntos utilizando una técnica de distancia inversa ponderada

Polígonos de Thiessen: Se basa en considerar que los puntos de una zona coinciden con el valor medido más próximo y generan, como consecuencia, zonas de influencia siendo el resultado la unión de polígonos que generan distintas zonas temáticas

library(tidyverse)
library(sf)

DESCRIPCIÓN DE LA ZONA DE ESTUDIO

El departamento de Boyacá está situado en el centro del país, en la cordillera oriental de los Andes; localizado entre los 04°39′10″ y los 07°03′17″ de latitud norte y los 71°57′49″ y los 74°41’35″ de longitud oeste. Cuenta con una superficie de 23 189 km², lo que representa el 2,03 % del territorio nacional. Limita por el norte con los departamentos de Santander y norte de Santander, por el este con los departamentos de Arauca, Casanare y con el país vecino de Venezuela, por el sur con Cundinamarca, y por el oeste con Cundinamarca, Caldas y Antioquia.

a continuacion podra ver la ubicacion en el mapa nacional:

colmap<-  read_sf("C:/Users/David Perdomo/Desktop/Geomatica/COL_adm/COL_adm1.shp")
st_crs(colmap)
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]
ggplot() + geom_sf(data = colmap) + coord_sf(crs=st_crs(3978))

boyaca <-  colmap %>%   filter(NAME_1 == "Boyacá")
ggplot() + geom_sf(data = boyaca) 

Hidrografia de Boyacá

El sistema hidrográfico de Boyacá está constituido por numerosos ríos y quebradas que nacen en la cordillera Oriental, afluentes directos o de alguno de los tributarios de los ríos Magdalena, Meta y Arauca; entre los ríos que confluyen a la cuenca del Magdalena están el Ermitaño, Negro, Minero, Suárez, Sutamanchán, Sáchica, Chíquiza, Iguaque, Arcabuco o Pómeca, Ubazá, Riachuelo, Moniquirá, Chicamocha, Chorrera, Tuta, Pesca, Tota, Saguera, Sasa, Cambas, Loblanco, Rechiminiga, Chitano, Susacón.

Actividades Economicas de Boyacá:

La economía de Boyacá se basa principalmente en la producción agrícola y ganadera, la explotación de minerales, la industria siderúrgica, el comercio y el turismo. La agricultura se ha desarrollado y tecnificado en los últimos años; los principales cultivos son papa, maíz, cebolla, trigo, cebada, caña panelera, yuca. Existen en Boyacá alrededor de 6.800 explotaciones mineras, en su mayoría de carácter artesanal, principalmente de carbón coquizable, arcilla, roca fosfórica, arena, yeso, mármol y caliza de hierro; el carbón extraído técnicamente tienen reservas importantes en 19 municipios.

El petróleo se encuentra en el territorio Vásquez; en el occidente se explotan las esmeraldas consideradas las más famosas del mundo por su calidad y belleza. La producción artesanal es muy laboriosa especialmente en cerámica, tejidos de lana de oveja y fique, tagua, tapices, instrumentos musicales y cestería, entre otros

Clima de Boyacá:

El Clima del departamento de Boyacá está determinado principalmente por su relieve y posición geográfica, dando como resultado, que se presenten todos los pisos térmicos desde el nival, en la sierra nevada del Cocuy, hasta el cálido, en el Territorio Vásquez y la vertiente oriental de la cordillera Oriental.

El departamento presenta una alta variabilidad territorial en la distribución de la precipitación. Las áreas con menores lluvias, de 500 a 1000 mm anuales, se localizan a lo largo del altiplano cundiboyacense y a partir de esta zona las lluvias se incrementan tanto al oriente como al occidente del departamento. Al oriente ocurren las lluvias orográficas correspondientes a la vertiente oriental de la cordillera oriental, registrando valores en el rango de 2000 a más de 5000 mm. Al occidente, en dirección al valle del Magdalena, las lluvias oscilan entre 2000 y 3000 mm al año.

Divición Administrativa de Boyacá:

El departamento de Boyacá está dividido en 123 municipios, los cuales se agrupan en 12 provincias: Sugamuxi, Tundama, Valderrama, Norte, Gutierrez, Centro, Neira, Oriente, Lengupa, Ricaurte, Marquez y Occidente.

DATOS Y METODOS:

Tecnicas de Interpolacion a usar:

Kriging: Es una herramienta de interpolación que basicamente interpola una superficie de ráster a partir de puntos. Kriging presupone que la distancia o la dirección entre los puntos de muestra reflejan una correlación espacial que puede utilizarse para explicar la variación en la superficie. Además ajusta una función matemática a una cantidad especificada de puntos o a todos los puntos dentro de un radio específico para determinar el valor de salida para cada ubicación. Pondera los valores medidos circundantes para calcular una predicción de una ubicación sin mediciones, estas ponderaciones están basadas no solo en la distancia entre los puntos medidos y la ubicación de la predicción, sino también en la disposición espacial general de los puntos medidos. Para utilizar la disposición espacial en las ponderaciones, la correlación espacial debe estar cuantificada. Por lo tanto, en un kriging ordinario, la ponderación depende de un modelo ajustado a los puntos medidos, la distancia a la ubicación de la predicción y las relaciones espaciales entre los valores medidos alrededor de la ubicación de la predicción.

IDW: La interpolación mediante distancia inversa ponderada es útil para determiar los valores de celda mediante una combinación ponderada linealmente de un conjunto de puntos de muestra. La ponderación es una función de la distancia inversa. La superficie que se interpola debe ser la de una variable dependiente de la ubicación. Así mismo, este método presupone que la variable que se representa cartográficamente disminuye su influencia a mayor distancia desde su ubicación de muestra, es decir, asume que los valores más cercanos están más relacionados que otros con su función. IDW es un método de interpolación espacial muy flexible ya que se puede configurar la interpolación de diferentes maneras, pues se puede espicificar el radio de búsqueda y la interpolación sólo utilizará el número de puntos conocidos dentro del radio de búsqueda. También se pueden establecer barreras. Si hay crestas en un perfil de elevación, o barreras de ruido, entonces estos son ejemplos apropiados para usar una barrera. Esta barrera de polilínea impide buscar los puntos de entrada de la muestra.

Polígonos de Thiessen: La interpolación de áreas utiliza el concepto de polígonos de Thiessen para dibujar límites en torno a las áreas que tienen el mismo valor. Este tipo de interpolador se llama interpolador proximal. Esta técnica construye polígonos mediante la asignación por cada punto de un área de interés un valor del punto de muestra que sea más cercano. Crea superficies escalonadas, donde los valores pueden cambiar drásticamente en distancias cortas, es decir, un valor estimado está representado dentro del área de cada polígono. Una vez descargado el archivo CHIRPS, leerlo sin comprimir:

library(tmap)
library(gstat)
library(sp)
library(knitr)
library(rgdal)
library(raster)
library(sf)
library(tidyverse)
precip <- raster("C:/Users/David Perdomo/Desktop/Geomatica/tif/chirps-v2.0.2020.10.6.tif") 

Como ya habrá notado, este archivo representa la precipitación acumulada en los últimos días de octubre de 2020, es decir, la precipitación del 26 al 31 de octubre.

precip
class      : RasterLayer 
dimensions : 2000, 7200, 14400000  (nrow, ncol, ncell)
resolution : 0.05, 0.05  (x, y)
extent     : -180, 180, -50, 50  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs 
source     : C:/Users/David Perdomo/Desktop/Geomatica/tif/chirps-v2.0.2020.10.6.tif 
names      : chirps.v2.0.2020.10.6 

Tenga en cuenta que este es un conjunto de datos con cobertura global. Su CRS es un sistema de coordenadas geográficas.

Carguemos un shapefile que represente nuestra área de interés

(aoi <- shapefile("C:/Users/David Perdomo/Desktop/Geomatica/15_BOYACA/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 123 
extent      : -74.66496, -71.94885, 4.655196, 7.055557  (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  :         15,      15001,    ALMEIDA,                               1537,   25.35271459,      2017,    BOYACÁ, 0.204497978002, 0.00206924119091 
max values  :         15,      15897, ZETAQUIRÁ, Ordenanza 8 de Diciembre 4 de 1965, 1513.60104233,      2017,    BOYACÁ,  2.40391520946,   0.123609862522 

Tenga en cuenta que los sistemas de referencia de coordenadas para ambos conjuntos de datos son los mismos.

Ahora, recortemos los datos de precipitación:

precip.crop <- raster::crop(precip, extent(aoi))
precip.mask <- mask(x = precip.crop, mask = aoi)
precip.mask 
class      : RasterLayer 
dimensions : 48, 54, 2592  (nrow, ncol, ncell)
resolution : 0.05, 0.05  (x, y)
extent     : -74.65, -71.95, 4.649999, 7.049999  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs 
source     : memory
names      : chirps.v2.0.2020.10.6 
values     : 12.18011, 95.86112  (min, max)

Trace la capa ráster enmascarada:

plot(precip.mask, main= "CHIRPS lluvia en Boyacá 2020 [mm]")
plot(aoi, add=TRUE)

Se puede hacer un mejor mapa con Leaflet usando la función addRasterImage:

library(leaflet)
package 㤼㸱leaflet㤼㸲 was built under R version 4.0.3
library(RColorBrewer)
package 㤼㸱RColorBrewer㤼㸲 was built under R version 4.0.3
pal <- colorNumeric(c("red", "orange", "yellow", "blue", "darkblue"), values(precip.mask),
  na.color = "transparent")

leaflet() %>% addTiles() %>%
  addRasterImage(precip.mask, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(precip.mask),
    title = "CHIRPS lluvia en Boyacá 2020 [mm]")
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_defsDiscarded datum WGS_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_defsDiscarded datum WGS_1984 in CRS definitionSome values were outside the color scale and will be treated as NA

NA

La conversión de ráster en puntos se puede realizar utilizando la función rasterToPoints de la biblioteca de ráster:

precip.points <- rasterToPoints(precip.mask, spatial = TRUE)
precip.points
class       : SpatialPointsDataFrame 
features    : 755 
extent      : -74.625, -71.975, 4.674999, 7.024999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       : chirps.v2.0.2020.10.6 
min values  :      12.1801061630249 
max values  :      95.8611221313477 
names(precip.points) <- "rain"
precip.points
class       : SpatialPointsDataFrame 
features    : 755 
extent      : -74.625, -71.975, 4.674999, 7.024999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :             rain 
min values  : 12.1801061630249 
max values  : 95.8611221313477 
str(precip.points)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 755 obs. of  1 variable:
  .. ..$ rain: num [1:755] 63.1 78.5 84.6 95.9 53.7 ...
  ..@ coords.nrs : num(0) 
  ..@ coords     : num [1:755, 1:2] -72.2 -72.1 -72.1 -72 -72.3 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "x" "y"
  ..@ bbox       : num [1:2, 1:2] -74.62 4.67 -71.97 7.02
  .. ..- 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"

Grafiquemos los puntos:

plot(precip.mask, main= "CHIRPS precipitaciones 2020 [mm]")
plot(aoi, add=TRUE)
points(precip.points$x, precip.points$y, col = "red", cex = .5)

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

Leamos los puntos de precipitación.

precip.points <- geojsonio::geojson_read("./chirps/ppoints.geojson", what="sp")
precip.points
class       : SpatialPointsDataFrame 
features    : 755 
extent      : -74.625, -71.975, 4.674999, 7.024999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :             rain 
min values  : 12.1801061630249 
max values  : 95.8611221313477 

¿Cuál es el punto de convertir datos de precipitación ráster en datos de precipitación puntual?

Bueno, hay pocas estaciones meteorológicas de la Organización Meteorológica Mundial (OMM) en nuestro país Por lo tanto, CHIRPS puede ser una opción para obtener los datos de precipitación puntual necesarios para obtener una superficie de precipitación continua.

ADICIONAL:

En caso de que se pierda la conexión, podemos volver a leer el shapefile con el área de interés:

(aoi <- shapefile("C:/Users/David Perdomo/Desktop/Geomatica/15_BOYACA/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 123 
extent      : -74.66496, -71.94885, 4.655196, 7.055557  (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  :         15,      15001,    ALMEIDA,                               1537,   25.35271459,      2017,    BOYACÁ, 0.204497978002, 0.00206924119091 
max values  :         15,      15897, ZETAQUIRÁ, Ordenanza 8 de Diciembre 4 de 1965, 1513.60104233,      2017,    BOYACÁ,  2.40391520946,   0.123609862522 

Necesitamos convertirlo en una característica espacial:

boya_sf <-  sf::st_as_sf(aoi)
(border_sf <-
  boya_sf %>%
  summarise(area = sum(MPIO_NAREA)))
Simple feature collection with 1 feature and 1 field
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -74.66496 ymin: 4.655196 xmax: -71.94885 ymax: 7.055557
geographic CRS: WGS 84
      area                       geometry
1 23138.05 POLYGON ((-73.03051 4.98230...

Convierta la característica espacial en un marco de datos espacial:

 (border <- as(border_sf, 'Spatial')) 
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : -74.66496, -71.94885, 4.655196, 7.055557  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs 
variables   : 1
names       :           area 
value       : 23138.04812969 
(boya.sf <- st_as_sf(aoi) %>% mutate(MUNIC = MPIO_CNMBR, CODIGO = MPIO_CCDGO) %>% select(MUNIC, CODIGO))
Simple feature collection with 123 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -74.66496 ymin: 4.655196 xmax: -71.94885 ymax: 7.055557
geographic CRS: WGS 84
First 10 features:
        MUNIC CODIGO                       geometry
1       TUNJA  15001 POLYGON ((-73.34014 5.58308...
2     ALMEIDA  15022 POLYGON ((-73.36793 5.01349...
3   AQUITANIA  15047 POLYGON ((-72.76242 5.63856...
4    ARCABUCO  15051 POLYGON ((-73.50487 5.84347...
5      BELÉN  15087 POLYGON ((-72.91692 6.08612...
6      BERBEO  15090 POLYGON ((-73.0677 5.27048,...
7  BETÉITIVA  15092 POLYGON ((-72.81796 5.97422...
8     BOAVITA  15097 POLYGON ((-72.64907 6.43640...
9  BOYACÃ\u0081  15104 POLYGON ((-73.34806 5.47411...
10   BRICEÑO  15106 POLYGON ((-73.89118 5.73749...

Ahora, intentaremos una tarea st_intersection. Esto se hace usando la biblioteca sf:

p.sf <- st_as_sf(precip.points)
(precip.sf = st_intersection(boya.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 755 features and 3 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -74.625 ymin: 4.674999 xmax: -71.975 ymax: 7.024999
geographic CRS: WGS 84
First 10 features:
        MUNIC CODIGO     rain                 geometry
122   CUBARÃ\u0081  15223 63.14175 POINT (-72.175 7.024999)
122.1 CUBARÃ\u0081  15223 78.48558 POINT (-72.125 7.024999)
122.2 CUBARÃ\u0081  15223 84.64105 POINT (-72.075 7.024999)
122.3 CUBARÃ\u0081  15223 95.86112 POINT (-72.025 7.024999)
122.4 CUBARÃ\u0081  15223 53.68439 POINT (-72.275 6.974999)
122.5 CUBARÃ\u0081  15223 60.33939 POINT (-72.225 6.974999)
122.6 CUBARÃ\u0081  15223 59.96722 POINT (-72.175 6.974999)
122.7 CUBARÃ\u0081  15223 62.04287 POINT (-72.125 6.974999)
122.8 CUBARÃ\u0081  15223 73.22034 POINT (-72.075 6.974999)
122.9 CUBARÃ\u0081  15223 84.24580 POINT (-72.025 6.974999)

Dos tareas de reproyección:

p.sf.magna <- st_transform(precip.sf, crs=3116)
boya.sf.magna <- st_transform(boya.sf, crs=3116)
(precip2 <- as(p.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definition,
 but +towgs84= values preservedDiscarded datum Marco_Geocentrico_Nacional_de_Referencia in CRS definition
class       : SpatialPointsDataFrame 
features    : 755 
extent      : 939360, 1232381, 1008778, 1269088  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 3
names       :      MUNIC, CODIGO,             rain 
min values  :    ALMEIDA,  15001, 12.1801061630249 
max values  : ZETAQUIRÁ,  15897, 95.8611221313477 

Nuevamente, podemos escribir el conjunto de datos intermedio

shapefile(precip2, filename='./chirps/precip2.shp', overwrite=TRUE)
precip2$rainfall <- round(precip2$rain, 1)
precip2
class       : SpatialPointsDataFrame 
features    : 755 
extent      : 939360, 1232381, 1008778, 1269088  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :      MUNIC, CODIGO,             rain, rainfall 
min values  :    ALMEIDA,  15001, 12.1801061630249,     12.2 
max values  : ZETAQUIRÁ,  15897, 95.8611221313477,     95.9 
(boya2 <- as(boya.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definition,
 but +towgs84= values preservedDiscarded datum Marco_Geocentrico_Nacional_de_Referencia in CRS definition
class       : SpatialPolygonsDataFrame 
features    : 123 
extent      : 934932.9, 1235253, 1006592, 1272398  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :      MUNIC, CODIGO 
min values  :    ALMEIDA,  15001 
max values  : ZETAQUIRÁ,  15897 
shapefile(boya2, filename='./chirps/boya2.shp', overwrite=TRUE)

Asegúrese de que las dos extensiones coincidan:

precip2@bbox <- boya2@bbox

Trazar los datos con tmap:

tm_shape(boya2) + tm_polygons() +
  tm_shape(precip2) +
  tm_dots(col="rainfall", palette = "RdBu", midpoint = 3.0,
             title="Precipitación muestreada \n(en mm)", size=0.2) +
  tm_text("rainfall", just="center", xmod=.6, size = 0.5) +
  tm_legend(legend.outside=TRUE)
CRS object has comment, which is lost in output

INTERPOLACIÓN DE DATOS DE PRECIPITACIÓN

1. polígonos de Thiessen

Los polígonos de Thiessen (o interpolación de proximidad) se pueden crear utilizando la función dirichlet de Spatstat.

library(spatstat.data)
package 㤼㸱spatstat.data㤼㸲 was built under R version 4.0.3
library(nlme)
package 㤼㸱nlme㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱nlme㤼㸲

The following object is masked from 㤼㸱package:dplyr㤼㸲:

    collapse

The following object is masked from 㤼㸱package:raster㤼㸲:

    getData
library(rpart)
library(gstat)
library(spatstat)
package 㤼㸱spatstat㤼㸲 was built under R version 4.0.3Registered S3 method overwritten by 'spatstat':
  method     from
  print.boxx cli 

spatstat 1.64-1       (nickname: 㤼㸱Help you I can, yes!㤼㸲) 
For an introduction to spatstat, type 㤼㸱beginner㤼㸲 


Note: spatstat version 1.64-1 is out of date by more than 7 months; we recommend upgrading to the latest version.

Attaching package: 㤼㸱spatstat㤼㸲

The following object is masked from 㤼㸱package:gstat㤼㸲:

    idw

The following objects are masked from 㤼㸱package:raster㤼㸲:

    area, rotate, shift
library(raster)
library(dplyr)
th  <-  as(dirichlet(as.ppp(precip2)), "SpatialPolygons")
crs(th) <- crs(precip2)
crs(boya2) <- crs(precip2)
crs(th) 
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
crs(precip2)
CRS arguments:
 +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +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 SpatialPolygonsDataFrame

th.z     <- over(th, precip2, fn=mean)
th.spdf  <-  SpatialPolygonsDataFrame(th, th.z)
th.clp   <- raster::intersect(boya2,th.spdf)
tm_shape(th.clp) + 
  tm_polygons(col="rainfall", palette="RdBu", midpoint=3.0,
              title="Polígonos de Thiessen \nPrecipitación prevista \n(en mm)") +
  tm_legend(legend.outside=TRUE)
CRS object has comment, which is lost in output

2. Interpolación ponderada de distancia inversa

Muchos paquetes comparten los mismos nombres de función. Esto puede ser un problema cuando estos paquetes se cargan en una misma sesión de R. Por ejemplo, la función de intersección está disponible en los paquetes base, Spatstat y Ráster, todos los cuales se cargan en esta sesión actual. Para asegurarse de que se selecciona la función adecuada, es una buena idea anteponer el nombre de la función con el nombre del paquete como en raster :: intersect ().

Esta sugerencia se utilizará en el siguiente fragmento de código cuando se llame a la función idw que está disponible tanto en Spatstat como en Gstat.

Tenga en cuenta que la función dirichlet (como la mayoría de las funciones del paquete spatsat) requiere que el objeto de punto esté en formato ppp, de ahí la sintaxis as.ppp (precip2) en línea.

La salida IDW es un ráster. Esto requiere que primero creemos una cuadrícula ráster vacía, luego interpolemos los valores de precipitación en cada celda de la cuadrícula sin muestrear. Se utilizará un valor de potencia IDW de 2 (idp = 2,0).


grd              <- as.data.frame(spsample(precip2, "regular", n=100000))

names(grd)       <- c("X", "Y")
coordinates(grd) <- c("X", "Y")
gridded(grd)     <- TRUE  # Create SpatialPixel object
fullgrid(grd)    <- TRUE  # Create SpatialGrid object
proj4string(grd) <- proj4string(precip2)
P.idw <- gstat::idw(rainfall ~ 1, precip2, newdata=grd, idp=2.0)
r       <- raster(P.idw)
r
class      : RasterLayer 
dimensions : 297, 336, 99792  (nrow, ncol, ncell)
resolution : 893.4599, 893.4599  (x, y)
extent     : 935181.8, 1235384, 1006720, 1272077  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 12.85712, 95.76158  (min, max)
boya2
class       : SpatialPolygonsDataFrame 
features    : 123 
extent      : 934932.9, 1235253, 1006592, 1272398  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :      MUNIC, CODIGO 
min values  :    ALMEIDA,  15001 
max values  : ZETAQUIRÁ,  15897 
r.m   <- raster::mask(r, boya2)
r.m 
class      : RasterLayer 
dimensions : 297, 336, 99792  (nrow, ncol, ncell)
resolution : 893.4599, 893.4599  (x, y)
extent     : 935181.8, 1235384, 1006720, 1272077  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 12.85712, 95.76158  (min, max)
tm_shape(r.m) + 
  tm_raster(n=10,palette = "RdBu", auto.palette.mapping = FALSE,
            title="Distancia inversa ponderada \nPrecipitación prevista \n(en mm)") + 
  tm_shape(precip2) + 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 la superficie interpolada:

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

leaflet() %>% addTiles() %>%
  addRasterImage(r.m, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(r.m),
    title = "IDW precipitación interpolada en Boyacá 2020 [mm]")
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_defsDiscarded datum WGS_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_defsDiscarded datum WGS_1984 in CRS definition

2.1 Ajuste de 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.

precip2
class       : SpatialPointsDataFrame 
features    : 755 
extent      : 934932.9, 1235253, 1006592, 1272398  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :      MUNIC, CODIGO,             rain, rainfall 
min values  :    ALMEIDA,  15001, 12.1801061630249,     12.2 
max values  : ZETAQUIRÁ,  15897, 95.8611221313477,     95.9 
P <- precip2
IDW.out <- vector(length = length(P))
for (i in 1:length(P)) {
  IDW.out[i] <- gstat::idw(rainfall ~ 1, P[-i,], P[i,], idp=6.0)$var1.pred
}
OP <- par(pty="s", mar=c(4,3,0,0))
  plot(IDW.out ~ P$rainfall, asp=1, xlab="Observado", ylab="Predicho", pch=16,
       col=rgb(0,0,0,0.5))
  abline(lm(IDW.out ~ P$rainfall), 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:

sqrt( sum((IDW.out - P$rainfall)^2) / length(P))
[1] 2.573842

2.2 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).

img <- gstat::idw(rainfall~1, P, newdata=grd, idp=2.0)
n   <- length(P)
Zi  <- matrix(nrow = length(img$var1.pred), ncol = n)
st <- stack()
for (i in 1:n){
  Z1 <- gstat::idw(rainfall~1, P[-i,], newdata=grd, idp=2.0)
  st <- addLayer(st,raster(Z1,layer=1))

  Zi[,i] <- n * img$var1.pred - (n-1) * Z1$var1.pred
}
Zj <- as.matrix(apply(Zi, 1, sum, na.rm=T) / n )
c1 <- apply(Zi,2,'-',Zj)            
c1 <- apply(c1^2, 1, sum, na.rm=T ) 
CI <- sqrt( 1/(n*(n-1)) * c1)
img.sig   <- img
img.sig$v <- CI /img$var1.pred 
r <- raster(img.sig, layer="v")
r.m <- raster::mask(r, boya2)
tm_shape(r.m) + tm_raster(n=7,title="IDW 95% \nintervalo de confianza \n(en mm)") +
  tm_shape(P) + tm_dots(size=0.2) +
  
  tm_legend(legend.outside=TRUE)

2.3 Ajuste polinomial de primer orden

Para ajustar un modelo polinomial de primer orden de la forma precip = intersección + aX + bY


f.1 <- as.formula(rainfall ~ X + Y) 
 

P$X <- coordinates(P)[,1]
P$Y <- coordinates(P)[,2]


lm.1 <- lm( f.1, data=P)


dat.1st <- SpatialGridDataFrame(grd, data.frame(var1.pred = predict(lm.1, newdata=grd))) 

r   <- raster(dat.1st)
r.m <- raster::mask(r, boya2)


tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE, 
            title="polinomio de primer orden \nPrecipitación prevista (en mm)") +
  tm_shape(P) + 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.

2.4 Ajuste polinomial de segundo orden

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


f.2 <- as.formula(rainfall ~ X + Y + I(X*X)+I(Y*Y) + I(X*Y))


P$X <- coordinates(P)[,1]
P$Y <- coordinates(P)[,2]
 

lm.2 <- lm( f.2, data=P)


dat.2nd <- SpatialGridDataFrame(grd, data.frame(var1.pred = predict(lm.2, newdata=grd))) 

r   <- raster(dat.2nd)
r.m <- raster::mask(r, boya2)


tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE,midpoint = NA,
            title="polinómico de segundo orden \nPrecipitación prevista \n(en mm)") +
  tm_shape(P) + 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.

3. Kriging

Ajustar el modelo de variograma

Primero, necesitamos crear un modelo de variograma. Tenga en cuenta que el modelo de variograma se calcula sobre los datos sin tendencia. Esto se implementa en el siguiente fragmento de código pasando el modelo de tendencia de primer orden a la función variograma.


f.1 <- as.formula(rainfall ~ X + Y) 


var.smpl <- variogram(f.1, P, cloud = FALSE, cutoff=100000, width=8990)


dat.fit  <- fit.variogram(var.smpl, fit.ranges = TRUE, fit.sills = TRUE,
                          vgm(psill=3, model="Mat", range=150000, nugget=0.0))
dat.fit
plot(var.smpl, dat.fit, xlim=c(0,130000))

3.1 Genera superficie Kriged

A continuación, utilice 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 residuales 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

f.1 <- as.formula(rainfall ~ X + Y) 

dat.krg <- krige( f.1, P, grd, dat.fit)
r <- raster(dat.krg)
r.m <- raster::mask(r, boya2)
r.m
class      : RasterLayer 
dimensions : 297, 336, 99792  (nrow, ncol, ncell)
resolution : 893.4599, 893.4599  (x, y)
extent     : 935181.8, 1235384, 1006720, 1272077  (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 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
source     : memory
names      : var1.pred 
values     : 11.93526, 95.82892  (min, max)
tm_shape(r.m) + 
  tm_raster(n=10, palette="RdBu", auto.palette.mapping=FALSE, 
            title="Kriging universal \nPrecipitación prevista \n(en mm)") +
  tm_shape(P) + 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 la superficie interpolada:

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

leaflet() %>% addTiles() %>%
  addRasterImage(r.m, colors = pal, opacity = 0.6) %>%
  addLegend(pal = pal, values = values(r.m),
    title = "Kriging interpolación-precipitación en Boyacá \ en 2020 [mm]")
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_defsDiscarded datum WGS_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_defsDiscarded datum WGS_1984 in CRS definitionSome values were outside the color scale and will be treated as NASome values were outside the color scale and will be treated as NA

3.3 Genere 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, boya2)

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Interpolación Kriging \nMapa de varianza \n(en mm cuadrados)") +tm_shape(P) + 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

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

tm_shape(r.m) + 
  tm_raster(n=7, palette ="Reds",
            title="Interpolación de Kriging \nMapa de IC del 95% \n(en mm)") +tm_shape(P) + tm_dots(size=0.2) +
  tm_legend(legend.outside=TRUE)

PRESENTACIÓN DE RESULTADOS

1. polígonos de Thiessen

El metodo de interpolacion de Thiessen permite trazar piligonos con una cantidad de puntos los cuales son ponderados posteriormente, en las partes oscuras es donde mas se presenta precipitación en mm, y en las partes claras es donde es menos común

donde se notan mas precipitaciones, de 40 a 100 mm en el departamento, en el Norte, entre el municipio de San Mateo a Cubara hay precipitacion de 40 a 100 mm, en el Sur del departamento entre la frontera con casanare, entre el municipio de Pajarito y Santa Maria, al occidente del departamento entre el municipio de chiquinquira hasta puerto boyacá.

2. Interpolación ponderada de distancia inversa

Con el metodo de interpolacion IDW, tenemos una serie de puntos, se quiere saber cual es la precipitacion en un punto del mapa, el metodo toma los puntos y traza una distancia con la cual mediante una operacion da unos datos representativos, lo cual nos indicaria el valor predicho.

lo que se busca es que la linea roja se encuentre en la linea de refrencia gris para lograr una mejor predicción, se hizo una validacion cruzada, y el margen de error fue bastante pequeño, ya que la linea roja esta bastante cerca de la linea de referencia.Se usó una potencia de 6.0, debido a que es un grado aceptable en el que disminiuye la interacción espacial en función inversa a la distancia.

3. Kriging

La interpolación Kriging es un procedimiento geo estadístico que genera una superficie estimada a partir de un conjunto de puntos dispersos con los valores a analizar.

el semivariograma permite cuantificar la auto correlación ya que grafica la varianza de todos de los datos según la distancia, es decir mide las relaciones estadísticas entre los puntos medidos, permitiendo que relacionar los puntos de muestreo cercano, entre mas cerca estén más relacionadas estaran y tendran una pequeña semivarianza, en cambio si los puntos de muestreo están lejanos estos estaran menos relacionados y por ende tienen una alta semivarianza.

Se grafica un semi-variograma exponencial que permite analizar la información, y se encuentra que los problemas de convergencia de la información no son tan amplios ya que los puntos estan bastante cerca al eje trazado.

este metodo no mostro un area con una superficie uniforme, se logran ver 9 areas ditintas con valores de precipitacion variables, posilemente debido a la faltaa de información

el mapa de Indice de confianza corrobora lo dicho, mostrando valores en casi todo el territorio del departamento de Boyacá de 8 a 12 en el indice de confianza

CONCLUSIONES

La interpolación espacial es el proceso de utilizar puntos con valores conocidos para estimar valores desconocidos en otros puntos. para realizar un mapa de precipitación, se sabe que para el departamento de Boyacá no se encontrarán suficientes estaciones meteorológicas distribuidas uniformemente para cubrir toda la región. La interpolación espacial puede estimar las temperaturas en lugares que no tienen ese dato utilizando lecturas de temperatura conocida en estaciones meteorológicas cercanas

Los metodos mas conliables de intepolación son IDW Y Kriging, la interpolación por polígonos de Thiessen no ofrece datos muy confiables y tiene una alta variacion, por lo que no tiene mucha precisión en sus predicciones.

Referente a los resutados, en geenral se observo que en el departamento de Boyacá, las precipitacion son mas altas en la parte Norte, Occidente y sur, en la parte media del departamento las precipitaciones no menos frecuentes la causa de esta variacion tal vez sea devido a la La Cordillera Oriental la cual atraviesa el departamento de sur a norte, haciendo que el departamento presente terreno quebrados, páramos, valles y altiplanos.

REFERENCIAS

1.Documentación de Qgis2.14[Análisis Espacial (Interpolación)] https://docs.qgis.org/2.14/es/docs/gentle_gis_introduction/spatial_analysis_interpolation.html#

2.Gonçalves João. (2018).Advanced Techniques With Raster Data - Part 3: Exercises.: R-exercises. https://www.r-exercises.com/2018/03/31/advanced-techniques-with-raster-data-part-3-regression-kriging/

3.DEPARTAMENTO DE BOYACÁ, Información general con ciudades y municipios del departamento http://www.colombiamania.com/departamentos/boyaca.html

4.Departamento de Boyacá https://encolombia.com/educacion-cultura/geografia/colombiana/departamentos/boyaca/

LS0tDQp0aXRsZTogIkludGVycG9sYWNpb24gZGUgZGF0b3MgZXNwYWNpYWxlcyINCmF1dGhvcjogIkpvcmdlIFBlcmRvbW8iDQpkYXRlOiAiSnVldmVzIDEwIGRlIERpY2llbWJyZSBkZSAyMDIwIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCl9fSU5UUk9EVUNDScOTTl9fDQotLS0NCkxhIGludGVycG9sYWNpw7NuIHNpcnZlIHBhcmEgcHJlZGVjaXIgdmFsb3JlcyBwYXJhIGxhcyBjZWxkYXMgZGUgdW4gcsOhc3RlciBhIHBhcnRpciBkZSB1bmEgY2FudGlkYWQgbGltaXRhZGEgZGUgcHVudG9zIGRlIGRhdG9zIGRlIG11ZXN0cmEuIEVzdGEgaGVycmFtaWVudGEgc2UgcHVlZGUgdXRpbGl6YXIgcGFyYSBwcmV2ZXIgdmFsb3JlcyBxdWUgbm8gc2UgY29ub2NlbiBkZSBjdWFscXVpZXIgZGF0byBkZSB1biBwdW50byBnZW9ncsOhZmljbyBjb21vIHBvciBlamVtcGxvIGxhIGVsZXZhY2nDs24geSBwcmVjaXBpdGFjacOzbi4NCg0KTGFzIGhlcnJhbWllbnRhcyBkZSBpbnRlcnBvbGFjacOzbiBkZSBzdXBlcmZpY2llIGNyZWFuIHVuYSBzdXBlcmZpY2llIGNvbnRpbnVhIChvIHByZWRpY2Npw7NuKSBhIHBhcnRpciBkZSB2YWxvcmVzIGRlIHB1bnRvIGRlIG11ZXN0cmEuIExvIGFudGVyaW9yIHNlIGhhY2UgdmlhYmxlIGN1YW5kbyBzZSBoYWNlIGxhIHN1cG9zaWNpw7NuIGRlIHF1ZSBsb3Mgb2JqZXRvcyBkaXN0cmlidWlkb3MgZXNwYWNpYWxtZW50ZSBlc3TDoW4gY29ycmVsYWNpb25hZG9zIGVzcGFjaWFsbWVudGUsIG8gc2VhLCBsYXMgY29zYXMgcXVlIGVzdMOhbiBjZXJjYSwgdGllbmRlbiBhIHBhcmVjZXJjZS4gQXPDrSwgbG9zIHB1bnRvcyBjZXJjYW5vcyBhIGxvcyBwdW50b3MgZGUgbXVlc3RyYSwgdGllbmVuIG3DoXMgcG9zaWJpbGlkYWRlcyBkZSBzZXIgbcOhcyBzaW1pbGFyZXMgcXVlIGxvcyBxdWUgZXN0w6FuIG3DoXMgYWxlamFkb3MuIFBhcmEgZXN0bywgZXhpc3RlbiBkaWZlcmVudGVzIG1hbmVyYXMgZGUgZGVyaXZhciB1bmEgcHJlZGljY2nDs24gcGFyYSBjYWRhIHViaWNhY2nDs247IGNhZGEgbcOpdG9kbyBzZSBkZW5vbWluYSBtb2RlbG8uIENvbiBjYWRhIG1vZGVsbywgc2UgcmVhbGl6YW4gZGlmZXJlbnRlcyBzdXBvc2ljaW9uZXMgYWNlcmNhIGRlIGxvcyBkYXRvcywgeSBhbGd1bm9zIG1vZGVsb3Mgc29uIG3DoXMgYXBsaWNhYmxlcyBwYXJhIGRldGVybWluYWRvcyBkYXRvcyB5IGNhZGEgdW5vIHByb2R1Y2UgcHJlZGljY2lvbmVzIHVzYW5kbyBkaWZlcmVudGVzIGPDoWxjdWxvcy4NCg0KRW4gZWwgcHJlc2VudGUgdHJhYmFqbywgc2UgcmVhbGl6YXLDoW4gMyBtw6l0b2RvcyBkZSBpbnRlcnBvbGFjacOzbiBsb3MgY3VhbGVzIHNlIGRlc2NyaWJlbiBhIGNvbnRpbnVhY2nDs246DQoNCl9fS3JpZ2dpbjpfXyBJbnRlcnBvbGEgdW5hIHN1cGVyZmljaWUgZGUgcsOhc3RlciBhIHBhcnRpciBkZSBwdW50b3MNCklEVzogSW50ZXJwb2xhIHVuYSBzdXBlcmZpY2llIGRlIHLDoXN0ZXIgYSBwYXJ0aXIgZGUgcHVudG9zIHV0aWxpemFuZG8gdW5hIHTDqWNuaWNhIGRlIGRpc3RhbmNpYSBpbnZlcnNhIHBvbmRlcmFkYQ0KDQpfX0lEVzpfXyBJbnRlcnBvbGEgdW5hIHN1cGVyZmljaWUgZGUgcsOhc3RlciBhIHBhcnRpciBkZSBwdW50b3MgdXRpbGl6YW5kbyB1bmEgdMOpY25pY2EgZGUgZGlzdGFuY2lhIGludmVyc2EgcG9uZGVyYWRhDQogDQpfX1BvbMOtZ29ub3MgZGUgVGhpZXNzZW46X18gU2UgYmFzYSBlbiBjb25zaWRlcmFyIHF1ZSBsb3MgcHVudG9zIGRlIHVuYSB6b25hIGNvaW5jaWRlbiBjb24gZWwgdmFsb3IgbWVkaWRvIG3DoXMgcHLDs3hpbW8geSBnZW5lcmFuLCBjb21vIGNvbnNlY3VlbmNpYSwgem9uYXMgZGUgaW5mbHVlbmNpYSBzaWVuZG8gZWwgcmVzdWx0YWRvIGxhIHVuacOzbiBkZSBwb2zDrWdvbm9zIHF1ZSBnZW5lcmFuIGRpc3RpbnRhcyB6b25hcyB0ZW3DoXRpY2FzDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzZikNCmBgYA0KDQpfX0RFU0NSSVBDScOTTiBERSBMQSBaT05BIERFIEVTVFVESU9fXyANCi0tLQ0KRWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EgZXN0w6Egc2l0dWFkbyBlbiBlbCBjZW50cm8gZGVsIHBhw61zLCBlbiBsYSBjb3JkaWxsZXJhIG9yaWVudGFsIGRlIGxvcyBBbmRlczsgbG9jYWxpemFkbyBlbnRyZSBsb3MgMDTCsDM54oCyMTDigLMgeSBsb3MgMDfCsDAz4oCyMTfigLMgZGUgbGF0aXR1ZCBub3J0ZSB5IGxvcyA3McKwNTfigLI0OeKAsyB5IGxvcyA3NMKwNDHigJkzNeKAsyBkZSBsb25naXR1ZCBvZXN0ZS4gQ3VlbnRhIGNvbiB1bmEgc3VwZXJmaWNpZSBkZSAyMyAxODkga23CsiwgbG8gcXVlIHJlcHJlc2VudGEgZWwgMiwwMyAlIGRlbCB0ZXJyaXRvcmlvIG5hY2lvbmFsLiBMaW1pdGEgcG9yIGVsIG5vcnRlIGNvbiBsb3MgZGVwYXJ0YW1lbnRvcyBkZSBTYW50YW5kZXIgeSBub3J0ZSBkZSBTYW50YW5kZXIsIHBvciBlbCBlc3RlIGNvbiBsb3MgZGVwYXJ0YW1lbnRvcyBkZSBBcmF1Y2EsIENhc2FuYXJlIHkgY29uIGVsIHBhw61zIHZlY2lubyBkZSBWZW5lenVlbGEsIHBvciBlbCBzdXIgY29uIEN1bmRpbmFtYXJjYSwgeSBwb3IgZWwgb2VzdGUgY29uIEN1bmRpbmFtYXJjYSwgQ2FsZGFzIHkgQW50aW9xdWlhLg0KDQphIGNvbnRpbnVhY2lvbiBwb2RyYSB2ZXIgbGEgdWJpY2FjaW9uIGVuIGVsIG1hcGEgbmFjaW9uYWw6DQpgYGB7cn0NCmNvbG1hcDwtICByZWFkX3NmKCJDOi9Vc2Vycy9EYXZpZCBQZXJkb21vL0Rlc2t0b3AvR2VvbWF0aWNhL0NPTF9hZG0vQ09MX2FkbTEuc2hwIikNCnN0X2Nycyhjb2xtYXApDQpnZ3Bsb3QoKSArIGdlb21fc2YoZGF0YSA9IGNvbG1hcCkgKyBjb29yZF9zZihjcnM9c3RfY3JzKDM5NzgpKQ0KYGBgDQpgYGB7cn0NCmJveWFjYSA8LSAgY29sbWFwICU+JSAgIGZpbHRlcihOQU1FXzEgPT0gIkJveWFjw6EiKQ0KZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGEgPSBib3lhY2EpIA0KYGBgDQpfX0hpZHJvZ3JhZmlhIGRlIEJveWFjw6FfXw0KDQpFbCBzaXN0ZW1hIGhpZHJvZ3LDoWZpY28gZGUgQm95YWPDoSBlc3TDoSBjb25zdGl0dWlkbyBwb3IgbnVtZXJvc29zIHLDrW9zIHkgcXVlYnJhZGFzIHF1ZSBuYWNlbiBlbiBsYSBjb3JkaWxsZXJhIE9yaWVudGFsLCBhZmx1ZW50ZXMgZGlyZWN0b3MgbyBkZSBhbGd1bm8gZGUgbG9zIHRyaWJ1dGFyaW9zIGRlIGxvcyByw61vcyBNYWdkYWxlbmEsIE1ldGEgeSBBcmF1Y2E7IGVudHJlIGxvcyByw61vcyBxdWUgY29uZmx1eWVuIGEgbGEgY3VlbmNhIGRlbCBNYWdkYWxlbmEgZXN0w6FuIGVsIEVybWl0YcOxbywgTmVncm8sIE1pbmVybywgU3XDoXJleiwgU3V0YW1hbmNow6FuLCBTw6FjaGljYSwgQ2jDrXF1aXphLCBJZ3VhcXVlLCBBcmNhYnVjbyBvIFDDs21lY2EsIFViYXrDoSwgUmlhY2h1ZWxvLCBNb25pcXVpcsOhLCBDaGljYW1vY2hhLCBDaG9ycmVyYSwgVHV0YSwgUGVzY2EsIFRvdGEsIFNhZ3VlcmEsIFNhc2EsIENhbWJhcywgTG9ibGFuY28sIFJlY2hpbWluaWdhLCBDaGl0YW5vLCBTdXNhY8Ozbi4NCg0KIVtdKEM6L1VzZXJzL0RhdmlkIFBlcmRvbW8vRGVza3RvcC9oaWRyb2dyYWZpYS5wbmcpe3dpZHRoPTgwJX0NCg0KX19BY3RpdmlkYWRlcyBFY29ub21pY2FzIGRlIEJveWFjw6E6X18NCg0KTGEgZWNvbm9tw61hIGRlIEJveWFjw6Egc2UgYmFzYSBwcmluY2lwYWxtZW50ZSBlbiBsYSBwcm9kdWNjacOzbiBhZ3LDrWNvbGEgeSBnYW5hZGVyYSwgbGEgZXhwbG90YWNpw7NuIGRlIG1pbmVyYWxlcywgbGEgaW5kdXN0cmlhIHNpZGVyw7pyZ2ljYSwgZWwgY29tZXJjaW8geSBlbCB0dXJpc21vLiBMYSBhZ3JpY3VsdHVyYSBzZSBoYSBkZXNhcnJvbGxhZG8geSB0ZWNuaWZpY2FkbyBlbiBsb3Mgw7psdGltb3MgYcOxb3M7IGxvcyBwcmluY2lwYWxlcyBjdWx0aXZvcyBzb24gcGFwYSwgbWHDrXosIGNlYm9sbGEsIHRyaWdvLCBjZWJhZGEsIGNhw7FhIHBhbmVsZXJhLCB5dWNhLiBFeGlzdGVuIGVuIEJveWFjw6EgYWxyZWRlZG9yIGRlIDYuODAwIGV4cGxvdGFjaW9uZXMgbWluZXJhcywgZW4gc3UgbWF5b3LDrWEgZGUgY2Fyw6FjdGVyIGFydGVzYW5hbCwgcHJpbmNpcGFsbWVudGUgZGUgY2FyYsOzbiBjb3F1aXphYmxlLCBhcmNpbGxhLCByb2NhIGZvc2bDs3JpY2EsIGFyZW5hLCB5ZXNvLCBtw6FybW9sIHkgY2FsaXphIGRlIGhpZXJybzsgZWwgY2FyYsOzbiBleHRyYcOtZG8gdMOpY25pY2FtZW50ZSB0aWVuZW4gcmVzZXJ2YXMgaW1wb3J0YW50ZXMgZW4gMTkgbXVuaWNpcGlvcy4NCg0KRWwgcGV0csOzbGVvIHNlIGVuY3VlbnRyYSBlbiBlbCB0ZXJyaXRvcmlvIFbDoXNxdWV6OyBlbiBlbCBvY2NpZGVudGUgc2UgZXhwbG90YW4gbGFzIGVzbWVyYWxkYXMgY29uc2lkZXJhZGFzIGxhcyBtw6FzIGZhbW9zYXMgZGVsIG11bmRvIHBvciBzdSBjYWxpZGFkIHkgYmVsbGV6YS4gTGEgcHJvZHVjY2nDs24gYXJ0ZXNhbmFsIGVzIG11eSBsYWJvcmlvc2EgZXNwZWNpYWxtZW50ZSBlbiBjZXLDoW1pY2EsIHRlamlkb3MgZGUgbGFuYSBkZSBvdmVqYSB5IGZpcXVlLCB0YWd1YSwgdGFwaWNlcywgaW5zdHJ1bWVudG9zIG11c2ljYWxlcyB5IGNlc3RlcsOtYSwgZW50cmUgb3Ryb3MNCg0KX19DbGltYSBkZSBCb3lhY8OhOl9fDQoNCkVsIENsaW1hIGRlbCBkZXBhcnRhbWVudG8gZGUgQm95YWPDoSBlc3TDoSBkZXRlcm1pbmFkbyBwcmluY2lwYWxtZW50ZSBwb3Igc3UgcmVsaWV2ZSB5IHBvc2ljacOzbiBnZW9ncsOhZmljYSwgZGFuZG8gY29tbyByZXN1bHRhZG8sIHF1ZSBzZSBwcmVzZW50ZW4gdG9kb3MgbG9zIHBpc29zIHTDqXJtaWNvcyBkZXNkZSBlbCBuaXZhbCwgZW4gbGEgc2llcnJhIG5ldmFkYSBkZWwgQ29jdXksIGhhc3RhIGVsIGPDoWxpZG8sIGVuIGVsIFRlcnJpdG9yaW8gVsOhc3F1ZXogeSBsYSB2ZXJ0aWVudGUgb3JpZW50YWwgZGUgbGEgY29yZGlsbGVyYSBPcmllbnRhbC4NCg0KRWwgZGVwYXJ0YW1lbnRvIHByZXNlbnRhIHVuYSBhbHRhIHZhcmlhYmlsaWRhZCB0ZXJyaXRvcmlhbCBlbiBsYSBkaXN0cmlidWNpw7NuIGRlIGxhIHByZWNpcGl0YWNpw7NuLiBMYXMgw6FyZWFzIGNvbiBtZW5vcmVzIGxsdXZpYXMsIGRlIDUwMCBhIDEwMDAgbW0gYW51YWxlcywgc2UgbG9jYWxpemFuIGEgbG8gbGFyZ28gZGVsIGFsdGlwbGFubyBjdW5kaWJveWFjZW5zZSB5IGEgcGFydGlyIGRlIGVzdGEgem9uYSBsYXMgbGx1dmlhcyBzZSBpbmNyZW1lbnRhbiB0YW50byBhbCBvcmllbnRlIGNvbW8gYWwgb2NjaWRlbnRlIGRlbCBkZXBhcnRhbWVudG8uIEFsIG9yaWVudGUgb2N1cnJlbiBsYXMgbGx1dmlhcyBvcm9ncsOhZmljYXMgY29ycmVzcG9uZGllbnRlcyBhIGxhIHZlcnRpZW50ZSBvcmllbnRhbCBkZSBsYSBjb3JkaWxsZXJhIG9yaWVudGFsLCByZWdpc3RyYW5kbyB2YWxvcmVzIGVuIGVsIHJhbmdvIGRlIDIwMDAgYSBtw6FzIGRlIDUwMDAgbW0uIEFsIG9jY2lkZW50ZSwgZW4gZGlyZWNjacOzbiBhbCB2YWxsZSBkZWwgTWFnZGFsZW5hLCBsYXMgbGx1dmlhcyBvc2NpbGFuIGVudHJlIDIwMDAgeSAzMDAwIG1tIGFsIGHDsW8uDQoNCl9fRGl2aWNpw7NuIEFkbWluaXN0cmF0aXZhIGRlIEJveWFjw6E6X18NCg0KRWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EgZXN0w6EgZGl2aWRpZG8gZW4gMTIzIG11bmljaXBpb3MsICBsb3MgY3VhbGVzIHNlIGFncnVwYW4gZW4gMTIgcHJvdmluY2lhczogU3VnYW11eGksIFR1bmRhbWEsIFZhbGRlcnJhbWEsIE5vcnRlLCBHdXRpZXJyZXosIENlbnRybywgTmVpcmEsIE9yaWVudGUsIExlbmd1cGEsIFJpY2F1cnRlLCBNYXJxdWV6IHkgT2NjaWRlbnRlLg0KDQohW10oQzovVXNlcnMvRGF2aWQgUGVyZG9tby9EZXNrdG9wL2FkbWkuanBnKQ0KDQpfX0RBVE9TIFkgTUVUT0RPUzpfXw0KLS0tDQpUZWNuaWNhcyBkZSBJbnRlcnBvbGFjaW9uIGEgdXNhcjoNCg0KX19LcmlnaW5nOl9fIEVzIHVuYSBoZXJyYW1pZW50YSBkZSBpbnRlcnBvbGFjacOzbiBxdWUgYmFzaWNhbWVudGUgaW50ZXJwb2xhIHVuYSBzdXBlcmZpY2llIGRlIHLDoXN0ZXIgYSBwYXJ0aXIgZGUgcHVudG9zLg0KS3JpZ2luZyBwcmVzdXBvbmUgcXVlIGxhIGRpc3RhbmNpYSBvIGxhIGRpcmVjY2nDs24gZW50cmUgbG9zIHB1bnRvcyBkZSBtdWVzdHJhIHJlZmxlamFuIHVuYSBjb3JyZWxhY2nDs24gZXNwYWNpYWwgcXVlIHB1ZWRlIHV0aWxpemFyc2UgcGFyYSBleHBsaWNhciBsYSB2YXJpYWNpw7NuIGVuIGxhIHN1cGVyZmljaWUuIEFkZW3DoXMgYWp1c3RhIHVuYSBmdW5jacOzbiBtYXRlbcOhdGljYSBhIHVuYSBjYW50aWRhZCBlc3BlY2lmaWNhZGEgZGUgcHVudG9zIG8gYSB0b2RvcyBsb3MgcHVudG9zIGRlbnRybyBkZSB1biByYWRpbyBlc3BlY8OtZmljbyBwYXJhIGRldGVybWluYXIgZWwgdmFsb3IgZGUgc2FsaWRhIHBhcmEgY2FkYSB1YmljYWNpw7NuLiBQb25kZXJhIGxvcyB2YWxvcmVzIG1lZGlkb3MgY2lyY3VuZGFudGVzIHBhcmEgY2FsY3VsYXIgdW5hIHByZWRpY2Npw7NuIGRlIHVuYSB1YmljYWNpw7NuIHNpbiBtZWRpY2lvbmVzLCBlc3RhcyBwb25kZXJhY2lvbmVzIGVzdMOhbiBiYXNhZGFzIG5vIHNvbG8gZW4gbGEgZGlzdGFuY2lhIGVudHJlIGxvcyBwdW50b3MgbWVkaWRvcyB5IGxhIHViaWNhY2nDs24gZGUgbGEgcHJlZGljY2nDs24sIHNpbm8gdGFtYmnDqW4gZW4gbGEgZGlzcG9zaWNpw7NuIGVzcGFjaWFsIGdlbmVyYWwgZGUgbG9zIHB1bnRvcyBtZWRpZG9zLiBQYXJhIHV0aWxpemFyIGxhIGRpc3Bvc2ljacOzbiBlc3BhY2lhbCBlbiBsYXMgcG9uZGVyYWNpb25lcywgbGEgY29ycmVsYWNpw7NuIGVzcGFjaWFsIGRlYmUgZXN0YXIgY3VhbnRpZmljYWRhLiBQb3IgbG8gdGFudG8sIGVuIHVuIGtyaWdpbmcgb3JkaW5hcmlvLCBsYSBwb25kZXJhY2nDs24gZGVwZW5kZSBkZSB1biBtb2RlbG8gYWp1c3RhZG8gYSBsb3MgcHVudG9zIG1lZGlkb3MsIGxhIGRpc3RhbmNpYSBhIGxhIHViaWNhY2nDs24gZGUgbGEgcHJlZGljY2nDs24geSBsYXMgcmVsYWNpb25lcyBlc3BhY2lhbGVzIGVudHJlIGxvcyB2YWxvcmVzIG1lZGlkb3MgYWxyZWRlZG9yIGRlIGxhIHViaWNhY2nDs24gZGUgbGEgcHJlZGljY2nDs24uDQoNCl9fSURXOl9fIExhIGludGVycG9sYWNpw7NuIG1lZGlhbnRlIGRpc3RhbmNpYSBpbnZlcnNhIHBvbmRlcmFkYSBlcyDDunRpbCBwYXJhIGRldGVybWlhciBsb3MgdmFsb3JlcyBkZSBjZWxkYSBtZWRpYW50ZSB1bmEgY29tYmluYWNpw7NuIHBvbmRlcmFkYSBsaW5lYWxtZW50ZSBkZSB1biBjb25qdW50byBkZSBwdW50b3MgZGUgbXVlc3RyYS4gTGEgcG9uZGVyYWNpw7NuIGVzIHVuYSBmdW5jacOzbiBkZSBsYSBkaXN0YW5jaWEgaW52ZXJzYS4gTGEgc3VwZXJmaWNpZSBxdWUgc2UgaW50ZXJwb2xhIGRlYmUgc2VyIGxhIGRlIHVuYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBkZSBsYSB1YmljYWNpw7NuLiBBc8OtIG1pc21vLCBlc3RlIG3DqXRvZG8gcHJlc3Vwb25lIHF1ZSBsYSB2YXJpYWJsZSBxdWUgc2UgcmVwcmVzZW50YSBjYXJ0b2dyw6FmaWNhbWVudGUgZGlzbWludXllIHN1IGluZmx1ZW5jaWEgYSBtYXlvciBkaXN0YW5jaWEgZGVzZGUgc3UgdWJpY2FjacOzbiBkZSBtdWVzdHJhLCBlcyBkZWNpciwgYXN1bWUgcXVlIGxvcyB2YWxvcmVzIG3DoXMgY2VyY2Fub3MgZXN0w6FuIG3DoXMgcmVsYWNpb25hZG9zIHF1ZSBvdHJvcyBjb24gc3UgZnVuY2nDs24uIElEVyBlcyB1biBtw6l0b2RvIGRlIGludGVycG9sYWNpw7NuIGVzcGFjaWFsIG11eSBmbGV4aWJsZSB5YSBxdWUgc2UgcHVlZGUgY29uZmlndXJhciBsYSBpbnRlcnBvbGFjacOzbiBkZSBkaWZlcmVudGVzIG1hbmVyYXMsIHB1ZXMgc2UgcHVlZGUgZXNwaWNpZmljYXIgZWwgcmFkaW8gZGUgYsO6c3F1ZWRhIHkgbGEgaW50ZXJwb2xhY2nDs24gc8OzbG8gdXRpbGl6YXLDoSBlbCBuw7ptZXJvIGRlIHB1bnRvcyBjb25vY2lkb3MgZGVudHJvIGRlbCByYWRpbyBkZSBiw7pzcXVlZGEuIFRhbWJpw6luIHNlIHB1ZWRlbiBlc3RhYmxlY2VyIGJhcnJlcmFzLiBTaSBoYXkgY3Jlc3RhcyBlbiB1biBwZXJmaWwgZGUgZWxldmFjacOzbiwgbyBiYXJyZXJhcyBkZSBydWlkbywgZW50b25jZXMgZXN0b3Mgc29uIGVqZW1wbG9zIGFwcm9waWFkb3MgcGFyYSB1c2FyIHVuYSBiYXJyZXJhLiBFc3RhIGJhcnJlcmEgZGUgcG9saWzDrW5lYSBpbXBpZGUgYnVzY2FyIGxvcyBwdW50b3MgZGUgZW50cmFkYSBkZSBsYSBtdWVzdHJhLg0KDQpfX1BvbMOtZ29ub3MgZGUgVGhpZXNzZW46X18gTGEgaW50ZXJwb2xhY2nDs24gZGUgw6FyZWFzIHV0aWxpemEgZWwgY29uY2VwdG8gZGUgcG9sw61nb25vcyBkZSBUaGllc3NlbiBwYXJhIGRpYnVqYXIgbMOtbWl0ZXMgZW4gdG9ybm8gYSBsYXMgw6FyZWFzIHF1ZSB0aWVuZW4gZWwgbWlzbW8gdmFsb3IuIEVzdGUgdGlwbyBkZSBpbnRlcnBvbGFkb3Igc2UgbGxhbWEgaW50ZXJwb2xhZG9yIHByb3hpbWFsLiBFc3RhIHTDqWNuaWNhIGNvbnN0cnV5ZSBwb2zDrWdvbm9zIG1lZGlhbnRlIGxhIGFzaWduYWNpw7NuIHBvciBjYWRhIHB1bnRvIGRlIHVuIMOhcmVhIGRlIGludGVyw6lzIHVuIHZhbG9yIGRlbCBwdW50byBkZSBtdWVzdHJhIHF1ZSBzZWEgbcOhcyBjZXJjYW5vLiBDcmVhIHN1cGVyZmljaWVzIGVzY2Fsb25hZGFzLCBkb25kZSBsb3MgdmFsb3JlcyBwdWVkZW4gY2FtYmlhciBkcsOhc3RpY2FtZW50ZSBlbiBkaXN0YW5jaWFzIGNvcnRhcywgZXMgZGVjaXIsIHVuIHZhbG9yIGVzdGltYWRvIGVzdMOhIHJlcHJlc2VudGFkbyBkZW50cm8gZGVsIMOhcmVhIGRlIGNhZGEgcG9sw61nb25vLiANClVuYSB2ZXogZGVzY2FyZ2FkbyBlbCBhcmNoaXZvIENISVJQUywgbGVlcmxvIHNpbiBjb21wcmltaXI6DQpgYGB7cn0NCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkoZ3N0YXQpDQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHJhc3RlcikNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KYGBge3J9DQpwcmVjaXAgPC0gcmFzdGVyKCJDOi9Vc2Vycy9EYXZpZCBQZXJkb21vL0Rlc2t0b3AvR2VvbWF0aWNhL3RpZi9jaGlycHMtdjIuMC4yMDIwLjEwLjYudGlmIikgDQpgYGANCkNvbW8geWEgaGFicsOhIG5vdGFkbywgZXN0ZSBhcmNoaXZvIHJlcHJlc2VudGEgbGEgcHJlY2lwaXRhY2nDs24gYWN1bXVsYWRhIGVuIGxvcyDDumx0aW1vcyBkw61hcyBkZSBvY3R1YnJlIGRlIDIwMjAsIGVzIGRlY2lyLCBsYSBwcmVjaXBpdGFjacOzbiBkZWwgMjYgYWwgMzEgZGUgb2N0dWJyZS4NCmBgYHtyfQ0KcHJlY2lwDQpgYGANClRlbmdhIGVuIGN1ZW50YSBxdWUgZXN0ZSBlcyB1biBjb25qdW50byBkZSBkYXRvcyBjb24gY29iZXJ0dXJhIGdsb2JhbC4gU3UgQ1JTIGVzIHVuIHNpc3RlbWEgZGUgY29vcmRlbmFkYXMgZ2VvZ3LDoWZpY2FzLg0KDQpDYXJndWVtb3MgdW4gc2hhcGVmaWxlIHF1ZSByZXByZXNlbnRlIG51ZXN0cmEgw6FyZWEgZGUgaW50ZXLDqXMNCmBgYHtyfQ0KKGFvaSA8LSBzaGFwZWZpbGUoIkM6L1VzZXJzL0RhdmlkIFBlcmRvbW8vRGVza3RvcC9HZW9tYXRpY2EvMTVfQk9ZQUNBL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQpUZW5nYSBlbiBjdWVudGEgcXVlIGxvcyBzaXN0ZW1hcyBkZSByZWZlcmVuY2lhIGRlIGNvb3JkZW5hZGFzIHBhcmEgYW1ib3MgY29uanVudG9zIGRlIGRhdG9zIHNvbiBsb3MgbWlzbW9zLg0KDQpBaG9yYSwgcmVjb3J0ZW1vcyBsb3MgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs246DQpgYGB7cn0NCnByZWNpcC5jcm9wIDwtIHJhc3Rlcjo6Y3JvcChwcmVjaXAsIGV4dGVudChhb2kpKQ0KYGBgDQpgYGB7cn0NCnByZWNpcC5tYXNrIDwtIG1hc2soeCA9IHByZWNpcC5jcm9wLCBtYXNrID0gYW9pKQ0KYGBgDQpgYGB7cn0NCnByZWNpcC5tYXNrIA0KYGBgDQpUcmFjZSBsYSBjYXBhIHLDoXN0ZXIgZW5tYXNjYXJhZGE6DQpgYGB7cn0NCnBsb3QocHJlY2lwLm1hc2ssIG1haW49ICJDSElSUFMgbGx1dmlhIGVuIEJveWFjw6EgMjAyMCBbbW1dIikNCnBsb3QoYW9pLCBhZGQ9VFJVRSkNCmBgYA0KU2UgcHVlZGUgaGFjZXIgdW4gbWVqb3IgbWFwYSBjb24gTGVhZmxldCB1c2FuZG8gbGEgZnVuY2nDs24gYWRkUmFzdGVySW1hZ2U6DQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KcGFsIDwtIGNvbG9yTnVtZXJpYyhjKCJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJibHVlIiwgImRhcmtibHVlIiksIHZhbHVlcyhwcmVjaXAubWFzayksDQogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShwcmVjaXAubWFzaywgY29sb3JzID0gcGFsLCBvcGFjaXR5ID0gMC42KSAlPiUNCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gdmFsdWVzKHByZWNpcC5tYXNrKSwNCiAgICB0aXRsZSA9ICJDSElSUFMgbGx1dmlhIGVuIEJveWFjw6EgMjAyMCBbbW1dIikNCiAgICAgICAgICAgIA0KYGBgDQpMYSBjb252ZXJzacOzbiBkZSByw6FzdGVyIGVuIHB1bnRvcyBzZSBwdWVkZSByZWFsaXphciB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIHJhc3RlclRvUG9pbnRzIGRlIGxhIGJpYmxpb3RlY2EgZGUgcsOhc3RlcjoNCmBgYHtyfQ0KcHJlY2lwLnBvaW50cyA8LSByYXN0ZXJUb1BvaW50cyhwcmVjaXAubWFzaywgc3BhdGlhbCA9IFRSVUUpDQpwcmVjaXAucG9pbnRzDQpgYGANCmBgYHtyfQ0KbmFtZXMocHJlY2lwLnBvaW50cykgPC0gInJhaW4iDQpwcmVjaXAucG9pbnRzDQpgYGANCmBgYHtyfQ0Kc3RyKHByZWNpcC5wb2ludHMpDQpgYGANCkdyYWZpcXVlbW9zIGxvcyBwdW50b3M6DQpgYGB7cn0NCnBsb3QocHJlY2lwLm1hc2ssIG1haW49ICJDSElSUFMgcHJlY2lwaXRhY2lvbmVzIDIwMjAgW21tXSIpDQpwbG90KGFvaSwgYWRkPVRSVUUpDQpwb2ludHMocHJlY2lwLnBvaW50cyR4LCBwcmVjaXAucG9pbnRzJHksIGNvbCA9ICJyZWQiLCBjZXggPSAuNSkNCmBgYA0KYGBge3J9DQpnZW9qc29uaW86Omdlb2pzb25fd3JpdGUocHJlY2lwLnBvaW50cywgZmlsZSA9ICIuL2NoaXJwcy9wcG9pbnRzLmdlb2pzb24iKQ0KYGBgDQpMZWFtb3MgbG9zIHB1bnRvcyBkZSBwcmVjaXBpdGFjacOzbi4NCmBgYHtyfQ0KcHJlY2lwLnBvaW50cyA8LSBnZW9qc29uaW86Omdlb2pzb25fcmVhZCgiLi9jaGlycHMvcHBvaW50cy5nZW9qc29uIiwgd2hhdD0ic3AiKQ0KcHJlY2lwLnBvaW50cw0KYGBgDQpfX8K/Q3XDoWwgZXMgZWwgcHVudG8gZGUgY29udmVydGlyIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuIHLDoXN0ZXIgZW4gZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gcHVudHVhbD9fXw0KDQpCdWVubywgaGF5IHBvY2FzIGVzdGFjaW9uZXMgbWV0ZW9yb2zDs2dpY2FzIGRlIGxhIE9yZ2FuaXphY2nDs24gTWV0ZW9yb2zDs2dpY2EgTXVuZGlhbCAoT01NKSBlbiBudWVzdHJvIHBhw61zDQpQb3IgbG8gdGFudG8sIENISVJQUyBwdWVkZSBzZXIgdW5hIG9wY2nDs24gcGFyYSBvYnRlbmVyIGxvcyBkYXRvcyBkZSBwcmVjaXBpdGFjacOzbiBwdW50dWFsIG5lY2VzYXJpb3MgcGFyYSBvYnRlbmVyIHVuYSBzdXBlcmZpY2llIGRlIHByZWNpcGl0YWNpw7NuIGNvbnRpbnVhLg0KDQpfX0FESUNJT05BTDpfXw0KDQpFbiBjYXNvIGRlIHF1ZSBzZSBwaWVyZGEgbGEgY29uZXhpw7NuLCBwb2RlbW9zIHZvbHZlciBhIGxlZXIgZWwgc2hhcGVmaWxlIGNvbiBlbCDDoXJlYSBkZSBpbnRlcsOpczoNCmBgYHtyfQ0KKGFvaSA8LSBzaGFwZWZpbGUoIkM6L1VzZXJzL0RhdmlkIFBlcmRvbW8vRGVza3RvcC9HZW9tYXRpY2EvMTVfQk9ZQUNBL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQpOZWNlc2l0YW1vcyBjb252ZXJ0aXJsbyBlbiB1bmEgY2FyYWN0ZXLDrXN0aWNhIGVzcGFjaWFsOg0KYGBge3J9DQpib3lhX3NmIDwtICBzZjo6c3RfYXNfc2YoYW9pKQ0KKGJvcmRlcl9zZiA8LQ0KICBib3lhX3NmICU+JQ0KICBzdW1tYXJpc2UoYXJlYSA9IHN1bShNUElPX05BUkVBKSkpDQpgYGANCkNvbnZpZXJ0YSBsYSBjYXJhY3RlcsOtc3RpY2EgZXNwYWNpYWwgZW4gdW4gbWFyY28gZGUgZGF0b3MgZXNwYWNpYWw6DQpgYGB7cn0NCiAoYm9yZGVyIDwtIGFzKGJvcmRlcl9zZiwgJ1NwYXRpYWwnKSkgDQpgYGANCmBgYHtyfQ0KKGJveWEuc2YgPC0gc3RfYXNfc2YoYW9pKSAlPiUgbXV0YXRlKE1VTklDID0gTVBJT19DTk1CUiwgQ09ESUdPID0gTVBJT19DQ0RHTykgJT4lIHNlbGVjdChNVU5JQywgQ09ESUdPKSkNCmBgYA0KQWhvcmEsIGludGVudGFyZW1vcyB1bmEgdGFyZWEgc3RfaW50ZXJzZWN0aW9uLiBFc3RvIHNlIGhhY2UgdXNhbmRvIGxhIGJpYmxpb3RlY2Egc2Y6DQpgYGB7cn0NCnAuc2YgPC0gc3RfYXNfc2YocHJlY2lwLnBvaW50cykNCihwcmVjaXAuc2YgPSBzdF9pbnRlcnNlY3Rpb24oYm95YS5zZiwgcC5zZikpDQpgYGANCkRvcyB0YXJlYXMgZGUgcmVwcm95ZWNjacOzbjoNCmBgYHtyfQ0KcC5zZi5tYWduYSA8LSBzdF90cmFuc2Zvcm0ocHJlY2lwLnNmLCBjcnM9MzExNikNCmJveWEuc2YubWFnbmEgPC0gc3RfdHJhbnNmb3JtKGJveWEuc2YsIGNycz0zMTE2KQ0KKHByZWNpcDIgPC0gYXMocC5zZi5tYWduYSwgJ1NwYXRpYWwnKSkNCmBgYA0KTnVldmFtZW50ZSwgcG9kZW1vcyBlc2NyaWJpciBlbCBjb25qdW50byBkZSBkYXRvcyBpbnRlcm1lZGlvDQpgYGB7cn0NCnNoYXBlZmlsZShwcmVjaXAyLCBmaWxlbmFtZT0nLi9jaGlycHMvcHJlY2lwMi5zaHAnLCBvdmVyd3JpdGU9VFJVRSkNCnByZWNpcDIkcmFpbmZhbGwgPC0gcm91bmQocHJlY2lwMiRyYWluLCAxKQ0KcHJlY2lwMg0KYGBgDQpgYGB7cn0NCihib3lhMiA8LSBhcyhib3lhLnNmLm1hZ25hLCAnU3BhdGlhbCcpKQ0KYGBgDQpgYGB7cn0NCnNoYXBlZmlsZShib3lhMiwgZmlsZW5hbWU9Jy4vY2hpcnBzL2JveWEyLnNocCcsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQpBc2Vnw7pyZXNlIGRlIHF1ZSBsYXMgZG9zIGV4dGVuc2lvbmVzIGNvaW5jaWRhbjoNCmBgYHtyfQ0KcHJlY2lwMkBiYm94IDwtIGJveWEyQGJib3gNCmBgYA0KVHJhemFyIGxvcyBkYXRvcyBjb24gdG1hcDoNCmBgYHtyfQ0KdG1fc2hhcGUoYm95YTIpICsgdG1fcG9seWdvbnMoKSArDQogIHRtX3NoYXBlKHByZWNpcDIpICsNCiAgdG1fZG90cyhjb2w9InJhaW5mYWxsIiwgcGFsZXR0ZSA9ICJSZEJ1IiwgbWlkcG9pbnQgPSAzLjAsDQogICAgICAgICAgICAgdGl0bGU9IlByZWNpcGl0YWNpw7NuIG11ZXN0cmVhZGEgXG4oZW4gbW0pIiwgc2l6ZT0wLjIpICsNCiAgdG1fdGV4dCgicmFpbmZhbGwiLCBqdXN0PSJjZW50ZXIiLCB4bW9kPS42LCBzaXplID0gMC41KSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQpfX0lOVEVSUE9MQUNJw5NOIERFIERBVE9TIERFIFBSRUNJUElUQUNJw5NOX18NCi0tLQ0KMS4gcG9sw61nb25vcyBkZSBUaGllc3Nlbg0KLS0tDQpMb3MgcG9sw61nb25vcyBkZSBUaGllc3NlbiAobyBpbnRlcnBvbGFjacOzbiBkZSBwcm94aW1pZGFkKSBzZSBwdWVkZW4gY3JlYXIgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiBkaXJpY2hsZXQgZGUgU3BhdHN0YXQuDQpgYGB7cn0NCmxpYnJhcnkoc3BhdHN0YXQuZGF0YSkNCmxpYnJhcnkobmxtZSkNCmxpYnJhcnkocnBhcnQpDQpsaWJyYXJ5KGdzdGF0KQ0KbGlicmFyeShzcGF0c3RhdCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShkcGx5cikNCmBgYA0KYGBge3J9DQp0aCAgPC0gIGFzKGRpcmljaGxldChhcy5wcHAocHJlY2lwMikpLCAiU3BhdGlhbFBvbHlnb25zIikNCmNycyh0aCkgPC0gY3JzKHByZWNpcDIpDQpjcnMoYm95YTIpIDwtIGNycyhwcmVjaXAyKQ0KYGBgDQpgYGB7cn0NCmNycyh0aCkgDQpgYGANCmBgYHtyfQ0KY3JzKHByZWNpcDIpDQpgYGANCl9MYSBzdXBlcmZpY2llIHRlc2VsYWRhIG5vIGFsbWFjZW5hIGluZm9ybWFjacOzbiBkZSBhdHJpYnV0b3MgZGUgbGEgY2FwYSBkZSBkYXRvcyBkZSBwdW50b3MuIFVzYXJlbW9zIGxhIGZ1bmNpw7NuIG92ZXIgKCkgKGRlbCBwYXF1ZXRlIHNwKSBwYXJhIHVuaXIgbG9zIGF0cmlidXRvcyBkZSBwdW50byBhIGxhIHN1cGVyZmljaWUgdGVzZWxhZGEgbWVkaWFudGUgdW5hIHVuacOzbiBlc3BhY2lhbC4gTGEgZnVuY2nDs24gb3ZlciAoKSBjcmVhIHVuIG1hcmNvIGRlIGRhdG9zIHF1ZSBuZWNlc2l0YXLDoSBzZXIgYWdyZWdhZG8gYWwgb2JqZXRvIGB0aGAgY3JlYW5kbyBhc8OtIHVuIG9iamV0byBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWVfDQoNCmBgYHtyfQ0KdGgueiAgICAgPC0gb3Zlcih0aCwgcHJlY2lwMiwgZm49bWVhbikNCnRoLnNwZGYgIDwtICBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUodGgsIHRoLnopDQp0aC5jbHAgICA8LSByYXN0ZXI6OmludGVyc2VjdChib3lhMix0aC5zcGRmKQ0KYGBgDQpgYGB7cn0NCnRtX3NoYXBlKHRoLmNscCkgKyANCiAgdG1fcG9seWdvbnMoY29sPSJyYWluZmFsbCIsIHBhbGV0dGU9IlJkQnUiLCBtaWRwb2ludD0zLjAsDQogICAgICAgICAgICAgIHRpdGxlPSJQb2zDrWdvbm9zIGRlIFRoaWVzc2VuIFxuUHJlY2lwaXRhY2nDs24gcHJldmlzdGEgXG4oZW4gbW0pIikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KMi4gSW50ZXJwb2xhY2nDs24gcG9uZGVyYWRhIGRlIGRpc3RhbmNpYSBpbnZlcnNhDQotLS0NCk11Y2hvcyBwYXF1ZXRlcyBjb21wYXJ0ZW4gbG9zIG1pc21vcyBub21icmVzIGRlIGZ1bmNpw7NuLiBFc3RvIHB1ZWRlIHNlciB1biBwcm9ibGVtYSBjdWFuZG8gZXN0b3MgcGFxdWV0ZXMgc2UgY2FyZ2FuIGVuIHVuYSBtaXNtYSBzZXNpw7NuIGRlIFIuIFBvciBlamVtcGxvLCBsYSBmdW5jacOzbiBkZSBpbnRlcnNlY2Npw7NuIGVzdMOhIGRpc3BvbmlibGUgZW4gbG9zIHBhcXVldGVzIGJhc2UsIFNwYXRzdGF0IHkgUsOhc3RlciwgdG9kb3MgbG9zIGN1YWxlcyBzZSBjYXJnYW4gZW4gZXN0YSBzZXNpw7NuIGFjdHVhbC4gUGFyYSBhc2VndXJhcnNlIGRlIHF1ZSBzZSBzZWxlY2Npb25hIGxhIGZ1bmNpw7NuIGFkZWN1YWRhLCBlcyB1bmEgYnVlbmEgaWRlYSBhbnRlcG9uZXIgZWwgbm9tYnJlIGRlIGxhIGZ1bmNpw7NuIGNvbiBlbCBub21icmUgZGVsIHBhcXVldGUgY29tbyBlbiByYXN0ZXIgOjogaW50ZXJzZWN0ICgpLg0KDQpFc3RhIHN1Z2VyZW5jaWEgc2UgdXRpbGl6YXLDoSBlbiBlbCBzaWd1aWVudGUgZnJhZ21lbnRvIGRlIGPDs2RpZ28gY3VhbmRvIHNlIGxsYW1lIGEgbGEgZnVuY2nDs24gaWR3IHF1ZSBlc3TDoSBkaXNwb25pYmxlIHRhbnRvIGVuIFNwYXRzdGF0IGNvbW8gZW4gR3N0YXQuDQoNClRlbmdhIGVuIGN1ZW50YSBxdWUgbGEgZnVuY2nDs24gZGlyaWNobGV0IChjb21vIGxhIG1heW9yw61hIGRlIGxhcyBmdW5jaW9uZXMgZGVsIHBhcXVldGUgc3BhdHNhdCkgcmVxdWllcmUgcXVlIGVsIG9iamV0byBkZSBwdW50byBlc3TDqSBlbiBmb3JtYXRvIHBwcCwgZGUgYWjDrSBsYSBzaW50YXhpcyBhcy5wcHAgKHByZWNpcDIpIGVuIGzDrW5lYS4NCg0KTGEgc2FsaWRhIElEVyBlcyB1biByw6FzdGVyLiBFc3RvIHJlcXVpZXJlIHF1ZSBwcmltZXJvIGNyZWVtb3MgdW5hIGN1YWRyw61jdWxhIHLDoXN0ZXIgdmFjw61hLCBsdWVnbyBpbnRlcnBvbGVtb3MgbG9zIHZhbG9yZXMgZGUgcHJlY2lwaXRhY2nDs24gZW4gY2FkYSBjZWxkYSBkZSBsYSBjdWFkcsOtY3VsYSBzaW4gbXVlc3RyZWFyLiBTZSB1dGlsaXphcsOhIHVuIHZhbG9yIGRlIHBvdGVuY2lhIElEVyBkZSAyIChpZHAgPSAyLDApLg0KYGBge3J9DQoNCmdyZCAgICAgICAgICAgICAgPC0gYXMuZGF0YS5mcmFtZShzcHNhbXBsZShwcmVjaXAyLCAicmVndWxhciIsIG49MTAwMDAwKSkNCg0KbmFtZXMoZ3JkKSAgICAgICA8LSBjKCJYIiwgIlkiKQ0KY29vcmRpbmF0ZXMoZ3JkKSA8LSBjKCJYIiwgIlkiKQ0KZ3JpZGRlZChncmQpICAgICA8LSBUUlVFICAjIENyZWF0ZSBTcGF0aWFsUGl4ZWwgb2JqZWN0DQpmdWxsZ3JpZChncmQpICAgIDwtIFRSVUUgICMgQ3JlYXRlIFNwYXRpYWxHcmlkIG9iamVjdA0KcHJvajRzdHJpbmcoZ3JkKSA8LSBwcm9qNHN0cmluZyhwcmVjaXAyKQ0KUC5pZHcgPC0gZ3N0YXQ6OmlkdyhyYWluZmFsbCB+IDEsIHByZWNpcDIsIG5ld2RhdGE9Z3JkLCBpZHA9Mi4wKQ0KciAgICAgICA8LSByYXN0ZXIoUC5pZHcpDQpgYGANCmBgYHtyfQ0Kcg0KYGBgDQpgYGB7cn0NCmJveWEyDQpgYGANCmBgYHtyfQ0Kci5tICAgPC0gcmFzdGVyOjptYXNrKHIsIGJveWEyKQ0KYGBgDQpgYGB7cn0NCnIubSANCmBgYA0KYGBge3J9DQp0bV9zaGFwZShyLm0pICsgDQogIHRtX3Jhc3RlcihuPTEwLHBhbGV0dGUgPSAiUmRCdSIsIGF1dG8ucGFsZXR0ZS5tYXBwaW5nID0gRkFMU0UsDQogICAgICAgICAgICB0aXRsZT0iRGlzdGFuY2lhIGludmVyc2EgcG9uZGVyYWRhIFxuUHJlY2lwaXRhY2nDs24gcHJldmlzdGEgXG4oZW4gbW0pIikgKyANCiAgdG1fc2hhcGUocHJlY2lwMikgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQpVbmEgbWVqb3IgdmlzdWFsaXphY2nDs24gZGUgbGEgc3VwZXJmaWNpZSBpbnRlcnBvbGFkYToNCmBgYHtyfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpgYGANCmBgYHtyfQ0KcGFsIDwtIGNvbG9yTnVtZXJpYyhjKCJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJibHVlIiwgImRhcmtibHVlIiksIHZhbHVlcyhwcmVjaXAubWFzayksDQogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShyLm0sIGNvbG9ycyA9IHBhbCwgb3BhY2l0eSA9IDAuNikgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IHZhbHVlcyhyLm0pLA0KICAgIHRpdGxlID0gIklEVyBwcmVjaXBpdGFjacOzbiBpbnRlcnBvbGFkYSBlbiBCb3lhY8OhIDIwMjAgW21tXSIpDQpgYGANCl8yLjEgQWp1c3RlIGRlIGxhIGludGVycG9sYWNpw7NuOl8NCi0tLQ0KTGEgZWxlY2Npw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIHBvdGVuY2lhIHB1ZWRlIHNlciBzdWJqZXRpdmEuIFBhcmEgYWp1c3RhciBsYSBlbGVjY2nDs24gZGVsIHBhcsOhbWV0cm8gZGUgcG90ZW5jaWEsIHB1ZWRlIHJlYWxpemFyIHVuYSBydXRpbmEgZGUgdmFsaWRhY2nDs24gZGUgZGVqYXIgdW5vIGZ1ZXJhIHBhcmEgbWVkaXIgZWwgZXJyb3IgZW4gbG9zIHZhbG9yZXMgaW50ZXJwb2xhZG9zLg0KYGBge3J9DQpwcmVjaXAyDQpgYGANCmBgYHtyfQ0KUCA8LSBwcmVjaXAyDQpgYGANCmBgYHtyfQ0KSURXLm91dCA8LSB2ZWN0b3IobGVuZ3RoID0gbGVuZ3RoKFApKQ0KYGBgDQpgYGB7cn0NCmZvciAoaSBpbiAxOmxlbmd0aChQKSkgew0KICBJRFcub3V0W2ldIDwtIGdzdGF0OjppZHcocmFpbmZhbGwgfiAxLCBQWy1pLF0sIFBbaSxdLCBpZHA9Ni4wKSR2YXIxLnByZWQNCn0NCmBgYA0KYGBge3J9DQpPUCA8LSBwYXIocHR5PSJzIiwgbWFyPWMoNCwzLDAsMCkpDQogIHBsb3QoSURXLm91dCB+IFAkcmFpbmZhbGwsIGFzcD0xLCB4bGFiPSJPYnNlcnZhZG8iLCB5bGFiPSJQcmVkaWNobyIsIHBjaD0xNiwNCiAgICAgICBjb2w9cmdiKDAsMCwwLDAuNSkpDQogIGFibGluZShsbShJRFcub3V0IH4gUCRyYWluZmFsbCksIGNvbD0icmVkIiwgbHc9MixsdHk9MikNCiAgYWJsaW5lKDAsMSkNCmBgYA0KYGBge3J9DQpwYXIoT1ApDQpgYGANCkVsIGVycm9yIGN1YWRyw6F0aWNvIG1lZGlvIChSTVNFKSBzZSBwdWVkZSBjYWxjdWxhciBhIHBhcnRpciBkZSBJRFcub3V0IGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQpgYGB7cn0NCnNxcnQoIHN1bSgoSURXLm91dCAtIFAkcmFpbmZhbGwpXjIpIC8gbGVuZ3RoKFApKQ0KYGBgDQpfMi4yIFZhbGlkYWNpw7NuIGNydXphZGFfDQotLS0NCg0KQWRlbcOhcyBkZSBnZW5lcmFyIHVuYSBzdXBlcmZpY2llIGludGVycG9sYWRhLCBwdWVkZSBjcmVhciB1biBtYXBhIGRlIGludGVydmFsbyBkZSBjb25maWFuemEgZGVsIDk1JSBkZWwgbW9kZWxvIGRlIGludGVycG9sYWNpw7NuLiBBcXXDrSBjcmVhcmVtb3MgdW4gbWFwYSBkZSBJQyBkZWwgOTUlIGEgcGFydGlyIGRlIHVuYSBpbnRlcnBvbGFjacOzbiBJRFcgcXVlIHVzYSB1biBwYXLDoW1ldHJvIGRlIHBvdGVuY2lhIGRlIDIgKGlkcCA9IDIuMCkuDQpgYGB7cn0NCmltZyA8LSBnc3RhdDo6aWR3KHJhaW5mYWxsfjEsIFAsIG5ld2RhdGE9Z3JkLCBpZHA9Mi4wKQ0KbiAgIDwtIGxlbmd0aChQKQ0KWmkgIDwtIG1hdHJpeChucm93ID0gbGVuZ3RoKGltZyR2YXIxLnByZWQpLCBuY29sID0gbikNCmBgYA0KYGBge3J9DQpzdCA8LSBzdGFjaygpDQpmb3IgKGkgaW4gMTpuKXsNCiAgWjEgPC0gZ3N0YXQ6OmlkdyhyYWluZmFsbH4xLCBQWy1pLF0sIG5ld2RhdGE9Z3JkLCBpZHA9Mi4wKQ0KICBzdCA8LSBhZGRMYXllcihzdCxyYXN0ZXIoWjEsbGF5ZXI9MSkpDQoNCiAgWmlbLGldIDwtIG4gKiBpbWckdmFyMS5wcmVkIC0gKG4tMSkgKiBaMSR2YXIxLnByZWQNCn0NCmBgYA0KYGBge3J9DQpaaiA8LSBhcy5tYXRyaXgoYXBwbHkoWmksIDEsIHN1bSwgbmEucm09VCkgLyBuICkNCmBgYA0KYGBge3J9DQpjMSA8LSBhcHBseShaaSwyLCctJyxaaikgICAgICAgICAgICANCmMxIDwtIGFwcGx5KGMxXjIsIDEsIHN1bSwgbmEucm09VCApIA0KYGBgDQpgYGB7cn0NCkNJIDwtIHNxcnQoIDEvKG4qKG4tMSkpICogYzEpDQpgYGANCmBgYHtyfQ0KaW1nLnNpZyAgIDwtIGltZw0KaW1nLnNpZyR2IDwtIENJIC9pbWckdmFyMS5wcmVkIA0KYGBgDQpgYGB7cn0NCnIgPC0gcmFzdGVyKGltZy5zaWcsIGxheWVyPSJ2IikNCnIubSA8LSByYXN0ZXI6Om1hc2sociwgYm95YTIpDQpgYGANCmBgYHtyfQ0KdG1fc2hhcGUoci5tKSArIHRtX3Jhc3RlcihuPTcsdGl0bGU9IklEVyA5NSUgXG5pbnRlcnZhbG8gZGUgY29uZmlhbnphIFxuKGVuIG1tKSIpICsNCiAgdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIA0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KXzIuMyBBanVzdGUgcG9saW5vbWlhbCBkZSBwcmltZXIgb3JkZW5fDQotLS0NClBhcmEgYWp1c3RhciB1biBtb2RlbG8gcG9saW5vbWlhbCBkZSBwcmltZXIgb3JkZW4gZGUgbGEgZm9ybWEgcHJlY2lwID0gaW50ZXJzZWNjacOzbiArIGFYICsgYlkNCmBgYHtyfQ0KDQpmLjEgPC0gYXMuZm9ybXVsYShyYWluZmFsbCB+IFggKyBZKSANCiANCg0KUCRYIDwtIGNvb3JkaW5hdGVzKFApWywxXQ0KUCRZIDwtIGNvb3JkaW5hdGVzKFApWywyXQ0KDQoNCmxtLjEgPC0gbG0oIGYuMSwgZGF0YT1QKQ0KDQoNCmRhdC4xc3QgPC0gU3BhdGlhbEdyaWREYXRhRnJhbWUoZ3JkLCBkYXRhLmZyYW1lKHZhcjEucHJlZCA9IHByZWRpY3QobG0uMSwgbmV3ZGF0YT1ncmQpKSkgDQpgYGANCmBgYHtyfQ0KDQpyICAgPC0gcmFzdGVyKGRhdC4xc3QpDQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIGJveWEyKQ0KDQoNCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49MTAsIHBhbGV0dGU9IlJkQnUiLCBhdXRvLnBhbGV0dGUubWFwcGluZz1GQUxTRSwgDQogICAgICAgICAgICB0aXRsZT0icG9saW5vbWlvIGRlIHByaW1lciBvcmRlbiBcblByZWNpcGl0YWNpw7NuIHByZXZpc3RhIChlbiBtbSkiKSArDQogIHRtX3NoYXBlKFApICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KXzIuNCBBanVzdGUgcG9saW5vbWlhbCBkZSBzZWd1bmRvIG9yZGVuXw0KLS0tDQpQYXJhIGFqdXN0YXIgdW4gbW9kZWxvIHBvbGlub21pYWwgZGUgc2VndW5kbyBvcmRlbiBkZSBsYSBmb3JtYSBwcmVjaXAgPSBpbnRlcnNlY2Npw7NuICsgYVggKyBiWSArIGRYMiArIGVZMiArIGZYWQ0KYGBge3J9DQoNCmYuMiA8LSBhcy5mb3JtdWxhKHJhaW5mYWxsIH4gWCArIFkgKyBJKFgqWCkrSShZKlkpICsgSShYKlkpKQ0KDQoNClAkWCA8LSBjb29yZGluYXRlcyhQKVssMV0NClAkWSA8LSBjb29yZGluYXRlcyhQKVssMl0NCiANCg0KbG0uMiA8LSBsbSggZi4yLCBkYXRhPVApDQoNCg0KZGF0LjJuZCA8LSBTcGF0aWFsR3JpZERhdGFGcmFtZShncmQsIGRhdGEuZnJhbWUodmFyMS5wcmVkID0gcHJlZGljdChsbS4yLCBuZXdkYXRhPWdyZCkpKSANCmBgYA0KYGBge3J9DQoNCnIgICA8LSByYXN0ZXIoZGF0LjJuZCkNCnIubSA8LSByYXN0ZXI6Om1hc2sociwgYm95YTIpDQoNCg0KdG1fc2hhcGUoci5tKSArIA0KICB0bV9yYXN0ZXIobj0xMCwgcGFsZXR0ZT0iUmRCdSIsIGF1dG8ucGFsZXR0ZS5tYXBwaW5nPUZBTFNFLG1pZHBvaW50ID0gTkEsDQogICAgICAgICAgICB0aXRsZT0icG9saW7Ds21pY28gZGUgc2VndW5kbyBvcmRlbiBcblByZWNpcGl0YWNpw7NuIHByZXZpc3RhIFxuKGVuIG1tKSIpICsNCiAgdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQozLiBLcmlnaW5nDQotLS0NCl9fQWp1c3RhciBlbCBtb2RlbG8gZGUgdmFyaW9ncmFtYV9fDQoNClByaW1lcm8sIG5lY2VzaXRhbW9zIGNyZWFyIHVuIG1vZGVsbyBkZSB2YXJpb2dyYW1hLiBUZW5nYSBlbiBjdWVudGEgcXVlIGVsIG1vZGVsbyBkZSB2YXJpb2dyYW1hIHNlIGNhbGN1bGEgc29icmUgbG9zIGRhdG9zIHNpbiB0ZW5kZW5jaWEuIEVzdG8gc2UgaW1wbGVtZW50YSBlbiBlbCBzaWd1aWVudGUgZnJhZ21lbnRvIGRlIGPDs2RpZ28gcGFzYW5kbyBlbCBtb2RlbG8gZGUgdGVuZGVuY2lhIGRlIHByaW1lciBvcmRlbiBhIGxhIGZ1bmNpw7NuIHZhcmlvZ3JhbWEuDQpgYGB7cn0NCg0KZi4xIDwtIGFzLmZvcm11bGEocmFpbmZhbGwgfiBYICsgWSkgDQoNCg0KdmFyLnNtcGwgPC0gdmFyaW9ncmFtKGYuMSwgUCwgY2xvdWQgPSBGQUxTRSwgY3V0b2ZmPTEwMDAwMCwgd2lkdGg9ODk5MCkNCg0KDQpkYXQuZml0ICA8LSBmaXQudmFyaW9ncmFtKHZhci5zbXBsLCBmaXQucmFuZ2VzID0gVFJVRSwgZml0LnNpbGxzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmdtKHBzaWxsPTMsIG1vZGVsPSJNYXQiLCByYW5nZT0xNTAwMDAsIG51Z2dldD0wLjApKQ0KYGBgDQpgYGB7cn0NCmRhdC5maXQNCmBgYA0KYGBge3J9DQpwbG90KHZhci5zbXBsLCBkYXQuZml0LCB4bGltPWMoMCwxMzAwMDApKQ0KYGBgDQpfMy4xIEdlbmVyYSBzdXBlcmZpY2llIEtyaWdlZF8NCi0tLQ0KQSBjb250aW51YWNpw7NuLCB1dGlsaWNlIGVsIG1vZGVsbyBkZSB2YXJpb2dyYW1hIGRhdC5maXQgcGFyYSBnZW5lcmFyIHVuYSBzdXBlcmZpY2llIGludGVycG9sYWRhIGtyaWdlZC4gTGEgZnVuY2nDs24ga3JpZ2Ugbm9zIHBlcm1pdGUgaW5jbHVpciBlbCBtb2RlbG8gZGUgdGVuZGVuY2lhLCBsbyBxdWUgbm9zIGFob3JyYSB0ZW5lciBxdWUgZWxpbWluYXIgbGEgdGVuZGVuY2lhIGRlIGxvcyBkYXRvcywga3JpZ2UgbG9zIHJlc2lkdWFsZXMgeSBsdWVnbyBjb21iaW5hciBsb3MgZG9zIHLDoXN0ZXJlcy4gRW4gY2FtYmlvLCB0b2RvIGxvIHF1ZSB0ZW5lbW9zIHF1ZSBoYWNlciBlcyBwYXNhciBhIGtyaWdlIGxhIGbDs3JtdWxhIGRlIHRlbmRlbmNpYSBmLjENCmBgYHtyfQ0KZi4xIDwtIGFzLmZvcm11bGEocmFpbmZhbGwgfiBYICsgWSkgDQoNCmRhdC5rcmcgPC0ga3JpZ2UoIGYuMSwgUCwgZ3JkLCBkYXQuZml0KQ0KYGBgDQpgYGB7cn0NCnIgPC0gcmFzdGVyKGRhdC5rcmcpDQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIGJveWEyKQ0KYGBgDQpgYGB7cn0NCnIubQ0KYGBgDQpgYGB7cn0NCnRtX3NoYXBlKHIubSkgKyANCiAgdG1fcmFzdGVyKG49MTAsIHBhbGV0dGU9IlJkQnUiLCBhdXRvLnBhbGV0dGUubWFwcGluZz1GQUxTRSwgDQogICAgICAgICAgICB0aXRsZT0iS3JpZ2luZyB1bml2ZXJzYWwgXG5QcmVjaXBpdGFjacOzbiBwcmV2aXN0YSBcbihlbiBtbSkiKSArDQogIHRtX3NoYXBlKFApICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KX19VbmEgbWVqb3IgdmlzdWFsaXphY2nDs24gZGUgbGEgc3VwZXJmaWNpZSBpbnRlcnBvbGFkYTpfXw0KDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KcGFsIDwtIGNvbG9yTnVtZXJpYyhjKCJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJibHVlIiwgImRhcmtibHVlIiksIHZhbHVlcyhwcmVjaXAubWFzayksDQogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShyLm0sIGNvbG9ycyA9IHBhbCwgb3BhY2l0eSA9IDAuNikgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IHZhbHVlcyhyLm0pLA0KICAgIHRpdGxlID0gIktyaWdpbmcgaW50ZXJwb2xhY2nDs24tcHJlY2lwaXRhY2nDs24gZW4gQm95YWPDoSBcIGVuIDIwMjAgW21tXSIpDQpgYGANCl8zLjMgR2VuZXJlIGxvcyBtYXBhcyBkZSBpbnRlcnZhbG8gZGUgY29uZmlhbnphIHkgdmFyaWFuemFfDQotLS0NCkVsIG9iamV0byBkYXQua3JnIGFsbWFjZW5hIG5vIHNvbG8gbG9zIHZhbG9yZXMgaW50ZXJwb2xhZG9zLCBzaW5vIHRhbWJpw6luIGxvcyB2YWxvcmVzIGRlIHZhcmlhbnphLiBFc3RvcyBzZSBwdWVkZW4gcGFzYXIgYWwgb2JqZXRvIHLDoXN0ZXIgcGFyYSBlbCBtYXBlbyBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KYGBge3J9DQpyICAgPC0gcmFzdGVyKGRhdC5rcmcsIGxheWVyPSJ2YXIxLnZhciIpDQpyLm0gPC0gcmFzdGVyOjptYXNrKHIsIGJveWEyKQ0KDQp0bV9zaGFwZShyLm0pICsgDQogIHRtX3Jhc3RlcihuPTcsIHBhbGV0dGUgPSJSZWRzIiwNCiAgICAgICAgICAgIHRpdGxlPSJJbnRlcnBvbGFjacOzbiBLcmlnaW5nIFxuTWFwYSBkZSB2YXJpYW56YSBcbihlbiBtbSBjdWFkcmFkb3MpIikgK3RtX3NoYXBlKFApICsgdG1fZG90cyhzaXplPTAuMikgKw0KICB0bV9sZWdlbmQobGVnZW5kLm91dHNpZGU9VFJVRSkNCmBgYA0KVW4gbWFwYSBtw6FzIGbDoWNpbG1lbnRlIGludGVycHJldGFibGUgZXMgZWwgbWFwYSBkZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBkZWwgOTUlIHF1ZSBzZSBwdWVkZSBnZW5lcmFyIGEgcGFydGlyIGRlbCBvYmpldG8gZGUgdmFyaWFuemEgZGUgbGEgc2lndWllbnRlIG1hbmVyYQ0KYGBge3J9DQpyICAgPC0gc3FydChyYXN0ZXIoZGF0LmtyZywgbGF5ZXI9InZhcjEudmFyIikpICogMS45Ng0Kci5tIDwtIHJhc3Rlcjo6bWFzayhyLCBib3lhMikNCg0KdG1fc2hhcGUoci5tKSArIA0KICB0bV9yYXN0ZXIobj03LCBwYWxldHRlID0iUmVkcyIsDQogICAgICAgICAgICB0aXRsZT0iSW50ZXJwb2xhY2nDs24gZGUgS3JpZ2luZyBcbk1hcGEgZGUgSUMgZGVsIDk1JSBcbihlbiBtbSkiKSArdG1fc2hhcGUoUCkgKyB0bV9kb3RzKHNpemU9MC4yKSArDQogIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFKQ0KYGBgDQpfX1BSRVNFTlRBQ0nDk04gREUgUkVTVUxUQURPU19fDQotLS0NCg0KXzEuIHBvbMOtZ29ub3MgZGUgVGhpZXNzZW5fDQotLS0NCg0KRWwgbWV0b2RvIGRlIGludGVycG9sYWNpb24gZGUgVGhpZXNzZW4gcGVybWl0ZSB0cmF6YXIgcGlsaWdvbm9zIGNvbiB1bmEgY2FudGlkYWQgZGUgcHVudG9zIGxvcyBjdWFsZXMgc29uIHBvbmRlcmFkb3MgcG9zdGVyaW9ybWVudGUsIGVuIGxhcyBwYXJ0ZXMgb3NjdXJhcyBlcyBkb25kZSBtYXMgc2UgcHJlc2VudGEgcHJlY2lwaXRhY2nDs24gZW4gbW0sIHkgZW4gbGFzIHBhcnRlcyBjbGFyYXMgZXMgZG9uZGUgZXMgbWVub3MgY29tw7puDQoNCmRvbmRlIHNlIG5vdGFuIG1hcyBwcmVjaXBpdGFjaW9uZXMsIGRlIDQwIGEgMTAwIG1tIGVuIGVsIGRlcGFydGFtZW50bywgZW4gZWwgTm9ydGUsIGVudHJlIGVsIG11bmljaXBpbyBkZSBTYW4gTWF0ZW8gYSBDdWJhcmEgaGF5IHByZWNpcGl0YWNpb24gZGUgNDAgYSAxMDAgbW0sIGVuIGVsIFN1ciBkZWwgZGVwYXJ0YW1lbnRvIGVudHJlIGxhIGZyb250ZXJhIGNvbiBjYXNhbmFyZSwgZW50cmUgZWwgbXVuaWNpcGlvICBkZSBQYWphcml0byB5IFNhbnRhIE1hcmlhLCBhbCBvY2NpZGVudGUgZGVsIGRlcGFydGFtZW50byBlbnRyZSBlbCBtdW5pY2lwaW8gZGUgY2hpcXVpbnF1aXJhIGhhc3RhIHB1ZXJ0byBib3lhY8OhLg0KDQoNCiFbXShDOi9Vc2Vycy9EYXZpZCBQZXJkb21vL0Rlc2t0b3AvdGhpZXNzZW4uUE5HKQ0KIA0KXzIuIEludGVycG9sYWNpw7NuIHBvbmRlcmFkYSBkZSBkaXN0YW5jaWEgaW52ZXJzYV8NCi0tLQ0KQ29uIGVsIG1ldG9kbyBkZSBpbnRlcnBvbGFjaW9uIElEVywgdGVuZW1vcyB1bmEgc2VyaWUgZGUgcHVudG9zLCBzZSBxdWllcmUgc2FiZXIgY3VhbCBlcyBsYSBwcmVjaXBpdGFjaW9uIGVuIHVuIHB1bnRvIGRlbCBtYXBhLCBlbCBtZXRvZG8gdG9tYSBsb3MgcHVudG9zIHkgdHJhemEgdW5hIGRpc3RhbmNpYSBjb24gbGEgY3VhbCBtZWRpYW50ZSB1bmEgb3BlcmFjaW9uIGRhIHVub3MgZGF0b3MgcmVwcmVzZW50YXRpdm9zLCBsbyBjdWFsIG5vcyBpbmRpY2FyaWEgZWwgdmFsb3IgcHJlZGljaG8uIA0KDQpsbyBxdWUgc2UgYnVzY2EgZXMgcXVlIGxhIGxpbmVhIHJvamEgc2UgZW5jdWVudHJlIGVuIGxhIGxpbmVhIGRlIHJlZnJlbmNpYSBncmlzIHBhcmEgbG9ncmFyIHVuYSBtZWpvciBwcmVkaWNjacOzbiwgc2UgaGl6byB1bmEgdmFsaWRhY2lvbiBjcnV6YWRhLCB5IGVsIG1hcmdlbiBkZSBlcnJvciBmdWUgYmFzdGFudGUgcGVxdWXDsW8sIHlhIHF1ZSBsYSBsaW5lYSByb2phIGVzdGEgYmFzdGFudGUgY2VyY2EgZGUgbGEgbGluZWEgZGUgcmVmZXJlbmNpYS5TZSB1c8OzIHVuYSBwb3RlbmNpYSBkZSA2LjAsIGRlYmlkbyBhIHF1ZSBlcyB1biBncmFkbyBhY2VwdGFibGUgZW4gZWwgcXVlIGRpc21pbml1eWUgbGEgaW50ZXJhY2Npw7NuIGVzcGFjaWFsIGVuIGZ1bmNpw7NuIGludmVyc2EgYSBsYSBkaXN0YW5jaWEuDQoNCiFbXShDOi9Vc2Vycy9EYXZpZCBQZXJkb21vL0Rlc2t0b3AvSURXMi5QTkcpDQoNCl8zLiBLcmlnaW5nXw0KLS0tDQogTGEgaW50ZXJwb2xhY2nDs24gS3JpZ2luZyBlcyB1biBwcm9jZWRpbWllbnRvIGdlbyBlc3RhZMOtc3RpY28gcXVlIGdlbmVyYSB1bmEgc3VwZXJmaWNpZSBlc3RpbWFkYSBhIHBhcnRpciBkZSB1biBjb25qdW50byBkZSBwdW50b3MgZGlzcGVyc29zIGNvbiBsb3MgdmFsb3JlcyBhIGFuYWxpemFyLg0KDQplbCBzZW1pdmFyaW9ncmFtYSBwZXJtaXRlIGN1YW50aWZpY2FyIGxhIGF1dG8gY29ycmVsYWNpw7NuIHlhIHF1ZSBncmFmaWNhIGxhIHZhcmlhbnphIGRlIHRvZG9zIGRlIGxvcyBkYXRvcyBzZWfDum4gbGEgZGlzdGFuY2lhLCBlcyBkZWNpciBtaWRlIGxhcyByZWxhY2lvbmVzIGVzdGFkw61zdGljYXMgZW50cmUgbG9zIHB1bnRvcyBtZWRpZG9zLCBwZXJtaXRpZW5kbyBxdWUgcmVsYWNpb25hciBsb3MgcHVudG9zIGRlIG11ZXN0cmVvIGNlcmNhbm8sIGVudHJlIG1hcyBjZXJjYSBlc3TDqW4gbcOhcyByZWxhY2lvbmFkYXMgZXN0YXJhbiB5IHRlbmRyYW4gdW5hIHBlcXVlw7FhIHNlbWl2YXJpYW56YSwgZW4gY2FtYmlvIHNpIGxvcyBwdW50b3MgZGUgbXVlc3RyZW8gZXN0w6FuIGxlamFub3MgZXN0b3MgZXN0YXJhbiBtZW5vcyByZWxhY2lvbmFkb3MgeSBwb3IgZW5kZSB0aWVuZW4gdW5hIGFsdGEgc2VtaXZhcmlhbnphLg0KDQpTZSBncmFmaWNhIHVuIHNlbWktdmFyaW9ncmFtYSBleHBvbmVuY2lhbCBxdWUgcGVybWl0ZSBhbmFsaXphciBsYSBpbmZvcm1hY2nDs24sIHkgc2UgZW5jdWVudHJhIHF1ZSBsb3MgcHJvYmxlbWFzIGRlIGNvbnZlcmdlbmNpYSBkZSBsYSBpbmZvcm1hY2nDs24gbm8gc29uIHRhbiBhbXBsaW9zIHlhIHF1ZSBsb3MgcHVudG9zIGVzdGFuIGJhc3RhbnRlIGNlcmNhIGFsIGVqZSB0cmF6YWRvLg0KDQohW10oQzovVXNlcnMvRGF2aWQgUGVyZG9tby9EZXNrdG9wL0tyaWdpbmcxLlBORykNCg0KZXN0ZSBtZXRvZG8gbm8gbW9zdHJvIHVuIGFyZWEgY29uIHVuYSBzdXBlcmZpY2llIHVuaWZvcm1lLCBzZSBsb2dyYW4gdmVyIDkgYXJlYXMgZGl0aW50YXMgY29uIHZhbG9yZXMgZGUgcHJlY2lwaXRhY2lvbiB2YXJpYWJsZXMsIHBvc2lsZW1lbnRlIGRlYmlkbyBhIGxhIGZhbHRhYSBkZSBpbmZvcm1hY2nDs24NCg0KIVtdKEM6L1VzZXJzL0RhdmlkIFBlcmRvbW8vRGVza3RvcC9LcmlnaW5nMi5QTkcpDQoNCmVsIG1hcGEgZGUgSW5kaWNlIGRlIGNvbmZpYW56YSBjb3Jyb2JvcmEgbG8gZGljaG8sIG1vc3RyYW5kbyB2YWxvcmVzIGVuIGNhc2kgdG9kbyBlbCB0ZXJyaXRvcmlvIGRlbCBkZXBhcnRhbWVudG8gZGUgQm95YWPDoSBkZSA4IGEgMTIgZW4gZWwgaW5kaWNlIGRlIGNvbmZpYW56YSANCg0KIVtdKEM6L1VzZXJzL0RhdmlkIFBlcmRvbW8vRGVza3RvcC9LcmlnaW5nNC5QTkcpDQoNCl9fQ09OQ0xVU0lPTkVTX18NCi0tLQ0KDQpMYSBpbnRlcnBvbGFjacOzbiBlc3BhY2lhbCBlcyBlbCBwcm9jZXNvIGRlIHV0aWxpemFyIHB1bnRvcyBjb24gdmFsb3JlcyBjb25vY2lkb3MgcGFyYSBlc3RpbWFyIHZhbG9yZXMgZGVzY29ub2NpZG9zIGVuIG90cm9zIHB1bnRvcy4NCnBhcmEgcmVhbGl6YXIgdW4gbWFwYSBkZSBwcmVjaXBpdGFjacOzbiwgc2UgIHNhYmUgcXVlIHBhcmEgZWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6Egbm8gc2UgZW5jb250cmFyw6FuIHN1ZmljaWVudGVzIGVzdGFjaW9uZXMgbWV0ZW9yb2zDs2dpY2FzIGRpc3RyaWJ1aWRhcyB1bmlmb3JtZW1lbnRlIHBhcmEgY3VicmlyIHRvZGEgbGEgcmVnacOzbi4gTGEgaW50ZXJwb2xhY2nDs24gZXNwYWNpYWwgcHVlZGUgZXN0aW1hciBsYXMgdGVtcGVyYXR1cmFzIGVuIGx1Z2FyZXMgcXVlIG5vIHRpZW5lbiBlc2UgZGF0byB1dGlsaXphbmRvIGxlY3R1cmFzIGRlIHRlbXBlcmF0dXJhIGNvbm9jaWRhIGVuIGVzdGFjaW9uZXMgbWV0ZW9yb2zDs2dpY2FzIGNlcmNhbmFzDQoNCkxvcyBtZXRvZG9zIG1hcyBjb25saWFibGVzIGRlIGludGVwb2xhY2nDs24gc29uIElEVyBZIEtyaWdpbmcsIGxhIGludGVycG9sYWNpw7NuIHBvciBwb2zDrWdvbm9zIGRlIFRoaWVzc2VuIG5vIG9mcmVjZSBkYXRvcyBtdXkgY29uZmlhYmxlcyB5IHRpZW5lIHVuYSBhbHRhIHZhcmlhY2lvbiwgcG9yIGxvIHF1ZSBubyB0aWVuZSBtdWNoYSBwcmVjaXNpw7NuIGVuIHN1cyBwcmVkaWNjaW9uZXMuDQoNClJlZmVyZW50ZSBhIGxvcyByZXN1dGFkb3MsIGVuIGdlZW5yYWwgc2Ugb2JzZXJ2byBxdWUgZW4gZWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EsIGxhcyBwcmVjaXBpdGFjaW9uIHNvbiBtYXMgYWx0YXMgZW4gbGEgcGFydGUgTm9ydGUsIE9jY2lkZW50ZSB5IHN1ciwgZW4gbGEgcGFydGUgbWVkaWEgZGVsIGRlcGFydGFtZW50byBsYXMgcHJlY2lwaXRhY2lvbmVzIG5vIG1lbm9zIGZyZWN1ZW50ZXMgbGEgY2F1c2EgZGUgZXN0YSB2YXJpYWNpb24gdGFsIHZleiBzZWEgZGV2aWRvIGEgbGEgTGEgQ29yZGlsbGVyYSBPcmllbnRhbCBsYSBjdWFsIGF0cmF2aWVzYSBlbCBkZXBhcnRhbWVudG8gZGUgc3VyIGEgbm9ydGUsIGhhY2llbmRvIHF1ZSBlbCBkZXBhcnRhbWVudG8gcHJlc2VudGUgdGVycmVubyBxdWVicmFkb3MsIHDDoXJhbW9zLCB2YWxsZXMgeSBhbHRpcGxhbm9zLg0KDQpfX1JFRkVSRU5DSUFTX18NCi0tLQ0KMS5Eb2N1bWVudGFjacOzbiBkZSBRZ2lzMi4xNFtBbsOhbGlzaXMgRXNwYWNpYWwgKEludGVycG9sYWNpw7NuKV0NCmh0dHBzOi8vZG9jcy5xZ2lzLm9yZy8yLjE0L2VzL2RvY3MvZ2VudGxlX2dpc19pbnRyb2R1Y3Rpb24vc3BhdGlhbF9hbmFseXNpc19pbnRlcnBvbGF0aW9uLmh0bWwjDQoNCjIuR29uw6dhbHZlcyBKb8Ojby4gKDIwMTgpLkFkdmFuY2VkIFRlY2huaXF1ZXMgV2l0aCBSYXN0ZXIgRGF0YSAtIFBhcnQgMzogRXhlcmNpc2VzLjogUi1leGVyY2lzZXMuDQpodHRwczovL3d3dy5yLWV4ZXJjaXNlcy5jb20vMjAxOC8wMy8zMS9hZHZhbmNlZC10ZWNobmlxdWVzLXdpdGgtcmFzdGVyLWRhdGEtcGFydC0zLXJlZ3Jlc3Npb24ta3JpZ2luZy8NCg0KMy5ERVBBUlRBTUVOVE8gREUgQk9ZQUPDgSwgSW5mb3JtYWNpw7NuIGdlbmVyYWwgY29uIGNpdWRhZGVzIHkgbXVuaWNpcGlvcyBkZWwgZGVwYXJ0YW1lbnRvDQpodHRwOi8vd3d3LmNvbG9tYmlhbWFuaWEuY29tL2RlcGFydGFtZW50b3MvYm95YWNhLmh0bWwNCg0KNC5EZXBhcnRhbWVudG8gZGUgQm95YWPDoQ0KaHR0cHM6Ly9lbmNvbG9tYmlhLmNvbS9lZHVjYWNpb24tY3VsdHVyYS9nZW9ncmFmaWEvY29sb21iaWFuYS9kZXBhcnRhbWVudG9zL2JveWFjYS8NCg0KDQo=