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 Tradicional

Importación de base de datos y geocercas

El conjunto de datos boston.c contiene 506 filas y 20 columnas. Incluye los datos de Harrison y Rubinfeld (1978), corregidos por pequeños errores y complementados con la latitud y longitud de las observaciones. Gilley y Pace también señalan que la variable MEDV está censurada, es decir, los valores medianos iguales o superiores a USD 50,000 se establecen en USD 50,000.

Este data frame contiene las siguientes columnas:

  • TOWN: Factor con los nombres de las localidades.

  • TOWNNO: Vector numérico correspondiente a TOWN.

  • TRACT: Vector numérico con los identificadores de los tramos censales.

  • LON: Longitud del punto central del tramo censal en grados decimales.

  • LAT: Latitud del punto central del tramo censal en grados decimales.

  • MEDV: Valor mediano de viviendas ocupadas por sus propietarios en miles de USD.

  • CMEDV: Valor mediano corregido de viviendas ocupadas por sus propietarios en miles de USD.

  • CRIM: Tasa de criminalidad per cápita.

  • ZN: Proporción de terreno residencial zonificado para lotes mayores a 25,000 pies² (constante para todos los tramos de Boston).

  • INDUS: Proporción de acres de negocios no minoristas por localidad (constante para todos los tramos de Boston).

  • CHAS: Factor con niveles: 1 si el tramo colinda con el río Charles; 0 en caso contrario.

  • NOX: Concentración de óxidos nítricos (partes por 10 millones) por localidad.

  • RM: Promedio de habitaciones por vivienda.

  • AGE: Proporción de unidades ocupadas por propietarios construidas antes de 1940.

  • DIS: Distancias ponderadas a cinco centros de empleo en Boston.

  • RAD: Índice de accesibilidad a autopistas radiales por localidad (constante para todos los tramos de Boston).

  • TAX: Tasa de impuesto predial por cada 10,000 USD de valor de propiedad (constante para todos los tramos de Boston).

  • PTRATIO: Relación alumno/profesor por localidad (constante para todos los tramos de Boston).

  • B: Cálculo de 1000*(Bk - 0.63)^2, donde Bk es la proporción de personas negras.

  • LSTAT: Porcentaje de población de menor nivel socioeconómico.

data(boston, package="spData")
head(boston.c)
##         TOWN TOWNNO TRACT      LON     LAT MEDV CMEDV    CRIM ZN INDUS CHAS
## 1     Nahant      0  2011 -70.9550 42.2550 24.0  24.0 0.00632 18  2.31    0
## 2 Swampscott      1  2021 -70.9500 42.2875 21.6  21.6 0.02731  0  7.07    0
## 3 Swampscott      1  2022 -70.9360 42.2830 34.7  34.7 0.02729  0  7.07    0
## 4 Marblehead      2  2031 -70.9280 42.2930 33.4  33.4 0.03237  0  2.18    0
## 5 Marblehead      2  2032 -70.9220 42.2980 36.2  36.2 0.06905  0  2.18    0
## 6 Marblehead      2  2033 -70.9165 42.3040 28.7  28.7 0.02985  0  2.18    0
##     NOX    RM  AGE    DIS RAD TAX PTRATIO      B LSTAT
## 1 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98
## 2 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14
## 3 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03
## 4 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94
## 5 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33
## 6 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21
glimpse(boston.c)
## Rows: 506
## Columns: 20
## $ TOWN    <fct> Nahant, Swampscott, Swampscott, Marblehead, Marblehead, Marble…
## $ TOWNNO  <int> 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ TRACT   <int> 2011, 2021, 2022, 2031, 2032, 2033, 2041, 2042, 2043, 2044, 20…
## $ LON     <dbl> -70.9550, -70.9500, -70.9360, -70.9280, -70.9220, -70.9165, -7…
## $ LAT     <dbl> 42.2550, 42.2875, 42.2830, 42.2930, 42.2980, 42.3040, 42.2970,…
## $ MEDV    <dbl> 24.0, 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 27.1, 16.5, 18.9, 15…
## $ CMEDV   <dbl> 24.0, 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 22.1, 16.5, 18.9, 15…
## $ CRIM    <dbl> 0.00632, 0.02731, 0.02729, 0.03237, 0.06905, 0.02985, 0.08829,…
## $ ZN      <dbl> 18.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.5, 12.5, 12.5, 12.5, 12.5, 1…
## $ INDUS   <dbl> 2.31, 7.07, 7.07, 2.18, 2.18, 2.18, 7.87, 7.87, 7.87, 7.87, 7.…
## $ CHAS    <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ NOX     <dbl> 0.538, 0.469, 0.469, 0.458, 0.458, 0.458, 0.524, 0.524, 0.524,…
## $ RM      <dbl> 6.575, 6.421, 7.185, 6.998, 7.147, 6.430, 6.012, 6.172, 5.631,…
## $ AGE     <dbl> 65.2, 78.9, 61.1, 45.8, 54.2, 58.7, 66.6, 96.1, 100.0, 85.9, 9…
## $ DIS     <dbl> 4.0900, 4.9671, 4.9671, 6.0622, 6.0622, 6.0622, 5.5605, 5.9505…
## $ RAD     <int> 1, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,…
## $ TAX     <int> 296, 242, 242, 222, 222, 222, 311, 311, 311, 311, 311, 311, 31…
## $ PTRATIO <dbl> 15.3, 17.8, 17.8, 18.7, 18.7, 18.7, 15.2, 15.2, 15.2, 15.2, 15…
## $ B       <dbl> 396.90, 396.90, 392.83, 394.63, 396.90, 394.12, 395.60, 396.90…
## $ LSTAT   <dbl> 4.98, 9.14, 4.03, 2.94, 5.33, 5.21, 12.43, 19.15, 29.93, 17.10…

Seguidamente, se cargan las geocercas asociadas a la data transversal previamente cargada

boston.tr<-st_read(system.file("shapes/boston_tracts.gpkg", package="spData")[1])
## Reading layer `boston_tracts' from data source 
##   `C:\Users\AVRIL\AppData\Local\R\win-library\4.3\spData\shapes\boston_tracts.gpkg' 
##   using driver `GPKG'
## Simple feature collection with 506 features and 36 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -71.52311 ymin: 42.00305 xmax: -70.63823 ymax: 42.67307
## Geodetic CRS:  NAD27

Summary Boston

boston.trSP<-as(boston.tr, "Spatial")
boston_nb<-poly2nb(boston.trSP)
summary(boston.trSP)
## Object of class SpatialPolygonsDataFrame
## Coordinates:
##         min       max
## x -71.52311 -70.63823
## y  42.00305  42.67307
## Is projected: FALSE 
## proj4string : [+proj=longlat +datum=NAD27 +no_defs]
## Data attributes:
##    poltract             TOWN               TOWNNO          TRACT     
##  Length:506         Length:506         Min.   : 0.00   Min.   :   1  
##  Class :character   Class :character   1st Qu.:26.25   1st Qu.:1303  
##  Mode  :character   Mode  :character   Median :42.00   Median :3394  
##                                        Mean   :47.53   Mean   :2700  
##                                        3rd Qu.:78.00   3rd Qu.:3740  
##                                        Max.   :91.00   Max.   :5082  
##                                                                      
##       LON              LAT             MEDV           CMEDV      
##  Min.   :-71.29   Min.   :42.03   Min.   : 5.00   Min.   : 5.00  
##  1st Qu.:-71.09   1st Qu.:42.18   1st Qu.:17.02   1st Qu.:17.02  
##  Median :-71.05   Median :42.22   Median :21.20   Median :21.20  
##  Mean   :-71.06   Mean   :42.22   Mean   :22.53   Mean   :22.53  
##  3rd Qu.:-71.02   3rd Qu.:42.25   3rd Qu.:25.00   3rd Qu.:25.00  
##  Max.   :-70.81   Max.   :42.38   Max.   :50.00   Max.   :50.00  
##                                                                  
##       CRIM                ZN             INDUS           CHAS          
##  Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46   Length:506        
##  1st Qu.: 0.08205   1st Qu.:  0.00   1st Qu.: 5.19   Class :character  
##  Median : 0.25651   Median :  0.00   Median : 9.69   Mode  :character  
##  Mean   : 3.61352   Mean   : 11.36   Mean   :11.14                     
##  3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10                     
##  Max.   :88.97620   Max.   :100.00   Max.   :27.74                     
##                                                                        
##       NOX               RM             AGE              DIS        
##  Min.   :0.3850   Min.   :3.561   Min.   :  2.90   Min.   : 1.130  
##  1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02   1st Qu.: 2.100  
##  Median :0.5380   Median :6.208   Median : 77.50   Median : 3.207  
##  Mean   :0.5547   Mean   :6.285   Mean   : 68.57   Mean   : 3.795  
##  3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08   3rd Qu.: 5.188  
##  Max.   :0.8710   Max.   :8.780   Max.   :100.00   Max.   :12.127  
##                                                                    
##       RAD              TAX           PTRATIO            B         
##  Min.   : 1.000   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 4.000   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 5.000   Median :330.0   Median :19.05   Median :391.44  
##  Mean   : 9.549   Mean   :408.2   Mean   :18.46   Mean   :356.67  
##  3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :24.000   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##                                                                   
##      LSTAT           units             cu5k            c5_7_5      
##  Min.   : 1.73   Min.   :   5.0   Min.   : 0.000   Min.   : 0.000  
##  1st Qu.: 6.95   1st Qu.: 115.0   1st Qu.: 0.000   1st Qu.: 1.000  
##  Median :11.36   Median : 511.5   Median : 1.000   Median : 3.000  
##  Mean   :12.65   Mean   : 680.8   Mean   : 2.921   Mean   : 5.534  
##  3rd Qu.:16.95   3rd Qu.:1152.0   3rd Qu.: 4.000   3rd Qu.: 7.000  
##  Max.   :37.97   Max.   :3031.0   Max.   :35.000   Max.   :70.000  
##                                                                    
##     C7_5_10            C10_15           C15_20          C20_25     
##  Min.   :  0.000   Min.   :  0.00   Min.   :  0.0   Min.   :  0.0  
##  1st Qu.:  2.000   1st Qu.: 14.00   1st Qu.: 19.0   1st Qu.: 13.0  
##  Median :  6.000   Median : 33.00   Median : 85.0   Median :101.5  
##  Mean   :  9.984   Mean   : 55.41   Mean   :141.8   Mean   :166.2  
##  3rd Qu.: 13.000   3rd Qu.: 75.50   3rd Qu.:210.0   3rd Qu.:281.8  
##  Max.   :121.000   Max.   :520.00   Max.   :937.0   Max.   :723.0  
##                                                                    
##      C25_35           C35_50           co50k            median     
##  Min.   :   0.0   Min.   :  0.00   Min.   :  0.00   Min.   : 5600  
##  1st Qu.:   7.0   1st Qu.:  1.00   1st Qu.:  0.00   1st Qu.:16800  
##  Median :  95.0   Median : 17.00   Median :  3.00   Median :21000  
##  Mean   : 170.8   Mean   : 82.74   Mean   : 45.44   Mean   :21749  
##  3rd Qu.: 292.0   3rd Qu.: 97.00   3rd Qu.: 20.00   3rd Qu.:24700  
##  Max.   :1189.0   Max.   :769.00   Max.   :980.00   Max.   :50000  
##                                                     NA's   :17     
##        BB           censored             NOX_ID           POP       
##  Min.   : 0.000   Length:506         Min.   : 1.00   Min.   :  434  
##  1st Qu.: 0.200   Class :character   1st Qu.:18.00   1st Qu.: 3697  
##  Median : 0.500   Mode  :character   Median :44.00   Median : 5105  
##  Mean   : 6.082                      Mean   :41.77   Mean   : 5340  
##  3rd Qu.: 1.600                      3rd Qu.:62.00   3rd Qu.: 6825  
##  Max.   :96.400                      Max.   :96.00   Max.   :15976  
## 
library(tmap)

tmap_mode("view") 

tm_shape(boston.tr) +
  tm_polygons(col = "gray90", border.col = "black") +
  tm_text("TOWN", size = 0.5) +
  tm_compass(position = c("left", "bottom")) +
  tm_title("Distritos de Boston (TOWN)")

Histogramas

El gráfico presenta los histogramas de las variables numéricas del conjunto de datos de Boston. A continuación se destacan algunos hallazgos clave:

  • Sesgo a la derecha: Variables como CRIM (tasa de criminalidad), DIS (distancia a centros laborales), y TAX (tasa de impuesto predial) presentan una distribución altamente asimétrica, con la mayoría de las observaciones concentradas en valores bajos y pocos valores extremos altos.

  • Variables censuradas: CMEDV y MEDV muestran un claro corte en el valor máximo de 50, lo cual refleja la censura superior impuesta en el conjunto de datos.

  • Distribuciones bimodales o discretas: Variables como RAD (accesibilidad a autopistas) y PTRATIO presentan distribuciones con valores repetidos o agrupamientos discretos.

  • Normalidad aparente: Algunas variables como RM (número promedio de habitaciones por vivienda) y LAT/LON (coordenadas geográficas) muestran distribuciones más cercanas a una forma normal o simétrica.

  • Concentración extrema: ZN (zonificación para terrenos residenciales grandes) y B (proporción transformada de población negra) presentan una alta concentración de observaciones en un valor específico, lo que indica poca variabilidad en muchas zonas.

Dicho análisis preliminar sugiere que será necesario transformar algunas variables previo a usarlas en modelos estadísticos.

boston.c.num <- boston.c %>% select(where(is.numeric))

boston.c.num %>% 
  pivot_longer(cols = everything(), names_to = "variable", values_to = "valor") %>%
  ggplot(aes(x = valor)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  facet_wrap(~variable, scales = "free") +
  labs(title = "Histogramas de Variables Numéricas")

Matriz de Correlación

Relaciones con el valor de la vivienda (MEDV y CMEDV):

  • RM (habitaciones por vivienda) tiene una fuerte correlación positiva con MEDV (0.70), lo que sugiere que más habitaciones se asocian con mayor valor de vivienda.

  • LSTAT (población de menor nivel socioeconómico) tiene una fuerte correlación negativa con MEDV (-0.74), indicando que zonas con mayor proporción de personas de bajos ingresos tienden a tener viviendas más baratas.

También hay una correlación negativa notable con NOX (-0.43) y PTRATIO (-0.51), lo que sugiere que altos niveles de contaminación y una mayor proporción alumno/profesor se relacionan con menores valores de vivienda.

Contaminación y urbanización:

  • NOX está fuertemente correlacionado con INDUS (0.76) y AGE (0.73), lo cual tiene sentido, ya que las zonas más industriales y con construcciones más antiguas suelen tener más contaminación.

También está negativamente correlacionado con DIS (-0.77), lo que indica que zonas más cercanas a los centros urbanos (menor distancia) presentan mayor contaminación.

Infraestructura y zonificación:

  • RAD y TAX tienen una correlación muy alta (0.91), lo que sugiere que las áreas con mejor acceso a autopistas tienden a tener impuestos prediales más altos.

  • ZN tiene correlaciones negativas con variables como INDUS, NOX y CRIM, lo que sugiere que las áreas con más zonificación residencial son menos industriales, menos contaminadas y más seguras.

library(corrplot)

mat_cor <- cor(boston.c.num, use = "complete.obs")

corrplot(mat_cor, method = "color", type = "upper", 
         col = colorRampPalette(c("blue", "white", "red"))(200),
         tl.col = "black", tl.srt = 45, 
         title = "Matriz de Correlaciones", mar = c(0,0,1,0))

corrplot(mat_cor, method = "number", type = "upper", 
         tl.col = "black", tl.srt = 45,
         title = "Matriz de Correlaciones (con valores)", mar = c(0,0,1,0))

Correlación con variable CRIME

En este caso, la variable CRIME será nuestra variable y, ante lo cual, se determina que tiene una correlación positiva moderada con TAX, RAD y PTRATIO, y negativa con ZN y DIS, lo que indica que áreas con mayor infraestructura o menor planificación residencial tienden a tener mayor crimen.

mat_cor <- cor(boston.c.num, use = "complete.obs")

cor_crim <- mat_cor["CRIM", ]

sort(cor_crim, decreasing = TRUE)
##        CRIM         RAD         TAX       LSTAT      TOWNNO         NOX 
##  1.00000000  0.62550515  0.58276431  0.45562148  0.44791970  0.42097171 
##       INDUS         AGE     PTRATIO         LON         LAT          ZN 
##  0.40658341  0.35273425  0.28994558  0.06510061 -0.08429296 -0.20046922 
##          RM         DIS           B        MEDV       CMEDV       TRACT 
## -0.21924670 -0.37967009 -0.38506394 -0.38830461 -0.38958244 -0.54716534
corrplot(mat_cor["CRIM", , drop = FALSE], is.corr = FALSE,
         method = "number", tl.col = "black", title = "Correlación de CRIM con otras variables",
         mar = c(0,0,2,0))

Boxplots

Variables con alta dispersión y outliers notables:

  • CRIM (criminalidad), DIS (distancia a centros laborales) y B (proporción de personas negras) muestran muchos valores atípicos (puntos rojos), lo que sugiere una gran variabilidad entre zonas.

  • ZN, RAD, y INDUS también presentan concentración de valores extremos, lo cual es esperable dado que son variables relacionadas con zonificación o infraestructura urbana.

Variables fuertemente sesgadas:

  • ZN y CRIM parecen tener una asimetría positiva (cola larga a la derecha), indicando que la mayoría de los tramos censales tienen valores bajos, pero unos pocos tienen valores muy altos.

  • B está fuertemente sesgada con valores máximos agrupados cerca del tope.

Variables más concentradas (baja dispersión y pocos outliers):

  • RM (habitaciones) y PTRATIO (alumnos/profesor) tienen una distribución bastante estrecha, lo que indica que esas variables son más homogéneas entre localidades.

Impuestos (TAX) y tramos censales (TRACT):

  • TAX tiene una distribución bastante amplia, lo cual sugiere diferencias importantes en política fiscal entre localidades.

  • TRACT muestra amplísima variación, pero como es un identificador, esta dispersión no implica un patrón útil directamente, sino que debe tratarse como variable categórica o de localización.

Valor de vivienda (MEDV y CMEDV):

  • Ambas presentan outliers por arriba, lo que sugiere presencia de zonas con viviendas significativamente más caras que el promedio, aunque la mayoría de los valores están agrupados en un rango estrecho.
library(dplyr)
library(tidyr)
library(ggplot2)

boston.c.num %>%
  pivot_longer(cols = everything(), names_to = "variable", values_to = "valor") %>%
  ggplot(aes(x = "", y = valor)) +  # x vacío porque no hay categorías internas
  geom_boxplot(fill = "lightblue", color = "darkblue", outlier.color = "red", outlier.shape = 16) +
  facet_wrap(~ variable, scales = "free_y") +  # facetas por variable con escala libre en Y
  labs(title = "Boxplots por Variable Numérica",
       x = NULL,
       y = "Valor") +
  theme_minimal() +
  theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())

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

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 506 polígonos (506 localidades en Boston).

  • Hay 2910 conexiones de vecindad entre ellos.

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

  • Cada estado tiene, en promedio, 5.75 vecinos

  • Sólo tres localidades tienen 1 vecino: Boston North End, Boston Beacon Hill y Bedford

  • Sólo 1 localidad está conectada con 15 vecinos: Boston Mattapan

boston_nb <- poly2nb(boston.trSP, queen = TRUE)
summary(boston_nb)
## Neighbour list object:
## Number of regions: 506 
## Number of nonzero links: 2910 
## Percentage nonzero weights: 1.136559 
## Average number of links: 5.750988 
## Link number distribution:
## 
##   1   2   3   4   5   6   7   8   9  10  11  12  15 
##   3   9  28  81 107 120  87  40  22   5   2   1   1 
## 3 least connected regions:
## 18 51 345 with 1 link
## 1 most connected region:
## 112 with 15 links

Conexiones entre areas

boston.trSP$TOWN[112]   # Area más conectada (con 15 vecinos)
## [1] "Boston Mattapan"
boston.trSP$TOWN[c(18, 15, 345)]  # Areas menos conectadas (con 1 vecino)
## [1] "Boston North End"   "Boston Beacon Hill" "Bedford"
# Se muestran las 9 conexiones del area con mayor número de conexiones, es decir, de Boston Mattapan
boston_nb[[112]]
##  [1]  69  75  77  78 100 101 110 111 113 114 115 117 118 119 120
# Listado de localidades conectados con Boston Mattapan
boston.trSP$TOWN[boston_nb[[112]]]
##  [1] "Boston Roxbury"      "Boston Roxbury"      "Boston Roxbury"     
##  [4] "Boston Savin Hill"   "Boston Savin Hill"   "Boston Dorchester"  
##  [7] "Boston Dorchester"   "Boston Dorchester"   "Boston Mattapan"    
## [10] "Boston Mattapan"     "Boston Mattapan"     "Boston Mattapan"    
## [13] "Boston Forest Hills" "Boston Forest Hills" "Boston Forest Hills"

Visualización Gráfica de la matriz de conectividad (Vecindades estilo ‘Reina’)

boston_listw <- nb2listw(boston_nb, style = "W", zero.policy = TRUE)

centroids <- coordinates(boston.trSP)
plot(boston.trSP, border = "blue", axes = FALSE, las = 1, main = "Boston Tracts - Queen Contiguity")
plot(boston.trSP, col = "lightgrey", border = grey(0.9), add = TRUE)
plot(boston_listw, coords = centroids, pch = 19, cex = 0.1, col = "red", add = TRUE)

CRIME

boston.tr_clean <- na.omit(boston.tr)
boston.trSP<-as(boston.tr, "Spatial")
boston_nb<-poly2nb(boston.trSP)
mapview(boston.trSP, zcol="CRIM", col.regions = viridisLite::magma(20))

Elección de variables explicativas

Con base en la combinación de variables realizada por la regresión stepwise, la matriz de correlación con CRIM y la significancia de cada variable según en random forest, se determina que las principales variables explicativas a utilizar y que conviene rezagar espacialmente son:

MEDV:

  • Tiene una correlación con CRIM de -0.39, refleja que el valor de vivienda más alto reduce crimen (relación negativa).

  • A mayor valor de la vivienda, menor crimen. Resultado esperado y significativo. Relación clara y altamente significativa (p < 0.001).

  • Su alta importancia como predictor indica que el valor mediano de las viviendas en un área está fuertemente asociado con las otras características consideradas.

