AD3003B Analítica Prescriptiva

Módulo 1 – Analítica Espacial de Datos

Febrero – Junio 2025

Actividad 1: Análisis espacial del turismo en México

Análisis previo

1) Brevemente, describir con sus propias palabras qué es un ESDA y cuál es su principal propósito en el proceso de analítica de datos.

EL ESDA por sus siglas en inglés o análisis exploratorio de datos espaciales, es un conjunto de herramientas y técnicas que se utilizan para poder análizar las tendencias y patrones de datos espaciales. Como principal objetivo, se busca indentificar estructuras, tendencias, concentraciones o irregularidades en la distribución de mis datos y a partir de ello, poder otorgar recomendacioes de valor dependiendo las necesidades.

2) Brevemente, describir con sus propias palabras el concepto de autocorrelación espacial así como 1-2 ejemplos relacionados con dicho concepto.

La autocorrelación espacial me indica qué tan probable es que se sigan las tendencias de mi vecino más cercano.

  • Ejemplo 1: La inversión extranjera que hay en un estado vecino, en caso de tener autocorrelación espacial positiva relevante y significativa, es similar en los estados aledaños. (Estados del norte poseen una alta inversión extranjera)

  • Ejemplo 2: La distribución de los precios de vivienda que hay en una colonia, es similar al de una colonia aledaña en caso de tener autocorrelación espacial positiva y significante. (En San Pedro, las colonias tinen precios de vivienda altos)

Análisis estadístico

3) Con base en el archivo de datos asignado realizar selección de variables y elaborar ESDA que incluye:

a) Estadísticos Descripitvos (Global y Regional).

Cargar librerías necesarias

library(readxl)     # Para leer archivos Excel
library(dplyr)      # Manipulación de datos
library(ggplot2)  
library(readxl)
library(scales)  # Para formatear números en el eje y (opcional)
library(sf)
#install.packages("sf")
#install.packages("tmap")
#install.packages("spdep")
library(tmap)
library(tmaptools)
library(spdep)

Base de datos

df<- read_excel("C:\\Users\\LuisD\\Documents\\OCTAVO SEMESTRE\\TURISMO MONTERREY\\tourism_state_data.xlsx")
View(df)
head(df)
## # A tibble: 6 × 18
##   state      year state_id tourism_gdp crime_rate college_education unemployment
##   <chr>     <dbl>    <dbl>       <dbl>      <dbl>             <dbl>        <dbl>
## 1 Aguascal…  2006     1057      11995.       2.32            0.164          0.05
## 2 Baja Cal…  2006     2304      54372.      15.5             0.181          0.03
## 3 Baja Cal…  2006     2327      24238.       4.54            0.191          0.02
## 4 Campeche   2006     1086      13032.       4.19            0.154          0.01
## 5 Chiapas    2006     1182      22730.      11.6             0.0875         0.04
## 6 Chihuahua  2006      888      37096.      19.4             0.153          0.04
## # ℹ 11 more variables: employment <dbl>, business_activity <dbl>,
## #   real_wage <dbl>, pop_density <dbl>, good_governance <dbl>,
## #   ratio_public_investment <dbl>, exchange_rate <dbl>, inpc <dbl>,
## #   border_distance <dbl>, region...17 <chr>, region...18 <dbl>

Analizamos la estructura general de los datos

summary(df)
##     state                year         state_id     tourism_gdp    
##  Length:544         Min.   :2006   Min.   : 888   Min.   :  6240  
##  Class :character   1st Qu.:2010   1st Qu.:1047   1st Qu.: 22685  
##  Mode  :character   Median :2014   Median :1081   Median : 32482  
##                     Mean   :2014   Mean   :1219   Mean   : 56520  
##                     3rd Qu.:2018   3rd Qu.:1118   3rd Qu.: 59014  
##                     Max.   :2022   Max.   :2357   Max.   :472642  
##    crime_rate      college_education  unemployment       employment    
##  Min.   :  1.710   Min.   :0.08751   Min.   :0.01000   Min.   :0.8900  
##  1st Qu.:  8.107   1st Qu.:0.16703   1st Qu.:0.03000   1st Qu.:0.9500  
##  Median : 13.880   Median :0.20304   Median :0.04000   Median :0.9700  
##  Mean   : 22.163   Mean   :0.21106   Mean   :0.04251   Mean   :0.9639  
##  3rd Qu.: 26.314   3rd Qu.:0.25085   3rd Qu.:0.05000   3rd Qu.:0.9754  
##  Max.   :181.510   Max.   :0.43761   Max.   :0.10000   Max.   :0.9928  
##  business_activity   real_wage      pop_density      good_governance  
##  Min.   :-2.980    Min.   :239.3   Min.   :   7.74   Min.   :  0.000  
##  1st Qu.:-2.260    1st Qu.:282.5   1st Qu.:  39.56   1st Qu.:  0.180  
##  Median :-2.070    Median :306.2   Median :  61.77   Median :  0.500  
##  Mean   :-1.757    Mean   :314.9   Mean   : 299.46   Mean   :  2.362  
##  3rd Qu.:-1.768    3rd Qu.:335.4   3rd Qu.: 150.46   3rd Qu.:  1.350  
##  Max.   : 2.470    Max.   :481.7   Max.   :6211.45   Max.   :200.020  
##  ratio_public_investment exchange_rate        inpc        border_distance  
##  Min.   :0.000000        Min.   :10.85   Min.   : 62.69   Min.   :   8.83  
##  1st Qu.:0.000000        1st Qu.:12.87   1st Qu.: 74.93   1st Qu.: 613.26  
##  Median :0.000000        Median :14.51   Median : 87.19   Median : 751.64  
##  Mean   :0.005736        Mean   :15.91   Mean   : 89.08   Mean   : 704.92  
##  3rd Qu.:0.010000        3rd Qu.:19.47   3rd Qu.:103.02   3rd Qu.: 875.76  
##  Max.   :0.067644        Max.   :20.52   Max.   :126.48   Max.   :1252.66  
##  region...17         region...18   
##  Length:544         Min.   :1.000  
##  Class :character   1st Qu.:2.000  
##  Mode  :character   Median :3.000  
##                     Mean   :3.188  
##                     3rd Qu.:4.250  
##                     Max.   :5.000

##Estadisticos Descriptivos

Dispersión nacional

####Evolución de turismo nacional

# Agrupar por año y sumar tourism_gdp
df_resumen <- df %>%
  group_by(year) %>%
  summarise(total_tourism_gdp = sum(tourism_gdp, na.rm = TRUE))

# Crear la gráfica de línea mejorada
ggplot(df_resumen, aes(x = year, y = total_tourism_gdp)) +
  geom_line(color = "blue", size = 1) +
  geom_point(color = "red", size = 3) +
  scale_x_continuous(breaks = seq(min(df_resumen$year), max(df_resumen$year), by = 1)) +
  labs(title = "Ganancias por Turismo por Año",
       x = "Año",
       y = "Ganancias") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

Evolución de crimen nacional

# Agrupar por año y calcular el promedio de crime_rate
df_resumen <- df %>%
  group_by(year) %>%
  summarise(avg_crime_rate = mean(crime_rate, na.rm = TRUE))

# Crear la gráfica de línea mejorada
ggplot(df_resumen, aes(x = year, y = avg_crime_rate)) +
  geom_line(color = "blue", size = 1) +
  geom_point(color = "red", size = 3) +
  scale_x_continuous(breaks = seq(min(df_resumen$year), max(df_resumen$year), by = 1)) +
  labs(title = "Promedio Anual de crimen por 100,000 habitantes",
       x = "Año",
       y = "Promedio de crimen") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

# Agrupar por año y calcular el promedio de real_wage
df_resumen_real_wage <- df %>%
  group_by(year) %>%
  summarise(avg_real_wage = mean(real_wage, na.rm = TRUE))

# Crear la gráfica de línea para real_wage
ggplot(df_resumen_real_wage, aes(x = year, y = avg_real_wage)) +
  geom_line(color = "blue", size = 1) +
  geom_point(color = "red", size = 3) +
  scale_x_continuous(breaks = seq(min(df_resumen_real_wage$year),
                                  max(df_resumen_real_wage$year), by = 1)) +
  labs(title = "Promedio Nacional de sueldo por Año",
       x = "Año",
       y = "Sueldo") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

# Agrupar por año y calcular el promedio de good_governance
df_resumen_good_governance <- df %>%
  group_by(year) %>%
  summarise(avg_good_governance = mean(good_governance, na.rm = TRUE))

# Crear la gráfica de línea para good_governance
ggplot(df_resumen_good_governance, aes(x = year, y = avg_good_governance)) +
  geom_line(color = "blue", size = 1) +
  geom_point(color = "red", size = 3) +
  scale_x_continuous(breaks = seq(min(df_resumen_good_governance$year),
                                  max(df_resumen_good_governance$year), by = 1)) +
  labs(title = "Promedio Nacional de buena governanza por Año",
       x = "Año",
       y = "Buena governanza") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

### Dispersión regional

# 1. Renombrar la variable "region...17" a "region"
df <- df %>% 
rename(region = `region...17`)

2. Promedio de tourism_gdp por región

df_region_tourism_gdp <- df %>%
  group_by(region) %>%
  summarise(avg_tourism_gdp = mean(tourism_gdp, na.rm = TRUE)) %>%
  arrange(desc(avg_tourism_gdp))

# Gráfico de barras para tourism_gdp
ggplot(df_region_tourism_gdp, aes(x = reorder(region, -avg_tourism_gdp), y = avg_tourism_gdp, fill = region)) +
  geom_bar(stat = "identity") +
  labs(title = "Promedio de Tourism GDP por Región",
       x = "Región",
       y = "Promedio Tourism GDP") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

#### 3. Promedio de crime_rate por región

df_region_crime_rate <- df %>%
  group_by(region) %>%
  summarise(avg_crime_rate = mean(crime_rate, na.rm = TRUE)) %>%
  arrange(desc(avg_crime_rate))

# Gráfico de barras para crime_rate
ggplot(df_region_crime_rate, aes(x = reorder(region, -avg_crime_rate), y = avg_crime_rate, fill = region)) +
  geom_bar(stat = "identity") +
  labs(title = "Promedio de Crime Rate por Región",
       x = "Región",
       y = "Promedio Crime Rate") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

4. Promedio de good_governance por región

df_region_good_governance <- df %>%
  group_by(region) %>%
  summarise(avg_good_governance = mean(good_governance, na.rm = TRUE)) %>%
  arrange(desc(avg_good_governance))

# Gráfico de barras para good_governance
ggplot(df_region_good_governance, aes(x = reorder(region, -avg_good_governance), y = avg_good_governance, fill = region)) +
  geom_bar(stat = "identity") +
  labs(title = "Promedio de Good Governance por Región",
       x = "Región",
       y = "Promedio Good Governance") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

#### 5. Agrupar por región y calcular el promedio de real_wage, ordenando de mayor a menor

df_region_real_wage <- df %>%
  group_by(region) %>%
  summarise(avg_real_wage = mean(real_wage, na.rm = TRUE)) %>%
  arrange(desc(avg_real_wage))

# 5. Crear el gráfico de barras con las regiones ordenadas
ggplot(df_region_real_wage, aes(x = reorder(region, -avg_real_wage), y = avg_real_wage, fill = region)) +
  geom_bar(stat = "identity") +
  labs(title = "Promedio de Real Wage por Región",
       x = "Región",
       y = "Promedio Real Wage") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

