Fabio Andrés Paternina Miranda

10/02/2025

_________________________________________________________________________________

Problema

Una empresa inmobiliaria líder en una gran ciudad está buscando comprender en profundidad el mercado de viviendas urbanas para tomar decisiones estratégicas más informadas. La empresa posee una base de datos extensa que contiene información detallada sobre diversas propiedades residenciales disponibles en el mercado. Se requiere realizar un análisis holístico de estos datos para identificar patrones, relaciones y segmentaciones relevantes que permitan mejorar la toma de decisiones en cuanto a la compra, venta y valoración de propiedades.

Retos:

El reto principal consisten en realizar un análisis integral y multidimensional de la base de datos para obtener una comprensión del mercado inmobiliario urbano. Se requiere aplicar diversas técnicas de análisis de datos, incluyendo:

  1. Análisis de Componentes Principales: Reducir la dimensionalidad del conjunto de datos y visualizar la estructura de las variables en componentes principales para identificar características clave que influyen en la variación de precios y preferencias del mercado.

  2. Análisis de Conglomerados: Agrupar las propiedades residenciales en segmentos homogéneos con características similares para entender las dinámicas y demandas específicas en diferentes partes de la ciudad y en diferentes estratos socioeconómicos.

  3. Análisis de Correspondencia : Examinar la relación entre las variables categóricas (tipo de vivienda, zona y barrio) y las variables numéricas (precio, área construida, número de parqueaderos, baños, habitaciones) para identificar patrones de comportamiento del mercado inmobiliario.

  4. Visualización de resultados: Presentar gráficos, mapas y otros recursos visuales para comunicar los hallazgos de manera clara y efectiva a la dirección de la empresa.

Conclusiones clave y las recomendaciones específicas para guiar las decisiones estratégicas de la empresa inmobiliaria

Desarrollo

Exploración y preparación del dataset

# Instalacion de librerías

install.packages(c("devtools", "Dplyr", "factoextra", "ggplot2", "ggfortify", "FactoMineR", "corrplot"))
Error in install.packages : Updating loaded packages
library(devtools)
library(dplyr)
library(factoextra)
library(ggplot2)
library(ggfortify)
library(FactoMineR)
library(corrplot)

Se realiza una exploracion y limpieza del Dataset original viviendas_faltantes que contiene 8330 observaciones y 13 variables (dimensiones)

data(vivienda_faltantes)
head(vivienda_faltantes)

summary(vivienda_faltantes)
       id           zona                piso           estrato         preciom      
 Min.   :   1   Length:8330        Min.   : 1.000   Min.   :3.000   Min.   :  58.0  
 1st Qu.:2082   Class :character   1st Qu.: 2.000   1st Qu.:4.000   1st Qu.: 220.0  
 Median :4164   Mode  :character   Median : 3.000   Median :5.000   Median : 330.0  
 Mean   :4164                      Mean   : 3.772   Mean   :4.634   Mean   : 434.2  
 3rd Qu.:6246                      3rd Qu.: 5.000   3rd Qu.:5.000   3rd Qu.: 540.0  
 Max.   :8319                      Max.   :12.000   Max.   :6.000   Max.   :1999.0  
 NA's   :3                         NA's   :2641     NA's   :3       NA's   :2       
   areaconst       parquea           banios          habitac           tipo          
 Min.   :  30   Min.   : 1.000   Min.   : 0.000   Min.   : 0.000   Length:8330       
 1st Qu.:  80   1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000   Class :character  
 Median : 123   Median : 2.000   Median : 3.000   Median : 3.000   Mode  :character  
 Mean   : 175   Mean   : 1.836   Mean   : 3.112   Mean   : 3.605                     
 3rd Qu.: 229   3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000                     
 Max.   :1745   Max.   :10.000   Max.   :10.000   Max.   :10.000                     
 NA's   :3      NA's   :1606     NA's   :3        NA's   :3                          
    barrio             longitud            latitud        
 Length:8330        Min.   :-76576.00   Min.   :   3.333  
 Class :character   1st Qu.:-76506.00   1st Qu.:   3.390  
 Mode  :character   Median :   -76.54   Median :   3.450  
                    Mean   :-21845.13   Mean   : 970.370  
                    3rd Qu.:   -76.52   3rd Qu.:3367.000  
                    Max.   :   -76.46   Max.   :3497.000  
                    NA's   :3           NA's   :3         

Se elimina columna id, ya que es un identificador único y no contiene información analítica.


# Eliminar la columna 'id' (suponiendo que se llama exactamente 'id')
vivienda <- vivienda_faltantes[ , -1]

# Verificar estructura después de la limpieza

summary(vivienda)
     zona                piso           estrato         preciom         areaconst   
 Length:8330        Min.   : 1.000   Min.   :3.000   Min.   :  58.0   Min.   :  30  
 Class :character   1st Qu.: 2.000   1st Qu.:4.000   1st Qu.: 220.0   1st Qu.:  80  
 Mode  :character   Median : 3.000   Median :5.000   Median : 330.0   Median : 123  
                    Mean   : 3.772   Mean   :4.634   Mean   : 434.2   Mean   : 175  
                    3rd Qu.: 5.000   3rd Qu.:5.000   3rd Qu.: 540.0   3rd Qu.: 229  
                    Max.   :12.000   Max.   :6.000   Max.   :1999.0   Max.   :1745  
                    NA's   :2641     NA's   :3       NA's   :2        NA's   :3     
    parquea           banios          habitac           tipo              barrio         
 Min.   : 1.000   Min.   : 0.000   Min.   : 0.000   Length:8330        Length:8330       
 1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000   Class :character   Class :character  
 Median : 2.000   Median : 3.000   Median : 3.000   Mode  :character   Mode  :character  
 Mean   : 1.836   Mean   : 3.112   Mean   : 3.605                                        
 3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000                                        
 Max.   :10.000   Max.   :10.000   Max.   :10.000                                        
 NA's   :1606     NA's   :3        NA's   :3                                             
    longitud            latitud        
 Min.   :-76576.00   Min.   :   3.333  
 1st Qu.:-76506.00   1st Qu.:   3.390  
 Median :   -76.54   Median :   3.450  
 Mean   :-21845.13   Mean   : 970.370  
 3rd Qu.:   -76.52   3rd Qu.:3367.000  
 Max.   :   -76.46   Max.   :3497.000  
 NA's   :3           NA's   :3         

Se procede a reemplazar valores NA de las columnas Piso (2641) y Parqueadero (1606) por valores 0.


vivienda$piso[is.na(vivienda$piso)] <- 0

vivienda$parquea[is.na(vivienda$parquea)] <- 0
head(vivienda)
NA

La variable “tipo” tiene un problema con las mayusculas y minisculas, se incluyen todas las variantes en: apartamento y casa.

vivienda$tipo <- tolower(vivienda$tipo)

vivienda$tipo <- gsub("apto", "apartamento", vivienda$tipo, ignore.case = TRUE)
unique(vivienda$tipo)
[1] "apartamento" "casa"        NA           
table(vivienda$tipo)

apartamento        casa 
       5106        3221 

Eliminamos filas con valores faltantes “NA”

vivienda_clean <- na.omit(vivienda)

sum(is.na(vivienda_clean)) # Debe devolver 0 si no hay NA
[1] 0
dim(vivienda_clean) #Nueva dimension (filas / columnas)
[1] 8327   12
nrow(vivienda) - nrow(vivienda_clean)  # Número de filas eliminadas
[1] 3
summary(vivienda_clean) #Comprobamos
     zona                piso           estrato         preciom         areaconst   
 Length:8327        Min.   : 0.000   Min.   :3.000   Min.   :  58.0   Min.   :  30  
 Class :character   1st Qu.: 0.000   1st Qu.:4.000   1st Qu.: 220.0   1st Qu.:  80  
 Mode  :character   Median : 2.000   Median :5.000   Median : 330.0   Median : 123  
                    Mean   : 2.577   Mean   :4.634   Mean   : 434.3   Mean   : 175  
                    3rd Qu.: 4.000   3rd Qu.:5.000   3rd Qu.: 540.0   3rd Qu.: 229  
                    Max.   :12.000   Max.   :6.000   Max.   :1999.0   Max.   :1745  
    parquea           banios          habitac           tipo              barrio         
 Min.   : 0.000   Min.   : 0.000   Min.   : 0.000   Length:8327        Length:8327       
 1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 3.000   Class :character   Class :character  
 Median : 1.000   Median : 3.000   Median : 3.000   Mode  :character   Mode  :character  
 Mean   : 1.483   Mean   : 3.112   Mean   : 3.605                                        
 3rd Qu.: 2.000   3rd Qu.: 4.000   3rd Qu.: 4.000                                        
 Max.   :10.000   Max.   :10.000   Max.   :10.000                                        
    longitud            latitud        
 Min.   :-76576.00   Min.   :   3.333  
 1st Qu.:-76506.00   1st Qu.:   3.390  
 Median :   -76.54   Median :   3.450  
 Mean   :-21845.13   Mean   : 970.370  
 3rd Qu.:   -76.52   3rd Qu.:3367.000  
 Max.   :   -76.46   Max.   :3497.000  

Calculamos la matriz de correlacion para descartar variables redundantes, seleccionamos las variables numéricas relevantes:

vrb_num_table  <- vivienda_clean[, c('preciom', 'areaconst', 'habitac', 'banios')]

correlation_matrix <- cor(vrb_num_table, use = "complete.obs")
print(correlation_matrix)
            preciom areaconst   habitac    banios
preciom   1.0000000 0.6872452 0.2633645 0.6691775
areaconst 0.6872452 1.0000000 0.5166996 0.6486675
habitac   0.2633645 0.5166996 1.0000000 0.5896911
banios    0.6691775 0.6486675 0.5896911 1.0000000

Visualizamos la matriz de correlación

install.packages("corrplot")
Error in install.packages : Updating loaded packages
library(corrplot)

corrplot(correlation_matrix, method = "circle", type = "lower",
         col = colorRampPalette(c("blue", "white", "red"))(200),
         tl.col = "black", tl.srt = 45, addCoef.col = "black")

ANÁLISIS DE COMPONENTES PRINCIPALES (PCA)

vivienda_pca <- vivienda_clean

numericas <- vivienda_pca[sapply(vivienda_pca, is.numeric)] # Seleccionamos solo variables numéricas para el PCA


numericas_scaled <- scale(numericas) # Estandarizar datos (media = 0, varianza = 1) para PCA
pca_result <- prcomp(numericas_scaled, center = TRUE, scale. = TRUE)

