Planeación estratégica basada en analítica prescriptiva

Grupo 503

Profesor Rodolfo Miguel Gameros

Equipo 7:

A00833113 - Avril Lobato

A01771127 - Lesly Darian Romero Vázquez

A00831105 - Jazmín Cortez Mendoza

A01284611 - Lisset Hernández

Análisis Exploratorio de Datos Espaciales (ESDA: Exploratory Spatial Data Analysis)

El Análisis exploratorio de datos espacial involucra diferentes herramientas para visualizar los patrones espaciales existentes en la base de datos. Dichos datos se pueden segregar o descomponer los patrones espaciales en diferentes elementos a lo largo des mapa, y a su vez medir la extensión de estas autocorrelaciones espaciales. El principal paquete de R que se utiliza para este propósito es ‘geostan’.

Importación de bases de datos y geocercas

A continuación, se realiza a importación de la bd a nivel estatal

mx_state <- read.csv("state_data.csv")
head(n=10, mx_state)
##                  state year state_id crime_rate unemployment employment
## 1       Aguascalientes 2021     1057       6.75         0.04       0.97
## 2      Baja California 2021     2304      84.67         0.01       0.98
## 3  Baja California Sur 2021     2327       8.52         0.03       0.97
## 4             Campeche 2021     1086       9.22         0.02       0.98
## 5              Chiapas 2021     1182      10.01         0.05       0.97
## 6            Chihuahua 2021      888      71.98         0.04       0.97
## 7     Ciudad de Mexico 2021     1114      11.58         0.06       0.94
## 8             Coahuila 2021      933       4.92         0.04       0.94
## 9               Colima 2021     1111      71.97         0.05       0.97
## 10             Durango 2021     1004       7.91         0.05       0.97
##    business_activity real_wage real_ave_month_income pop_density lq_primary
## 1              -1.90    361.02               5641.67      261.21       0.16
## 2               2.47    388.22               7599.62       53.19       0.47
## 3              -2.12    345.57               8660.90       11.27       0.73
## 4              -2.44    414.48               5357.29       16.42       0.73
## 5              -2.41    312.37               6581.28       77.16       1.56
## 6              -1.25    362.93               5708.75       15.30       0.64
## 7              -2.08    466.80               4528.42     6195.59       0.03
## 8              -1.38    365.18               6480.66       21.44       0.17
## 9              -2.31    324.82               6097.68      136.06       1.19
## 10             -1.93    289.78               4969.61       15.07       1.05
##    lq_secondary lq_tertiary new_fdi_real_mxn log_new_fdi_real_mxn  region_a
## 1          1.24        1.00          1270.03                 3.10     Bajio
## 2          1.62        0.86         20407.81                 4.31     Norte
## 3          0.51        1.13         19022.55                 4.28 Occidente
## 4          0.78        1.06          2390.64                 3.38       Sur
## 5          0.88        0.99           189.58                 2.28       Sur
## 6          1.97        0.80          7153.63                 3.86     Norte
## 7          0.58        1.14         34394.95                 4.54    Centro
## 8          1.55        0.93          6254.19                 3.80     Norte
## 9          0.58        1.07            63.41                 1.80 Occidente
## 10         1.15        0.96          -483.58                -2.68 Occidente
##    region_b
## 1         2
## 2         3
## 3         4
## 4         5
## 5         5
## 6         3
## 7         1
## 8         3
## 9         4
## 10        4
glimpse(mx_state)
## Rows: 32
## Columns: 17
## $ state                 <chr> "Aguascalientes", "Baja California", "Baja Calif…
## $ year                  <int> 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, …
## $ state_id              <int> 1057, 2304, 2327, 1086, 1182, 888, 1114, 933, 11…
## $ crime_rate            <dbl> 6.75, 84.67, 8.52, 9.22, 10.01, 71.98, 11.58, 4.…
## $ unemployment          <dbl> 0.04, 0.01, 0.03, 0.02, 0.05, 0.04, 0.06, 0.04, …
## $ employment            <dbl> 0.97, 0.98, 0.97, 0.98, 0.97, 0.97, 0.94, 0.94, …
## $ business_activity     <dbl> -1.90, 2.47, -2.12, -2.44, -2.41, -1.25, -2.08, …
## $ real_wage             <dbl> 361.02, 388.22, 345.57, 414.48, 312.37, 362.93, …
## $ real_ave_month_income <dbl> 5641.67, 7599.62, 8660.90, 5357.29, 6581.28, 570…
## $ pop_density           <dbl> 261.21, 53.19, 11.27, 16.42, 77.16, 15.30, 6195.…
## $ lq_primary            <dbl> 0.16, 0.47, 0.73, 0.73, 1.56, 0.64, 0.03, 0.17, …
## $ lq_secondary          <dbl> 1.24, 1.62, 0.51, 0.78, 0.88, 1.97, 0.58, 1.55, …
## $ lq_tertiary           <dbl> 1.00, 0.86, 1.13, 1.06, 0.99, 0.80, 1.14, 0.93, …
## $ new_fdi_real_mxn      <dbl> 1270.03, 20407.81, 19022.55, 2390.64, 189.58, 71…
## $ log_new_fdi_real_mxn  <dbl> 3.10, 4.31, 4.28, 3.38, 2.28, 3.86, 4.54, 3.80, …
## $ region_a              <chr> "Bajio", "Norte", "Occidente", "Sur", "Sur", "No…
## $ region_b              <int> 2, 3, 4, 5, 5, 3, 1, 3, 4, 4, 2, 5, 1, 4, 1, 4, …

Seguidamente, se leen los archivos de las formas geométricas (geocercas) que determinarán los mapas a realizar después para visualizar los datos; en este caso se realiza a nivel estado, los cuales son 32 en México.

mx_state_map <- st_read("mexlatlong.shp")
## Reading layer `mexlatlong' from data source 
##   `C:\Users\AVRIL\Downloads\mexlatlong.shp' using driver `ESRI Shapefile'
## Simple feature collection with 32 features and 19 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -118.4042 ymin: 14.55055 xmax: -86.73862 ymax: 32.71846
## CRS:           NA
#mx_state_map <- read_sf("mexlatlong.shp")

Basic Map Making

Se realiza exploración visual básica del conjunto de datos geoespaciales a nivel estatal en México, útil para identificar patrones o validar la información unida mediante el geo_join. Cada mapa representa un atributo diferente, como:

  • OBJECTID, FIPS_ADMIN, GMI_ADMIN, ADMIN_NAME: identificadores y nombres administrativos de los estados.

  • POP_ADMIN: muestra diferencias de población entre estados (por ejemplo, CDMX y Edomex con colores más intensos).

  • CNTRY_NAME, FIPS_CNTRY, GMI_CNTRY, TYPE_ENG: datos que son iguales para todos los estados, ya que todos pertenecen a México.

state_geodata <- geo_join(mx_state_map,mx_state,'OBJECTID','state_id',how='inner')
plot(state_geodata)

Visualización a nivel estado

Se observa y visualiza el mapa con los estados de México, acorde a esto se mezcla la data de las geocercas con alguna de las variables seleccionadas de la tabla de datos inicial para su análisis geoespacial.

tm_shape(mx_state_map) +
  tm_polygons(col = "black") +
  tm_compass(position = c("left", "bottom")) +
  tm_text("ADMIN_NAME", size = "AREA") +
  tm_layout(title = "Estados de México")

Distribución de Business Activity por Estado