DIS

  • Tiene correlación de -0.38, lo que puede implicar que a mayor distancia a centros laborales = menos crimen.

  • A mayor distancia a centros laborales, menor crimen; además es muy significativo (p < 0.001).

  • Su alta importancia en ambas métricas (%IncMSE e IncNodePurity) indica que la cercanía a los centros de empleo es un factor crucial para predecir CRIM.

VARImportance

En resumen, considerando ambas gráficas, algunas de las variables que consistentemente aparecen como importantes son:

  • LSTAT: Porcentaje de estatus bajo de la población.

  • RM: Número promedio de habitaciones por vivienda.

  • DIS: Distancias ponderadas a cinco centros de empleo de Boston.

  • RAD: Índice de accesibilidad a carreteras radiales.

  • CMEDV / MEDV: Valor mediano de las viviendas ocupadas por sus dueños (podrían ser la misma variable o una transformación).

  • B: 1000(Bk−0.63) donde Bk es la proporción de afroamericanos por ciudad.

library(randomForest)

set.seed(123)
modelo_rf <- randomForest(CRIM ~ ., data = boston.c.num, importance = TRUE, ntree = 500)

varImpPlot(modelo_rf)

Regresión Stepwise

El modelo incluye 8 variables explicativas de entre las 12 posibles que se integraron inicialmente. Se eligieron por balancear calidad del ajuste y simplicidad del modelo (criterio AIC).

  • RAD (+0.53): A mayor acceso a autopistas, mayor crimen. Relación clara y altamente significativa (p < 0.001).

  • LSTAT (+0.11): A mayor % de población vulnerable, mayor crimen. No es estadísticamente significativo (p = 0.11).

  • ZN (+0.043): Mayor proporción de zonas residenciales parece asociarse a más crimen.

  • DIS (–0.91): Mayor distancia a centros laborales, menor crimen. Muy significativo.

  • MEDV (–0.17): A mayor valor de la vivienda, menor crimen. Resultado esperado y significativo.

  • NOX (–12.75): Menor calidad del aire (mayor NOX), menor crimen (algo contraintuitivo, aunque es posible colinealidad).

  • PTRATIO (–0.31): A mayor ratio alumno-profesor, menor crimen. Marginalmente significativo (p ~ 0.09).

  • B (–0.0079): A mayor población de personas negras (B), menor crimen. Sin embargo, esta variable suele estar correlacionada con otras condiciones estructurales.

boston_sf <- st_as_sf(boston.trSP)

modelo_full <- lm(CRIM ~ RAD + TAX + LSTAT + ZN + INDUS + DIS + AGE + MEDV+ NOX + RM + PTRATIO + B, data = boston_sf)

# Stepwise regresión usando AIC
modelo_step <- step(modelo_full, direction = "both")
## Start:  AIC=1896.97
## CRIM ~ RAD + TAX + LSTAT + ZN + INDUS + DIS + AGE + MEDV + NOX + 
##     RM + PTRATIO + B
## 
##           Df Sum of Sq   RSS    AIC
## - AGE      1      0.10 20417 1895.0
## - TAX      1     18.86 20436 1895.4
## - RM       1     21.39 20438 1895.5
## - INDUS    1     28.84 20446 1895.7
## <none>                 20417 1897.0
## - PTRATIO  1     84.55 20501 1897.1
## - LSTAT    1    114.89 20532 1897.8
## - NOX      1    165.79 20582 1899.1
## - B        1    178.18 20595 1899.4
## - ZN       1    238.94 20656 1900.9
## - MEDV     1    483.47 20900 1906.8
## - DIS      1    515.68 20932 1907.6
## - RAD      1   1834.83 22252 1938.5
## 
## Step:  AIC=1894.97
## CRIM ~ RAD + TAX + LSTAT + ZN + INDUS + DIS + MEDV + NOX + RM + 
##     PTRATIO + B
## 
##           Df Sum of Sq   RSS    AIC
## - TAX      1     18.81 20436 1893.4
## - RM       1     22.76 20440 1893.5
## - INDUS    1     28.82 20446 1893.7
## <none>                 20417 1895.0
## - PTRATIO  1     84.57 20501 1895.1
## - LSTAT    1    129.63 20546 1896.2
## + AGE      1      0.10 20417 1897.0
## - NOX      1    175.96 20593 1897.3
## - B        1    178.37 20595 1897.4
## - ZN       1    241.26 20658 1898.9
## - MEDV     1    483.38 20900 1904.8
## - DIS      1    563.37 20980 1906.8
## - RAD      1   1842.82 22260 1936.7
## 
## Step:  AIC=1893.44
## CRIM ~ RAD + LSTAT + ZN + INDUS + DIS + MEDV + NOX + RM + PTRATIO + 
##     B
## 
##           Df Sum of Sq   RSS    AIC
## - RM       1      23.0 20459 1892.0
## - INDUS    1      64.4 20500 1893.0
## <none>                 20436 1893.4
## - PTRATIO  1      87.4 20523 1893.6
## - LSTAT    1     137.9 20574 1894.8
## + TAX      1      18.8 20417 1895.0
## + AGE      1       0.0 20436 1895.4
## - B        1     178.1 20614 1895.8
## - NOX      1     181.9 20617 1895.9
## - ZN       1     222.9 20658 1896.9
## - MEDV     1     465.3 20901 1902.8
## - DIS      1     556.9 20992 1905.0
## - RAD      1    4693.4 25129 1996.0
## 
## Step:  AIC=1892.01
## CRIM ~ RAD + LSTAT + ZN + INDUS + DIS + MEDV + NOX + PTRATIO + 
##     B
## 
##           Df Sum of Sq   RSS    AIC
## - INDUS    1      74.0 20533 1891.8
## <none>                 20459 1892.0
## - PTRATIO  1      88.2 20547 1892.2
## - LSTAT    1     118.9 20577 1892.9
## + RM       1      23.0 20436 1893.4
## + TAX      1      19.1 20440 1893.5
## + AGE      1       1.2 20457 1894.0
## - NOX      1     176.9 20636 1894.4
## - B        1     202.4 20661 1895.0
## - ZN       1     233.9 20693 1895.8
## - MEDV     1     458.7 20917 1901.2
## - DIS      1     572.2 21031 1904.0
## - RAD      1    4811.3 25270 1996.9
## 
## Step:  AIC=1891.83
## CRIM ~ RAD + LSTAT + ZN + DIS + MEDV + NOX + PTRATIO + B
## 
##           Df Sum of Sq   RSS    AIC
## <none>                 20533 1891.8
## + INDUS    1      74.0 20459 1892.0
## + TAX      1      58.8 20474 1892.4
## - LSTAT    1     104.7 20637 1892.4
## - PTRATIO  1     119.0 20652 1892.8
## + RM       1      32.6 20500 1893.0
## + AGE      1       1.3 20531 1893.8
## - B        1     198.4 20731 1894.7
## - ZN       1     239.6 20772 1895.7
## - NOX      1     296.6 20829 1897.1
## - MEDV     1     430.2 20963 1900.3
## - DIS      1     507.8 21040 1902.2
## - RAD      1    4739.5 25272 1994.9
summary(modelo_step)
## 
## Call:
## lm(formula = CRIM ~ RAD + LSTAT + ZN + DIS + MEDV + NOX + PTRATIO + 
##     B, data = boston_sf)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -9.860 -2.102 -0.363  0.895 75.702 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  19.683128   6.086010   3.234 0.001301 ** 
## RAD           0.532617   0.049727  10.711  < 2e-16 ***
## LSTAT         0.110173   0.069219   1.592 0.112097    
## ZN            0.043293   0.017977   2.408 0.016394 *  
## DIS          -0.918318   0.261932  -3.506 0.000496 ***
## MEDV         -0.174207   0.053988  -3.227 0.001334 ** 
## NOX         -12.753708   4.760157  -2.679 0.007623 ** 
## PTRATIO      -0.310541   0.182941  -1.697 0.090229 .  
## B            -0.007922   0.003615  -2.191 0.028897 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 6.428 on 497 degrees of freedom
## Multiple R-squared:  0.4505, Adjusted R-squared:  0.4416 
## F-statistic: 50.92 on 8 and 497 DF,  p-value: < 2.2e-16

MEDV y DIS

library(tmap)
# Calcular rezago espacial de MEDV
boston_sf$sp_lag_MEDV <- lag.listw(boston_listw, boston_sf$MEDV, zero.policy = TRUE)

# Calcular rangos comunes para una escala continua compartida
medv_range <- range(c(boston_sf$MEDV, boston_sf$sp_lag_MEDV), na.rm = TRUE)
medv_breaks <- seq(medv_range[1], medv_range[2], length.out = 10)

