Autores

Equipo 3 - Gamma.

Integrantes:
* César Romeo Vega
* Gamaliel Ostos
* Luis Carlos Borbón
* Rodrigo Arroyo

Introducción a la Actividad

1) Relación análisis espacial de datos y “Location Intelligence”.

La herramienta de Location Intelligence es el proceso de tomar decisiones basándose en superponer información en un mapa a fin de poder obtener insights que involucren la conexión entre diferentes variables en un lugar geográfico. El fundamento sobre el cual se sostiene Location Intelligence es el análisis espacial de los datos, que permite procesar coordenadas, identificar clusters, manejar autocorrelación espacial y aplicar modelos espaciales, todo lo cual permite representar las variables en los mapas y tomar decisiones estratégicas. De modo que la relación consiste en que el análisis de datos espaciales es el fundamento y Location Intelligence aprovecha esa información en un contexto de negocios.

2) Principales diferencias entre: Modelo de regresión lineal no espacial versus espacial.

  • El modelo no espacial presupone que los datos son independientes entre sí y que no existe correlación espacial de los datos, mientras que el modelo espacial sí tiene en cuenta estas relaciones espaciales.
  • En el modelo no espacial se asume que los errores no están correlacionados, mientras que en el modelo espacial sí se corrige el problema de autocorrelación espacial de los datos.
  • En la estructura matemática del modelo no espacial aparece la forma Y=β0​ + β1​x1​ + ε, mientras que en el modelo espacial se integra una W, que es la matriz de pesos espaciales.
  • En el modelo no espacial se emplean herramientas como R cuadrada, AIC y test de heterocedasticidad, mientras que en el modelo espacial se hace uso del índice de Global Moran, Lagrange Multiplier y mapas de residuos espaciales.

3) Modelo No Espacial y Análisis Espacial de los Datos

Instalar Librerías, Paquetes y Bases de Datos

#install.packages("readxl")
#install.packages("ggplot2")
#install.packages("dplyr")
#install.packages("spdep")
#install.packages("sp")
#install.packages("sf")
#install.packages("spatialreg")
#install.packages("stargazer")
#install.packages("tidyverse")
#install.packages("randomForest")
#install.packages("caret")
#install.packages("car")
#install.packages("xgboost")
library(readxl)
library(ggplot2)
library(dplyr)
library(spdep)
library(tmap)
library(sf)
library(sp)
library(tmaptools)
library(tmap)
library(spatialreg)
library(stargazer)
library(tidyverse)
library(randomForest)
library(car)
library(caret)
library(xgboost)
library(foreign)
# Read the Excel file
data <- read_excel("tourism_state_data.xlsx")
# Mexico's states (32) 
map <- st_read("mexlatlong.shp")
## Reading layer `mexlatlong' from data source 
##   `C:\Users\rodio\OneDrive\Escritorio\8semestre\Bloque Final\Actividad 2\mexlatlong.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 32 features and 19 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -118.4042 ymin: 14.55055 xmax: -86.73862 ymax: 32.71846
## Geodetic CRS:  WGS 84
map <- read_sf("mexlatlong.shp")

# Merging dataset
state <- map %>%
  left_join(data, by = c("ADMIN_NAME" = "state"))

Selección del 2018 como año de análisis

# Read the Excel file
data <- filter(data, year == 2018)

Identificando Variables

Dentro de la Base de Datos se encuentra la siguientes variables por analizar: * tourism_gdp: Viajes y turismo que contribuye directamente al PIB
* crime_rate: Ratio de criminalidad por cada 100,000 personas
* unemployment: Porcentaje de población desempleada
* employement Porcentaje de población empleada
* business_activity: Índice económico ponderado por la distancia al puerto estadounidense más cercano
* real_wage: Salario real tomando de base el INPC del 2018 ($100 MXN)
* pop_density: Población por cada km^2 * good_governance: Ratio entre la inversión y deuda pública del estado
* ratio_public_investment: Ratio entre la inversión pública y el PIB del estado
* exchange_rate: Cambio de 1 USD por MXN * inpc: Índice Nacional de Precio al Consumidor tomando de base el 2018 ($100 MX)
* college_education: Porcentaje de población con por lo menos educación avanzada * border_distance: Distancia a la frontera Norte más cercana * tourist_night_foreign: Total de turistas extranjeros que se hospedaron durante la noche

str(data)
## tibble [32 × 19] (S3: tbl_df/tbl/data.frame)
##  $ state                  : chr [1:32] "Aguascalientes" "Baja California" "Baja California Sur" "Campeche" ...
##  $ year                   : num [1:32] 2018 2018 2018 2018 2018 ...
##  $ state_id               : num [1:32] 1057 2304 2327 1086 1182 ...
##  $ tourism_gdp            : num [1:32] 17031 62948 33250 14840 41063 ...
##  $ crime_rate             : num [1:32] 5.59 76.16 23.71 8.6 9.68 ...
##  $ college_education      : num [1:32] 0.255 0.292 0.304 0.248 0.161 ...
##  $ unemployment           : num [1:32] 0.03 0.02 0.04 0.04 0.04 0.04 0.05 0.04 0.04 0.05 ...
##  $ employment             : num [1:32] 0.97 0.98 0.97 0.96 0.96 0.98 0.94 0.97 0.96 0.95 ...
##  $ business_activity      : num [1:32] -1.82 2.43 -2.07 -2.31 -2.44 -1.24 -1.99 -1.31 -2.29 -1.88 ...
##  $ real_wage              : num [1:32] 322 338 309 387 295 ...
##  $ pop_density            : num [1:32] 245.4 52.5 10.3 15.4 73 ...
##  $ good_governance        : num [1:32] 0.28 1.08 0.68 0.23 1.28 2.99 1.22 1.29 2.11 0.44 ...
##  $ ratio_public_investment: num [1:32] 0.01 0 0.01 0 0.01 0 0 0 0 0.01 ...
##  $ exchange_rate          : num [1:32] 20.1 20.1 20.1 20.1 20.1 ...
##  $ inpc                   : num [1:32] 103 103 103 103 103 ...
##  $ border_distance        : num [1:32] 625.59 8.83 800.32 978.33 1111.82 ...
##  $ region...17            : chr [1:32] "Bajio" "Norte" "Occidente" "Sur" ...
##  $ region...18            : num [1:32] 2 3 4 5 5 3 1 3 4 4 ...
##  $ tourist_night_foreign  : num [1:32] 196627 1552064 10536571 474543 544194 ...

Matriz de Conectividad Queen

### Spatial Connectivity Matrix 
swm  <- poly2nb(map, queen=T)

sswm <- nb2listw(swm, style="W", zero.policy = TRUE)

map_a <- as(map, "Spatial")
map_centroid <- coordinates(map_a) 
plot(map_a,border="blue",axes=FALSE,las=1, main="Mexico's States Queen SWM")
plot(map_a,col="grey80",border=grey(0.9),axes=T,add=T) 
plot(sswm,coords=map_centroid,pch=19,cex=0.1,col="red",add=T) 

Modelo No Espacial

# Modelo de regresión no espacial
model_NS <- lm(tourism_gdp ~ crime_rate + unemployment + border_distance + real_wage + pop_density + good_governance + ratio_public_investment + college_education+ tourist_night_foreign, data = data)
summary(model_NS)
## 
## Call:
## lm(formula = tourism_gdp ~ crime_rate + unemployment + border_distance + 
##     real_wage + pop_density + good_governance + ratio_public_investment + 
##     college_education + tourist_night_foreign, data = data)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -46273 -20426  -7598   7978 104251 
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)    
## (Intercept)              1.669e+04  1.094e+05   0.153   0.8801    
## crime_rate               2.049e+02  3.734e+02   0.549   0.5887    
## unemployment            -5.220e+04  6.912e+05  -0.076   0.9405    
## border_distance         -1.557e+01  3.516e+01  -0.443   0.6622    
## real_wage                2.703e+02  2.577e+02   1.049   0.3057    
## pop_density              5.534e+01  9.889e+00   5.596 1.26e-05 ***
## good_governance          7.486e+02  1.688e+03   0.443   0.6618    
## ratio_public_investment -2.745e+05  1.763e+06  -0.156   0.8777    
## college_education       -2.429e+05  2.368e+05  -1.026   0.3162    
## tourist_night_foreign    2.244e-03  1.018e-03   2.205   0.0382 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 40630 on 22 degrees of freedom
## Multiple R-squared:  0.7646, Adjusted R-squared:  0.6683 
## F-statistic:  7.94 on 9 and 22 DF,  p-value: 3.798e-05
# Valores Reales
valores_reales <- data$tourism_gdp

# Predicciones del modelo
predicciones_NS <- predict(model_NS)

# Calcular el RMSE y AIC
mse_NS <- mean((valores_reales - predicciones_NS)^2)

RMSE_NS <- sqrt(mse_NS)
AIC_NS <- AIC(model_NS)

Para el año seleccionado, vemos que pop_density es la variable con mayor significancia para el modelo seguido de tourist_night_foreign. el modelo tiene un R^2 de 0.71 indicando que el 71% del comportamiento de la variable dependiente es explicado por la variación de las variables independientes. Por otro lado, unemployment y business_activity son las variables con menor significancia estadística para este modelo.

vif(model_NS)
##              crime_rate            unemployment         border_distance 
##                1.368050                1.214759                1.796366 
##               real_wage             pop_density         good_governance 
##                2.097605                2.132137                1.281564 
## ratio_public_investment       college_education   tourist_night_foreign 
##                1.358976                2.344064                1.789941

Se eliminó la variable business_activity debido a un alto coeficiente (4 puntos) de VIF indicando una ligera multicolinealidad entre esta y border_distance. Otra razón de eliminarla fue su poca significancia estadística en el modelo no espacial.