### Dispersión estatal

tourism_gdp

# Agrupar por estado y calcular el promedio de tourism_gdp
df_state_tourism_gdp <- df %>%
  group_by(state) %>%
  summarise(avg_tourism_gdp = mean(tourism_gdp, na.rm = TRUE))

# Seleccionar el top 10 de estados con mayor promedio de tourism_gdp
df_top10_tourism_gdp <- df_state_tourism_gdp %>%
  slice_max(order_by = avg_tourism_gdp, n = 10)

# Gráfico de barras para tourism_gdp (Top 10)
ggplot(df_top10_tourism_gdp, aes(x = reorder(state, -avg_tourism_gdp), y = avg_tourism_gdp, fill = state)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 10 Estados por Promedio Tourism GDP",
       x = "Estado",
       y = "Promedio Tourism GDP") +
  scale_y_continuous(labels = comma) +  # Opcional: formatea los números con comas
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

crime_rate

# Agrupar por estado y calcular el promedio de crime_rate
df_state_crime_rate <- df %>%
  group_by(state) %>%
  summarise(avg_crime_rate = mean(crime_rate, na.rm = TRUE))

# Seleccionar el top 10 de estados con mayor promedio de crime_rate
df_top10_crime_rate <- df_state_crime_rate %>%
  slice_max(order_by = avg_crime_rate, n = 10)

# Gráfico de barras para crime_rate (Top 10)
ggplot(df_top10_crime_rate, aes(x = reorder(state, -avg_crime_rate), y = avg_crime_rate, fill = state)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 10 Estados por Promedio Crime Rate",
       x = "Estado",
       y = "Promedio Crime Rate") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

Good_governance

# Agrupar por estado y calcular el promedio de good_governance
df_state_good_governance <- df %>%
  group_by(state) %>%
  summarise(avg_good_governance = mean(good_governance, na.rm = TRUE))

# Seleccionar el top 10 de estados con mayor promedio de good_governance
df_top10_good_governance <- df_state_good_governance %>%
  slice_max(order_by = avg_good_governance, n = 10)

# Gráfico de barras para good_governance (Top 10)
ggplot(df_top10_good_governance, aes(x = reorder(state, -avg_good_governance), y = avg_good_governance, fill = state)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 10 Estados por Promedio Good Governance",
       x = "Estado",
       y = "Promedio Good Governance") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

real_wage

# Agrupar por estado y calcular el promedio de real_wage
df_state_real_wage <- df %>%
  group_by(state) %>%
  summarise(avg_real_wage = mean(real_wage, na.rm = TRUE))

# Seleccionar el top 10 de estados con mayor promedio de real_wage
df_top10_real_wage <- df_state_real_wage %>%
  slice_max(order_by = avg_real_wage, n = 10)

# Gráfico de barras para real_wage (Top 10)
ggplot(df_top10_real_wage, aes(x = reorder(state, -avg_real_wage), y = avg_real_wage, fill = state)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 10 Estados por Promedio Real Wage",
       x = "Estado",
       y = "Promedio Real Wage") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

Estadísticos de Dispersión (Global y Regional).

Dispersión nacional

options(scipen = 999)  # Evita notación científica

# Crear el boxplot de tourism_gdp por año
ggplot(df, aes(x = factor(year), y = tourism_gdp)) +
  geom_boxplot(fill = "skyblue", color = "darkblue") +
  labs(title = "Distribución de Tourism GDP a Nivel Nacional por Año",
       x = "Año",
       y = "Tourism GDP") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(df, aes(x = factor(year), y = crime_rate)) +
  geom_boxplot(fill = "tomato", color = "darkred") +
  labs(title = "Distribución de Crime Rate a Nivel Nacional por Año",
       x = "Año",
       y = "Crime Rate") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(df, aes(x = factor(year), y = real_wage)) +
  geom_boxplot(fill = "lightgreen", color = "darkgreen") +
  labs(title = "Distribución de Real Wage a Nivel Nacional por Año",
       x = "Año",
       y = "Real Wage") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),
        axis.text.x = element_text(angle = 45, hjust = 1))

ggplot(df, aes(x = factor(year), y = good_governance)) +
  # Quitar símbolo de outliers
  geom_boxplot(fill = "plum", color = "purple", outlier.shape = NA) +
  labs(title = "Distribución de Good Governance a Nivel Nacional por Año (Con Límite)",
       x = "Año",
       y = "Good Governance") +
  # Limitar el rango del eje y
  coord_cartesian(ylim = c(0, 25)) +  # Ajusta (0, 10) a tu rango preferido
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Dispersión estatal

library(scales)  # Para formatear números, si lo requieres

options(scipen = 999)  # Evita la notación científica

# 1. Calcular el promedio de tourism_gdp por estado y seleccionar el top 10
df_state_tourism <- df %>%
  group_by(state) %>%
  summarise(avg_tourism_gdp = mean(tourism_gdp, na.rm = TRUE)) %>%
  slice_max(order_by = avg_tourism_gdp, n = 10)

# 2. Filtrar el dataframe original para conservar solo los estados del top 10
top_states_tourism <- df_state_tourism$state
df_top_tourism <- df %>% filter(state %in% top_states_tourism)

# 3. Generar el boxplot de tourism_gdp para los top 10 estados
ggplot(df_top_tourism, aes(x = reorder(state, tourism_gdp, FUN = median, na.rm = TRUE), 
                           y = tourism_gdp, fill = state)) +
  geom_boxplot() +
  labs(title = "Boxplot de Tourism GDP para Top 10 Estados",
       x = "Estado",
       y = "Tourism GDP") +
  scale_y_continuous(labels = comma) +  # Opcional: formatea los números del eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

# 1. Calcular el promedio de crime_rate por estado y seleccionar el top 10
df_state_crime <- df %>%
  group_by(state) %>%
  summarise(avg_crime_rate = mean(crime_rate, na.rm = TRUE)) %>%
  slice_max(order_by = avg_crime_rate, n = 10)

# 2. Filtrar el dataframe original para conservar solo los estados del top 10
top_states_crime <- df_state_crime$state
df_top_crime <- df %>% filter(state %in% top_states_crime)

# 3. Generar el boxplot de crime_rate para los top 10 estados
ggplot(df_top_crime, aes(x = reorder(state, crime_rate, FUN = median, na.rm = TRUE), 
                         y = crime_rate, fill = state)) +
  geom_boxplot() +
  labs(title = "Boxplot de Crime Rate para Top 10 Estados",
       x = "Estado",
       y = "Crime Rate") +
  scale_y_continuous(labels = comma) +  # Opcional: formatea los números del eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

# 1. Calcular el promedio de good_governance por estado y seleccionar el top 10
df_state_governance <- df %>%
  group_by(state) %>%
  summarise(avg_good_governance = mean(good_governance, na.rm = TRUE)) %>%
  slice_max(order_by = avg_good_governance, n = 10)

# 2. Filtrar el dataframe original para conservar solo los estados del top 10
top_states_governance <- df_state_governance$state
df_top_governance <- df %>% filter(state %in% top_states_governance)

# 3. Generar el boxplot de good_governance para los top 10 estados
ggplot(df_top_governance, aes(x = reorder(state, good_governance, FUN = median, na.rm = TRUE), 
                              y = good_governance, fill = state)) +
  geom_boxplot() +
  labs(title = "Boxplot de Good Governance para Top 10 Estados",
       x = "Estado",
       y = "Good Governance") +
  scale_y_continuous(labels = comma) +  # Opcional: formatea los números del eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

# 1. Calcular el promedio de real_wage por estado y seleccionar el top 10
df_state_realwage <- df %>%
  group_by(state) %>%
  summarise(avg_real_wage = mean(real_wage, na.rm = TRUE)) %>%
  slice_max(order_by = avg_real_wage, n = 10)

# 2. Filtrar el dataframe original para conservar solo los estados del top 10
top_states_realwage <- df_state_realwage$state
df_top_realwage <- df %>% filter(state %in% top_states_realwage)

# 3. Generar el boxplot de real_wage para los top 10 estados
ggplot(df_top_realwage, aes(x = reorder(state, real_wage, FUN = median, na.rm = TRUE), 
                            y = real_wage, fill = state)) +
  geom_boxplot() +
  labs(title = "Boxplot de Real Wage para Top 10 Estados",
       x = "Estado",
       y = "Real Wage") +
  scale_y_continuous(labels = comma) +  # Opcional: formatea los números del eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

Visualizar la distribución espacial de las variables usando mapas

Leer archivo mapas

# Leer el archivo .shp
estados_mx <- st_read("C:\\Users\\LuisD\\Documents\\OCTAVO SEMESTRE\\TURISMO MONTERREY\\mx_spatial_data\\mx_spatial_data\\mx_maps\\mx_states\\mexlatlong.shp")
## Reading layer `mexlatlong' from data source 
##   `C:\Users\LuisD\Documents\OCTAVO SEMESTRE\TURISMO MONTERREY\mx_spatial_data\mx_spatial_data\mx_maps\mx_states\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
## Geodetic CRS:  WGS 84
names(estados_mx)
##  [1] "OBJECTID"   "FIPS_ADMIN" "GMI_ADMIN"  "ADMIN_NAME" "FIPS_CNTRY"
##  [6] "GMI_CNTRY"  "CNTRY_NAME" "POP_ADMIN"  "TYPE_ENG"   "TYPE_LOC"  
## [11] "SQKM"       "SQMI"       "COLOR_MAP"  "Shape_Leng" "Shape_Area"
## [16] "OBJECTID_1" "OBJECTID_2" "longitude"  "latitude"   "geometry"
head(estados_mx)
## Simple feature collection with 6 features and 19 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -109.4428 ymin: 22.21486 xmax: -97.1375 ymax: 31.78389
## Geodetic CRS:  WGS 84
##   OBJECTID FIPS_ADMIN GMI_ADMIN ADMIN_NAME FIPS_CNTRY GMI_CNTRY CNTRY_NAME
## 1      888       MX06   MEX-CHH  Chihuahua         MX       MEX     Mexico
## 2      933       MX07   MEX-CDZ   Coahuila         MX       MEX     Mexico
## 3      976       MX19   MEX-NLE Nuevo Leon         MX       MEX     Mexico
## 4      978       MX28   MEX-TML Tamaulipas         MX       MEX     Mexico
## 5      998       MX25   MEX-SIN    Sinaloa         MX       MEX     Mexico
## 6     1004       MX10   MEX-DRN    Durango         MX       MEX     Mexico
##   POP_ADMIN TYPE_ENG TYPE_LOC      SQKM     SQMI COLOR_MAP Shape_Leng
## 1   2656214    State   Estado 247935.02 95727.70        12   22.60928
## 2   2145539    State   Estado 150843.95 58240.87         2   18.99309
## 3   3370912    State   Estado  65173.05 25163.31         3   15.42617
## 4   2272724    State   Estado  79502.24 30695.81        11   18.02314
## 5   2397706    State   Estado  57638.85 22254.36         5   16.46605
## 6   1467826    State   Estado 120674.60 46592.46         4   17.51290
##   Shape_Area OBJECTID_1 OBJECTID_2  longitude latitude
## 1  22.890985          1        888 -106.44431 28.80303
## 2  13.733655          2        933 -102.03356 27.30662
## 3   5.844668          3        976  -99.83125 25.60105
## 4   7.056563          4        978  -98.62181 24.29819
## 5   5.145524          5        998 -107.48280 25.02179
## 6  10.764853          6       1004 -104.92001 24.93519
##                         geometry
## 1 MULTIPOLYGON (((-103.6309 2...
## 2 MULTIPOLYGON (((-102.6669 2...
## 3 MULTIPOLYGON (((-99.7139 27...
## 4 MULTIPOLYGON (((-98.61609 2...
## 5 MULTIPOLYGON (((-108.3942 2...
## 6 MULTIPOLYGON (((-104.3114 2...

