1. Introducción GeoXp
- Es un paquete de R para gráficos interactivos de análisis exploratorio de datos espaciales.
- Conjunto de rutinas estadísticas adaptadas a la exploración de datos georreferenciados, una herramienta adaptable, integral y unificada.
- Es una herramienta exploratoria para investigadores y usuarios experimentados en estadísticas espaciales, econometría espacial, geografía, ecología, epidemiología, etc.
Análisis Exploratorio de Datos Espaciales Es el conjunto de técnicas que describen y visualizan las distribuciones espaciales, identifican localizaciones atípicas o “atípicos espaciales” (“spatial outliers”), descubren esquemas de asociación espacial, agrupamientos (“clusters”) o puntos calientes (“hot spots”) y sugieren estructuras espaciales u otras formas de heterogeneidad espacial (Anselin, 1999). Por tanto, el AEDE se correspondería con los métodos de estadística descriptiva espacial.
2. Descripción de las funcionalidades básicas
2.1. Descripción del conjunto de datos
El conjunto de datos que consideramos se refiere a las 226 escuelas secundarias públicas de la región francesa de Midi-Pyrénées en el año escolar 2003-2004 (correspondiente a 175 comunas).
Para cada escuela, consideramos 13 características:
longitude: coordenada x
latitude: coordenada y
namem.city: nombre de la ciudad
index.rurality: Un factor con niveles de ruralidad.
Nb.students: El número de estudiantes por clase.
Occupancy.rate: La tasa de ocupación = [número de estudiantes] / [cantidad de estudiantes para los que la escuela ha sido diseñada].
Cost.per.student: Costo por estudiante.
Nb.students.per.class: Número promedio de estudiantes por clases.
Freq.certifies: Frecuencia de docentes certificados.
Freq.rep.stud: La frecuencia de alumnos que repitieron una clase.
Nb.specialties: La cantidad de especialidades que se ofrecen a los estudiantes en la escuela.
Teachers.age: El promedio de edades de los profesores en la escuela.
# Importando paquete GeoXp
library("GeoXp")
# Datos:
data("mp.school")
# Clase:
class(mp.school)
[1] "data.frame"
# Dimension:
dim(mp.school)
[1] 226 13
# Nombres:
names(mp.school)
[1] "longitude" "latitude"
[3] "name.city" "index.rurality"
[5] "Nb.students" "Occupancy.rate"
[7] "Cost.per.student" "Nb.students.per.class"
[9] "Freq.certifies" "Freq.agreges"
[11] "Freq.rep.stud" "Nb.specialties"
[13] "Teachers.age"
# 6 primeros datos
head(mp.school)
2.2. Principios generales
Es bastante sencillo crear un objeto espacial.
- En nuestro conjunto de datos, las unidades espaciales están representadas por
puntos.
# Seleccionando las coordenadas (longitud, latidud)
mp.school_coord <- cbind(mp.school$longitude, mp.school$latitude)
- Se crea primero un objeto
SpatialPoints que solo contiene las coordenadas de las unidades espaciales
# Convirtiendo coordenadas a objeto de puntos espaciales
mp.school_sp <- SpatialPoints(mp.school_coord)
- Se crea un objeto
SpatialPointsDataFrame que contiene tanto el objeto SpatialPoints como el data.frame:
# Convirtiendo DataFrame a objeto Data Frame de puntos espaciales
mp.school_spdf <- SpatialPointsDataFrame(mp.school_sp, mp.school)
Se pueden utilizar las coordenadas de contornos espaciales poligonales para mejorar la calidad del mapa y ayudar a identificar ubicaciones. En cuanto al formato, se puede utilizar cualquier formato que se pueda importar en R siempre que contenga las coordenadas geográficas.
- Se puede importar un formato shapefile desde ArcView usando la función
readShapePoly del paquete R maptools o la función readOGR del paquete R rgdal.
- Las dos funciones de GeoXp
polylist2list y spdf2list permiten convertir algún objeto espacial al formato de contornos GeoXp.
shp.file <- system.file("shapes/school.shp", package="GeoXp")[1] # Ruta del archivo
shp.file
[1] "C:/Users/EQUIPO/Documents/R/win-library/4.0/GeoXp/shapes/school.shp"
library("rgdal") # Para importar un formato shapefile
mp_map <- readOGR(shp.file) # Leyendo ("SpatialPolygonsDataFrame")
OGR data source with driver: ESRI Shapefile
Source: "C:\Users\EQUIPO\Documents\R\win-library\4.0\GeoXp\shapes\school.shp", layer: "school"
with 8 features
It has 2 fields
mp.contour <- spdf2list(mp_map)$poly # Convierte objeto espacial a coordenadas del contorno
# Grafico de los datos con plot
plot(mp_map, col=rainbow(8))
plot(mp.school_spdf, pch=20, add=T)