# Mapa MEDV original
medv_map <- tm_shape(boston_sf) +  
  tm_polygons(
    col = "MEDV",
    palette = "YlGnBu",
    style = "fixed",
    breaks = medv_breaks,
    title = "MEDV",
    textNA = "",     # Ocultar "Missing"
    showNA = FALSE   # Excluir NA de la leyenda
  ) +
  tm_title("Valor Vivienda (MEDV)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Calcular rangos comunes para una escala continua compartida
dis_range <- range(c(boston_sf$DIS, boston_sf$sp_lag_DIS), na.rm = TRUE)
dis_breaks <- seq(dis_range[1], dis_range[2], length.out = 10)

# Mapa DIS original
dis_map <- tm_shape(boston_sf) +  
  tm_polygons(
    col = "DIS",
    palette = "YlOrBr",  # Paleta naranjosa
    style = "fixed",
    breaks = dis_breaks,
    title = "DIS",
    textNA = "",        # Oculta etiqueta "Missing"
    showNA = FALSE      # Excluye NA de la leyenda
  ) +
  tm_title("Distancia a Centros (DIS)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

tmap_arrange(medv_map, dis_map, ncol = 1)

Í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 CRIME tiene autocorrelación espacial, es decir, si las areas ya sea con alto o bajo crimen tienden a estar cerca unos de otros. También se analiza si MEDV y/o DIS, tienem o no autocorrelación espacial, es decir, si las localidades ya sea con alto o bajo nivel tienden a estar cerca unos de otros.

moran.test(boston.trSP$CRIM, boston_listw) # Global Moran's I is 0.527 and statistically significant (p-value < 10%).
## 
##  Moran I test under randomisation
## 
## data:  boston.trSP$CRIM  
## weights: boston_listw    
## 
## Moran I statistic standard deviate = 20.398, p-value < 2.2e-16
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      0.5274633075     -0.0019801980      0.0006736983
moran.test(boston.trSP$MEDV, boston_listw) # Global Moran's I is 0.627 and statistically significant (p-value < 10%).
## 
##  Moran I test under randomisation
## 
## data:  boston.trSP$MEDV  
## weights: boston_listw    
## 
## Moran I statistic standard deviate = 23.35, p-value < 2.2e-16
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      0.6266753872     -0.0019801980      0.0007248686
moran.test(boston.trSP$DIS, boston_listw) # Global Moran's I is 0.956 and statistically significant (p-value < 10%).
## 
##  Moran I test under randomisation
## 
## data:  boston.trSP$DIS  
## weights: boston_listw    
## 
## Moran I statistic standard deviate = 35.56, p-value < 2.2e-16
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       0.956380200      -0.001980198       0.000726315

Presentación de resultados

Crimen (CRIM)
Se determina que sí existe un patrón espacial significativo en la distribución del crimen (CRIM) en Boston. Las áreas con tasas similares de crimen están espacialmente agrupadas. El crimen no está distribuida aleatoriamente; hay agrupamientos claros.

  • Moran’s I = 0.527 → Hay una autocorrelación espacial positiva moderada en los valores de criminalidad, es decir, las zonas con alta (o baja) criminalidad tienden a estar cerca unas de otras, en lugar de distribuirse aleatoriamente en el espacio.

  • P-value = 2.2e-16 → El valor es extremadamente significativo, es decir, la probabilidad de observar un valor de Moran’s I tan alto por puro azar es virtualmente cero.

Valor de vivienda (MEDV)
Existe un patrón espacial fuerte. El valor de vivienda no está distribuida aleatoriamente ya que, existen hay agrupamientos claros.

  • Moran’s I = 0.627 → Existe una fuerte autocorrelación espacial positiva en los valores de la vivienda. Por ende, los vecindarios con viviendas de alto o bajo valor se agrupan geográficamente, lo cual es un patrón esperado en la realidad urbana (zonas caras vs. zonas más accesibles).

  • P-value = 2.2e-16 → Sí es estadísticamente significativo (p<0.10).

Distancia a centros (DIS)
Las distancias se comportan como una variable espacialmente estructurada. La distancia a centros no está distribuida aleatoriamente ya que, existen hay agrupamientos claros.

  • Moran’s I = 0.956 → Hay una autocorrelación espacial extremadamente fuerte. Las distancias a los centros de empleo están muy agrupadas espacialmente, es decir, hay zonas muy cercanas o muy lejanas a los centros laborales que tienden a estar juntas.

  • P-value = 2.2e-16 → Sí es estadísticamente significativo (p<0.10).

table <- data.frame(Variable = c("CRIM", "MEDV", "DIS"), GM = c(0.527, 0.627, 0.956), Significance = c("***", "***", "***"))
table
##   Variable    GM Significance
## 1     CRIM 0.527          ***
## 2     MEDV 0.627          ***
## 3      DIS 0.956          ***

Análisis de Autocorrelación Espacial

Mapa de Lag Espacial CRIM

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

# Cargar librerías necesarias
library(spdep)
library(tmap)
library(sf)

# Si boston.trSP es de tipo SpatialPolygonsDataFrame, conviértelo a sf
boston_sf <- st_as_sf(boston.trSP)

# Crear objeto de vecinos (Queen contiguity)
boston_nb <- poly2nb(boston_sf, queen = TRUE)
boston_listw <- nb2listw(boston_nb, style = "W", zero.policy = TRUE)

# Calcular rezago espacial de CRIM
boston_sf$sp_lag_CRIM <- lag.listw(boston_listw, boston_sf$CRIM, zero.policy = TRUE)

Se realiza cálculo de rangos comunes y grafico de mapa de CRIM original con mapa de CRIM-lag

# Calcular rangos comunes y ajustar breaks
crim_range <- range(c(boston_sf$CRIM, boston_sf$sp_lag_CRIM), na.rm = TRUE)
crim_breaks <- seq(crim_range[1], crim_range[2], length.out = 10)

# Mapa CRIM original
crim_map <- tm_shape(boston_sf) +  
  tm_polygons(
    col = "CRIM",
    palette = "Purples",
    style = "fixed",
    breaks = crim_breaks,
    title = "CRIM",
    textNA = "",     # Oculta etiqueta "Missing"
    showNA = FALSE   # Excluye NA de la leyenda
  ) +
  tm_title("Tasa de Crimen (CRIM)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa CRIM con rezago espacial
crim_lag_map <- tm_shape(boston_sf) + 
  tm_polygons(
    col = "sp_lag_CRIM",
    palette = "Purples",
    style = "fixed",
    breaks = crim_breaks,
    title = "CRIM (Lag-1)",
    textNA = "",
    showNA = FALSE
  ) +
  tm_title("Tasa de Crimen Rezagada (Lag-1)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mostrar los mapas
tmap_arrange(crim_map, crim_lag_map, ncol = 1)

Mapa de Lag Espacial MEDV

# Calcular rezago espacial de MEDV
boston_sf$sp_lag_MEDV <- lag.listw(boston_listw, boston_sf$MEDV, zero.policy = TRUE)

# Calcular rangos comunes para una escala continua compartida
medv_range <- range(c(boston_sf$MEDV, boston_sf$sp_lag_MEDV), na.rm = TRUE)
medv_breaks <- seq(medv_range[1], medv_range[2], length.out = 10)

# Mapa MEDV original
medv_map <- tm_shape(boston_sf) +  
  tm_polygons(
    col = "MEDV",
    palette = "YlGnBu",
    style = "fixed",
    breaks = medv_breaks,
    title = "MEDV",
    textNA = "",     # Ocultar "Missing"
    showNA = FALSE   # Excluir NA de la leyenda
  ) +
  tm_title("Valor Vivienda (MEDV)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa MEDV con rezago espacial
medv_lag_map <- tm_shape(boston_sf) + 
  tm_polygons(
    col = "sp_lag_MEDV",
    palette = "YlGnBu",
    style = "fixed",
    breaks = medv_breaks,
    title = "MEDV (Lag-1)",
    textNA = "",
    showNA = FALSE
  ) +
  tm_title("Valor Vivienda Rezagado (Lag-1)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mostrar mapas lado a lado
tmap_arrange(medv_map, medv_lag_map, ncol = 1)

Mapa de Lag Espacial DIS

# Calcular rezago espacial de DIS
boston_sf$sp_lag_DIS <- lag.listw(boston_listw, boston_sf$DIS, zero.policy = TRUE)

# Calcular rangos comunes para una escala continua compartida
dis_range <- range(c(boston_sf$DIS, boston_sf$sp_lag_DIS), na.rm = TRUE)
dis_breaks <- seq(dis_range[1], dis_range[2], length.out = 10)

# Mapa DIS original
dis_map <- tm_shape(boston_sf) +  
  tm_polygons(
    col = "DIS",
    palette = "YlOrBr",  # Paleta naranjosa
    style = "fixed",
    breaks = dis_breaks,
    title = "DIS",
    textNA = "",        # Oculta etiqueta "Missing"
    showNA = FALSE      # Excluye NA de la leyenda
  ) +
  tm_title("Distancia a Centros (DIS)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mapa DIS con rezago espacial
dis_lag_map <- tm_shape(boston_sf) + 
  tm_polygons(
    col = "sp_lag_DIS",
    palette = "YlOrBr",
    style = "fixed",
    breaks = dis_breaks,
    title = "DIS (Lag-1)",
    textNA = "",
    showNA = FALSE
  ) +
  tm_title("Distancia a Centros Rezagada (Lag-1)") +
  tm_layout(
    title.position = c("right", "top"),
    legend.position = c("left", "bottom"),
    title.size = 1
  )

# Mostrar mapas lado a lado
tmap_arrange(dis_map, dis_lag_map, ncol = 1)

Scatterplot Moran

Los tres gráficos muestran que CRIM, MEDV y DIS presentan patrones espaciales estructurados, lo que tiene implicaciones clave para el modelado espacial:

  • La criminalidad no es aleatoria en el espacio. Está influida por lo que ocurre en las zonas vecinas. Por lo tanto, cualquier modelo que explique el crimen debe incorporar dependencia espacial.

  • Variables como MEDV y DIS están también espacialmente autocorrelacionadas, lo cual podría introducir efectos indirectos si no se controla adecuadamente.

  • MEDV podría tener un efecto negativo sobre CRIM, dado que barrios con viviendas más caras suelen ser más seguros.

  • Asimismo, DIS puede estar relacionado con menos crimen en áreas más lejanas (menos densas o más suburbanas), aunque esto debe verificarse en el modelo.

CRIM

  • Hay una clara autocorrelación espacial positiva, donde barrios con alta criminalidad están rodeados de barrios similares.

  • Se destacan zonas como Boston Roxbury, South Boston y Charlestown, que muestran valores extremos.

  • Lo anterior apoya el valor de Moran’s I = 0.527, evidenciando agrupamientos espaciales no aleatorios.

# Ajuste de regresión
M1 <- lm(sp_lag_CRIM ~ CRIM, boston_sf)

# Calcular los residuos absolutos
boston_sf$residuals <- abs(resid(M1))

# Identificar outliers
n_outliers <- 5
top_outliers <- order(boston_sf$residuals, decreasing = TRUE)[1:n_outliers]

# Promedios (para líneas divisorias y cuadrantes)
mean_x <- mean(boston_sf$CRIM)
mean_y <- mean(boston_sf$sp_lag_CRIM)

# Graficar scatterplot de Moran
plot(sp_lag_CRIM ~ CRIM, boston_sf, pch=21, asp=1, las=1, 
     col = "grey40", bg="grey80", main="Tasa de Crimen vs Rezago Espacial",
     xlab = "CRIM", ylab = "Rezago Espacial de CRIM")

abline(M1, col="blue")  # Línea de regresión
abline(v = mean_x, lty=3, col = "grey80")  # Línea vertical media CRIM
abline(h = mean_y, lty=3, col = "grey80")  # Línea horizontal media lag

# Resaltar los outliers
points(boston_sf$CRIM[top_outliers], 
       boston_sf$sp_lag_CRIM[top_outliers], 
       pch=21, bg="red", col="black", cex=1.4)

# Etiquetas de outliers
text(boston_sf$CRIM[top_outliers], 
     boston_sf$sp_lag_CRIM[top_outliers], 
     labels = boston_sf$TOWN[top_outliers], 
     pos = 3, cex = 0.8, col = "black")

MEDV

  • Existe una fuerte correlación positiva entre el valor de una vivienda y el de sus vecinas.

  • Zonas como Brookline y Beacon Hill muestran altos valores, mientras que Boston North End y Waltham destacan con valores más bajos.

  • Confirma el Moran’s I = 0.627, lo que indica una estructura espacial clara en el valor de las viviendas.

M2 <- lm(sp_lag_MEDV ~ MEDV, boston_sf)

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

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

# Graficar los datos (Moran scatterplot) + línea de regresión
plot(sp_lag_MEDV ~ MEDV, boston_sf, pch=21, asp=1, las=1, 
     col = "grey40", bg="grey80", main="Tasa de Valor Vivienda vs Rezago Espacial")
abline(M1, col="blue") # Línea de regresión
abline(v = mean(boston_sf$MEDV), lty=3, col = "grey80")
abline(h = mean(boston_sf$sp_lag_MEDV), lty=3, col = "grey80")

# Resaltar los puntos más lejanos (outliers)
points(boston_sf$MEDV[top_outliers], 
       boston_sf$sp_lag_MEDV[top_outliers], 
       pch=21, bg="red", col="black", cex=1.4)

# Agregar etiquetas con el nombre de la localidad
text(boston_sf$MEDV[top_outliers], 
     boston_sf$sp_lag_MEDV[top_outliers], 
     labels = boston_sf$TOWN[top_outliers], 
     pos = 3, cex = 0.8, col = "black")

DIS

  • Hay una autocorrelación espacial extremadamente alta (Moran’s I = 0.956). Las zonas con similares distancias a centros laborales están muy agrupadas.

  • Ejemplos: Lexington, Duxbury y Garland se agrupan por sus mayores distancias.

M3 <- lm(sp_lag_DIS ~ DIS, boston_sf)

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

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

# Graficar los datos (Moran scatterplot) + línea de regresión
plot(sp_lag_DIS ~ DIS, boston_sf, pch=21, asp=1, las=1, 
     col = "grey40", bg="grey80", main="Tasa de Distancia de Centros vs Rezago Espacial")
abline(M1, col="blue") # Línea de regresión
abline(v = mean(boston_sf$DIS), lty=3, col = "grey80")
abline(h = mean(boston_sf$sp_lag_DIS), lty=3, col = "grey80")

# Resaltar los puntos más lejanos (outliers)
points(boston_sf$DIS[top_outliers], 
       boston_sf$sp_lag_DIS[top_outliers], 
       pch=21, bg="red", col="black", cex=1.4)

# Agregar etiquetas con el nombre de la localidad
text(boston_sf$DIS[top_outliers], 
     boston_sf$sp_lag_DIS[top_outliers], 
     labels = boston_sf$TOWN[top_outliers], 
     pos = 3, cex = 0.8, col = "black")

Análisis de clusters

Visualización Espacial de Clusters de CRIM

  • High-High: Alta criminalidad rodeada de alta criminalidad. Indica zonas vulnerables, usualmente urbanas, con posibles problemas estructurales.

  • Low-High: Baja criminalidad en zonas rodeadas de alta criminalidad. Puede reflejar zonas de resistencia o enclaves seguros en entornos conflictivos.

  • Low-Low: Baja criminalidad rodeada de baja criminalidad. Áreas seguras, probablemente con buena infraestructura y calidad de vida.

  • Not significant: Sin patrón espacial claro. Áreas heterogéneas o en transición.

swm_a <- queen_weights(boston_sf)  # Matriz de pesos espaciales Queen

lisa_crim <- local_moran(swm_a, boston_sf["CRIM"])

boston_sf$cluster_crim <- as.factor(lisa_crim$GetClusterIndicators())
levels(boston_sf$cluster_crim) <- lisa_crim$GetLabels()

library(ggplot2)

ggplot(data = boston_sf) +
  geom_sf(aes(fill = cluster_crim), color = "white") +
  ggtitle(label = "Tasa de Crimen", subtitle = "Clústeres Espaciales en Boston") +
  theme_minimal() +
  scale_fill_manual(values = c("salmon", "turquoise", "grey", "purple", "green")) + # Colores para los clusters
  theme(legend.title = element_blank(), 
        legend.position = "bottom")

Visualización Espacial de Clusters de MEDV

  • High-High: Alto valor de vivienda en zonas rodeadas también de alto valor. Barrios acomodados o suburbanos consolidados.

  • Low-High: Bajo valor en zonas de alto valor. Pueden ser focos de gentrificación o rezago en zonas desarrolladas.

  • Low-Low: Bajo valor rodeado de bajo valor. Zonas marginadas o de menor desarrollo económico.

  • Not significant: Sin patrón claro en el valor de vivienda. Pueden ser zonas con mezcla de clases sociales o desarrollo desigual.

lisa_medv <- local_moran(swm_a, boston_sf["MEDV"])

boston_sf$cluster_medv <- as.factor(lisa_medv$GetClusterIndicators())
levels(boston_sf$cluster_medv) <- lisa_medv$GetLabels()

library(ggplot2)

ggplot(data = boston_sf) +
  geom_sf(aes(fill = cluster_medv), color = "white") +
  ggtitle(label = "Tasa de Valor Vivienda", subtitle = "Clústeres Espaciales en Boston") +
  theme_minimal() +
  scale_fill_manual(values = c("salmon", "turquoise", "grey", "purple", "green")) + # Colores para los clusters
  theme(legend.title = element_blank(), 
        legend.position = "bottom")

Visualización Espacial de Clusters de DIS

  • High-High: Alta distancia a centros de empleo en zonas también alejadas. Zonas periféricas con mala accesibilidad.

  • Low-Low: Baja distancia a centros de empleo en zonas también bien conectadas. Zonas centrales o privilegiadas para movilidad laboral.

  • Not significant: Sin patrón espacial evidente. Pueden combinar accesibilidad variable o estar en zonas en transformación urbana.

lisa_dis <- local_moran(swm_a, boston_sf["DIS"])

boston_sf$cluster_dis <- as.factor(lisa_dis$GetClusterIndicators())
levels(boston_sf$cluster_dis) <- lisa_dis$GetLabels()

library(ggplot2)

ggplot(data = boston_sf) +
  geom_sf(aes(fill = cluster_dis), color = "white") +
  ggtitle(label = "Tasa de Distancia a Centros", subtitle = "Clústeres Espaciales en Boston") +
  theme_minimal() +
  scale_fill_manual(values = c("salmon", "turquoise", "grey", "purple", "green")) + # Colores para los clusters
  theme(legend.title = element_blank(), 
        legend.position = "bottom")

Modelos de Regresión

Modelo de Regresión Lineal Tradicional

model_a <- lm(CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf)
summary(model_a)
## 
## Call:
## lm(formula = CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -10.240  -1.915  -0.376   0.852  75.438 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 14.642639   3.709443   3.947 9.04e-05 ***
## RAD          0.499838   0.044036  11.351  < 2e-16 ***
## ZN           0.053963   0.017305   3.118 0.001923 ** 
## DIS         -0.992811   0.255075  -3.892 0.000113 ***
## MEDV        -0.195990   0.037685  -5.201 2.90e-07 ***
## NOX         -9.238768   4.477580  -2.063 0.039597 *  
## B           -0.008711   0.003612  -2.412 0.016237 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 6.452 on 499 degrees of freedom
## Multiple R-squared:  0.444,  Adjusted R-squared:  0.4373 
## F-statistic: 66.42 on 6 and 499 DF,  p-value: < 2.2e-16
AIC(model_a)
## [1] 3331.699

Modelo de Regresión Espacial AutoRegresivo (SAR)

model_b <- lagsarlm(CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf, listw = boston_listw) 
summary(model_b)
## 
## Call:
## lagsarlm(formula = CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf, 
##     listw = boston_listw)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -15.43339  -1.23757  -0.13543   0.60312  77.51277 
## 
## Type: lag 
## Coefficients: (asymptotic standard errors) 
##               Estimate Std. Error z value  Pr(>|z|)
## (Intercept)  9.1439555  3.4397417  2.6583 0.0078530
## RAD          0.3151860  0.0469326  6.7157 1.872e-11
## ZN           0.0300711  0.0158958  1.8918 0.0585232
## DIS         -0.5420924  0.2372669 -2.2847 0.0223283
## MEDV        -0.1254791  0.0349231 -3.5930 0.0003269
## NOX         -6.9910289  4.0975511 -1.7061 0.0879805
## B           -0.0048688  0.0033311 -1.4616 0.1438538
## 
## Rho: 0.45994, LR test value: 64.289, p-value: 1.1102e-15
## Asymptotic standard error: 0.051889
##     z-value: 8.864, p-value: < 2.22e-16
## Wald statistic: 78.57, p-value: < 2.22e-16
## 
## Log likelihood: -1625.705 for lag model
## ML residual variance (sigma squared): 34.621, (sigma: 5.884)
## Number of observations: 506 
## Number of parameters estimated: 9 
## AIC: 3269.4, (AIC for lm: 3331.7)
## LM test for residual autocorrelation
## test value: 3.161, p-value: 0.075418
AIC(model_b)
## [1] 3269.41

Modelo de Regresión Espacial de Errores (SEM)

model_c <- errorsarlm(CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf, listw = boston_listw)
summary(model_c)
## 
## Call:errorsarlm(formula = CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, 
##     data = boston_sf, listw = boston_listw)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -15.71377  -1.39281  -0.28216   0.67829  74.72508 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##                Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)  14.4531897   4.9291680  2.9322  0.003366
## RAD           0.5281683   0.0619590  8.5245 < 2.2e-16
## ZN            0.0338710   0.0190154  1.7812  0.074873
## DIS          -0.9547810   0.3515253 -2.7161  0.006605
## MEDV         -0.1443547   0.0443807 -3.2526  0.001143
## NOX         -11.1216131   6.2787627 -1.7713  0.076510
## B            -0.0086773   0.0044375 -1.9555  0.050529
## 
## Lambda: 0.50686, LR test value: 67.679, p-value: 2.2204e-16
## Asymptotic standard error: 0.052503
##     z-value: 9.654, p-value: < 2.22e-16
## Wald statistic: 93.199, p-value: < 2.22e-16
## 
## Log likelihood: -1624.01 for error model
## ML residual variance (sigma squared): 34.029, (sigma: 5.8335)
## Number of observations: 506 
## Number of parameters estimated: 9 
## AIC: 3266, (AIC for lm: 3331.7)
AIC(model_c)
## [1] 3266.019

Modelo de Regresión Espacial Durbin

model_d <- lagsarlm(CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf, listw = boston_listw, type="mixed") 
summary(model_d)
## 
## Call:
## lagsarlm(formula = CRIM ~ RAD + ZN + DIS + MEDV + NOX + B, data = boston_sf, 
##     listw = boston_listw, type = "mixed")
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -15.90472  -1.40501  -0.17087   0.76848  73.53893 
## 
## Type: mixed 
## Coefficients: (asymptotic standard errors) 
##                Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)  8.8905e+00  4.3786e+00  2.0304  0.042312
## RAD          5.6078e-01  9.6201e-02  5.8292 5.568e-09
## ZN           1.7655e-02  2.0960e-02  0.8423  0.399608
## DIS         -9.3051e-01  9.0294e-01 -1.0305  0.302755
## MEDV        -1.1644e-01  5.0754e-02 -2.2943  0.021776
## NOX         -2.1876e+01  9.7217e+00 -2.2502  0.024433
## B           -5.7419e-03  5.6323e-03 -1.0195  0.307986
## lag.RAD     -3.3954e-01  1.1709e-01 -2.8998  0.003734
## lag.ZN       3.6048e-02  3.1789e-02  1.1340  0.256810
## lag.DIS      2.7964e-01  9.6850e-01  0.2887  0.772788
## lag.MEDV    -2.7766e-02  7.0705e-02 -0.3927  0.694537
## lag.NOX      1.8741e+01  1.1436e+01  1.6387  0.101270
## lag.B       -5.6835e-04  7.6990e-03 -0.0738  0.941152
## 
## Rho: 0.48978, LR test value: 64.365, p-value: 9.992e-16
## Asymptotic standard error: 0.053295
##     z-value: 9.1899, p-value: < 2.22e-16
## Wald statistic: 84.455, p-value: < 2.22e-16
## 
## Log likelihood: -1620.707 for mixed model
## ML residual variance (sigma squared): 33.723, (sigma: 5.8071)
## Number of observations: 506 
## Number of parameters estimated: 15 
## AIC: 3271.4, (AIC for lm: 3333.8)
## LM test for residual autocorrelation
## test value: 1.026, p-value: 0.31109
AIC(model_d)
## [1] 3271.415

Comparativa de modelos

Con base en los resultados de los cuatro modelos de regresión estimados para explicar la tasa de crimen (CRIM), se determina que:

  • Todos los modelos espaciales (2 a 4) tienen mejor desempeño que el OLS (Modelo 1), lo cual indica que existe autocorrelación espacial en los datos y debe ser tomada en cuenta.

  • Modelo 3 (SEM) tiene el AIC más bajo, lo que le permite explicar bien con menos complejidad.

  • Modelo 4 (SDM) incluye rezagos de las variables explicativas. Tiene la mejor log-likelihood y menor sigma², lo cual sugiere que ajusta mejor los datos, aunque su AIC es ligeramente más alto.

Acorde a lo anterior, se determina que el mejor modelo es el de Regresión Espacial Durbin debido a que:

  • Mayor log-likelihood (−1,620.707): El Modelo 4 tiene el valor menos negativo, lo que implica un mejor ajuste general, por ende, es el que “explica” de forma más probable los datos observados dados sus parámetros estimados.

  • Menor error residual (σ² = 33.723): El Modelo 4 muestra la menor varianza del residuo entre los modelos, lo cual es indicio de una mayor precisión en las predicciones (comete menos errores al predecir la dependiente).

  • Aunque el AIC de Modelo 3 tiene una diferencia de 5.396 con el AIC del Modelo 4. Este último modelo incorpora simultáneamente la dependencia espacial en la variable dependiente (lag de CRIM) y la dependencia espacial en el error (estructura de autocorrelación del error).

  • Resultados significativos en Wald y Likelihood Ratio Tests Ambas pruebas (Wald y LR) evalúan la relevancia de incluir componentes espaciales. En el Modelo 4, estos tests son estadísticamente significativos (p < 0.05), lo que indica que los efectos espaciales no solo están presentes, sino que su inclusión mejora significativamente la explicación del modelo.

stargazer(model_a, model_b, model_c, model_d, type = "text", title="Estimated Regression Results")
## 
## Estimated Regression Results
## ====================================================================================
##                                           Dependent variable:                       
##                     ----------------------------------------------------------------
##                                                   CRIM                              
##                               OLS              spatial      spatial      spatial    
##                                             autoregressive   error    autoregressive
##                               (1)                (2)          (3)          (4)      
## ------------------------------------------------------------------------------------
## RAD                        0.500***            0.315***     0.528***     0.561***   
##                             (0.044)            (0.047)      (0.062)      (0.096)    
##                                                                                     
## ZN                         0.054***             0.030*       0.034*       0.018     
##                             (0.017)            (0.016)      (0.019)      (0.021)    
##                                                                                     
## DIS                        -0.993***           -0.542**    -0.955***      -0.931    
##                             (0.255)            (0.237)      (0.352)      (0.903)    
##                                                                                     
## MEDV                       -0.196***          -0.125***    -0.144***     -0.116**   
##                             (0.038)            (0.035)      (0.044)      (0.051)    
##                                                                                     
## NOX                        -9.239**            -6.991*      -11.122*    -21.876**   
##                             (4.478)            (4.098)      (6.279)      (9.722)    
##                                                                                     
## B                          -0.009**             -0.005      -0.009*       -0.006    
##                             (0.004)            (0.003)      (0.004)      (0.006)    
##                                                                                     
## lag.RAD                                                                 -0.340***   
##                                                                          (0.117)    
##                                                                                     
## lag.ZN                                                                    0.036     
##                                                                          (0.032)    
##                                                                                     
## lag.DIS                                                                   0.280     
##                                                                          (0.969)    
##                                                                                     
## lag.MEDV                                                                  -0.028    
##                                                                          (0.071)    
##                                                                                     
## lag.NOX                                                                   18.741    
##                                                                          (11.436)   
##                                                                                     
## lag.B                                                                     -0.001    
##                                                                          (0.008)    
##                                                                                     
## Constant                   14.643***           9.144***    14.453***     8.891**    
##                             (3.709)            (3.440)      (4.929)      (4.379)    
##                                                                                     
## ------------------------------------------------------------------------------------
## Observations                  506                506          506          506      
## R2                           0.444                                                  
## Adjusted R2                  0.437                                                  
## Log Likelihood                                -1,625.705   -1,624.010   -1,620.707  
## sigma2                                          34.621       34.029       33.723    
## Akaike Inf. Crit.                             3,269.410    3,266.019    3,271.415   
## Residual Std. Error    6.452 (df = 499)                                             
## F Statistic         66.418*** (df = 6; 499)                                         
## Wald Test (df = 1)                            78.570***    93.199***    84.455***   
## LR Test (df = 1)                              64.289***    67.679***    64.365***   
## ====================================================================================
## Note:                                                    *p<0.1; **p<0.05; ***p<0.01

Conclusión

El análisis exploratorio de la variable dependiente CRIM (tasa de crimen por distrito) muestra una clara concentración espacial del crimen en la zona central de Boston. Esta área presenta los valores más altos de criminalidad, representados por tonalidades oscuras en los mapas temáticos. Al comparar la distribución espacial de CRIM con su rezago espacial (Lag-1), se observa una gran similitud, lo cual sugiere la presencia de dependencia espacial: las zonas con alto nivel de crimen tienden a estar rodeadas por otras zonas con niveles también elevados.

El análisis LISA (Indicadores Locales de Asociación Espacial) permitió identificar agrupamientos significativos de valores altos y bajos de crimen:

  • High-High: zonas con alta criminalidad rodeadas de zonas igualmente altas. Se concentran principalmente en el centro-norte de la ciudad y representan áreas críticas desde la perspectiva de seguridad pública.

  • Low-High: zonas con baja criminalidad pero rodeadas de vecindarios con alta criminalidad. Estas pueden representar zonas de riesgo por contagio espacial del crimen.

  • Low-Low: zonas con baja criminalidad rodeadas por otras zonas similares, posiblemente asociadas a condiciones socioeconómicas favorables.

  • Not Significant: zonas sin patrones espaciales significativos.

El modelo seleccionado fue la Regresión Espacial Durbin, ya que incorpora tanto los efectos locales como los rezagos espaciales de las variables explicativas. Asimismo, mostró un buen desempeño estadístico, con un log-likelihood de –1,620.7 y un criterio de información de Akaike (AIC) relativamente bajo, confirmando su ajuste óptimo. Los resultados más relevantes demuestran que:

  • RAD (acceso a autopistas): tiene un efecto directo positivo y significativo (coef. = 0.561), lo cual indica que a mayor accesibilidad a autopistas, mayor es la tasa de crimen. Sin embargo, el efecto espacial de esta variable es negativo y también significativo (lag.RAD = –0.340***), lo cual sugiere que estar rodeado de zonas bien conectadas puede disminuir la criminalidad local, posiblemente por la redistribución de actividades o vigilancia indirecta.

  • MEDV (valor medio de las viviendas): tiene un efecto negativo (–0.116**), lo que implica que en vecindarios con mayor valor inmobiliario la criminalidad tiende a ser menor.

  • NOX (contaminación por óxidos de nitrógeno): presenta un efecto negativo y significativo (–21.876**), lo cual podría estar relacionado con un entorno físico poco habitable que desincentiva la actividad delictiva o concentra menor densidad poblacional.

  • ZN (porcentaje de terrenos residenciales grandes), DIS (distancia a centros laborales) y B (índice racial) pierden significancia estadística en este modelo, lo que indica que sus efectos son absorbidos por otras variables o por sus componentes espaciales.

Con base en lo anterior, se determina que las estrategias de prevención del crimen deben considerar no solo las condiciones internas de cada distrito, sino también su contexto espacial. En otras palabras, las políticas públicas deben diseñarse con una perspectiva regional, reconociendo la interdependencia entre zonas urbanas para lograr intervenciones más efectivas y sostenibles.

LS0tDQp0aXRsZTogIlJlZ3Jlc2nDs24gTGluZWFsIEVzcGFjaWFsIg0Kc3VidGl0bGU6ICJBY3RpdmlkYWQgMDMiDQphdXRob3I6ICJFcXVpcG8gNyINCmRhdGU6ICIyMDI1LTA1LTExIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQotLS0NCg0KIVtdKGh0dHBzOi8vY2l0cmlzLXVjLm9yZy93cC1jb250ZW50L3VwbG9hZHMvMjAxOS8xMC9UZWMtZGUtTW9udGVycmV5LWxvZ28taG9yaXpvbnRhbC1ibHVlLnBuZykNCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyIj4NCiAgPHA+PHN0cm9uZz5QbGFuZWFjacOzbiBlc3RyYXTDqWdpY2EgYmFzYWRhIGVuIGFuYWzDrXRpY2EgcHJlc2NyaXB0aXZhPC9zdHJvbmc+PC9wPg0KICA8cD48c3Ryb25nPkdydXBvIDUwMzwvc3Ryb25nPjwvcD4NCiAgPHA+PHN0cm9uZz5Qcm9mZXNvciBSb2RvbGZvIE1pZ3VlbCBHYW1lcm9zPC9zdHJvbmc+PC9wPg0KPC9kaXY+DQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlciI+DQogIDxwPjxzdHJvbmc+RXF1aXBvIDc6PC9zdHJvbmc+PC9wPg0KICA8cD5BMDA4MzMxMTMgLSBBdnJpbCBMb2JhdG88L3A+DQogIDxwPkEwMTc3MTEyNyAtIExlc2x5IERhcmlhbiBSb21lcm8gVsOhenF1ZXo8L3A+DQogIDxwPkEwMDgzMTEwNSAtIEphem3DrW4gQ29ydGV6IE1lbmRvemE8L3A+DQogIDxwPkEwMTI4NDYxMSAtIExpc3NldCBIZXJuw6FuZGV6PC9wPg0KPC9kaXY+DQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KCWVjaG8gPSBUUlVFLA0KCW1lc3NhZ2UgPSBGQUxTRSwNCgl3YXJuaW5nID0gRkFMU0UNCikNCiNpbnN0YWxsLnBhY2thZ2VzKCJybmF0dXJhbGVhcnRoaGlyZXMiLCByZXBvcyA9ICJodHRwczovL3BhY2thZ2VzLnJvcGVuc2NpLm9yZyIpDQojaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQ0KcGFjbWFuOjpwX2xvYWQoZHBseXIsIGNhciwgTUFTUywgQUVSLCBxdWFudG1vZCwgc3RhdHMsIGRsb29rciwgdGlkeXZlcnNlLCB1cmNhLCBhVFNBLCBnZ3Bsb3QyLCBuYW5pYXIsIHRpZ3JpcywgY29ycnBsb3QsIHBhdGNod29yaywgcmVhZHhsLCBwc3ljaCwgbWFwcywgc2YsIHJuYXR1cmFsZWFydGgsIHJuYXR1cmFsZWFydGhkYXRhLCBzdHJpbmdpLCBzY2FsZXMsIERhdGFFeHBsb3JlciwgdGlkeXIsIGtuaXRyLCBSQ29sb3JCcmV3ZXIsIHBsb3RseSwgZm9yZWNhc3QsIHRzZXJpZXMsIG9wZW54bHN4LCB2YXJzLCBsbXRlc3QsIGZvcmVpZ24sIHNwZGVwLCByZ2VvZGEsIHZpcmlkaXMsIHRtYXAsIHNwLCBzcGd3ciwgR1dtb2RlbCwgaHRtbHRvb2xzLCBzcGF0aWFscmVnLCBzdGFyZ2F6ZXIsIHBsbSwgc3BsbSwgcHNwYXRyZWcsIHJlZ2NsYXNzLCBtY3Rlc3QsIGxtdGVzdCwgc3BEYXRhLCBtYXB2aWV3LCBjYXJldCwgZTEwNzEsIFNwYXJzZU0sIE1ldHJpY3MsIHJhbmRvbUZvcmVzdCwgcnBhcnQucGxvdCwgaW5zaWdodCwganRvb2xzLCB4Z2Jvb3N0LCBEaWFncmFtbWVSLCBlZmZlY3RzLCBsZWFmbGV0LCBHR2FsbHkpDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KDQojICoqQW7DoWxpc2lzIEV4cGxvcmF0b3JpbyBkZSBEYXRvcyBUcmFkaWNpb25hbCoqDQoNCiMjIEltcG9ydGFjacOzbiBkZSBiYXNlIGRlIGRhdG9zIHkgZ2VvY2VyY2FzDQpFbCBjb25qdW50byBkZSBkYXRvcyBgYm9zdG9uLmNgIGNvbnRpZW5lIDUwNiBmaWxhcyB5IDIwIGNvbHVtbmFzLiBJbmNsdXllIGxvcyBkYXRvcyBkZSBIYXJyaXNvbiB5IFJ1YmluZmVsZCAoMTk3OCksIGNvcnJlZ2lkb3MgcG9yIHBlcXVlw7FvcyBlcnJvcmVzIHkgY29tcGxlbWVudGFkb3MgY29uIGxhIGxhdGl0dWQgeSBsb25naXR1ZCBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gR2lsbGV5IHkgUGFjZSB0YW1iacOpbiBzZcOxYWxhbiBxdWUgbGEgdmFyaWFibGUgYE1FRFZgIGVzdMOhIGNlbnN1cmFkYSwgZXMgZGVjaXIsIGxvcyB2YWxvcmVzIG1lZGlhbm9zIGlndWFsZXMgbyBzdXBlcmlvcmVzIGEgVVNEIDUwLDAwMCBzZSBlc3RhYmxlY2VuIGVuIFVTRCA1MCwwMDAuDQoNCkVzdGUgZGF0YSBmcmFtZSBjb250aWVuZSBsYXMgc2lndWllbnRlcyBjb2x1bW5hczoNCg0KLSBgVE9XTmA6IEZhY3RvciBjb24gbG9zIG5vbWJyZXMgZGUgbGFzIGxvY2FsaWRhZGVzLg0KDQotIGBUT1dOTk9gOiBWZWN0b3IgbnVtw6lyaWNvIGNvcnJlc3BvbmRpZW50ZSBhIGBUT1dOYC4NCg0KLSBgVFJBQ1RgOiBWZWN0b3IgbnVtw6lyaWNvIGNvbiBsb3MgaWRlbnRpZmljYWRvcmVzIGRlIGxvcyB0cmFtb3MgY2Vuc2FsZXMuDQoNCi0gYExPTmA6IExvbmdpdHVkIGRlbCBwdW50byBjZW50cmFsIGRlbCB0cmFtbyBjZW5zYWwgZW4gZ3JhZG9zIGRlY2ltYWxlcy4NCg0KLSBgTEFUYDogTGF0aXR1ZCBkZWwgcHVudG8gY2VudHJhbCBkZWwgdHJhbW8gY2Vuc2FsIGVuIGdyYWRvcyBkZWNpbWFsZXMuDQoNCi0gYE1FRFZgOiBWYWxvciBtZWRpYW5vIGRlIHZpdmllbmRhcyBvY3VwYWRhcyBwb3Igc3VzIHByb3BpZXRhcmlvcyBlbiBtaWxlcyBkZSBVU0QuDQoNCi0gYENNRURWYDogVmFsb3IgbWVkaWFubyBjb3JyZWdpZG8gZGUgdml2aWVuZGFzIG9jdXBhZGFzIHBvciBzdXMgcHJvcGlldGFyaW9zIGVuIG1pbGVzIGRlIFVTRC4NCg0KLSBgQ1JJTWA6IFRhc2EgZGUgY3JpbWluYWxpZGFkIHBlciBjw6FwaXRhLg0KDQotIGBaTmA6IFByb3BvcmNpw7NuIGRlIHRlcnJlbm8gcmVzaWRlbmNpYWwgem9uaWZpY2FkbyBwYXJhIGxvdGVzIG1heW9yZXMgYSAyNSwwMDAgcGllc8KyIChjb25zdGFudGUgcGFyYSB0b2RvcyBsb3MgdHJhbW9zIGRlIEJvc3RvbikuDQoNCi0gYElORFVTYDogUHJvcG9yY2nDs24gZGUgYWNyZXMgZGUgbmVnb2Npb3Mgbm8gbWlub3Jpc3RhcyBwb3IgbG9jYWxpZGFkIChjb25zdGFudGUgcGFyYSB0b2RvcyBsb3MgdHJhbW9zIGRlIEJvc3RvbikuDQoNCi0gYENIQVNgOiBGYWN0b3IgY29uIG5pdmVsZXM6IDEgc2kgZWwgdHJhbW8gY29saW5kYSBjb24gZWwgcsOtbyBDaGFybGVzOyAwIGVuIGNhc28gY29udHJhcmlvLg0KDQotIGBOT1hgOiBDb25jZW50cmFjacOzbiBkZSDDs3hpZG9zIG7DrXRyaWNvcyAocGFydGVzIHBvciAxMCBtaWxsb25lcykgcG9yIGxvY2FsaWRhZC4NCg0KLSBgUk1gOiBQcm9tZWRpbyBkZSBoYWJpdGFjaW9uZXMgcG9yIHZpdmllbmRhLg0KDQotIGBBR0VgOiBQcm9wb3JjacOzbiBkZSB1bmlkYWRlcyBvY3VwYWRhcyBwb3IgcHJvcGlldGFyaW9zIGNvbnN0cnVpZGFzIGFudGVzIGRlIDE5NDAuDQoNCi0gYERJU2A6IERpc3RhbmNpYXMgcG9uZGVyYWRhcyBhIGNpbmNvIGNlbnRyb3MgZGUgZW1wbGVvIGVuIEJvc3Rvbi4NCg0KLSBgUkFEYDogw41uZGljZSBkZSBhY2Nlc2liaWxpZGFkIGEgYXV0b3Bpc3RhcyByYWRpYWxlcyBwb3IgbG9jYWxpZGFkIChjb25zdGFudGUgcGFyYSB0b2RvcyBsb3MgdHJhbW9zIGRlIEJvc3RvbikuDQoNCi0gYFRBWGA6IFRhc2EgZGUgaW1wdWVzdG8gcHJlZGlhbCBwb3IgY2FkYSAxMCwwMDAgVVNEIGRlIHZhbG9yIGRlIHByb3BpZWRhZCAoY29uc3RhbnRlIHBhcmEgdG9kb3MgbG9zIHRyYW1vcyBkZSBCb3N0b24pLg0KDQotIGBQVFJBVElPYDogUmVsYWNpw7NuIGFsdW1uby9wcm9mZXNvciBwb3IgbG9jYWxpZGFkIChjb25zdGFudGUgcGFyYSB0b2RvcyBsb3MgdHJhbW9zIGRlIEJvc3RvbikuDQoNCi0gYEJgOiBDw6FsY3VsbyBkZSAxMDAwKihCayAtIDAuNjMpXjIsIGRvbmRlIGBCa2AgZXMgbGEgcHJvcG9yY2nDs24gZGUgcGVyc29uYXMgbmVncmFzLg0KDQotIGBMU1RBVGA6IFBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBkZSBtZW5vciBuaXZlbCBzb2Npb2Vjb27Ds21pY28uDQoNCmBgYHtyfQ0KZGF0YShib3N0b24sIHBhY2thZ2U9InNwRGF0YSIpDQpoZWFkKGJvc3Rvbi5jKQ0KZ2xpbXBzZShib3N0b24uYykNCmBgYA0KDQpTZWd1aWRhbWVudGUsIHNlIGNhcmdhbiBsYXMgZ2VvY2VyY2FzIGFzb2NpYWRhcyBhIGxhIGRhdGEgdHJhbnN2ZXJzYWwgcHJldmlhbWVudGUgY2FyZ2FkYQ0KYGBge3J9DQpib3N0b24udHI8LXN0X3JlYWQoc3lzdGVtLmZpbGUoInNoYXBlcy9ib3N0b25fdHJhY3RzLmdwa2ciLCBwYWNrYWdlPSJzcERhdGEiKVsxXSkNCmBgYA0KDQojIyBTdW1tYXJ5IEJvc3Rvbg0KYGBge3J9DQpib3N0b24udHJTUDwtYXMoYm9zdG9uLnRyLCAiU3BhdGlhbCIpDQpib3N0b25fbmI8LXBvbHkybmIoYm9zdG9uLnRyU1ApDQpzdW1tYXJ5KGJvc3Rvbi50clNQKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh0bWFwKQ0KDQp0bWFwX21vZGUoInZpZXciKSANCg0KdG1fc2hhcGUoYm9zdG9uLnRyKSArDQogIHRtX3BvbHlnb25zKGNvbCA9ICJncmF5OTAiLCBib3JkZXIuY29sID0gImJsYWNrIikgKw0KICB0bV90ZXh0KCJUT1dOIiwgc2l6ZSA9IDAuNSkgKw0KICB0bV9jb21wYXNzKHBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSkgKw0KICB0bV90aXRsZSgiRGlzdHJpdG9zIGRlIEJvc3RvbiAoVE9XTikiKQ0KYGBgDQoNCg0KIyMgSGlzdG9ncmFtYXMNCg0KRWwgZ3LDoWZpY28gcHJlc2VudGEgbG9zIGhpc3RvZ3JhbWFzIGRlIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyBkZWwgY29uanVudG8gZGUgZGF0b3MgZGUgQm9zdG9uLiBBIGNvbnRpbnVhY2nDs24gc2UgZGVzdGFjYW4gYWxndW5vcyBoYWxsYXpnb3MgY2xhdmU6DQoNCiogU2VzZ28gYSBsYSBkZXJlY2hhOiBWYXJpYWJsZXMgY29tbyBDUklNICh0YXNhIGRlIGNyaW1pbmFsaWRhZCksIERJUyAoZGlzdGFuY2lhIGEgY2VudHJvcyBsYWJvcmFsZXMpLCB5IFRBWCAodGFzYSBkZSBpbXB1ZXN0byBwcmVkaWFsKSBwcmVzZW50YW4gdW5hIGRpc3RyaWJ1Y2nDs24gYWx0YW1lbnRlIGFzaW3DqXRyaWNhLCBjb24gbGEgbWF5b3LDrWEgZGUgbGFzIG9ic2VydmFjaW9uZXMgY29uY2VudHJhZGFzIGVuIHZhbG9yZXMgYmFqb3MgeSBwb2NvcyB2YWxvcmVzIGV4dHJlbW9zIGFsdG9zLg0KDQoqIFZhcmlhYmxlcyBjZW5zdXJhZGFzOiBDTUVEViB5IE1FRFYgbXVlc3RyYW4gdW4gY2xhcm8gY29ydGUgZW4gZWwgdmFsb3IgbcOheGltbyBkZSA1MCwgbG8gY3VhbCByZWZsZWphIGxhIGNlbnN1cmEgc3VwZXJpb3IgaW1wdWVzdGEgZW4gZWwgY29uanVudG8gZGUgZGF0b3MuDQoNCiogRGlzdHJpYnVjaW9uZXMgYmltb2RhbGVzIG8gZGlzY3JldGFzOiBWYXJpYWJsZXMgY29tbyBSQUQgKGFjY2VzaWJpbGlkYWQgYSBhdXRvcGlzdGFzKSB5IFBUUkFUSU8gcHJlc2VudGFuIGRpc3RyaWJ1Y2lvbmVzIGNvbiB2YWxvcmVzIHJlcGV0aWRvcyBvIGFncnVwYW1pZW50b3MgZGlzY3JldG9zLg0KDQoqIE5vcm1hbGlkYWQgYXBhcmVudGU6IEFsZ3VuYXMgdmFyaWFibGVzIGNvbW8gUk0gKG7Dum1lcm8gcHJvbWVkaW8gZGUgaGFiaXRhY2lvbmVzIHBvciB2aXZpZW5kYSkgeSBMQVQvTE9OIChjb29yZGVuYWRhcyBnZW9ncsOhZmljYXMpIG11ZXN0cmFuIGRpc3RyaWJ1Y2lvbmVzIG3DoXMgY2VyY2FuYXMgYSB1bmEgZm9ybWEgbm9ybWFsIG8gc2ltw6l0cmljYS4NCg0KKiBDb25jZW50cmFjacOzbiBleHRyZW1hOiBaTiAoem9uaWZpY2FjacOzbiBwYXJhIHRlcnJlbm9zIHJlc2lkZW5jaWFsZXMgZ3JhbmRlcykgeSBCIChwcm9wb3JjacOzbiB0cmFuc2Zvcm1hZGEgZGUgcG9ibGFjacOzbiBuZWdyYSkgcHJlc2VudGFuIHVuYSBhbHRhIGNvbmNlbnRyYWNpw7NuIGRlIG9ic2VydmFjaW9uZXMgZW4gdW4gdmFsb3IgZXNwZWPDrWZpY28sIGxvIHF1ZSBpbmRpY2EgcG9jYSB2YXJpYWJpbGlkYWQgZW4gbXVjaGFzIHpvbmFzLg0KDQpEaWNobyBhbsOhbGlzaXMgcHJlbGltaW5hciBzdWdpZXJlIHF1ZSBzZXLDoSBuZWNlc2FyaW8gdHJhbnNmb3JtYXIgYWxndW5hcyB2YXJpYWJsZXMgcHJldmlvIGEgdXNhcmxhcyBlbiBtb2RlbG9zIGVzdGFkw61zdGljb3MuDQoNCmBgYHtyfQ0KYm9zdG9uLmMubnVtIDwtIGJvc3Rvbi5jICU+JSBzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpDQoNCmJvc3Rvbi5jLm51bSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJ2YWxvciIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB2YWxvcikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGNvbG9yID0gIndoaXRlIikgKw0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSArDQogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtYXMgZGUgVmFyaWFibGVzIE51bcOpcmljYXMiKQ0KYGBgDQoNCiMjIE1hdHJpeiBkZSBDb3JyZWxhY2nDs24NCg0KKipSZWxhY2lvbmVzIGNvbiBlbCB2YWxvciBkZSBsYSB2aXZpZW5kYSAoTUVEViB5IENNRURWKToqKg0KDQoqIFJNIChoYWJpdGFjaW9uZXMgcG9yIHZpdmllbmRhKSB0aWVuZSB1bmEgZnVlcnRlIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBjb24gTUVEViAoMC43MCksIGxvIHF1ZSBzdWdpZXJlIHF1ZSBtw6FzIGhhYml0YWNpb25lcyBzZSBhc29jaWFuIGNvbiBtYXlvciB2YWxvciBkZSB2aXZpZW5kYS4NCg0KKiBMU1RBVCAocG9ibGFjacOzbiBkZSBtZW5vciBuaXZlbCBzb2Npb2Vjb27Ds21pY28pIHRpZW5lIHVuYSBmdWVydGUgY29ycmVsYWNpw7NuIG5lZ2F0aXZhIGNvbiBNRURWICgtMC43NCksIGluZGljYW5kbyBxdWUgem9uYXMgY29uIG1heW9yIHByb3BvcmNpw7NuIGRlIHBlcnNvbmFzIGRlIGJham9zIGluZ3Jlc29zIHRpZW5kZW4gYSB0ZW5lciB2aXZpZW5kYXMgbcOhcyBiYXJhdGFzLg0KDQpUYW1iacOpbiBoYXkgdW5hIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBub3RhYmxlIGNvbiBOT1ggKC0wLjQzKSB5IFBUUkFUSU8gKC0wLjUxKSwgbG8gcXVlIHN1Z2llcmUgcXVlIGFsdG9zIG5pdmVsZXMgZGUgY29udGFtaW5hY2nDs24geSB1bmEgbWF5b3IgcHJvcG9yY2nDs24gYWx1bW5vL3Byb2Zlc29yIHNlIHJlbGFjaW9uYW4gY29uIG1lbm9yZXMgdmFsb3JlcyBkZSB2aXZpZW5kYS4NCg0KDQoqKkNvbnRhbWluYWNpw7NuIHkgdXJiYW5pemFjacOzbjoqKg0KDQoqIE5PWCBlc3TDoSBmdWVydGVtZW50ZSBjb3JyZWxhY2lvbmFkbyBjb24gSU5EVVMgKDAuNzYpIHkgQUdFICgwLjczKSwgbG8gY3VhbCB0aWVuZSBzZW50aWRvLCB5YSBxdWUgbGFzIHpvbmFzIG3DoXMgaW5kdXN0cmlhbGVzIHkgY29uIGNvbnN0cnVjY2lvbmVzIG3DoXMgYW50aWd1YXMgc3VlbGVuIHRlbmVyIG3DoXMgY29udGFtaW5hY2nDs24uDQoNClRhbWJpw6luIGVzdMOhIG5lZ2F0aXZhbWVudGUgY29ycmVsYWNpb25hZG8gY29uIERJUyAoLTAuNzcpLCBsbyBxdWUgaW5kaWNhIHF1ZSB6b25hcyBtw6FzIGNlcmNhbmFzIGEgbG9zIGNlbnRyb3MgdXJiYW5vcyAobWVub3IgZGlzdGFuY2lhKSBwcmVzZW50YW4gbWF5b3IgY29udGFtaW5hY2nDs24uDQoNCg0KKipJbmZyYWVzdHJ1Y3R1cmEgeSB6b25pZmljYWNpw7NuOioqDQoNCiogUkFEIHkgVEFYIHRpZW5lbiB1bmEgY29ycmVsYWNpw7NuIG11eSBhbHRhICgwLjkxKSwgbG8gcXVlIHN1Z2llcmUgcXVlIGxhcyDDoXJlYXMgY29uIG1lam9yIGFjY2VzbyBhIGF1dG9waXN0YXMgdGllbmRlbiBhIHRlbmVyIGltcHVlc3RvcyBwcmVkaWFsZXMgbcOhcyBhbHRvcy4NCg0KKiBaTiB0aWVuZSBjb3JyZWxhY2lvbmVzIG5lZ2F0aXZhcyBjb24gdmFyaWFibGVzIGNvbW8gSU5EVVMsIE5PWCB5IENSSU0sIGxvIHF1ZSBzdWdpZXJlIHF1ZSBsYXMgw6FyZWFzIGNvbiBtw6FzIHpvbmlmaWNhY2nDs24gcmVzaWRlbmNpYWwgc29uIG1lbm9zIGluZHVzdHJpYWxlcywgbWVub3MgY29udGFtaW5hZGFzIHkgbcOhcyBzZWd1cmFzLg0KDQoNCmBgYHtyfQ0KbGlicmFyeShjb3JycGxvdCkNCg0KbWF0X2NvciA8LSBjb3IoYm9zdG9uLmMubnVtLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KY29ycnBsb3QobWF0X2NvciwgbWV0aG9kID0gImNvbG9yIiwgdHlwZSA9ICJ1cHBlciIsIA0KICAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSgyMDApLA0KICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gNDUsIA0KICAgICAgICAgdGl0bGUgPSAiTWF0cml6IGRlIENvcnJlbGFjaW9uZXMiLCBtYXIgPSBjKDAsMCwxLDApKQ0KDQpjb3JycGxvdChtYXRfY29yLCBtZXRob2QgPSAibnVtYmVyIiwgdHlwZSA9ICJ1cHBlciIsIA0KICAgICAgICAgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gNDUsDQogICAgICAgICB0aXRsZSA9ICJNYXRyaXogZGUgQ29ycmVsYWNpb25lcyAoY29uIHZhbG9yZXMpIiwgbWFyID0gYygwLDAsMSwwKSkNCg0KYGBgDQoNCiMjIyBDb3JyZWxhY2nDs24gY29uIHZhcmlhYmxlIENSSU1FDQoNCkVuIGVzdGUgY2FzbywgbGEgdmFyaWFibGUgQ1JJTUUgc2Vyw6EgbnVlc3RyYSB2YXJpYWJsZSB5LCBhbnRlIGxvIGN1YWwsIHNlIGRldGVybWluYSBxdWUgdGllbmUgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBtb2RlcmFkYSBjb24gVEFYLCBSQUQgeSBQVFJBVElPLCB5IG5lZ2F0aXZhIGNvbiBaTiB5IERJUywgbG8gcXVlIGluZGljYSBxdWUgw6FyZWFzIGNvbiBtYXlvciBpbmZyYWVzdHJ1Y3R1cmEgbyBtZW5vciBwbGFuaWZpY2FjacOzbiByZXNpZGVuY2lhbCB0aWVuZGVuIGEgdGVuZXIgbWF5b3IgY3JpbWVuLg0KDQpgYGB7cn0NCm1hdF9jb3IgPC0gY29yKGJvc3Rvbi5jLm51bSwgdXNlID0gImNvbXBsZXRlLm9icyIpDQoNCmNvcl9jcmltIDwtIG1hdF9jb3JbIkNSSU0iLCBdDQoNCnNvcnQoY29yX2NyaW0sIGRlY3JlYXNpbmcgPSBUUlVFKQ0KY29ycnBsb3QobWF0X2NvclsiQ1JJTSIsICwgZHJvcCA9IEZBTFNFXSwgaXMuY29yciA9IEZBTFNFLA0KICAgICAgICAgbWV0aG9kID0gIm51bWJlciIsIHRsLmNvbCA9ICJibGFjayIsIHRpdGxlID0gIkNvcnJlbGFjacOzbiBkZSBDUklNIGNvbiBvdHJhcyB2YXJpYWJsZXMiLA0KICAgICAgICAgbWFyID0gYygwLDAsMiwwKSkNCmBgYA0KDQojIyBCb3hwbG90cw0KDQoqKlZhcmlhYmxlcyBjb24gYWx0YSBkaXNwZXJzacOzbiB5IG91dGxpZXJzIG5vdGFibGVzOioqDQoNCiogQ1JJTSAoY3JpbWluYWxpZGFkKSwgRElTIChkaXN0YW5jaWEgYSBjZW50cm9zIGxhYm9yYWxlcykgeSBCIChwcm9wb3JjacOzbiBkZSBwZXJzb25hcyBuZWdyYXMpIG11ZXN0cmFuIG11Y2hvcyB2YWxvcmVzIGF0w61waWNvcyAocHVudG9zIHJvam9zKSwgbG8gcXVlIHN1Z2llcmUgdW5hIGdyYW4gdmFyaWFiaWxpZGFkIGVudHJlIHpvbmFzLg0KDQoqIFpOLCBSQUQsIHkgSU5EVVMgdGFtYmnDqW4gcHJlc2VudGFuIGNvbmNlbnRyYWNpw7NuIGRlIHZhbG9yZXMgZXh0cmVtb3MsIGxvIGN1YWwgZXMgZXNwZXJhYmxlIGRhZG8gcXVlIHNvbiB2YXJpYWJsZXMgcmVsYWNpb25hZGFzIGNvbiB6b25pZmljYWNpw7NuIG8gaW5mcmFlc3RydWN0dXJhIHVyYmFuYS4NCg0KKipWYXJpYWJsZXMgZnVlcnRlbWVudGUgc2VzZ2FkYXM6KioNCg0KKiBaTiB5IENSSU0gcGFyZWNlbiB0ZW5lciB1bmEgYXNpbWV0csOtYSBwb3NpdGl2YSAoY29sYSBsYXJnYSBhIGxhIGRlcmVjaGEpLCBpbmRpY2FuZG8gcXVlIGxhIG1heW9yw61hIGRlIGxvcyB0cmFtb3MgY2Vuc2FsZXMgdGllbmVuIHZhbG9yZXMgYmFqb3MsIHBlcm8gdW5vcyBwb2NvcyB0aWVuZW4gdmFsb3JlcyBtdXkgYWx0b3MuDQoNCiogQiBlc3TDoSBmdWVydGVtZW50ZSBzZXNnYWRhIGNvbiB2YWxvcmVzIG3DoXhpbW9zIGFncnVwYWRvcyBjZXJjYSBkZWwgdG9wZS4NCg0KKipWYXJpYWJsZXMgbcOhcyBjb25jZW50cmFkYXMgKGJhamEgZGlzcGVyc2nDs24geSBwb2NvcyBvdXRsaWVycyk6KioNCg0KKiBSTSAoaGFiaXRhY2lvbmVzKSB5IFBUUkFUSU8gKGFsdW1ub3MvcHJvZmVzb3IpIHRpZW5lbiB1bmEgZGlzdHJpYnVjacOzbiBiYXN0YW50ZSBlc3RyZWNoYSwgbG8gcXVlIGluZGljYSBxdWUgZXNhcyB2YXJpYWJsZXMgc29uIG3DoXMgaG9tb2fDqW5lYXMgZW50cmUgbG9jYWxpZGFkZXMuDQoNCioqSW1wdWVzdG9zIChUQVgpIHkgdHJhbW9zIGNlbnNhbGVzIChUUkFDVCk6KioNCg0KKiBUQVggdGllbmUgdW5hIGRpc3RyaWJ1Y2nDs24gYmFzdGFudGUgYW1wbGlhLCBsbyBjdWFsIHN1Z2llcmUgZGlmZXJlbmNpYXMgaW1wb3J0YW50ZXMgZW4gcG9sw610aWNhIGZpc2NhbCBlbnRyZSBsb2NhbGlkYWRlcy4NCg0KKiBUUkFDVCBtdWVzdHJhIGFtcGzDrXNpbWEgdmFyaWFjacOzbiwgcGVybyBjb21vIGVzIHVuIGlkZW50aWZpY2Fkb3IsIGVzdGEgZGlzcGVyc2nDs24gbm8gaW1wbGljYSB1biBwYXRyw7NuIMO6dGlsIGRpcmVjdGFtZW50ZSwgc2lubyBxdWUgZGViZSB0cmF0YXJzZSBjb21vIHZhcmlhYmxlIGNhdGVnw7NyaWNhIG8gZGUgbG9jYWxpemFjacOzbi4NCg0KKipWYWxvciBkZSB2aXZpZW5kYSAoTUVEViB5IENNRURWKToqKg0KDQoqIEFtYmFzIHByZXNlbnRhbiBvdXRsaWVycyBwb3IgYXJyaWJhLCBsbyBxdWUgc3VnaWVyZSBwcmVzZW5jaWEgZGUgem9uYXMgY29uIHZpdmllbmRhcyBzaWduaWZpY2F0aXZhbWVudGUgbcOhcyBjYXJhcyBxdWUgZWwgcHJvbWVkaW8sIGF1bnF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgdmFsb3JlcyBlc3TDoW4gYWdydXBhZG9zIGVuIHVuIHJhbmdvIGVzdHJlY2hvLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpib3N0b24uYy5udW0gJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJ2YXJpYWJsZSIsIHZhbHVlc190byA9ICJ2YWxvciIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSAiIiwgeSA9IHZhbG9yKSkgKyAgIyB4IHZhY8OtbyBwb3JxdWUgbm8gaGF5IGNhdGVnb3LDrWFzIGludGVybmFzDQogIGdlb21fYm94cGxvdChmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gImRhcmtibHVlIiwgb3V0bGllci5jb2xvciA9ICJyZWQiLCBvdXRsaWVyLnNoYXBlID0gMTYpICsNCiAgZmFjZXRfd3JhcCh+IHZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZV95IikgKyAgIyBmYWNldGFzIHBvciB2YXJpYWJsZSBjb24gZXNjYWxhIGxpYnJlIGVuIFkNCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90cyBwb3IgVmFyaWFibGUgTnVtw6lyaWNhIiwNCiAgICAgICB4ID0gTlVMTCwNCiAgICAgICB5ID0gIlZhbG9yIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQoNCg0KIyAqKkFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgRGF0b3MgRXNwYWNpYWxlcyAoRVNEQTogRXhwbG9yYXRvcnkgU3BhdGlhbCBEYXRhIEFuYWx5c2lzKSoqDQoNCiMjIE1hdHJpeiBkZSBDb25lY3RpdmlkYWQgRXNwYWNpYWwNCg0KU2UgY3JlYSBtYXRyaXogZGUgY29uZWN0aXZpZGFkIGVzcGFjaWFsIG8gbGlzdGEgZGUgdmVjaW5vcyBlbnRyZSBwb2zDrWdvbm9zIHBhcmEgbG8gY3VhbCBzZSB1c2EgZWwgcGFyw6FtZXRybyBkZSBRVUVFTiBwYXJhIGRlZmluaXIgbGEgdmVjaW5kYWQsIGVuIGTDs25kZSBzZSB0b21hcsOhbiBlbiBjdWFlbnRhIHNpIGRvcyBwb2zDrWdvbm9zIHNvbiB2ZWNpbm9zIG8sIHNpIGNvbXBhcnRlbiB1biBib3JkZSBvIHVuIHB1bnRvIChoYWNlIGxhIGNlcmNhbsOtYSBtw6FzIGluY2x1c2l2YSkuDQoNCkNvbiBiYXNlIGVuIGVsIHN1bW1hcnkgb2J0ZW5lbW9zIGxvIHNpZ3VpZW50ZToNCg0KKiBIYXkgNTA2IHBvbMOtZ29ub3MgKDUwNiBsb2NhbGlkYWRlcyBlbiBCb3N0b24pLg0KDQoqIEhheSAyOTEwIGNvbmV4aW9uZXMgZGUgdmVjaW5kYWQgZW50cmUgZWxsb3MuDQoNCiogUHJvcG9yY2nDs24gZGUgcGFyZXMgdmVjaW5vcyBjb24gcmVsYWNpw7NuIGFsIHRvdGFsIHBvc2libGUgPSAxLjE0DQoNCiogQ2FkYSBlc3RhZG8gdGllbmUsIGVuIHByb21lZGlvLCA1Ljc1IHZlY2lub3MNCg0KKiBTw7NsbyB0cmVzIGxvY2FsaWRhZGVzIHRpZW5lbiAxIHZlY2lubzogKkJvc3RvbiBOb3J0aCBFbmQsIEJvc3RvbiBCZWFjb24gSGlsbCB5IEJlZGZvcmQqDQoNCiogU8OzbG8gMSBsb2NhbGlkYWQgZXN0w6EgY29uZWN0YWRhIGNvbiAxNSB2ZWNpbm9zOiAqQm9zdG9uIE1hdHRhcGFuKg0KDQpgYGB7cn0NCmJvc3Rvbl9uYiA8LSBwb2x5Mm5iKGJvc3Rvbi50clNQLCBxdWVlbiA9IFRSVUUpDQpzdW1tYXJ5KGJvc3Rvbl9uYikNCmBgYA0KDQojIyMgQ29uZXhpb25lcyBlbnRyZSBhcmVhcw0KYGBge3J9DQpib3N0b24udHJTUCRUT1dOWzExMl0gICAjIEFyZWEgbcOhcyBjb25lY3RhZGEgKGNvbiAxNSB2ZWNpbm9zKQ0KYm9zdG9uLnRyU1AkVE9XTltjKDE4LCAxNSwgMzQ1KV0gICMgQXJlYXMgbWVub3MgY29uZWN0YWRhcyAoY29uIDEgdmVjaW5vKQ0KYGBgDQoNCmBgYHtyfQ0KIyBTZSBtdWVzdHJhbiBsYXMgOSBjb25leGlvbmVzIGRlbCBhcmVhIGNvbiBtYXlvciBuw7ptZXJvIGRlIGNvbmV4aW9uZXMsIGVzIGRlY2lyLCBkZSBCb3N0b24gTWF0dGFwYW4NCmJvc3Rvbl9uYltbMTEyXV0NCiMgTGlzdGFkbyBkZSBsb2NhbGlkYWRlcyBjb25lY3RhZG9zIGNvbiBCb3N0b24gTWF0dGFwYW4NCmJvc3Rvbi50clNQJFRPV05bYm9zdG9uX25iW1sxMTJdXV0NCmBgYA0KDQoNCiMjIFZpc3VhbGl6YWNpw7NuIEdyw6FmaWNhIGRlIGxhIG1hdHJpeiBkZSBjb25lY3RpdmlkYWQgKFZlY2luZGFkZXMgZXN0aWxvIOKAmFJlaW5h4oCZKQ0KYGBge3J9DQpib3N0b25fbGlzdHcgPC0gbmIybGlzdHcoYm9zdG9uX25iLCBzdHlsZSA9ICJXIiwgemVyby5wb2xpY3kgPSBUUlVFKQ0KDQpjZW50cm9pZHMgPC0gY29vcmRpbmF0ZXMoYm9zdG9uLnRyU1ApDQpwbG90KGJvc3Rvbi50clNQLCBib3JkZXIgPSAiYmx1ZSIsIGF4ZXMgPSBGQUxTRSwgbGFzID0gMSwgbWFpbiA9ICJCb3N0b24gVHJhY3RzIC0gUXVlZW4gQ29udGlndWl0eSIpDQpwbG90KGJvc3Rvbi50clNQLCBjb2wgPSAibGlnaHRncmV5IiwgYm9yZGVyID0gZ3JleSgwLjkpLCBhZGQgPSBUUlVFKQ0KcGxvdChib3N0b25fbGlzdHcsIGNvb3JkcyA9IGNlbnRyb2lkcywgcGNoID0gMTksIGNleCA9IDAuMSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUpDQpgYGANCg0KIyMjIENSSU1FDQogDQpgYGB7cn0NCmJvc3Rvbi50cl9jbGVhbiA8LSBuYS5vbWl0KGJvc3Rvbi50cikNCmJvc3Rvbi50clNQPC1hcyhib3N0b24udHIsICJTcGF0aWFsIikNCmJvc3Rvbl9uYjwtcG9seTJuYihib3N0b24udHJTUCkNCm1hcHZpZXcoYm9zdG9uLnRyU1AsIHpjb2w9IkNSSU0iLCBjb2wucmVnaW9ucyA9IHZpcmlkaXNMaXRlOjptYWdtYSgyMCkpDQpgYGANCg0KDQoNCiMjIyBFbGVjY2nDs24gZGUgdmFyaWFibGVzIGV4cGxpY2F0aXZhcw0KDQpDb24gYmFzZSBlbiBsYSBjb21iaW5hY2nDs24gZGUgdmFyaWFibGVzIHJlYWxpemFkYSBwb3IgbGEgcmVncmVzacOzbiBzdGVwd2lzZSwgbGEgbWF0cml6IGRlIGNvcnJlbGFjacOzbiBjb24gQ1JJTSB5IGxhIHNpZ25pZmljYW5jaWEgZGUgY2FkYSB2YXJpYWJsZSBzZWfDum4gZW4gcmFuZG9tIGZvcmVzdCwgc2UgZGV0ZXJtaW5hIHF1ZSBsYXMgcHJpbmNpcGFsZXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyBhIHV0aWxpemFyIHkgcXVlIGNvbnZpZW5lIHJlemFnYXIgZXNwYWNpYWxtZW50ZSBzb246IA0KDQoqKk1FRFY6KioNCg0KKiBUaWVuZSB1bmEgY29ycmVsYWNpw7NuIGNvbiBDUklNIGRlIC0wLjM5LCByZWZsZWphIHF1ZSBlbCB2YWxvciBkZSB2aXZpZW5kYSBtw6FzIGFsdG8gcmVkdWNlIGNyaW1lbiAocmVsYWNpw7NuIG5lZ2F0aXZhKS4NCg0KKiBBIG1heW9yIHZhbG9yIGRlIGxhIHZpdmllbmRhLCBtZW5vciBjcmltZW4uIFJlc3VsdGFkbyBlc3BlcmFkbyB5IHNpZ25pZmljYXRpdm8uIFJlbGFjacOzbiBjbGFyYSB5IGFsdGFtZW50ZSBzaWduaWZpY2F0aXZhIChwIDwgMC4wMDEpLg0KDQoqICBTdSBhbHRhIGltcG9ydGFuY2lhIGNvbW8gcHJlZGljdG9yIGluZGljYSBxdWUgZWwgdmFsb3IgbWVkaWFubyBkZSBsYXMgdml2aWVuZGFzIGVuIHVuIMOhcmVhIGVzdMOhIGZ1ZXJ0ZW1lbnRlIGFzb2NpYWRvIGNvbiBsYXMgb3RyYXMgY2FyYWN0ZXLDrXN0aWNhcyBjb25zaWRlcmFkYXMuDQoNCg0KKipESVMqKg0KDQoqIFRpZW5lIGNvcnJlbGFjacOzbiBkZSAtMC4zOCwgbG8gcXVlIHB1ZWRlIGltcGxpY2FyIHF1ZSBhIG1heW9yIGRpc3RhbmNpYSBhIGNlbnRyb3MgbGFib3JhbGVzID0gbWVub3MgY3JpbWVuLg0KDQoqIEEgbWF5b3IgZGlzdGFuY2lhIGEgY2VudHJvcyBsYWJvcmFsZXMsIG1lbm9yIGNyaW1lbjsgYWRlbcOhcyBlcyBtdXkgc2lnbmlmaWNhdGl2byAocCA8IDAuMDAxKS4NCg0KKiAgU3UgYWx0YSBpbXBvcnRhbmNpYSBlbiBhbWJhcyBtw6l0cmljYXMgKCVJbmNNU0UgZSBJbmNOb2RlUHVyaXR5KSBpbmRpY2EgcXVlIGxhIGNlcmNhbsOtYSBhIGxvcyBjZW50cm9zIGRlIGVtcGxlbyBlcyB1biBmYWN0b3IgY3J1Y2lhbCBwYXJhIHByZWRlY2lyIENSSU0uDQoNCg0KIyMjIyBWQVJJbXBvcnRhbmNlDQoNCkVuIHJlc3VtZW4sIGNvbnNpZGVyYW5kbyBhbWJhcyBncsOhZmljYXMsIGFsZ3VuYXMgZGUgbGFzIHZhcmlhYmxlcyBxdWUgY29uc2lzdGVudGVtZW50ZSBhcGFyZWNlbiBjb21vIGltcG9ydGFudGVzIHNvbjoNCg0KKiBMU1RBVDogUG9yY2VudGFqZSBkZSBlc3RhdHVzIGJham8gZGUgbGEgcG9ibGFjacOzbi4NCg0KKiBSTTogTsO6bWVybyBwcm9tZWRpbyBkZSBoYWJpdGFjaW9uZXMgcG9yIHZpdmllbmRhLg0KDQoqIERJUzogRGlzdGFuY2lhcyBwb25kZXJhZGFzIGEgY2luY28gY2VudHJvcyBkZSBlbXBsZW8gZGUgQm9zdG9uLg0KDQoqIFJBRDogw41uZGljZSBkZSBhY2Nlc2liaWxpZGFkIGEgY2FycmV0ZXJhcyByYWRpYWxlcy4NCg0KKiBDTUVEViAvIE1FRFY6IFZhbG9yIG1lZGlhbm8gZGUgbGFzIHZpdmllbmRhcyBvY3VwYWRhcyBwb3Igc3VzIGR1ZcOxb3MgKHBvZHLDrWFuIHNlciBsYSBtaXNtYSB2YXJpYWJsZSBvIHVuYSB0cmFuc2Zvcm1hY2nDs24pLg0KDQoqIEI6IDEwMDAoQmviiJIwLjYzKSBkb25kZSBCayBlcyBsYSBwcm9wb3JjacOzbiBkZSBhZnJvYW1lcmljYW5vcyBwb3IgY2l1ZGFkLg0KICANCmBgYHtyfQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQoNCnNldC5zZWVkKDEyMykNCm1vZGVsb19yZiA8LSByYW5kb21Gb3Jlc3QoQ1JJTSB+IC4sIGRhdGEgPSBib3N0b24uYy5udW0sIGltcG9ydGFuY2UgPSBUUlVFLCBudHJlZSA9IDUwMCkNCg0KdmFySW1wUGxvdChtb2RlbG9fcmYpDQpgYGANCg0KDQojIyMjIFJlZ3Jlc2nDs24gU3RlcHdpc2UNCg0KRWwgbW9kZWxvIGluY2x1eWUgOCB2YXJpYWJsZXMgZXhwbGljYXRpdmFzIGRlIGVudHJlIGxhcyAxMiBwb3NpYmxlcyBxdWUgc2UgaW50ZWdyYXJvbiBpbmljaWFsbWVudGUuIFNlIGVsaWdpZXJvbiBwb3IgYmFsYW5jZWFyIGNhbGlkYWQgZGVsIGFqdXN0ZSB5IHNpbXBsaWNpZGFkIGRlbCBtb2RlbG8gKGNyaXRlcmlvIEFJQykuDQoNCiogUkFECSgrMC41Myk6CUEgbWF5b3IgYWNjZXNvIGEgYXV0b3Bpc3RhcywgbWF5b3IgY3JpbWVuLiBSZWxhY2nDs24gY2xhcmEgeSBhbHRhbWVudGUgc2lnbmlmaWNhdGl2YSAocCA8IDAuMDAxKS4NCg0KKiBMU1RBVAkoKzAuMTEpOglBIG1heW9yICUgZGUgcG9ibGFjacOzbiB2dWxuZXJhYmxlLCBtYXlvciBjcmltZW4uIE5vIGVzIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdm8gKHAgPSAwLjExKS4NCg0KKiBaTiAoKzAuMDQzKTogTWF5b3IgcHJvcG9yY2nDs24gZGUgem9uYXMgcmVzaWRlbmNpYWxlcyBwYXJlY2UgYXNvY2lhcnNlIGEgbcOhcyBjcmltZW4uDQoNCiogRElTCSjigJMwLjkxKToJTWF5b3IgZGlzdGFuY2lhIGEgY2VudHJvcyBsYWJvcmFsZXMsIG1lbm9yIGNyaW1lbi4gTXV5IHNpZ25pZmljYXRpdm8uDQoNCiogTUVEVgko4oCTMC4xNyk6CUEgbWF5b3IgdmFsb3IgZGUgbGEgdml2aWVuZGEsIG1lbm9yIGNyaW1lbi4gUmVzdWx0YWRvIGVzcGVyYWRvIHkgc2lnbmlmaWNhdGl2by4NCg0KKiBOT1gJKOKAkzEyLjc1KToJTWVub3IgY2FsaWRhZCBkZWwgYWlyZSAobWF5b3IgTk9YKSwgbWVub3IgY3JpbWVuIChhbGdvIGNvbnRyYWludHVpdGl2bywgYXVucXVlIGVzIHBvc2libGUgY29saW5lYWxpZGFkKS4NCg0KKiBQVFJBVElPCSjigJMwLjMxKToJQSBtYXlvciByYXRpbyBhbHVtbm8tcHJvZmVzb3IsIG1lbm9yIGNyaW1lbi4gTWFyZ2luYWxtZW50ZSBzaWduaWZpY2F0aXZvIChwIH4gMC4wOSkuDQoNCiogQgko4oCTMC4wMDc5KToJQSBtYXlvciBwb2JsYWNpw7NuIGRlIHBlcnNvbmFzIG5lZ3JhcyAoQiksIG1lbm9yIGNyaW1lbi4gU2luIGVtYmFyZ28sIGVzdGEgdmFyaWFibGUgc3VlbGUgZXN0YXIgY29ycmVsYWNpb25hZGEgY29uIG90cmFzIGNvbmRpY2lvbmVzIGVzdHJ1Y3R1cmFsZXMuDQoNCg0KYGBge3J9DQpib3N0b25fc2YgPC0gc3RfYXNfc2YoYm9zdG9uLnRyU1ApDQoNCm1vZGVsb19mdWxsIDwtIGxtKENSSU0gfiBSQUQgKyBUQVggKyBMU1RBVCArIFpOICsgSU5EVVMgKyBESVMgKyBBR0UgKyBNRURWKyBOT1ggKyBSTSArIFBUUkFUSU8gKyBCLCBkYXRhID0gYm9zdG9uX3NmKQ0KDQojIFN0ZXB3aXNlIHJlZ3Jlc2nDs24gdXNhbmRvIEFJQw0KbW9kZWxvX3N0ZXAgPC0gc3RlcChtb2RlbG9fZnVsbCwgZGlyZWN0aW9uID0gImJvdGgiKQ0KDQpzdW1tYXJ5KG1vZGVsb19zdGVwKQ0KYGBgDQoNCg0KIyMjIE1FRFYgeSBESVMNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodG1hcCkNCiMgQ2FsY3VsYXIgcmV6YWdvIGVzcGFjaWFsIGRlIE1FRFYNCmJvc3Rvbl9zZiRzcF9sYWdfTUVEViA8LSBsYWcubGlzdHcoYm9zdG9uX2xpc3R3LCBib3N0b25fc2YkTUVEViwgemVyby5wb2xpY3kgPSBUUlVFKQ0KDQojIENhbGN1bGFyIHJhbmdvcyBjb211bmVzIHBhcmEgdW5hIGVzY2FsYSBjb250aW51YSBjb21wYXJ0aWRhDQptZWR2X3JhbmdlIDwtIHJhbmdlKGMoYm9zdG9uX3NmJE1FRFYsIGJvc3Rvbl9zZiRzcF9sYWdfTUVEViksIG5hLnJtID0gVFJVRSkNCm1lZHZfYnJlYWtzIDwtIHNlcShtZWR2X3JhbmdlWzFdLCBtZWR2X3JhbmdlWzJdLCBsZW5ndGgub3V0ID0gMTApDQoNCiMgTWFwYSBNRURWIG9yaWdpbmFsDQptZWR2X21hcCA8LSB0bV9zaGFwZShib3N0b25fc2YpICsgIA0KICB0bV9wb2x5Z29ucygNCiAgICBjb2wgPSAiTUVEViIsDQogICAgcGFsZXR0ZSA9ICJZbEduQnUiLA0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBtZWR2X2JyZWFrcywNCiAgICB0aXRsZSA9ICJNRURWIiwNCiAgICB0ZXh0TkEgPSAiIiwgICAgICMgT2N1bHRhciAiTWlzc2luZyINCiAgICBzaG93TkEgPSBGQUxTRSAgICMgRXhjbHVpciBOQSBkZSBsYSBsZXllbmRhDQogICkgKw0KICB0bV90aXRsZSgiVmFsb3IgVml2aWVuZGEgKE1FRFYpIikgKw0KICB0bV9sYXlvdXQoDQogICAgdGl0bGUucG9zaXRpb24gPSBjKCJyaWdodCIsICJ0b3AiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpLA0KICAgIHRpdGxlLnNpemUgPSAxDQogICkNCg0KIyBDYWxjdWxhciByYW5nb3MgY29tdW5lcyBwYXJhIHVuYSBlc2NhbGEgY29udGludWEgY29tcGFydGlkYQ0KZGlzX3JhbmdlIDwtIHJhbmdlKGMoYm9zdG9uX3NmJERJUywgYm9zdG9uX3NmJHNwX2xhZ19ESVMpLCBuYS5ybSA9IFRSVUUpDQpkaXNfYnJlYWtzIDwtIHNlcShkaXNfcmFuZ2VbMV0sIGRpc19yYW5nZVsyXSwgbGVuZ3RoLm91dCA9IDEwKQ0KDQojIE1hcGEgRElTIG9yaWdpbmFsDQpkaXNfbWFwIDwtIHRtX3NoYXBlKGJvc3Rvbl9zZikgKyAgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJESVMiLA0KICAgIHBhbGV0dGUgPSAiWWxPckJyIiwgICMgUGFsZXRhIG5hcmFuam9zYQ0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBkaXNfYnJlYWtzLA0KICAgIHRpdGxlID0gIkRJUyIsDQogICAgdGV4dE5BID0gIiIsICAgICAgICAjIE9jdWx0YSBldGlxdWV0YSAiTWlzc2luZyINCiAgICBzaG93TkEgPSBGQUxTRSAgICAgICMgRXhjbHV5ZSBOQSBkZSBsYSBsZXllbmRhDQogICkgKw0KICB0bV90aXRsZSgiRGlzdGFuY2lhIGEgQ2VudHJvcyAoRElTKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCnRtYXBfYXJyYW5nZShtZWR2X21hcCwgZGlzX21hcCwgbmNvbCA9IDEpDQoNCmBgYA0KDQoNCiMjIMONbmRpY2UgR2xvYmFsIGRlIE1vcmFuDQoNClRlw7NyaWNhbWVudGUgZWwgcmFuZ28gZGUgTW9yYW4gc2UgbXVlc3RyYSBlbnRyZSDigJMxIHkgKzEsIGVuIGTDs25kZTogDQoqICsxIEFsdGEgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBwb3NpdGl2YSAodmFsb3JlcyBzaW1pbGFyZXMgZXN0w6FuIGNlcmNhIGVudHJlIHPDrSkuICANCg0KKiAwIERpc3RyaWJ1Y2nDs24gYWxlYXRvcmlhIChubyBoYXkgcGF0csOzbiBlc3BhY2lhbCkuICANCg0KKiAtMSBBbHRhIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgbmVnYXRpdmEgKHZhbG9yZXMgZGlmZXJlbnRlcyBlc3TDoW4gY2VyY2EgZW50cmUgc8OtKS4gIA0KDQpBY29yZGUgYSBsbyBhbnRlcmlvciwgc2UgZ2VuZXJhIGNvZGlnbyBwYXJhIGRldGVybWluYXIgc2kgQ1JJTUUgdGllbmUgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCwgZXMgZGVjaXIsIHNpIGxhcyBhcmVhcyB5YSBzZWEgY29uIGFsdG8gbyBiYWpvIGNyaW1lbiB0aWVuZGVuIGEgZXN0YXIgY2VyY2EgdW5vcyBkZSBvdHJvcy4gVGFtYmnDqW4gc2UgYW5hbGl6YSBzaSBNRURWIHkvbyBESVMsIHRpZW5lbSBvIG5vIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwsIGVzIGRlY2lyLCBzaSBsYXMgbG9jYWxpZGFkZXMgeWEgc2VhIGNvbiBhbHRvIG8gYmFqbyBuaXZlbCB0aWVuZGVuIGEgZXN0YXIgY2VyY2EgdW5vcyBkZSBvdHJvcy4NCg0KYGBge3J9DQptb3Jhbi50ZXN0KGJvc3Rvbi50clNQJENSSU0sIGJvc3Rvbl9saXN0dykgIyBHbG9iYWwgTW9yYW4ncyBJIGlzIDAuNTI3IGFuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChwLXZhbHVlIDwgMTAlKS4NCm1vcmFuLnRlc3QoYm9zdG9uLnRyU1AkTUVEViwgYm9zdG9uX2xpc3R3KSAjIEdsb2JhbCBNb3JhbidzIEkgaXMgMC42MjcgYW5kIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAtdmFsdWUgPCAxMCUpLg0KbW9yYW4udGVzdChib3N0b24udHJTUCRESVMsIGJvc3Rvbl9saXN0dykgIyBHbG9iYWwgTW9yYW4ncyBJIGlzIDAuOTU2IGFuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChwLXZhbHVlIDwgMTAlKS4NCmBgYA0KDQoNCioqUHJlc2VudGFjacOzbiBkZSByZXN1bHRhZG9zKioNCg0KKkNyaW1lbiAoQ1JJTSkqICANClNlIGRldGVybWluYSBxdWUgc8OtIGV4aXN0ZSB1biBwYXRyw7NuIGVzcGFjaWFsIHNpZ25pZmljYXRpdm8gZW4gbGEgZGlzdHJpYnVjacOzbiBkZWwgY3JpbWVuIChDUklNKSBlbiBCb3N0b24uIExhcyDDoXJlYXMgY29uIHRhc2FzIHNpbWlsYXJlcyBkZSBjcmltZW4gZXN0w6FuIGVzcGFjaWFsbWVudGUgYWdydXBhZGFzLiBFbCAqKmNyaW1lbiBubyBlc3TDoSBkaXN0cmlidWlkYSBhbGVhdG9yaWFtZW50ZSoqOyBoYXkgYWdydXBhbWllbnRvcyBjbGFyb3MuICANCg0KKiBNb3JhbuKAmXMgSSA9ICowLjUyNyog4oaSIEhheSB1bmEgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBwb3NpdGl2YSBtb2RlcmFkYSBlbiBsb3MgdmFsb3JlcyBkZSBjcmltaW5hbGlkYWQsIGVzIGRlY2lyLCBsYXMgem9uYXMgY29uIGFsdGEgKG8gYmFqYSkgY3JpbWluYWxpZGFkIHRpZW5kZW4gYSBlc3RhciBjZXJjYSB1bmFzIGRlIG90cmFzLCBlbiBsdWdhciBkZSBkaXN0cmlidWlyc2UgYWxlYXRvcmlhbWVudGUgZW4gZWwgZXNwYWNpby4NCg0KKiBQLXZhbHVlID0gKjIuMmUtMTYqIOKGkiBFbCB2YWxvciBlcyBleHRyZW1hZGFtZW50ZSBzaWduaWZpY2F0aXZvLCBlcyBkZWNpciwgbGEgcHJvYmFiaWxpZGFkIGRlIG9ic2VydmFyIHVuIHZhbG9yIGRlIE1vcmFuJ3MgSSB0YW4gYWx0byBwb3IgcHVybyBhemFyIGVzIHZpcnR1YWxtZW50ZSBjZXJvLg0KDQoNCipWYWxvciBkZSB2aXZpZW5kYSAoTUVEVikqICANCkV4aXN0ZSB1biBwYXRyw7NuIGVzcGFjaWFsIGZ1ZXJ0ZS4gRWwgKip2YWxvciBkZSB2aXZpZW5kYSBubyBlc3TDoSBkaXN0cmlidWlkYSBhbGVhdG9yaWFtZW50ZSoqIHlhIHF1ZSwgZXhpc3RlbiBoYXkgYWdydXBhbWllbnRvcyBjbGFyb3MuICANCg0KKiBNb3JhbuKAmXMgSSA9ICowLjYyNyog4oaSIEV4aXN0ZSB1bmEgZnVlcnRlIGF1dG9jb3JyZWxhY2nDs24gZXNwYWNpYWwgcG9zaXRpdmEgZW4gbG9zIHZhbG9yZXMgZGUgbGEgdml2aWVuZGEuIFBvciBlbmRlLCBsb3MgdmVjaW5kYXJpb3MgY29uIHZpdmllbmRhcyBkZSBhbHRvIG8gYmFqbyB2YWxvciBzZSBhZ3J1cGFuIGdlb2dyw6FmaWNhbWVudGUsIGxvIGN1YWwgZXMgdW4gcGF0csOzbiBlc3BlcmFkbyBlbiBsYSByZWFsaWRhZCB1cmJhbmEgKHpvbmFzIGNhcmFzIHZzLiB6b25hcyBtw6FzIGFjY2VzaWJsZXMpLg0KDQoqIFAtdmFsdWUgPSAqMi4yZS0xNiog4oaSIFPDrSBlcyBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZvIChwPDAuMTApLiAgDQoNCg0KKkRpc3RhbmNpYSBhIGNlbnRyb3MgKERJUykqICANCkxhcyBkaXN0YW5jaWFzIHNlIGNvbXBvcnRhbiBjb21vIHVuYSB2YXJpYWJsZSBlc3BhY2lhbG1lbnRlIGVzdHJ1Y3R1cmFkYS4gTGEgKipkaXN0YW5jaWEgYSBjZW50cm9zIG5vIGVzdMOhIGRpc3RyaWJ1aWRhIGFsZWF0b3JpYW1lbnRlKiogeWEgcXVlLCBleGlzdGVuIGhheSBhZ3J1cGFtaWVudG9zIGNsYXJvcy4gIA0KDQoqIE1vcmFu4oCZcyBJID0gKjAuOTU2KiDihpIgSGF5IHVuYSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIGV4dHJlbWFkYW1lbnRlIGZ1ZXJ0ZS4gTGFzIGRpc3RhbmNpYXMgYSBsb3MgY2VudHJvcyBkZSBlbXBsZW8gZXN0w6FuIG11eSBhZ3J1cGFkYXMgZXNwYWNpYWxtZW50ZSwgZXMgZGVjaXIsIGhheSB6b25hcyBtdXkgY2VyY2FuYXMgbyBtdXkgbGVqYW5hcyBhIGxvcyBjZW50cm9zIGxhYm9yYWxlcyBxdWUgdGllbmRlbiBhIGVzdGFyIGp1bnRhcy4NCg0KKiBQLXZhbHVlID0gKjIuMmUtMTYqIOKGkiBTw60gZXMgZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2byAocDwwLjEwKS4NCg0KYGBge3J9DQp0YWJsZSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlID0gYygiQ1JJTSIsICJNRURWIiwgIkRJUyIpLCBHTSA9IGMoMC41MjcsIDAuNjI3LCAwLjk1NiksIFNpZ25pZmljYW5jZSA9IGMoIioqKiIsICIqKioiLCAiKioqIikpDQp0YWJsZQ0KYGBgDQoNCg0KIyAqKkFuw6FsaXNpcyBkZSBBdXRvY29ycmVsYWNpw7NuIEVzcGFjaWFsKioNCg0KIyMgTWFwYSBkZSBMYWcgRXNwYWNpYWwgQ1JJTQ0KDQpTZSByZWFsaXphIGPDoWxjdWxvIGRlIGxhZ3MgZGUgYWN1ZXJkbyBjb24gbGEgbWF0cml6IGRlIGNvbmVjdGl2aWRhZCBhbnRlcmlvcm1lbnRlIGNyZWFkYQ0KDQoNCmBgYHtyfQ0KIyBDYXJnYXIgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KHNwZGVwKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShzZikNCg0KIyBTaSBib3N0b24udHJTUCBlcyBkZSB0aXBvIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSwgY29udmnDqXJ0ZWxvIGEgc2YNCmJvc3Rvbl9zZiA8LSBzdF9hc19zZihib3N0b24udHJTUCkNCg0KIyBDcmVhciBvYmpldG8gZGUgdmVjaW5vcyAoUXVlZW4gY29udGlndWl0eSkNCmJvc3Rvbl9uYiA8LSBwb2x5Mm5iKGJvc3Rvbl9zZiwgcXVlZW4gPSBUUlVFKQ0KYm9zdG9uX2xpc3R3IDwtIG5iMmxpc3R3KGJvc3Rvbl9uYiwgc3R5bGUgPSAiVyIsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KIyBDYWxjdWxhciByZXphZ28gZXNwYWNpYWwgZGUgQ1JJTQ0KYm9zdG9uX3NmJHNwX2xhZ19DUklNIDwtIGxhZy5saXN0dyhib3N0b25fbGlzdHcsIGJvc3Rvbl9zZiRDUklNLCB6ZXJvLnBvbGljeSA9IFRSVUUpDQpgYGANCg0KU2UgcmVhbGl6YSBjw6FsY3VsbyBkZSByYW5nb3MgY29tdW5lcyB5IGdyYWZpY28gZGUgbWFwYSBkZSBDUklNIG9yaWdpbmFsIGNvbiBtYXBhIGRlIENSSU0tbGFnDQoNCmBgYHtyfQ0KIyBDYWxjdWxhciByYW5nb3MgY29tdW5lcyB5IGFqdXN0YXIgYnJlYWtzDQpjcmltX3JhbmdlIDwtIHJhbmdlKGMoYm9zdG9uX3NmJENSSU0sIGJvc3Rvbl9zZiRzcF9sYWdfQ1JJTSksIG5hLnJtID0gVFJVRSkNCmNyaW1fYnJlYWtzIDwtIHNlcShjcmltX3JhbmdlWzFdLCBjcmltX3JhbmdlWzJdLCBsZW5ndGgub3V0ID0gMTApDQoNCiMgTWFwYSBDUklNIG9yaWdpbmFsDQpjcmltX21hcCA8LSB0bV9zaGFwZShib3N0b25fc2YpICsgIA0KICB0bV9wb2x5Z29ucygNCiAgICBjb2wgPSAiQ1JJTSIsDQogICAgcGFsZXR0ZSA9ICJQdXJwbGVzIiwNCiAgICBzdHlsZSA9ICJmaXhlZCIsDQogICAgYnJlYWtzID0gY3JpbV9icmVha3MsDQogICAgdGl0bGUgPSAiQ1JJTSIsDQogICAgdGV4dE5BID0gIiIsICAgICAjIE9jdWx0YSBldGlxdWV0YSAiTWlzc2luZyINCiAgICBzaG93TkEgPSBGQUxTRSAgICMgRXhjbHV5ZSBOQSBkZSBsYSBsZXllbmRhDQogICkgKw0KICB0bV90aXRsZSgiVGFzYSBkZSBDcmltZW4gKENSSU0pIikgKw0KICB0bV9sYXlvdXQoDQogICAgdGl0bGUucG9zaXRpb24gPSBjKCJyaWdodCIsICJ0b3AiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKCJsZWZ0IiwgImJvdHRvbSIpLA0KICAgIHRpdGxlLnNpemUgPSAxDQogICkNCg0KIyBNYXBhIENSSU0gY29uIHJlemFnbyBlc3BhY2lhbA0KY3JpbV9sYWdfbWFwIDwtIHRtX3NoYXBlKGJvc3Rvbl9zZikgKyANCiAgdG1fcG9seWdvbnMoDQogICAgY29sID0gInNwX2xhZ19DUklNIiwNCiAgICBwYWxldHRlID0gIlB1cnBsZXMiLA0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBjcmltX2JyZWFrcywNCiAgICB0aXRsZSA9ICJDUklNIChMYWctMSkiLA0KICAgIHRleHROQSA9ICIiLA0KICAgIHNob3dOQSA9IEZBTFNFDQogICkgKw0KICB0bV90aXRsZSgiVGFzYSBkZSBDcmltZW4gUmV6YWdhZGEgKExhZy0xKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCiMgTW9zdHJhciBsb3MgbWFwYXMNCnRtYXBfYXJyYW5nZShjcmltX21hcCwgY3JpbV9sYWdfbWFwLCBuY29sID0gMSkNCmBgYA0KDQoNCiMjIE1hcGEgZGUgTGFnIEVzcGFjaWFsIE1FRFYNCg0KYGBge3J9DQojIENhbGN1bGFyIHJlemFnbyBlc3BhY2lhbCBkZSBNRURWDQpib3N0b25fc2Ykc3BfbGFnX01FRFYgPC0gbGFnLmxpc3R3KGJvc3Rvbl9saXN0dywgYm9zdG9uX3NmJE1FRFYsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KIyBDYWxjdWxhciByYW5nb3MgY29tdW5lcyBwYXJhIHVuYSBlc2NhbGEgY29udGludWEgY29tcGFydGlkYQ0KbWVkdl9yYW5nZSA8LSByYW5nZShjKGJvc3Rvbl9zZiRNRURWLCBib3N0b25fc2Ykc3BfbGFnX01FRFYpLCBuYS5ybSA9IFRSVUUpDQptZWR2X2JyZWFrcyA8LSBzZXEobWVkdl9yYW5nZVsxXSwgbWVkdl9yYW5nZVsyXSwgbGVuZ3RoLm91dCA9IDEwKQ0KDQojIE1hcGEgTUVEViBvcmlnaW5hbA0KbWVkdl9tYXAgPC0gdG1fc2hhcGUoYm9zdG9uX3NmKSArICANCiAgdG1fcG9seWdvbnMoDQogICAgY29sID0gIk1FRFYiLA0KICAgIHBhbGV0dGUgPSAiWWxHbkJ1IiwNCiAgICBzdHlsZSA9ICJmaXhlZCIsDQogICAgYnJlYWtzID0gbWVkdl9icmVha3MsDQogICAgdGl0bGUgPSAiTUVEViIsDQogICAgdGV4dE5BID0gIiIsICAgICAjIE9jdWx0YXIgIk1pc3NpbmciDQogICAgc2hvd05BID0gRkFMU0UgICAjIEV4Y2x1aXIgTkEgZGUgbGEgbGV5ZW5kYQ0KICApICsNCiAgdG1fdGl0bGUoIlZhbG9yIFZpdmllbmRhIChNRURWKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCiMgTWFwYSBNRURWIGNvbiByZXphZ28gZXNwYWNpYWwNCm1lZHZfbGFnX21hcCA8LSB0bV9zaGFwZShib3N0b25fc2YpICsgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJzcF9sYWdfTUVEViIsDQogICAgcGFsZXR0ZSA9ICJZbEduQnUiLA0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBtZWR2X2JyZWFrcywNCiAgICB0aXRsZSA9ICJNRURWIChMYWctMSkiLA0KICAgIHRleHROQSA9ICIiLA0KICAgIHNob3dOQSA9IEZBTFNFDQogICkgKw0KICB0bV90aXRsZSgiVmFsb3IgVml2aWVuZGEgUmV6YWdhZG8gKExhZy0xKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCiMgTW9zdHJhciBtYXBhcyBsYWRvIGEgbGFkbw0KdG1hcF9hcnJhbmdlKG1lZHZfbWFwLCBtZWR2X2xhZ19tYXAsIG5jb2wgPSAxKQ0KYGBgDQoNCg0KDQojIyBNYXBhIGRlIExhZyBFc3BhY2lhbCBESVMNCg0KYGBge3J9DQojIENhbGN1bGFyIHJlemFnbyBlc3BhY2lhbCBkZSBESVMNCmJvc3Rvbl9zZiRzcF9sYWdfRElTIDwtIGxhZy5saXN0dyhib3N0b25fbGlzdHcsIGJvc3Rvbl9zZiRESVMsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KIyBDYWxjdWxhciByYW5nb3MgY29tdW5lcyBwYXJhIHVuYSBlc2NhbGEgY29udGludWEgY29tcGFydGlkYQ0KZGlzX3JhbmdlIDwtIHJhbmdlKGMoYm9zdG9uX3NmJERJUywgYm9zdG9uX3NmJHNwX2xhZ19ESVMpLCBuYS5ybSA9IFRSVUUpDQpkaXNfYnJlYWtzIDwtIHNlcShkaXNfcmFuZ2VbMV0sIGRpc19yYW5nZVsyXSwgbGVuZ3RoLm91dCA9IDEwKQ0KDQojIE1hcGEgRElTIG9yaWdpbmFsDQpkaXNfbWFwIDwtIHRtX3NoYXBlKGJvc3Rvbl9zZikgKyAgDQogIHRtX3BvbHlnb25zKA0KICAgIGNvbCA9ICJESVMiLA0KICAgIHBhbGV0dGUgPSAiWWxPckJyIiwgICMgUGFsZXRhIG5hcmFuam9zYQ0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBkaXNfYnJlYWtzLA0KICAgIHRpdGxlID0gIkRJUyIsDQogICAgdGV4dE5BID0gIiIsICAgICAgICAjIE9jdWx0YSBldGlxdWV0YSAiTWlzc2luZyINCiAgICBzaG93TkEgPSBGQUxTRSAgICAgICMgRXhjbHV5ZSBOQSBkZSBsYSBsZXllbmRhDQogICkgKw0KICB0bV90aXRsZSgiRGlzdGFuY2lhIGEgQ2VudHJvcyAoRElTKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCiMgTWFwYSBESVMgY29uIHJlemFnbyBlc3BhY2lhbA0KZGlzX2xhZ19tYXAgPC0gdG1fc2hhcGUoYm9zdG9uX3NmKSArIA0KICB0bV9wb2x5Z29ucygNCiAgICBjb2wgPSAic3BfbGFnX0RJUyIsDQogICAgcGFsZXR0ZSA9ICJZbE9yQnIiLA0KICAgIHN0eWxlID0gImZpeGVkIiwNCiAgICBicmVha3MgPSBkaXNfYnJlYWtzLA0KICAgIHRpdGxlID0gIkRJUyAoTGFnLTEpIiwNCiAgICB0ZXh0TkEgPSAiIiwNCiAgICBzaG93TkEgPSBGQUxTRQ0KICApICsNCiAgdG1fdGl0bGUoIkRpc3RhbmNpYSBhIENlbnRyb3MgUmV6YWdhZGEgKExhZy0xKSIpICsNCiAgdG1fbGF5b3V0KA0KICAgIHRpdGxlLnBvc2l0aW9uID0gYygicmlnaHQiLCAidG9wIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSwNCiAgICB0aXRsZS5zaXplID0gMQ0KICApDQoNCiMgTW9zdHJhciBtYXBhcyBsYWRvIGEgbGFkbw0KdG1hcF9hcnJhbmdlKGRpc19tYXAsIGRpc19sYWdfbWFwLCBuY29sID0gMSkNCmBgYA0KDQoNCg0KIyMgU2NhdHRlcnBsb3QgTW9yYW4NCg0KTG9zIHRyZXMgZ3LDoWZpY29zIG11ZXN0cmFuIHF1ZSBDUklNLCBNRURWIHkgRElTIHByZXNlbnRhbiBwYXRyb25lcyBlc3BhY2lhbGVzIGVzdHJ1Y3R1cmFkb3MsIGxvIHF1ZSB0aWVuZSBpbXBsaWNhY2lvbmVzIGNsYXZlIHBhcmEgZWwgbW9kZWxhZG8gZXNwYWNpYWw6DQoNCiogTGEgY3JpbWluYWxpZGFkIG5vIGVzIGFsZWF0b3JpYSBlbiBlbCBlc3BhY2lvLiBFc3TDoSBpbmZsdWlkYSBwb3IgbG8gcXVlIG9jdXJyZSBlbiBsYXMgem9uYXMgdmVjaW5hcy4gUG9yIGxvIHRhbnRvLCBjdWFscXVpZXIgbW9kZWxvIHF1ZSBleHBsaXF1ZSBlbCBjcmltZW4gZGViZSBpbmNvcnBvcmFyIGRlcGVuZGVuY2lhIGVzcGFjaWFsLg0KDQoqIFZhcmlhYmxlcyBjb21vIE1FRFYgeSBESVMgZXN0w6FuIHRhbWJpw6luIGVzcGFjaWFsbWVudGUgYXV0b2NvcnJlbGFjaW9uYWRhcywgbG8gY3VhbCBwb2Ryw61hIGludHJvZHVjaXIgZWZlY3RvcyBpbmRpcmVjdG9zIHNpIG5vIHNlIGNvbnRyb2xhIGFkZWN1YWRhbWVudGUuDQoNCiogTUVEViBwb2Ryw61hIHRlbmVyIHVuIGVmZWN0byBuZWdhdGl2byBzb2JyZSBDUklNLCBkYWRvIHF1ZSBiYXJyaW9zIGNvbiB2aXZpZW5kYXMgbcOhcyBjYXJhcyBzdWVsZW4gc2VyIG3DoXMgc2VndXJvcy4NCg0KKiBBc2ltaXNtbywgRElTIHB1ZWRlIGVzdGFyIHJlbGFjaW9uYWRvIGNvbiBtZW5vcyBjcmltZW4gZW4gw6FyZWFzIG3DoXMgbGVqYW5hcyAobWVub3MgZGVuc2FzIG8gbcOhcyBzdWJ1cmJhbmFzKSwgYXVucXVlIGVzdG8gZGViZSB2ZXJpZmljYXJzZSBlbiBlbCBtb2RlbG8uDQoNCiMjIyBDUklNDQoNCiogSGF5IHVuYSBjbGFyYSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIHBvc2l0aXZhLCBkb25kZSBiYXJyaW9zIGNvbiBhbHRhIGNyaW1pbmFsaWRhZCBlc3TDoW4gcm9kZWFkb3MgZGUgYmFycmlvcyBzaW1pbGFyZXMuDQoNCiogU2UgZGVzdGFjYW4gem9uYXMgY29tbyBCb3N0b24gUm94YnVyeSwgU291dGggQm9zdG9uIHkgQ2hhcmxlc3Rvd24sIHF1ZSBtdWVzdHJhbiB2YWxvcmVzIGV4dHJlbW9zLg0KDQoqIExvIGFudGVyaW9yIGFwb3lhIGVsIHZhbG9yIGRlIE1vcmFu4oCZcyBJID0gMC41MjcsIGV2aWRlbmNpYW5kbyBhZ3J1cGFtaWVudG9zIGVzcGFjaWFsZXMgbm8gYWxlYXRvcmlvcy4NCg0KYGBge3J9DQojIEFqdXN0ZSBkZSByZWdyZXNpw7NuDQpNMSA8LSBsbShzcF9sYWdfQ1JJTSB+IENSSU0sIGJvc3Rvbl9zZikNCg0KIyBDYWxjdWxhciBsb3MgcmVzaWR1b3MgYWJzb2x1dG9zDQpib3N0b25fc2YkcmVzaWR1YWxzIDwtIGFicyhyZXNpZChNMSkpDQoNCiMgSWRlbnRpZmljYXIgb3V0bGllcnMNCm5fb3V0bGllcnMgPC0gNQ0KdG9wX291dGxpZXJzIDwtIG9yZGVyKGJvc3Rvbl9zZiRyZXNpZHVhbHMsIGRlY3JlYXNpbmcgPSBUUlVFKVsxOm5fb3V0bGllcnNdDQoNCiMgUHJvbWVkaW9zIChwYXJhIGzDrW5lYXMgZGl2aXNvcmlhcyB5IGN1YWRyYW50ZXMpDQptZWFuX3ggPC0gbWVhbihib3N0b25fc2YkQ1JJTSkNCm1lYW5feSA8LSBtZWFuKGJvc3Rvbl9zZiRzcF9sYWdfQ1JJTSkNCg0KIyBHcmFmaWNhciBzY2F0dGVycGxvdCBkZSBNb3Jhbg0KcGxvdChzcF9sYWdfQ1JJTSB+IENSSU0sIGJvc3Rvbl9zZiwgcGNoPTIxLCBhc3A9MSwgbGFzPTEsIA0KICAgICBjb2wgPSAiZ3JleTQwIiwgYmc9ImdyZXk4MCIsIG1haW49IlRhc2EgZGUgQ3JpbWVuIHZzIFJlemFnbyBFc3BhY2lhbCIsDQogICAgIHhsYWIgPSAiQ1JJTSIsIHlsYWIgPSAiUmV6YWdvIEVzcGFjaWFsIGRlIENSSU0iKQ0KDQphYmxpbmUoTTEsIGNvbD0iYmx1ZSIpICAjIEzDrW5lYSBkZSByZWdyZXNpw7NuDQphYmxpbmUodiA9IG1lYW5feCwgbHR5PTMsIGNvbCA9ICJncmV5ODAiKSAgIyBMw61uZWEgdmVydGljYWwgbWVkaWEgQ1JJTQ0KYWJsaW5lKGggPSBtZWFuX3ksIGx0eT0zLCBjb2wgPSAiZ3JleTgwIikgICMgTMOtbmVhIGhvcml6b250YWwgbWVkaWEgbGFnDQoNCiMgUmVzYWx0YXIgbG9zIG91dGxpZXJzDQpwb2ludHMoYm9zdG9uX3NmJENSSU1bdG9wX291dGxpZXJzXSwgDQogICAgICAgYm9zdG9uX3NmJHNwX2xhZ19DUklNW3RvcF9vdXRsaWVyc10sIA0KICAgICAgIHBjaD0yMSwgYmc9InJlZCIsIGNvbD0iYmxhY2siLCBjZXg9MS40KQ0KDQojIEV0aXF1ZXRhcyBkZSBvdXRsaWVycw0KdGV4dChib3N0b25fc2YkQ1JJTVt0b3Bfb3V0bGllcnNdLCANCiAgICAgYm9zdG9uX3NmJHNwX2xhZ19DUklNW3RvcF9vdXRsaWVyc10sIA0KICAgICBsYWJlbHMgPSBib3N0b25fc2YkVE9XTlt0b3Bfb3V0bGllcnNdLCANCiAgICAgcG9zID0gMywgY2V4ID0gMC44LCBjb2wgPSAiYmxhY2siKQ0KYGBgDQoNCg0KIyMjIE1FRFYNCg0KKiBFeGlzdGUgdW5hIGZ1ZXJ0ZSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgZWwgdmFsb3IgZGUgdW5hIHZpdmllbmRhIHkgZWwgZGUgc3VzIHZlY2luYXMuDQoNCiogWm9uYXMgY29tbyBCcm9va2xpbmUgeSBCZWFjb24gSGlsbCBtdWVzdHJhbiBhbHRvcyB2YWxvcmVzLCBtaWVudHJhcyBxdWUgQm9zdG9uIE5vcnRoIEVuZCB5IFdhbHRoYW0gZGVzdGFjYW4gY29uIHZhbG9yZXMgbcOhcyBiYWpvcy4NCg0KKiBDb25maXJtYSBlbCBNb3JhbuKAmXMgSSA9IDAuNjI3LCBsbyBxdWUgaW5kaWNhIHVuYSBlc3RydWN0dXJhIGVzcGFjaWFsIGNsYXJhIGVuIGVsIHZhbG9yIGRlIGxhcyB2aXZpZW5kYXMuDQoNCmBgYHtyfQ0KTTIgPC0gbG0oc3BfbGFnX01FRFYgfiBNRURWLCBib3N0b25fc2YpDQoNCiMgQ2FsY3VsYXIgbG9zIHJlc2lkdW9zIGFic29sdXRvcyAoZGlzdGFuY2lhIHZlcnRpY2FsIGEgbGEgbMOtbmVhIGRlIHJlZ3Jlc2nDs24pDQpib3N0b25fc2YkcmVzaWR1YWxzIDwtIGFicyhyZXNpZChNMikpDQoNCiMgSWRlbnRpZmljYXIgbG9zIG4gcHVudG9zIG3DoXMgbGVqYW5vcyAocG9yIGVqZW1wbG8sIGxvcyA1IG1heW9yZXMgcmVzaWR1b3MpDQpuX291dGxpZXJzIDwtIDUNCnRvcF9vdXRsaWVycyA8LSBvcmRlcihib3N0b25fc2YkcmVzaWR1YWxzLCBkZWNyZWFzaW5nID0gVFJVRSlbMTpuX291dGxpZXJzXQ0KDQojIEdyYWZpY2FyIGxvcyBkYXRvcyAoTW9yYW4gc2NhdHRlcnBsb3QpICsgbMOtbmVhIGRlIHJlZ3Jlc2nDs24NCnBsb3Qoc3BfbGFnX01FRFYgfiBNRURWLCBib3N0b25fc2YsIHBjaD0yMSwgYXNwPTEsIGxhcz0xLCANCiAgICAgY29sID0gImdyZXk0MCIsIGJnPSJncmV5ODAiLCBtYWluPSJUYXNhIGRlIFZhbG9yIFZpdmllbmRhIHZzIFJlemFnbyBFc3BhY2lhbCIpDQphYmxpbmUoTTEsIGNvbD0iYmx1ZSIpICMgTMOtbmVhIGRlIHJlZ3Jlc2nDs24NCmFibGluZSh2ID0gbWVhbihib3N0b25fc2YkTUVEViksIGx0eT0zLCBjb2wgPSAiZ3JleTgwIikNCmFibGluZShoID0gbWVhbihib3N0b25fc2Ykc3BfbGFnX01FRFYpLCBsdHk9MywgY29sID0gImdyZXk4MCIpDQoNCiMgUmVzYWx0YXIgbG9zIHB1bnRvcyBtw6FzIGxlamFub3MgKG91dGxpZXJzKQ0KcG9pbnRzKGJvc3Rvbl9zZiRNRURWW3RvcF9vdXRsaWVyc10sIA0KICAgICAgIGJvc3Rvbl9zZiRzcF9sYWdfTUVEVlt0b3Bfb3V0bGllcnNdLCANCiAgICAgICBwY2g9MjEsIGJnPSJyZWQiLCBjb2w9ImJsYWNrIiwgY2V4PTEuNCkNCg0KIyBBZ3JlZ2FyIGV0aXF1ZXRhcyBjb24gZWwgbm9tYnJlIGRlIGxhIGxvY2FsaWRhZA0KdGV4dChib3N0b25fc2YkTUVEVlt0b3Bfb3V0bGllcnNdLCANCiAgICAgYm9zdG9uX3NmJHNwX2xhZ19NRURWW3RvcF9vdXRsaWVyc10sIA0KICAgICBsYWJlbHMgPSBib3N0b25fc2YkVE9XTlt0b3Bfb3V0bGllcnNdLCANCiAgICAgcG9zID0gMywgY2V4ID0gMC44LCBjb2wgPSAiYmxhY2siKQ0KYGBgDQoNCg0KDQojIyMgRElTDQoNCiogSGF5IHVuYSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIGV4dHJlbWFkYW1lbnRlIGFsdGEgKE1vcmFu4oCZcyBJID0gMC45NTYpLiBMYXMgem9uYXMgY29uIHNpbWlsYXJlcyBkaXN0YW5jaWFzIGEgY2VudHJvcyBsYWJvcmFsZXMgZXN0w6FuIG11eSBhZ3J1cGFkYXMuDQoNCiogRWplbXBsb3M6IExleGluZ3RvbiwgRHV4YnVyeSB5IEdhcmxhbmQgc2UgYWdydXBhbiBwb3Igc3VzIG1heW9yZXMgZGlzdGFuY2lhcy4NCg0KYGBge3J9DQpNMyA8LSBsbShzcF9sYWdfRElTIH4gRElTLCBib3N0b25fc2YpDQoNCiMgQ2FsY3VsYXIgbG9zIHJlc2lkdW9zIGFic29sdXRvcyAoZGlzdGFuY2lhIHZlcnRpY2FsIGEgbGEgbMOtbmVhIGRlIHJlZ3Jlc2nDs24pDQpib3N0b25fc2YkcmVzaWR1YWxzIDwtIGFicyhyZXNpZChNMykpDQoNCiMgSWRlbnRpZmljYXIgbG9zIG4gcHVudG9zIG3DoXMgbGVqYW5vcyAocG9yIGVqZW1wbG8sIGxvcyA1IG1heW9yZXMgcmVzaWR1b3MpDQpuX291dGxpZXJzIDwtIDUNCnRvcF9vdXRsaWVycyA8LSBvcmRlcihib3N0b25fc2YkcmVzaWR1YWxzLCBkZWNyZWFzaW5nID0gVFJVRSlbMTpuX291dGxpZXJzXQ0KDQojIEdyYWZpY2FyIGxvcyBkYXRvcyAoTW9yYW4gc2NhdHRlcnBsb3QpICsgbMOtbmVhIGRlIHJlZ3Jlc2nDs24NCnBsb3Qoc3BfbGFnX0RJUyB+IERJUywgYm9zdG9uX3NmLCBwY2g9MjEsIGFzcD0xLCBsYXM9MSwgDQogICAgIGNvbCA9ICJncmV5NDAiLCBiZz0iZ3JleTgwIiwgbWFpbj0iVGFzYSBkZSBEaXN0YW5jaWEgZGUgQ2VudHJvcyB2cyBSZXphZ28gRXNwYWNpYWwiKQ0KYWJsaW5lKE0xLCBjb2w9ImJsdWUiKSAjIEzDrW5lYSBkZSByZWdyZXNpw7NuDQphYmxpbmUodiA9IG1lYW4oYm9zdG9uX3NmJERJUyksIGx0eT0zLCBjb2wgPSAiZ3JleTgwIikNCmFibGluZShoID0gbWVhbihib3N0b25fc2Ykc3BfbGFnX0RJUyksIGx0eT0zLCBjb2wgPSAiZ3JleTgwIikNCg0KIyBSZXNhbHRhciBsb3MgcHVudG9zIG3DoXMgbGVqYW5vcyAob3V0bGllcnMpDQpwb2ludHMoYm9zdG9uX3NmJERJU1t0b3Bfb3V0bGllcnNdLCANCiAgICAgICBib3N0b25fc2Ykc3BfbGFnX0RJU1t0b3Bfb3V0bGllcnNdLCANCiAgICAgICBwY2g9MjEsIGJnPSJyZWQiLCBjb2w9ImJsYWNrIiwgY2V4PTEuNCkNCg0KIyBBZ3JlZ2FyIGV0aXF1ZXRhcyBjb24gZWwgbm9tYnJlIGRlIGxhIGxvY2FsaWRhZA0KdGV4dChib3N0b25fc2YkRElTW3RvcF9vdXRsaWVyc10sIA0KICAgICBib3N0b25fc2Ykc3BfbGFnX0RJU1t0b3Bfb3V0bGllcnNdLCANCiAgICAgbGFiZWxzID0gYm9zdG9uX3NmJFRPV05bdG9wX291dGxpZXJzXSwgDQogICAgIHBvcyA9IDMsIGNleCA9IDAuOCwgY29sID0gImJsYWNrIikNCmBgYA0KDQoNCiMgKipBbsOhbGlzaXMgZGUgY2x1c3RlcnMqKg0KDQojIyBWaXN1YWxpemFjacOzbiBFc3BhY2lhbCBkZSBDbHVzdGVycyBkZSBDUklNDQoNCiogSGlnaC1IaWdoOglBbHRhIGNyaW1pbmFsaWRhZCByb2RlYWRhIGRlIGFsdGEgY3JpbWluYWxpZGFkLiBJbmRpY2Egem9uYXMgdnVsbmVyYWJsZXMsIHVzdWFsbWVudGUgdXJiYW5hcywgY29uIHBvc2libGVzIHByb2JsZW1hcyBlc3RydWN0dXJhbGVzLg0KDQoqIExvdy1IaWdoOglCYWphIGNyaW1pbmFsaWRhZCBlbiB6b25hcyByb2RlYWRhcyBkZSBhbHRhIGNyaW1pbmFsaWRhZC4gUHVlZGUgcmVmbGVqYXIgem9uYXMgZGUgcmVzaXN0ZW5jaWEgbyBlbmNsYXZlcyBzZWd1cm9zIGVuIGVudG9ybm9zIGNvbmZsaWN0aXZvcy4NCg0KKiBMb3ctTG93OglCYWphIGNyaW1pbmFsaWRhZCByb2RlYWRhIGRlIGJhamEgY3JpbWluYWxpZGFkLiDDgXJlYXMgc2VndXJhcywgcHJvYmFibGVtZW50ZSBjb24gYnVlbmEgaW5mcmFlc3RydWN0dXJhIHkgY2FsaWRhZCBkZSB2aWRhLg0KDQoqIE5vdCBzaWduaWZpY2FudDoJU2luIHBhdHLDs24gZXNwYWNpYWwgY2xhcm8uIMOBcmVhcyBoZXRlcm9nw6luZWFzIG8gZW4gdHJhbnNpY2nDs24uDQoNCmBgYHtyfQ0Kc3dtX2EgPC0gcXVlZW5fd2VpZ2h0cyhib3N0b25fc2YpICAjIE1hdHJpeiBkZSBwZXNvcyBlc3BhY2lhbGVzIFF1ZWVuDQoNCmxpc2FfY3JpbSA8LSBsb2NhbF9tb3Jhbihzd21fYSwgYm9zdG9uX3NmWyJDUklNIl0pDQoNCmJvc3Rvbl9zZiRjbHVzdGVyX2NyaW0gPC0gYXMuZmFjdG9yKGxpc2FfY3JpbSRHZXRDbHVzdGVySW5kaWNhdG9ycygpKQ0KbGV2ZWxzKGJvc3Rvbl9zZiRjbHVzdGVyX2NyaW0pIDwtIGxpc2FfY3JpbSRHZXRMYWJlbHMoKQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhID0gYm9zdG9uX3NmKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjbHVzdGVyX2NyaW0pLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2d0aXRsZShsYWJlbCA9ICJUYXNhIGRlIENyaW1lbiIsIHN1YnRpdGxlID0gIkNsw7pzdGVyZXMgRXNwYWNpYWxlcyBlbiBCb3N0b24iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsICJ0dXJxdW9pc2UiLCAiZ3JleSIsICJwdXJwbGUiLCAiZ3JlZW4iKSkgKyAjIENvbG9yZXMgcGFyYSBsb3MgY2x1c3RlcnMNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KIyMgVmlzdWFsaXphY2nDs24gRXNwYWNpYWwgZGUgQ2x1c3RlcnMgZGUgTUVEVg0KDQoqIEhpZ2gtSGlnaDoJQWx0byB2YWxvciBkZSB2aXZpZW5kYSBlbiB6b25hcyByb2RlYWRhcyB0YW1iacOpbiBkZSBhbHRvIHZhbG9yLiBCYXJyaW9zIGFjb21vZGFkb3MgbyBzdWJ1cmJhbm9zIGNvbnNvbGlkYWRvcy4NCg0KKiBMb3ctSGlnaDoJQmFqbyB2YWxvciBlbiB6b25hcyBkZSBhbHRvIHZhbG9yLiBQdWVkZW4gc2VyIGZvY29zIGRlIGdlbnRyaWZpY2FjacOzbiBvIHJlemFnbyBlbiB6b25hcyBkZXNhcnJvbGxhZGFzLg0KDQoqIExvdy1Mb3c6CUJham8gdmFsb3Igcm9kZWFkbyBkZSBiYWpvIHZhbG9yLiBab25hcyBtYXJnaW5hZGFzIG8gZGUgbWVub3IgZGVzYXJyb2xsbyBlY29uw7NtaWNvLg0KDQoqIE5vdCBzaWduaWZpY2FudDoJU2luIHBhdHLDs24gY2xhcm8gZW4gZWwgdmFsb3IgZGUgdml2aWVuZGEuIFB1ZWRlbiBzZXIgem9uYXMgY29uIG1lemNsYSBkZSBjbGFzZXMgc29jaWFsZXMgbyBkZXNhcnJvbGxvIGRlc2lndWFsLg0KDQpgYGB7cn0NCmxpc2FfbWVkdiA8LSBsb2NhbF9tb3Jhbihzd21fYSwgYm9zdG9uX3NmWyJNRURWIl0pDQoNCmJvc3Rvbl9zZiRjbHVzdGVyX21lZHYgPC0gYXMuZmFjdG9yKGxpc2FfbWVkdiRHZXRDbHVzdGVySW5kaWNhdG9ycygpKQ0KbGV2ZWxzKGJvc3Rvbl9zZiRjbHVzdGVyX21lZHYpIDwtIGxpc2FfbWVkdiRHZXRMYWJlbHMoKQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhID0gYm9zdG9uX3NmKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjbHVzdGVyX21lZHYpLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZ2d0aXRsZShsYWJlbCA9ICJUYXNhIGRlIFZhbG9yIFZpdmllbmRhIiwgc3VidGl0bGUgPSAiQ2zDunN0ZXJlcyBFc3BhY2lhbGVzIGVuIEJvc3RvbiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2FsbW9uIiwgInR1cnF1b2lzZSIsICJncmV5IiwgInB1cnBsZSIsICJncmVlbiIpKSArICMgQ29sb3JlcyBwYXJhIGxvcyBjbHVzdGVycw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQojIyBWaXN1YWxpemFjacOzbiBFc3BhY2lhbCBkZSBDbHVzdGVycyBkZSBESVMNCg0KKiBIaWdoLUhpZ2g6CUFsdGEgZGlzdGFuY2lhIGEgY2VudHJvcyBkZSBlbXBsZW8gZW4gem9uYXMgdGFtYmnDqW4gYWxlamFkYXMuIFpvbmFzIHBlcmlmw6lyaWNhcyBjb24gbWFsYSBhY2Nlc2liaWxpZGFkLg0KDQoqIExvdy1Mb3c6CUJhamEgZGlzdGFuY2lhIGEgY2VudHJvcyBkZSBlbXBsZW8gZW4gem9uYXMgdGFtYmnDqW4gYmllbiBjb25lY3RhZGFzLiBab25hcyBjZW50cmFsZXMgbyBwcml2aWxlZ2lhZGFzIHBhcmEgbW92aWxpZGFkIGxhYm9yYWwuDQoNCiogTm90IHNpZ25pZmljYW50OglTaW4gcGF0csOzbiBlc3BhY2lhbCBldmlkZW50ZS4gUHVlZGVuIGNvbWJpbmFyIGFjY2VzaWJpbGlkYWQgdmFyaWFibGUgbyBlc3RhciBlbiB6b25hcyBlbiB0cmFuc2Zvcm1hY2nDs24gdXJiYW5hLg0KDQpgYGB7cn0NCmxpc2FfZGlzIDwtIGxvY2FsX21vcmFuKHN3bV9hLCBib3N0b25fc2ZbIkRJUyJdKQ0KDQpib3N0b25fc2YkY2x1c3Rlcl9kaXMgPC0gYXMuZmFjdG9yKGxpc2FfZGlzJEdldENsdXN0ZXJJbmRpY2F0b3JzKCkpDQpsZXZlbHMoYm9zdG9uX3NmJGNsdXN0ZXJfZGlzKSA8LSBsaXNhX2RpcyRHZXRMYWJlbHMoKQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRhID0gYm9zdG9uX3NmKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSBjbHVzdGVyX2RpcyksIGNvbG9yID0gIndoaXRlIikgKw0KICBnZ3RpdGxlKGxhYmVsID0gIlRhc2EgZGUgRGlzdGFuY2lhIGEgQ2VudHJvcyIsIHN1YnRpdGxlID0gIkNsw7pzdGVyZXMgRXNwYWNpYWxlcyBlbiBCb3N0b24iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNhbG1vbiIsICJ0dXJxdW9pc2UiLCAiZ3JleSIsICJwdXJwbGUiLCAiZ3JlZW4iKSkgKyAjIENvbG9yZXMgcGFyYSBsb3MgY2x1c3RlcnMNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KDQojICoqTW9kZWxvcyBkZSBSZWdyZXNpw7NuKioNCg0KIyMgTW9kZWxvIGRlIFJlZ3Jlc2nDs24gTGluZWFsIFRyYWRpY2lvbmFsDQpgYGB7cn0NCm1vZGVsX2EgPC0gbG0oQ1JJTSB+IFJBRCArIFpOICsgRElTICsgTUVEViArIE5PWCArIEIsIGRhdGEgPSBib3N0b25fc2YpDQpzdW1tYXJ5KG1vZGVsX2EpDQpBSUMobW9kZWxfYSkNCmBgYA0KDQojIyBNb2RlbG8gZGUgUmVncmVzacOzbiBFc3BhY2lhbCBBdXRvUmVncmVzaXZvIChTQVIpDQpgYGB7cn0NCm1vZGVsX2IgPC0gbGFnc2FybG0oQ1JJTSB+IFJBRCArIFpOICsgRElTICsgTUVEViArIE5PWCArIEIsIGRhdGEgPSBib3N0b25fc2YsIGxpc3R3ID0gYm9zdG9uX2xpc3R3KSANCnN1bW1hcnkobW9kZWxfYikNCkFJQyhtb2RlbF9iKQ0KYGBgDQoNCiMjIE1vZGVsbyBkZSBSZWdyZXNpw7NuIEVzcGFjaWFsIGRlIEVycm9yZXMgKFNFTSkNCmBgYHtyfQ0KbW9kZWxfYyA8LSBlcnJvcnNhcmxtKENSSU0gfiBSQUQgKyBaTiArIERJUyArIE1FRFYgKyBOT1ggKyBCLCBkYXRhID0gYm9zdG9uX3NmLCBsaXN0dyA9IGJvc3Rvbl9saXN0dykNCnN1bW1hcnkobW9kZWxfYykNCkFJQyhtb2RlbF9jKQ0KYGBgDQoNCiMjIE1vZGVsbyBkZSBSZWdyZXNpw7NuIEVzcGFjaWFsIER1cmJpbg0KYGBge3J9DQptb2RlbF9kIDwtIGxhZ3NhcmxtKENSSU0gfiBSQUQgKyBaTiArIERJUyArIE1FRFYgKyBOT1ggKyBCLCBkYXRhID0gYm9zdG9uX3NmLCBsaXN0dyA9IGJvc3Rvbl9saXN0dywgdHlwZT0ibWl4ZWQiKSANCnN1bW1hcnkobW9kZWxfZCkNCkFJQyhtb2RlbF9kKQ0KYGBgDQoNCiMjIENvbXBhcmF0aXZhIGRlIG1vZGVsb3MNCg0KQ29uIGJhc2UgZW4gbG9zIHJlc3VsdGFkb3MgZGUgbG9zIGN1YXRybyBtb2RlbG9zIGRlIHJlZ3Jlc2nDs24gZXN0aW1hZG9zIHBhcmEgZXhwbGljYXIgbGEgdGFzYSBkZSBjcmltZW4gKENSSU0pLCBzZSBkZXRlcm1pbmEgcXVlOg0KDQoqIFRvZG9zIGxvcyBtb2RlbG9zIGVzcGFjaWFsZXMgKDIgYSA0KSB0aWVuZW4gbWVqb3IgZGVzZW1wZcOxbyBxdWUgZWwgT0xTIChNb2RlbG8gMSksIGxvIGN1YWwgaW5kaWNhIHF1ZSBleGlzdGUgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCBlbiBsb3MgZGF0b3MgeSBkZWJlIHNlciB0b21hZGEgZW4gY3VlbnRhLg0KDQoqIE1vZGVsbyAzIChTRU0pIHRpZW5lIGVsIEFJQyBtw6FzIGJham8sIGxvIHF1ZSBsZSBwZXJtaXRlIGV4cGxpY2FyIGJpZW4gY29uIG1lbm9zIGNvbXBsZWppZGFkLg0KDQoqIE1vZGVsbyA0IChTRE0pIGluY2x1eWUgcmV6YWdvcyBkZSBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcy4gVGllbmUgbGEgbWVqb3IgbG9nLWxpa2VsaWhvb2QgeSBtZW5vciBzaWdtYcKyLCBsbyBjdWFsIHN1Z2llcmUgcXVlIGFqdXN0YSBtZWpvciBsb3MgZGF0b3MsIGF1bnF1ZSBzdSBBSUMgZXMgbGlnZXJhbWVudGUgbcOhcyBhbHRvLg0KDQoNCkFjb3JkZSBhIGxvIGFudGVyaW9yLCBzZSBkZXRlcm1pbmEgcXVlIGVsIG1lam9yIG1vZGVsbyBlcyBlbCBkZSAqKlJlZ3Jlc2nDs24gRXNwYWNpYWwgRHVyYmluKiogZGViaWRvIGEgcXVlOg0KDQoqIE1heW9yIGxvZy1saWtlbGlob29kICjiiJIxLDYyMC43MDcpOiBFbCBNb2RlbG8gNCB0aWVuZSBlbCB2YWxvciBtZW5vcyBuZWdhdGl2bywgbG8gcXVlIGltcGxpY2EgdW4gbWVqb3IgYWp1c3RlIGdlbmVyYWwsIHBvciBlbmRlLCBlcyBlbCBxdWUg4oCcZXhwbGljYeKAnSBkZSBmb3JtYSBtw6FzIHByb2JhYmxlIGxvcyBkYXRvcyBvYnNlcnZhZG9zIGRhZG9zIHN1cyBwYXLDoW1ldHJvcyBlc3RpbWFkb3MuDQoNCiogTWVub3IgZXJyb3IgcmVzaWR1YWwgKM+DwrIgPSAzMy43MjMpOiBFbCBNb2RlbG8gNCBtdWVzdHJhIGxhIG1lbm9yIHZhcmlhbnphIGRlbCByZXNpZHVvIGVudHJlIGxvcyBtb2RlbG9zLCBsbyBjdWFsIGVzIGluZGljaW8gZGUgdW5hIG1heW9yIHByZWNpc2nDs24gZW4gbGFzIHByZWRpY2Npb25lcyAoY29tZXRlIG1lbm9zIGVycm9yZXMgYWwgcHJlZGVjaXIgbGEgZGVwZW5kaWVudGUpLg0KDQoqIEF1bnF1ZSBlbCBBSUMgZGUgTW9kZWxvIDMgdGllbmUgdW5hIGRpZmVyZW5jaWEgZGUgNS4zOTYgY29uIGVsIEFJQyBkZWwgTW9kZWxvIDQuIEVzdGUgw7psdGltbyBtb2RlbG8gaW5jb3Jwb3JhIHNpbXVsdMOhbmVhbWVudGUgbGEgZGVwZW5kZW5jaWEgZXNwYWNpYWwgZW4gbGEgdmFyaWFibGUgZGVwZW5kaWVudGUgKGxhZyBkZSBDUklNKSB5IGxhIGRlcGVuZGVuY2lhIGVzcGFjaWFsIGVuIGVsIGVycm9yIChlc3RydWN0dXJhIGRlIGF1dG9jb3JyZWxhY2nDs24gZGVsIGVycm9yKS4NCg0KKiBSZXN1bHRhZG9zIHNpZ25pZmljYXRpdm9zIGVuIFdhbGQgeSBMaWtlbGlob29kIFJhdGlvIFRlc3RzIEFtYmFzIHBydWViYXMgKFdhbGQgeSBMUikgZXZhbMO6YW4gbGEgcmVsZXZhbmNpYSBkZSBpbmNsdWlyIGNvbXBvbmVudGVzIGVzcGFjaWFsZXMuIEVuIGVsIE1vZGVsbyA0LCBlc3RvcyB0ZXN0cyBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2b3MgKHAgPCAwLjA1KSwgbG8gcXVlIGluZGljYSBxdWUgbG9zIGVmZWN0b3MgZXNwYWNpYWxlcyBubyBzb2xvIGVzdMOhbiBwcmVzZW50ZXMsIHNpbm8gcXVlIHN1IGluY2x1c2nDs24gbWVqb3JhIHNpZ25pZmljYXRpdmFtZW50ZSBsYSBleHBsaWNhY2nDs24gZGVsIG1vZGVsby4NCg0KDQpgYGB7cn0NCnN0YXJnYXplcihtb2RlbF9hLCBtb2RlbF9iLCBtb2RlbF9jLCBtb2RlbF9kLCB0eXBlID0gInRleHQiLCB0aXRsZT0iRXN0aW1hdGVkIFJlZ3Jlc3Npb24gUmVzdWx0cyIpDQpgYGANCg0KDQojICoqQ29uY2x1c2nDs24qKiANCg0KRWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBDUklNICh0YXNhIGRlIGNyaW1lbiBwb3IgZGlzdHJpdG8pIG11ZXN0cmEgdW5hIGNsYXJhIGNvbmNlbnRyYWNpw7NuIGVzcGFjaWFsIGRlbCBjcmltZW4gZW4gbGEgem9uYSBjZW50cmFsIGRlIEJvc3Rvbi4gRXN0YSDDoXJlYSBwcmVzZW50YSBsb3MgdmFsb3JlcyBtw6FzIGFsdG9zIGRlIGNyaW1pbmFsaWRhZCwgcmVwcmVzZW50YWRvcyBwb3IgdG9uYWxpZGFkZXMgb3NjdXJhcyBlbiBsb3MgbWFwYXMgdGVtw6F0aWNvcy4gQWwgY29tcGFyYXIgbGEgZGlzdHJpYnVjacOzbiBlc3BhY2lhbCBkZSBDUklNIGNvbiBzdSByZXphZ28gZXNwYWNpYWwgKExhZy0xKSwgc2Ugb2JzZXJ2YSB1bmEgZ3JhbiBzaW1pbGl0dWQsIGxvIGN1YWwgc3VnaWVyZSBsYSBwcmVzZW5jaWEgZGUgZGVwZW5kZW5jaWEgZXNwYWNpYWw6IGxhcyB6b25hcyBjb24gYWx0byBuaXZlbCBkZSBjcmltZW4gdGllbmRlbiBhIGVzdGFyIHJvZGVhZGFzIHBvciBvdHJhcyB6b25hcyBjb24gbml2ZWxlcyB0YW1iacOpbiBlbGV2YWRvcy4NCg0KRWwgYW7DoWxpc2lzIExJU0EgKEluZGljYWRvcmVzIExvY2FsZXMgZGUgQXNvY2lhY2nDs24gRXNwYWNpYWwpIHBlcm1pdGnDsyBpZGVudGlmaWNhciBhZ3J1cGFtaWVudG9zIHNpZ25pZmljYXRpdm9zIGRlIHZhbG9yZXMgYWx0b3MgeSBiYWpvcyBkZSBjcmltZW46DQoNCiogSGlnaC1IaWdoOiB6b25hcyBjb24gYWx0YSBjcmltaW5hbGlkYWQgcm9kZWFkYXMgZGUgem9uYXMgaWd1YWxtZW50ZSBhbHRhcy4gU2UgY29uY2VudHJhbiBwcmluY2lwYWxtZW50ZSBlbiBlbCBjZW50cm8tbm9ydGUgZGUgbGEgY2l1ZGFkIHkgcmVwcmVzZW50YW4gw6FyZWFzIGNyw610aWNhcyBkZXNkZSBsYSBwZXJzcGVjdGl2YSBkZSBzZWd1cmlkYWQgcMO6YmxpY2EuDQoNCiogTG93LUhpZ2g6IHpvbmFzIGNvbiBiYWphIGNyaW1pbmFsaWRhZCBwZXJvIHJvZGVhZGFzIGRlIHZlY2luZGFyaW9zIGNvbiBhbHRhIGNyaW1pbmFsaWRhZC4gRXN0YXMgcHVlZGVuIHJlcHJlc2VudGFyIHpvbmFzIGRlIHJpZXNnbyBwb3IgY29udGFnaW8gZXNwYWNpYWwgZGVsIGNyaW1lbi4NCg0KKiBMb3ctTG93OiB6b25hcyBjb24gYmFqYSBjcmltaW5hbGlkYWQgcm9kZWFkYXMgcG9yIG90cmFzIHpvbmFzIHNpbWlsYXJlcywgcG9zaWJsZW1lbnRlIGFzb2NpYWRhcyBhIGNvbmRpY2lvbmVzIHNvY2lvZWNvbsOzbWljYXMgZmF2b3JhYmxlcy4NCg0KKiBOb3QgU2lnbmlmaWNhbnQ6IHpvbmFzIHNpbiBwYXRyb25lcyBlc3BhY2lhbGVzIHNpZ25pZmljYXRpdm9zLg0KDQpFbCBtb2RlbG8gc2VsZWNjaW9uYWRvIGZ1ZSBsYSBSZWdyZXNpw7NuIEVzcGFjaWFsIER1cmJpbiwgeWEgcXVlIGluY29ycG9yYSB0YW50byBsb3MgZWZlY3RvcyBsb2NhbGVzIGNvbW8gbG9zIHJlemFnb3MgZXNwYWNpYWxlcyBkZSBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcy4gQXNpbWlzbW8sIG1vc3Ryw7MgdW4gYnVlbiBkZXNlbXBlw7FvIGVzdGFkw61zdGljbywgY29uIHVuIGxvZy1saWtlbGlob29kIGRlIOKAkzEsNjIwLjcgeSB1biBjcml0ZXJpbyBkZSBpbmZvcm1hY2nDs24gZGUgQWthaWtlIChBSUMpIHJlbGF0aXZhbWVudGUgYmFqbywgY29uZmlybWFuZG8gc3UgYWp1c3RlIMOzcHRpbW8uIExvcyByZXN1bHRhZG9zIG3DoXMgcmVsZXZhbnRlcyBkZW11ZXN0cmFuIHF1ZToNCg0KKiBSQUQgKGFjY2VzbyBhIGF1dG9waXN0YXMpOiB0aWVuZSB1biBlZmVjdG8gZGlyZWN0byBwb3NpdGl2byB5IHNpZ25pZmljYXRpdm8gKGNvZWYuID0gMC41NjEpLCBsbyBjdWFsIGluZGljYSBxdWUgYSBtYXlvciBhY2Nlc2liaWxpZGFkIGEgYXV0b3Bpc3RhcywgbWF5b3IgZXMgbGEgdGFzYSBkZSBjcmltZW4uIFNpbiBlbWJhcmdvLCBlbCBlZmVjdG8gZXNwYWNpYWwgZGUgZXN0YSB2YXJpYWJsZSBlcyBuZWdhdGl2byB5IHRhbWJpw6luIHNpZ25pZmljYXRpdm8gKGxhZy5SQUQgPSDigJMwLjM0MCoqKiksIGxvIGN1YWwgc3VnaWVyZSBxdWUgZXN0YXIgcm9kZWFkbyBkZSB6b25hcyBiaWVuIGNvbmVjdGFkYXMgcHVlZGUgZGlzbWludWlyIGxhIGNyaW1pbmFsaWRhZCBsb2NhbCwgcG9zaWJsZW1lbnRlIHBvciBsYSByZWRpc3RyaWJ1Y2nDs24gZGUgYWN0aXZpZGFkZXMgbyB2aWdpbGFuY2lhIGluZGlyZWN0YS4NCg0KKiBNRURWICh2YWxvciBtZWRpbyBkZSBsYXMgdml2aWVuZGFzKTogdGllbmUgdW4gZWZlY3RvIG5lZ2F0aXZvICjigJMwLjExNioqKSwgbG8gcXVlIGltcGxpY2EgcXVlIGVuIHZlY2luZGFyaW9zIGNvbiBtYXlvciB2YWxvciBpbm1vYmlsaWFyaW8gbGEgY3JpbWluYWxpZGFkIHRpZW5kZSBhIHNlciBtZW5vci4NCg0KKiBOT1ggKGNvbnRhbWluYWNpw7NuIHBvciDDs3hpZG9zIGRlIG5pdHLDs2dlbm8pOiBwcmVzZW50YSB1biBlZmVjdG8gbmVnYXRpdm8geSBzaWduaWZpY2F0aXZvICjigJMyMS44NzYqKiksIGxvIGN1YWwgcG9kcsOtYSBlc3RhciByZWxhY2lvbmFkbyBjb24gdW4gZW50b3JubyBmw61zaWNvIHBvY28gaGFiaXRhYmxlIHF1ZSBkZXNpbmNlbnRpdmEgbGEgYWN0aXZpZGFkIGRlbGljdGl2YSBvIGNvbmNlbnRyYSBtZW5vciBkZW5zaWRhZCBwb2JsYWNpb25hbC4NCg0KKiBaTiAocG9yY2VudGFqZSBkZSB0ZXJyZW5vcyByZXNpZGVuY2lhbGVzIGdyYW5kZXMpLCBESVMgKGRpc3RhbmNpYSBhIGNlbnRyb3MgbGFib3JhbGVzKSB5IEIgKMOtbmRpY2UgcmFjaWFsKSBwaWVyZGVuIHNpZ25pZmljYW5jaWEgZXN0YWTDrXN0aWNhIGVuIGVzdGUgbW9kZWxvLCBsbyBxdWUgaW5kaWNhIHF1ZSBzdXMgZWZlY3RvcyBzb24gYWJzb3JiaWRvcyBwb3Igb3RyYXMgdmFyaWFibGVzIG8gcG9yIHN1cyBjb21wb25lbnRlcyBlc3BhY2lhbGVzLg0KDQpDb24gYmFzZSBlbiBsbyBhbnRlcmlvciwgc2UgZGV0ZXJtaW5hIHF1ZSBsYXMgZXN0cmF0ZWdpYXMgZGUgcHJldmVuY2nDs24gZGVsIGNyaW1lbiBkZWJlbiBjb25zaWRlcmFyIG5vIHNvbG8gbGFzIGNvbmRpY2lvbmVzIGludGVybmFzIGRlIGNhZGEgZGlzdHJpdG8sIHNpbm8gdGFtYmnDqW4gc3UgY29udGV4dG8gZXNwYWNpYWwuIEVuIG90cmFzIHBhbGFicmFzLCBsYXMgcG9sw610aWNhcyBww7pibGljYXMgZGViZW4gZGlzZcOxYXJzZSBjb24gdW5hIHBlcnNwZWN0aXZhIHJlZ2lvbmFsLCByZWNvbm9jaWVuZG8gbGEgaW50ZXJkZXBlbmRlbmNpYSBlbnRyZSB6b25hcyB1cmJhbmFzIHBhcmEgbG9ncmFyIGludGVydmVuY2lvbmVzIG3DoXMgZWZlY3RpdmFzIHkgc29zdGVuaWJsZXMuDQoNCiMgKipSZWZlcmVuY2lhcyoqDQoNCldoYXQgaXMgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcz8gDQpodHRwczovL3d3dy5pYm0uY29tL3RvcGljcy9leHBsb3JhdG9yeS1kYXRhLWFuYWx5c2lzDQoNCkV4cGxvcmF0b3J5IFNwYXRpYWwgRGF0YSBBbmFseXNpcw0KaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2dlb3N0YW4vdmlnbmV0dGVzL21lYXN1cmluZy1zYS5odG1s