# Visualizar la importancia de cada componente
summary(pca_result)
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7     PC8     PC9
Standard deviation     1.8538 1.3646 1.1782 0.91890 0.67666 0.65159 0.49055 0.43498 0.39550
Proportion of Variance 0.3819 0.2069 0.1542 0.09382 0.05087 0.04717 0.02674 0.02102 0.01738
Cumulative Proportion  0.3819 0.5887 0.7430 0.83681 0.88768 0.93486 0.96160 0.98262 1.00000
library(ggplot2)
library(ggfortify)

# Gráfico de varianza explicada (Scree Plot)
fviz_eig(pca_result, addlabels = TRUE, ylim = c(0, 100))

La gráfica que muestra es un Scree Plot (gráfico de sedimentación) que representa el porcentaje de varianza explicada por cada componente principal en el análisis de componentes Principales (PCA).

Interpretación de la gráfica eje X (Dimensions): Representa los componentes principales (PC1, PC2, PC3, etc.).

Eje Y (Percentage of Explained Variance): Muestra el porcentaje de variabilidad de los datos explicada por cada componente.

Barras azules: Indican cuánta varianza explica cada componente.

Línea negra con puntos: Ayuda a visualizar la disminución progresiva de la varianza explicada.

fviz_pca_var(pca_result,
col.var = "contrib", # Color by contributions to the PC
gradient.cols = c("#17becf",  "#7f7f7f"),
repel = TRUE     # Avoid text overlapping
) 

El biplot de PCA muestra cómo las variables del mercado inmobiliario urbano se agrupan y contribuyen a la variabilidad de los datos. El primer componente (Dim1, 38.2%) está principalmente influenciado por variables económicas y estructurales como precio por metro cuadrado, área construida, baños y parqueaderos, mientras que el segundo componente (Dim2, 20.7%) está dominado por factores geográficos (latitud y longitud). Las variables altamente contribuyentes (en verde) tienen mayor impacto en la estructura de los datos, mientras que otras, como piso y estrato, tienen menor relevancia. Este análisis permite identificar patrones clave en el mercado inmobiliario y la relación entre sus variables principales.

Conclusión

Este gráfico sugiere que los primeros 3-4 componentes principales capturan la mayor parte de la variabilidad del dataset y pueden usarse para reducir la dimensionalidad sin perder demasiada información.

ANÁLISIS DE CONGLOMERADOS (CLUSTERING)

Estandarizamos las variables numéricas para evitar que variables con escalas grandes dominen el análisis:

vivienda_scaled <- scale(vivienda_clean[, c("preciom", "areaconst", "banios", "habitac", "estrato", "piso", "latitud", "longitud")])
head(vivienda_scaled)
        preciom  areaconst     banios    habitac    estrato       piso  latitud  longitud
[1,]  2.6311816  1.0004376  0.6216667 -1.1000930  1.3267681  0.5109872 1.613631 -1.586223
[2,]  0.1390340  0.8745193  0.6216667  0.2706199  1.3267681 -0.5664983 1.613631 -1.586078
[3,]  2.3272612  4.3722495  2.7219989  0.9559764  0.3552593 -0.9256602 1.614281 -1.585991
[4,] -0.6511591 -0.1747998 -0.7785548  0.2706199 -1.5877582 -0.2073365 1.589592 -1.585904
[5,] -0.3168466 -0.4406273  0.6216667 -0.4147365  0.3552593 -0.9256602 1.583745 -1.585904
[6,]  2.7831419  1.5041107  4.8223312  4.3827586  0.3552593 -0.9256602 1.584394 -1.585904

Método de codo para agrupamiento

#Para determinar el número óptimo de clusters, se puede usar el método del codo (elbow method):

fviz_nbclust(vivienda_scaled, kmeans, method = "wss")

install.packages("corrplot")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Warning in install.packages :
  package ‘corrplot’ is in use and will not be installed
install.packages(c("devtools", "Dplyr", "factoextra", "ggplot2", "ggfortify", "FactoMineR", "corrplot"))
Error in install.packages : Updating loaded packages

El Método nos indica que el codo (número de clusters) es de 3.

Método de la silueta

library(cluster)

fviz_nbclust(vivienda_scaled, kmeans, method = "silhouette") + labs (subtitle="silhouette method")

En este método se confirma que el número de clúster optimo es de 3.

Visualizamos asignación de clusters

set.seed(123)  
kmeans_result <- kmeans(vivienda_scaled, centers = 3, nstart = 25)
vivienda_clean$cluster <- as.factor(kmeans_result$cluster)

silhouette_plot <- silhouette(kmeans_result$cluster, dist(vivienda_scaled))
fviz_silhouette(silhouette_plot)

La imagen muestra el análisis de silhouette para evaluar la calidad de la segmentación en tres clusters. El valor promedio de silhouette es 0.3, lo que indica una estructura de clustering moderada pero no óptima. El Cluster 1 (rojo) tiene la mejor cohesión y separación con un promedio de 0.41, lo que sugiere que sus puntos están relativamente bien agrupados. En contraste, el Cluster 2 (verde) tiene el menor valor promedio (0.11), lo que indica una pobre separación y posible solapamiento con otros clusters. El Cluster 3 (azul) tiene un valor intermedio (0.27), lo que sugiere una agrupación débil. En general, la segmentación podría mejorarse ajustando el número de clusters o utilizando otros métodos de agrupamiento.

Clustering Jerárquico

d <- dist(vivienda_scaled, method = "euclidean")
hc <- hclust(d, method = "ward.D2")
install.packages(c("devtools", "Dplyr", "factoextra", "ggplot2", "ggfortify", "FactoMineR", "corrplot"))
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Warning in install.packages :
  packages ‘devtools’, ‘factoextra’, ‘ggplot2’, ‘ggfortify’, ‘FactoMineR’, ‘corrplot’ are in use and will not be installed
Installing package into ‘C:/Users/Fabio/AppData/Local/R/win-library/4.4’
(as ‘lib’ is unspecified)
Warning in install.packages :
  package ‘Dplyr’ is not available for this version of R

A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
Warning in install.packages :
  Perhaps you meant ‘dplyr’ ?
plot(hc)
rect.hclust(hc, k = 3, border = "red")

Distribución del clúster

fviz_cluster(kmeans_result, data = vivienda_scaled, ellipse.type = "convex")

Conclusión

El análisis de conglomerados permitió identificar tres segmentos diferenciados dentro del mercado inmobiliario urbano. El primer grupo agrupa propiedades de alto valor con mayor área construida, más baños y parqueaderos, generalmente ubicadas en zonas de mayor estrato socioeconómico. El segundo grupo representa viviendas de gama media, con precios y características equilibradas, dirigidas a compradores de clase media que buscan una combinación de accesibilidad y comodidad. El tercer grupo, por su parte, se compone de propiedades más económicas, con menor área construida y ubicadas en sectores de estrato más bajo, lo que sugiere una oferta orientada a compradores con menor capacidad adquisitiva. Estos resultados son clave para el desarrollo de estrategias de inversión, fijación de precios y planificación urbana, permitiendo a desarrolladores y compradores comprender mejor la segmentación del mercado y optimizar la toma de decisiones en función de sus objetivos.

ANÁLISIS DE CORRESPONDIENCIA


tabla <- table(vivienda_clean$tipo, vivienda_clean$zona, vivienda_clean$estrato, vivienda_clean$barrio)
summary(tabla)
Number of cases in table: 8327 
Number of factors: 4 
Test for independence of all factors:
    Chisq = 228752, df = 16996, p-value = 0
    Chi-squared approximation may be incorrect
summary(vivienda_clean$barrio)
   Length     Class      Mode 
     8327 character character 
#Se omite la variable categorica barrio debido a la alta cantidad de registros y baja relevancia para el analisis

Se omite la variable categorica barrio debido a la alta cantidad de registros y baja relevancia para el analisis

#Se realiza histograma de precio y se realiza una conversion a variable cantegorica empleando rangos de 250 Millones de COP
hist(vivienda_clean$preciom, xlab = 'Precio')

El histograma muestra la distribución de precios de vivienda a partir de la variable vivienda_clean$preciom. Se observa una distribución sesgada a la derecha, lo que indica que la mayoría de las viviendas tienen precios más bajos, concentrándose principalmente por debajo de los 500. A medida que el precio aumenta, la frecuencia de viviendas disminuye progresivamente, con pocos valores superiores a 1500. Esta asimetría sugiere que los precios elevados son menos comunes en la muestra analizada.

vivienda_CA <- vivienda_clean
# Crear los cortes para los intervalos de 250, comenzando desde 0
breaks <- seq(0, max(vivienda_CA$preciom, na.rm = TRUE) + 250, by = 250)

# Crear etiquetas de manera dinámica asegurando que coincidan en número con los intervalos
labels <- paste0("[", head(breaks, -1), "-", tail(breaks, -1), ")")

# Convertir `preciom` en una variable categórica con los intervalos corregidos
vivienda_CA$preciom_cat <- cut(vivienda_CA$preciom, 
                                  breaks = breaks, 
                                  include.lowest = TRUE, 
                                  right = FALSE,  # Intervalos cerrados a la izquierda [)
                                  labels = labels)

# Verificar la nueva variable
table(vivienda_CA$preciom_cat)

    [0-250)   [250-500)   [500-750)  [750-1000) [1000-1250) [1250-1500) [1500-1750) [1750-2000) 
       2664        3313        1175         586         234         190         108          57 
install.packages("gridExtra")
Error in install.packages : Updating loaded packages
library(gridExtra)

# Crea los gráficos de barras con las etiquetas del eje x giradas
G1 <- ggplot(vivienda_CA, aes(x=zona)) + geom_bar(fill= "#17becf") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
G2 <- ggplot(vivienda_CA, aes(x=estrato)) + geom_bar(fill= "#7f7f7f")
G3 <- ggplot(vivienda_CA, aes(x=tipo)) + geom_bar(fill= "#7f7f7f")
G4 <- ggplot(vivienda_CA, aes(x=preciom_cat)) + geom_bar(fill= "#17becf") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

# Organiza los gráficos en una cuadrícula
grid.arrange(G1, G2, G3, G4, nrow = 2)

Las gráficas muestran la distribución de viviendas según diferentes variables. La mayoría se encuentra en la Zona Sur, seguida por la Zona Norte y la Zona Oeste, mientras que la Zona Centro y la Zona Oriente tienen menos presencia. En cuanto a estrato, predominan los niveles 4 y 5, con menor representación en los estratos 3 y 6. En tipo de vivienda, los apartamentos son más comunes que las casas. Finalmente, la mayoría de las viviendas tienen precios en los rangos más bajos (0-500), con una disminución progresiva en frecuencia a medida que el precio aumenta, evidenciando una distribución sesgada a la derecha.

Análisis Zona/Estrato