businessactivity <- tm_shape(state_geodata) + 
  tm_polygons(
    col = "business_activity",
    palette = "-RdBu",  # el signo "-" invierte los colores para que los negativos estén en azul
    style = "cont",
    title = "Business Activity"
  ) +
  tm_layout(
    main.title = "Business Activity",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

Distribución de Desempleo por Estado

unemployment <- tm_shape(state_geodata) + 
  tm_polygons(
    col = "unemployment",
    palette = "viridis",       # sin el "-" para que los valores más bajos sean claros
    style = "quantile",
    n = 8,
    title = "Unemployment"
  ) +
  tm_layout(
    main.title = "Unemployment",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

Mapas de Business Activity & Unemployment

Business Activity:

  • Casi todo el país está en azul, lo que sugiere que la mayoría de los estados tienen valores negativos o bajos de business_activity.

  • Baja California aparece con un valor rojo oscuro → por lo que puede destacar en tener una actividad empresarial notablemente más alta o diferente.

Unemployment:

  • Guerrero, Baja California, Campeche, tienen desempleo más bajo (morado oscuro).

  • Nuevo León un rago medio-bajo de desempleo.

  • Algunos estados como CDMX, Chiapas o Veracruz están en tonos más claros, lo que indica mayor desempleo relativo.

tmap_arrange(businessactivity, unemployment, ncol = 2)

Matriz de Conectividad Espacial

Se crea matriz de conectividad espacial o lista de vecinos entre polígonos para lo cual se usa el parámetro de QUEEN para definir la vecindad, en dónde se tomarán en cuaenta si dos polígonos son vecinos o, si comparten un borde o un punto (hace la cercanía más inclusiva).

Con base en el summary obtenemos lo siguiente:

  • Hay 32 polígonos (32 estados de México).

  • Hay 138 conexiones de vecindad entre ellos.

  • Proporción de pares vecinos con relación al total posible = 13.5%

  • Cada estado tiene, en promedio, 4.31 vecinos

  • Sólo 1 estado tiene 1 vecino. Baja California Sur

  • Sólo 1 estado está conectado con 9 vecinos San Luis Potosí

swm  <- poly2nb(mx_state_map, queen=T)

summary(swm) # The average number of neighbors is 4.31
## Neighbour list object:
## Number of regions: 32 
## Number of nonzero links: 138 
## Percentage nonzero weights: 13.47656 
## Average number of links: 4.3125 
## Link number distribution:
## 
## 1 2 3 4 5 6 7 8 9 
## 1 6 6 6 5 2 3 2 1 
## 1 least connected region:
## 31 with 1 link
## 1 most connected region:
## 8 with 9 links
mx_state_map$ADMIN_NAME[8]   # Estado más conectado (con 9 vecinos)
## [1] "San Luis Potosi"
mx_state_map$ADMIN_NAME[31]  # Estado menos conectado (con 1 vecino)
## [1] "Baja California Sur"
state_geodata$ADMIN_NAME[8]   # Estado más conectado (con 9 vecinos)
## [1] "San Luis Potosi"
state_geodata$ADMIN_NAME[31]  # Estado menos conectado (con 1 vecino)
## [1] "Baja California Sur"
# Se muestran las 9 conexiones del Estado con mayor número de conexiones, es decir, de San Luis Potosí
swm[[8]]
## [1]  2  3  4  7  9 11 12 13 16
# Listado de estados conectados con San Luis Potosí
mx_state_map$ADMIN_NAME[swm[[8]]]
## [1] "Coahuila"   "Nuevo Leon" "Tamaulipas" "Zacatecas"  "Jalisco"   
## [6] "Veracruz"   "Guanajuato" "Queretaro"  "Hidalgo"
# Comprobación de estados conectados con San Luis Potosí
state_geodata$ADMIN_NAME[swm[[8]]]
## [1] "Coahuila"   "Nuevo Leon" "Tamaulipas" "Zacatecas"  "Jalisco"   
## [6] "Veracruz"   "Guanajuato" "Queretaro"  "Hidalgo"

Visualización Gráfica de la matriz de conectividad (Vecindades estilo ‘Reina’) del país.

# 1. Crear lista de vecinos
swm <- poly2nb(mx_state_map, queen = TRUE)

# 2. Convertir a matriz de pesos espaciales
sswm <- nb2listw(swm, style = "W", zero.policy = TRUE)

# 3. Convertir a objeto "Spatial" (para funciones más antigu
mx_state_map_a <- as(mx_state_map, "Spatial")

# 4. Obtener centroides (coordenadas)
mx_state_map_centroid <- coordinates(mx_state_map_a)

# 5. Graficar el mapa base
plot(mx_state_map_a, border = "blue", axes = FALSE, las = 1, main = "Mexico's States Queen SWM")
plot(mx_state_map_a, col = "grey", border = grey(0.9), axes = TRUE, add = TRUE)

# 6. Dibujar líneas de conectividad (vecindad)
plot(sswm, coords = mx_state_map_centroid, pch = 19, cex = 0.1, col = "red", add = TRUE)

# 7. Agregar nombres de los estados con ajuste
pointLabel(
  x = mx_state_map_centroid[,1],
  y = mx_state_map_centroid[,2],
  labels = mx_state_map$ADMIN_NAME,
  cex = 0.5,
  col = "black"
)

Análisis de Autocorrelación Espacial

Índice Global de Moran

Teóricamente el rango de Moran se muestra entre –1 y +1, en dónde: * +1 Alta autocorrelación espacial positiva (valores similares están cerca entre sí).

  • 0 Distribución aleatoria (no hay patrón espacial).

  • -1 Alta autocorrelación espacial negativa (valores diferentes están cerca entre sí).

Acorde a lo anterior, se genera codigo para determinar si el desempleo (unemployment) tiene autocorrelación espacial, es decir, si los estados ya sea con alto o bajo desempleo tienden a estar cerca unos de otros. También se analiza si el nivel de actividad empresarial (business_activity) tiene o no autocorrelación espacial, es decir, si los estados ya sea con alto o bajo nivel de actividad tienden a estar cerca unos de otros.

moran.test(state_geodata$business_activity, sswm)       # Global Moran's I is 0.18 but statistically significant (p-value > 10%). 
## 
##  Moran I test under randomisation
## 
## data:  state_geodata$business_activity  
## weights: sswm    
## 
## Moran I statistic standard deviate = 2.6024, p-value = 0.004629
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.184181268      -0.032258065       0.006917295
moran.test(state_geodata$unemployment, sswm)            # Global Moran's I is 0.021 but not statistically significant (p-value > 10%). 
## 
##  Moran I test under randomisation
## 
## data:  state_geodata$unemployment  
## weights: sswm    
## 
## Moran I statistic standard deviate = 0.43866, p-value = 0.3305
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##        0.02162698       -0.03225806        0.01508982

Presentación de resultados

Actividad Empresarial (Business Activity )

  • Moran’s I = 0.184 → hay autocorrelación espacial positiva: regiones con alta actividad empresarial tienden a estar cerca de otras similares.

  • P-value = 0.0046 → es altamente significativo (p < 0.01).

Existe un patrón espacial fuerte. La actividad empresarial no está distribuida aleatoriamente; hay agrupamientos claros.

Desempleo (Unemployment)

  • Moran’s I = 0.0216 (cercano a 0) sugiere poca autocorrelación espacial, regiones con alto desempleo pueden o no tender a estar cerca de otras similares, pero el índice no es igual o mayor a 0.35.

  • P-value = 0.3305 > 0.10 → No es estadísticamente significativo (p>0.10).

No hay evidencia de que el desempleo esté agrupado geográficamente. Su distribución parece aleatoria pero no cumple con los estándares mínimos por ende, se realiza lag.

table <- data.frame(Variable = c("Business Activity", "Unemployment"), GM = c(0.184, 0.021), Significance = c("***", "NS"))
table
##            Variable    GM Significance
## 1 Business Activity 0.184          ***
## 2      Unemployment 0.021           NS

Identificación de Clusters

Se realiza cálculo de lags de acuerdo con la matriz de conectividad anteriormente creada

state_geodata$sp_lag_unemployment <- lag.listw(sswm, state_geodata$unemployment, zero.policy=TRUE) 
state_geodata$sp_lag_business_activity <- lag.listw(sswm, state_geodata$business_activity, zero.policy=TRUE)

Mapas de lag para Business Activity y Unemployment

Actividad Empresarial (Business Activity)

Mapa de businessactivity: Valor real por estado

  • Baja California tiene actividad negativa más alta (rojo oscuro).

  • El resto del país tiene valores más moderadamente negativos (azules claros a medios).

  • Algunos estados del sur/sureste tienen actividad levemente positiva.

Mapa de ba_lag: Promedio de actividad empresarial en los estados vecinos

  • El norte del país: colores fuertes en naranjas → se concentran los vecindarios (estados) con mayor actividad empresarial.

  • Contraste con el sur: colores claros → sus vecinos tienen baja actividad empresarial.

  • Algunos estados como Sonora y Baja California tienen valores altos en lag pero bajos en el presente, lo que sugiere que están rodeados de estados con mayor actividad.

Se observa que claramente si hay agrupamiento espacial positivo ya que se nota la diferencia de actividad empresarial entre el Norte y el Sur del país (clústeres regionales de actividad).

Desempleo (Unemployment)

Mapa de Unemployment: Porcentaje de desempleo en cada estado

  • Distribución variada, no tan clara como Business Activity.

  • Estados como Nayarit y Baja California Sur tienen desempleo relativamente alto.

  • Varios estados del norte y centro tienen desempleo medio-bajo.

Mapa de Lag-1 Unemployment: Promedio de desempleo en los vecinos de cada estado

  • Algunos estados como Chiapas o Campeche tienen valores moderados pero están rodeados de estados con bajo desempleo.

  • Baja California Sur se mantiene con alto desempleo y sus vecinos también, reforzando la presencia de un cluster negativo.

  • Muestra que el desempleo está más fragmentado, no hay patrones tan fuertes ni continuidad regional clara.

  • Refuerza el resultado del estadístico Moran, que nos mostró que el desempleo no tiene autocorrelación espacial significativa, sino aleatoria.

Algunos estados están dentro de clusters donde tanto ellos como sus vecinos tienen valores similares, especialmente en desempleo (posible autocorrelación espacial). Asimismo, se observa que claramente no hay agrupamiento espacial positivo ya que no se diferencia la variación de la tasa de desempleo entre el Norte, Centro y Sur del país.

# Calcular rangos comunes
ba_range <- range(c(state_geodata$business_activity, state_geodata$sp_lag_business_activity), na.rm = TRUE)
unemp_range <- range(c(state_geodata$unemployment, state_geodata$sp_lag_unemployment), na.rm = TRUE)

# Mapa de Business Activity
businessactivity1 <- tm_shape(state_geodata) +  
  tm_polygons(
    col = "business_activity",
    palette = "-RdBu",
    style = "cont",
    title = "Business Activity",
    breaks = seq(ba_range[1], ba_range[2], length.out = 10)  # escala común
  ) +
  tm_layout(
    main.title = "Business Activity",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa de Business Activity (Lag)
ba_lag1 <- tm_shape(state_geodata) + 
  tm_polygons(
    col = "sp_lag_business_activity",
    palette = "-RdBu",  # misma paleta
    style = "cont",
    title = "Business Activity (Lag-1)",
    breaks = seq(ba_range[1], ba_range[2], length.out = 10)  # misma escala
  ) +
  tm_layout(
    main.title = "Clusters of Business Activity (Lag-1)",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa de Unemployment
unemployment1 <- tm_shape(state_geodata) + 
  tm_polygons(
    col = "unemployment",
    palette = "viridis",
    style = "cont",
    title = "Unemployment",
    breaks = seq(unemp_range[1], unemp_range[2], length.out = 8)  # escala común
  ) +
  tm_layout(
    main.title = "Unemployment",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa de Unemployment (Lag)
unemployment_lag1 <- tm_shape(state_geodata) +  
  tm_polygons(
    col = "sp_lag_unemployment",
    palette = "viridis",  # misma paleta
    style = "cont",
    title = "Unemployment (Lag-1)",
    breaks = seq(unemp_range[1], unemp_range[2], length.out = 8)  # misma escala
  ) +
  tm_layout(
    main.title = "Clusters of Unemployment (Lag-1)",
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mostrar todos los mapas
tmap_arrange(businessactivity1, ba_lag1, unemployment1, unemployment_lag1, ncol = 2)

Scatterplots

Business Activity

Se realiza un modelo de regresión lineal, para identificar qué tan bien se puede predecir el valor de los estados vecinos con el valor del estado:

  • Puntos: cada estado

  • Eje X: actividad empresarial del estado

  • Eje Y: el promedio de actividad empresarial de sus vecinos

  • M1 (lm): La línea azul tiene pendiente positiva → hay agrupamiento espacial positivo, por lo que también refuerza el resultado de Moran que se arrojó previamente.

Con base al modelo, tiene una pendiente positiva, es decir, que los estados con más actividad tienden a estar cerca de otros similares → autocorrelación positiva.

M1 <- lm(sp_lag_business_activity ~ business_activity, state_geodata)

state_geodata$residuals <- abs(resid(M1))

n_outliers <- 5
top_outliers <- order(state_geodata$residuals, decreasing = TRUE)[1:n_outliers]

# Plot
plot(sp_lag_business_activity ~ business_activity, state_geodata, pch=21, asp=1, las=1, 
     col = "grey40", bg="grey80", main="Business Activity")

# Línea de regresión y líneas medias
abline(M1, col="blue")
abline(v = mean(state_geodata$business_activity), lty=3, col = "grey80")
abline(h = mean(state_geodata$sp_lag_business_activity), lty=3, col = "grey80")

# Puntos outliers
points(state_geodata$business_activity[top_outliers], 
       state_geodata$sp_lag_business_activity[top_outliers], 
       pch=21, bg="red", col="black", cex=1.4)

# Etiquetas con nombre (ajusta 'NAME' si tu columna tiene otro nombre)
text(state_geodata$business_activity[top_outliers],
     state_geodata$sp_lag_business_activity[top_outliers],
     labels = state_geodata$state[top_outliers],
     pos = 3, cex = 0.8, col = "black")

Unemployment

Se realiza un modelo de regresión lineal, para identificar como el desempleo en un estado predice el desempleo promedio de sus estados vecinos en donde:

  • Puntos: cada estado

  • Eje X: tasa de desempleo del estado

  • Eje Y: el promedio de desempleo de sus vecinos

  • M1 (lm): La línea azul tiene una pendiente casi plana (recta horizontalmente) → muy débil relación espacial, por lo que también refuerza el resultado de Moran que nos arrojó previamente

  • Puntos dispersos → no hay agrupamientos claros. (No hay clústeres fuertes ni agrupamiento espacial de la variable.)

  • El desempleo parece espacialmente aleatorio: no se agrupa de forma clara por regiones.

Con base al modelo, se determina que la variable tiene una pendiente muy baja → No hay evidencia de autocorrelación espacial significativa, es decir, un estado con alto desempleo no necesariamente está rodeado de otros con alto desempleo.

# Create a regression model
M2 <- lm(sp_lag_unemployment ~ unemployment, state_geodata)

# Calcular los residuos absolutos (distancia vertical a la línea de regresión)
state_geodata$residuals <- abs(resid(M2))

# Identificar los n puntos más lejanos (por ejemplo, los 5 mayores residuos)
n_outliers <- 5
top_outliers <- order(state_geodata$residuals, decreasing = TRUE)[1:n_outliers]

# Plot the data (Moran scatterplot) + LM
plot(sp_lag_unemployment ~ unemployment, state_geodata, pch=21, asp=1, las=1, 
     col = "grey40", bg="grey80", main="Unemployment")
abline(M1, col="blue") # Línea de regresión
abline(v = mean(state_geodata$unemployment), lty=3, col = "grey80")
abline(h = mean(state_geodata$sp_lag_unemployment), lty=3, col = "grey80")

points(state_geodata$unemployment[top_outliers], 
       state_geodata$sp_lag_unemployment[top_outliers], 
       pch=21, bg="red", col="black", cex=1.4)

# Etiquetas con nombre (ajusta 'NAME' si tu columna tiene otro nombre)
text(state_geodata$unemployment[top_outliers],
     state_geodata$sp_lag_unemployment[top_outliers],
     labels = state_geodata$state[top_outliers],
     pos = 3, cex = 0.8, col = "black")

Visualización Espacial de Clusters (Conglomerados)

Segregación en las diferentes posibilidades de agrupaciones:

  • No significante

  • HotSpots: High - High

  • ColdSpots: Low - Low

  • Atípicos: High - Low

  • Atípicos: Low - High

Business Activity

Se generan clústers:

  • Low-High: Baja actividad empresarial, pero rodeado de vecinos con altactividad empresarial (posible outlier espacial).

  • High-High: Alta actividad empresarial, rodeado de vecinos con alta actividad empresarial (clúster positivo).

  • High-Low: Alta actividad empresarial, pero vecinos con baja actividad empresarial (posible outlier espacial).

  • Low-Low: Baja actividad empresarial, rodeado de vecinos con baja actividad empresarial (clúster negativo).

Con base a la colorimetría del mapa se determina que:

  • 🔴 Estados sin evidencia de agrupamiento espacial

  • 🟢 Sonora estado con alta actividad empresarial rodeados de otros similares

  • 🔵 Península de Yucatán estados con baja actividad empresarial rodeado de otros similares (clúster negativo)

  • 🟣 Baja California Sur estado con baja actividad empresarial rodeado de vecinos con alta actividad (outlier negativo)

swm_a <- queen_weights(mx_state_map) # queen spatial weight matrix (alternative format)

# 1. Calcular LISA
lisa_business <- local_moran(swm_a, state_geodata["business_activity"])

# 2. Asignar clústeres con etiquetas
state_geodata$cluster_business <- as.factor(lisa_business$GetClusterIndicators())
levels(state_geodata$cluster_business) <- lisa_business$GetLabels()

# 3. Mapa con estilo por defecto
library(ggplot2)

ggplot(data = state_geodata) +
  geom_sf(aes(fill = cluster_business), color = "white") +
  ggtitle(label = "Business Activity", subtitle = "Mexico's States") +
  theme_minimal()

Unemployment

Se generan clústers:

  • Low-High: Bajo desempleo, pero rodeado de vecinos con alto desempleo (posible outlier espacial).

  • High-High: Alto desempleo, rodeado de vecinos con alto desempleo (clúster positivo).

  • High-Low: Alto desempleo, pero vecinos con bajo desempleo (posible outlier espacial).

  • Low-Low: Bajo desempleo, rodeado de vecinos con bajo desempleo (clúster negativo).

Con base a la colorimetría del mapa se determina que:

  • 🔴 Estados sin evidencia de agrupamiento espacial

  • 🟢 Hidalgo estado con alto desempleo rodeados de otros similares

  • 🔵 Quintana Roo estado con baja tasa de desempleo rodeado de otros similares (clúster negativo)

sswm_a <- queen_weights(mx_state_map) # queen spatial weight matrix (alternative format)
lisa_income <- local_moran(sswm_a, state_geodata["unemployment"]) 
state_geodata$cluster_unemployment <- as.factor(lisa_income$GetClusterIndicators())
levels(state_geodata$cluster_unemployment)<-lisa_income$GetLabels() 

ggplot(data=state_geodata) +
  geom_sf(aes(fill=cluster_unemployment)) + 
  ggtitle(label = "Unemployment", subtitle = "Mexico's States")

Modelos

Se cargan librerías para el ajuste de modelos de regresión:

library(spatialreg)
library(stargazer)

Regresión Simple

Se busca explicar la variable de Inversión Extranjera Directa considerando las variables de Actividad Empresarial y la Tasa de Desempleo.

El modelo_a, aunque significativo, realmente no es tan bueno, pues la \(R^2\) ajustada apenas sobrepasa el 0.5 (\(\bar{R^2}\) = 0.5821).

Con base a esto, se generaán otros modelos para dar una mayor complejidad al considerar terminos de autocorrelación espacial.

model_a <- lm(new_fdi_real_mxn ~ business_activity + unemployment, data = state_geodata)
summary(model_a)
## 
## Call:
## lm(formula = new_fdi_real_mxn ~ business_activity + unemployment, 
##     data = state_geodata)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
##  -8473  -4523  -2443   1047  26134 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)  
## (Intercept)          12176       4971   2.449   0.0206 *
## business_activity     4695       1722   2.727   0.0107 *
## unemployment         97524     124597   0.783   0.4401  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 8077 on 29 degrees of freedom
## Multiple R-squared:  0.2043, Adjusted R-squared:  0.1494 
## F-statistic: 3.722 on 2 and 29 DF,  p-value: 0.03641
AIC(model_a)
## [1] 671.4531

SAR - Spatial AutoRegressive Model

Se realiza modelo SAR, también conocido como Spatial Lag Model Esencial, en el cual se incluye la matriz de conectividad espacial dada en el parámetro ‘listw’ por el objeto previamente calculado con el nombre de ‘sswm’. Se observa que el AIC es mayor que el de regresión simple.

model_b <- lagsarlm(new_fdi_real_mxn ~ business_activity + unemployment, data = state_geodata, listw = sswm) 
summary(model_b)
## 
## Call:lagsarlm(formula = new_fdi_real_mxn ~ business_activity + unemployment, 
##     data = state_geodata, listw = sswm)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -8378.93 -4533.51 -2475.15   922.67 26266.71 
## 
## Type: lag 
## Coefficients: (numerical Hessian approximate standard errors) 
##                   Estimate Std. Error z value Pr(>|z|)
## (Intercept)        11811.5     5539.3  2.1323 0.032982
## business_activity   4623.7     1740.1  2.6572 0.007879
## unemployment       97513.3   118721.1  0.8214 0.411438
## 
## Rho: 0.032956, LR test value: 0.017546, p-value: 0.89462
## Approximate (numerical Hessian) standard error: 0.26295
##     z-value: 0.12534, p-value: 0.90026
## Wald statistic: 0.015709, p-value: 0.90026
## 
## Log likelihood: -331.7178 for lag model
## ML residual variance (sigma squared): 59069000, (sigma: 7685.6)
## Number of observations: 32 
## Number of parameters estimated: 5 
## AIC: 673.44, (AIC for lm: 671.45)
AIC(model_b)
## [1] 673.4356

SEM - Spatial Error Model

Se genera Modelo de Error Espacial. Igual que en el modelo SAR es esencial, incluir la matriz de conectividad espacial dada en el parámetro ‘listw’ por el objeto previamente calculado con el nombre de ‘sswm’. Se calcula que su valor de AIC es menor que el SAR y con una diferencia mayor de 0.21 al AIC de la regresión simple.

model_c <- errorsarlm(new_fdi_real_mxn ~ business_activity + unemployment, data = state_geodata, listw = sswm)
summary(model_c)
## 
## Call:errorsarlm(formula = new_fdi_real_mxn ~ business_activity + unemployment, 
##     data = state_geodata, listw = sswm)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9664.0 -4067.2 -2083.9  1860.1 25175.2 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##                   Estimate Std. Error z value  Pr(>|z|)
## (Intercept)        13904.6     4153.0  3.3481 0.0008137
## business_activity   5786.5     1386.1  4.1746 2.985e-05
## unemployment      100452.6   110678.7  0.9076 0.3640865
## 
## Lambda: -0.39762, LR test value: 1.7915, p-value: 0.18074
## Asymptotic standard error: 0.23953
##     z-value: -1.66, p-value: 0.096917
## Wald statistic: 2.7556, p-value: 0.096917
## 
## Log likelihood: -330.8308 for error model
## ML residual variance (sigma squared): 53778000, (sigma: 7333.3)
## Number of observations: 32 
## Number of parameters estimated: 5 
## AIC: 671.66, (AIC for lm: 671.45)
AIC(model_c)
## [1] 671.6616

SDM - Spatial Durbin Model

Igual que en los modelo SAR y SEM es esencial, incluir la matriz de conectividad espacial dada en el parámetro ‘listw’ por el objeto previamente calculado con el nombre de ‘sswm’ y aquí en particular se debe añadir el parámetro ‘type’ con valor ‘mixed’ para que en esencia mezcle los dos modelos previos (SAR y SEM). SU valor de AIC es el más alto pero, logra la menor varianza residual y mejor interpretación estructural.

model_d <- lagsarlm(new_fdi_real_mxn ~ business_activity + unemployment, data = state_geodata, listw = sswm, type="mixed") 
summary(model_d)
## 
## Call:lagsarlm(formula = new_fdi_real_mxn ~ business_activity + unemployment, 
##     data = state_geodata, listw = sswm, type = "mixed")
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9395.9 -4069.3 -2000.3  2234.7 25838.6 
## 
## Type: mixed 
## Coefficients: (numerical Hessian approximate standard errors) 
##                       Estimate Std. Error z value Pr(>|z|)
## (Intercept)            16582.9    10206.0  1.6248 0.104201
## business_activity       4471.6     1664.1  2.6871 0.007208
## unemployment          105464.9   110826.1  0.9516 0.341287
## lag.business_activity   4018.2     2206.8  1.8208 0.068638
## lag.unemployment       97809.4   261432.2  0.3741 0.708308
## 
## Rho: -0.23256, LR test value: 0.6703, p-value: 0.41295
## Approximate (numerical Hessian) standard error: 0.28212
##     z-value: -0.82434, p-value: 0.40974
## Wald statistic: 0.67954, p-value: 0.40974
## 
## Log likelihood: -329.7602 for mixed model
## ML residual variance (sigma squared): 51591000, (sigma: 7182.7)
## Number of observations: 32 
## Number of parameters estimated: 7 
## AIC: 673.52, (AIC for lm: 672.19)
AIC(model_d)
## [1] 673.5205

Comparativa

Aunque el modelo c presenta un mejor rendimiento estadístico con el menor AIC (671.66), el objetivo principal es identificar cómo el entorno —específicamente la actividad de los estados vecinos— influye en la Inversión Extranjera Directa (FDI). Por ello, se selecciona el modelo d, ya que permite captar efectos espaciales indirectos (influencia de regiones vecinas), a pesar de tener un AIC ligeramente superior. Además, tanto la variable business_activity como su retardo espacial resultan significativas o cercanas a la significancia, lo cual evidencia una interdependencia regional en la atracción de inversión. De esta manera, el modelo d ofrece una representación más completa y realista del fenómeno espacial analizado.

stargazer(model_a, model_b, model_c, model_d, type = "text", title="Estimated Regression Results")
## 
## Estimated Regression Results
## =======================================================================================
##                                              Dependent variable:                       
##                       -----------------------------------------------------------------
##                                               new_fdi_real_mxn                         
##                               OLS             spatial        spatial        spatial    
##                                            autoregressive     error      autoregressive
##                               (1)               (2)            (3)            (4)      
## ---------------------------------------------------------------------------------------
## business_activity         4,695.418**       4,623.750***   5,786.464***   4,471.587*** 
##                           (1,722.100)       (1,740.075)    (1,386.100)    (1,664.106)  
##                                                                                        
## unemployment               97,523.970        97,513.350    100,452.600    105,464.900  
##                          (124,597.400)     (118,721.100)  (110,678.700)  (110,826.100) 
##                                                                                        
## lag.business_activity                                                      4,018.200*  
##                                                                           (2,206.836)  
##                                                                                        
## lag.unemployment                                                           97,809.420  
##                                                                          (261,432.200) 
##                                                                                        
## Constant                  12,175.640**      11,811.500**  13,904.580***    16,582.930  
##                           (4,971.108)       (5,539.305)    (4,152.975)    (10,206.020) 
##                                                                                        
## ---------------------------------------------------------------------------------------
## Observations                   32                32             32             32      
## R2                           0.204                                                     
## Adjusted R2                  0.149                                                     
## Log Likelihood                                -331.718       -330.831       -329.760   
## sigma2                                     59,068,556.000 53,777,605.000 51,590,758.000
## Akaike Inf. Crit.                             673.436        671.662        673.520    
## Residual Std. Error   8,076.685 (df = 29)                                              
## F Statistic           3.722** (df = 2; 29)                                             
## Wald Test (df = 1)                             0.016          2.756*         0.680     
## LR Test (df = 1)                               0.018          1.792          0.670     
## =======================================================================================
## Note:                                                       *p<0.1; **p<0.05; ***p<0.01

Conclusión

Se evaluaron cuatro modelos de regresión (OLS y espaciales) para explicar la variación de la inversión extranjera directa (new_fdi_real_mxn) en los estados de México. El modelo d, que incorpora efectos espaciales autoregresivos y los lags espaciales de los predictores, fue seleccionado como el más adecuado por las siguientes razones:

  • Captura la dependencia espacial de la FDI: incluye un componente autoregresivo que reconoce que la inversión en un estado puede estar influida por la de sus estados vecinos.

  • Incorpora los efectos del entorno: al incluir el lag.business_activity, considera que la actividad empresarial en los estados vecinos también afecta las decisiones de inversión.

  • Mantenimiento del ajuste estadístico: aunque el modelo c tuvo el AIC más bajo, el modelo d conserva un ajuste competitivo (AIC = 673), con todos los efectos relevantes incluidos.

  • Interpretación más amplia y adecuada al entoro de estudio: permite entender no solo los efectos directos, sino también los efectos espaciales indirectos, lo que es clave para decisiones de política económica regional.

LS0tDQp0aXRsZTogIkF1dG9jb3JyZWxhY2nDs24gRXNwYWNpYWwiDQpzdWJ0aXRsZTogIkFjdGl2aWRhZCAwMiINCmF1dGhvcjogIkVxdWlwbyA3Ig0KZGF0ZTogIjIwMjUtMDMtMjgiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCi0tLQ0KDQohW10oaHR0cHM6Ly9jaXRyaXMtdWMub3JnL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE5LzEwL1RlYy1kZS1Nb250ZXJyZXktbG9nby1ob3Jpem9udGFsLWJsdWUucG5nKQ0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXIiPg0KICA8cD48c3Ryb25nPlBsYW5lYWNpw7NuIGVzdHJhdMOpZ2ljYSBiYXNhZGEgZW4gYW5hbMOtdGljYSBwcmVzY3JpcHRpdmE8L3N0cm9uZz48L3A+DQogIDxwPjxzdHJvbmc+R3J1cG8gNTAzPC9zdHJvbmc+PC9wPg0KICA8cD48c3Ryb25nPlByb2Zlc29yIFJvZG9sZm8gTWlndWVsIEdhbWVyb3M8L3N0cm9uZz48L3A+DQo8L2Rpdj4NCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyIj4NCiAgPHA+PHN0cm9uZz5FcXVpcG8gNzo8L3N0cm9uZz48L3A+DQogIDxwPkEwMDgzMzExMyAtIEF2cmlsIExvYmF0bzwvcD4NCiAgPHA+QTAxNzcxMTI3IC0gTGVzbHkgRGFyaWFuIFJvbWVybyBWw6F6cXVlejwvcD4NCiAgPHA+QTAwODMxMTA1IC0gSmF6bcOtbiBDb3J0ZXogTWVuZG96YTwvcD4NCiAgPHA+QTAxMjg0NjExIC0gTGlzc2V0IEhlcm7DoW5kZXo8L3A+DQo8L2Rpdj4NCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQoJZWNobyA9IFRSVUUsDQoJbWVzc2FnZSA9IEZBTFNFLA0KCXdhcm5pbmcgPSBGQUxTRQ0KKQ0KI2luc3RhbGwucGFja2FnZXMoInJuYXR1cmFsZWFydGhoaXJlcyIsIHJlcG9zID0gImh0dHBzOi8vcGFja2FnZXMucm9wZW5zY2kub3JnIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQpwYWNtYW46OnBfbG9hZChkcGx5ciwgY2FyLCBNQVNTLCBBRVIsIHF1YW50bW9kLCBzdGF0cywgZGxvb2tyLCB0aWR5dmVyc2UsIHVyY2EsIGFUU0EsIGdncGxvdDIsIG5hbmlhciwgdGlncmlzLCBjb3JycGxvdCwgcGF0Y2h3b3JrLCByZWFkeGwsIHBzeWNoLCBtYXBzLCBzZiwgcm5hdHVyYWxlYXJ0aCwgcm5hdHVyYWxlYXJ0aGRhdGEsIHN0cmluZ2ksIHNjYWxlcywgRGF0YUV4cGxvcmVyLCB0aWR5ciwga25pdHIsIFJDb2xvckJyZXdlciwgcGxvdGx5LCBmb3JlY2FzdCwgdHNlcmllcywgb3Blbnhsc3gsIHZhcnMsIGxtdGVzdCwgZm9yZWlnbiwgc3BkZXAsIHJnZW9kYSwgdmlyaWRpcywgdG1hcCwgc3AsIHNwZ3dyLCBHV21vZGVsLCBodG1sdG9vbHMpDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KDQojICoqQW7DoWxpc2lzIEV4cGxvcmF0b3JpbyBkZSBEYXRvcyBFc3BhY2lhbGVzIChFU0RBOiBFeHBsb3JhdG9yeSBTcGF0aWFsIERhdGEgQW5hbHlzaXMpKioNCg0KRWwgQW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBkYXRvcyBlc3BhY2lhbCBpbnZvbHVjcmEgZGlmZXJlbnRlcyBoZXJyYW1pZW50YXMgcGFyYSB2aXN1YWxpemFyIGxvcyBwYXRyb25lcyBlc3BhY2lhbGVzIGV4aXN0ZW50ZXMgZW4gbGEgYmFzZSBkZSBkYXRvcy4gRGljaG9zICBkYXRvcyBzZSBwdWVkZW4gc2VncmVnYXIgbyBkZXNjb21wb25lciBsb3MgcGF0cm9uZXMgZXNwYWNpYWxlcyBlbiBkaWZlcmVudGVzIGVsZW1lbnRvcyBhIGxvIGxhcmdvIGRlcyBtYXBhLCB5IGEgc3UgdmV6IG1lZGlyIGxhIGV4dGVuc2nDs24gZGUgZXN0YXMgYXV0b2NvcnJlbGFjaW9uZXMgZXNwYWNpYWxlcy4gRWwgcHJpbmNpcGFsIHBhcXVldGUgZGUgUiBxdWUgc2UgdXRpbGl6YSBwYXJhIGVzdGUgcHJvcMOzc2l0byBlcyAnZ2Vvc3RhbicuDQoNCiMjIEltcG9ydGFjacOzbiBkZSBiYXNlcyBkZSBkYXRvcyB5IGdlb2NlcmNhcw0KDQpBIGNvbnRpbnVhY2nDs24sIHNlIHJlYWxpemEgYSBpbXBvcnRhY2nDs24gZGUgbGEgYmQgYSBuaXZlbCBlc3RhdGFsDQpgYGB7cn0NCm14X3N0YXRlIDwtIHJlYWQuY3N2KCJzdGF0ZV9kYXRhLmNzdiIpDQpoZWFkKG49MTAsIG14X3N0YXRlKQ0KZ2xpbXBzZShteF9zdGF0ZSkNCmBgYA0KDQpTZWd1aWRhbWVudGUsIHNlIGxlZW4gbG9zIGFyY2hpdm9zIGRlIGxhcyBmb3JtYXMgZ2VvbcOpdHJpY2FzIChnZW9jZXJjYXMpIHF1ZSBkZXRlcm1pbmFyw6FuIGxvcyBtYXBhcyBhIHJlYWxpemFyIGRlc3B1w6lzIHBhcmEgdmlzdWFsaXphciBsb3MgZGF0b3M7IGVuIGVzdGUgY2FzbyBzZSByZWFsaXphICBhIG5pdmVsIGVzdGFkbywgbG9zIGN1YWxlcyBzb24gMzIgZW4gTcOpeGljby4NCmBgYHtyfQ0KbXhfc3RhdGVfbWFwIDwtIHN0X3JlYWQoIm1leGxhdGxvbmcuc2hwIikNCiNteF9zdGF0ZV9tYXAgPC0gcmVhZF9zZigibWV4bGF0bG9uZy5zaHAiKQ0KYGBgDQoNCg0KIyMgQmFzaWMgTWFwIE1ha2luZw0KDQpTZSByZWFsaXphIGV4cGxvcmFjacOzbiB2aXN1YWwgYsOhc2ljYSBkZWwgY29uanVudG8gZGUgZGF0b3MgZ2VvZXNwYWNpYWxlcyBhIG5pdmVsIGVzdGF0YWwgZW4gTcOpeGljbywgw7p0aWwgcGFyYSBpZGVudGlmaWNhciBwYXRyb25lcyBvIHZhbGlkYXIgbGEgaW5mb3JtYWNpw7NuIHVuaWRhIG1lZGlhbnRlIGVsIGdlb19qb2luLiBDYWRhIG1hcGEgcmVwcmVzZW50YSB1biBhdHJpYnV0byBkaWZlcmVudGUsIGNvbW86DQoNCiogT0JKRUNUSUQsIEZJUFNfQURNSU4sIEdNSV9BRE1JTiwgQURNSU5fTkFNRTogaWRlbnRpZmljYWRvcmVzIHkgbm9tYnJlcyBhZG1pbmlzdHJhdGl2b3MgZGUgbG9zIGVzdGFkb3MuDQoNCiogUE9QX0FETUlOOiBtdWVzdHJhIGRpZmVyZW5jaWFzIGRlIHBvYmxhY2nDs24gZW50cmUgZXN0YWRvcyAocG9yIGVqZW1wbG8sIENETVggeSBFZG9tZXggY29uIGNvbG9yZXMgbcOhcyBpbnRlbnNvcykuDQoNCiogQ05UUllfTkFNRSwgRklQU19DTlRSWSwgR01JX0NOVFJZLCBUWVBFX0VORzogZGF0b3MgcXVlIHNvbiBpZ3VhbGVzIHBhcmEgdG9kb3MgbG9zIGVzdGFkb3MsIHlhIHF1ZSB0b2RvcyBwZXJ0ZW5lY2VuIGEgTcOpeGljby4NCg0KYGBge3J9DQpzdGF0ZV9nZW9kYXRhIDwtIGdlb19qb2luKG14X3N0YXRlX21hcCxteF9zdGF0ZSwnT0JKRUNUSUQnLCdzdGF0ZV9pZCcsaG93PSdpbm5lcicpDQpwbG90KHN0YXRlX2dlb2RhdGEpDQpgYGANCg0KDQojIyBWaXN1YWxpemFjacOzbiBhIG5pdmVsIGVzdGFkbw0KU2Ugb2JzZXJ2YSB5IHZpc3VhbGl6YSBlbCBtYXBhIGNvbiBsb3MgZXN0YWRvcyBkZSBNw6l4aWNvLCBhY29yZGUgYSBlc3RvIHNlIG1lemNsYSBsYSBkYXRhIGRlIGxhcyBnZW9jZXJjYXMgY29uIGFsZ3VuYSBkZSBsYXMgdmFyaWFibGVzIHNlbGVjY2lvbmFkYXMgZGUgbGEgdGFibGEgZGUgZGF0b3MgaW5pY2lhbCBwYXJhIHN1IGFuw6FsaXNpcyBnZW9lc3BhY2lhbC4NCg0KYGBge3J9DQp0bV9zaGFwZShteF9zdGF0ZV9tYXApICsNCiAgdG1fcG9seWdvbnMoY29sID0gImJsYWNrIikgKw0KICB0bV9jb21wYXNzKHBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSkgKw0KICB0bV90ZXh0KCJBRE1JTl9OQU1FIiwgc2l6ZSA9ICJBUkVBIikgKw0KICB0bV9sYXlvdXQodGl0bGUgPSAiRXN0YWRvcyBkZSBNw6l4aWNvIikNCmBgYA0KDQoNCiMjIERpc3RyaWJ1Y2nDs24gZGUgQnVzaW5lc3MgQWN0aXZpdHkgcG9yIEVzdGFkbw0KYGBge3J9DQpidXNpbmVzc2FjdGl2aXR5IDwtIHRtX3NoYXBlKHN0YXRlX2dlb2RhdGEpICsgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJidXNpbmVzc19hY3Rpdml0eSIsDQogICAgcGFsZXR0ZSA9ICItUmRCdSIsICAjIGVsIHNpZ25vICItIiBpbnZpZXJ0ZSBsb3MgY29sb3JlcyBwYXJhIHF1ZSBsb3MgbmVnYXRpdm9zIGVzdMOpbiBlbiBhenVsDQogICAgc3R5bGUgPSAiY29udCIsDQogICAgdGl0bGUgPSAiQnVzaW5lc3MgQWN0aXZpdHkiDQogICkgKw0KICB0bV9sYXlvdXQoDQogICAgbWFpbi50aXRsZSA9ICJCdXNpbmVzcyBBY3Rpdml0eSIsDQogICAgdGl0bGUucG9zaXRpb24gPSBjKCJyaWdodCIsICJ0b3AiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpLA0KICAgIHRpdGxlLnNpemUgPSAxDQogICkNCmBgYA0KDQojIyBEaXN0cmlidWNpw7NuIGRlIERlc2VtcGxlbyBwb3IgRXN0YWRvDQpgYGB7cn0NCnVuZW1wbG95bWVudCA8LSB0bV9zaGFwZShzdGF0ZV9nZW9kYXRhKSArIA0KICB0bV9wb2x5Z29ucygNCiAgICBjb2wgPSAidW5lbXBsb3ltZW50IiwNCiAgICBwYWxldHRlID0gInZpcmlkaXMiLCAgICAgICAjIHNpbiBlbCAiLSIgcGFyYSBxdWUgbG9zIHZhbG9yZXMgbcOhcyBiYWpvcyBzZWFuIGNsYXJvcw0KICAgIHN0eWxlID0gInF1YW50aWxlIiwNCiAgICBuID0gOCwNCiAgICB0aXRsZSA9ICJVbmVtcGxveW1lbnQiDQogICkgKw0KICB0bV9sYXlvdXQoDQogICAgbWFpbi50aXRsZSA9ICJVbmVtcGxveW1lbnQiLA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQpgYGANCg0KIyMgTWFwYXMgZGUgQnVzaW5lc3MgQWN0aXZpdHkgJiBVbmVtcGxveW1lbnQNCg0KKipCdXNpbmVzcyBBY3Rpdml0eToqKg0KDQoqIENhc2kgdG9kbyBlbCBwYcOtcyBlc3TDoSBlbiBhenVsLCBsbyBxdWUgc3VnaWVyZSBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIGVzdGFkb3MgdGllbmVuIHZhbG9yZXMgbmVnYXRpdm9zIG8gYmFqb3MgZGUgYnVzaW5lc3NfYWN0aXZpdHkuDQoNCiogQmFqYSBDYWxpZm9ybmlhIGFwYXJlY2UgY29uIHVuIHZhbG9yIHJvam8gb3NjdXJvIOKGkiBwb3IgbG8gcXVlIHB1ZWRlIGRlc3RhY2FyIGVuIHRlbmVyIHVuYSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgbm90YWJsZW1lbnRlIG3DoXMgYWx0YSBvIGRpZmVyZW50ZS4NCg0KDQoqKlVuZW1wbG95bWVudDoqKg0KDQoqIEd1ZXJyZXJvLCBCYWphIENhbGlmb3JuaWEsIENhbXBlY2hlLCAgdGllbmVuIGRlc2VtcGxlbyBtw6FzIGJham8gKG1vcmFkbyBvc2N1cm8pLg0KDQoqIE51ZXZvIExlw7NuIHVuIHJhZ28gbWVkaW8tYmFqbyBkZSBkZXNlbXBsZW8uDQoNCiogQWxndW5vcyBlc3RhZG9zIGNvbW8gQ0RNWCwgQ2hpYXBhcyBvIFZlcmFjcnV6IGVzdMOhbiBlbiB0b25vcyBtw6FzIGNsYXJvcywgbG8gcXVlIGluZGljYSBtYXlvciBkZXNlbXBsZW8gcmVsYXRpdm8uDQoNCmBgYHtyfQ0KdG1hcF9hcnJhbmdlKGJ1c2luZXNzYWN0aXZpdHksIHVuZW1wbG95bWVudCwgbmNvbCA9IDIpDQpgYGANCg0KDQojIyBNYXRyaXogZGUgQ29uZWN0aXZpZGFkIEVzcGFjaWFsDQpTZSBjcmVhIG1hdHJpeiBkZSBjb25lY3RpdmlkYWQgZXNwYWNpYWwgbyBsaXN0YSBkZSB2ZWNpbm9zIGVudHJlIHBvbMOtZ29ub3MgcGFyYSBsbyBjdWFsIHNlIHVzYSBlbCBwYXLDoW1ldHJvIGRlIFFVRUVOIHBhcmEgZGVmaW5pciBsYSB2ZWNpbmRhZCwgZW4gZMOzbmRlIHNlIHRvbWFyw6FuIGVuIGN1YWVudGEgc2kgZG9zIHBvbMOtZ29ub3Mgc29uIHZlY2lub3Mgbywgc2kgY29tcGFydGVuIHVuIGJvcmRlIG8gdW4gcHVudG8gKGhhY2UgbGEgY2VyY2Fuw61hIG3DoXMgaW5jbHVzaXZhKS4NCg0KQ29uIGJhc2UgZW4gZWwgc3VtbWFyeSBvYnRlbmVtb3MgbG8gc2lndWllbnRlOg0KDQoqIEhheSAzMiBwb2zDrWdvbm9zICgzMiBlc3RhZG9zIGRlIE3DqXhpY28pLg0KDQoqIEhheSAxMzggY29uZXhpb25lcyBkZSB2ZWNpbmRhZCBlbnRyZSBlbGxvcy4NCg0KKiBQcm9wb3JjacOzbiBkZSBwYXJlcyB2ZWNpbm9zIGNvbiByZWxhY2nDs24gYWwgdG90YWwgcG9zaWJsZSA9IDEzLjUlDQoNCiogKkNhZGEgZXN0YWRvIHRpZW5lLCBlbiBwcm9tZWRpbywgNC4zMSB2ZWNpbm9zKg0KDQoqIFPDs2xvIDEgZXN0YWRvIHRpZW5lIDEgdmVjaW5vLiAqQmFqYSBDYWxpZm9ybmlhIFN1cioNCg0KKiBTw7NsbyAxIGVzdGFkbyBlc3TDoSBjb25lY3RhZG8gY29uIDkgdmVjaW5vcyAqU2FuIEx1aXMgUG90b3PDrSoNCg0KYGBge3J9DQpzd20gIDwtIHBvbHkybmIobXhfc3RhdGVfbWFwLCBxdWVlbj1UKQ0KDQpzdW1tYXJ5KHN3bSkgIyBUaGUgYXZlcmFnZSBudW1iZXIgb2YgbmVpZ2hib3JzIGlzIDQuMzENCmBgYA0KDQpgYGB7cn0NCm14X3N0YXRlX21hcCRBRE1JTl9OQU1FWzhdICAgIyBFc3RhZG8gbcOhcyBjb25lY3RhZG8gKGNvbiA5IHZlY2lub3MpDQpteF9zdGF0ZV9tYXAkQURNSU5fTkFNRVszMV0gICMgRXN0YWRvIG1lbm9zIGNvbmVjdGFkbyAoY29uIDEgdmVjaW5vKQ0Kc3RhdGVfZ2VvZGF0YSRBRE1JTl9OQU1FWzhdICAgIyBFc3RhZG8gbcOhcyBjb25lY3RhZG8gKGNvbiA5IHZlY2lub3MpDQpzdGF0ZV9nZW9kYXRhJEFETUlOX05BTUVbMzFdICAjIEVzdGFkbyBtZW5vcyBjb25lY3RhZG8gKGNvbiAxIHZlY2lubykNCg0KYGBgDQoNCmBgYHtyfQ0KIyBTZSBtdWVzdHJhbiBsYXMgOSBjb25leGlvbmVzIGRlbCBFc3RhZG8gY29uIG1heW9yIG7Dum1lcm8gZGUgY29uZXhpb25lcywgZXMgZGVjaXIsIGRlIFNhbiBMdWlzIFBvdG9zw60NCnN3bVtbOF1dDQojIExpc3RhZG8gZGUgZXN0YWRvcyBjb25lY3RhZG9zIGNvbiBTYW4gTHVpcyBQb3Rvc8OtDQpteF9zdGF0ZV9tYXAkQURNSU5fTkFNRVtzd21bWzhdXV0NCiMgQ29tcHJvYmFjacOzbiBkZSBlc3RhZG9zIGNvbmVjdGFkb3MgY29uIFNhbiBMdWlzIFBvdG9zw60NCnN0YXRlX2dlb2RhdGEkQURNSU5fTkFNRVtzd21bWzhdXV0NCmBgYA0KDQojIyBWaXN1YWxpemFjacOzbiBHcsOhZmljYSBkZSBsYSBtYXRyaXogZGUgY29uZWN0aXZpZGFkIChWZWNpbmRhZGVzIGVzdGlsbyAnUmVpbmEnKSBkZWwgcGHDrXMuDQoNCmBgYHtyLCBpbmNsdWRlPSBGQUxTRX0NCnNzd20gPC0gbmIybGlzdHcoc3dtLCBzdHlsZT0iVyIsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KbXhfc3RhdGVfbWFwX2EgPC0gYXMobXhfc3RhdGVfbWFwLCAiU3BhdGlhbCIpDQpteF9zdGF0ZV9tYXBfY2VudHJvaWQgPC0gY29vcmRpbmF0ZXMobXhfc3RhdGVfbWFwX2EpIA0KcGxvdChteF9zdGF0ZV9tYXBfYSxib3JkZXI9ImJsdWUiLGF4ZXM9RkFMU0UsbGFzPTEsIG1haW49Ik1leGljbydzIFN0YXRlcyBRdWVlbiBTV00iKQ0KcGxvdChteF9zdGF0ZV9tYXBfYSxjb2w9ImdyZXkiLGJvcmRlcj1ncmV5KDAuOSksYXhlcz1ULGFkZD1UKSANCnBsb3Qoc3N3bSxjb29yZHM9bXhfc3RhdGVfbWFwX2NlbnRyb2lkLHBjaD0xOSxjZXg9MC4xLGNvbD0icmVkIixhZGQ9VCkgDQpgYGANCg0KYGBge3J9DQojIDEuIENyZWFyIGxpc3RhIGRlIHZlY2lub3MNCnN3bSA8LSBwb2x5Mm5iKG14X3N0YXRlX21hcCwgcXVlZW4gPSBUUlVFKQ0KDQojIDIuIENvbnZlcnRpciBhIG1hdHJpeiBkZSBwZXNvcyBlc3BhY2lhbGVzDQpzc3dtIDwtIG5iMmxpc3R3KHN3bSwgc3R5bGUgPSAiVyIsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KIyAzLiBDb252ZXJ0aXIgYSBvYmpldG8gIlNwYXRpYWwiIChwYXJhIGZ1bmNpb25lcyBtw6FzIGFudGlndQ0KbXhfc3RhdGVfbWFwX2EgPC0gYXMobXhfc3RhdGVfbWFwLCAiU3BhdGlhbCIpDQoNCiMgNC4gT2J0ZW5lciBjZW50cm9pZGVzIChjb29yZGVuYWRhcykNCm14X3N0YXRlX21hcF9jZW50cm9pZCA8LSBjb29yZGluYXRlcyhteF9zdGF0ZV9tYXBfYSkNCg0KIyA1LiBHcmFmaWNhciBlbCBtYXBhIGJhc2UNCnBsb3QobXhfc3RhdGVfbWFwX2EsIGJvcmRlciA9ICJibHVlIiwgYXhlcyA9IEZBTFNFLCBsYXMgPSAxLCBtYWluID0gIk1leGljbydzIFN0YXRlcyBRdWVlbiBTV00iKQ0KcGxvdChteF9zdGF0ZV9tYXBfYSwgY29sID0gImdyZXkiLCBib3JkZXIgPSBncmV5KDAuOSksIGF4ZXMgPSBUUlVFLCBhZGQgPSBUUlVFKQ0KDQojIDYuIERpYnVqYXIgbMOtbmVhcyBkZSBjb25lY3RpdmlkYWQgKHZlY2luZGFkKQ0KcGxvdChzc3dtLCBjb29yZHMgPSBteF9zdGF0ZV9tYXBfY2VudHJvaWQsIHBjaCA9IDE5LCBjZXggPSAwLjEsIGNvbCA9ICJyZWQiLCBhZGQgPSBUUlVFKQ0KDQojIDcuIEFncmVnYXIgbm9tYnJlcyBkZSBsb3MgZXN0YWRvcyBjb24gYWp1c3RlDQpwb2ludExhYmVsKA0KICB4ID0gbXhfc3RhdGVfbWFwX2NlbnRyb2lkWywxXSwNCiAgeSA9IG14X3N0YXRlX21hcF9jZW50cm9pZFssMl0sDQogIGxhYmVscyA9IG14X3N0YXRlX21hcCRBRE1JTl9OQU1FLA0KICBjZXggPSAwLjUsDQogIGNvbCA9ICJibGFjayINCikNCmBgYA0KDQojICoqQW7DoWxpc2lzIGRlIEF1dG9jb3JyZWxhY2nDs24gRXNwYWNpYWwqKg0KDQojIyDDjW5kaWNlIEdsb2JhbCBkZSBNb3Jhbg0KVGXDs3JpY2FtZW50ZSBlbCByYW5nbyBkZSBNb3JhbiBzZSBtdWVzdHJhIGVudHJlIOKAkzEgeSArMSwgZW4gZMOzbmRlOiANCiogKzEgQWx0YSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIHBvc2l0aXZhICh2YWxvcmVzIHNpbWlsYXJlcyBlc3TDoW4gY2VyY2EgZW50cmUgc8OtKS4gIA0KDQoqIDAgRGlzdHJpYnVjacOzbiBhbGVhdG9yaWEgKG5vIGhheSBwYXRyw7NuIGVzcGFjaWFsKS4gIA0KDQoqIC0xIEFsdGEgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBuZWdhdGl2YSAodmFsb3JlcyBkaWZlcmVudGVzIGVzdMOhbiBjZXJjYSBlbnRyZSBzw60pLiAgDQoNCkFjb3JkZSBhIGxvIGFudGVyaW9yLCBzZSBnZW5lcmEgY29kaWdvIHBhcmEgZGV0ZXJtaW5hciBzaSBlbCBkZXNlbXBsZW8gKHVuZW1wbG95bWVudCkgdGllbmUgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCwgZXMgZGVjaXIsIHNpIGxvcyBlc3RhZG9zIHlhIHNlYSBjb24gYWx0byBvIGJham8gZGVzZW1wbGVvIHRpZW5kZW4gYSBlc3RhciBjZXJjYSB1bm9zIGRlIG90cm9zLiBUYW1iacOpbiBzZSBhbmFsaXphIHNpIGVsIG5pdmVsIGRlIGFjdGl2aWRhZCBlbXByZXNhcmlhbCAoYnVzaW5lc3NfYWN0aXZpdHkpIHRpZW5lIG8gbm8gYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCwgZXMgZGVjaXIsIHNpIGxvcyBlc3RhZG9zIHlhIHNlYSBjb24gYWx0byBvIGJham8gbml2ZWwgZGUgYWN0aXZpZGFkIHRpZW5kZW4gYSBlc3RhciBjZXJjYSB1bm9zIGRlIG90cm9zLg0KDQpgYGB7cn0NCm1vcmFuLnRlc3Qoc3RhdGVfZ2VvZGF0YSRidXNpbmVzc19hY3Rpdml0eSwgc3N3bSkgICAgICAgIyBHbG9iYWwgTW9yYW4ncyBJIGlzIDAuMTggYnV0IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAtdmFsdWUgPiAxMCUpLiANCm1vcmFuLnRlc3Qoc3RhdGVfZ2VvZGF0YSR1bmVtcGxveW1lbnQsIHNzd20pICAgICAgICAgICAgIyBHbG9iYWwgTW9yYW4ncyBJIGlzIDAuMDIxIGJ1dCBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAocC12YWx1ZSA+IDEwJSkuIA0KYGBgDQoNCioqUHJlc2VudGFjacOzbiBkZSByZXN1bHRhZG9zKioNCg0KKkFjdGl2aWRhZCBFbXByZXNhcmlhbCAoQnVzaW5lc3MgQWN0aXZpdHkJKSogIA0KDQoqIE1vcmFu4oCZcyBJID0gKjAuMTg0KiDihpIgaGF5IGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgcG9zaXRpdmE6IHJlZ2lvbmVzIGNvbiBhbHRhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCB0aWVuZGVuIGEgZXN0YXIgY2VyY2EgZGUgb3RyYXMgc2ltaWxhcmVzLiAgDQoNCiogUC12YWx1ZSA9ICowLjAwNDYqIOKGkiBlcyBhbHRhbWVudGUgc2lnbmlmaWNhdGl2byAocCA8IDAuMDEpLiAgDQoNCkV4aXN0ZSB1biBwYXRyw7NuIGVzcGFjaWFsIGZ1ZXJ0ZS4gTGEgKiphY3RpdmlkYWQgZW1wcmVzYXJpYWwgbm8gZXN0w6EgZGlzdHJpYnVpZGEgYWxlYXRvcmlhbWVudGUqKjsgaGF5IGFncnVwYW1pZW50b3MgY2xhcm9zLiAgDQoNCg0KKkRlc2VtcGxlbyAoVW5lbXBsb3ltZW50KSogIA0KDQoqIE1vcmFu4oCZcyBJID0gKjAuMDIxNiogKGNlcmNhbm8gYSAwKSBzdWdpZXJlIHBvY2EgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCwgcmVnaW9uZXMgY29uIGFsdG8gZGVzZW1wbGVvIHB1ZWRlbiBvIG5vIHRlbmRlciBhIGVzdGFyIGNlcmNhIGRlIG90cmFzIHNpbWlsYXJlcywgcGVybyBlbCDDrW5kaWNlIG5vIGVzIGlndWFsIG8gbWF5b3IgYSAwLjM1LiAgDQoNCiogUC12YWx1ZSA9ICowLjMzMDUqID4gMC4xMCDihpIgTm8gZXMgZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2byAocD4wLjEwKS4gIA0KDQoqKk5vIGhheSBldmlkZW5jaWEgZGUgcXVlIGVsIGRlc2VtcGxlbyBlc3TDqSBhZ3J1cGFkbyBnZW9ncsOhZmljYW1lbnRlKiouIFN1IGRpc3RyaWJ1Y2nDs24gcGFyZWNlIGFsZWF0b3JpYSBwZXJvIG5vIGN1bXBsZSBjb24gbG9zIGVzdMOhbmRhcmVzIG3DrW5pbW9zIHBvciBlbmRlLCBzZSByZWFsaXphIGxhZy4NCg0KYGBge3J9DQp0YWJsZSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlID0gYygiQnVzaW5lc3MgQWN0aXZpdHkiLCAiVW5lbXBsb3ltZW50IiksIEdNID0gYygwLjE4NCwgMC4wMjEpLCBTaWduaWZpY2FuY2UgPSBjKCIqKioiLCAiTlMiKSkNCnRhYmxlDQpgYGANCg0KDQojIyBJZGVudGlmaWNhY2nDs24gZGUgQ2x1c3RlcnMNCg0KU2UgcmVhbGl6YSBjw6FsY3VsbyBkZSBsYWdzIGRlIGFjdWVyZG8gY29uIGxhIG1hdHJpeiBkZSBjb25lY3RpdmlkYWQgYW50ZXJpb3JtZW50ZSBjcmVhZGENCmBgYHtyfQ0Kc3RhdGVfZ2VvZGF0YSRzcF9sYWdfdW5lbXBsb3ltZW50IDwtIGxhZy5saXN0dyhzc3dtLCBzdGF0ZV9nZW9kYXRhJHVuZW1wbG95bWVudCwgemVyby5wb2xpY3k9VFJVRSkgDQpzdGF0ZV9nZW9kYXRhJHNwX2xhZ19idXNpbmVzc19hY3Rpdml0eSA8LSBsYWcubGlzdHcoc3N3bSwgc3RhdGVfZ2VvZGF0YSRidXNpbmVzc19hY3Rpdml0eSwgemVyby5wb2xpY3k9VFJVRSkNCmBgYA0KDQojIyMgTWFwYXMgZGUgbGFnIHBhcmEgQnVzaW5lc3MgQWN0aXZpdHkgeSBVbmVtcGxveW1lbnQNCg0KKipBY3RpdmlkYWQgRW1wcmVzYXJpYWwgKEJ1c2luZXNzIEFjdGl2aXR5KSoqDQoNCk1hcGEgZGUgYnVzaW5lc3NhY3Rpdml0eTogKlZhbG9yIHJlYWwgcG9yIGVzdGFkbyoNCg0KKiBCYWphIENhbGlmb3JuaWEgdGllbmUgYWN0aXZpZGFkIG5lZ2F0aXZhIG3DoXMgYWx0YSAocm9qbyBvc2N1cm8pLg0KDQoqIEVsIHJlc3RvIGRlbCBwYcOtcyB0aWVuZSB2YWxvcmVzIG3DoXMgbW9kZXJhZGFtZW50ZSBuZWdhdGl2b3MgKGF6dWxlcyBjbGFyb3MgYSBtZWRpb3MpLg0KDQoqIEFsZ3Vub3MgZXN0YWRvcyBkZWwgc3VyL3N1cmVzdGUgdGllbmVuIGFjdGl2aWRhZCBsZXZlbWVudGUgcG9zaXRpdmEuDQoNCg0KTWFwYSBkZSBiYV9sYWc6ICpQcm9tZWRpbyBkZSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgZW4gbG9zIGVzdGFkb3MgdmVjaW5vcyoNCg0KKiBFbCBub3J0ZSBkZWwgcGHDrXM6IGNvbG9yZXMgZnVlcnRlcyBlbiBuYXJhbmphcyDihpIgc2UgY29uY2VudHJhbiBsb3MgdmVjaW5kYXJpb3MgKGVzdGFkb3MpIGNvbiBtYXlvciBhY3RpdmlkYWQgZW1wcmVzYXJpYWwuDQoNCiogQ29udHJhc3RlIGNvbiBlbCBzdXI6IGNvbG9yZXMgY2xhcm9zIOKGkiBzdXMgdmVjaW5vcyB0aWVuZW4gYmFqYSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwuDQoNCiogQWxndW5vcyBlc3RhZG9zIGNvbW8gU29ub3JhIHkgQmFqYSBDYWxpZm9ybmlhIHRpZW5lbiB2YWxvcmVzIGFsdG9zIGVuIGxhZyBwZXJvIGJham9zIGVuIGVsIHByZXNlbnRlLCBsbyBxdWUgc3VnaWVyZSBxdWUgZXN0w6FuIHJvZGVhZG9zIGRlIGVzdGFkb3MgY29uIG1heW9yIGFjdGl2aWRhZC4NCg0KU2Ugb2JzZXJ2YSBxdWUgY2xhcmFtZW50ZSAqc2kgaGF5IGFncnVwYW1pZW50byBlc3BhY2lhbCBwb3NpdGl2byogeWEgcXVlIHNlIG5vdGEgbGEgZGlmZXJlbmNpYSBkZSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgZW50cmUgZWwgTm9ydGUgeSBlbCBTdXIgZGVsIHBhw61zIChjbMO6c3RlcmVzIHJlZ2lvbmFsZXMgZGUgYWN0aXZpZGFkKS4gIA0KIA0KDQoqKkRlc2VtcGxlbyAoVW5lbXBsb3ltZW50KSoqDQoNCk1hcGEgZGUgVW5lbXBsb3ltZW50OiAqUG9yY2VudGFqZSBkZSBkZXNlbXBsZW8gZW4gY2FkYSBlc3RhZG8qDQoNCiogRGlzdHJpYnVjacOzbiB2YXJpYWRhLCBubyB0YW4gY2xhcmEgY29tbyBCdXNpbmVzcyBBY3Rpdml0eS4NCg0KKiBFc3RhZG9zIGNvbW8gTmF5YXJpdCB5IEJhamEgQ2FsaWZvcm5pYSBTdXIgdGllbmVuIGRlc2VtcGxlbyByZWxhdGl2YW1lbnRlIGFsdG8uDQoNCiogVmFyaW9zIGVzdGFkb3MgZGVsIG5vcnRlIHkgY2VudHJvIHRpZW5lbiBkZXNlbXBsZW8gbWVkaW8tYmFqby4NCg0KDQpNYXBhIGRlIExhZy0xIFVuZW1wbG95bWVudDogKlByb21lZGlvIGRlIGRlc2VtcGxlbyBlbiBsb3MgdmVjaW5vcyBkZSBjYWRhIGVzdGFkbyoNCg0KKiBBbGd1bm9zIGVzdGFkb3MgY29tbyBDaGlhcGFzIG8gQ2FtcGVjaGUgdGllbmVuIHZhbG9yZXMgbW9kZXJhZG9zIHBlcm8gZXN0w6FuIHJvZGVhZG9zIGRlIGVzdGFkb3MgY29uIGJham8gZGVzZW1wbGVvLg0KDQoqIEJhamEgQ2FsaWZvcm5pYSBTdXIgc2UgbWFudGllbmUgY29uIGFsdG8gZGVzZW1wbGVvIHkgc3VzIHZlY2lub3MgdGFtYmnDqW4sIHJlZm9yemFuZG8gbGEgcHJlc2VuY2lhIGRlIHVuIGNsdXN0ZXIgbmVnYXRpdm8uDQoNCiogTXVlc3RyYSBxdWUgZWwgZGVzZW1wbGVvIGVzdMOhIG3DoXMgZnJhZ21lbnRhZG8sIG5vIGhheSBwYXRyb25lcyB0YW4gZnVlcnRlcyBuaSBjb250aW51aWRhZCByZWdpb25hbCBjbGFyYS4NCg0KKiBSZWZ1ZXJ6YSBlbCByZXN1bHRhZG8gZGVsIGVzdGFkw61zdGljbyBNb3JhbiwgcXVlIG5vcyBtb3N0csOzIHF1ZSBlbCBkZXNlbXBsZW8gbm8gdGllbmUgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBzaWduaWZpY2F0aXZhLCBzaW5vIGFsZWF0b3JpYS4NCg0KQWxndW5vcyBlc3RhZG9zIGVzdMOhbiBkZW50cm8gZGUgY2x1c3RlcnMgZG9uZGUgdGFudG8gZWxsb3MgY29tbyBzdXMgdmVjaW5vcyB0aWVuZW4gdmFsb3JlcyBzaW1pbGFyZXMsIGVzcGVjaWFsbWVudGUgZW4gZGVzZW1wbGVvIChwb3NpYmxlIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwpLiBBc2ltaXNtbywgc2Ugb2JzZXJ2YSBxdWUgY2xhcmFtZW50ZSAqbm8gaGF5IGFncnVwYW1pZW50byBlc3BhY2lhbCBwb3NpdGl2byogeWEgcXVlIG5vIHNlIGRpZmVyZW5jaWEgbGEgdmFyaWFjacOzbiBkZSBsYSB0YXNhIGRlIGRlc2VtcGxlbyBlbnRyZSBlbCBOb3J0ZSwgQ2VudHJvIHkgU3VyIGRlbCBwYcOtcy4NCiANCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KdW5lbXBsb3ltZW50X2xhZyA8LSB0bV9zaGFwZShzdGF0ZV9nZW9kYXRhKSArIA0KICB0bV9wb2x5Z29ucyhjb2wgPSAic3BfbGFnX3VuZW1wbG95bWVudCIsIA0KICAgICAgICAgICAgICBwYWxldHRlPSJHcmVlbnMiLCBzdHlsZT0icXVhbnRpbGUiLCANCiAgICAgICAgICAgICAgbj04LCANCiAgICAgICAgICAgICAgdGl0bGU9IlVuZW1wbG95bWVudCIpICsNCiAgdG1fbGF5b3V0KG1haW4udGl0bGU9ICdDbHVzdGVycyBvZiBVbmVtcGxveW1lbnQnLCAgDQogICAgICAgICAgICB0aXRsZS5wb3NpdGlvbiA9IGMoJ3JpZ2h0JywgJ3RvcCcpLCANCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0gYygibGVmdCIsICJib3R0b20iKSwgDQogICAgICAgICAgICB0aXRsZS5zaXplID0gMSkNCg0KYmFfbGFnIDwtIHRtX3NoYXBlKHN0YXRlX2dlb2RhdGEpICsgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJzcF9sYWdfYnVzaW5lc3NfYWN0aXZpdHkiLCANCiAgICBwYWxldHRlID0gIk9yUmQiLCANCiAgICBzdHlsZSA9ICJxdWFudGlsZSIsIA0KICAgIG4gPSA4LCANCiAgICBtaWRwb2ludCA9IE5BLCAgICAgIyA8LS0gZXZpdGEgZm9yemFyIGVsIHB1bnRvIG1lZGlvIGVuIDANCiAgICB0aXRsZSA9ICJCdXNpbmVzcyBBY3Rpdml0eSAoTGFnLTEpIg0KICApICsNCiAgdG1fbGF5b3V0KA0KICAgIG1haW4udGl0bGUgPSAiQ2x1c3RlcnMgb2YgQnVzaW5lc3MgQWN0aXZpdHkgKExhZy0xKSIsICANCiAgICB0aXRsZS5wb3NpdGlvbiA9IGMoInJpZ2h0IiwgInRvcCIpLCANCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpLCANCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQp0bWFwX2FycmFuZ2UoYnVzaW5lc3NhY3Rpdml0eSwgYmFfbGFnLCB1bmVtcGxveW1lbnQsIHVuZW1wbG95bWVudF9sYWcsIG5jb2wgPSAyKQ0KYGBgDQoNCg0KYGBge3J9DQojIENhbGN1bGFyIHJhbmdvcyBjb211bmVzDQpiYV9yYW5nZSA8LSByYW5nZShjKHN0YXRlX2dlb2RhdGEkYnVzaW5lc3NfYWN0aXZpdHksIHN0YXRlX2dlb2RhdGEkc3BfbGFnX2J1c2luZXNzX2FjdGl2aXR5KSwgbmEucm0gPSBUUlVFKQ0KdW5lbXBfcmFuZ2UgPC0gcmFuZ2UoYyhzdGF0ZV9nZW9kYXRhJHVuZW1wbG95bWVudCwgc3RhdGVfZ2VvZGF0YSRzcF9sYWdfdW5lbXBsb3ltZW50KSwgbmEucm0gPSBUUlVFKQ0KDQojIE1hcGEgZGUgQnVzaW5lc3MgQWN0aXZpdHkNCmJ1c2luZXNzYWN0aXZpdHkxIDwtIHRtX3NoYXBlKHN0YXRlX2dlb2RhdGEpICsgIA0KICB0bV9wb2x5Z29ucygNCiAgICBjb2wgPSAiYnVzaW5lc3NfYWN0aXZpdHkiLA0KICAgIHBhbGV0dGUgPSAiLVJkQnUiLA0KICAgIHN0eWxlID0gImNvbnQiLA0KICAgIHRpdGxlID0gIkJ1c2luZXNzIEFjdGl2aXR5IiwNCiAgICBicmVha3MgPSBzZXEoYmFfcmFuZ2VbMV0sIGJhX3JhbmdlWzJdLCBsZW5ndGgub3V0ID0gMTApICAjIGVzY2FsYSBjb23Dum4NCiAgKSArDQogIHRtX2xheW91dCgNCiAgICBtYWluLnRpdGxlID0gIkJ1c2luZXNzIEFjdGl2aXR5IiwNCiAgICB0aXRsZS5wb3NpdGlvbiA9IGMoInJpZ2h0IiwgInRvcCIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoImxlZnQiLCAiYm90dG9tIiksDQogICAgdGl0bGUuc2l6ZSA9IDENCiAgKQ0KDQojIE1hcGEgZGUgQnVzaW5lc3MgQWN0aXZpdHkgKExhZykNCmJhX2xhZzEgPC0gdG1fc2hhcGUoc3RhdGVfZ2VvZGF0YSkgKyANCiAgdG1fcG9seWdvbnMoDQogICAgY29sID0gInNwX2xhZ19idXNpbmVzc19hY3Rpdml0eSIsDQogICAgcGFsZXR0ZSA9ICItUmRCdSIsICAjIG1pc21hIHBhbGV0YQ0KICAgIHN0eWxlID0gImNvbnQiLA0KICAgIHRpdGxlID0gIkJ1c2luZXNzIEFjdGl2aXR5IChMYWctMSkiLA0KICAgIGJyZWFrcyA9IHNlcShiYV9yYW5nZVsxXSwgYmFfcmFuZ2VbMl0sIGxlbmd0aC5vdXQgPSAxMCkgICMgbWlzbWEgZXNjYWxhDQogICkgKw0KICB0bV9sYXlvdXQoDQogICAgbWFpbi50aXRsZSA9ICJDbHVzdGVycyBvZiBCdXNpbmVzcyBBY3Rpdml0eSAoTGFnLTEpIiwNCiAgICB0aXRsZS5wb3NpdGlvbiA9IGMoInJpZ2h0IiwgInRvcCIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoImxlZnQiLCAiYm90dG9tIiksDQogICAgdGl0bGUuc2l6ZSA9IDENCiAgKQ0KDQojIE1hcGEgZGUgVW5lbXBsb3ltZW50DQp1bmVtcGxveW1lbnQxIDwtIHRtX3NoYXBlKHN0YXRlX2dlb2RhdGEpICsgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJ1bmVtcGxveW1lbnQiLA0KICAgIHBhbGV0dGUgPSAidmlyaWRpcyIsDQogICAgc3R5bGUgPSAiY29udCIsDQogICAgdGl0bGUgPSAiVW5lbXBsb3ltZW50IiwNCiAgICBicmVha3MgPSBzZXEodW5lbXBfcmFuZ2VbMV0sIHVuZW1wX3JhbmdlWzJdLCBsZW5ndGgub3V0ID0gOCkgICMgZXNjYWxhIGNvbcO6bg0KICApICsNCiAgdG1fbGF5b3V0KA0KICAgIG1haW4udGl0bGUgPSAiVW5lbXBsb3ltZW50IiwNCiAgICB0aXRsZS5wb3NpdGlvbiA9IGMoInJpZ2h0IiwgInRvcCIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoImxlZnQiLCAiYm90dG9tIiksDQogICAgdGl0bGUuc2l6ZSA9IDENCiAgKQ0KDQojIE1hcGEgZGUgVW5lbXBsb3ltZW50IChMYWcpDQp1bmVtcGxveW1lbnRfbGFnMSA8LSB0bV9zaGFwZShzdGF0ZV9nZW9kYXRhKSArICANCiAgdG1fcG9seWdvbnMoDQogICAgY29sID0gInNwX2xhZ191bmVtcGxveW1lbnQiLA0KICAgIHBhbGV0dGUgPSAidmlyaWRpcyIsICAjIG1pc21hIHBhbGV0YQ0KICAgIHN0eWxlID0gImNvbnQiLA0KICAgIHRpdGxlID0gIlVuZW1wbG95bWVudCAoTGFnLTEpIiwNCiAgICBicmVha3MgPSBzZXEodW5lbXBfcmFuZ2VbMV0sIHVuZW1wX3JhbmdlWzJdLCBsZW5ndGgub3V0ID0gOCkgICMgbWlzbWEgZXNjYWxhDQogICkgKw0KICB0bV9sYXlvdXQoDQogICAgbWFpbi50aXRsZSA9ICJDbHVzdGVycyBvZiBVbmVtcGxveW1lbnQgKExhZy0xKSIsDQogICAgdGl0bGUucG9zaXRpb24gPSBjKCJyaWdodCIsICJ0b3AiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpLA0KICAgIHRpdGxlLnNpemUgPSAxDQogICkNCg0KIyBNb3N0cmFyIHRvZG9zIGxvcyBtYXBhcw0KdG1hcF9hcnJhbmdlKGJ1c2luZXNzYWN0aXZpdHkxLCBiYV9sYWcxLCB1bmVtcGxveW1lbnQxLCB1bmVtcGxveW1lbnRfbGFnMSwgbmNvbCA9IDIpDQoNCmBgYA0KDQoNCiMjIFNjYXR0ZXJwbG90cw0KDQojIyMgQnVzaW5lc3MgQWN0aXZpdHkNCg0KU2UgcmVhbGl6YSB1biBtb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwsIHBhcmEgIGlkZW50aWZpY2FyICBxdcOpIHRhbiBiaWVuIHNlIHB1ZWRlIHByZWRlY2lyIGVsIHZhbG9yIGRlIGxvcyBlc3RhZG9zIHZlY2lub3MgY29uIGVsIHZhbG9yIGRlbCBlc3RhZG86DQoNCiogUHVudG9zOiBjYWRhIGVzdGFkbw0KDQoqIEVqZSBYOiBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgZGVsIGVzdGFkbw0KDQoqIEVqZSBZOiBlbCBwcm9tZWRpbyBkZSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgZGUgc3VzIHZlY2lub3MNCg0KKiBNMSAobG0pOiBMYSBsw61uZWEgYXp1bCB0aWVuZSBwZW5kaWVudGUgcG9zaXRpdmEg4oaSIGhheSBhZ3J1cGFtaWVudG8gZXNwYWNpYWwgcG9zaXRpdm8sIHBvciBsbyBxdWUgdGFtYmnDqW4gcmVmdWVyemEgZWwgcmVzdWx0YWRvIGRlIE1vcmFuIHF1ZSBzZSBhcnJvasOzIHByZXZpYW1lbnRlLg0KDQpDb24gYmFzZSBhbCBtb2RlbG8sIHRpZW5lIHVuYSBwZW5kaWVudGUgcG9zaXRpdmEsIGVzIGRlY2lyLCBxdWUgbG9zICoqZXN0YWRvcyBjb24gbcOhcyBhY3RpdmlkYWQgdGllbmRlbiBhIGVzdGFyIGNlcmNhIGRlIG90cm9zIHNpbWlsYXJlcyDihpIgYXV0b2NvcnJlbGFjacOzbiBwb3NpdGl2YSoqLg0KDQpgYGB7cn0NCk0xIDwtIGxtKHNwX2xhZ19idXNpbmVzc19hY3Rpdml0eSB+IGJ1c2luZXNzX2FjdGl2aXR5LCBzdGF0ZV9nZW9kYXRhKQ0KDQpzdGF0ZV9nZW9kYXRhJHJlc2lkdWFscyA8LSBhYnMocmVzaWQoTTEpKQ0KDQpuX291dGxpZXJzIDwtIDUNCnRvcF9vdXRsaWVycyA8LSBvcmRlcihzdGF0ZV9nZW9kYXRhJHJlc2lkdWFscywgZGVjcmVhc2luZyA9IFRSVUUpWzE6bl9vdXRsaWVyc10NCg0KIyBQbG90DQpwbG90KHNwX2xhZ19idXNpbmVzc19hY3Rpdml0eSB+IGJ1c2luZXNzX2FjdGl2aXR5LCBzdGF0ZV9nZW9kYXRhLCBwY2g9MjEsIGFzcD0xLCBsYXM9MSwgDQogICAgIGNvbCA9ICJncmV5NDAiLCBiZz0iZ3JleTgwIiwgbWFpbj0iQnVzaW5lc3MgQWN0aXZpdHkiKQ0KDQojIEzDrW5lYSBkZSByZWdyZXNpw7NuIHkgbMOtbmVhcyBtZWRpYXMNCmFibGluZShNMSwgY29sPSJibHVlIikNCmFibGluZSh2ID0gbWVhbihzdGF0ZV9nZW9kYXRhJGJ1c2luZXNzX2FjdGl2aXR5KSwgbHR5PTMsIGNvbCA9ICJncmV5ODAiKQ0KYWJsaW5lKGggPSBtZWFuKHN0YXRlX2dlb2RhdGEkc3BfbGFnX2J1c2luZXNzX2FjdGl2aXR5KSwgbHR5PTMsIGNvbCA9ICJncmV5ODAiKQ0KDQojIFB1bnRvcyBvdXRsaWVycw0KcG9pbnRzKHN0YXRlX2dlb2RhdGEkYnVzaW5lc3NfYWN0aXZpdHlbdG9wX291dGxpZXJzXSwgDQogICAgICAgc3RhdGVfZ2VvZGF0YSRzcF9sYWdfYnVzaW5lc3NfYWN0aXZpdHlbdG9wX291dGxpZXJzXSwgDQogICAgICAgcGNoPTIxLCBiZz0icmVkIiwgY29sPSJibGFjayIsIGNleD0xLjQpDQoNCiMgRXRpcXVldGFzIGNvbiBub21icmUgKGFqdXN0YSAnTkFNRScgc2kgdHUgY29sdW1uYSB0aWVuZSBvdHJvIG5vbWJyZSkNCnRleHQoc3RhdGVfZ2VvZGF0YSRidXNpbmVzc19hY3Rpdml0eVt0b3Bfb3V0bGllcnNdLA0KICAgICBzdGF0ZV9nZW9kYXRhJHNwX2xhZ19idXNpbmVzc19hY3Rpdml0eVt0b3Bfb3V0bGllcnNdLA0KICAgICBsYWJlbHMgPSBzdGF0ZV9nZW9kYXRhJHN0YXRlW3RvcF9vdXRsaWVyc10sDQogICAgIHBvcyA9IDMsIGNleCA9IDAuOCwgY29sID0gImJsYWNrIikNCg0KYGBgDQoNCiMjIyBVbmVtcGxveW1lbnQNCg0KU2UgcmVhbGl6YSB1biBtb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwsIHBhcmEgIGlkZW50aWZpY2FyIGNvbW8gZWwgZGVzZW1wbGVvIGVuIHVuIGVzdGFkbyBwcmVkaWNlIGVsIGRlc2VtcGxlbyBwcm9tZWRpbyBkZSBzdXMgZXN0YWRvcyB2ZWNpbm9zIGVuIGRvbmRlOg0KDQoqIFB1bnRvczogY2FkYSBlc3RhZG8NCg0KKiBFamUgWDogdGFzYSBkZSBkZXNlbXBsZW8gZGVsIGVzdGFkbw0KDQoqIEVqZSBZOiBlbCBwcm9tZWRpbyBkZSBkZXNlbXBsZW8gZGUgc3VzIHZlY2lub3MNCg0KKiBNMSAobG0pOiBMYSBsw61uZWEgYXp1bCB0aWVuZSB1bmEgcGVuZGllbnRlIGNhc2kgcGxhbmEgKHJlY3RhIGhvcml6b250YWxtZW50ZSkg4oaSIG11eSBkw6liaWwgcmVsYWNpw7NuIGVzcGFjaWFsLCBwb3IgbG8gcXVlIHRhbWJpw6luIHJlZnVlcnphIGVsIHJlc3VsdGFkbyBkZSBNb3JhbiBxdWUgbm9zIGFycm9qw7MgcHJldmlhbWVudGUNCg0KKiBQdW50b3MgZGlzcGVyc29zIOKGkiBubyBoYXkgYWdydXBhbWllbnRvcyBjbGFyb3MuIChObyBoYXkgY2zDunN0ZXJlcyBmdWVydGVzIG5pIGFncnVwYW1pZW50byBlc3BhY2lhbCBkZSBsYSB2YXJpYWJsZS4pDQoNCiogRWwgZGVzZW1wbGVvIHBhcmVjZSBlc3BhY2lhbG1lbnRlIGFsZWF0b3Jpbzogbm8gc2UgYWdydXBhIGRlIGZvcm1hIGNsYXJhIHBvciByZWdpb25lcy4NCg0KQ29uIGJhc2UgYWwgbW9kZWxvLCBzZSBkZXRlcm1pbmEgcXVlIGxhIHZhcmlhYmxlIHRpZW5lIHVuYSBwZW5kaWVudGUgbXV5IGJhamEgIOKGkiBObyBoYXkgZXZpZGVuY2lhIGRlIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgc2lnbmlmaWNhdGl2YSwgZXMgZGVjaXIsICoqdW4gZXN0YWRvIGNvbiBhbHRvIGRlc2VtcGxlbyBubyBuZWNlc2FyaWFtZW50ZSBlc3TDoSByb2RlYWRvIGRlIG90cm9zIGNvbiBhbHRvIGRlc2VtcGxlbyoqLg0KDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSByZWdyZXNzaW9uIG1vZGVsDQpNMiA8LSBsbShzcF9sYWdfdW5lbXBsb3ltZW50IH4gdW5lbXBsb3ltZW50LCBzdGF0ZV9nZW9kYXRhKQ0KDQojIENhbGN1bGFyIGxvcyByZXNpZHVvcyBhYnNvbHV0b3MgKGRpc3RhbmNpYSB2ZXJ0aWNhbCBhIGxhIGzDrW5lYSBkZSByZWdyZXNpw7NuKQ0Kc3RhdGVfZ2VvZGF0YSRyZXNpZHVhbHMgPC0gYWJzKHJlc2lkKE0yKSkNCg0KIyBJZGVudGlmaWNhciBsb3MgbiBwdW50b3MgbcOhcyBsZWphbm9zIChwb3IgZWplbXBsbywgbG9zIDUgbWF5b3JlcyByZXNpZHVvcykNCm5fb3V0bGllcnMgPC0gNQ0KdG9wX291dGxpZXJzIDwtIG9yZGVyKHN0YXRlX2dlb2RhdGEkcmVzaWR1YWxzLCBkZWNyZWFzaW5nID0gVFJVRSlbMTpuX291dGxpZXJzXQ0KDQojIFBsb3QgdGhlIGRhdGEgKE1vcmFuIHNjYXR0ZXJwbG90KSArIExNDQpwbG90KHNwX2xhZ191bmVtcGxveW1lbnQgfiB1bmVtcGxveW1lbnQsIHN0YXRlX2dlb2RhdGEsIHBjaD0yMSwgYXNwPTEsIGxhcz0xLCANCiAgICAgY29sID0gImdyZXk0MCIsIGJnPSJncmV5ODAiLCBtYWluPSJVbmVtcGxveW1lbnQiKQ0KYWJsaW5lKE0xLCBjb2w9ImJsdWUiKSAjIEzDrW5lYSBkZSByZWdyZXNpw7NuDQphYmxpbmUodiA9IG1lYW4oc3RhdGVfZ2VvZGF0YSR1bmVtcGxveW1lbnQpLCBsdHk9MywgY29sID0gImdyZXk4MCIpDQphYmxpbmUoaCA9IG1lYW4oc3RhdGVfZ2VvZGF0YSRzcF9sYWdfdW5lbXBsb3ltZW50KSwgbHR5PTMsIGNvbCA9ICJncmV5ODAiKQ0KDQpwb2ludHMoc3RhdGVfZ2VvZGF0YSR1bmVtcGxveW1lbnRbdG9wX291dGxpZXJzXSwgDQogICAgICAgc3RhdGVfZ2VvZGF0YSRzcF9sYWdfdW5lbXBsb3ltZW50W3RvcF9vdXRsaWVyc10sIA0KICAgICAgIHBjaD0yMSwgYmc9InJlZCIsIGNvbD0iYmxhY2siLCBjZXg9MS40KQ0KDQojIEV0aXF1ZXRhcyBjb24gbm9tYnJlIChhanVzdGEgJ05BTUUnIHNpIHR1IGNvbHVtbmEgdGllbmUgb3RybyBub21icmUpDQp0ZXh0KHN0YXRlX2dlb2RhdGEkdW5lbXBsb3ltZW50W3RvcF9vdXRsaWVyc10sDQogICAgIHN0YXRlX2dlb2RhdGEkc3BfbGFnX3VuZW1wbG95bWVudFt0b3Bfb3V0bGllcnNdLA0KICAgICBsYWJlbHMgPSBzdGF0ZV9nZW9kYXRhJHN0YXRlW3RvcF9vdXRsaWVyc10sDQogICAgIHBvcyA9IDMsIGNleCA9IDAuOCwgY29sID0gImJsYWNrIikNCg0KYGBgDQoNCiMjIFZpc3VhbGl6YWNpw7NuIEVzcGFjaWFsIGRlIENsdXN0ZXJzIChDb25nbG9tZXJhZG9zKQ0KDQpTZWdyZWdhY2nDs24gZW4gbGFzIGRpZmVyZW50ZXMgcG9zaWJpbGlkYWRlcyBkZSBhZ3J1cGFjaW9uZXM6DQoNCiogTm8gc2lnbmlmaWNhbnRlDQoNCiogSG90U3BvdHM6IEhpZ2ggLSBIaWdoDQoNCiogQ29sZFNwb3RzOiBMb3cgLSBMb3cNCg0KKiBBdMOtcGljb3M6IEhpZ2ggLSBMb3cNCg0KKiBBdMOtcGljb3M6IExvdyAtIEhpZ2gNCg0KIyMjIEJ1c2luZXNzIEFjdGl2aXR5DQoNClNlIGdlbmVyYW4gY2zDunN0ZXJzOg0KDQoqIExvdy1IaWdoOiBCYWphIGFjdGl2aWRhZCBlbXByZXNhcmlhbCwgcGVybyByb2RlYWRvIGRlIHZlY2lub3MgY29uIGFsdGFjdGl2aWRhZCBlbXByZXNhcmlhbCAgKHBvc2libGUgb3V0bGllciBlc3BhY2lhbCkuDQoNCiogSGlnaC1IaWdoOiBBbHRhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCwgcm9kZWFkbyBkZSB2ZWNpbm9zIGNvbiBhbHRhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCAoY2zDunN0ZXIgcG9zaXRpdm8pLg0KDQoqIEhpZ2gtTG93OiBBbHRhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCwgcGVybyB2ZWNpbm9zIGNvbiBiYWphIGFjdGl2aWRhZCBlbXByZXNhcmlhbCAocG9zaWJsZSBvdXRsaWVyIGVzcGFjaWFsKS4NCg0KKiBMb3ctTG93OiBCYWphIGFjdGl2aWRhZCBlbXByZXNhcmlhbCwgcm9kZWFkbyBkZSB2ZWNpbm9zIGNvbiBiYWphIGFjdGl2aWRhZCBlbXByZXNhcmlhbCAoY2zDunN0ZXIgbmVnYXRpdm8pLiAgDQoNCg0KQ29uIGJhc2UgYSBsYSBjb2xvcmltZXRyw61hIGRlbCBtYXBhIHNlIGRldGVybWluYSBxdWU6DQoNCiog8J+UtCBFc3RhZG9zIHNpbiBldmlkZW5jaWEgZGUgYWdydXBhbWllbnRvIGVzcGFjaWFsDQoNCiog8J+foiBTb25vcmEgZXN0YWRvIGNvbiBhbHRhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCByb2RlYWRvcyBkZSBvdHJvcyBzaW1pbGFyZXMNCg0KKiDwn5S1IFBlbsOtbnN1bGEgZGUgWXVjYXTDoW4gZXN0YWRvcyBjb24gYmFqYSBhY3RpdmlkYWQgZW1wcmVzYXJpYWwgcm9kZWFkbyBkZSBvdHJvcyBzaW1pbGFyZXMgKGNsw7pzdGVyIG5lZ2F0aXZvKQ0KDQoqIPCfn6MgQmFqYSBDYWxpZm9ybmlhIFN1ciBlc3RhZG8gY29uIGJhamEgYWN0aXZpZGFkIGVtcHJlc2FyaWFsIHJvZGVhZG8gZGUgdmVjaW5vcyBjb24gYWx0YSBhY3RpdmlkYWQgKG91dGxpZXIgbmVnYXRpdm8pDQoNCg0KYGBge3J9DQpzd21fYSA8LSBxdWVlbl93ZWlnaHRzKG14X3N0YXRlX21hcCkgIyBxdWVlbiBzcGF0aWFsIHdlaWdodCBtYXRyaXggKGFsdGVybmF0aXZlIGZvcm1hdCkNCg0KIyAxLiBDYWxjdWxhciBMSVNBDQpsaXNhX2J1c2luZXNzIDwtIGxvY2FsX21vcmFuKHN3bV9hLCBzdGF0ZV9nZW9kYXRhWyJidXNpbmVzc19hY3Rpdml0eSJdKQ0KDQojIDIuIEFzaWduYXIgY2zDunN0ZXJlcyBjb24gZXRpcXVldGFzDQpzdGF0ZV9nZW9kYXRhJGNsdXN0ZXJfYnVzaW5lc3MgPC0gYXMuZmFjdG9yKGxpc2FfYnVzaW5lc3MkR2V0Q2x1c3RlckluZGljYXRvcnMoKSkNCmxldmVscyhzdGF0ZV9nZW9kYXRhJGNsdXN0ZXJfYnVzaW5lc3MpIDwtIGxpc2FfYnVzaW5lc3MkR2V0TGFiZWxzKCkNCg0KIyAzLiBNYXBhIGNvbiBlc3RpbG8gcG9yIGRlZmVjdG8NCmxpYnJhcnkoZ2dwbG90MikNCg0KZ2dwbG90KGRhdGEgPSBzdGF0ZV9nZW9kYXRhKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjbHVzdGVyX2J1c2luZXNzKSwgY29sb3IgPSAid2hpdGUiKSArDQogIGdndGl0bGUobGFiZWwgPSAiQnVzaW5lc3MgQWN0aXZpdHkiLCBzdWJ0aXRsZSA9ICJNZXhpY28ncyBTdGF0ZXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KIyMjIFVuZW1wbG95bWVudA0KDQpTZSBnZW5lcmFuIGNsw7pzdGVyczoNCg0KKiBMb3ctSGlnaDogQmFqbyBkZXNlbXBsZW8sIHBlcm8gcm9kZWFkbyBkZSB2ZWNpbm9zIGNvbiBhbHRvIGRlc2VtcGxlbyAocG9zaWJsZSBvdXRsaWVyIGVzcGFjaWFsKS4NCg0KKiBIaWdoLUhpZ2g6IEFsdG8gZGVzZW1wbGVvLCByb2RlYWRvIGRlIHZlY2lub3MgY29uIGFsdG8gZGVzZW1wbGVvIChjbMO6c3RlciBwb3NpdGl2bykuIA0KDQoqIEhpZ2gtTG93OiBBbHRvIGRlc2VtcGxlbywgcGVybyB2ZWNpbm9zIGNvbiBiYWpvIGRlc2VtcGxlbyAocG9zaWJsZSBvdXRsaWVyIGVzcGFjaWFsKS4NCg0KKiBMb3ctTG93OiBCYWpvIGRlc2VtcGxlbywgcm9kZWFkbyBkZSB2ZWNpbm9zIGNvbiBiYWpvIGRlc2VtcGxlbyAoY2zDunN0ZXIgbmVnYXRpdm8pLg0KDQoNCkNvbiBiYXNlIGEgbGEgY29sb3JpbWV0csOtYSBkZWwgbWFwYSBzZSBkZXRlcm1pbmEgcXVlOg0KDQoqIPCflLQgRXN0YWRvcyBzaW4gZXZpZGVuY2lhIGRlIGFncnVwYW1pZW50byBlc3BhY2lhbA0KDQoqIPCfn6IgSGlkYWxnbyBlc3RhZG8gY29uIGFsdG8gZGVzZW1wbGVvIHJvZGVhZG9zIGRlIG90cm9zIHNpbWlsYXJlcw0KDQoqIPCflLUgUXVpbnRhbmEgUm9vIGVzdGFkbyBjb24gYmFqYSB0YXNhIGRlIGRlc2VtcGxlbyByb2RlYWRvIGRlIG90cm9zIHNpbWlsYXJlcyAoY2zDunN0ZXIgbmVnYXRpdm8pDQoNCmBgYHtyfQ0Kc3N3bV9hIDwtIHF1ZWVuX3dlaWdodHMobXhfc3RhdGVfbWFwKSAjIHF1ZWVuIHNwYXRpYWwgd2VpZ2h0IG1hdHJpeCAoYWx0ZXJuYXRpdmUgZm9ybWF0KQ0KbGlzYV9pbmNvbWUgPC0gbG9jYWxfbW9yYW4oc3N3bV9hLCBzdGF0ZV9nZW9kYXRhWyJ1bmVtcGxveW1lbnQiXSkgDQpzdGF0ZV9nZW9kYXRhJGNsdXN0ZXJfdW5lbXBsb3ltZW50IDwtIGFzLmZhY3RvcihsaXNhX2luY29tZSRHZXRDbHVzdGVySW5kaWNhdG9ycygpKQ0KbGV2ZWxzKHN0YXRlX2dlb2RhdGEkY2x1c3Rlcl91bmVtcGxveW1lbnQpPC1saXNhX2luY29tZSRHZXRMYWJlbHMoKSANCg0KZ2dwbG90KGRhdGE9c3RhdGVfZ2VvZGF0YSkgKw0KICBnZW9tX3NmKGFlcyhmaWxsPWNsdXN0ZXJfdW5lbXBsb3ltZW50KSkgKyANCiAgZ2d0aXRsZShsYWJlbCA9ICJVbmVtcGxveW1lbnQiLCBzdWJ0aXRsZSA9ICJNZXhpY28ncyBTdGF0ZXMiKQ0KYGBgDQoNCg0KIyAqKk1vZGVsb3MqKg0KDQpTZSBjYXJnYW4gbGlicmVyw61hcyBwYXJhIGVsIGFqdXN0ZSBkZSBtb2RlbG9zIGRlIHJlZ3Jlc2nDs246DQpgYGB7cn0NCmxpYnJhcnkoc3BhdGlhbHJlZykNCmxpYnJhcnkoc3RhcmdhemVyKQ0KYGBgDQoNCg0KIyMgUmVncmVzacOzbiBTaW1wbGUNCg0KU2UgYnVzY2EgZXhwbGljYXIgbGEgdmFyaWFibGUgZGUgSW52ZXJzacOzbiBFeHRyYW5qZXJhIERpcmVjdGEgY29uc2lkZXJhbmRvIGxhcyB2YXJpYWJsZXMgZGUgQWN0aXZpZGFkIEVtcHJlc2FyaWFsIHkgbGEgVGFzYSBkZSBEZXNlbXBsZW8uDQoNCkVsIG1vZGVsb19hLCBhdW5xdWUgc2lnbmlmaWNhdGl2bywgcmVhbG1lbnRlIG5vIGVzIHRhbiBidWVubywgcHVlcyBsYSAkUl4yJCBhanVzdGFkYSBhcGVuYXMgc29icmVwYXNhIGVsIDAuNSAoJFxiYXJ7Ul4yfSQgPSAwLjU4MjEpLiANCg0KQ29uIGJhc2UgYSBlc3RvLCBzZSBnZW5lcmHDoW4gb3Ryb3MgbW9kZWxvcyBwYXJhIGRhciB1bmEgbWF5b3IgY29tcGxlamlkYWQgYWwgY29uc2lkZXJhciB0ZXJtaW5vcyBkZSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsLg0KDQpgYGB7cn0NCm1vZGVsX2EgPC0gbG0obmV3X2ZkaV9yZWFsX214biB+IGJ1c2luZXNzX2FjdGl2aXR5ICsgdW5lbXBsb3ltZW50LCBkYXRhID0gc3RhdGVfZ2VvZGF0YSkNCnN1bW1hcnkobW9kZWxfYSkNCkFJQyhtb2RlbF9hKQ0KYGBgDQoNCg0KIyMgU0FSIC0gU3BhdGlhbCBBdXRvUmVncmVzc2l2ZSBNb2RlbA0KDQpTZSByZWFsaXphIG1vZGVsbyBTQVIsIHRhbWJpw6luIGNvbm9jaWRvIGNvbW8gU3BhdGlhbCBMYWcgTW9kZWwgRXNlbmNpYWwsIGVuIGVsIGN1YWwgc2UgaW5jbHV5ZSBsYSBtYXRyaXogZGUgY29uZWN0aXZpZGFkIGVzcGFjaWFsIGRhZGEgZW4gZWwgcGFyw6FtZXRybyAnbGlzdHcnIHBvciBlbCBvYmpldG8gcHJldmlhbWVudGUgY2FsY3VsYWRvIGNvbiBlbCBub21icmUgZGUgJ3Nzd20nLiBTZSBvYnNlcnZhIHF1ZSBlbCBBSUMgZXMgbWF5b3IgcXVlIGVsIGRlIHJlZ3Jlc2nDs24gc2ltcGxlLg0KDQpgYGB7cn0NCm1vZGVsX2IgPC0gbGFnc2FybG0obmV3X2ZkaV9yZWFsX214biB+IGJ1c2luZXNzX2FjdGl2aXR5ICsgdW5lbXBsb3ltZW50LCBkYXRhID0gc3RhdGVfZ2VvZGF0YSwgbGlzdHcgPSBzc3dtKSANCnN1bW1hcnkobW9kZWxfYikNCkFJQyhtb2RlbF9iKQ0KYGBgDQoNCg0KIyMgU0VNIC0gU3BhdGlhbCBFcnJvciBNb2RlbA0KDQpTZSBnZW5lcmEgTW9kZWxvIGRlIEVycm9yIEVzcGFjaWFsLiBJZ3VhbCBxdWUgZW4gZWwgbW9kZWxvIFNBUiBlcyBlc2VuY2lhbCwgaW5jbHVpciBsYSBtYXRyaXogZGUgY29uZWN0aXZpZGFkIGVzcGFjaWFsIGRhZGEgZW4gZWwgcGFyw6FtZXRybyAnbGlzdHcnIHBvciBlbCBvYmpldG8gcHJldmlhbWVudGUgY2FsY3VsYWRvIGNvbiBlbCBub21icmUgZGUgJ3Nzd20nLiBTZSBjYWxjdWxhIHF1ZSBzdSB2YWxvciBkZSBBSUMgZXMgbWVub3IgcXVlIGVsIFNBUiB5IGNvbiB1bmEgZGlmZXJlbmNpYSBtYXlvciBkZSAwLjIxIGFsIEFJQyBkZSBsYSByZWdyZXNpw7NuIHNpbXBsZS4NCg0KYGBge3J9DQptb2RlbF9jIDwtIGVycm9yc2FybG0obmV3X2ZkaV9yZWFsX214biB+IGJ1c2luZXNzX2FjdGl2aXR5ICsgdW5lbXBsb3ltZW50LCBkYXRhID0gc3RhdGVfZ2VvZGF0YSwgbGlzdHcgPSBzc3dtKQ0Kc3VtbWFyeShtb2RlbF9jKQ0KQUlDKG1vZGVsX2MpDQpgYGANCg0KDQojIyBTRE0gLSAgU3BhdGlhbCBEdXJiaW4gTW9kZWwNCg0KSWd1YWwgcXVlIGVuIGxvcyBtb2RlbG8gU0FSIHkgU0VNIGVzIGVzZW5jaWFsLCBpbmNsdWlyIGxhIG1hdHJpeiBkZSBjb25lY3RpdmlkYWQgZXNwYWNpYWwgZGFkYSBlbiBlbCBwYXLDoW1ldHJvICdsaXN0dycgcG9yIGVsIG9iamV0byBwcmV2aWFtZW50ZSBjYWxjdWxhZG8gY29uIGVsIG5vbWJyZSBkZSAnc3N3bScgeSBhcXXDrSBlbiBwYXJ0aWN1bGFyIHNlIGRlYmUgYcOxYWRpciBlbCBwYXLDoW1ldHJvICd0eXBlJyBjb24gdmFsb3IgJ21peGVkJyBwYXJhIHF1ZSBlbiBlc2VuY2lhIG1lemNsZSBsb3MgZG9zIG1vZGVsb3MgcHJldmlvcyAoU0FSIHkgU0VNKS4gU1UgdmFsb3IgZGUgQUlDIGVzIGVsIG3DoXMgYWx0byBwZXJvLCBsb2dyYSBsYSBtZW5vciB2YXJpYW56YSByZXNpZHVhbCB5IG1lam9yIGludGVycHJldGFjacOzbiBlc3RydWN0dXJhbC4NCg0KYGBge3J9DQptb2RlbF9kIDwtIGxhZ3NhcmxtKG5ld19mZGlfcmVhbF9teG4gfiBidXNpbmVzc19hY3Rpdml0eSArIHVuZW1wbG95bWVudCwgZGF0YSA9IHN0YXRlX2dlb2RhdGEsIGxpc3R3ID0gc3N3bSwgdHlwZT0ibWl4ZWQiKSANCnN1bW1hcnkobW9kZWxfZCkNCkFJQyhtb2RlbF9kKQ0KYGBgDQoNCg0KIyMgQ29tcGFyYXRpdmENCkF1bnF1ZSBlbCBtb2RlbG8gYyBwcmVzZW50YSB1biBtZWpvciByZW5kaW1pZW50byBlc3RhZMOtc3RpY28gY29uIGVsIG1lbm9yIEFJQyAoNjcxLjY2KSwgZWwgb2JqZXRpdm8gcHJpbmNpcGFsIGVzIGlkZW50aWZpY2FyIGPDs21vIGVsIGVudG9ybm8g4oCUZXNwZWPDrWZpY2FtZW50ZSBsYSBhY3RpdmlkYWQgZGUgbG9zIGVzdGFkb3MgdmVjaW5vc+KAlCBpbmZsdXllIGVuIGxhIEludmVyc2nDs24gRXh0cmFuamVyYSBEaXJlY3RhIChGREkpLiBQb3IgZWxsbywgc2Ugc2VsZWNjaW9uYSBlbCBtb2RlbG8gZCwgeWEgcXVlIHBlcm1pdGUgY2FwdGFyIGVmZWN0b3MgZXNwYWNpYWxlcyBpbmRpcmVjdG9zIChpbmZsdWVuY2lhIGRlIHJlZ2lvbmVzIHZlY2luYXMpLCBhIHBlc2FyIGRlIHRlbmVyIHVuIEFJQyBsaWdlcmFtZW50ZSBzdXBlcmlvci4gQWRlbcOhcywgdGFudG8gbGEgdmFyaWFibGUgYnVzaW5lc3NfYWN0aXZpdHkgY29tbyBzdSByZXRhcmRvIGVzcGFjaWFsIHJlc3VsdGFuIHNpZ25pZmljYXRpdmFzIG8gY2VyY2FuYXMgYSBsYSBzaWduaWZpY2FuY2lhLCBsbyBjdWFsIGV2aWRlbmNpYSB1bmEgaW50ZXJkZXBlbmRlbmNpYSByZWdpb25hbCBlbiBsYSBhdHJhY2Npw7NuIGRlIGludmVyc2nDs24uIERlIGVzdGEgbWFuZXJhLCBlbCBtb2RlbG8gZCBvZnJlY2UgdW5hIHJlcHJlc2VudGFjacOzbiBtw6FzIGNvbXBsZXRhIHkgcmVhbGlzdGEgZGVsIGZlbsOzbWVubyBlc3BhY2lhbCBhbmFsaXphZG8uDQoNCmBgYHtyfQ0Kc3RhcmdhemVyKG1vZGVsX2EsIG1vZGVsX2IsIG1vZGVsX2MsIG1vZGVsX2QsIHR5cGUgPSAidGV4dCIsIHRpdGxlPSJFc3RpbWF0ZWQgUmVncmVzc2lvbiBSZXN1bHRzIikNCmBgYA0KDQoNCiMgKipDb25jbHVzacOzbioqIA0KU2UgZXZhbHVhcm9uIGN1YXRybyBtb2RlbG9zIGRlIHJlZ3Jlc2nDs24gKE9MUyB5IGVzcGFjaWFsZXMpIHBhcmEgZXhwbGljYXIgbGEgdmFyaWFjacOzbiBkZSBsYSBpbnZlcnNpw7NuIGV4dHJhbmplcmEgZGlyZWN0YSAobmV3X2ZkaV9yZWFsX214bikgZW4gbG9zIGVzdGFkb3MgZGUgTcOpeGljby4gRWwgKm1vZGVsbyBkKiwgcXVlIGluY29ycG9yYSBlZmVjdG9zIGVzcGFjaWFsZXMgYXV0b3JlZ3Jlc2l2b3MgeSBsb3MgbGFncyBlc3BhY2lhbGVzIGRlIGxvcyBwcmVkaWN0b3JlcywgZnVlICpzZWxlY2Npb25hZG8gY29tbyBlbCBtw6FzIGFkZWN1YWRvKiBwb3IgbGFzIHNpZ3VpZW50ZXMgcmF6b25lczoNCg0KKiBDYXB0dXJhIGxhIGRlcGVuZGVuY2lhIGVzcGFjaWFsIGRlIGxhIEZESTogaW5jbHV5ZSB1biBjb21wb25lbnRlIGF1dG9yZWdyZXNpdm8gcXVlIHJlY29ub2NlIHF1ZSBsYSBpbnZlcnNpw7NuIGVuIHVuIGVzdGFkbyBwdWVkZSBlc3RhciBpbmZsdWlkYSBwb3IgbGEgZGUgc3VzIGVzdGFkb3MgdmVjaW5vcy4NCg0KKiBJbmNvcnBvcmEgbG9zIGVmZWN0b3MgZGVsIGVudG9ybm86IGFsIGluY2x1aXIgZWwgbGFnLmJ1c2luZXNzX2FjdGl2aXR5LCBjb25zaWRlcmEgcXVlIGxhIGFjdGl2aWRhZCBlbXByZXNhcmlhbCBlbiBsb3MgZXN0YWRvcyB2ZWNpbm9zIHRhbWJpw6luIGFmZWN0YSBsYXMgZGVjaXNpb25lcyBkZSBpbnZlcnNpw7NuLg0KDQoqIE1hbnRlbmltaWVudG8gZGVsIGFqdXN0ZSBlc3RhZMOtc3RpY286IGF1bnF1ZSBlbCAqbW9kZWxvIGMqIHR1dm8gZWwgQUlDIG3DoXMgYmFqbywgZWwgKm1vZGVsbyBkKiBjb25zZXJ2YSB1biBhanVzdGUgY29tcGV0aXRpdm8gKEFJQyA9IDY3MyksIGNvbiB0b2RvcyBsb3MgZWZlY3RvcyByZWxldmFudGVzIGluY2x1aWRvcy4NCg0KKiBJbnRlcnByZXRhY2nDs24gbcOhcyBhbXBsaWEgeSBhZGVjdWFkYSBhbCBlbnRvcm8gZGUgZXN0dWRpbzogcGVybWl0ZSBlbnRlbmRlciBubyBzb2xvIGxvcyBlZmVjdG9zIGRpcmVjdG9zLCBzaW5vIHRhbWJpw6luIGxvcyBlZmVjdG9zIGVzcGFjaWFsZXMgaW5kaXJlY3RvcywgbG8gcXVlIGVzIGNsYXZlIHBhcmEgZGVjaXNpb25lcyBkZSBwb2zDrXRpY2EgZWNvbsOzbWljYSByZWdpb25hbC4gIA0KDQoNCiMgKipSZWZlcmVuY2lhcyoqDQoNCldoYXQgaXMgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcz8gDQpodHRwczovL3d3dy5pYm0uY29tL3RvcGljcy9leHBsb3JhdG9yeS1kYXRhLWFuYWx5c2lzDQoNCkV4cGxvcmF0b3J5IFNwYXRpYWwgRGF0YSBBbmFseXNpcw0KaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dlb3N0YW4vdmlnbmV0dGVzL21lYXN1cmluZy1zYS5odG1sDQoNCg==