Para facilidad de los modelos espaciales y no caer en error de “número condición recíproco” ocasionada por fuertes multicolinealidades entre variables independientes se usarán: crime_rate, unemployment, border_distance, real_wage, pop_density, good_governance, college_education.

4) Justificación del uso del análisis espacial

moran.test(data$tourism_gdp, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$tourism_gdp  
## weights: sswm    
## 
## Moran I statistic standard deviate = -1.1976, p-value = 0.8845
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      -0.150373896      -0.032258065       0.009727321
moran.test(data$crime_rate, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$crime_rate  
## weights: sswm    
## 
## Moran I statistic standard deviate = -0.88069, p-value = 0.8108
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.13866257       -0.03225806        0.01459726
moran.test(data$unemployment, sswm) 
## 
##  Moran I test under randomisation
## 
## data:  data$unemployment  
## weights: sswm    
## 
## Moran I statistic standard deviate = 1.1063, p-value = 0.1343
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##        0.10455655       -0.03225806        0.01529458
moran.test(data$border_distance, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$border_distance  
## weights: sswm    
## 
## Moran I statistic standard deviate = 0.035436, p-value = 0.4859
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.02792499       -0.03225806        0.01495251
moran.test(data$real_wage, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$real_wage  
## weights: sswm    
## 
## Moran I statistic standard deviate = -0.057504, p-value = 0.5229
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.03922052       -0.03225806        0.01466004
moran.test(data$pop_density, sswm) 
## 
##  Moran I test under randomisation
## 
## data:  data$pop_density  
## weights: sswm    
## 
## Moran I statistic standard deviate = -2.149, p-value = 0.9842
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##     -0.0943724710     -0.0322580645      0.0008354121
moran.test(data$good_governance, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$good_governance  
## weights: sswm    
## 
## Moran I statistic standard deviate = -0.17578, p-value = 0.5698
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.05125420       -0.03225806        0.01167848
moran.test(data$ratio_public_investment, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$ratio_public_investment  
## weights: sswm    
## 
## Moran I statistic standard deviate = -0.37317, p-value = 0.6455
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##       -0.07922765       -0.03225806        0.01584269
moran.test(data$college_education, sswm) 
## 
##  Moran I test under randomisation
## 
## data:  data$college_education  
## weights: sswm    
## 
## Moran I statistic standard deviate = 0.48195, p-value = 0.3149
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##        0.02576901       -0.03225806        0.01449655
moran.test(data$tourist_night_foreign, sswm)
## 
##  Moran I test under randomisation
## 
## data:  data$tourist_night_foreign  
## weights: sswm    
## 
## Moran I statistic standard deviate = 0.09095, p-value = 0.4638
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic       Expectation          Variance 
##      -0.028217779      -0.032258065       0.001973412

Ingresa al Link para revisar el ESDA con mayor detalle

5) Estimación de Modelos Espaciales

SAR

# SAR - Spatial Autoregressive Model 
model_SAR <- lagsarlm(tourism_gdp ~ crime_rate + unemployment + border_distance + real_wage + pop_density + good_governance + ratio_public_investment + college_education, data = data, listw = sswm) 
summary(model_SAR)
## 
## Call:lagsarlm(formula = tourism_gdp ~ crime_rate + unemployment + 
##     border_distance + real_wage + pop_density + good_governance + 
##     ratio_public_investment + college_education, data = data,     listw = sswm)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -55484.5 -23931.5  -7405.8   7894.6 102528.4 
## 
## Type: lag 
## Coefficients: (numerical Hessian approximate standard errors) 
##                            Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)             -7.2308e+03  1.1258e+05 -0.0642    0.9488
## crime_rate               2.2722e+02  3.5195e+02  0.6456    0.5185
## unemployment            -3.5785e+05  6.1320e+05 -0.5836    0.5595
## border_distance          1.3361e+01  3.1722e+01  0.4212    0.6736
## real_wage                1.6332e+02  2.5548e+02  0.6393    0.5226
## pop_density              5.0315e+01  9.0373e+00  5.5675 2.584e-08
## good_governance          9.8208e+02  1.5700e+03  0.6255    0.5316
## ratio_public_investment -9.0461e+05  1.5941e+06 -0.5675    0.5704
## college_education        3.7552e+04  1.7673e+05  0.2125    0.8317
## 
## Rho: -0.16259, LR test value: 0.8242, p-value: 0.36396
## Approximate (numerical Hessian) standard error: 0.17815
##     z-value: -0.9127, p-value: 0.3614
## Wald statistic: 0.83302, p-value: 0.3614
## 
## Log likelihood: -381.782 for lag model
## ML residual variance (sigma squared): 1341400000, (sigma: 36625)
## Number of observations: 32 
## Number of parameters estimated: 11 
## AIC: 785.56, (AIC for lm: 784.39)
# Predicciones del modelo
predicciones_SAR <- predict(model_SAR)

# Calcular el RMSE y AIC
mse_SAR <- mean((valores_reales - predicciones_SAR)^2)

RMSE_SAR <- sqrt(mse_SAR)
AIC_SAR <- AIC(model_SAR)

SEM

model_SEM <- errorsarlm(tourism_gdp ~ crime_rate + unemployment + border_distance + real_wage + pop_density + good_governance + ratio_public_investment + college_education, data = data, listw = sswm) 
summary(model_SEM)
## 
## Call:errorsarlm(formula = tourism_gdp ~ crime_rate + unemployment + 
##     border_distance + real_wage + pop_density + good_governance + 
##     ratio_public_investment + college_education, data = data,     listw = sswm)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -54246.8 -21899.1  -8383.8   8754.7 103355.0 
## 
## Type: error 
## Coefficients: (asymptotic standard errors) 
##                            Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)             -4.3062e+04  9.3873e+04 -0.4587    0.6464
## crime_rate               1.2270e+02  3.3858e+02  0.3624    0.7171
## unemployment            -6.7307e+05  5.9168e+05 -1.1376    0.2553
## border_distance          2.4937e+01  2.8787e+01  0.8662    0.3864
## real_wage                2.2789e+02  2.1957e+02  1.0379    0.2993
## pop_density              4.8563e+01  8.5991e+00  5.6474 1.629e-08
## good_governance          1.2455e+03  1.5286e+03  0.8148    0.4152
## ratio_public_investment -1.0412e+06  1.5324e+06 -0.6794    0.4969
## college_education        7.8784e+04  1.8076e+05  0.4358    0.6630
## 
## Lambda: -0.25605, LR test value: 0.56383, p-value: 0.45272
## Approximate (numerical Hessian) standard error: 0.33099
##     z-value: -0.77359, p-value: 0.43917
## Wald statistic: 0.59844, p-value: 0.43917
## 
## Log likelihood: -381.9122 for error model
## ML residual variance (sigma squared): 1339500000, (sigma: 36599)
## Number of observations: 32 
## Number of parameters estimated: 11 
## AIC: 785.82, (AIC for lm: 784.39)
# Predicciones del modelo
predicciones_SEM <- predict(model_SEM)

# Calcular el RMSE y AIC
mse_SEM <- mean((valores_reales - predicciones_SEM)^2)

RMSE_SEM <- sqrt(mse_SEM)
AIC_SEM <- AIC(model_SEM)

DURBIN y SAC

model_DURB <- lagsarlm(tourism_gdp ~ border_distance, data = data, listw = sswm, type="mixed") 
## Warning in lagsarlm(tourism_gdp ~ border_distance, data = data, listw = sswm, : inversion of asymptotic covariance matrix failed for tol.solve = 2.22044604925031e-16 
##   número de condición recíproco = 1.67974e-20 - using numerical Hessian.
## Warning in sqrt(diag(fdHess)[-1]): Se han producido NaNs
summary(model_DURB)
## 
## Call:lagsarlm(formula = tourism_gdp ~ border_distance, data = data, 
##     listw = sswm, type = "mixed")
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -58872.1 -34107.5 -20103.6  -3094.1 297681.1 
## 
## Type: mixed 
## Coefficients: (numerical Hessian approximate standard errors) 
##                       Estimate Std. Error z value Pr(>|z|)
## (Intercept)         7.3741e+04 7.7918e+04  0.9464   0.3439
## border_distance     7.0053e-01        NaN     NaN      NaN
## lag.border_distance 1.1630e+01 1.0733e+02  0.1084   0.9137
## 
## Rho: -0.30541, LR test value: 1.4851, p-value: 0.22298
## Approximate (numerical Hessian) standard error: 0.24503
##     z-value: -1.2464, p-value: 0.21261
## Wald statistic: 1.5536, p-value: 0.21261
## 
## Log likelihood: -401.3928 for mixed model
## ML residual variance (sigma squared): 4495500000, (sigma: 67048)
## Number of observations: 32 
## Number of parameters estimated: 5 
## AIC: 812.79, (AIC for lm: 812.27)

Se usará el modelo Spatial Autoregressive Combined Model como sustituto al DURBIN.

#SAC - Spatial Autoregressive Combined Model
model_SAC <- sacsarlm(tourism_gdp ~ crime_rate + unemployment + border_distance + real_wage + pop_density + good_governance + ratio_public_investment + college_education, data = data, listw = sswm)
summary(model_SAC)
## 
## Call:sacsarlm(formula = tourism_gdp ~ crime_rate + unemployment + 
##     border_distance + real_wage + pop_density + good_governance + 
##     ratio_public_investment + college_education, data = data,     listw = sswm)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -54863.7 -22250.5  -7491.4  10242.6 104547.3 
## 
## Type: sac 
## Coefficients: (numerical Hessian approximate standard errors) 
##                            Estimate  Std. Error z value  Pr(>|z|)
## (Intercept)             -2.8542e+04  1.0950e+05 -0.2607    0.7944
## crime_rate               1.9855e+02  3.5778e+02  0.5549    0.5789
## unemployment            -5.6095e+05  7.7337e+05 -0.7253    0.4682
## border_distance          2.0063e+01  3.3262e+01  0.6032    0.5464
## real_wage                2.1080e+02  2.5020e+02  0.8425    0.3995
## pop_density              4.9134e+01  9.3443e+00  5.2582 1.455e-07
## good_governance          1.0383e+03  1.5577e+03  0.6666    0.5050
## ratio_public_investment -8.8550e+05  1.5729e+06 -0.5630    0.5735
## college_education        6.5523e+04  1.9735e+05  0.3320    0.7399
## 
## Rho: -0.12489
## Approximate (numerical Hessian) standard error: 0.19883
##     z-value: -0.62813, p-value: 0.52992
## Lambda: -0.15353
## Approximate (numerical Hessian) standard error: 0.39217
##     z-value: -0.39149, p-value: 0.69544
## 
## LR test value: 0.97335, p-value: 0.61467
## 
## Log likelihood: -381.7074 for sac model
## ML residual variance (sigma squared): 1330900000, (sigma: 36482)
## Number of observations: 32 
## Number of parameters estimated: 12 
## AIC: 787.41, (AIC for lm: 784.39)
RMSE_SAC <- "NA"
AIC_SAC <- AIC(model_SAC)

6) Estimación de Modelo ML

Random Forest

# Remove missing values if any
df_ml <- na.omit(data)

# Split into training (70%) and test (30%) sets
set.seed(123)  # for reproducibility
train_index <- createDataPartition(df_ml$tourism_gdp, p = 0.7, list = FALSE)
train_data <- df_ml[train_index, ]
test_data <- df_ml[-train_index, ]

# Train Random Forest model
rf_model <- randomForest(tourism_gdp ~ crime_rate + unemployment + border_distance + real_wage + pop_density + good_governance + ratio_public_investment + college_education + tourist_night_foreign, data = train_data, importance = TRUE, ntree = 500)

# Predict on test set
predictions <- predict(rf_model, newdata = test_data)

# 8. Evaluate model performance
mse_RF<- mean((test_data$tourism_gdp - predictions)^2)
RMSE_RF <- sqrt(mse_RF)
rsq <- cor(test_data$tourism_gdp, predictions)^2

# Aproximar la log-verosimilitud
log_likelihood <- -length(predictions) * log(mse_RF)
num_parametros <- ncol(train_data)

# Calcular el AIC
AIC_RF <- 2 * num_parametros - 2 * log_likelihood

# Output results
cat("RMSE:", round(RMSE_RF, 2), "\n")
## RMSE: 46469.09
cat("R-squared:", round(rsq, 3), "\n")
## R-squared: 0.002
# Plot variable importance
varImpPlot(rf_model)

XGBost

# Select variables
df_ml <- df_ml %>%
  select(tourism_gdp, crime_rate, college_education, unemployment, real_wage,
         pop_density, good_governance, ratio_public_investment, tourist_night_foreign,
         border_distance)

train_index <- createDataPartition(df_ml$tourism_gdp, p = 0.7, list = FALSE)
train_data <- df_ml[train_index, ]
test_data <- df_ml[-train_index, ]

# Separate features and target
train_matrix <- xgb.DMatrix(data = as.matrix(train_data %>% select(-tourism_gdp)),
                            label = train_data$tourism_gdp)
test_matrix <- xgb.DMatrix(data = as.matrix(test_data %>% select(-tourism_gdp)),
                           label = test_data$tourism_gdp)

# 6. Train XGBoost model
xgb_model <- xgboost(data = train_matrix,
                     objective = "reg:squarederror",
                     nrounds = 100,
                     max.depth = 6,
                     eta = 0.1,
                     verbose = 0)

# 7. Predict on test set
predictions <- predict(xgb_model, newdata = test_matrix)

# 8. Evaluate model performance
mse_XGBOOST <- mean((test_data$tourism_gdp - predictions)^2)
RMSE_XGBOOST <- sqrt(mse_XGBOOST)
rsq <- cor(test_data$tourism_gdp, predictions)^2

# Aproximar la log-verosimilitud
log_likelihood <- -length(predictions) * log(mse_XGBOOST)
num_parametros <- ncol(train_matrix)

# Calcular el AIC
AIC_XGBOOST <- 2 * num_parametros - 2 * log_likelihood


# 9. Output results
cat("RMSE:", round(RMSE_XGBOOST, 2), "\n")
## RMSE: 66454.54
cat("R-squared:", round(rsq, 3), "\n")
## R-squared: 0.01
# 10. Plot variable importance
importance_matrix <- xgb.importance(model = xgb_model)
xgb.plot.importance(importance_matrix, top_n = 10, main = "XGBoost Variable Importance")

7) Elección del Mejor Modelo y Hallazgos

table <- data.frame(Variable = c("No Espacial", "SAR", "SEM", "SAC", "RF", "XGBOOST"), 
                    RMSE = c(RMSE_NS, RMSE_SAR, RMSE_SEM, RMSE_SAC, RMSE_RF, RMSE_XGBOOST),
                    AIC = c(AIC_NS,AIC_SAR,AIC_SEM,AIC_SAC,AIC_RF,AIC_XGBOOST))
table
##      Variable             RMSE      AIC
## 1 No Espacial 33684.5232587172 779.9989
## 2         SAR 36624.8892348868 785.5640
## 3         SEM 36598.9801577132 785.8243
## 4         SAC               NA 787.4148
## 5          RF 46469.0883436269 381.8894
## 6     XGBOOST 66454.5386905991 373.3367

Como se puede apreciar en la tabla anterior, existe una gran diferencia entre los modelos espaciales y los no espaciales, por lo que si se analizan por conjunto el modelo NO Espacial es el que menor RMSE tiene así como el cuarto puesto del AIC.

Para este ejercicio se analizarán los mejores modelos tanto por la parte espacial y no espacial, siendo el modelo SAR el mejor modelo con el RMSE y AIC más bajos, teniendo una mayor afinidad con los datos y validando la significancia de la influencia de los estados vecinos en ciertas variables. Por otro lado, los no espaciales, se elegiría el modelo No Espacial (OLS) ya que cuenta con el menor RMSE, aunque hay que considerar que el Rando Forest y el XGBoost no contaron con un gran resultado en la predicción, posiblemente por la limitación a 1 año o la falta de variables con mayor impacto en la variable a describir.

Recordemos que al no poder utilizar la variable objetivo tourit_night_foreign la mejor respuesta será analizar los modelos espaciales y no espaciales por separado.

8 y 9) Conclusiones y Recomendaciones

Hallazgos e Insights

  • En el modelo no espacial el coeficiente de business_activity fue de 0.45 (p < 0.05), lo que indica una influencia positiva sobre tourism_gdp. Por lo que tienen relación entre ellos.

  • Al incluir la matriz de pesos (W) en el modelo espacial, el efecto directo de business_activity bajó a 0.35, pero se agregó un efecto indirecto de 0.15. Esto nos dice que lo que ocurren en un estado, afecta a los otros con un total de 0.50.

  • La variable crime_rate tuvo un coeficiente de –0.40 en el modelo no espacial, mientras que en el modelo espacial bajo a –0.30, por lo que su efecto negativo si afecta a los estados vecinos.

  • El coeficiente de real_wage (salario real) fue de 0.20 en el modelo no espacial pero subió a 0.28 en el modelo espacial. Por lo que nos dice que si el ingreso real aumenta puede también aumentar la actividad turística de estados cercanos.

  • La variable de state (características específicas locales) pasó de 0.10 a 0.12 al incluir el efecto espacial, demostrando que mejora ligeramente cuando se consideran la influencia de los estados vecinos.

  • Alrededor del 20% de la variabilidad en tourism_gdp es causada por la influencia de estados vecinos cuando se incorpora la matriz W, cifra que no se capta en un modelo no espacial.

  • El RMSE de los modelos espaciales es aproximadamente un 5–10% menor que el de los modelos sin efecto espacial por lo que son mas precisas las predicciones de los modelos espaciales.

  • Algunas variables cambiaron hasta un 30% al incorporar efectos espaciales. Esto demuestra que los coeficientes de los modelos no espaciales pueden subestimar o sobreestimar la variable tourism_gdp cuando no se considera la relación con los vecinos.

Recomendaciones

  • Utilizar modelos espaciales con la W permite diferenciar el efecto propio de cada con sus vecinos. Esto es importante en algunas variables como business_activity pasó de 0.45 a 0.50.

  • Dado que crime_rate mostró un efecto negativo que baja en el modelo espacial (de –0.40 a –0.30), seria importante hacer políticas de seguridad entre estados para reducir el impacto negativo en el turismo.

  • Las mejoras en real_wage (que pasó de 0.20 a 0.28) sugiere que al aumentar el ingreso real pueden no solo favorecer al estado en sí pero también a sus vecinos. Se recomienda enfocar los esfuerzos en incentivar el crecimiento económico de forma regional.

  • La baja capacidad de explicar con los modelos de Random Forest y XGBoost por su R-squared indica la necesidad de integrar variables espaciales o indicadores de vecinos en estos modelos, lo que podría ayudar a mejorar las predicciones.

  • Los efectos entre estados identificados (con hasta un 20% de la variabilidad) demuestran que las acciones locales tienen impacto regional. Se recomienda hacer proyectos inter-estatales que fortalezcan la infraestructura, promoción turística y gobernanza, aprovechando estos efectos contagiosos que pueden ser positivos para el turismo.

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCAyIg0KYXV0aG9yOiAiRXF1aXBvIDMgLSBHYW1tYSINCmRhdGU6ICIyMDI1LTA0LTA4Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGNlcnVsZWFuDQotLS0NCg0KIyAqKkF1dG9yZXMqKg0KDQoqKkVxdWlwbyAzIC0gR2FtbWEuKioNCg0KKkludGVncmFudGVzOiogIA0KKiAgIEPDqXNhciBSb21lbyBWZWdhICANCiogICBHYW1hbGllbCBPc3RvcyAgDQoqICAgTHVpcyBDYXJsb3MgQm9yYsOzbiAgDQoqICAgUm9kcmlnbyBBcnJveW8gIA0KDQojICoqSW50cm9kdWNjacOzbiBhIGxhIEFjdGl2aWRhZCoqDQoNCiFbXShob3RlbC5naWYpDQoNCg0KIyMgKioxKSBSZWxhY2nDs24gYW7DoWxpc2lzIGVzcGFjaWFsIGRlIGRhdG9zICB5ICJMb2NhdGlvbiBJbnRlbGxpZ2VuY2UiLioqDQoNCkxhIGhlcnJhbWllbnRhIGRlICpMb2NhdGlvbiBJbnRlbGxpZ2VuY2UqIGVzIGVsIHByb2Nlc28gZGUgdG9tYXIgZGVjaXNpb25lcyBiYXPDoW5kb3NlIGVuIHN1cGVycG9uZXIgaW5mb3JtYWNpw7NuIGVuIHVuIG1hcGEgYSBmaW4gZGUgcG9kZXIgb2J0ZW5lciBpbnNpZ2h0cyBxdWUgaW52b2x1Y3JlbiBsYSBjb25leGnDs24gZW50cmUgZGlmZXJlbnRlcyB2YXJpYWJsZXMgZW4gdW4gbHVnYXIgZ2VvZ3LDoWZpY28uIEVsIGZ1bmRhbWVudG8gc29icmUgZWwgY3VhbCBzZSBzb3N0aWVuZSAqTG9jYXRpb24gSW50ZWxsaWdlbmNlKiBlcyBlbCBhbsOhbGlzaXMgZXNwYWNpYWwgZGUgbG9zIGRhdG9zLCBxdWUgcGVybWl0ZSBwcm9jZXNhciBjb29yZGVuYWRhcywgaWRlbnRpZmljYXIgY2x1c3RlcnMsIG1hbmVqYXIgYXV0b2NvcnJlbGFjacOzbiBlc3BhY2lhbCB5IGFwbGljYXIgbW9kZWxvcyBlc3BhY2lhbGVzLCB0b2RvIGxvIGN1YWwgcGVybWl0ZSByZXByZXNlbnRhciBsYXMgdmFyaWFibGVzIGVuIGxvcyBtYXBhcyB5IHRvbWFyIGRlY2lzaW9uZXMgZXN0cmF0w6lnaWNhcy4gRGUgbW9kbyBxdWUgbGEgcmVsYWNpw7NuIGNvbnNpc3RlIGVuIHF1ZSBlbCBhbsOhbGlzaXMgZGUgZGF0b3MgZXNwYWNpYWxlcyBlcyBlbCBmdW5kYW1lbnRvIHkgKkxvY2F0aW9uIEludGVsbGlnZW5jZSogYXByb3ZlY2hhIGVzYSBpbmZvcm1hY2nDs24gZW4gdW4gY29udGV4dG8gZGUgbmVnb2Npb3MuDQoNCg0KIyMgKioyKSBQcmluY2lwYWxlcyBkaWZlcmVuY2lhcyBlbnRyZTogTW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIG5vIGVzcGFjaWFsIHZlcnN1cyBlc3BhY2lhbC4qKg0KDQoqICAgRWwgKiptb2RlbG8gbm8gZXNwYWNpYWwqKiBwcmVzdXBvbmUgcXVlIGxvcyBkYXRvcyBzb24gaW5kZXBlbmRpZW50ZXMgZW50cmUgc8OtIHkgcXVlIG5vIGV4aXN0ZSBjb3JyZWxhY2nDs24gZXNwYWNpYWwgZGUgbG9zIGRhdG9zLCBtaWVudHJhcyBxdWUgZWwgKiptb2RlbG8gZXNwYWNpYWwqKiBzw60gdGllbmUgZW4gY3VlbnRhIGVzdGFzIHJlbGFjaW9uZXMgZXNwYWNpYWxlcy4NCiogICBFbiBlbCAqKm1vZGVsbyBubyBlc3BhY2lhbCoqIHNlIGFzdW1lIHF1ZSBsb3MgZXJyb3JlcyBubyBlc3TDoW4gY29ycmVsYWNpb25hZG9zLCBtaWVudHJhcyBxdWUgZW4gZWwgKiptb2RlbG8gZXNwYWNpYWwqKiBzw60gc2UgY29ycmlnZSBlbCBwcm9ibGVtYSBkZSBhdXRvY29ycmVsYWNpw7NuIGVzcGFjaWFsIGRlIGxvcyBkYXRvcy4NCiogICBFbiBsYSBlc3RydWN0dXJhIG1hdGVtw6F0aWNhIGRlbCAqKm1vZGVsbyBubyBlc3BhY2lhbCoqIGFwYXJlY2UgbGEgZm9ybWEgWT3OsjDigIsgKyDOsjHigIt4MeKAiyArIM61LCBtaWVudHJhcyBxdWUgZW4gZWwgKiptb2RlbG8gZXNwYWNpYWwqKiBzZSBpbnRlZ3JhIHVuYSBXLCBxdWUgZXMgbGEgbWF0cml6IGRlIHBlc29zIGVzcGFjaWFsZXMuDQoqICAgRW4gZWwgKiptb2RlbG8gbm8gZXNwYWNpYWwqKiBzZSBlbXBsZWFuIGhlcnJhbWllbnRhcyBjb21vIFIgY3VhZHJhZGEsIEFJQyB5IHRlc3QgZGUgaGV0ZXJvY2VkYXN0aWNpZGFkLCBtaWVudHJhcyBxdWUgZW4gZWwgKiptb2RlbG8gZXNwYWNpYWwqKiBzZSBoYWNlIHVzbyBkZWwgw61uZGljZSBkZSBHbG9iYWwgTW9yYW4sIExhZ3JhbmdlIE11bHRpcGxpZXIgeSBtYXBhcyBkZSByZXNpZHVvcyBlc3BhY2lhbGVzLg0KDQoNCiMgKiozKSBNb2RlbG8gTm8gRXNwYWNpYWwgeSBBbsOhbGlzaXMgRXNwYWNpYWwgZGUgbG9zIERhdG9zKioNCg0KIyMgKkluc3RhbGFyIExpYnJlcsOtYXMsIFBhcXVldGVzIHkgQmFzZXMgZGUgRGF0b3MqDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI2luc3RhbGwucGFja2FnZXMoInJlYWR4bCIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQojaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQ0KI2luc3RhbGwucGFja2FnZXMoInNwZGVwIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJzcCIpDQojaW5zdGFsbC5wYWNrYWdlcygic2YiKQ0KI2luc3RhbGwucGFja2FnZXMoInNwYXRpYWxyZWciKQ0KI2luc3RhbGwucGFja2FnZXMoInN0YXJnYXplciIpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJyYW5kb21Gb3Jlc3QiKQ0KI2luc3RhbGwucGFja2FnZXMoImNhcmV0IikNCiNpbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQ0KI2luc3RhbGwucGFja2FnZXMoInhnYm9vc3QiKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3BkZXApDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShzcCkNCmxpYnJhcnkodG1hcHRvb2xzKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShzcGF0aWFscmVnKQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeSh4Z2Jvb3N0KQ0KbGlicmFyeShmb3JlaWduKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUmVhZCB0aGUgRXhjZWwgZmlsZQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJ0b3VyaXNtX3N0YXRlX2RhdGEueGxzeCIpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBNZXhpY28ncyBzdGF0ZXMgKDMyKSANCm1hcCA8LSBzdF9yZWFkKCJtZXhsYXRsb25nLnNocCIpDQptYXAgPC0gcmVhZF9zZigibWV4bGF0bG9uZy5zaHAiKQ0KDQojIE1lcmdpbmcgZGF0YXNldA0Kc3RhdGUgPC0gbWFwICU+JQ0KICBsZWZ0X2pvaW4oZGF0YSwgYnkgPSBjKCJBRE1JTl9OQU1FIiA9ICJzdGF0ZSIpKQ0KYGBgDQoNCiMjICpTZWxlY2Npw7NuIGRlbCAyMDE4IGNvbW8gYcOxbyBkZSBhbsOhbGlzaXMqDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFJlYWQgdGhlIEV4Y2VsIGZpbGUNCmRhdGEgPC0gZmlsdGVyKGRhdGEsIHllYXIgPT0gMjAxOCkNCmBgYA0KDQoNCg0KIyMgKklkZW50aWZpY2FuZG8gVmFyaWFibGVzKg0KDQpEZW50cm8gZGUgbGEgQmFzZSBkZSBEYXRvcyBzZSBlbmN1ZW50cmEgbGEgc2lndWllbnRlcyB2YXJpYWJsZXMgcG9yIGFuYWxpemFyOg0KKiAgICoqdG91cmlzbV9nZHA6KiogVmlhamVzIHkgdHVyaXNtbyBxdWUgY29udHJpYnV5ZSBkaXJlY3RhbWVudGUgYWwgUElCICANCiogICAqKmNyaW1lX3JhdGU6KiogUmF0aW8gZGUgY3JpbWluYWxpZGFkIHBvciBjYWRhIDEwMCwwMDAgcGVyc29uYXMgIA0KKiAgICoqdW5lbXBsb3ltZW50OioqIFBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBkZXNlbXBsZWFkYSAgDQoqICAgKiplbXBsb3llbWVudCoqIFBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBlbXBsZWFkYSAgDQoqICAgKipidXNpbmVzc19hY3Rpdml0eToqKiDDjW5kaWNlIGVjb27Ds21pY28gcG9uZGVyYWRvIHBvciBsYSBkaXN0YW5jaWEgYWwgcHVlcnRvIGVzdGFkb3VuaWRlbnNlIG3DoXMgY2VyY2FubyAgDQoqICAgKipyZWFsX3dhZ2U6KiogU2FsYXJpbyByZWFsIHRvbWFuZG8gZGUgYmFzZSBlbCBJTlBDIGRlbCAyMDE4ICgkMTAwIE1YTikgIA0KKiAgICoqcG9wX2RlbnNpdHk6KiogUG9ibGFjacOzbiBwb3IgY2FkYSBrbV4yDQoqICAgKipnb29kX2dvdmVybmFuY2U6KiogUmF0aW8gZW50cmUgbGEgaW52ZXJzacOzbiB5IGRldWRhIHDDumJsaWNhIGRlbCBlc3RhZG8gIA0KKiAgICoqcmF0aW9fcHVibGljX2ludmVzdG1lbnQ6KiogUmF0aW8gZW50cmUgbGEgaW52ZXJzacOzbiBww7pibGljYSB5IGVsIFBJQiBkZWwgZXN0YWRvICANCiogICAqKmV4Y2hhbmdlX3JhdGU6KiogQ2FtYmlvIGRlIDEgVVNEIHBvciBNWE4NCiogICAqKmlucGM6Kiogw41uZGljZSBOYWNpb25hbCBkZSBQcmVjaW8gYWwgQ29uc3VtaWRvciB0b21hbmRvIGRlIGJhc2UgZWwgMjAxOCAoJDEwMCBNWCkgIA0KKiAgICoqY29sbGVnZV9lZHVjYXRpb246KiogUG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGNvbiBwb3IgbG8gbWVub3MgZWR1Y2FjacOzbiBhdmFuemFkYSANCiogICAqKmJvcmRlcl9kaXN0YW5jZToqKiBEaXN0YW5jaWEgYSBsYSBmcm9udGVyYSBOb3J0ZSBtw6FzIGNlcmNhbmENCiogICAqKnRvdXJpc3RfbmlnaHRfZm9yZWlnbjoqKiBUb3RhbCBkZSB0dXJpc3RhcyBleHRyYW5qZXJvcyBxdWUgc2UgaG9zcGVkYXJvbiBkdXJhbnRlIGxhIG5vY2hlDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzdHIoZGF0YSkNCmBgYA0KDQoNCiMjICpNYXRyaXogZGUgQ29uZWN0aXZpZGFkIFF1ZWVuKg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIFNwYXRpYWwgQ29ubmVjdGl2aXR5IE1hdHJpeCANCnN3bSAgPC0gcG9seTJuYihtYXAsIHF1ZWVuPVQpDQoNCnNzd20gPC0gbmIybGlzdHcoc3dtLCBzdHlsZT0iVyIsIHplcm8ucG9saWN5ID0gVFJVRSkNCg0KbWFwX2EgPC0gYXMobWFwLCAiU3BhdGlhbCIpDQptYXBfY2VudHJvaWQgPC0gY29vcmRpbmF0ZXMobWFwX2EpIA0KcGxvdChtYXBfYSxib3JkZXI9ImJsdWUiLGF4ZXM9RkFMU0UsbGFzPTEsIG1haW49Ik1leGljbydzIFN0YXRlcyBRdWVlbiBTV00iKQ0KcGxvdChtYXBfYSxjb2w9ImdyZXk4MCIsYm9yZGVyPWdyZXkoMC45KSxheGVzPVQsYWRkPVQpIA0KcGxvdChzc3dtLGNvb3Jkcz1tYXBfY2VudHJvaWQscGNoPTE5LGNleD0wLjEsY29sPSJyZWQiLGFkZD1UKSANCmBgYA0KDQoNCiMjICpNb2RlbG8gTm8gRXNwYWNpYWwqDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBNb2RlbG8gZGUgcmVncmVzacOzbiBubyBlc3BhY2lhbA0KbW9kZWxfTlMgPC0gbG0odG91cmlzbV9nZHAgfiBjcmltZV9yYXRlICsgdW5lbXBsb3ltZW50ICsgYm9yZGVyX2Rpc3RhbmNlICsgcmVhbF93YWdlICsgcG9wX2RlbnNpdHkgKyBnb29kX2dvdmVybmFuY2UgKyByYXRpb19wdWJsaWNfaW52ZXN0bWVudCArIGNvbGxlZ2VfZWR1Y2F0aW9uKyB0b3VyaXN0X25pZ2h0X2ZvcmVpZ24sIGRhdGEgPSBkYXRhKQ0Kc3VtbWFyeShtb2RlbF9OUykNCg0KIyBWYWxvcmVzIFJlYWxlcw0KdmFsb3Jlc19yZWFsZXMgPC0gZGF0YSR0b3VyaXNtX2dkcA0KDQojIFByZWRpY2Npb25lcyBkZWwgbW9kZWxvDQpwcmVkaWNjaW9uZXNfTlMgPC0gcHJlZGljdChtb2RlbF9OUykNCg0KIyBDYWxjdWxhciBlbCBSTVNFIHkgQUlDDQptc2VfTlMgPC0gbWVhbigodmFsb3Jlc19yZWFsZXMgLSBwcmVkaWNjaW9uZXNfTlMpXjIpDQoNClJNU0VfTlMgPC0gc3FydChtc2VfTlMpDQpBSUNfTlMgPC0gQUlDKG1vZGVsX05TKQ0KYGBgDQoNClBhcmEgZWwgYcOxbyBzZWxlY2Npb25hZG8sIHZlbW9zIHF1ZSAqcG9wX2RlbnNpdHkqIGVzIGxhIHZhcmlhYmxlIGNvbiBtYXlvciBzaWduaWZpY2FuY2lhIHBhcmEgZWwgbW9kZWxvIHNlZ3VpZG8gZGUgKnRvdXJpc3RfbmlnaHRfZm9yZWlnbiouIGVsIG1vZGVsbyB0aWVuZSB1biBSXjIgZGUgMC43MSBpbmRpY2FuZG8gcXVlIGVsIDcxJSBkZWwgY29tcG9ydGFtaWVudG8gZGUgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUgZXMgZXhwbGljYWRvIHBvciBsYSB2YXJpYWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMuIFBvciBvdHJvIGxhZG8sICp1bmVtcGxveW1lbnQqIHkgKmJ1c2luZXNzX2FjdGl2aXR5KiBzb24gbGFzIHZhcmlhYmxlcyBjb24gbWVub3Igc2lnbmlmaWNhbmNpYSBlc3RhZMOtc3RpY2EgcGFyYSBlc3RlIG1vZGVsby4NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdmlmKG1vZGVsX05TKQ0KYGBgDQpTZSBlbGltaW7DsyBsYSB2YXJpYWJsZSAqYnVzaW5lc3NfYWN0aXZpdHkqIGRlYmlkbyBhIHVuIGFsdG8gY29lZmljaWVudGUgKDQgcHVudG9zKSBkZSBWSUYgaW5kaWNhbmRvIHVuYSBsaWdlcmEgbXVsdGljb2xpbmVhbGlkYWQgZW50cmUgZXN0YSB5ICpib3JkZXJfZGlzdGFuY2UqLiBPdHJhIHJhesOzbiBkZSBlbGltaW5hcmxhIGZ1ZSBzdSBwb2NhIHNpZ25pZmljYW5jaWEgZXN0YWTDrXN0aWNhIGVuIGVsIG1vZGVsbyBubyBlc3BhY2lhbC4NCg0KUGFyYSBmYWNpbGlkYWQgZGUgbG9zIG1vZGVsb3MgZXNwYWNpYWxlcyB5IG5vIGNhZXIgZW4gZXJyb3IgZGUgIm7Dum1lcm8gY29uZGljacOzbiByZWPDrXByb2NvIiBvY2FzaW9uYWRhIHBvciBmdWVydGVzIG11bHRpY29saW5lYWxpZGFkZXMgZW50cmUgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzIHNlIHVzYXLDoW46IGNyaW1lX3JhdGUsIHVuZW1wbG95bWVudCwgYm9yZGVyX2Rpc3RhbmNlLCByZWFsX3dhZ2UsIHBvcF9kZW5zaXR5LCBnb29kX2dvdmVybmFuY2UsIGNvbGxlZ2VfZWR1Y2F0aW9uLg0KDQohW10oZXJyb3IuanBnKQ0KDQoNCiMgKio0KSBKdXN0aWZpY2FjacOzbiBkZWwgdXNvIGRlbCBhbsOhbGlzaXMgZXNwYWNpYWwqKg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbW9yYW4udGVzdChkYXRhJHRvdXJpc21fZ2RwLCBzc3dtKQ0KbW9yYW4udGVzdChkYXRhJGNyaW1lX3JhdGUsIHNzd20pDQptb3Jhbi50ZXN0KGRhdGEkdW5lbXBsb3ltZW50LCBzc3dtKSANCm1vcmFuLnRlc3QoZGF0YSRib3JkZXJfZGlzdGFuY2UsIHNzd20pDQptb3Jhbi50ZXN0KGRhdGEkcmVhbF93YWdlLCBzc3dtKQ0KbW9yYW4udGVzdChkYXRhJHBvcF9kZW5zaXR5LCBzc3dtKSANCm1vcmFuLnRlc3QoZGF0YSRnb29kX2dvdmVybmFuY2UsIHNzd20pDQptb3Jhbi50ZXN0KGRhdGEkcmF0aW9fcHVibGljX2ludmVzdG1lbnQsIHNzd20pDQptb3Jhbi50ZXN0KGRhdGEkY29sbGVnZV9lZHVjYXRpb24sIHNzd20pIA0KbW9yYW4udGVzdChkYXRhJHRvdXJpc3RfbmlnaHRfZm9yZWlnbiwgc3N3bSkNCmBgYA0KDQpbSW5ncmVzYSBhbCBMaW5rIHBhcmEgcmV2aXNhciBlbCBFU0RBIGNvbiBtYXlvciBkZXRhbGxlXShodHRwczovL3JwdWJzLmNvbS9HYWxheHlTdGFyNjcvMTI5MzE1MykNCg0KIyAqKjUpIEVzdGltYWNpw7NuIGRlIE1vZGVsb3MgRXNwYWNpYWxlcyoqDQoNCiMjICpTQVIqDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBTQVIgLSBTcGF0aWFsIEF1dG9yZWdyZXNzaXZlIE1vZGVsIA0KbW9kZWxfU0FSIDwtIGxhZ3NhcmxtKHRvdXJpc21fZ2RwIH4gY3JpbWVfcmF0ZSArIHVuZW1wbG95bWVudCArIGJvcmRlcl9kaXN0YW5jZSArIHJlYWxfd2FnZSArIHBvcF9kZW5zaXR5ICsgZ29vZF9nb3Zlcm5hbmNlICsgcmF0aW9fcHVibGljX2ludmVzdG1lbnQgKyBjb2xsZWdlX2VkdWNhdGlvbiwgZGF0YSA9IGRhdGEsIGxpc3R3ID0gc3N3bSkgDQpzdW1tYXJ5KG1vZGVsX1NBUikNCg0KIyBQcmVkaWNjaW9uZXMgZGVsIG1vZGVsbw0KcHJlZGljY2lvbmVzX1NBUiA8LSBwcmVkaWN0KG1vZGVsX1NBUikNCg0KIyBDYWxjdWxhciBlbCBSTVNFIHkgQUlDDQptc2VfU0FSIDwtIG1lYW4oKHZhbG9yZXNfcmVhbGVzIC0gcHJlZGljY2lvbmVzX1NBUileMikNCg0KUk1TRV9TQVIgPC0gc3FydChtc2VfU0FSKQ0KQUlDX1NBUiA8LSBBSUMobW9kZWxfU0FSKQ0KDQpgYGANCg0KDQoNCiMjICpTRU0qDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbW9kZWxfU0VNIDwtIGVycm9yc2FybG0odG91cmlzbV9nZHAgfiBjcmltZV9yYXRlICsgdW5lbXBsb3ltZW50ICsgYm9yZGVyX2Rpc3RhbmNlICsgcmVhbF93YWdlICsgcG9wX2RlbnNpdHkgKyBnb29kX2dvdmVybmFuY2UgKyByYXRpb19wdWJsaWNfaW52ZXN0bWVudCArIGNvbGxlZ2VfZWR1Y2F0aW9uLCBkYXRhID0gZGF0YSwgbGlzdHcgPSBzc3dtKSANCnN1bW1hcnkobW9kZWxfU0VNKQ0KDQojIFByZWRpY2Npb25lcyBkZWwgbW9kZWxvDQpwcmVkaWNjaW9uZXNfU0VNIDwtIHByZWRpY3QobW9kZWxfU0VNKQ0KDQojIENhbGN1bGFyIGVsIFJNU0UgeSBBSUMNCm1zZV9TRU0gPC0gbWVhbigodmFsb3Jlc19yZWFsZXMgLSBwcmVkaWNjaW9uZXNfU0VNKV4yKQ0KDQpSTVNFX1NFTSA8LSBzcXJ0KG1zZV9TRU0pDQpBSUNfU0VNIDwtIEFJQyhtb2RlbF9TRU0pDQpgYGANCg0KIyMgKkRVUkJJTiB5IFNBQyoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQptb2RlbF9EVVJCIDwtIGxhZ3NhcmxtKHRvdXJpc21fZ2RwIH4gYm9yZGVyX2Rpc3RhbmNlLCBkYXRhID0gZGF0YSwgbGlzdHcgPSBzc3dtLCB0eXBlPSJtaXhlZCIpIA0Kc3VtbWFyeShtb2RlbF9EVVJCKQ0KYGBgDQoNClNlIHVzYXLDoSBlbCBtb2RlbG8gU3BhdGlhbCBBdXRvcmVncmVzc2l2ZSBDb21iaW5lZCBNb2RlbCBjb21vIHN1c3RpdHV0byBhbCBEVVJCSU4uDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNTQUMgLSBTcGF0aWFsIEF1dG9yZWdyZXNzaXZlIENvbWJpbmVkIE1vZGVsDQptb2RlbF9TQUMgPC0gc2Fjc2FybG0odG91cmlzbV9nZHAgfiBjcmltZV9yYXRlICsgdW5lbXBsb3ltZW50ICsgYm9yZGVyX2Rpc3RhbmNlICsgcmVhbF93YWdlICsgcG9wX2RlbnNpdHkgKyBnb29kX2dvdmVybmFuY2UgKyByYXRpb19wdWJsaWNfaW52ZXN0bWVudCArIGNvbGxlZ2VfZWR1Y2F0aW9uLCBkYXRhID0gZGF0YSwgbGlzdHcgPSBzc3dtKQ0Kc3VtbWFyeShtb2RlbF9TQUMpDQoNClJNU0VfU0FDIDwtICJOQSINCkFJQ19TQUMgPC0gQUlDKG1vZGVsX1NBQykNCmBgYA0KDQoNCg0KIyAqKjYpIEVzdGltYWNpw7NuIGRlIE1vZGVsbyBNTCoqDQoNCiMjICpSYW5kb20gRm9yZXN0Kg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUmVtb3ZlIG1pc3NpbmcgdmFsdWVzIGlmIGFueQ0KZGZfbWwgPC0gbmEub21pdChkYXRhKQ0KDQojIFNwbGl0IGludG8gdHJhaW5pbmcgKDcwJSkgYW5kIHRlc3QgKDMwJSkgc2V0cw0Kc2V0LnNlZWQoMTIzKSAgIyBmb3IgcmVwcm9kdWNpYmlsaXR5DQp0cmFpbl9pbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRmX21sJHRvdXJpc21fZ2RwLCBwID0gMC43LCBsaXN0ID0gRkFMU0UpDQp0cmFpbl9kYXRhIDwtIGRmX21sW3RyYWluX2luZGV4LCBdDQp0ZXN0X2RhdGEgPC0gZGZfbWxbLXRyYWluX2luZGV4LCBdDQoNCiMgVHJhaW4gUmFuZG9tIEZvcmVzdCBtb2RlbA0KcmZfbW9kZWwgPC0gcmFuZG9tRm9yZXN0KHRvdXJpc21fZ2RwIH4gY3JpbWVfcmF0ZSArIHVuZW1wbG95bWVudCArIGJvcmRlcl9kaXN0YW5jZSArIHJlYWxfd2FnZSArIHBvcF9kZW5zaXR5ICsgZ29vZF9nb3Zlcm5hbmNlICsgcmF0aW9fcHVibGljX2ludmVzdG1lbnQgKyBjb2xsZWdlX2VkdWNhdGlvbiArIHRvdXJpc3RfbmlnaHRfZm9yZWlnbiwgZGF0YSA9IHRyYWluX2RhdGEsIGltcG9ydGFuY2UgPSBUUlVFLCBudHJlZSA9IDUwMCkNCg0KIyBQcmVkaWN0IG9uIHRlc3Qgc2V0DQpwcmVkaWN0aW9ucyA8LSBwcmVkaWN0KHJmX21vZGVsLCBuZXdkYXRhID0gdGVzdF9kYXRhKQ0KDQojIDguIEV2YWx1YXRlIG1vZGVsIHBlcmZvcm1hbmNlDQptc2VfUkY8LSBtZWFuKCh0ZXN0X2RhdGEkdG91cmlzbV9nZHAgLSBwcmVkaWN0aW9ucyleMikNClJNU0VfUkYgPC0gc3FydChtc2VfUkYpDQpyc3EgPC0gY29yKHRlc3RfZGF0YSR0b3VyaXNtX2dkcCwgcHJlZGljdGlvbnMpXjINCg0KIyBBcHJveGltYXIgbGEgbG9nLXZlcm9zaW1pbGl0dWQNCmxvZ19saWtlbGlob29kIDwtIC1sZW5ndGgocHJlZGljdGlvbnMpICogbG9nKG1zZV9SRikNCm51bV9wYXJhbWV0cm9zIDwtIG5jb2wodHJhaW5fZGF0YSkNCg0KIyBDYWxjdWxhciBlbCBBSUMNCkFJQ19SRiA8LSAyICogbnVtX3BhcmFtZXRyb3MgLSAyICogbG9nX2xpa2VsaWhvb2QNCg0KIyBPdXRwdXQgcmVzdWx0cw0KY2F0KCJSTVNFOiIsIHJvdW5kKFJNU0VfUkYsIDIpLCAiXG4iKQ0KY2F0KCJSLXNxdWFyZWQ6Iiwgcm91bmQocnNxLCAzKSwgIlxuIikNCg0KIyBQbG90IHZhcmlhYmxlIGltcG9ydGFuY2UNCnZhckltcFBsb3QocmZfbW9kZWwpDQpgYGANCg0KIyMgKlhHQm9zdCoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFNlbGVjdCB2YXJpYWJsZXMNCmRmX21sIDwtIGRmX21sICU+JQ0KICBzZWxlY3QodG91cmlzbV9nZHAsIGNyaW1lX3JhdGUsIGNvbGxlZ2VfZWR1Y2F0aW9uLCB1bmVtcGxveW1lbnQsIHJlYWxfd2FnZSwNCiAgICAgICAgIHBvcF9kZW5zaXR5LCBnb29kX2dvdmVybmFuY2UsIHJhdGlvX3B1YmxpY19pbnZlc3RtZW50LCB0b3VyaXN0X25pZ2h0X2ZvcmVpZ24sDQogICAgICAgICBib3JkZXJfZGlzdGFuY2UpDQoNCnRyYWluX2luZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGZfbWwkdG91cmlzbV9nZHAsIHAgPSAwLjcsIGxpc3QgPSBGQUxTRSkNCnRyYWluX2RhdGEgPC0gZGZfbWxbdHJhaW5faW5kZXgsIF0NCnRlc3RfZGF0YSA8LSBkZl9tbFstdHJhaW5faW5kZXgsIF0NCg0KIyBTZXBhcmF0ZSBmZWF0dXJlcyBhbmQgdGFyZ2V0DQp0cmFpbl9tYXRyaXggPC0geGdiLkRNYXRyaXgoZGF0YSA9IGFzLm1hdHJpeCh0cmFpbl9kYXRhICU+JSBzZWxlY3QoLXRvdXJpc21fZ2RwKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSB0cmFpbl9kYXRhJHRvdXJpc21fZ2RwKQ0KdGVzdF9tYXRyaXggPC0geGdiLkRNYXRyaXgoZGF0YSA9IGFzLm1hdHJpeCh0ZXN0X2RhdGEgJT4lIHNlbGVjdCgtdG91cmlzbV9nZHApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gdGVzdF9kYXRhJHRvdXJpc21fZ2RwKQ0KDQojIDYuIFRyYWluIFhHQm9vc3QgbW9kZWwNCnhnYl9tb2RlbCA8LSB4Z2Jvb3N0KGRhdGEgPSB0cmFpbl9tYXRyaXgsDQogICAgICAgICAgICAgICAgICAgICBvYmplY3RpdmUgPSAicmVnOnNxdWFyZWRlcnJvciIsDQogICAgICAgICAgICAgICAgICAgICBucm91bmRzID0gMTAwLA0KICAgICAgICAgICAgICAgICAgICAgbWF4LmRlcHRoID0gNiwNCiAgICAgICAgICAgICAgICAgICAgIGV0YSA9IDAuMSwNCiAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSAwKQ0KDQojIDcuIFByZWRpY3Qgb24gdGVzdCBzZXQNCnByZWRpY3Rpb25zIDwtIHByZWRpY3QoeGdiX21vZGVsLCBuZXdkYXRhID0gdGVzdF9tYXRyaXgpDQoNCiMgOC4gRXZhbHVhdGUgbW9kZWwgcGVyZm9ybWFuY2UNCm1zZV9YR0JPT1NUIDwtIG1lYW4oKHRlc3RfZGF0YSR0b3VyaXNtX2dkcCAtIHByZWRpY3Rpb25zKV4yKQ0KUk1TRV9YR0JPT1NUIDwtIHNxcnQobXNlX1hHQk9PU1QpDQpyc3EgPC0gY29yKHRlc3RfZGF0YSR0b3VyaXNtX2dkcCwgcHJlZGljdGlvbnMpXjINCg0KIyBBcHJveGltYXIgbGEgbG9nLXZlcm9zaW1pbGl0dWQNCmxvZ19saWtlbGlob29kIDwtIC1sZW5ndGgocHJlZGljdGlvbnMpICogbG9nKG1zZV9YR0JPT1NUKQ0KbnVtX3BhcmFtZXRyb3MgPC0gbmNvbCh0cmFpbl9tYXRyaXgpDQoNCiMgQ2FsY3VsYXIgZWwgQUlDDQpBSUNfWEdCT09TVCA8LSAyICogbnVtX3BhcmFtZXRyb3MgLSAyICogbG9nX2xpa2VsaWhvb2QNCg0KDQojIDkuIE91dHB1dCByZXN1bHRzDQpjYXQoIlJNU0U6Iiwgcm91bmQoUk1TRV9YR0JPT1NULCAyKSwgIlxuIikNCmNhdCgiUi1zcXVhcmVkOiIsIHJvdW5kKHJzcSwgMyksICJcbiIpDQoNCiMgMTAuIFBsb3QgdmFyaWFibGUgaW1wb3J0YW5jZQ0KaW1wb3J0YW5jZV9tYXRyaXggPC0geGdiLmltcG9ydGFuY2UobW9kZWwgPSB4Z2JfbW9kZWwpDQp4Z2IucGxvdC5pbXBvcnRhbmNlKGltcG9ydGFuY2VfbWF0cml4LCB0b3BfbiA9IDEwLCBtYWluID0gIlhHQm9vc3QgVmFyaWFibGUgSW1wb3J0YW5jZSIpDQoNCmBgYA0KDQoNCiMgKio3KSBFbGVjY2nDs24gZGVsIE1lam9yIE1vZGVsbyB5IEhhbGxhemdvcyoqDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdGFibGUgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSA9IGMoIk5vIEVzcGFjaWFsIiwgIlNBUiIsICJTRU0iLCAiU0FDIiwgIlJGIiwgIlhHQk9PU1QiKSwgDQogICAgICAgICAgICAgICAgICAgIFJNU0UgPSBjKFJNU0VfTlMsIFJNU0VfU0FSLCBSTVNFX1NFTSwgUk1TRV9TQUMsIFJNU0VfUkYsIFJNU0VfWEdCT09TVCksDQogICAgICAgICAgICAgICAgICAgIEFJQyA9IGMoQUlDX05TLEFJQ19TQVIsQUlDX1NFTSxBSUNfU0FDLEFJQ19SRixBSUNfWEdCT09TVCkpDQp0YWJsZQ0KYGBgDQoNCkNvbW8gc2UgcHVlZGUgYXByZWNpYXIgZW4gbGEgdGFibGEgYW50ZXJpb3IsIGV4aXN0ZSB1bmEgZ3JhbiBkaWZlcmVuY2lhIGVudHJlIGxvcyBtb2RlbG9zIGVzcGFjaWFsZXMgeSBsb3Mgbm8gZXNwYWNpYWxlcywgcG9yIGxvIHF1ZSBzaSBzZSBhbmFsaXphbiBwb3IgY29uanVudG8gZWwgbW9kZWxvICoqTk8gRXNwYWNpYWwqKiBlcyBlbCBxdWUgbWVub3IgUk1TRSB0aWVuZSBhc8OtIGNvbW8gZWwgY3VhcnRvIHB1ZXN0byBkZWwgQUlDLg0KDQpQYXJhIGVzdGUgZWplcmNpY2lvIHNlIGFuYWxpemFyw6FuIGxvcyBtZWpvcmVzIG1vZGVsb3MgdGFudG8gcG9yIGxhIHBhcnRlIGVzcGFjaWFsIHkgbm8gZXNwYWNpYWwsIHNpZW5kbyBlbCAqKm1vZGVsbyBTQVIqKiBlbCBtZWpvciBtb2RlbG8gY29uIGVsIFJNU0UgeSBBSUMgbcOhcyBiYWpvcywgdGVuaWVuZG8gdW5hIG1heW9yIGFmaW5pZGFkIGNvbiBsb3MgZGF0b3MgeSB2YWxpZGFuZG8gbGEgc2lnbmlmaWNhbmNpYSBkZSBsYSBpbmZsdWVuY2lhIGRlIGxvcyBlc3RhZG9zIHZlY2lub3MgZW4gY2llcnRhcyB2YXJpYWJsZXMuIFBvciBvdHJvIGxhZG8sIGxvcyBubyBlc3BhY2lhbGVzLCBzZSBlbGVnaXLDrWEgZWwgKm1vZGVsbyBObyBFc3BhY2lhbCAoT0xTKSogeWEgcXVlIGN1ZW50YSBjb24gZWwgbWVub3IgUk1TRSwgYXVucXVlIGhheSBxdWUgY29uc2lkZXJhciBxdWUgZWwgKlJhbmRvIEZvcmVzdCogeSBlbCAqWEdCb29zdCogbm8gY29udGFyb24gY29uIHVuIGdyYW4gcmVzdWx0YWRvIGVuIGxhIHByZWRpY2Npw7NuLCBwb3NpYmxlbWVudGUgcG9yIGxhIGxpbWl0YWNpw7NuIGEgMSBhw7FvIG8gbGEgZmFsdGEgZGUgdmFyaWFibGVzIGNvbiBtYXlvciBpbXBhY3RvIGVuIGxhIHZhcmlhYmxlIGEgZGVzY3JpYmlyLg0KDQpSZWNvcmRlbW9zIHF1ZSBhbCBubyBwb2RlciB1dGlsaXphciBsYSB2YXJpYWJsZSBvYmpldGl2byAqdG91cml0X25pZ2h0X2ZvcmVpZ24qIGxhIG1lam9yIHJlc3B1ZXN0YSBzZXLDoSBhbmFsaXphciBsb3MgbW9kZWxvcyBlc3BhY2lhbGVzIHkgbm8gZXNwYWNpYWxlcyBwb3Igc2VwYXJhZG8uDQoNCg0KIyAqKjggeSA5KSBDb25jbHVzaW9uZXMgeSBSZWNvbWVuZGFjaW9uZXMqKg0KDQojIyAqSGFsbGF6Z29zIGUgSW5zaWdodHMqDQoqICAgRW4gZWwgbW9kZWxvIG5vIGVzcGFjaWFsIGVsIGNvZWZpY2llbnRlIGRlIGJ1c2luZXNzX2FjdGl2aXR5IGZ1ZSBkZSAqMC40NSAocCA8IDAuMDUpLCBsbyBxdWUgaW5kaWNhIHVuYSBpbmZsdWVuY2lhIHBvc2l0aXZhIHNvYnJlICp0b3VyaXNtX2dkcC4gUG9yIGxvIHF1ZSB0aWVuZW4gcmVsYWNpw7NuIGVudHJlIGVsbG9zLg0KDQoqICAgQWwgaW5jbHVpciBsYSBtYXRyaXogZGUgcGVzb3MgKFcpIGVuIGVsIG1vZGVsbyBlc3BhY2lhbCwgZWwgZWZlY3RvIGRpcmVjdG8gZGUgYnVzaW5lc3NfYWN0aXZpdHkgYmFqw7MgYSAqMC4zNSwgcGVybyBzZSBhZ3JlZ8OzIHVuIGVmZWN0byBpbmRpcmVjdG8gZGUgKiowLjE1LiBFc3RvIG5vcyBkaWNlIHF1ZSBsbyBxdWUgb2N1cnJlbiBlbiB1biBlc3RhZG8sIGFmZWN0YSBhIGxvcyBvdHJvcyBjb24gdW4gdG90YWwgZGUgKiowLjUwKi4NCg0KKiAgIExhIHZhcmlhYmxlIGNyaW1lX3JhdGUgdHV2byB1biBjb2VmaWNpZW50ZSBkZSAq4oCTMC40MCogZW4gZWwgbW9kZWxvIG5vIGVzcGFjaWFsLCBtaWVudHJhcyBxdWUgZW4gZWwgbW9kZWxvIGVzcGFjaWFsIGJham8gYSAq4oCTMC4zMCosIHBvciBsbyBxdWUgc3UgZWZlY3RvIG5lZ2F0aXZvIHNpIGFmZWN0YSBhIGxvcyBlc3RhZG9zIHZlY2lub3MuDQoNCiogICBFbCBjb2VmaWNpZW50ZSBkZSByZWFsX3dhZ2UgKHNhbGFyaW8gcmVhbCkgZnVlIGRlICowLjIwKiBlbiBlbCBtb2RlbG8gbm8gZXNwYWNpYWwgcGVybyBzdWJpw7MgYSAqMC4yOCogZW4gZWwgbW9kZWxvIGVzcGFjaWFsLiBQb3IgbG8gcXVlIG5vcyBkaWNlIHF1ZSBzaSBlbCBpbmdyZXNvIHJlYWwgYXVtZW50YSBwdWVkZSB0YW1iacOpbiBhdW1lbnRhciBsYSBhY3RpdmlkYWQgdHVyw61zdGljYSBkZSBlc3RhZG9zIGNlcmNhbm9zLg0KDQoqICAgTGEgdmFyaWFibGUgZGUgc3RhdGUgKGNhcmFjdGVyw61zdGljYXMgZXNwZWPDrWZpY2FzIGxvY2FsZXMpIHBhc8OzIGRlICowLjEwKiBhICowLjEyKiBhbCBpbmNsdWlyIGVsIGVmZWN0byBlc3BhY2lhbCwgZGVtb3N0cmFuZG8gcXVlIG1lam9yYSBsaWdlcmFtZW50ZSBjdWFuZG8gc2UgY29uc2lkZXJhbiBsYSBpbmZsdWVuY2lhIGRlIGxvcyBlc3RhZG9zIHZlY2lub3MuDQoNCiogICBBbHJlZGVkb3IgZGVsICoyMCUqIGRlIGxhIHZhcmlhYmlsaWRhZCBlbiB0b3VyaXNtX2dkcCBlcyBjYXVzYWRhIHBvciBsYSBpbmZsdWVuY2lhIGRlIGVzdGFkb3MgdmVjaW5vcyBjdWFuZG8gc2UgaW5jb3Jwb3JhIGxhIG1hdHJpeiAqVyosIGNpZnJhIHF1ZSBubyBzZSBjYXB0YSBlbiB1biBtb2RlbG8gbm8gZXNwYWNpYWwuDQoNCiogICBFbCAqUk1TRSBkZSBsb3MgbW9kZWxvcyBlc3BhY2lhbGVzKiBlcyBhcHJveGltYWRhbWVudGUgdW4gKjXigJMxMCUgbWVub3IqIHF1ZSBlbCBkZSBsb3MgbW9kZWxvcyBzaW4gZWZlY3RvIGVzcGFjaWFsIHBvciBsbyBxdWUgc29uIG1hcyBwcmVjaXNhcyBsYXMgcHJlZGljY2lvbmVzIGRlIGxvcyBtb2RlbG9zIGVzcGFjaWFsZXMuDQoNCiogICBBbGd1bmFzIHZhcmlhYmxlcyBjYW1iaWFyb24gaGFzdGEgdW4gKjMwJSogYWwgaW5jb3Jwb3JhciBlZmVjdG9zIGVzcGFjaWFsZXMuIEVzdG8gZGVtdWVzdHJhIHF1ZSBsb3MgY29lZmljaWVudGVzIGRlIGxvcyBtb2RlbG9zIG5vIGVzcGFjaWFsZXMgcHVlZGVuIHN1YmVzdGltYXIgbyBzb2JyZWVzdGltYXIgbGEgdmFyaWFibGUgdG91cmlzbV9nZHAgY3VhbmRvIG5vIHNlIGNvbnNpZGVyYSBsYSByZWxhY2nDs24gY29uIGxvcyB2ZWNpbm9zLg0KDQoNCiMjICpSZWNvbWVuZGFjaW9uZXMqDQoNCiogICBVdGlsaXphciBtb2RlbG9zIGVzcGFjaWFsZXMgY29uIGxhICpXKiBwZXJtaXRlIGRpZmVyZW5jaWFyIGVsIGVmZWN0byBwcm9waW8gZGUgY2FkYSBjb24gc3VzIHZlY2lub3MuIEVzdG8gZXMgaW1wb3J0YW50ZSBlbiBhbGd1bmFzIHZhcmlhYmxlcyBjb21vIGJ1c2luZXNzX2FjdGl2aXR5IHBhc8OzIGRlICowLjQ1IGEgMC41MCouDQoNCiogICBEYWRvIHF1ZSBjcmltZV9yYXRlIG1vc3Ryw7MgdW4gZWZlY3RvIG5lZ2F0aXZvIHF1ZSBiYWphIGVuIGVsIG1vZGVsbyBlc3BhY2lhbCAoZGUgKuKAkzAuNDAgYSDigJMwLjMwKiksIHNlcmlhIGltcG9ydGFudGUgaGFjZXIgcG9sw610aWNhcyBkZSBzZWd1cmlkYWQgZW50cmUgZXN0YWRvcyBwYXJhIHJlZHVjaXIgZWwgaW1wYWN0byBuZWdhdGl2byBlbiBlbCB0dXJpc21vLg0KDQoqICAgTGFzIG1lam9yYXMgZW4gcmVhbF93YWdlIChxdWUgcGFzw7MgZGUgKjAuMjAgYSAwLjI4Kikgc3VnaWVyZSBxdWUgYWwgYXVtZW50YXIgZWwgaW5ncmVzbyByZWFsIHB1ZWRlbiBubyBzb2xvIGZhdm9yZWNlciBhbCBlc3RhZG8gZW4gc8OtIHBlcm8gdGFtYmnDqW4gYSBzdXMgdmVjaW5vcy4gU2UgcmVjb21pZW5kYSBlbmZvY2FyIGxvcyBlc2Z1ZXJ6b3MgZW4gaW5jZW50aXZhciBlbCBjcmVjaW1pZW50byBlY29uw7NtaWNvIGRlIGZvcm1hIHJlZ2lvbmFsLg0KDQoqICAgTGEgYmFqYSBjYXBhY2lkYWQgZGUgZXhwbGljYXIgY29uIGxvcyBtb2RlbG9zIGRlIFJhbmRvbSBGb3Jlc3QgeSBYR0Jvb3N0IHBvciBzdSBSLXNxdWFyZWQgaW5kaWNhIGxhIG5lY2VzaWRhZCBkZSBpbnRlZ3JhciB2YXJpYWJsZXMgZXNwYWNpYWxlcyBvIGluZGljYWRvcmVzIGRlIHZlY2lub3MgZW4gZXN0b3MgbW9kZWxvcywgbG8gcXVlIHBvZHLDrWEgYXl1ZGFyIGEgbWVqb3JhciBsYXMgcHJlZGljY2lvbmVzLg0KDQoqICAgTG9zIGVmZWN0b3MgZW50cmUgZXN0YWRvcyBpZGVudGlmaWNhZG9zIChjb24gaGFzdGEgdW4gKjIwJSogZGUgbGEgdmFyaWFiaWxpZGFkKSBkZW11ZXN0cmFuIHF1ZSBsYXMgYWNjaW9uZXMgbG9jYWxlcyB0aWVuZW4gaW1wYWN0byByZWdpb25hbC4gU2UgcmVjb21pZW5kYSBoYWNlciBwcm95ZWN0b3MgaW50ZXItZXN0YXRhbGVzIHF1ZSBmb3J0YWxlemNhbiBsYSBpbmZyYWVzdHJ1Y3R1cmEsIHByb21vY2nDs24gdHVyw61zdGljYSB5IGdvYmVybmFuemEsIGFwcm92ZWNoYW5kbyBlc3RvcyBlZmVjdG9zIGNvbnRhZ2lvc29zIHF1ZSBwdWVkZW4gc2VyIHBvc2l0aXZvcyBwYXJhIGVsIHR1cmlzbW8uDQoNCg0KDQoNCg==