Vista rápida

plot(st_geometry(estados_mx))

Union mapa con excel

# Unir shapefile con los datos
estados_datos <- left_join(estados_mx, df, by = c("ADMIN_NAME" = "state"))

# Crear matriz de vecinos y pesos
vecinos <- poly2nb(estados_datos)
pesos <- nb2listw(vecinos, style = "W")

Mapas

library(tmap)

# Modo estático (puedes cambiarlo a "view" si quieres mapas interactivos)
tmap_mode("plot")

# Mapa 1: tourism_gdp
tm_shape(estados_datos) +
  tm_polygons("tourism_gdp",
              palette = "Blues",
              title = "PIB Turístico") +
  tm_layout(main.title = "Distribución Espacial del PIB Turístico",
            legend.outside = TRUE)

# Mapa 2: crime_rate
tm_shape(estados_datos) +
  tm_polygons("crime_rate",
              palette = "Reds",
              title = "Índice de Criminalidad") +
  tm_layout(main.title = "Distribución Espacial del Crimen",
            legend.outside = TRUE)

# Mapa 3: good_governance
tm_shape(estados_datos) +
  tm_polygons("good_governance",
              palette = "Greens",
              title = "Índice de Buen Gobierno") +
  tm_layout(main.title = "Distribución Espacial del Buen Gobierno",
            legend.outside = TRUE)

# Mapa 4: real_wage
tm_shape(estados_datos) +
  tm_polygons("real_wage",
              palette = "Purples",
              title = "Salario Real") +
  tm_layout(main.title = "Distribución Espacial del Salario Real",
            legend.outside = TRUE)

Matrices de conectividad

Matriz de conectividad binaria

Matriz de pesos

Indice Global de Moran (Detectar la presencia de autocorrelación espacial Global)

PIB Turístico

library(spdep)
estados_validos <- estados_datos[!is.na(estados_datos$tourism_gdp), ]
estados_validos <- estados_datos[!is.na(estados_datos$real_wage), ]
estados_validos <- estados_datos[!is.na(estados_datos$crime_rate), ]
estados_validos <- estados_datos[!is.na(estados_datos$good_governance), ]

vecinos_validos <- poly2nb(estados_validos)
pesos_validos <- nb2listw(vecinos_validos, style = "W")

moran_gdp_turismo <- moran.test(estados_validos$tourism_gdp, pesos_validos, zero.policy = TRUE)
moran_gdp_turismo
## 
##  Moran I test under randomisation
## 
## data:  estados_validos$tourism_gdp  
## weights: pesos_validos    
## 
## Moran I statistic standard deviate = 2.8037, p-value = 0.002526
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##     0.01580368341    -0.00190114068     0.00003987752

En este primer caso para la variable PIB de turismo podemos observar dos cosas: - El Moran I Statistic es de 0.015 por lo que es un valor relativamente bajo - El P value es de 0.0025 por lo que existe significancia estadística Es decir, hay cierta agrupación estadísticamente significativa de estados con PIB turístico similar, pero esta agrupación es muy débil.

Crímen

moran_crimen <- moran.test(estados_validos$crime_rate, pesos_validos, zero.policy = TRUE)
moran_crimen
## 
##  Moran I test under randomisation
## 
## data:  estados_validos$crime_rate  
## weights: pesos_validos    
## 
## Moran I statistic standard deviate = 28.098, p-value <
## 0.00000000000000022
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##     0.17473678872    -0.00190114068     0.00003952118

Para la variable de crimen contamos con un valor de Moran de 0.1747 el cual es más alto que el del PIB y su P-value es extremadamente bajo por lo que existe significancia estadística, es decir, los estados con altas tasas de criminalidad tienden a estar cerca de otros con tasas similares

Buen Gobierno

moran_gobierno <- moran.test(estados_validos$good_governance, pesos_validos, zero.policy = TRUE)
moran_gobierno
## 
##  Moran I test under randomisation
## 
## data:  estados_validos$good_governance  
## weights: pesos_validos    
## 
## Moran I statistic standard deviate = 3.6914, p-value = 0.0001115
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##     0.01433605218    -0.00190114068     0.00001934785

En la variable de Buen Gobierno contamos nuevamente con un valor del Moran Statistic bajo (0.0143) y un P-value también bajo (<0.05) por lo que existe una autocorrelación débil pero significativa, lo cual sugiere que los estados con mejor (o peor) gobernanza tienden a estar agrupados, pero el patrón no es tan marcado como para ser observado a simple vista

Salario real

moran_salario <- moran.test(estados_validos$real_wage, pesos_validos, zero.policy = TRUE)
moran_salario
## 
##  Moran I test under randomisation
## 
## data:  estados_validos$real_wage  
## weights: pesos_validos    
## 
## Moran I statistic standard deviate = 22.319, p-value <
## 0.00000000000000022
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##     0.13930452561    -0.00190114068     0.00004002578

Finalmente para el caso de los salarios reales contamos con un valor del Moral Statistic de 0.139 y un P-value extremadamente bajo por lo que si existe una autocorrelación positiva esstadísticamente significativa por lo que podemos decir que hay una tendencia regional en los niveles salariales reales en donde los estados con sueldos altos cerca de otros con sueldos altos

LISA (Detectar la presencia de autocorrelación espacial local)

Para este caso únicamente seleccionamos las variables “crime_rate” y “real_wage” pues fueron las que presentaron los valores más altos en el Moran I Statistic además de un P-value extremadamente bajos

Crime Rate

estados_validos$local_moran_crimen <- local_moran_crimen[,1]
estados_validos$pval_moran_crimen <- local_moran_crimen[,5]
tm_shape(estados_validos) +
  tm_polygons("local_moran_crimen",
              palette = "RdBu",
              title = "Local Moran I - Crime Rate") +
  tm_layout(main.title = "Clusters Espaciales del Crime Rate",
            legend.outside = TRUE)
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the visual variable `fill` namely 'palette' (rename to 'values') to fill.scale
## = tm_scale(<HERE>).
## [v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(main.title = )`
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "RdBu" is named
## "brewer.rd_bu"
## Multiple palettes called "rd_bu" found: "brewer.rd_bu", "matplotlib.rd_bu". The first one, "brewer.rd_bu", is returned.
## 
## [scale] tm_polygons:() the data variable assigned to 'fill' contains positive and negative values, so midpoint is set to 0. Set 'midpoint = NA' in 'fill.scale = tm_scale_intervals(<HERE>)' to use all visual values (e.g. colors)

Podemos observar claramente como los clusters se agrupan por región norte que es donde se concentra la mayor parte del crimen, una menor concentración en los estados de color café y vuelve a subir pero no tanto en la región centro-sur del país

Salario Real

estados_validos$local_moran_salarios <- local_moran_salarios[,1]
estados_validos$pval_moran_salarios <- local_moran_salarios[,5]
tm_shape(estados_validos) +
  tm_polygons("local_moran_salarios",
              palette = "RdBu",
              title = "Local Moran I - Salarios") +
  tm_layout(main.title = "Clusters Espaciales de Salarios",
            legend.outside = TRUE)
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the visual variable `fill` namely 'palette' (rename to 'values') to fill.scale
## = tm_scale(<HERE>).
## [v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(main.title = )`
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "RdBu" is named
## "brewer.rd_bu"
## Multiple palettes called "rd_bu" found: "brewer.rd_bu", "matplotlib.rd_bu". The first one, "brewer.rd_bu", is returned.
## 
## [scale] tm_polygons:() the data variable assigned to 'fill' contains positive and negative values, so midpoint is set to 0. Set 'midpoint = NA' in 'fill.scale = tm_scale_intervals(<HERE>)' to use all visual values (e.g. colors)

En el caso para los clusters de salarios, podemos ver una concentración de salarios altos bastante marcada en el norte del país con los estados de Nuevo León y Tamaulipas así como con Sinaloa y BCS, de la misma manera se vuelven a agrupar Chihuahua y Sonora, podemos ver que en este mapa los clusters son mas claros debido a la variación de los salarios que es mayor a la presentada con las tasas de criminalidad