tabla1 <- table(vivienda_CA$zona, vivienda_CA$estrato)
colnames(tabla1) <- c("Estrato3", "Estrato4", "Estrato5", "Estrato6" )
tabla1
              
               Estrato3 Estrato4 Estrato5 Estrato6
  Zona Centro       105       14        4        1
  Zona Norte        572      408      770      172
  Zona Oeste         54       85      290      775
  Zona Oriente      340        8        2        1
  Zona Sur          382     1616     1685     1043
chisq.test(tabla1)

    Pearson's Chi-squared test

data:  tabla1
X-squared = 3840.4, df = 12, p-value < 2.2e-16

Este análisis indica que las variables en Zona-Estrato no son independientes, es decir, existe una asociación estadísticamente significativa entre ellas.

library(FactoMineR)
resultados_zona_estrato <- CA(tabla1)

Conclusión:

  • Existen patrones claros de asociación entre las zonas y los estratos socioeconómicos.
  • Zonas como Oriente y Centro parecen estar relacionadas con los estratos más bajos o medios.
  • Zonas como Oeste están más vinculadas con los estratos más altos.
  • El análisis de correspondencia ha sido efectivo para identificar la relación entre la ubicación geográfica y el nivel socioeconómico.

Análisis Precio/Tipo

tabla2 <- table(vivienda_CA$preciom_cat, vivienda_CA$tipo)
colnames(tabla2) <- c("Casa", "Apartamento")
tabla2
             
              Casa Apartamento
  [0-250)     2179         485
  [250-500)   1875        1438
  [500-750)    565         610
  [750-1000)   239         347
  [1000-1250)  110         124
  [1250-1500)   86         104
  [1500-1750)   29          79
  [1750-2000)   23          34
chisq.test(tabla2)

    Pearson's Chi-squared test

data:  tabla2
X-squared = 798.48, df = 7, p-value < 2.2e-16

Este análisis indica que las variables en Zona-Estrato no son independientes, es decir, existe una asociación estadísticamente significativa entre ellas.

# Cargar librerías necesarias
library(ggplot2)
library(reshape2)

# Convertir la tabla en un dataframe
tabla2_df <- as.data.frame.matrix(tabla2)

# Agregar la columna de rangos de precios
tabla2_df$Rango <- rownames(tabla2_df)

# Convertir a formato largo (melt)
tabla2_melt <- melt(tabla2_df, id.vars = "Rango")