3. Funciones descriptivas
Una llamada a una función GeoXp generalmente abre tres ventanas: dos ventanas gráficas R para el gráfico estadístico y el mapa respectivamente, y una ventana Tk para el menú. Luego, el usuario selecciona en el menú el gráfico en el que desea seleccionar puntos primero. Este gráfico se activa y comienza la selección haciendo clic con el mouse.
Las funciones descriptivas se denominan barmap, boxplotmap, histomap, densitymap, histobarmap, dblehistomap, dbledensitymap, polyboxplotmap, ginimap, plot3dmap y scattermap.
Histomap:
La función histomap() dibuja un histograma de una variable dada name.var y un mapa con sitios de coordenadas de coordenadas.
histomap(mp.school_spdf,"Cost.per.student",carte=mp.contour)

- En este mapa, se puede observar las zonas donde los colegios son más costosos, y también se observa un conjunto pequeño en la zona central, puede deberse a que sea una zona urbana y a otros factores.
Barmap:
La función barmap() dibuja un diagrama de barras (barra vertical) de la variable de factor dada name.var y un mapa con los sitios de coordenadas de coordenadas (sp.obj).
barmap(mp.school_spdf,"index.rurality", carte=mp.contour,
col=c("red","green","purple"))

- En el mapa se puede observar, cómo la zona urbana está más centrada, y luego, a sus alrededores, se va distribuyendo la zona rural.
scattermap
La función scattermap dibuja un diagrama de dispersión de las variables dadas indicadas en names.var y un mapa con sitios de coordenadas de coordenadas (sp.obj).
scattermap(mp.school_spdf,
c("Occupancy.rate", "Cost.per.student"),
quantiles=c(0.25, 0.75),
carte=mp.contour,
pch = 15,
cex = 0.9,
xlab = c("Occupancy rate", "Cost per student"))
- Se puede observar que existe una relación inversa entre el costo por estudiantes y el radio de ocupación, por lo que, a mayor número de estudiantes en la escuela, menor es el costo.

boxplotmap
Diagrama de cajas de una variable dada name.var
boxplotmap(mp.school_spdf,"Occupancy.rate", carte=mp.contour)