LS0tDQp0aXRsZTogIkFDVCAxLiBBbmFsaXNpcyBkZSB0dXJpc21vIGVuIE1leGljbyINCmF1dGhvcjogIkRpZWdvIEFsZWphbmRybyBQw6lyZXogQ2lzbmVyb3MgLSBBMDEyNzU1NjENCg0KICAgICAgICAgIEx1aXMgRGF2aWQgU2FuY2jDqXogQ2FzdGlsbG8gLSBBMDEyNzU2NTUNCiAgICAgICAgICANCiAgICAgICAgICBBZHJpw6FuIFF1ZXphZGEgUm9kcsOtZ3VleiAtIEEwMTI1MjUzMQ0KICAgICAgICAgIA0KICAgICAgICAgIEphaW1lIEVybmVzdG8gQWd1aWxhciBUcmVqbyAtIEEwMTI3NTg1OSINCmRhdGU6ICIyMDI1LTA0LTAyIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQotLS0NCiMgQUQzMDAzQiBBbmFsw610aWNhIFByZXNjcmlwdGl2YQ0KDQojIE3Ds2R1bG8gMSDigJMgQW5hbMOtdGljYSBFc3BhY2lhbCBkZSBEYXRvcw0KDQojIEZlYnJlcm8g4oCTIEp1bmlvIDIwMjUNCg0KIyBBY3RpdmlkYWQgMTogQW7DoWxpc2lzIGVzcGFjaWFsIGRlbCB0dXJpc21vIGVuIE3DqXhpY28NCg0KIyMgQW7DoWxpc2lzIHByZXZpbw0KDQoqKjEpIEJyZXZlbWVudGUsIGRlc2NyaWJpciBjb24gc3VzIHByb3BpYXMgcGFsYWJyYXMgcXXDqSBlcyB1biBFU0RBIHkgY3XDoWwgZXMgc3UgcHJpbmNpcGFsIHByb3DDs3NpdG8gZW4gZWwgcHJvY2VzbyBkZSBhbmFsw610aWNhIGRlIGRhdG9zLioqDQoNCkVMIEVTREEgcG9yIHN1cyBzaWdsYXMgZW4gaW5nbMOpcyBvIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgZXNwYWNpYWxlcywgZXMgdW4gY29uanVudG8gZGUgaGVycmFtaWVudGFzIHkgdMOpY25pY2FzIHF1ZSBzZSB1dGlsaXphbiBwYXJhIHBvZGVyIGFuw6FsaXphciBsYXMgdGVuZGVuY2lhcyB5IHBhdHJvbmVzIGRlIGRhdG9zIGVzcGFjaWFsZXMuIENvbW8gcHJpbmNpcGFsIG9iamV0aXZvLCBzZSBidXNjYSBpbmRlbnRpZmljYXIgZXN0cnVjdHVyYXMsIHRlbmRlbmNpYXMsIGNvbmNlbnRyYWNpb25lcyBvIGlycmVndWxhcmlkYWRlcyBlbiBsYSBkaXN0cmlidWNpw7NuIGRlIG1pcyBkYXRvcyB5IGEgcGFydGlyIGRlIGVsbG8sIHBvZGVyIG90b3JnYXIgcmVjb21lbmRhY2lvZXMgZGUgdmFsb3IgZGVwZW5kaWVuZG8gbGFzIG5lY2VzaWRhZGVzLiANCg0KKioyKSBCcmV2ZW1lbnRlLCBkZXNjcmliaXIgY29uIHN1cyBwcm9waWFzIHBhbGFicmFzIGVsIGNvbmNlcHRvIGRlIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgYXPDrSBjb21vIDEtMiBlamVtcGxvcyByZWxhY2lvbmFkb3MgY29uIGRpY2hvIGNvbmNlcHRvLioqDQoNCkxhIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgbWUgaW5kaWNhIHF1w6kgdGFuIHByb2JhYmxlIGVzIHF1ZSBzZSBzaWdhbiBsYXMgdGVuZGVuY2lhcyBkZSBtaSB2ZWNpbm8gbcOhcyBjZXJjYW5vLg0KDQotIEVqZW1wbG8gMTogTGEgaW52ZXJzacOzbiBleHRyYW5qZXJhIHF1ZSBoYXkgZW4gdW4gZXN0YWRvIHZlY2lubywgZW4gY2FzbyBkZSB0ZW5lciBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIHBvc2l0aXZhIHJlbGV2YW50ZSB5IHNpZ25pZmljYXRpdmEsIGVzIHNpbWlsYXIgZW4gbG9zIGVzdGFkb3MgYWxlZGHDsW9zLiAoRXN0YWRvcyBkZWwgbm9ydGUgcG9zZWVuIHVuYSBhbHRhIGludmVyc2nDs24gZXh0cmFuamVyYSkNCg0KLSBFamVtcGxvIDI6IExhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHByZWNpb3MgZGUgdml2aWVuZGEgcXVlIGhheSBlbiB1bmEgY29sb25pYSwgZXMgc2ltaWxhciBhbCBkZSB1bmEgY29sb25pYSBhbGVkYcOxYSBlbiBjYXNvIGRlIHRlbmVyIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgcG9zaXRpdmEgeSBzaWduaWZpY2FudGUuIChFbiBTYW4gUGVkcm8sIGxhcyBjb2xvbmlhcyB0aW5lbiBwcmVjaW9zIGRlIHZpdmllbmRhIGFsdG9zKQ0KDQojIyBBbsOhbGlzaXMgZXN0YWTDrXN0aWNvDQoNCioqMykgQ29uIGJhc2UgZW4gZWwgYXJjaGl2byBkZSBkYXRvcyBhc2lnbmFkbyByZWFsaXphciBzZWxlY2Npw7NuIGRlIHZhcmlhYmxlcyB5IGVsYWJvcmFyIEVTREEgcXVlIGluY2x1eWU6KioNCg0KIyMgYSkgRXN0YWTDrXN0aWNvcyBEZXNjcmlwaXR2b3MgKEdsb2JhbCB5IFJlZ2lvbmFsKS4gDQoNCiMjIyMgQ2FyZ2FyIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocmVhZHhsKSAgICAgIyBQYXJhIGxlZXIgYXJjaGl2b3MgRXhjZWwNCmxpYnJhcnkoZHBseXIpICAgICAgIyBNYW5pcHVsYWNpw7NuIGRlIGRhdG9zDQpsaWJyYXJ5KGdncGxvdDIpICANCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShzY2FsZXMpICAjIFBhcmEgZm9ybWF0ZWFyIG7Dum1lcm9zIGVuIGVsIGVqZSB5IChvcGNpb25hbCkNCmxpYnJhcnkoc2YpDQojaW5zdGFsbC5wYWNrYWdlcygic2YiKQ0KI2luc3RhbGwucGFja2FnZXMoInRtYXAiKQ0KI2luc3RhbGwucGFja2FnZXMoInNwZGVwIikNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkodG1hcHRvb2xzKQ0KbGlicmFyeShzcGRlcCkNCmBgYA0KDQojIyMjIEJhc2UgZGUgZGF0b3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZjwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcT0NUQVZPIFNFTUVTVFJFXFxUVVJJU01PIE1PTlRFUlJFWVxcdG91cmlzbV9zdGF0ZV9kYXRhLnhsc3giKQ0KVmlldyhkZikNCmhlYWQoZGYpDQpgYGANCg0KIyMjIyBBbmFsaXphbW9zIGxhIGVzdHJ1Y3R1cmEgZ2VuZXJhbCBkZSBsb3MgZGF0b3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzdW1tYXJ5KGRmKQ0KYGBgDQojI0VzdGFkaXN0aWNvcyBEZXNjcmlwdGl2b3MNCg0KIyMjIERpc3BlcnNpw7NuIG5hY2lvbmFsIA0KDQojIyMjRXZvbHVjacOzbiBkZSB0dXJpc21vIG5hY2lvbmFsDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZ3J1cGFyIHBvciBhw7FvIHkgc3VtYXIgdG91cmlzbV9nZHANCmRmX3Jlc3VtZW4gPC0gZGYgJT4lDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfdG91cmlzbV9nZHAgPSBzdW0odG91cmlzbV9nZHAsIG5hLnJtID0gVFJVRSkpDQoNCiMgQ3JlYXIgbGEgZ3LDoWZpY2EgZGUgbMOtbmVhIG1lam9yYWRhDQpnZ3Bsb3QoZGZfcmVzdW1lbiwgYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfdG91cmlzbV9nZHApKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKG1pbihkZl9yZXN1bWVuJHllYXIpLCBtYXgoZGZfcmVzdW1lbiR5ZWFyKSwgYnkgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIkdhbmFuY2lhcyBwb3IgVHVyaXNtbyBwb3IgQcOxbyIsDQogICAgICAgeCA9ICJBw7FvIiwNCiAgICAgICB5ID0gIkdhbmFuY2lhcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpDQpgYGANCg0KIyMjIyBFdm9sdWNpw7NuIGRlIGNyaW1lbiBuYWNpb25hbA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQWdydXBhciBwb3IgYcOxbyB5IGNhbGN1bGFyIGVsIHByb21lZGlvIGRlIGNyaW1lX3JhdGUNCmRmX3Jlc3VtZW4gPC0gZGYgJT4lDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICBzdW1tYXJpc2UoYXZnX2NyaW1lX3JhdGUgPSBtZWFuKGNyaW1lX3JhdGUsIG5hLnJtID0gVFJVRSkpDQoNCiMgQ3JlYXIgbGEgZ3LDoWZpY2EgZGUgbMOtbmVhIG1lam9yYWRhDQpnZ3Bsb3QoZGZfcmVzdW1lbiwgYWVzKHggPSB5ZWFyLCB5ID0gYXZnX2NyaW1lX3JhdGUpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKG1pbihkZl9yZXN1bWVuJHllYXIpLCBtYXgoZGZfcmVzdW1lbiR5ZWFyKSwgYnkgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlByb21lZGlvIEFudWFsIGRlIGNyaW1lbiBwb3IgMTAwLDAwMCBoYWJpdGFudGVzIiwNCiAgICAgICB4ID0gIkHDsW8iLA0KICAgICAgIHkgPSAiUHJvbWVkaW8gZGUgY3JpbWVuIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZ3J1cGFyIHBvciBhw7FvIHkgY2FsY3VsYXIgZWwgcHJvbWVkaW8gZGUgcmVhbF93YWdlDQpkZl9yZXN1bWVuX3JlYWxfd2FnZSA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcmlzZShhdmdfcmVhbF93YWdlID0gbWVhbihyZWFsX3dhZ2UsIG5hLnJtID0gVFJVRSkpDQoNCiMgQ3JlYXIgbGEgZ3LDoWZpY2EgZGUgbMOtbmVhIHBhcmEgcmVhbF93YWdlDQpnZ3Bsb3QoZGZfcmVzdW1lbl9yZWFsX3dhZ2UsIGFlcyh4ID0geWVhciwgeSA9IGF2Z19yZWFsX3dhZ2UpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKG1pbihkZl9yZXN1bWVuX3JlYWxfd2FnZSR5ZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoZGZfcmVzdW1lbl9yZWFsX3dhZ2UkeWVhciksIGJ5ID0gMSkpICsNCiAgbGFicyh0aXRsZSA9ICJQcm9tZWRpbyBOYWNpb25hbCBkZSBzdWVsZG8gcG9yIEHDsW8iLA0KICAgICAgIHggPSAiQcOxbyIsDQogICAgICAgeSA9ICJTdWVsZG8iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEFncnVwYXIgcG9yIGHDsW8geSBjYWxjdWxhciBlbCBwcm9tZWRpbyBkZSBnb29kX2dvdmVybmFuY2UNCmRmX3Jlc3VtZW5fZ29vZF9nb3Zlcm5hbmNlIDwtIGRmICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKGF2Z19nb29kX2dvdmVybmFuY2UgPSBtZWFuKGdvb2RfZ292ZXJuYW5jZSwgbmEucm0gPSBUUlVFKSkNCg0KIyBDcmVhciBsYSBncsOhZmljYSBkZSBsw61uZWEgcGFyYSBnb29kX2dvdmVybmFuY2UNCmdncGxvdChkZl9yZXN1bWVuX2dvb2RfZ292ZXJuYW5jZSwgYWVzKHggPSB5ZWFyLCB5ID0gYXZnX2dvb2RfZ292ZXJuYW5jZSkpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gInJlZCIsIHNpemUgPSAzKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEobWluKGRmX3Jlc3VtZW5fZ29vZF9nb3Zlcm5hbmNlJHllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChkZl9yZXN1bWVuX2dvb2RfZ292ZXJuYW5jZSR5ZWFyKSwgYnkgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlByb21lZGlvIE5hY2lvbmFsIGRlIGJ1ZW5hIGdvdmVybmFuemEgcG9yIEHDsW8iLA0KICAgICAgIHggPSAiQcOxbyIsDQogICAgICAgeSA9ICJCdWVuYSBnb3Zlcm5hbnphIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkNCg0KYGBgDQojIyMgRGlzcGVyc2nDs24gcmVnaW9uYWwNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgMS4gUmVub21icmFyIGxhIHZhcmlhYmxlICJyZWdpb24uLi4xNyIgYSAicmVnaW9uIg0KZGYgPC0gZGYgJT4lIA0KcmVuYW1lKHJlZ2lvbiA9IGByZWdpb24uLi4xN2ApDQpgYGANCg0KIyMjIyAyLiBQcm9tZWRpbyBkZSB0b3VyaXNtX2dkcCBwb3IgcmVnacOzbg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmX3JlZ2lvbl90b3VyaXNtX2dkcCA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKGF2Z190b3VyaXNtX2dkcCA9IG1lYW4odG91cmlzbV9nZHAsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoYXZnX3RvdXJpc21fZ2RwKSkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgcGFyYSB0b3VyaXNtX2dkcA0KZ2dwbG90KGRmX3JlZ2lvbl90b3VyaXNtX2dkcCwgYWVzKHggPSByZW9yZGVyKHJlZ2lvbiwgLWF2Z190b3VyaXNtX2dkcCksIHkgPSBhdmdfdG91cmlzbV9nZHAsIGZpbGwgPSByZWdpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSAiUHJvbWVkaW8gZGUgVG91cmlzbSBHRFAgcG9yIFJlZ2nDs24iLA0KICAgICAgIHggPSAiUmVnacOzbiIsDQogICAgICAgeSA9ICJQcm9tZWRpbyBUb3VyaXNtIEdEUCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpDQpgYGANCiMjIyMgMy4gUHJvbWVkaW8gZGUgY3JpbWVfcmF0ZSBwb3IgcmVnacOzbg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmX3JlZ2lvbl9jcmltZV9yYXRlIDwtIGRmICU+JQ0KICBncm91cF9ieShyZWdpb24pICU+JQ0KICBzdW1tYXJpc2UoYXZnX2NyaW1lX3JhdGUgPSBtZWFuKGNyaW1lX3JhdGUsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoYXZnX2NyaW1lX3JhdGUpKQ0KDQojIEdyw6FmaWNvIGRlIGJhcnJhcyBwYXJhIGNyaW1lX3JhdGUNCmdncGxvdChkZl9yZWdpb25fY3JpbWVfcmF0ZSwgYWVzKHggPSByZW9yZGVyKHJlZ2lvbiwgLWF2Z19jcmltZV9yYXRlKSwgeSA9IGF2Z19jcmltZV9yYXRlLCBmaWxsID0gcmVnaW9uKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlByb21lZGlvIGRlIENyaW1lIFJhdGUgcG9yIFJlZ2nDs24iLA0KICAgICAgIHggPSAiUmVnacOzbiIsDQogICAgICAgeSA9ICJQcm9tZWRpbyBDcmltZSBSYXRlIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSkNCmBgYA0KDQojIyMjIDQuIFByb21lZGlvIGRlIGdvb2RfZ292ZXJuYW5jZSBwb3IgcmVnacOzbg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmX3JlZ2lvbl9nb29kX2dvdmVybmFuY2UgPC0gZGYgJT4lDQogIGdyb3VwX2J5KHJlZ2lvbikgJT4lDQogIHN1bW1hcmlzZShhdmdfZ29vZF9nb3Zlcm5hbmNlID0gbWVhbihnb29kX2dvdmVybmFuY2UsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBhcnJhbmdlKGRlc2MoYXZnX2dvb2RfZ292ZXJuYW5jZSkpDQoNCiMgR3LDoWZpY28gZGUgYmFycmFzIHBhcmEgZ29vZF9nb3Zlcm5hbmNlDQpnZ3Bsb3QoZGZfcmVnaW9uX2dvb2RfZ292ZXJuYW5jZSwgYWVzKHggPSByZW9yZGVyKHJlZ2lvbiwgLWF2Z19nb29kX2dvdmVybmFuY2UpLCB5ID0gYXZnX2dvb2RfZ292ZXJuYW5jZSwgZmlsbCA9IHJlZ2lvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJQcm9tZWRpbyBkZSBHb29kIEdvdmVybmFuY2UgcG9yIFJlZ2nDs24iLA0KICAgICAgIHggPSAiUmVnacOzbiIsDQogICAgICAgeSA9ICJQcm9tZWRpbyBHb29kIEdvdmVybmFuY2UiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQojIyMjIDUuIEFncnVwYXIgcG9yIHJlZ2nDs24geSBjYWxjdWxhciBlbCBwcm9tZWRpbyBkZSByZWFsX3dhZ2UsIG9yZGVuYW5kbyBkZSBtYXlvciBhIG1lbm9yDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZfcmVnaW9uX3JlYWxfd2FnZSA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKGF2Z19yZWFsX3dhZ2UgPSBtZWFuKHJlYWxfd2FnZSwgbmEucm0gPSBUUlVFKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhhdmdfcmVhbF93YWdlKSkNCg0KIyA1LiBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMgY29uIGxhcyByZWdpb25lcyBvcmRlbmFkYXMNCmdncGxvdChkZl9yZWdpb25fcmVhbF93YWdlLCBhZXMoeCA9IHJlb3JkZXIocmVnaW9uLCAtYXZnX3JlYWxfd2FnZSksIHkgPSBhdmdfcmVhbF93YWdlLCBmaWxsID0gcmVnaW9uKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlByb21lZGlvIGRlIFJlYWwgV2FnZSBwb3IgUmVnacOzbiIsDQogICAgICAgeCA9ICJSZWdpw7NuIiwNCiAgICAgICB5ID0gIlByb21lZGlvIFJlYWwgV2FnZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpDQpgYGANCiMjIyBEaXNwZXJzacOzbiBlc3RhdGFsDQoNCiMjIyMgdG91cmlzbV9nZHANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEFncnVwYXIgcG9yIGVzdGFkbyB5IGNhbGN1bGFyIGVsIHByb21lZGlvIGRlIHRvdXJpc21fZ2RwDQpkZl9zdGF0ZV90b3VyaXNtX2dkcCA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoc3RhdGUpICU+JQ0KICBzdW1tYXJpc2UoYXZnX3RvdXJpc21fZ2RwID0gbWVhbih0b3VyaXNtX2dkcCwgbmEucm0gPSBUUlVFKSkNCg0KIyBTZWxlY2Npb25hciBlbCB0b3AgMTAgZGUgZXN0YWRvcyBjb24gbWF5b3IgcHJvbWVkaW8gZGUgdG91cmlzbV9nZHANCmRmX3RvcDEwX3RvdXJpc21fZ2RwIDwtIGRmX3N0YXRlX3RvdXJpc21fZ2RwICU+JQ0KICBzbGljZV9tYXgob3JkZXJfYnkgPSBhdmdfdG91cmlzbV9nZHAsIG4gPSAxMCkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgcGFyYSB0b3VyaXNtX2dkcCAoVG9wIDEwKQ0KZ2dwbG90KGRmX3RvcDEwX3RvdXJpc21fZ2RwLCBhZXMoeCA9IHJlb3JkZXIoc3RhdGUsIC1hdmdfdG91cmlzbV9nZHApLCB5ID0gYXZnX3RvdXJpc21fZ2RwLCBmaWxsID0gc3RhdGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDEwIEVzdGFkb3MgcG9yIFByb21lZGlvIFRvdXJpc20gR0RQIiwNCiAgICAgICB4ID0gIkVzdGFkbyIsDQogICAgICAgeSA9ICJQcm9tZWRpbyBUb3VyaXNtIEdEUCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArICAjIE9wY2lvbmFsOiBmb3JtYXRlYSBsb3MgbsO6bWVyb3MgY29uIGNvbWFzDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQoNCiMjIyMgY3JpbWVfcmF0ZQ0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQWdydXBhciBwb3IgZXN0YWRvIHkgY2FsY3VsYXIgZWwgcHJvbWVkaW8gZGUgY3JpbWVfcmF0ZQ0KZGZfc3RhdGVfY3JpbWVfcmF0ZSA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoc3RhdGUpICU+JQ0KICBzdW1tYXJpc2UoYXZnX2NyaW1lX3JhdGUgPSBtZWFuKGNyaW1lX3JhdGUsIG5hLnJtID0gVFJVRSkpDQoNCiMgU2VsZWNjaW9uYXIgZWwgdG9wIDEwIGRlIGVzdGFkb3MgY29uIG1heW9yIHByb21lZGlvIGRlIGNyaW1lX3JhdGUNCmRmX3RvcDEwX2NyaW1lX3JhdGUgPC0gZGZfc3RhdGVfY3JpbWVfcmF0ZSAlPiUNCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYXZnX2NyaW1lX3JhdGUsIG4gPSAxMCkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgcGFyYSBjcmltZV9yYXRlIChUb3AgMTApDQpnZ3Bsb3QoZGZfdG9wMTBfY3JpbWVfcmF0ZSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCAtYXZnX2NyaW1lX3JhdGUpLCB5ID0gYXZnX2NyaW1lX3JhdGUsIGZpbGwgPSBzdGF0ZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgRXN0YWRvcyBwb3IgUHJvbWVkaW8gQ3JpbWUgUmF0ZSIsDQogICAgICAgeCA9ICJFc3RhZG8iLA0KICAgICAgIHkgPSAiUHJvbWVkaW8gQ3JpbWUgUmF0ZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQoNCiMjIyMgR29vZF9nb3Zlcm5hbmNlDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZ3J1cGFyIHBvciBlc3RhZG8geSBjYWxjdWxhciBlbCBwcm9tZWRpbyBkZSBnb29kX2dvdmVybmFuY2UNCmRmX3N0YXRlX2dvb2RfZ292ZXJuYW5jZSA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoc3RhdGUpICU+JQ0KICBzdW1tYXJpc2UoYXZnX2dvb2RfZ292ZXJuYW5jZSA9IG1lYW4oZ29vZF9nb3Zlcm5hbmNlLCBuYS5ybSA9IFRSVUUpKQ0KDQojIFNlbGVjY2lvbmFyIGVsIHRvcCAxMCBkZSBlc3RhZG9zIGNvbiBtYXlvciBwcm9tZWRpbyBkZSBnb29kX2dvdmVybmFuY2UNCmRmX3RvcDEwX2dvb2RfZ292ZXJuYW5jZSA8LSBkZl9zdGF0ZV9nb29kX2dvdmVybmFuY2UgJT4lDQogIHNsaWNlX21heChvcmRlcl9ieSA9IGF2Z19nb29kX2dvdmVybmFuY2UsIG4gPSAxMCkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgcGFyYSBnb29kX2dvdmVybmFuY2UgKFRvcCAxMCkNCmdncGxvdChkZl90b3AxMF9nb29kX2dvdmVybmFuY2UsIGFlcyh4ID0gcmVvcmRlcihzdGF0ZSwgLWF2Z19nb29kX2dvdmVybmFuY2UpLCB5ID0gYXZnX2dvb2RfZ292ZXJuYW5jZSwgZmlsbCA9IHN0YXRlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCAxMCBFc3RhZG9zIHBvciBQcm9tZWRpbyBHb29kIEdvdmVybmFuY2UiLA0KICAgICAgIHggPSAiRXN0YWRvIiwNCiAgICAgICB5ID0gIlByb21lZGlvIEdvb2QgR292ZXJuYW5jZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQoNCiMjIyMgcmVhbF93YWdlDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZ3J1cGFyIHBvciBlc3RhZG8geSBjYWxjdWxhciBlbCBwcm9tZWRpbyBkZSByZWFsX3dhZ2UNCmRmX3N0YXRlX3JlYWxfd2FnZSA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoc3RhdGUpICU+JQ0KICBzdW1tYXJpc2UoYXZnX3JlYWxfd2FnZSA9IG1lYW4ocmVhbF93YWdlLCBuYS5ybSA9IFRSVUUpKQ0KDQojIFNlbGVjY2lvbmFyIGVsIHRvcCAxMCBkZSBlc3RhZG9zIGNvbiBtYXlvciBwcm9tZWRpbyBkZSByZWFsX3dhZ2UNCmRmX3RvcDEwX3JlYWxfd2FnZSA8LSBkZl9zdGF0ZV9yZWFsX3dhZ2UgJT4lDQogIHNsaWNlX21heChvcmRlcl9ieSA9IGF2Z19yZWFsX3dhZ2UsIG4gPSAxMCkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgcGFyYSByZWFsX3dhZ2UgKFRvcCAxMCkNCmdncGxvdChkZl90b3AxMF9yZWFsX3dhZ2UsIGFlcyh4ID0gcmVvcmRlcihzdGF0ZSwgLWF2Z19yZWFsX3dhZ2UpLCB5ID0gYXZnX3JlYWxfd2FnZSwgZmlsbCA9IHN0YXRlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCAxMCBFc3RhZG9zIHBvciBQcm9tZWRpbyBSZWFsIFdhZ2UiLA0KICAgICAgIHggPSAiRXN0YWRvIiwNCiAgICAgICB5ID0gIlByb21lZGlvIFJlYWwgV2FnZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KDQpgYGANCg0KIyMgRXN0YWTDrXN0aWNvcyBkZSBEaXNwZXJzacOzbiAoR2xvYmFsIHkgUmVnaW9uYWwpLiANCg0KIyMjIERpc3BlcnNpw7NuIG5hY2lvbmFsDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAjIEV2aXRhIG5vdGFjacOzbiBjaWVudMOtZmljYQ0KDQojIENyZWFyIGVsIGJveHBsb3QgZGUgdG91cmlzbV9nZHAgcG9yIGHDsW8NCmdncGxvdChkZiwgYWVzKHggPSBmYWN0b3IoeWVhciksIHkgPSB0b3VyaXNtX2dkcCkpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAic2t5Ymx1ZSIsIGNvbG9yID0gImRhcmtibHVlIikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgVG91cmlzbSBHRFAgYSBOaXZlbCBOYWNpb25hbCBwb3IgQcOxbyIsDQogICAgICAgeCA9ICJBw7FvIiwNCiAgICAgICB5ID0gIlRvdXJpc20gR0RQIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmdncGxvdChkZiwgYWVzKHggPSBmYWN0b3IoeWVhciksIHkgPSBjcmltZV9yYXRlKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJ0b21hdG8iLCBjb2xvciA9ICJkYXJrcmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgQ3JpbWUgUmF0ZSBhIE5pdmVsIE5hY2lvbmFsIHBvciBBw7FvIiwNCiAgICAgICB4ID0gIkHDsW8iLA0KICAgICAgIHkgPSAiQ3JpbWUgUmF0ZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gZmFjdG9yKHllYXIpLCB5ID0gcmVhbF93YWdlKSkgKw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJsaWdodGdyZWVuIiwgY29sb3IgPSAiZGFya2dyZWVuIikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgUmVhbCBXYWdlIGEgTml2ZWwgTmFjaW9uYWwgcG9yIEHDsW8iLA0KICAgICAgIHggPSAiQcOxbyIsDQogICAgICAgeSA9ICJSZWFsIFdhZ2UiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gZmFjdG9yKHllYXIpLCB5ID0gZ29vZF9nb3Zlcm5hbmNlKSkgKw0KICAjIFF1aXRhciBzw61tYm9sbyBkZSBvdXRsaWVycw0KICBnZW9tX2JveHBsb3QoZmlsbCA9ICJwbHVtIiwgY29sb3IgPSAicHVycGxlIiwgb3V0bGllci5zaGFwZSA9IE5BKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBHb29kIEdvdmVybmFuY2UgYSBOaXZlbCBOYWNpb25hbCBwb3IgQcOxbyAoQ29uIEzDrW1pdGUpIiwNCiAgICAgICB4ID0gIkHDsW8iLA0KICAgICAgIHkgPSAiR29vZCBHb3Zlcm5hbmNlIikgKw0KICAjIExpbWl0YXIgZWwgcmFuZ28gZGVsIGVqZSB5DQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAyNSkpICsgICMgQWp1c3RhICgwLCAxMCkgYSB0dSByYW5nbyBwcmVmZXJpZG8NCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkNCiAgKQ0KYGBgDQogDQojIyMgRGlzcGVyc2nDs24gZXN0YXRhbA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoc2NhbGVzKSAgIyBQYXJhIGZvcm1hdGVhciBuw7ptZXJvcywgc2kgbG8gcmVxdWllcmVzDQoNCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAgIyBFdml0YSBsYSBub3RhY2nDs24gY2llbnTDrWZpY2ENCg0KIyAxLiBDYWxjdWxhciBlbCBwcm9tZWRpbyBkZSB0b3VyaXNtX2dkcCBwb3IgZXN0YWRvIHkgc2VsZWNjaW9uYXIgZWwgdG9wIDEwDQpkZl9zdGF0ZV90b3VyaXNtIDwtIGRmICU+JQ0KICBncm91cF9ieShzdGF0ZSkgJT4lDQogIHN1bW1hcmlzZShhdmdfdG91cmlzbV9nZHAgPSBtZWFuKHRvdXJpc21fZ2RwLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYXZnX3RvdXJpc21fZ2RwLCBuID0gMTApDQoNCiMgMi4gRmlsdHJhciBlbCBkYXRhZnJhbWUgb3JpZ2luYWwgcGFyYSBjb25zZXJ2YXIgc29sbyBsb3MgZXN0YWRvcyBkZWwgdG9wIDEwDQp0b3Bfc3RhdGVzX3RvdXJpc20gPC0gZGZfc3RhdGVfdG91cmlzbSRzdGF0ZQ0KZGZfdG9wX3RvdXJpc20gPC0gZGYgJT4lIGZpbHRlcihzdGF0ZSAlaW4lIHRvcF9zdGF0ZXNfdG91cmlzbSkNCg0KIyAzLiBHZW5lcmFyIGVsIGJveHBsb3QgZGUgdG91cmlzbV9nZHAgcGFyYSBsb3MgdG9wIDEwIGVzdGFkb3MNCmdncGxvdChkZl90b3BfdG91cmlzbSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCB0b3VyaXNtX2dkcCwgRlVOID0gbWVkaWFuLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB0b3VyaXNtX2dkcCwgZmlsbCA9IHN0YXRlKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBUb3VyaXNtIEdEUCBwYXJhIFRvcCAxMCBFc3RhZG9zIiwNCiAgICAgICB4ID0gIkVzdGFkbyIsDQogICAgICAgeSA9ICJUb3VyaXNtIEdEUCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArICAjIE9wY2lvbmFsOiBmb3JtYXRlYSBsb3MgbsO6bWVyb3MgZGVsIGVqZSB5DQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KDQojIDEuIENhbGN1bGFyIGVsIHByb21lZGlvIGRlIGNyaW1lX3JhdGUgcG9yIGVzdGFkbyB5IHNlbGVjY2lvbmFyIGVsIHRvcCAxMA0KZGZfc3RhdGVfY3JpbWUgPC0gZGYgJT4lDQogIGdyb3VwX2J5KHN0YXRlKSAlPiUNCiAgc3VtbWFyaXNlKGF2Z19jcmltZV9yYXRlID0gbWVhbihjcmltZV9yYXRlLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gYXZnX2NyaW1lX3JhdGUsIG4gPSAxMCkNCg0KIyAyLiBGaWx0cmFyIGVsIGRhdGFmcmFtZSBvcmlnaW5hbCBwYXJhIGNvbnNlcnZhciBzb2xvIGxvcyBlc3RhZG9zIGRlbCB0b3AgMTANCnRvcF9zdGF0ZXNfY3JpbWUgPC0gZGZfc3RhdGVfY3JpbWUkc3RhdGUNCmRmX3RvcF9jcmltZSA8LSBkZiAlPiUgZmlsdGVyKHN0YXRlICVpbiUgdG9wX3N0YXRlc19jcmltZSkNCg0KIyAzLiBHZW5lcmFyIGVsIGJveHBsb3QgZGUgY3JpbWVfcmF0ZSBwYXJhIGxvcyB0b3AgMTAgZXN0YWRvcw0KZ2dwbG90KGRmX3RvcF9jcmltZSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCBjcmltZV9yYXRlLCBGVU4gPSBtZWRpYW4sIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBjcmltZV9yYXRlLCBmaWxsID0gc3RhdGUpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90IGRlIENyaW1lIFJhdGUgcGFyYSBUb3AgMTAgRXN0YWRvcyIsDQogICAgICAgeCA9ICJFc3RhZG8iLA0KICAgICAgIHkgPSAiQ3JpbWUgUmF0ZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArICAjIE9wY2lvbmFsOiBmb3JtYXRlYSBsb3MgbsO6bWVyb3MgZGVsIGVqZSB5DQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQ0KDQojIDEuIENhbGN1bGFyIGVsIHByb21lZGlvIGRlIGdvb2RfZ292ZXJuYW5jZSBwb3IgZXN0YWRvIHkgc2VsZWNjaW9uYXIgZWwgdG9wIDEwDQpkZl9zdGF0ZV9nb3Zlcm5hbmNlIDwtIGRmICU+JQ0KICBncm91cF9ieShzdGF0ZSkgJT4lDQogIHN1bW1hcmlzZShhdmdfZ29vZF9nb3Zlcm5hbmNlID0gbWVhbihnb29kX2dvdmVybmFuY2UsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBzbGljZV9tYXgob3JkZXJfYnkgPSBhdmdfZ29vZF9nb3Zlcm5hbmNlLCBuID0gMTApDQoNCiMgMi4gRmlsdHJhciBlbCBkYXRhZnJhbWUgb3JpZ2luYWwgcGFyYSBjb25zZXJ2YXIgc29sbyBsb3MgZXN0YWRvcyBkZWwgdG9wIDEwDQp0b3Bfc3RhdGVzX2dvdmVybmFuY2UgPC0gZGZfc3RhdGVfZ292ZXJuYW5jZSRzdGF0ZQ0KZGZfdG9wX2dvdmVybmFuY2UgPC0gZGYgJT4lIGZpbHRlcihzdGF0ZSAlaW4lIHRvcF9zdGF0ZXNfZ292ZXJuYW5jZSkNCg0KIyAzLiBHZW5lcmFyIGVsIGJveHBsb3QgZGUgZ29vZF9nb3Zlcm5hbmNlIHBhcmEgbG9zIHRvcCAxMCBlc3RhZG9zDQpnZ3Bsb3QoZGZfdG9wX2dvdmVybmFuY2UsIGFlcyh4ID0gcmVvcmRlcihzdGF0ZSwgZ29vZF9nb3Zlcm5hbmNlLCBGVU4gPSBtZWRpYW4sIG5hLnJtID0gVFJVRSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGdvb2RfZ292ZXJuYW5jZSwgZmlsbCA9IHN0YXRlKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBHb29kIEdvdmVybmFuY2UgcGFyYSBUb3AgMTAgRXN0YWRvcyIsDQogICAgICAgeCA9ICJFc3RhZG8iLA0KICAgICAgIHkgPSAiR29vZCBHb3Zlcm5hbmNlIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsgICMgT3BjaW9uYWw6IGZvcm1hdGVhIGxvcyBuw7ptZXJvcyBkZWwgZWplIHkNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpDQoNCiMgMS4gQ2FsY3VsYXIgZWwgcHJvbWVkaW8gZGUgcmVhbF93YWdlIHBvciBlc3RhZG8geSBzZWxlY2Npb25hciBlbCB0b3AgMTANCmRmX3N0YXRlX3JlYWx3YWdlIDwtIGRmICU+JQ0KICBncm91cF9ieShzdGF0ZSkgJT4lDQogIHN1bW1hcmlzZShhdmdfcmVhbF93YWdlID0gbWVhbihyZWFsX3dhZ2UsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBzbGljZV9tYXgob3JkZXJfYnkgPSBhdmdfcmVhbF93YWdlLCBuID0gMTApDQoNCiMgMi4gRmlsdHJhciBlbCBkYXRhZnJhbWUgb3JpZ2luYWwgcGFyYSBjb25zZXJ2YXIgc29sbyBsb3MgZXN0YWRvcyBkZWwgdG9wIDEwDQp0b3Bfc3RhdGVzX3JlYWx3YWdlIDwtIGRmX3N0YXRlX3JlYWx3YWdlJHN0YXRlDQpkZl90b3BfcmVhbHdhZ2UgPC0gZGYgJT4lIGZpbHRlcihzdGF0ZSAlaW4lIHRvcF9zdGF0ZXNfcmVhbHdhZ2UpDQoNCiMgMy4gR2VuZXJhciBlbCBib3hwbG90IGRlIHJlYWxfd2FnZSBwYXJhIGxvcyB0b3AgMTAgZXN0YWRvcw0KZ2dwbG90KGRmX3RvcF9yZWFsd2FnZSwgYWVzKHggPSByZW9yZGVyKHN0YXRlLCByZWFsX3dhZ2UsIEZVTiA9IG1lZGlhbiwgbmEucm0gPSBUUlVFKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlYWxfd2FnZSwgZmlsbCA9IHN0YXRlKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBSZWFsIFdhZ2UgcGFyYSBUb3AgMTAgRXN0YWRvcyIsDQogICAgICAgeCA9ICJFc3RhZG8iLA0KICAgICAgIHkgPSAiUmVhbCBXYWdlIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsgICMgT3BjaW9uYWw6IGZvcm1hdGVhIGxvcyBuw7ptZXJvcyBkZWwgZWplIHkNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIikpDQoNCmBgYA0KDQojIyBWaXN1YWxpemFyIGxhIGRpc3RyaWJ1Y2nDs24gZXNwYWNpYWwgZGUgbGFzIHZhcmlhYmxlcyB1c2FuZG8gbWFwYXMNCg0KIyMjIExlZXIgYXJjaGl2byBtYXBhcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgTGVlciBlbCBhcmNoaXZvIC5zaHANCmVzdGFkb3NfbXggPC0gc3RfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxPQ1RBVk8gU0VNRVNUUkVcXFRVUklTTU8gTU9OVEVSUkVZXFxteF9zcGF0aWFsX2RhdGFcXG14X3NwYXRpYWxfZGF0YVxcbXhfbWFwc1xcbXhfc3RhdGVzXFxtZXhsYXRsb25nLnNocCIpDQpuYW1lcyhlc3RhZG9zX214KQ0KaGVhZChlc3RhZG9zX214KQ0KYGBgDQoNCiMjIyBWaXN0YSByw6FwaWRhDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQpwbG90KHN0X2dlb21ldHJ5KGVzdGFkb3NfbXgpKQ0KDQpgYGANCg0KIyMjIFVuaW9uIG1hcGEgY29uIGV4Y2VsDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBVbmlyIHNoYXBlZmlsZSBjb24gbG9zIGRhdG9zDQplc3RhZG9zX2RhdG9zIDwtIGxlZnRfam9pbihlc3RhZG9zX214LCBkZiwgYnkgPSBjKCJBRE1JTl9OQU1FIiA9ICJzdGF0ZSIpKQ0KDQojIENyZWFyIG1hdHJpeiBkZSB2ZWNpbm9zIHkgcGVzb3MNCnZlY2lub3MgPC0gcG9seTJuYihlc3RhZG9zX2RhdG9zKQ0KcGVzb3MgPC0gbmIybGlzdHcodmVjaW5vcywgc3R5bGUgPSAiVyIpDQpgYGANCg0KIyMjIE1hcGFzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0bWFwKQ0KDQojIE1vZG8gZXN0w6F0aWNvIChwdWVkZXMgY2FtYmlhcmxvIGEgInZpZXciIHNpIHF1aWVyZXMgbWFwYXMgaW50ZXJhY3Rpdm9zKQ0KdG1hcF9tb2RlKCJwbG90IikNCg0KIyBNYXBhIDE6IHRvdXJpc21fZ2RwDQp0bV9zaGFwZShlc3RhZG9zX2RhdG9zKSArDQogIHRtX3BvbHlnb25zKCJ0b3VyaXNtX2dkcCIsDQogICAgICAgICAgICAgIHBhbGV0dGUgPSAiQmx1ZXMiLA0KICAgICAgICAgICAgICB0aXRsZSA9ICJQSUIgVHVyw61zdGljbyIpICsNCiAgdG1fbGF5b3V0KG1haW4udGl0bGUgPSAiRGlzdHJpYnVjacOzbiBFc3BhY2lhbCBkZWwgUElCIFR1csOtc3RpY28iLA0KICAgICAgICAgICAgbGVnZW5kLm91dHNpZGUgPSBUUlVFKQ0KDQojIE1hcGEgMjogY3JpbWVfcmF0ZQ0KdG1fc2hhcGUoZXN0YWRvc19kYXRvcykgKw0KICB0bV9wb2x5Z29ucygiY3JpbWVfcmF0ZSIsDQogICAgICAgICAgICAgIHBhbGV0dGUgPSAiUmVkcyIsDQogICAgICAgICAgICAgIHRpdGxlID0gIsONbmRpY2UgZGUgQ3JpbWluYWxpZGFkIikgKw0KICB0bV9sYXlvdXQobWFpbi50aXRsZSA9ICJEaXN0cmlidWNpw7NuIEVzcGFjaWFsIGRlbCBDcmltZW4iLA0KICAgICAgICAgICAgbGVnZW5kLm91dHNpZGUgPSBUUlVFKQ0KDQojIE1hcGEgMzogZ29vZF9nb3Zlcm5hbmNlDQp0bV9zaGFwZShlc3RhZG9zX2RhdG9zKSArDQogIHRtX3BvbHlnb25zKCJnb29kX2dvdmVybmFuY2UiLA0KICAgICAgICAgICAgICBwYWxldHRlID0gIkdyZWVucyIsDQogICAgICAgICAgICAgIHRpdGxlID0gIsONbmRpY2UgZGUgQnVlbiBHb2JpZXJubyIpICsNCiAgdG1fbGF5b3V0KG1haW4udGl0bGUgPSAiRGlzdHJpYnVjacOzbiBFc3BhY2lhbCBkZWwgQnVlbiBHb2JpZXJubyIsDQogICAgICAgICAgICBsZWdlbmQub3V0c2lkZSA9IFRSVUUpDQoNCiMgTWFwYSA0OiByZWFsX3dhZ2UNCnRtX3NoYXBlKGVzdGFkb3NfZGF0b3MpICsNCiAgdG1fcG9seWdvbnMoInJlYWxfd2FnZSIsDQogICAgICAgICAgICAgIHBhbGV0dGUgPSAiUHVycGxlcyIsDQogICAgICAgICAgICAgIHRpdGxlID0gIlNhbGFyaW8gUmVhbCIpICsNCiAgdG1fbGF5b3V0KG1haW4udGl0bGUgPSAiRGlzdHJpYnVjacOzbiBFc3BhY2lhbCBkZWwgU2FsYXJpbyBSZWFsIiwNCiAgICAgICAgICAgIGxlZ2VuZC5vdXRzaWRlID0gVFJVRSkNCg0KYGBgDQoNCiMjIE1hdHJpY2VzIGRlIGNvbmVjdGl2aWRhZA0KDQojIyMgTWF0cml6IGRlIGNvbmVjdGl2aWRhZCBiaW5hcmlhDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KIyBNYXRyaXogYmluYXJpYSAoMSA9IHZlY2lub3MsIDAgPSBubyB2ZWNpbm9zKQ0KbWF0cml6X2JpbmFyaWEgPC0gbmIybWF0KHZlY2lub3MsIHN0eWxlID0gIkIiLCB6ZXJvLnBvbGljeSA9IFRSVUUpDQoNCiMgVmVyIGxhcyBwcmltZXJhcyBmaWxhcyBjb21vIHRhYmxhDQpoZWFkKG1hdHJpel9iaW5hcmlhKQ0KYGBgDQoNCiMjIyBNYXRyaXogZGUgcGVzb3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQojIE1hdHJpeiBkZSBwZXNvcyBub3JtYWxpemFkb3MgKFcpDQptYXRyaXpfcGVzb3MgPC0gbmIybWF0KHZlY2lub3MsIHN0eWxlID0gIlciLCB6ZXJvLnBvbGljeSA9IFRSVUUpDQoNCiMgVmlzdWFsaXphcg0KaGVhZChtYXRyaXpfcGVzb3MpDQpgYGANCg0KIyMgSW5kaWNlIEdsb2JhbCBkZSBNb3JhbiAoRGV0ZWN0YXIgbGEgcHJlc2VuY2lhIGRlIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgR2xvYmFsKQ0KIyMjIFBJQiBUdXLDrXN0aWNvDQpgYGB7cn0NCmxpYnJhcnkoc3BkZXApDQplc3RhZG9zX3ZhbGlkb3MgPC0gZXN0YWRvc19kYXRvc1shaXMubmEoZXN0YWRvc19kYXRvcyR0b3VyaXNtX2dkcCksIF0NCmVzdGFkb3NfdmFsaWRvcyA8LSBlc3RhZG9zX2RhdG9zWyFpcy5uYShlc3RhZG9zX2RhdG9zJHJlYWxfd2FnZSksIF0NCmVzdGFkb3NfdmFsaWRvcyA8LSBlc3RhZG9zX2RhdG9zWyFpcy5uYShlc3RhZG9zX2RhdG9zJGNyaW1lX3JhdGUpLCBdDQplc3RhZG9zX3ZhbGlkb3MgPC0gZXN0YWRvc19kYXRvc1shaXMubmEoZXN0YWRvc19kYXRvcyRnb29kX2dvdmVybmFuY2UpLCBdDQoNCnZlY2lub3NfdmFsaWRvcyA8LSBwb2x5Mm5iKGVzdGFkb3NfdmFsaWRvcykNCnBlc29zX3ZhbGlkb3MgPC0gbmIybGlzdHcodmVjaW5vc192YWxpZG9zLCBzdHlsZSA9ICJXIikNCg0KbW9yYW5fZ2RwX3R1cmlzbW8gPC0gbW9yYW4udGVzdChlc3RhZG9zX3ZhbGlkb3MkdG91cmlzbV9nZHAsIHBlc29zX3ZhbGlkb3MsIHplcm8ucG9saWN5ID0gVFJVRSkNCm1vcmFuX2dkcF90dXJpc21vDQoNCmBgYA0KRW4gZXN0ZSBwcmltZXIgY2FzbyBwYXJhIGxhIHZhcmlhYmxlIFBJQiBkZSB0dXJpc21vIHBvZGVtb3Mgb2JzZXJ2YXIgZG9zIGNvc2FzOiANCi0gRWwgTW9yYW4gSSBTdGF0aXN0aWMgZXMgZGUgMC4wMTUgcG9yIGxvIHF1ZSBlcyB1biB2YWxvciByZWxhdGl2YW1lbnRlIGJham8NCi0gRWwgUCB2YWx1ZSBlcyBkZSAwLjAwMjUgcG9yIGxvIHF1ZSBleGlzdGUgc2lnbmlmaWNhbmNpYSBlc3RhZMOtc3RpY2ENCkVzIGRlY2lyLCBoYXkgY2llcnRhIGFncnVwYWNpw7NuIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgZGUgZXN0YWRvcyBjb24gUElCIHR1csOtc3RpY28gc2ltaWxhciwgcGVybyBlc3RhIGFncnVwYWNpw7NuIGVzIG11eSBkw6liaWwuDQoNCiMjIyBDcsOtbWVuIA0KYGBge3J9DQptb3Jhbl9jcmltZW4gPC0gbW9yYW4udGVzdChlc3RhZG9zX3ZhbGlkb3MkY3JpbWVfcmF0ZSwgcGVzb3NfdmFsaWRvcywgemVyby5wb2xpY3kgPSBUUlVFKQ0KbW9yYW5fY3JpbWVuDQpgYGANClBhcmEgbGEgdmFyaWFibGUgZGUgY3JpbWVuIGNvbnRhbW9zIGNvbiB1biB2YWxvciBkZSBNb3JhbiBkZSAwLjE3NDcgZWwgY3VhbCBlcyBtw6FzIGFsdG8gcXVlIGVsIGRlbCBQSUIgeSBzdSBQLXZhbHVlIGVzIGV4dHJlbWFkYW1lbnRlIGJham8gcG9yIGxvIHF1ZSBleGlzdGUgc2lnbmlmaWNhbmNpYSBlc3RhZMOtc3RpY2EsIGVzIGRlY2lyLCBsb3MgZXN0YWRvcyBjb24gYWx0YXMgdGFzYXMgZGUgY3JpbWluYWxpZGFkIHRpZW5kZW4gYSBlc3RhciBjZXJjYSBkZSBvdHJvcyBjb24gdGFzYXMgc2ltaWxhcmVzDQoNCiMjIyBCdWVuIEdvYmllcm5vDQpgYGB7cn0NCm1vcmFuX2dvYmllcm5vIDwtIG1vcmFuLnRlc3QoZXN0YWRvc192YWxpZG9zJGdvb2RfZ292ZXJuYW5jZSwgcGVzb3NfdmFsaWRvcywgemVyby5wb2xpY3kgPSBUUlVFKQ0KbW9yYW5fZ29iaWVybm8NCmBgYA0KRW4gbGEgdmFyaWFibGUgZGUgQnVlbiBHb2JpZXJubyBjb250YW1vcyBudWV2YW1lbnRlIGNvbiB1biB2YWxvciBkZWwgTW9yYW4gU3RhdGlzdGljIGJham8gKDAuMDE0MykgeSB1biBQLXZhbHVlIHRhbWJpw6luIGJham8gKDwwLjA1KSBwb3IgbG8gcXVlIGV4aXN0ZSB1bmEgYXV0b2NvcnJlbGFjacOzbiBkw6liaWwgcGVybyBzaWduaWZpY2F0aXZhLCBsbyBjdWFsIHN1Z2llcmUgcXVlIGxvcyBlc3RhZG9zIGNvbiBtZWpvciAobyBwZW9yKSBnb2Jlcm5hbnphIHRpZW5kZW4gYSBlc3RhciBhZ3J1cGFkb3MsIHBlcm8gZWwgcGF0csOzbiBubyBlcyB0YW4gbWFyY2FkbyBjb21vIHBhcmEgc2VyIG9ic2VydmFkbyBhIHNpbXBsZSB2aXN0YQ0KDQojIyMgU2FsYXJpbyByZWFsDQpgYGB7cn0NCm1vcmFuX3NhbGFyaW8gPC0gbW9yYW4udGVzdChlc3RhZG9zX3ZhbGlkb3MkcmVhbF93YWdlLCBwZXNvc192YWxpZG9zLCB6ZXJvLnBvbGljeSA9IFRSVUUpDQptb3Jhbl9zYWxhcmlvDQpgYGANCkZpbmFsbWVudGUgcGFyYSBlbCBjYXNvIGRlIGxvcyBzYWxhcmlvcyByZWFsZXMgY29udGFtb3MgY29uIHVuIHZhbG9yIGRlbCBNb3JhbCBTdGF0aXN0aWMgZGUgMC4xMzkgeSB1biBQLXZhbHVlIGV4dHJlbWFkYW1lbnRlIGJham8gcG9yIGxvIHF1ZSBzaSBleGlzdGUgdW5hIGF1dG9jb3JyZWxhY2nDs24gcG9zaXRpdmEgZXNzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgcG9yIGxvIHF1ZSBwb2RlbW9zIGRlY2lyIHF1ZSBoYXkgdW5hIHRlbmRlbmNpYSByZWdpb25hbCBlbiBsb3Mgbml2ZWxlcyBzYWxhcmlhbGVzIHJlYWxlcyBlbiBkb25kZSBsb3MgZXN0YWRvcyBjb24gc3VlbGRvcyBhbHRvcyBjZXJjYSBkZSBvdHJvcyBjb24gc3VlbGRvcyBhbHRvcw0KDQojIyBMSVNBIChEZXRlY3RhciBsYSBwcmVzZW5jaWEgZGUgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBsb2NhbCkNClBhcmEgZXN0ZSBjYXNvIMO6bmljYW1lbnRlIHNlbGVjY2lvbmFtb3MgbGFzIHZhcmlhYmxlcyAiY3JpbWVfcmF0ZSIgeSAicmVhbF93YWdlIiBwdWVzIGZ1ZXJvbiBsYXMgcXVlIHByZXNlbnRhcm9uIGxvcyB2YWxvcmVzIG3DoXMgYWx0b3MgZW4gZWwgTW9yYW4gSSBTdGF0aXN0aWMgYWRlbcOhcyBkZSB1biBQLXZhbHVlIGV4dHJlbWFkYW1lbnRlIGJham9zDQoNCiMjIyBDcmltZSBSYXRlDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KbG9jYWxfbW9yYW5fY3JpbWVuIDwtIGxvY2FsbW9yYW4oZXN0YWRvc192YWxpZG9zJGNyaW1lX3JhdGUsIHBlc29zX3ZhbGlkb3MpDQpsb2NhbF9tb3Jhbl9jcmltZW4NCmBgYA0KYGBge3J9DQplc3RhZG9zX3ZhbGlkb3MkbG9jYWxfbW9yYW5fY3JpbWVuIDwtIGxvY2FsX21vcmFuX2NyaW1lblssMV0NCmVzdGFkb3NfdmFsaWRvcyRwdmFsX21vcmFuX2NyaW1lbiA8LSBsb2NhbF9tb3Jhbl9jcmltZW5bLDVdDQp0bV9zaGFwZShlc3RhZG9zX3ZhbGlkb3MpICsNCiAgdG1fcG9seWdvbnMoImxvY2FsX21vcmFuX2NyaW1lbiIsDQogICAgICAgICAgICAgIHBhbGV0dGUgPSAiUmRCdSIsDQogICAgICAgICAgICAgIHRpdGxlID0gIkxvY2FsIE1vcmFuIEkgLSBDcmltZSBSYXRlIikgKw0KICB0bV9sYXlvdXQobWFpbi50aXRsZSA9ICJDbHVzdGVycyBFc3BhY2lhbGVzIGRlbCBDcmltZSBSYXRlIiwNCiAgICAgICAgICAgIGxlZ2VuZC5vdXRzaWRlID0gVFJVRSkNCmBgYA0KUG9kZW1vcyBvYnNlcnZhciBjbGFyYW1lbnRlIGNvbW8gbG9zIGNsdXN0ZXJzIHNlIGFncnVwYW4gcG9yIHJlZ2nDs24gbm9ydGUgcXVlIGVzIGRvbmRlIHNlIGNvbmNlbnRyYSBsYSBtYXlvciBwYXJ0ZSBkZWwgY3JpbWVuLCB1bmEgbWVub3IgY29uY2VudHJhY2nDs24gZW4gbG9zIGVzdGFkb3MgZGUgY29sb3IgY2Fmw6kgeSB2dWVsdmUgYSBzdWJpciBwZXJvIG5vIHRhbnRvIGVuIGxhIHJlZ2nDs24gY2VudHJvLXN1ciBkZWwgcGHDrXMNCg0KIyMjIFNhbGFyaW8gUmVhbA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxvY2FsX21vcmFuX3NhbGFyaW9zIDwtIGxvY2FsbW9yYW4oZXN0YWRvc192YWxpZG9zJHJlYWxfd2FnZSwgcGVzb3NfdmFsaWRvcykNCmxvY2FsX21vcmFuX3NhbGFyaW9zDQpgYGANCmBgYHtyfQ0KZXN0YWRvc192YWxpZG9zJGxvY2FsX21vcmFuX3NhbGFyaW9zIDwtIGxvY2FsX21vcmFuX3NhbGFyaW9zWywxXQ0KZXN0YWRvc192YWxpZG9zJHB2YWxfbW9yYW5fc2FsYXJpb3MgPC0gbG9jYWxfbW9yYW5fc2FsYXJpb3NbLDVdDQp0bV9zaGFwZShlc3RhZG9zX3ZhbGlkb3MpICsNCiAgdG1fcG9seWdvbnMoImxvY2FsX21vcmFuX3NhbGFyaW9zIiwNCiAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJSZEJ1IiwNCiAgICAgICAgICAgICAgdGl0bGUgPSAiTG9jYWwgTW9yYW4gSSAtIFNhbGFyaW9zIikgKw0KICB0bV9sYXlvdXQobWFpbi50aXRsZSA9ICJDbHVzdGVycyBFc3BhY2lhbGVzIGRlIFNhbGFyaW9zIiwNCiAgICAgICAgICAgIGxlZ2VuZC5vdXRzaWRlID0gVFJVRSkNCmBgYA0KRW4gZWwgY2FzbyBwYXJhIGxvcyBjbHVzdGVycyBkZSBzYWxhcmlvcywgcG9kZW1vcyB2ZXIgdW5hIGNvbmNlbnRyYWNpw7NuIGRlIHNhbGFyaW9zIGFsdG9zIGJhc3RhbnRlIG1hcmNhZGEgZW4gZWwgbm9ydGUgZGVsIHBhw61zIGNvbiBsb3MgZXN0YWRvcyBkZSBOdWV2byBMZcOzbiB5IFRhbWF1bGlwYXMgYXPDrSBjb21vIGNvbiBTaW5hbG9hIHkgQkNTLCBkZSBsYSBtaXNtYSBtYW5lcmEgc2UgdnVlbHZlbiBhIGFncnVwYXIgQ2hpaHVhaHVhIHkgU29ub3JhLCBwb2RlbW9zIHZlciBxdWUgZW4gZXN0ZSBtYXBhIGxvcyBjbHVzdGVycyBzb24gbWFzIGNsYXJvcyBkZWJpZG8gYSBsYSB2YXJpYWNpw7NuIGRlIGxvcyBzYWxhcmlvcyBxdWUgZXMgbWF5b3IgYSBsYSBwcmVzZW50YWRhIGNvbiBsYXMgdGFzYXMgZGUgY3JpbWluYWxpZGFkDQo=