# Crear el gráfico en un plano cartesiano
ggplot(tabla2_melt, aes(x = Rango, y = value, fill = variable)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Distribución de Viviendas por Precio y Tipo",
       x = "Rango de Precio",
       y = "Cantidad de Viviendas") +
  theme_minimal() +
  scale_fill_manual(values = c("blue", "red")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

NA
NA
NA

La distribución de viviendas por rango de precio y tipo muestra que la mayoría de las casas se encuentran en los rangos de precios más bajos, especialmente en el intervalo [0-250), mientras que los apartamentos tienen una distribución más uniforme en los distintos rangos de precios. Se observa que en el rango [250-500) hay una alta concentración de viviendas de ambos tipos, lo que sugiere que este segmento de precio es clave en el mercado. A medida que el precio aumenta, la cantidad de viviendas disminuye, pero los apartamentos mantienen una presencia relativamente mayor en los rangos superiores. Esto podría indicar que las viviendas más costosas tienden a ser apartamentos en lugar de casas.

Análisis Precio Zona

tabla3 <- table(vivienda_CA$preciom_cat, vivienda_CA$zona)
colnames(tabla3) <- c("Zona_Centro", "Zona_Norte", "Zona_Oeste", "Zona_Oriente", "Zona_Sur")
tabla3
             
              Zona_Centro Zona_Norte Zona_Oeste Zona_Oriente Zona_Sur
  [0-250)              46        765         95          219     1539
  [250-500)            65        806        396          124     1922
  [500-750)            10        215        311            6      633
  [750-1000)            1         92        159            1      333
  [1000-1250)           2         22        110            0      100
  [1250-1500)           0         12         80            1       97
  [1500-1750)           0          8         28            0       72
  [1750-2000)           0          2         25            0       30
chisq.test(tabla3)
Aviso: Chi-squared approximation may be incorrect

    Pearson's Chi-squared test

data:  tabla3
X-squared = 1082, df = 28, p-value < 2.2e-16

Este análisis indica que las variables en Zona-Precio no son independientes, es decir, existe una asociación estadísticamente significativa entre ellas.

library(FactoMineR)
resultados_zona_estrato <- CA(tabla3)

Conclusión

Las zonas Oriente, Norte y Centro están más relacionadas con precios bajos (0-250), mientras que las zonas Oeste y Sur se asocian con precios más altos, reflejando una posible segmentación del mercado inmobiliario. Además, la dispersión de los precios en la zona Oeste sugiere una mayor variabilidad en los valores de los inmuebles dentro de esta área.

RESULTADOS

1. Distribución de Precios

El análisis de la distribución de precios muestra que la mayoría de las viviendas tienen precios concentrados en rangos bajos a medios, con una disminución progresiva en la frecuencia a medida que el precio aumenta. Esto sugiere que el mercado inmobiliario está dominado por propiedades económicas y de costo medio, con una menor representación de viviendas de lujo.

Gráfico: Histograma de precios de vivienda mostrando la distribución de frecuencia.

2. Segmentación por Zonas y Estratos

El análisis por zonas revela que la “Zona Sur” concentra el mayor número de propiedades, mientras que “Zona Oriente” tiene la menor cantidad. En términos de estrato socioeconómico, la mayor parte de las viviendas pertenecen a los estratos 4 y 5, indicando un mercado inmobiliario dirigido principalmente a la clase media-alta.

Gráfico: Gráficos de barras comparando la distribución de viviendas por zona y estrato.

3. Relación entre Tipo de Vivienda y Precio

Se observa que los apartamentos tienen mayor representación en el mercado en comparación con las casas. Además, los precios más bajos tienden a concentrarse en apartamentos, mientras que las casas tienden a ubicarse en segmentos de precios más altos.

Gráfico: Gráfico de barras que compara la cantidad de apartamentos y casas.

4. Análisis de Correspondencia

La correspondencia entre zonas y precios muestra que las viviendas de menor costo se concentran en ciertas zonas específicas, mientras que las propiedades más costosas se distribuyen en ubicaciones más exclusivas. Esta información es clave para la toma de decisiones en estrategias de comercialización.

Gráfico: Mapa de correspondencias entre zonas y rangos de precios.

5. Análisis Geoespacial

Si se consideran datos geoespaciales como latitud y longitud, se pueden visualizar patrones específicos de distribución inmobiliaria en un mapa. Esto ayuda a identificar áreas de alta y baja demanda, facilitando la toma de decisiones estratégicas.

Gráfico: Mapa de calor mostrando la distribución geográfica de precios de vivienda.

Conclusión General

El estudio inmobiliario revela una distribución desigual de propiedades, con una mayor concentración de viviendas en zonas específicas y un mercado dominado por apartamentos a precios bajos y medios. El análisis geoespacial y de correspondencia brinda información valiosa para la planeación y comercialización efectiva en el sector inmobiliario.

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCAxLiBFdmFsdWFjacOzbiBkZSBsYSBvZmVydGEgaW5tb2JpbGlhcmlhIHVyYmFuYSINCmF1dG9yOiBGYWJpbyBBbmRyw6lzIFBhdGVybmluYSBNaXJhbmRhDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KIyMjIEZhYmlvIEFuZHLDqXMgUGF0ZXJuaW5hIE1pcmFuZGENCg0KIyMjIyAxMC8wMi8yMDI1DQoNCiMjIyMgXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfXF9cX1xfDQoNCiMjIyMgUHJvYmxlbWENCg0KVW5hIGVtcHJlc2EgaW5tb2JpbGlhcmlhIGzDrWRlciBlbiB1bmEgZ3JhbiBjaXVkYWQgZXN0w6EgYnVzY2FuZG8gY29tcHJlbmRlciBlbiBwcm9mdW5kaWRhZCBlbCBtZXJjYWRvIGRlIHZpdmllbmRhcyB1cmJhbmFzIHBhcmEgdG9tYXIgZGVjaXNpb25lcyBlc3RyYXTDqWdpY2FzIG3DoXMgaW5mb3JtYWRhcy4gTGEgZW1wcmVzYSBwb3NlZSB1bmEgYmFzZSBkZSBkYXRvcyBleHRlbnNhIHF1ZSBjb250aWVuZSBpbmZvcm1hY2nDs24gZGV0YWxsYWRhIHNvYnJlIGRpdmVyc2FzIHByb3BpZWRhZGVzIHJlc2lkZW5jaWFsZXMgZGlzcG9uaWJsZXMgZW4gZWwgbWVyY2Fkby4gU2UgcmVxdWllcmUgcmVhbGl6YXIgdW4gYW7DoWxpc2lzIGhvbMOtc3RpY28gZGUgZXN0b3MgZGF0b3MgcGFyYSBpZGVudGlmaWNhciBwYXRyb25lcywgcmVsYWNpb25lcyB5IHNlZ21lbnRhY2lvbmVzIHJlbGV2YW50ZXMgcXVlIHBlcm1pdGFuIG1lam9yYXIgbGEgdG9tYSBkZSBkZWNpc2lvbmVzIGVuIGN1YW50byBhIGxhIGNvbXByYSwgdmVudGEgeSB2YWxvcmFjacOzbiBkZSBwcm9waWVkYWRlcy4NCg0KUmV0b3M6DQoNCkVsIHJldG8gcHJpbmNpcGFsIGNvbnNpc3RlbiBlbiByZWFsaXphciB1biBhbsOhbGlzaXMgaW50ZWdyYWwgeSBtdWx0aWRpbWVuc2lvbmFsIGRlIGxhIGJhc2UgZGUgZGF0b3MgcGFyYSBvYnRlbmVyIHVuYSBjb21wcmVuc2nDs24gZGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvIHVyYmFuby4gU2UgcmVxdWllcmUgYXBsaWNhciBkaXZlcnNhcyB0w6ljbmljYXMgZGUgYW7DoWxpc2lzIGRlIGRhdG9zLCBpbmNsdXllbmRvOg0KDQoxLiAgQW7DoWxpc2lzIGRlIENvbXBvbmVudGVzIFByaW5jaXBhbGVzOiBSZWR1Y2lyIGxhIGRpbWVuc2lvbmFsaWRhZCBkZWwgY29uanVudG8gZGUgZGF0b3MgeSB2aXN1YWxpemFyIGxhIGVzdHJ1Y3R1cmEgZGUgbGFzIHZhcmlhYmxlcyBlbiBjb21wb25lbnRlcyBwcmluY2lwYWxlcyBwYXJhIGlkZW50aWZpY2FyIGNhcmFjdGVyw61zdGljYXMgY2xhdmUgcXVlIGluZmx1eWVuIGVuIGxhIHZhcmlhY2nDs24gZGUgcHJlY2lvcyB5IHByZWZlcmVuY2lhcyBkZWwgbWVyY2Fkby4NCg0KMi4gIEFuw6FsaXNpcyBkZSBDb25nbG9tZXJhZG9zOiBBZ3J1cGFyIGxhcyBwcm9waWVkYWRlcyByZXNpZGVuY2lhbGVzIGVuIHNlZ21lbnRvcyBob21vZ8OpbmVvcyBjb24gY2FyYWN0ZXLDrXN0aWNhcyBzaW1pbGFyZXMgcGFyYSBlbnRlbmRlciBsYXMgZGluw6FtaWNhcyB5IGRlbWFuZGFzIGVzcGVjw61maWNhcyBlbiBkaWZlcmVudGVzIHBhcnRlcyBkZSBsYSBjaXVkYWQgeSBlbiBkaWZlcmVudGVzIGVzdHJhdG9zIHNvY2lvZWNvbsOzbWljb3MuDQoNCjMuICBBbsOhbGlzaXMgZGUgQ29ycmVzcG9uZGVuY2lhIDogRXhhbWluYXIgbGEgcmVsYWNpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzICh0aXBvIGRlIHZpdmllbmRhLCB6b25hIHkgYmFycmlvKSB5IGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyAocHJlY2lvLCDDoXJlYSBjb25zdHJ1aWRhLCBuw7ptZXJvIGRlIHBhcnF1ZWFkZXJvcywgYmHDsW9zLCBoYWJpdGFjaW9uZXMpIHBhcmEgaWRlbnRpZmljYXIgcGF0cm9uZXMgZGUgY29tcG9ydGFtaWVudG8gZGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvLg0KDQo0LiAgVmlzdWFsaXphY2nDs24gZGUgcmVzdWx0YWRvczogUHJlc2VudGFyIGdyw6FmaWNvcywgbWFwYXMgeSBvdHJvcyByZWN1cnNvcyB2aXN1YWxlcyBwYXJhIGNvbXVuaWNhciBsb3MgaGFsbGF6Z29zIGRlIG1hbmVyYSBjbGFyYSB5IGVmZWN0aXZhIGEgbGEgZGlyZWNjacOzbiBkZSBsYSBlbXByZXNhLg0KDQpDb25jbHVzaW9uZXMgY2xhdmUgeSBsYXMgcmVjb21lbmRhY2lvbmVzIGVzcGVjw61maWNhcyBwYXJhIGd1aWFyIGxhcyBkZWNpc2lvbmVzIGVzdHJhdMOpZ2ljYXMgZGUgbGEgZW1wcmVzYSBpbm1vYmlsaWFyaWENCg0KIyMgRGVzYXJyb2xsbw0KDQojIyMjIEV4cGxvcmFjacOzbiB5IHByZXBhcmFjacOzbiBkZWwgZGF0YXNldA0KDQpgYGB7ciBlY2hvPVRSVUV9DQojIEluc3RhbGFjaW9uIGRlIGxpYnJlcsOtYXMNCg0KaW5zdGFsbC5wYWNrYWdlcyhjKCJkZXZ0b29scyIsICJEcGx5ciIsICJmYWN0b2V4dHJhIiwgImdncGxvdDIiLCAiZ2dmb3J0aWZ5IiwgIkZhY3RvTWluZVIiLCAiY29ycnBsb3QiKSkNCmxpYnJhcnkoZGV2dG9vbHMpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ2ZvcnRpZnkpDQpsaWJyYXJ5KEZhY3RvTWluZVIpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KDQpgYGANCg0KIyMjIyBTZSByZWFsaXphIHVuYSBleHBsb3JhY2lvbiB5IGxpbXBpZXphIGRlbCBEYXRhc2V0IG9yaWdpbmFsIHZpdmllbmRhc19mYWx0YW50ZXMgcXVlIGNvbnRpZW5lIDgzMzAgb2JzZXJ2YWNpb25lcyB5IDEzIHZhcmlhYmxlcyAoZGltZW5zaW9uZXMpDQoNCmBgYHtyfQ0KZGF0YSh2aXZpZW5kYV9mYWx0YW50ZXMpDQpoZWFkKHZpdmllbmRhX2ZhbHRhbnRlcykNCmBgYA0KDQpgYGB7cn0NCg0Kc3VtbWFyeSh2aXZpZW5kYV9mYWx0YW50ZXMpDQpgYGANCg0KIyMjIyBTZSBlbGltaW5hIGNvbHVtbmEgaWQsIHlhIHF1ZSBlcyB1biBpZGVudGlmaWNhZG9yIMO6bmljbyB5IG5vIGNvbnRpZW5lIGluZm9ybWFjacOzbiBhbmFsw610aWNhLg0KDQpgYGB7cn0NCg0KIyBFbGltaW5hciBsYSBjb2x1bW5hICdpZCcgKHN1cG9uaWVuZG8gcXVlIHNlIGxsYW1hIGV4YWN0YW1lbnRlICdpZCcpDQp2aXZpZW5kYSA8LSB2aXZpZW5kYV9mYWx0YW50ZXNbICwgLTFdDQoNCiMgVmVyaWZpY2FyIGVzdHJ1Y3R1cmEgZGVzcHXDqXMgZGUgbGEgbGltcGllemENCg0Kc3VtbWFyeSh2aXZpZW5kYSkNCg0KYGBgDQoNCiMjIyMgU2UgcHJvY2VkZSBhIHJlZW1wbGF6YXIgdmFsb3JlcyBOQSBkZSBsYXMgY29sdW1uYXMgUGlzbyAoMjY0MSkgeSBQYXJxdWVhZGVybyAoMTYwNikgcG9yIHZhbG9yZXMgMC4NCg0KYGBge3J9DQoNCnZpdmllbmRhJHBpc29baXMubmEodml2aWVuZGEkcGlzbyldIDwtIDANCg0Kdml2aWVuZGEkcGFycXVlYVtpcy5uYSh2aXZpZW5kYSRwYXJxdWVhKV0gPC0gMA0KDQoNCmBgYA0KDQpgYGB7cn0NCmhlYWQodml2aWVuZGEpDQoNCmBgYA0KDQojIyMjIExhIHZhcmlhYmxlICJ0aXBvIiB0aWVuZSB1biBwcm9ibGVtYSBjb24gbGFzIG1heXVzY3VsYXMgeSBtaW5pc2N1bGFzLCBzZSBpbmNsdXllbiB0b2RhcyBsYXMgdmFyaWFudGVzIGVuOiBhcGFydGFtZW50byB5IGNhc2EuDQoNCmBgYHtyfQ0Kdml2aWVuZGEkdGlwbyA8LSB0b2xvd2VyKHZpdmllbmRhJHRpcG8pDQoNCnZpdmllbmRhJHRpcG8gPC0gZ3N1YigiYXB0byIsICJhcGFydGFtZW50byIsIHZpdmllbmRhJHRpcG8sIGlnbm9yZS5jYXNlID0gVFJVRSkNCnVuaXF1ZSh2aXZpZW5kYSR0aXBvKQ0KdGFibGUodml2aWVuZGEkdGlwbykNCg0KYGBgDQoNCiMjIyMgRWxpbWluYW1vcyBmaWxhcyBjb24gdmFsb3JlcyBmYWx0YW50ZXMgIk5BIg0KDQpgYGB7cn0NCnZpdmllbmRhX2NsZWFuIDwtIG5hLm9taXQodml2aWVuZGEpDQoNCnN1bShpcy5uYSh2aXZpZW5kYV9jbGVhbikpICMgRGViZSBkZXZvbHZlciAwIHNpIG5vIGhheSBOQQ0KDQpkaW0odml2aWVuZGFfY2xlYW4pICNOdWV2YSBkaW1lbnNpb24gKGZpbGFzIC8gY29sdW1uYXMpDQoNCm5yb3codml2aWVuZGEpIC0gbnJvdyh2aXZpZW5kYV9jbGVhbikgICMgTsO6bWVybyBkZSBmaWxhcyBlbGltaW5hZGFzDQoNCnN1bW1hcnkodml2aWVuZGFfY2xlYW4pICNDb21wcm9iYW1vcw0KYGBgDQoNCiMjIyMgQ2FsY3VsYW1vcyBsYSBtYXRyaXogZGUgY29ycmVsYWNpb24gcGFyYSBkZXNjYXJ0YXIgdmFyaWFibGVzIHJlZHVuZGFudGVzLCBzZWxlY2Npb25hbW9zIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyByZWxldmFudGVzOg0KDQpgYGB7cn0NCnZyYl9udW1fdGFibGUgIDwtIHZpdmllbmRhX2NsZWFuWywgYygncHJlY2lvbScsICdhcmVhY29uc3QnLCAnaGFiaXRhYycsICdiYW5pb3MnKV0NCg0KY29ycmVsYXRpb25fbWF0cml4IDwtIGNvcih2cmJfbnVtX3RhYmxlLCB1c2UgPSAiY29tcGxldGUub2JzIikNCnByaW50KGNvcnJlbGF0aW9uX21hdHJpeCkNCmBgYA0KDQojIyMjIFZpc3VhbGl6YW1vcyBsYSBtYXRyaXogZGUgY29ycmVsYWNpw7NuDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiY29ycnBsb3QiKQ0KbGlicmFyeShjb3JycGxvdCkNCg0KY29ycnBsb3QoY29ycmVsYXRpb25fbWF0cml4LCBtZXRob2QgPSAiY2lyY2xlIiwgdHlwZSA9ICJsb3dlciIsDQogICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpKDIwMCksDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCB0bC5zcnQgPSA0NSwgYWRkQ29lZi5jb2wgPSAiYmxhY2siKQ0KYGBgDQoNCiMgQU7DgUxJU0lTIERFIENPTVBPTkVOVEVTIFBSSU5DSVBBTEVTIChQQ0EpDQoNCmBgYHtyfQ0Kdml2aWVuZGFfcGNhIDwtIHZpdmllbmRhX2NsZWFuDQoNCm51bWVyaWNhcyA8LSB2aXZpZW5kYV9wY2Fbc2FwcGx5KHZpdmllbmRhX3BjYSwgaXMubnVtZXJpYyldICMgU2VsZWNjaW9uYW1vcyBzb2xvIHZhcmlhYmxlcyBudW3DqXJpY2FzIHBhcmEgZWwgUENBDQoNCg0KbnVtZXJpY2FzX3NjYWxlZCA8LSBzY2FsZShudW1lcmljYXMpICMgRXN0YW5kYXJpemFyIGRhdG9zIChtZWRpYSA9IDAsIHZhcmlhbnphID0gMSkgcGFyYSBQQ0ENCmBgYA0KDQpgYGB7cn0NCnBjYV9yZXN1bHQgPC0gcHJjb21wKG51bWVyaWNhc19zY2FsZWQsIGNlbnRlciA9IFRSVUUsIHNjYWxlLiA9IFRSVUUpDQoNCiMgVmlzdWFsaXphciBsYSBpbXBvcnRhbmNpYSBkZSBjYWRhIGNvbXBvbmVudGUNCnN1bW1hcnkocGNhX3Jlc3VsdCkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dmb3J0aWZ5KQ0KDQojIEdyw6FmaWNvIGRlIHZhcmlhbnphIGV4cGxpY2FkYSAoU2NyZWUgUGxvdCkNCmZ2aXpfZWlnKHBjYV9yZXN1bHQsIGFkZGxhYmVscyA9IFRSVUUsIHlsaW0gPSBjKDAsIDEwMCkpDQoNCmBgYA0KDQojIyMjIExhIGdyw6FmaWNhIHF1ZSBtdWVzdHJhIGVzIHVuIFNjcmVlIFBsb3QgKGdyw6FmaWNvIGRlIHNlZGltZW50YWNpw7NuKSBxdWUgcmVwcmVzZW50YSBlbCBwb3JjZW50YWplIGRlIHZhcmlhbnphIGV4cGxpY2FkYSBwb3IgY2FkYSBjb21wb25lbnRlIHByaW5jaXBhbCBlbiBlbCBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKFBDQSkuDQoNCiMjIyMgSW50ZXJwcmV0YWNpw7NuIGRlIGxhIGdyw6FmaWNhIGVqZSBYIChEaW1lbnNpb25zKTogUmVwcmVzZW50YSBsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgKFBDMSwgUEMyLCBQQzMsIGV0Yy4pLg0KDQojIyMjIEVqZSBZIChQZXJjZW50YWdlIG9mIEV4cGxhaW5lZCBWYXJpYW5jZSk6IE11ZXN0cmEgZWwgcG9yY2VudGFqZSBkZSB2YXJpYWJpbGlkYWQgZGUgbG9zIGRhdG9zIGV4cGxpY2FkYSBwb3IgY2FkYSBjb21wb25lbnRlLg0KDQojIyMjIEJhcnJhcyBhenVsZXM6IEluZGljYW4gY3XDoW50YSB2YXJpYW56YSBleHBsaWNhIGNhZGEgY29tcG9uZW50ZS4NCg0KIyMjIyBMw61uZWEgbmVncmEgY29uIHB1bnRvczogQXl1ZGEgYSB2aXN1YWxpemFyIGxhIGRpc21pbnVjacOzbiBwcm9ncmVzaXZhIGRlIGxhIHZhcmlhbnphIGV4cGxpY2FkYS4NCg0KYGBge3J9DQpmdml6X3BjYV92YXIocGNhX3Jlc3VsdCwNCmNvbC52YXIgPSAiY29udHJpYiIsICMgQ29sb3IgYnkgY29udHJpYnV0aW9ucyB0byB0aGUgUEMNCmdyYWRpZW50LmNvbHMgPSBjKCIjMTdiZWNmIiwgICIjN2Y3ZjdmIiksDQpyZXBlbCA9IFRSVUUgICAgICMgQXZvaWQgdGV4dCBvdmVybGFwcGluZw0KKSANCg0KYGBgDQoNCiMjIyMgRWwgYmlwbG90IGRlIFBDQSBtdWVzdHJhIGPDs21vIGxhcyB2YXJpYWJsZXMgZGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvIHVyYmFubyBzZSBhZ3J1cGFuIHkgY29udHJpYnV5ZW4gYSBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGRhdG9zLiBFbCBwcmltZXIgY29tcG9uZW50ZSAoRGltMSwgMzguMiUpIGVzdMOhIHByaW5jaXBhbG1lbnRlIGluZmx1ZW5jaWFkbyBwb3IgdmFyaWFibGVzIGVjb27Ds21pY2FzIHkgZXN0cnVjdHVyYWxlcyBjb21vIHByZWNpbyBwb3IgbWV0cm8gY3VhZHJhZG8sIMOhcmVhIGNvbnN0cnVpZGEsIGJhw7FvcyB5IHBhcnF1ZWFkZXJvcywgbWllbnRyYXMgcXVlIGVsIHNlZ3VuZG8gY29tcG9uZW50ZSAoRGltMiwgMjAuNyUpIGVzdMOhIGRvbWluYWRvIHBvciBmYWN0b3JlcyBnZW9ncsOhZmljb3MgKGxhdGl0dWQgeSBsb25naXR1ZCkuIExhcyB2YXJpYWJsZXMgYWx0YW1lbnRlIGNvbnRyaWJ1eWVudGVzIChlbiB2ZXJkZSkgdGllbmVuIG1heW9yIGltcGFjdG8gZW4gbGEgZXN0cnVjdHVyYSBkZSBsb3MgZGF0b3MsIG1pZW50cmFzIHF1ZSBvdHJhcywgY29tbyBwaXNvIHkgZXN0cmF0bywgdGllbmVuIG1lbm9yIHJlbGV2YW5jaWEuIEVzdGUgYW7DoWxpc2lzIHBlcm1pdGUgaWRlbnRpZmljYXIgcGF0cm9uZXMgY2xhdmUgZW4gZWwgbWVyY2FkbyBpbm1vYmlsaWFyaW8geSBsYSByZWxhY2nDs24gZW50cmUgc3VzIHZhcmlhYmxlcyBwcmluY2lwYWxlcy4NCg0KIyMjIENvbmNsdXNpw7NuDQoNCiMjIyMgRXN0ZSBncsOhZmljbyBzdWdpZXJlIHF1ZSBsb3MgcHJpbWVyb3MgMy00IGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGNhcHR1cmFuIGxhIG1heW9yIHBhcnRlIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgZGF0YXNldCB5IHB1ZWRlbiB1c2Fyc2UgcGFyYSByZWR1Y2lyIGxhIGRpbWVuc2lvbmFsaWRhZCBzaW4gcGVyZGVyIGRlbWFzaWFkYSBpbmZvcm1hY2nDs24uDQoNCiMgQU7DgUxJU0lTIERFIENPTkdMT01FUkFET1MgKENMVVNURVJJTkcpDQoNCiMjIyMgRXN0YW5kYXJpemFtb3MgbGFzIHZhcmlhYmxlcyBudW3DqXJpY2FzIHBhcmEgZXZpdGFyIHF1ZSB2YXJpYWJsZXMgY29uIGVzY2FsYXMgZ3JhbmRlcyBkb21pbmVuIGVsIGFuw6FsaXNpczoNCg0KYGBge3J9DQp2aXZpZW5kYV9zY2FsZWQgPC0gc2NhbGUodml2aWVuZGFfY2xlYW5bLCBjKCJwcmVjaW9tIiwgImFyZWFjb25zdCIsICJiYW5pb3MiLCAiaGFiaXRhYyIsICJlc3RyYXRvIiwgInBpc28iLCAibGF0aXR1ZCIsICJsb25naXR1ZCIpXSkNCmhlYWQodml2aWVuZGFfc2NhbGVkKQ0KYGBgDQoNCiMjIE3DqXRvZG8gZGUgY29kbyBwYXJhIGFncnVwYW1pZW50bw0KDQpgYGB7cn0NCiNQYXJhIGRldGVybWluYXIgZWwgbsO6bWVybyDDs3B0aW1vIGRlIGNsdXN0ZXJzLCBzZSBwdWVkZSB1c2FyIGVsIG3DqXRvZG8gZGVsIGNvZG8gKGVsYm93IG1ldGhvZCk6DQoNCmZ2aXpfbmJjbHVzdCh2aXZpZW5kYV9zY2FsZWQsIGttZWFucywgbWV0aG9kID0gIndzcyIpDQoNCmBgYA0KDQojIyMjIEVsIE3DqXRvZG8gbm9zIGluZGljYSBxdWUgZWwgY29kbyAobsO6bWVybyBkZSBjbHVzdGVycykgZXMgZGUgMy4NCg0KIyMgTcOpdG9kbyBkZSBsYSBzaWx1ZXRhDQoNCmBgYHtyfQ0KbGlicmFyeShjbHVzdGVyKQ0KDQpmdml6X25iY2x1c3Qodml2aWVuZGFfc2NhbGVkLCBrbWVhbnMsIG1ldGhvZCA9ICJzaWxob3VldHRlIikgKyBsYWJzIChzdWJ0aXRsZT0ic2lsaG91ZXR0ZSBtZXRob2QiKQ0KYGBgDQoNCiMjIyMgRW4gZXN0ZSBtw6l0b2RvIHNlIGNvbmZpcm1hIHF1ZSBlbCBuw7ptZXJvIGRlIGNsw7pzdGVyIG9wdGltbyBlcyBkZSAzLg0KDQojIyMgVmlzdWFsaXphbW9zIGFzaWduYWNpw7NuIGRlIGNsdXN0ZXJzDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKSAgDQprbWVhbnNfcmVzdWx0IDwtIGttZWFucyh2aXZpZW5kYV9zY2FsZWQsIGNlbnRlcnMgPSAzLCBuc3RhcnQgPSAyNSkNCnZpdmllbmRhX2NsZWFuJGNsdXN0ZXIgPC0gYXMuZmFjdG9yKGttZWFuc19yZXN1bHQkY2x1c3RlcikNCg0Kc2lsaG91ZXR0ZV9wbG90IDwtIHNpbGhvdWV0dGUoa21lYW5zX3Jlc3VsdCRjbHVzdGVyLCBkaXN0KHZpdmllbmRhX3NjYWxlZCkpDQpmdml6X3NpbGhvdWV0dGUoc2lsaG91ZXR0ZV9wbG90KQ0KYGBgDQoNCiMjIyMgTGEgaW1hZ2VuIG11ZXN0cmEgZWwgYW7DoWxpc2lzIGRlIHNpbGhvdWV0dGUgcGFyYSBldmFsdWFyIGxhIGNhbGlkYWQgZGUgbGEgc2VnbWVudGFjacOzbiBlbiB0cmVzIGNsdXN0ZXJzLiBFbCB2YWxvciBwcm9tZWRpbyBkZSBzaWxob3VldHRlIGVzIDAuMywgbG8gcXVlIGluZGljYSB1bmEgZXN0cnVjdHVyYSBkZSBjbHVzdGVyaW5nIG1vZGVyYWRhIHBlcm8gbm8gw7NwdGltYS4gRWwgQ2x1c3RlciAxIChyb2pvKSB0aWVuZSBsYSBtZWpvciBjb2hlc2nDs24geSBzZXBhcmFjacOzbiBjb24gdW4gcHJvbWVkaW8gZGUgMC40MSwgbG8gcXVlIHN1Z2llcmUgcXVlIHN1cyBwdW50b3MgZXN0w6FuIHJlbGF0aXZhbWVudGUgYmllbiBhZ3J1cGFkb3MuIEVuIGNvbnRyYXN0ZSwgZWwgQ2x1c3RlciAyICh2ZXJkZSkgdGllbmUgZWwgbWVub3IgdmFsb3IgcHJvbWVkaW8gKDAuMTEpLCBsbyBxdWUgaW5kaWNhIHVuYSBwb2JyZSBzZXBhcmFjacOzbiB5IHBvc2libGUgc29sYXBhbWllbnRvIGNvbiBvdHJvcyBjbHVzdGVycy4gRWwgQ2x1c3RlciAzIChhenVsKSB0aWVuZSB1biB2YWxvciBpbnRlcm1lZGlvICgwLjI3KSwgbG8gcXVlIHN1Z2llcmUgdW5hIGFncnVwYWNpw7NuIGTDqWJpbC4gRW4gZ2VuZXJhbCwgbGEgc2VnbWVudGFjacOzbiBwb2Ryw61hIG1lam9yYXJzZSBhanVzdGFuZG8gZWwgbsO6bWVybyBkZSBjbHVzdGVycyBvIHV0aWxpemFuZG8gb3Ryb3MgbcOpdG9kb3MgZGUgYWdydXBhbWllbnRvLg0KDQojIyBDbHVzdGVyaW5nIEplcsOhcnF1aWNvDQoNCmBgYHtyfQ0KZCA8LSBkaXN0KHZpdmllbmRhX3NjYWxlZCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpoYyA8LSBoY2x1c3QoZCwgbWV0aG9kID0gIndhcmQuRDIiKQ0KcGxvdChoYykNCnJlY3QuaGNsdXN0KGhjLCBrID0gMywgYm9yZGVyID0gInJlZCIpDQoNCmBgYA0KDQojIyMgRGlzdHJpYnVjacOzbiBkZWwgY2zDunN0ZXINCg0KYGBge3J9DQpmdml6X2NsdXN0ZXIoa21lYW5zX3Jlc3VsdCwgZGF0YSA9IHZpdmllbmRhX3NjYWxlZCwgZWxsaXBzZS50eXBlID0gImNvbnZleCIpDQoNCmBgYA0KDQojIyMgQ29uY2x1c2nDs24NCg0KIyMjIyBFbCBhbsOhbGlzaXMgZGUgY29uZ2xvbWVyYWRvcyBwZXJtaXRpw7MgaWRlbnRpZmljYXIgdHJlcyBzZWdtZW50b3MgZGlmZXJlbmNpYWRvcyBkZW50cm8gZGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvIHVyYmFuby4gRWwgcHJpbWVyIGdydXBvIGFncnVwYSBwcm9waWVkYWRlcyBkZSBhbHRvIHZhbG9yIGNvbiBtYXlvciDDoXJlYSBjb25zdHJ1aWRhLCBtw6FzIGJhw7FvcyB5IHBhcnF1ZWFkZXJvcywgZ2VuZXJhbG1lbnRlIHViaWNhZGFzIGVuIHpvbmFzIGRlIG1heW9yIGVzdHJhdG8gc29jaW9lY29uw7NtaWNvLiBFbCBzZWd1bmRvIGdydXBvIHJlcHJlc2VudGEgdml2aWVuZGFzIGRlIGdhbWEgbWVkaWEsIGNvbiBwcmVjaW9zIHkgY2FyYWN0ZXLDrXN0aWNhcyBlcXVpbGlicmFkYXMsIGRpcmlnaWRhcyBhIGNvbXByYWRvcmVzIGRlIGNsYXNlIG1lZGlhIHF1ZSBidXNjYW4gdW5hIGNvbWJpbmFjacOzbiBkZSBhY2Nlc2liaWxpZGFkIHkgY29tb2RpZGFkLiBFbCB0ZXJjZXIgZ3J1cG8sIHBvciBzdSBwYXJ0ZSwgc2UgY29tcG9uZSBkZSBwcm9waWVkYWRlcyBtw6FzIGVjb27Ds21pY2FzLCBjb24gbWVub3Igw6FyZWEgY29uc3RydWlkYSB5IHViaWNhZGFzIGVuIHNlY3RvcmVzIGRlIGVzdHJhdG8gbcOhcyBiYWpvLCBsbyBxdWUgc3VnaWVyZSB1bmEgb2ZlcnRhIG9yaWVudGFkYSBhIGNvbXByYWRvcmVzIGNvbiBtZW5vciBjYXBhY2lkYWQgYWRxdWlzaXRpdmEuIEVzdG9zIHJlc3VsdGFkb3Mgc29uIGNsYXZlIHBhcmEgZWwgZGVzYXJyb2xsbyBkZSBlc3RyYXRlZ2lhcyBkZSBpbnZlcnNpw7NuLCBmaWphY2nDs24gZGUgcHJlY2lvcyB5IHBsYW5pZmljYWNpw7NuIHVyYmFuYSwgcGVybWl0aWVuZG8gYSBkZXNhcnJvbGxhZG9yZXMgeSBjb21wcmFkb3JlcyBjb21wcmVuZGVyIG1lam9yIGxhIHNlZ21lbnRhY2nDs24gZGVsIG1lcmNhZG8geSBvcHRpbWl6YXIgbGEgdG9tYSBkZSBkZWNpc2lvbmVzIGVuIGZ1bmNpw7NuIGRlIHN1cyBvYmpldGl2b3MuDQoNCiMgQU7DgUxJU0lTIERFIENPUlJFU1BPTkRJRU5DSUENCg0KYGBge3J9DQoNCnRhYmxhIDwtIHRhYmxlKHZpdmllbmRhX2NsZWFuJHRpcG8sIHZpdmllbmRhX2NsZWFuJHpvbmEsIHZpdmllbmRhX2NsZWFuJGVzdHJhdG8sIHZpdmllbmRhX2NsZWFuJGJhcnJpbykNCnN1bW1hcnkodGFibGEpDQpzdW1tYXJ5KHZpdmllbmRhX2NsZWFuJGJhcnJpbykNCg0KYGBgDQoNCiMjIyMgU2Ugb21pdGUgbGEgdmFyaWFibGUgY2F0ZWdvcmljYSBiYXJyaW8gZGViaWRvIGEgbGEgYWx0YSBjYW50aWRhZCBkZSByZWdpc3Ryb3MgeSBiYWphIHJlbGV2YW5jaWEgcGFyYSBlbCBhbmFsaXNpcw0KDQpgYGB7cn0NCiNTZSByZWFsaXphIGhpc3RvZ3JhbWEgZGUgcHJlY2lvIHkgc2UgcmVhbGl6YSB1bmEgY29udmVyc2lvbiBhIHZhcmlhYmxlIGNhbnRlZ29yaWNhIGVtcGxlYW5kbyByYW5nb3MgZGUgMjUwIE1pbGxvbmVzIGRlIENPUA0KaGlzdCh2aXZpZW5kYV9jbGVhbiRwcmVjaW9tLCB4bGFiID0gJ1ByZWNpbycpDQpgYGANCg0KIyMjIyBFbCBoaXN0b2dyYW1hIG11ZXN0cmEgbGEgZGlzdHJpYnVjacOzbiBkZSBwcmVjaW9zIGRlIHZpdmllbmRhIGEgcGFydGlyIGRlIGxhIHZhcmlhYmxlIHZpdmllbmRhX2NsZWFuXCRwcmVjaW9tLiBTZSBvYnNlcnZhIHVuYSBkaXN0cmlidWNpw7NuIHNlc2dhZGEgYSBsYSBkZXJlY2hhLCBsbyBxdWUgaW5kaWNhIHF1ZSBsYSBtYXlvcsOtYSBkZSBsYXMgdml2aWVuZGFzIHRpZW5lbiBwcmVjaW9zIG3DoXMgYmFqb3MsIGNvbmNlbnRyw6FuZG9zZSBwcmluY2lwYWxtZW50ZSBwb3IgZGViYWpvIGRlIGxvcyA1MDAuIEEgbWVkaWRhIHF1ZSBlbCBwcmVjaW8gYXVtZW50YSwgbGEgZnJlY3VlbmNpYSBkZSB2aXZpZW5kYXMgZGlzbWludXllIHByb2dyZXNpdmFtZW50ZSwgY29uIHBvY29zIHZhbG9yZXMgc3VwZXJpb3JlcyBhIDE1MDAuIEVzdGEgYXNpbWV0csOtYSBzdWdpZXJlIHF1ZSBsb3MgcHJlY2lvcyBlbGV2YWRvcyBzb24gbWVub3MgY29tdW5lcyBlbiBsYSBtdWVzdHJhIGFuYWxpemFkYS4NCg0KYGBge3J9DQp2aXZpZW5kYV9DQSA8LSB2aXZpZW5kYV9jbGVhbg0KIyBDcmVhciBsb3MgY29ydGVzIHBhcmEgbG9zIGludGVydmFsb3MgZGUgMjUwLCBjb21lbnphbmRvIGRlc2RlIDANCmJyZWFrcyA8LSBzZXEoMCwgbWF4KHZpdmllbmRhX0NBJHByZWNpb20sIG5hLnJtID0gVFJVRSkgKyAyNTAsIGJ5ID0gMjUwKQ0KDQojIENyZWFyIGV0aXF1ZXRhcyBkZSBtYW5lcmEgZGluw6FtaWNhIGFzZWd1cmFuZG8gcXVlIGNvaW5jaWRhbiBlbiBuw7ptZXJvIGNvbiBsb3MgaW50ZXJ2YWxvcw0KbGFiZWxzIDwtIHBhc3RlMCgiWyIsIGhlYWQoYnJlYWtzLCAtMSksICItIiwgdGFpbChicmVha3MsIC0xKSwgIikiKQ0KDQojIENvbnZlcnRpciBgcHJlY2lvbWAgZW4gdW5hIHZhcmlhYmxlIGNhdGVnw7NyaWNhIGNvbiBsb3MgaW50ZXJ2YWxvcyBjb3JyZWdpZG9zDQp2aXZpZW5kYV9DQSRwcmVjaW9tX2NhdCA8LSBjdXQodml2aWVuZGFfQ0EkcHJlY2lvbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYnJlYWtzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0ID0gRkFMU0UsICAjIEludGVydmFsb3MgY2VycmFkb3MgYSBsYSBpenF1aWVyZGEgWykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsYWJlbHMpDQoNCiMgVmVyaWZpY2FyIGxhIG51ZXZhIHZhcmlhYmxlDQp0YWJsZSh2aXZpZW5kYV9DQSRwcmVjaW9tX2NhdCkNCg0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KDQojIENyZWEgbG9zIGdyw6FmaWNvcyBkZSBiYXJyYXMgY29uIGxhcyBldGlxdWV0YXMgZGVsIGVqZSB4IGdpcmFkYXMNCkcxIDwtIGdncGxvdCh2aXZpZW5kYV9DQSwgYWVzKHg9em9uYSkpICsgZ2VvbV9iYXIoZmlsbD0gIiMxN2JlY2YiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkNCkcyIDwtIGdncGxvdCh2aXZpZW5kYV9DQSwgYWVzKHg9ZXN0cmF0bykpICsgZ2VvbV9iYXIoZmlsbD0gIiM3ZjdmN2YiKQ0KRzMgPC0gZ2dwbG90KHZpdmllbmRhX0NBLCBhZXMoeD10aXBvKSkgKyBnZW9tX2JhcihmaWxsPSAiIzdmN2Y3ZiIpDQpHNCA8LSBnZ3Bsb3Qodml2aWVuZGFfQ0EsIGFlcyh4PXByZWNpb21fY2F0KSkgKyBnZW9tX2JhcihmaWxsPSAiIzE3YmVjZiIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQ0KDQojIE9yZ2FuaXphIGxvcyBncsOhZmljb3MgZW4gdW5hIGN1YWRyw61jdWxhDQpncmlkLmFycmFuZ2UoRzEsIEcyLCBHMywgRzQsIG5yb3cgPSAyKQ0KYGBgDQoNCiMjIyMgTGFzIGdyw6FmaWNhcyBtdWVzdHJhbiBsYSBkaXN0cmlidWNpw7NuIGRlIHZpdmllbmRhcyBzZWfDum4gZGlmZXJlbnRlcyB2YXJpYWJsZXMuIExhIG1heW9yw61hIHNlIGVuY3VlbnRyYSBlbiBsYSBab25hIFN1ciwgc2VndWlkYSBwb3IgbGEgWm9uYSBOb3J0ZSB5IGxhIFpvbmEgT2VzdGUsIG1pZW50cmFzIHF1ZSBsYSBab25hIENlbnRybyB5IGxhIFpvbmEgT3JpZW50ZSB0aWVuZW4gbWVub3MgcHJlc2VuY2lhLiBFbiBjdWFudG8gYSBlc3RyYXRvLCBwcmVkb21pbmFuIGxvcyBuaXZlbGVzIDQgeSA1LCBjb24gbWVub3IgcmVwcmVzZW50YWNpw7NuIGVuIGxvcyBlc3RyYXRvcyAzIHkgNi4gRW4gdGlwbyBkZSB2aXZpZW5kYSwgbG9zIGFwYXJ0YW1lbnRvcyBzb24gbcOhcyBjb211bmVzIHF1ZSBsYXMgY2FzYXMuIEZpbmFsbWVudGUsIGxhIG1heW9yw61hIGRlIGxhcyB2aXZpZW5kYXMgdGllbmVuIHByZWNpb3MgZW4gbG9zIHJhbmdvcyBtw6FzIGJham9zICgwLTUwMCksIGNvbiB1bmEgZGlzbWludWNpw7NuIHByb2dyZXNpdmEgZW4gZnJlY3VlbmNpYSBhIG1lZGlkYSBxdWUgZWwgcHJlY2lvIGF1bWVudGEsIGV2aWRlbmNpYW5kbyB1bmEgZGlzdHJpYnVjacOzbiBzZXNnYWRhIGEgbGEgZGVyZWNoYS4NCg0KIyMjIEFuw6FsaXNpcyBab25hL0VzdHJhdG8NCg0KYGBge3J9DQoNCnRhYmxhMSA8LSB0YWJsZSh2aXZpZW5kYV9DQSR6b25hLCB2aXZpZW5kYV9DQSRlc3RyYXRvKQ0KY29sbmFtZXModGFibGExKSA8LSBjKCJFc3RyYXRvMyIsICJFc3RyYXRvNCIsICJFc3RyYXRvNSIsICJFc3RyYXRvNiIgKQ0KdGFibGExDQpgYGANCg0KYGBge3J9DQpjaGlzcS50ZXN0KHRhYmxhMSkNCmBgYA0KDQojIyMjIEVzdGUgYW7DoWxpc2lzIGluZGljYSBxdWUgbGFzIHZhcmlhYmxlcyBlbiBab25hLUVzdHJhdG8gbm8gc29uIGluZGVwZW5kaWVudGVzLCBlcyBkZWNpciwgZXhpc3RlIHVuYSBhc29jaWFjacOzbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIGVudHJlIGVsbGFzLg0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCnJlc3VsdGFkb3Nfem9uYV9lc3RyYXRvIDwtIENBKHRhYmxhMSkNCmBgYA0KDQojIyMgQ29uY2x1c2nDs246DQoNCi0gICBFeGlzdGVuIHBhdHJvbmVzIGNsYXJvcyBkZSBhc29jaWFjacOzbiBlbnRyZSBsYXMgem9uYXMgeSBsb3MgZXN0cmF0b3Mgc29jaW9lY29uw7NtaWNvcy4NCi0gICBab25hcyBjb21vIE9yaWVudGUgeSBDZW50cm8gcGFyZWNlbiBlc3RhciByZWxhY2lvbmFkYXMgY29uIGxvcyBlc3RyYXRvcyBtw6FzIGJham9zIG8gbWVkaW9zLg0KLSAgIFpvbmFzIGNvbW8gT2VzdGUgZXN0w6FuIG3DoXMgdmluY3VsYWRhcyBjb24gbG9zIGVzdHJhdG9zIG3DoXMgYWx0b3MuDQotICAgRWwgYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYSBoYSBzaWRvIGVmZWN0aXZvIHBhcmEgaWRlbnRpZmljYXIgbGEgcmVsYWNpw7NuIGVudHJlIGxhIHViaWNhY2nDs24gZ2VvZ3LDoWZpY2EgeSBlbCBuaXZlbCBzb2Npb2Vjb27Ds21pY28uDQoNCiMjIyBBbsOhbGlzaXMgUHJlY2lvL1RpcG8NCg0KYGBge3J9DQp0YWJsYTIgPC0gdGFibGUodml2aWVuZGFfQ0EkcHJlY2lvbV9jYXQsIHZpdmllbmRhX0NBJHRpcG8pDQpjb2xuYW1lcyh0YWJsYTIpIDwtIGMoIkNhc2EiLCAiQXBhcnRhbWVudG8iKQ0KdGFibGEyDQpgYGANCg0KYGBge3J9DQpjaGlzcS50ZXN0KHRhYmxhMikNCmBgYA0KDQpFc3RlIGFuw6FsaXNpcyBpbmRpY2EgcXVlIGxhcyB2YXJpYWJsZXMgZW4gWm9uYS1Fc3RyYXRvIG5vIHNvbiBpbmRlcGVuZGllbnRlcywgZXMgZGVjaXIsIGV4aXN0ZSB1bmEgYXNvY2lhY2nDs24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YSBlbnRyZSBlbGxhcy4NCg0KYGBge3J9DQojIENhcmdhciBsaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVzaGFwZTIpDQoNCiMgQ29udmVydGlyIGxhIHRhYmxhIGVuIHVuIGRhdGFmcmFtZQ0KdGFibGEyX2RmIDwtIGFzLmRhdGEuZnJhbWUubWF0cml4KHRhYmxhMikNCg0KIyBBZ3JlZ2FyIGxhIGNvbHVtbmEgZGUgcmFuZ29zIGRlIHByZWNpb3MNCnRhYmxhMl9kZiRSYW5nbyA8LSByb3duYW1lcyh0YWJsYTJfZGYpDQoNCiMgQ29udmVydGlyIGEgZm9ybWF0byBsYXJnbyAobWVsdCkNCnRhYmxhMl9tZWx0IDwtIG1lbHQodGFibGEyX2RmLCBpZC52YXJzID0gIlJhbmdvIikNCg0KIyBDcmVhciBlbCBncsOhZmljbyBlbiB1biBwbGFubyBjYXJ0ZXNpYW5vDQpnZ3Bsb3QodGFibGEyX21lbHQsIGFlcyh4ID0gUmFuZ28sIHkgPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBWaXZpZW5kYXMgcG9yIFByZWNpbyB5IFRpcG8iLA0KICAgICAgIHggPSAiUmFuZ28gZGUgUHJlY2lvIiwNCiAgICAgICB5ID0gIkNhbnRpZGFkIGRlIFZpdmllbmRhcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQoNCg0KYGBgDQoNCiMjIyMgTGEgZGlzdHJpYnVjacOzbiBkZSB2aXZpZW5kYXMgcG9yIHJhbmdvIGRlIHByZWNpbyB5IHRpcG8gbXVlc3RyYSBxdWUgbGEgbWF5b3LDrWEgZGUgbGFzIGNhc2FzIHNlIGVuY3VlbnRyYW4gZW4gbG9zIHJhbmdvcyBkZSBwcmVjaW9zIG3DoXMgYmFqb3MsIGVzcGVjaWFsbWVudGUgZW4gZWwgaW50ZXJ2YWxvIFswLTI1MCksIG1pZW50cmFzIHF1ZSBsb3MgYXBhcnRhbWVudG9zIHRpZW5lbiB1bmEgZGlzdHJpYnVjacOzbiBtw6FzIHVuaWZvcm1lIGVuIGxvcyBkaXN0aW50b3MgcmFuZ29zIGRlIHByZWNpb3MuIFNlIG9ic2VydmEgcXVlIGVuIGVsIHJhbmdvIFsyNTAtNTAwKSBoYXkgdW5hIGFsdGEgY29uY2VudHJhY2nDs24gZGUgdml2aWVuZGFzIGRlIGFtYm9zIHRpcG9zLCBsbyBxdWUgc3VnaWVyZSBxdWUgZXN0ZSBzZWdtZW50byBkZSBwcmVjaW8gZXMgY2xhdmUgZW4gZWwgbWVyY2Fkby4gQSBtZWRpZGEgcXVlIGVsIHByZWNpbyBhdW1lbnRhLCBsYSBjYW50aWRhZCBkZSB2aXZpZW5kYXMgZGlzbWludXllLCBwZXJvIGxvcyBhcGFydGFtZW50b3MgbWFudGllbmVuIHVuYSBwcmVzZW5jaWEgcmVsYXRpdmFtZW50ZSBtYXlvciBlbiBsb3MgcmFuZ29zIHN1cGVyaW9yZXMuIEVzdG8gcG9kcsOtYSBpbmRpY2FyIHF1ZSBsYXMgdml2aWVuZGFzIG3DoXMgY29zdG9zYXMgdGllbmRlbiBhIHNlciBhcGFydGFtZW50b3MgZW4gbHVnYXIgZGUgY2FzYXMuDQoNCiMjIyBBbsOhbGlzaXMgUHJlY2lvIFpvbmENCg0KYGBge3J9DQp0YWJsYTMgPC0gdGFibGUodml2aWVuZGFfQ0EkcHJlY2lvbV9jYXQsIHZpdmllbmRhX0NBJHpvbmEpDQpjb2xuYW1lcyh0YWJsYTMpIDwtIGMoIlpvbmFfQ2VudHJvIiwgIlpvbmFfTm9ydGUiLCAiWm9uYV9PZXN0ZSIsICJab25hX09yaWVudGUiLCAiWm9uYV9TdXIiKQ0KdGFibGEzDQpgYGANCg0KYGBge3J9DQpjaGlzcS50ZXN0KHRhYmxhMykNCmBgYA0KDQpFc3RlIGFuw6FsaXNpcyBpbmRpY2EgcXVlIGxhcyB2YXJpYWJsZXMgZW4gWm9uYS1QcmVjaW8gbm8gc29uIGluZGVwZW5kaWVudGVzLCBlcyBkZWNpciwgZXhpc3RlIHVuYSBhc29jaWFjacOzbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIGVudHJlIGVsbGFzLg0KDQpgYGB7cn0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCnJlc3VsdGFkb3Nfem9uYV9lc3RyYXRvIDwtIENBKHRhYmxhMykNCg0KYGBgDQoNCiMjIyBDb25jbHVzacOzbg0KDQpMYXMgem9uYXMgT3JpZW50ZSwgTm9ydGUgeSBDZW50cm8gZXN0w6FuIG3DoXMgcmVsYWNpb25hZGFzIGNvbiBwcmVjaW9zIGJham9zICgwLTI1MCksIG1pZW50cmFzIHF1ZSBsYXMgem9uYXMgT2VzdGUgeSBTdXIgc2UgYXNvY2lhbiBjb24gcHJlY2lvcyBtw6FzIGFsdG9zLCByZWZsZWphbmRvIHVuYSBwb3NpYmxlIHNlZ21lbnRhY2nDs24gZGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvLiBBZGVtw6FzLCBsYSBkaXNwZXJzacOzbiBkZSBsb3MgcHJlY2lvcyBlbiBsYSB6b25hIE9lc3RlIHN1Z2llcmUgdW5hIG1heW9yIHZhcmlhYmlsaWRhZCBlbiBsb3MgdmFsb3JlcyBkZSBsb3MgaW5tdWVibGVzIGRlbnRybyBkZSBlc3RhIMOhcmVhLg0KDQojIyBSRVNVTFRBRE9TDQoNCiMjIyAxLiBEaXN0cmlidWNpw7NuIGRlIFByZWNpb3MNCg0KIyMjIyBFbCBhbsOhbGlzaXMgZGUgbGEgZGlzdHJpYnVjacOzbiBkZSBwcmVjaW9zIG11ZXN0cmEgcXVlIGxhIG1heW9yw61hIGRlIGxhcyB2aXZpZW5kYXMgdGllbmVuIHByZWNpb3MgY29uY2VudHJhZG9zIGVuIHJhbmdvcyBiYWpvcyBhIG1lZGlvcywgY29uIHVuYSBkaXNtaW51Y2nDs24gcHJvZ3Jlc2l2YSBlbiBsYSBmcmVjdWVuY2lhIGEgbWVkaWRhIHF1ZSBlbCBwcmVjaW8gYXVtZW50YS4gRXN0byBzdWdpZXJlIHF1ZSBlbCBtZXJjYWRvIGlubW9iaWxpYXJpbyBlc3TDoSBkb21pbmFkbyBwb3IgcHJvcGllZGFkZXMgZWNvbsOzbWljYXMgeSBkZSBjb3N0byBtZWRpbywgY29uIHVuYSBtZW5vciByZXByZXNlbnRhY2nDs24gZGUgdml2aWVuZGFzIGRlIGx1am8uDQoNCiMjIyMgR3LDoWZpY286IEhpc3RvZ3JhbWEgZGUgcHJlY2lvcyBkZSB2aXZpZW5kYSBtb3N0cmFuZG8gbGEgZGlzdHJpYnVjacOzbiBkZSBmcmVjdWVuY2lhLg0KDQojIyMgMi4gU2VnbWVudGFjacOzbiBwb3IgWm9uYXMgeSBFc3RyYXRvcw0KDQojIyMjIEVsIGFuw6FsaXNpcyBwb3Igem9uYXMgcmV2ZWxhIHF1ZSBsYSAiWm9uYSBTdXIiIGNvbmNlbnRyYSBlbCBtYXlvciBuw7ptZXJvIGRlIHByb3BpZWRhZGVzLCBtaWVudHJhcyBxdWUgIlpvbmEgT3JpZW50ZSIgdGllbmUgbGEgbWVub3IgY2FudGlkYWQuIEVuIHTDqXJtaW5vcyBkZSBlc3RyYXRvIHNvY2lvZWNvbsOzbWljbywgbGEgbWF5b3IgcGFydGUgZGUgbGFzIHZpdmllbmRhcyBwZXJ0ZW5lY2VuIGEgbG9zIGVzdHJhdG9zIDQgeSA1LCBpbmRpY2FuZG8gdW4gbWVyY2FkbyBpbm1vYmlsaWFyaW8gZGlyaWdpZG8gcHJpbmNpcGFsbWVudGUgYSBsYSBjbGFzZSBtZWRpYS1hbHRhLg0KDQojIyMjIEdyw6FmaWNvOiBHcsOhZmljb3MgZGUgYmFycmFzIGNvbXBhcmFuZG8gbGEgZGlzdHJpYnVjacOzbiBkZSB2aXZpZW5kYXMgcG9yIHpvbmEgeSBlc3RyYXRvLg0KDQojIyMgMy4gUmVsYWNpw7NuIGVudHJlIFRpcG8gZGUgVml2aWVuZGEgeSBQcmVjaW8NCg0KIyMjIyBTZSBvYnNlcnZhIHF1ZSBsb3MgYXBhcnRhbWVudG9zIHRpZW5lbiBtYXlvciByZXByZXNlbnRhY2nDs24gZW4gZWwgbWVyY2FkbyBlbiBjb21wYXJhY2nDs24gY29uIGxhcyBjYXNhcy4gQWRlbcOhcywgbG9zIHByZWNpb3MgbcOhcyBiYWpvcyB0aWVuZGVuIGEgY29uY2VudHJhcnNlIGVuIGFwYXJ0YW1lbnRvcywgbWllbnRyYXMgcXVlIGxhcyBjYXNhcyB0aWVuZGVuIGEgdWJpY2Fyc2UgZW4gc2VnbWVudG9zIGRlIHByZWNpb3MgbcOhcyBhbHRvcy4NCg0KIyMjIyBHcsOhZmljbzogR3LDoWZpY28gZGUgYmFycmFzIHF1ZSBjb21wYXJhIGxhIGNhbnRpZGFkIGRlIGFwYXJ0YW1lbnRvcyB5IGNhc2FzLg0KDQojIyMgNC4gQW7DoWxpc2lzIGRlIENvcnJlc3BvbmRlbmNpYQ0KDQojIyMjIExhIGNvcnJlc3BvbmRlbmNpYSBlbnRyZSB6b25hcyB5IHByZWNpb3MgbXVlc3RyYSBxdWUgbGFzIHZpdmllbmRhcyBkZSBtZW5vciBjb3N0byBzZSBjb25jZW50cmFuIGVuIGNpZXJ0YXMgem9uYXMgZXNwZWPDrWZpY2FzLCBtaWVudHJhcyBxdWUgbGFzIHByb3BpZWRhZGVzIG3DoXMgY29zdG9zYXMgc2UgZGlzdHJpYnV5ZW4gZW4gdWJpY2FjaW9uZXMgbcOhcyBleGNsdXNpdmFzLiBFc3RhIGluZm9ybWFjacOzbiBlcyBjbGF2ZSBwYXJhIGxhIHRvbWEgZGUgZGVjaXNpb25lcyBlbiBlc3RyYXRlZ2lhcyBkZSBjb21lcmNpYWxpemFjacOzbi4NCg0KIyMjIyBHcsOhZmljbzogTWFwYSBkZSBjb3JyZXNwb25kZW5jaWFzIGVudHJlIHpvbmFzIHkgcmFuZ29zIGRlIHByZWNpb3MuDQoNCiMjIyA1LiBBbsOhbGlzaXMgR2VvZXNwYWNpYWwNCg0KIyMjIyBTaSBzZSBjb25zaWRlcmFuIGRhdG9zIGdlb2VzcGFjaWFsZXMgY29tbyBsYXRpdHVkIHkgbG9uZ2l0dWQsIHNlIHB1ZWRlbiB2aXN1YWxpemFyIHBhdHJvbmVzIGVzcGVjw61maWNvcyBkZSBkaXN0cmlidWNpw7NuIGlubW9iaWxpYXJpYSBlbiB1biBtYXBhLiBFc3RvIGF5dWRhIGEgaWRlbnRpZmljYXIgw6FyZWFzIGRlIGFsdGEgeSBiYWphIGRlbWFuZGEsIGZhY2lsaXRhbmRvIGxhIHRvbWEgZGUgZGVjaXNpb25lcyBlc3RyYXTDqWdpY2FzLg0KDQojIyMjIEdyw6FmaWNvOiBNYXBhIGRlIGNhbG9yIG1vc3RyYW5kbyBsYSBkaXN0cmlidWNpw7NuIGdlb2dyw6FmaWNhIGRlIHByZWNpb3MgZGUgdml2aWVuZGEuDQoNCiMjIyBDb25jbHVzacOzbiBHZW5lcmFsDQoNCiMjIyMgRWwgZXN0dWRpbyBpbm1vYmlsaWFyaW8gcmV2ZWxhIHVuYSBkaXN0cmlidWNpw7NuIGRlc2lndWFsIGRlIHByb3BpZWRhZGVzLCBjb24gdW5hIG1heW9yIGNvbmNlbnRyYWNpw7NuIGRlIHZpdmllbmRhcyBlbiB6b25hcyBlc3BlY8OtZmljYXMgeSB1biBtZXJjYWRvIGRvbWluYWRvIHBvciBhcGFydGFtZW50b3MgYSBwcmVjaW9zIGJham9zIHkgbWVkaW9zLiBFbCBhbsOhbGlzaXMgZ2VvZXNwYWNpYWwgeSBkZSBjb3JyZXNwb25kZW5jaWEgYnJpbmRhIGluZm9ybWFjacOzbiB2YWxpb3NhIHBhcmEgbGEgcGxhbmVhY2nDs24geSBjb21lcmNpYWxpemFjacOzbiBlZmVjdGl2YSBlbiBlbCBzZWN0b3IgaW5tb2JpbGlhcmlvLg0K