- Se puede observar, en el diagrama de cajas que hay algunos valores atípicos en el radio de ocupación, por lo que, hay algunas zonas dónde el radio de ocupación, es alto, es decir, donde el número de estudiantes superaron la cantidad de estudiantes para los que la escuela fue diseñada.
Otras funciones:
angleplotmap: vincula un mapa y un gráfico de ángulos (solo el gráfico de ángulos está activo).
barmap: vincula un mapa y un diagrama de barras.
barnbmap: Vincula un mapa y un diagrama de barras del número de vecinos.
boxplotmap: vincula un mapa y un diagrama de caja y bigotes.
clustermap: Vincula un mapa y un mapa de barras de una variable de agrupamiento (método de k-medias).
dbledensitymap: Vincula un mapa y dos estimadores de densidad.
dblehistomap: Vincula un mapa y dos histogramas.
densitymap: vincula un mapa y un estimador de densidad.
driftmap: esta función está destinada a detectar tendencias (no interactivo).
ginimap: vincula un mapa y una gráfica de Gini (curva de Lorenz).
histobarmap: vincula un mapa a un histograma y un diagrama de barras.
histomap: vincula un mapa y un histograma.
histnbmap: Vincula un mapa y un histograma de las distancias entre vecinos.
moranplotmap: vincula un mapa y un diagrama de dispersión de Moran.
neighbormap: vincula un mapa y un diagrama vecino (diagrama de dispersión de variable contra variable para los sitios vecinos).
pcamap: Vincula un mapa y un diagrama de dispersión de los ejes principales del análisis de componentes principales.
plot3dmap: una versión tridimensional del mapa de dispersión.
polyboxplotmap: Vincula un mapa y un diagrama de caja y bigotes.
scattermap: enlaces a un mapa y un diagrama de dispersión bidimensional.
variocloudmap: vincula un mapa y una nube de variogramas (solo la nube de variogramas es activo).
LS0tDQp0aXRsZTogJyoqQW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBkYXRvcyBlc3BhY2lhbGVzIGNvbiBHZW9YcCoqJw0KYXV0aG9yOiAiRWlsaW4gTHVuYSBNLiINCmRhdGU6ICIxNCBkZSBtYXJ6byBkZSAyMDIxIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyAqKjEuIEludHJvZHVjY2nDs24gR2VvWHAgKioNCg0KKyBFcyB1biBwYXF1ZXRlIGRlIFIgcGFyYSBncsOhZmljb3MgaW50ZXJhY3Rpdm9zIGRlIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgZXNwYWNpYWxlcy4gIA0KKyBDb25qdW50byBkZSBydXRpbmFzIGVzdGFkw61zdGljYXMgYWRhcHRhZGFzIGEgbGEgZXhwbG9yYWNpw7NuIGRlIGRhdG9zIGdlb3JyZWZlcmVuY2lhZG9zLCB1bmEgaGVycmFtaWVudGEgYWRhcHRhYmxlLCBpbnRlZ3JhbCB5IHVuaWZpY2FkYS4gIA0KKyBFcyB1bmEgaGVycmFtaWVudGEgZXhwbG9yYXRvcmlhIHBhcmEgaW52ZXN0aWdhZG9yZXMgeSB1c3VhcmlvcyBleHBlcmltZW50YWRvcyBlbiBlc3RhZMOtc3RpY2FzIGVzcGFjaWFsZXMsIGVjb25vbWV0csOtYSBlc3BhY2lhbCwgZ2VvZ3JhZsOtYSwgZWNvbG9nw61hLCBlcGlkZW1pb2xvZ8OtYSwgZXRjLiANCg0KDQoqKkFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgRGF0b3MgRXNwYWNpYWxlcyoqDQpFcyBlbCBjb25qdW50byBkZSB0w6ljbmljYXMgcXVlIGRlc2NyaWJlbiB5IHZpc3VhbGl6YW4gbGFzIGRpc3RyaWJ1Y2lvbmVzIGVzcGFjaWFsZXMsIGlkZW50aWZpY2FuIGxvY2FsaXphY2lvbmVzIGF0w61waWNhcyBvIOKAnGF0w61waWNvcyBlc3BhY2lhbGVz4oCdICjigJxzcGF0aWFsIG91dGxpZXJz4oCdKSwgZGVzY3VicmVuIGVzcXVlbWFzIGRlIGFzb2NpYWNpw7NuIGVzcGFjaWFsLCBhZ3J1cGFtaWVudG9zICjigJxjbHVzdGVyc+KAnSkgbyBwdW50b3MgY2FsaWVudGVzICjigJxob3Qgc3BvdHPigJ0pIHkgc3VnaWVyZW4gZXN0cnVjdHVyYXMgZXNwYWNpYWxlcyB1IG90cmFzIGZvcm1hcyBkZSBoZXRlcm9nZW5laWRhZCBlc3BhY2lhbCAoQW5zZWxpbiwgMTk5OSkuIFBvciB0YW50bywgZWwgQUVERSBzZSBjb3JyZXNwb25kZXLDrWEgY29uIGxvcyBtw6l0b2RvcyBkZSBlc3RhZMOtc3RpY2EgZGVzY3JpcHRpdmEgZXNwYWNpYWwuDQoNCiMgKioyLiBEZXNjcmlwY2nDs24gZGUgbGFzIGZ1bmNpb25hbGlkYWRlcyBiw6FzaWNhcyoqDQoNCiMjIDIuMS4gRGVzY3JpcGNpw7NuIGRlbCBjb25qdW50byBkZSBkYXRvcw0KDQpFbCBjb25qdW50byBkZSBkYXRvcyBxdWUgY29uc2lkZXJhbW9zIHNlIHJlZmllcmUgYSBsYXMgMjI2IGVzY3VlbGFzIHNlY3VuZGFyaWFzIHDDumJsaWNhcyBkZSBsYSByZWdpw7NuIGZyYW5jZXNhIGRlIE1pZGktUHlyw6luw6llcyBlbiBlbCBhw7FvIGVzY29sYXIgMjAwMy0yMDA0IChjb3JyZXNwb25kaWVudGUgYSAxNzUgY29tdW5hcykuIA0KDQpQYXJhIGNhZGEgZXNjdWVsYSwgY29uc2lkZXJhbW9zIDEzIGNhcmFjdGVyw61zdGljYXM6ICANCg0KKyBgbG9uZ2l0dWRlYDogY29vcmRlbmFkYSB4ICANCisgYGxhdGl0dWRlYDogY29vcmRlbmFkYSB5ICANCisgYG5hbWVtLmNpdHlgOiBub21icmUgZGUgbGEgY2l1ZGFkICANCisgYGluZGV4LnJ1cmFsaXR5YDogVW4gZmFjdG9yIGNvbiBuaXZlbGVzIGRlIHJ1cmFsaWRhZC4gIA0KKyBgTmIuc3R1ZGVudHNgOiBFbCBuw7ptZXJvIGRlIGVzdHVkaWFudGVzIHBvciBjbGFzZS4gIA0KKyBgT2NjdXBhbmN5LnJhdGVgOiBMYSB0YXNhIGRlIG9jdXBhY2nDs24gPSBbbsO6bWVybyBkZSBlc3R1ZGlhbnRlc10gLyBbY2FudGlkYWQgZGUgZXN0dWRpYW50ZXMgcGFyYSBsb3MgcXVlIGxhIGVzY3VlbGEgaGEgc2lkbyBkaXNlw7FhZGFdLiAgDQorIGBDb3N0LnBlci5zdHVkZW50YDogQ29zdG8gcG9yIGVzdHVkaWFudGUuICANCisgYE5iLnN0dWRlbnRzLnBlci5jbGFzc2A6IE7Dum1lcm8gcHJvbWVkaW8gZGUgZXN0dWRpYW50ZXMgcG9yIGNsYXNlcy4gIA0KKyBgRnJlcS5jZXJ0aWZpZXNgOiBGcmVjdWVuY2lhIGRlIGRvY2VudGVzIGNlcnRpZmljYWRvcy4gIA0KKyBgRnJlcS5yZXAuc3R1ZGA6IExhIGZyZWN1ZW5jaWEgZGUgYWx1bW5vcyBxdWUgcmVwaXRpZXJvbiB1bmEgY2xhc2UuICANCisgYE5iLnNwZWNpYWx0aWVzYDogTGEgY2FudGlkYWQgZGUgZXNwZWNpYWxpZGFkZXMgcXVlIHNlIG9mcmVjZW4gYSBsb3MgZXN0dWRpYW50ZXMgZW4gbGEgZXNjdWVsYS4gIA0KKyBgVGVhY2hlcnMuYWdlYDogRWwgcHJvbWVkaW8gZGUgZWRhZGVzIGRlIGxvcyBwcm9mZXNvcmVzIGVuIGxhIGVzY3VlbGEuICANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgSW1wb3J0YW5kbyBwYXF1ZXRlIEdlb1hwDQpsaWJyYXJ5KCJHZW9YcCIpIA0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1GQUxTRX0NCiMgRGF0b3M6IA0KZGF0YSgibXAuc2Nob29sIikgIA0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1GQUxTRX0NCiMgQ2xhc2U6DQpjbGFzcyhtcC5zY2hvb2wpDQoNCiMgRGltZW5zaW9uOg0KZGltKG1wLnNjaG9vbCkNCg0KIyBOb21icmVzOg0KbmFtZXMobXAuc2Nob29sKSAgDQoNCiMgNiBwcmltZXJvcyBkYXRvcw0KaGVhZChtcC5zY2hvb2wpDQpgYGANCg0KIyMgMi4yLiBQcmluY2lwaW9zIGdlbmVyYWxlcw0KDQpFcyBiYXN0YW50ZSBzZW5jaWxsbyBjcmVhciB1biBvYmpldG8gZXNwYWNpYWwuIA0KIA0KKyBFbiBudWVzdHJvIGNvbmp1bnRvIGRlIGRhdG9zLCBsYXMgdW5pZGFkZXMgZXNwYWNpYWxlcyBlc3TDoW4gcmVwcmVzZW50YWRhcyBwb3IgYHB1bnRvc2AuICANCg0KYGBge3J9DQojIFNlbGVjY2lvbmFuZG8gbGFzIGNvb3JkZW5hZGFzIChsb25naXR1ZCwgbGF0aWR1ZCkNCm1wLnNjaG9vbF9jb29yZCA8LSBjYmluZChtcC5zY2hvb2wkbG9uZ2l0dWRlLCBtcC5zY2hvb2wkbGF0aXR1ZGUpIA0KYGBgDQoNCisgU2UgY3JlYSBwcmltZXJvIHVuIG9iamV0byBgU3BhdGlhbFBvaW50c2AgcXVlIHNvbG8gY29udGllbmUgbGFzIGNvb3JkZW5hZGFzIGRlIGxhcyB1bmlkYWRlcyBlc3BhY2lhbGVzICANCmBgYHtyfQ0KIyBDb252aXJ0aWVuZG8gY29vcmRlbmFkYXMgYSBvYmpldG8gZGUgcHVudG9zIGVzcGFjaWFsZXMNCm1wLnNjaG9vbF9zcCA8LSBTcGF0aWFsUG9pbnRzKG1wLnNjaG9vbF9jb29yZCkNCmBgYA0KDQorIFNlIGNyZWEgdW4gb2JqZXRvIGBTcGF0aWFsUG9pbnRzRGF0YUZyYW1lYCBxdWUgY29udGllbmUgdGFudG8gZWwgb2JqZXRvIFNwYXRpYWxQb2ludHMgY29tbyBlbCBkYXRhLmZyYW1lOg0KYGBge3J9DQojIENvbnZpcnRpZW5kbyBEYXRhRnJhbWUgYSBvYmpldG8gRGF0YSBGcmFtZSBkZSBwdW50b3MgZXNwYWNpYWxlcw0KbXAuc2Nob29sX3NwZGYgPC0gU3BhdGlhbFBvaW50c0RhdGFGcmFtZShtcC5zY2hvb2xfc3AsIG1wLnNjaG9vbCkNCmBgYA0KDQpTZSBwdWVkZW4gdXRpbGl6YXIgbGFzIGNvb3JkZW5hZGFzIGRlIGNvbnRvcm5vcyBlc3BhY2lhbGVzIHBvbGlnb25hbGVzIHBhcmEgbWVqb3JhciBsYSBjYWxpZGFkIGRlbCBtYXBhIHkgYXl1ZGFyIGEgaWRlbnRpZmljYXIgdWJpY2FjaW9uZXMuIEVuIGN1YW50byBhbCBmb3JtYXRvLCBzZSBwdWVkZSB1dGlsaXphciBjdWFscXVpZXIgZm9ybWF0byBxdWUgc2UgcHVlZGEgaW1wb3J0YXIgZW4gUiBzaWVtcHJlIHF1ZSBjb250ZW5nYSBsYXMgY29vcmRlbmFkYXMgZ2VvZ3LDoWZpY2FzLiANCg0KKyAgU2UgcHVlZGUgaW1wb3J0YXIgdW4gZm9ybWF0byBzaGFwZWZpbGUgZGVzZGUgQXJjVmlldyB1c2FuZG8gbGEgZnVuY2nDs24gKipgcmVhZFNoYXBlUG9seWAgZGVsIHBhcXVldGUgKlIgbWFwdG9vbHMqICoqIG8gbGEgZnVuY2nDs24gYHJlYWRPR1JgIGRlbCBwYXF1ZXRlICpSIHJnZGFsKi4NCisgTGFzIGRvcyBmdW5jaW9uZXMgZGUgR2VvWHAgYHBvbHlsaXN0Mmxpc3RgIHkgYHNwZGYybGlzdGAgcGVybWl0ZW4gY29udmVydGlyIGFsZ8O6biBvYmpldG8gZXNwYWNpYWwgYWwgZm9ybWF0byBkZSBjb250b3Jub3MgR2VvWHAuIA0KDQpgYGB7cn0NCnNocC5maWxlIDwtIHN5c3RlbS5maWxlKCJzaGFwZXMvc2Nob29sLnNocCIsIHBhY2thZ2U9Ikdlb1hwIilbMV0gIyBSdXRhIGRlbCBhcmNoaXZvDQpzaHAuZmlsZQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KbGlicmFyeSgicmdkYWwiKSAjIFBhcmEgaW1wb3J0YXIgdW4gZm9ybWF0byBzaGFwZWZpbGUNCm1wX21hcCA8LSByZWFkT0dSKHNocC5maWxlKSAjIExleWVuZG8gICgiU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIikNCmBgYA0KDQpgYGB7cn0NCm1wLmNvbnRvdXIgPC0gc3BkZjJsaXN0KG1wX21hcCkkcG9seSAjIENvbnZpZXJ0ZSBvYmpldG8gZXNwYWNpYWwgYSBjb29yZGVuYWRhcyBkZWwgY29udG9ybm8NCmBgYA0KDQpgYGB7cn0NCiMgR3JhZmljbyBkZSBsb3MgZGF0b3MgY29uIHBsb3QNCnBsb3QobXBfbWFwLCBjb2w9cmFpbmJvdyg4KSkNCnBsb3QobXAuc2Nob29sX3NwZGYsIHBjaD0yMCwgYWRkPVQpDQpgYGANCg0KDQoNCg0KIyAqKjMuIEZ1bmNpb25lcyBkZXNjcmlwdGl2YXMqKg0KDQpVbmEgbGxhbWFkYSBhIHVuYSBmdW5jacOzbiBHZW9YcCBnZW5lcmFsbWVudGUgYWJyZSB0cmVzIHZlbnRhbmFzOiBkb3MgdmVudGFuYXMgZ3LDoWZpY2FzIFIgcGFyYSBlbCBncsOhZmljbyBlc3RhZMOtc3RpY28geSBlbCBtYXBhIHJlc3BlY3RpdmFtZW50ZSwgeSB1bmEgdmVudGFuYSBUayBwYXJhIGVsIG1lbsO6LiBMdWVnbywgZWwgdXN1YXJpbyBzZWxlY2Npb25hIGVuIGVsIG1lbsO6IGVsIGdyw6FmaWNvIGVuIGVsIHF1ZSBkZXNlYSBzZWxlY2Npb25hciBwdW50b3MgcHJpbWVyby4gRXN0ZSBncsOhZmljbyBzZSBhY3RpdmEgeSBjb21pZW56YSBsYSBzZWxlY2Npw7NuIGhhY2llbmRvIGNsaWMgY29uIGVsIG1vdXNlLg0KDQpMYXMgZnVuY2lvbmVzIGRlc2NyaXB0aXZhcyBzZSBkZW5vbWluYW4gYmFybWFwLCBib3hwbG90bWFwLCBoaXN0b21hcCwgZGVuc2l0eW1hcCwgaGlzdG9iYXJtYXAsIGRibGVoaXN0b21hcCwgZGJsZWRlbnNpdHltYXAsIHBvbHlib3hwbG90bWFwLCBnaW5pbWFwLCBwbG90M2RtYXAgeSBzY2F0dGVybWFwLg0KDQojIyMgSGlzdG9tYXA6DQoNCkxhIGZ1bmNpw7NuIGBoaXN0b21hcCgpYCBkaWJ1amEgdW4gaGlzdG9ncmFtYSBkZSB1bmEgdmFyaWFibGUgZGFkYSBuYW1lLnZhciB5IHVuIG1hcGEgY29uIHNpdGlvcyBkZSBjb29yZGVuYWRhcyBkZSBjb29yZGVuYWRhcy4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQpoaXN0b21hcChtcC5zY2hvb2xfc3BkZiwiQ29zdC5wZXIuc3R1ZGVudCIsY2FydGU9bXAuY29udG91cikNCmBgYA0KDQohW10oQzpcVXNlcnNcRVFVSVBPXERvY3VtZW50c1xHaXRIdWJcRXN0YWRpc3RpY2FFc3BhY2lhbFxpbWFnZXNcaGlzdG9ncmFtYS5wbmcpDQoNCiogRW4gZXN0ZSBtYXBhLCBzZSBwdWVkZSBvYnNlcnZhciBsYXMgem9uYXMgZG9uZGUgbG9zIGNvbGVnaW9zIHNvbiBtw6FzIGNvc3Rvc29zLCB5IHRhbWJpw6luIHNlIG9ic2VydmEgdW4gY29uanVudG8gcGVxdWXDsW8gZW4gbGEgem9uYSBjZW50cmFsLCBwdWVkZSBkZWJlcnNlIGEgcXVlIHNlYSB1bmEgem9uYSB1cmJhbmEgeSBhIG90cm9zIGZhY3RvcmVzLg0KDQojIyMgQmFybWFwOg0KDQpMYSBmdW5jacOzbiBgYmFybWFwKClgIGRpYnVqYSB1biBkaWFncmFtYSBkZSBiYXJyYXMgKGJhcnJhIHZlcnRpY2FsKSBkZSBsYSB2YXJpYWJsZSBkZSBmYWN0b3IgZGFkYSBuYW1lLnZhciB5IHVuIG1hcGEgY29uIGxvcyBzaXRpb3MgZGUgY29vcmRlbmFkYXMgZGUgY29vcmRlbmFkYXMgKHNwLm9iaikuDQoNCmBgYHtyfQ0KYmFybWFwKG1wLnNjaG9vbF9zcGRmLCJpbmRleC5ydXJhbGl0eSIsIGNhcnRlPW1wLmNvbnRvdXIsIA0KICAgICAgIGNvbD1jKCJyZWQiLCJncmVlbiIsInB1cnBsZSIpKQ0KYGBgDQoNCiFbXShDOlxVc2Vyc1xFUVVJUE9cRG9jdW1lbnRzXEdpdEh1YlxFc3RhZGlzdGljYUVzcGFjaWFsXGltYWdlc1xiYXJyYXMucG5nKQ0KDQoqIEVuIGVsIG1hcGEgc2UgcHVlZGUgb2JzZXJ2YXIsIGPDs21vIGxhIHpvbmEgdXJiYW5hIGVzdMOhIG3DoXMgY2VudHJhZGEsIHkgbHVlZ28sIGEgc3VzIGFscmVkZWRvcmVzLCBzZSB2YSBkaXN0cmlidXllbmRvIGxhIHpvbmEgcnVyYWwuDQoNCiMjIyBzY2F0dGVybWFwDQoNCkxhIGZ1bmNpw7NuIGBzY2F0dGVybWFwYCBkaWJ1amEgdW4gZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24gZGUgbGFzIHZhcmlhYmxlcyBkYWRhcyBpbmRpY2FkYXMgZW4gbmFtZXMudmFyIHkgdW4gbWFwYSBjb24gc2l0aW9zIGRlIGNvb3JkZW5hZGFzIGRlIGNvb3JkZW5hZGFzIChzcC5vYmopLg0KDQpgYGB7cn0NCnNjYXR0ZXJtYXAobXAuc2Nob29sX3NwZGYsIA0KICAgICAgICAgICBjKCJPY2N1cGFuY3kucmF0ZSIsICJDb3N0LnBlci5zdHVkZW50IiksDQogICAgICAgICAgIHF1YW50aWxlcz1jKDAuMjUsIDAuNzUpLA0KICAgICAgICAgICBjYXJ0ZT1tcC5jb250b3VyLA0KICAgICAgICAgICBwY2ggPSAxNSwNCiAgICAgICAgICAgY2V4ID0gMC45LCANCiAgICAgICAgICAgeGxhYiA9IGMoIk9jY3VwYW5jeSByYXRlIiwgIkNvc3QgcGVyIHN0dWRlbnQiKSkNCmBgYA0KDQoqIFNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBleGlzdGUgdW5hIHJlbGFjacOzbiBpbnZlcnNhIGVudHJlIGVsIGNvc3RvIHBvciBlc3R1ZGlhbnRlcyB5IGVsIHJhZGlvIGRlIG9jdXBhY2nDs24sIHBvciBsbyBxdWUsIGEgbWF5b3IgbsO6bWVybyBkZSBlc3R1ZGlhbnRlcyBlbiBsYSBlc2N1ZWxhLCBtZW5vciBlcyBlbCBjb3N0by4NCg0KIVtdKEM6XFVzZXJzXEVRVUlQT1xEb2N1bWVudHNcR2l0SHViXEVzdGFkaXN0aWNhRXNwYWNpYWxcaW1hZ2VzXHNjYXR0ZXJwbG90LnBuZykNCg0KIyMjIGJveHBsb3RtYXANCg0KRGlhZ3JhbWEgZGUgY2FqYXMgZGUgdW5hIHZhcmlhYmxlIGRhZGEgbmFtZS52YXINCg0KYGBge3J9DQpib3hwbG90bWFwKG1wLnNjaG9vbF9zcGRmLCJPY2N1cGFuY3kucmF0ZSIsIGNhcnRlPW1wLmNvbnRvdXIpDQpgYGANCg0KIVtdKEM6XFVzZXJzXEVRVUlQT1xEb2N1bWVudHNcR2l0SHViXEVzdGFkaXN0aWNhRXNwYWNpYWxcaW1hZ2VzXGJveHBsb3RtYXAucG5nKQ0KDQoqIFNlIHB1ZWRlIG9ic2VydmFyLCBlbiBlbCBkaWFncmFtYSBkZSBjYWphcyBxdWUgaGF5IGFsZ3Vub3MgdmFsb3JlcyBhdMOtcGljb3MgZW4gZWwgcmFkaW8gZGUgb2N1cGFjacOzbiwgcG9yIGxvIHF1ZSwgaGF5IGFsZ3VuYXMgem9uYXMgZMOzbmRlIGVsIHJhZGlvIGRlIG9jdXBhY2nDs24sIGVzIGFsdG8sIGVzIGRlY2lyLCBkb25kZSBlbCBuw7ptZXJvIGRlIGVzdHVkaWFudGVzIHN1cGVyYXJvbiBsYSBjYW50aWRhZCBkZSBlc3R1ZGlhbnRlcyBwYXJhIGxvcyBxdWUgbGEgZXNjdWVsYSBmdWUgZGlzZcOxYWRhLg0KDQojIyMgT3RyYXMgZnVuY2lvbmVzOg0KDQoxLiBgYW5nbGVwbG90bWFwYDogdmluY3VsYSB1biBtYXBhIHkgdW4gZ3LDoWZpY28gZGUgw6FuZ3Vsb3MgKHNvbG8gZWwgZ3LDoWZpY28gZGUgw6FuZ3Vsb3MgZXN0w6EgYWN0aXZvKS4NCjIuIGBiYXJtYXBgOiB2aW5jdWxhIHVuIG1hcGEgeSB1biBkaWFncmFtYSBkZSBiYXJyYXMuDQozLiBgYmFybmJtYXBgOiBWaW5jdWxhIHVuIG1hcGEgeSB1biBkaWFncmFtYSBkZSBiYXJyYXMgZGVsIG7Dum1lcm8gZGUgdmVjaW5vcy4NCjQuIGBib3hwbG90bWFwYDogdmluY3VsYSB1biBtYXBhIHkgdW4gZGlhZ3JhbWEgZGUgY2FqYSB5IGJpZ290ZXMuDQo1LiBgY2x1c3Rlcm1hcGA6IFZpbmN1bGEgdW4gbWFwYSB5IHVuIG1hcGEgZGUgYmFycmFzIGRlIHVuYSB2YXJpYWJsZSBkZSBhZ3J1cGFtaWVudG8gKG3DqXRvZG8gZGUgay1tZWRpYXMpLg0KNi4gYGRibGVkZW5zaXR5bWFwYDogVmluY3VsYSB1biBtYXBhIHkgZG9zIGVzdGltYWRvcmVzIGRlIGRlbnNpZGFkLg0KNy4gYGRibGVoaXN0b21hcGA6IFZpbmN1bGEgdW4gbWFwYSB5IGRvcyBoaXN0b2dyYW1hcy4NCjguIGBkZW5zaXR5bWFwYDogdmluY3VsYSB1biBtYXBhIHkgdW4gZXN0aW1hZG9yIGRlIGRlbnNpZGFkLg0KOS4gYGRyaWZ0bWFwYDogZXN0YSBmdW5jacOzbiBlc3TDoSBkZXN0aW5hZGEgYSBkZXRlY3RhciB0ZW5kZW5jaWFzIChubyBpbnRlcmFjdGl2bykuDQoxMC4gYGdpbmltYXBgOiB2aW5jdWxhIHVuIG1hcGEgeSB1bmEgZ3LDoWZpY2EgZGUgR2luaSAoY3VydmEgZGUgTG9yZW56KS4NCjExLiBgaGlzdG9iYXJtYXBgOiB2aW5jdWxhIHVuIG1hcGEgYSB1biBoaXN0b2dyYW1hIHkgdW4gZGlhZ3JhbWEgZGUgYmFycmFzLg0KMTIuIGBoaXN0b21hcGA6IHZpbmN1bGEgdW4gbWFwYSB5IHVuIGhpc3RvZ3JhbWEuDQoxMy4gYGhpc3RuYm1hcGA6IFZpbmN1bGEgdW4gbWFwYSB5IHVuIGhpc3RvZ3JhbWEgZGUgbGFzIGRpc3RhbmNpYXMgZW50cmUgdmVjaW5vcy4NCjE0LiBgbW9yYW5wbG90bWFwYDogdmluY3VsYSB1biBtYXBhIHkgdW4gZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24gZGUgTW9yYW4uDQoxNS4gYG5laWdoYm9ybWFwYDogdmluY3VsYSB1biBtYXBhIHkgdW4gZGlhZ3JhbWEgdmVjaW5vIChkaWFncmFtYSBkZSBkaXNwZXJzacOzbiBkZSB2YXJpYWJsZSBjb250cmEgdmFyaWFibGUgcGFyYSBsb3Mgc2l0aW9zIHZlY2lub3MpLg0KMTYuIGBwY2FtYXBgOiBWaW5jdWxhIHVuIG1hcGEgeSB1biBkaWFncmFtYSBkZSBkaXNwZXJzacOzbiBkZSBsb3MgZWplcyBwcmluY2lwYWxlcyBkZWwgYW7DoWxpc2lzIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KMTcuIGBwbG90M2RtYXBgOiB1bmEgdmVyc2nDs24gdHJpZGltZW5zaW9uYWwgZGVsIG1hcGEgZGUgZGlzcGVyc2nDs24uDQoxOC4gYHBvbHlib3hwbG90bWFwYDogVmluY3VsYSB1biBtYXBhIHkgdW4gZGlhZ3JhbWEgZGUgY2FqYSB5IGJpZ290ZXMuDQoxOS4gYHNjYXR0ZXJtYXBgOiBlbmxhY2VzIGEgdW4gbWFwYSB5IHVuIGRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuIGJpZGltZW5zaW9uYWwuDQoyMC4gYHZhcmlvY2xvdWRtYXBgOiB2aW5jdWxhIHVuIG1hcGEgeSB1bmEgbnViZSBkZSB2YXJpb2dyYW1hcyAoc29sbyBsYSBudWJlIGRlIHZhcmlvZ3JhbWFzIGVzDQphY3Rpdm8pLg==